libdebugserver.cpp [plain text]
#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"
typedef enum
{
eRNBRunLoopModeInvalid = 0,
eRNBRunLoopModeGetStartModeFromRemoteProtocol,
eRNBRunLoopModeInferiorExecuting,
eRNBRunLoopModeExit
} RNBRunLoopMode;
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)
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;
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);
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
{
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;
}
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 SIGPIPE:
g_sigpipe_received = 1;
break;
}
}
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:
return eRNBRunLoopModeExit;
break;
case eStateAttaching:
case eStateLaunching:
return eRNBRunLoopModeInferiorExecuting;
case eStateSuspended:
case eStateCrashed:
case eStateStopped:
if (initialize == false)
{
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;
}
return eRNBRunLoopModeExit;
}
RNBRunLoopMode
RNBRunLoopInferiorExecuting (RNBRemoteSP &remote)
{
DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
RNBContext& ctx = remote->Context();
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())
{
event_mask &= ~RNBContext::event_proc_stdio_available;
}
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)
{
set_events ^= RNBContext::event_read_packet_available;
if (ctx.ProcessStateRunning())
{
if (remote->HandleAsyncPacket() == rnb_not_connected)
{
}
}
else
{
if (remote->HandleReceivedPacket() == rnb_not_connected)
{
}
}
}
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)
{
if (ctx.HasValidProcessID())
{
if (ctx.ProcessStateRunning())
{
DNBProcessKill (ctx.ProcessID());
}
}
mode = eRNBRunLoopModeExit;
}
}
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;
}