Initial import of lldb
Change-Id: Ib244e837bee349effa12b2ff6ffffbe3d730e929
This commit is contained in:
397
external/bsd/llvm/dist/lldb/tools/debugserver/source/libdebugserver.cpp
vendored
Normal file
397
external/bsd/llvm/dist/lldb/tools/debugserver/source/libdebugserver.cpp
vendored
Normal file
@@ -0,0 +1,397 @@
|
||||
//===-- libdebugserver.cpp --------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include "DNB.h"
|
||||
#include "DNBLog.h"
|
||||
#include "DNBTimer.h"
|
||||
#include "PseudoTerminal.h"
|
||||
#include "RNBContext.h"
|
||||
#include "RNBServices.h"
|
||||
#include "RNBSocket.h"
|
||||
#include "RNBRemote.h"
|
||||
#include "SysSignal.h"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Run loop modes which determine which run loop function will be called
|
||||
//----------------------------------------------------------------------
|
||||
typedef enum
|
||||
{
|
||||
eRNBRunLoopModeInvalid = 0,
|
||||
eRNBRunLoopModeGetStartModeFromRemoteProtocol,
|
||||
eRNBRunLoopModeInferiorExecuting,
|
||||
eRNBRunLoopModeExit
|
||||
} RNBRunLoopMode;
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Global Variables
|
||||
//----------------------------------------------------------------------
|
||||
RNBRemoteSP g_remoteSP;
|
||||
int g_disable_aslr = 0;
|
||||
int g_isatty = 0;
|
||||
|
||||
#define RNBLogSTDOUT(fmt, ...) do { if (g_isatty) { fprintf(stdout, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
|
||||
#define RNBLogSTDERR(fmt, ...) do { if (g_isatty) { fprintf(stderr, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Get our program path and arguments from the remote connection.
|
||||
// We will need to start up the remote connection without a PID, get the
|
||||
// arguments, wait for the new process to finish launching and hit its
|
||||
// entry point, and then return the run loop mode that should come next.
|
||||
//----------------------------------------------------------------------
|
||||
RNBRunLoopMode
|
||||
RNBRunLoopGetStartModeFromRemote (RNBRemoteSP &remoteSP)
|
||||
{
|
||||
std::string packet;
|
||||
|
||||
if (remoteSP.get() != NULL)
|
||||
{
|
||||
RNBRemote* remote = remoteSP.get();
|
||||
RNBContext& ctx = remote->Context();
|
||||
uint32_t event_mask = RNBContext::event_read_packet_available;
|
||||
|
||||
// Spin waiting to get the A packet.
|
||||
while (1)
|
||||
{
|
||||
DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) ...",__FUNCTION__, event_mask);
|
||||
nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
|
||||
DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) => 0x%08x", __FUNCTION__, event_mask, set_events);
|
||||
|
||||
if (set_events & RNBContext::event_read_packet_available)
|
||||
{
|
||||
rnb_err_t err = rnb_err;
|
||||
RNBRemote::PacketEnum type;
|
||||
|
||||
err = remote->HandleReceivedPacket (&type);
|
||||
|
||||
// check if we tried to attach to a process
|
||||
if (type == RNBRemote::vattach || type == RNBRemote::vattachwait)
|
||||
{
|
||||
if (err == rnb_success)
|
||||
return eRNBRunLoopModeInferiorExecuting;
|
||||
else
|
||||
{
|
||||
RNBLogSTDERR ("error: attach failed.");
|
||||
return eRNBRunLoopModeExit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (err == rnb_success)
|
||||
{
|
||||
DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Got success...",__FUNCTION__);
|
||||
continue;
|
||||
}
|
||||
else if (err == rnb_not_connected)
|
||||
{
|
||||
RNBLogSTDERR ("error: connection lost.");
|
||||
return eRNBRunLoopModeExit;
|
||||
}
|
||||
else
|
||||
{
|
||||
// a catch all for any other gdb remote packets that failed
|
||||
DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.",__FUNCTION__);
|
||||
continue;
|
||||
}
|
||||
|
||||
DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
|
||||
}
|
||||
else
|
||||
{
|
||||
DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Connection closed before getting \"A\" packet.", __FUNCTION__);
|
||||
return eRNBRunLoopModeExit;
|
||||
}
|
||||
}
|
||||
}
|
||||
return eRNBRunLoopModeExit;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Watch for signals:
|
||||
// SIGINT: so we can halt our inferior. (disabled for now)
|
||||
// SIGPIPE: in case our child process dies
|
||||
//----------------------------------------------------------------------
|
||||
nub_process_t g_pid;
|
||||
int g_sigpipe_received = 0;
|
||||
void
|
||||
signal_handler(int signo)
|
||||
{
|
||||
DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (%s)", __FUNCTION__, SysSignal::Name(signo));
|
||||
|
||||
switch (signo)
|
||||
{
|
||||
// case SIGINT:
|
||||
// DNBProcessKill (g_pid, signo);
|
||||
// break;
|
||||
|
||||
case SIGPIPE:
|
||||
g_sigpipe_received = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the new run loop mode based off of the current process state
|
||||
RNBRunLoopMode
|
||||
HandleProcessStateChange (RNBRemoteSP &remote, bool initialize)
|
||||
{
|
||||
RNBContext& ctx = remote->Context();
|
||||
nub_process_t pid = ctx.ProcessID();
|
||||
|
||||
if (pid == INVALID_NUB_PROCESS)
|
||||
{
|
||||
DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s error: pid invalid, exiting...", __FUNCTION__);
|
||||
return eRNBRunLoopModeExit;
|
||||
}
|
||||
nub_state_t pid_state = DNBProcessGetState (pid);
|
||||
|
||||
DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state));
|
||||
|
||||
switch (pid_state)
|
||||
{
|
||||
case eStateInvalid:
|
||||
case eStateUnloaded:
|
||||
// Something bad happened
|
||||
return eRNBRunLoopModeExit;
|
||||
break;
|
||||
|
||||
case eStateAttaching:
|
||||
case eStateLaunching:
|
||||
return eRNBRunLoopModeInferiorExecuting;
|
||||
|
||||
case eStateSuspended:
|
||||
case eStateCrashed:
|
||||
case eStateStopped:
|
||||
if (initialize == false)
|
||||
{
|
||||
// Compare the last stop count to our current notion of a stop count
|
||||
// to make sure we don't notify more than once for a given stop.
|
||||
nub_size_t prev_pid_stop_count = ctx.GetProcessStopCount();
|
||||
bool pid_stop_count_changed = ctx.SetProcessStopCount(DNBProcessGetStopCount(pid));
|
||||
if (pid_stop_count_changed)
|
||||
{
|
||||
remote->FlushSTDIO();
|
||||
|
||||
if (ctx.GetProcessStopCount() == 1)
|
||||
{
|
||||
DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %u (old %u)) Notify??? no, first stop...", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), ctx.GetProcessStopCount(), prev_pid_stop_count);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %u (old %u)) Notify??? YES!!!", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), ctx.GetProcessStopCount(), prev_pid_stop_count);
|
||||
remote->NotifyThatProcessStopped ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %u (old %u)) Notify??? skipping...", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), ctx.GetProcessStopCount(), prev_pid_stop_count);
|
||||
}
|
||||
}
|
||||
return eRNBRunLoopModeInferiorExecuting;
|
||||
|
||||
case eStateStepping:
|
||||
case eStateRunning:
|
||||
return eRNBRunLoopModeInferiorExecuting;
|
||||
|
||||
case eStateExited:
|
||||
remote->HandlePacket_last_signal(NULL);
|
||||
return eRNBRunLoopModeExit;
|
||||
case eStateDetached:
|
||||
return eRNBRunLoopModeExit;
|
||||
|
||||
}
|
||||
|
||||
// Catch all...
|
||||
return eRNBRunLoopModeExit;
|
||||
}
|
||||
// This function handles the case where our inferior program is stopped and
|
||||
// we are waiting for gdb remote protocol packets. When a packet occurs that
|
||||
// makes the inferior run, we need to leave this function with a new state
|
||||
// as the return code.
|
||||
RNBRunLoopMode
|
||||
RNBRunLoopInferiorExecuting (RNBRemoteSP &remote)
|
||||
{
|
||||
DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
|
||||
RNBContext& ctx = remote->Context();
|
||||
|
||||
// Init our mode and set 'is_running' based on the current process state
|
||||
RNBRunLoopMode mode = HandleProcessStateChange (remote, true);
|
||||
|
||||
while (ctx.ProcessID() != INVALID_NUB_PROCESS)
|
||||
{
|
||||
|
||||
std::string set_events_str;
|
||||
uint32_t event_mask = ctx.NormalEventBits();
|
||||
|
||||
if (!ctx.ProcessStateRunning())
|
||||
{
|
||||
// Clear the stdio bits if we are not running so we don't send any async packets
|
||||
event_mask &= ~RNBContext::event_proc_stdio_available;
|
||||
}
|
||||
|
||||
// We want to make sure we consume all process state changes and have
|
||||
// whomever is notifying us to wait for us to reset the event bit before
|
||||
// continuing.
|
||||
//ctx.Events().SetResetAckMask (RNBContext::event_proc_state_changed);
|
||||
|
||||
DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) ...",__FUNCTION__, event_mask);
|
||||
nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
|
||||
DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) => 0x%08x (%s)",__FUNCTION__, event_mask, set_events, ctx.EventsAsString(set_events, set_events_str));
|
||||
|
||||
if (set_events)
|
||||
{
|
||||
if ((set_events & RNBContext::event_proc_thread_exiting) ||
|
||||
(set_events & RNBContext::event_proc_stdio_available))
|
||||
{
|
||||
remote->FlushSTDIO();
|
||||
}
|
||||
|
||||
if (set_events & RNBContext::event_read_packet_available)
|
||||
{
|
||||
// handleReceivedPacket will take care of resetting the
|
||||
// event_read_packet_available events when there are no more...
|
||||
set_events ^= RNBContext::event_read_packet_available;
|
||||
|
||||
if (ctx.ProcessStateRunning())
|
||||
{
|
||||
if (remote->HandleAsyncPacket() == rnb_not_connected)
|
||||
{
|
||||
// TODO: connect again? Exit?
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (remote->HandleReceivedPacket() == rnb_not_connected)
|
||||
{
|
||||
// TODO: connect again? Exit?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (set_events & RNBContext::event_proc_state_changed)
|
||||
{
|
||||
mode = HandleProcessStateChange (remote, false);
|
||||
ctx.Events().ResetEvents(RNBContext::event_proc_state_changed);
|
||||
set_events ^= RNBContext::event_proc_state_changed;
|
||||
}
|
||||
|
||||
if (set_events & RNBContext::event_proc_thread_exiting)
|
||||
{
|
||||
mode = eRNBRunLoopModeExit;
|
||||
}
|
||||
|
||||
if (set_events & RNBContext::event_read_thread_exiting)
|
||||
{
|
||||
// Out remote packet receiving thread exited, exit for now.
|
||||
if (ctx.HasValidProcessID())
|
||||
{
|
||||
// TODO: We should add code that will leave the current process
|
||||
// in its current state and listen for another connection...
|
||||
if (ctx.ProcessStateRunning())
|
||||
{
|
||||
DNBProcessKill (ctx.ProcessID());
|
||||
}
|
||||
}
|
||||
mode = eRNBRunLoopModeExit;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset all event bits that weren't reset for now...
|
||||
if (set_events != 0)
|
||||
ctx.Events().ResetEvents(set_events);
|
||||
|
||||
if (mode != eRNBRunLoopModeInferiorExecuting)
|
||||
break;
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
void
|
||||
ASLLogCallback(void *baton, uint32_t flags, const char *format, va_list args)
|
||||
{
|
||||
#if 0
|
||||
vprintf(format, args);
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
debug_server_main(int fd)
|
||||
{
|
||||
#if 1
|
||||
g_isatty = 0;
|
||||
#else
|
||||
g_isatty = ::isatty (STDIN_FILENO);
|
||||
|
||||
DNBLogSetDebug(1);
|
||||
DNBLogSetVerbose(1);
|
||||
DNBLogSetLogMask(-1);
|
||||
DNBLogSetLogCallback(ASLLogCallback, NULL);
|
||||
#endif
|
||||
|
||||
signal (SIGPIPE, signal_handler);
|
||||
|
||||
g_remoteSP.reset (new RNBRemote);
|
||||
|
||||
RNBRemote *remote = g_remoteSP.get();
|
||||
if (remote == NULL)
|
||||
{
|
||||
RNBLogSTDERR ("error: failed to create a remote connection class\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
RNBRunLoopMode mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol;
|
||||
|
||||
while (mode != eRNBRunLoopModeExit)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case eRNBRunLoopModeGetStartModeFromRemoteProtocol:
|
||||
if (g_remoteSP->Comm().useFD(fd) == rnb_success) {
|
||||
RNBLogSTDOUT("Starting remote data thread.\n");
|
||||
g_remoteSP->StartReadRemoteDataThread();
|
||||
|
||||
RNBLogSTDOUT("Waiting for start mode from remote.\n");
|
||||
mode = RNBRunLoopGetStartModeFromRemote(g_remoteSP);
|
||||
}
|
||||
else
|
||||
{
|
||||
mode = eRNBRunLoopModeExit;
|
||||
}
|
||||
break;
|
||||
|
||||
case eRNBRunLoopModeInferiorExecuting:
|
||||
mode = RNBRunLoopInferiorExecuting(g_remoteSP);
|
||||
break;
|
||||
|
||||
default:
|
||||
mode = eRNBRunLoopModeExit;
|
||||
break;
|
||||
|
||||
case eRNBRunLoopModeExit:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_remoteSP->StopReadRemoteDataThread ();
|
||||
g_remoteSP->Context().SetProcessID(INVALID_NUB_PROCESS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user