1*bd2d88d6SJason Molenda //===-- libdebugserver.cpp --------------------------------------*- C++ -*-===// 2*bd2d88d6SJason Molenda // 3*bd2d88d6SJason Molenda // The LLVM Compiler Infrastructure 4*bd2d88d6SJason Molenda // 5*bd2d88d6SJason Molenda // This file is distributed under the University of Illinois Open Source 6*bd2d88d6SJason Molenda // License. See LICENSE.TXT for details. 7*bd2d88d6SJason Molenda // 8*bd2d88d6SJason Molenda //===----------------------------------------------------------------------===// 9d676074dSJason Molenda 10d676074dSJason Molenda #include <sys/socket.h> 11d676074dSJason Molenda #include <sys/types.h> 12d676074dSJason Molenda #include <errno.h> 13d676074dSJason Molenda #include <getopt.h> 14d676074dSJason Molenda #include <netinet/in.h> 15d676074dSJason Molenda #include <sys/select.h> 16d676074dSJason Molenda #include <sys/sysctl.h> 17d676074dSJason Molenda 18d676074dSJason Molenda #include "DNB.h" 19d676074dSJason Molenda #include "DNBLog.h" 20d676074dSJason Molenda #include "DNBTimer.h" 21d676074dSJason Molenda #include "PseudoTerminal.h" 22d676074dSJason Molenda #include "RNBContext.h" 23d676074dSJason Molenda #include "RNBServices.h" 24d676074dSJason Molenda #include "RNBSocket.h" 25d676074dSJason Molenda #include "RNBRemote.h" 26d676074dSJason Molenda #include "SysSignal.h" 27d676074dSJason Molenda 28d676074dSJason Molenda //---------------------------------------------------------------------- 29d676074dSJason Molenda // Run loop modes which determine which run loop function will be called 30d676074dSJason Molenda //---------------------------------------------------------------------- 31d676074dSJason Molenda typedef enum 32d676074dSJason Molenda { 33d676074dSJason Molenda eRNBRunLoopModeInvalid = 0, 34d676074dSJason Molenda eRNBRunLoopModeGetStartModeFromRemoteProtocol, 35d676074dSJason Molenda eRNBRunLoopModeInferiorExecuting, 36d676074dSJason Molenda eRNBRunLoopModeExit 37d676074dSJason Molenda } RNBRunLoopMode; 38d676074dSJason Molenda 39d676074dSJason Molenda 40d676074dSJason Molenda //---------------------------------------------------------------------- 41d676074dSJason Molenda // Global Variables 42d676074dSJason Molenda //---------------------------------------------------------------------- 43d676074dSJason Molenda RNBRemoteSP g_remoteSP; 44d676074dSJason Molenda int g_disable_aslr = 0; 45d676074dSJason Molenda int g_isatty = 0; 46d676074dSJason Molenda 47d676074dSJason Molenda #define RNBLogSTDOUT(fmt, ...) do { if (g_isatty) { fprintf(stdout, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0) 48d676074dSJason Molenda #define RNBLogSTDERR(fmt, ...) do { if (g_isatty) { fprintf(stderr, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0) 49d676074dSJason Molenda 50d676074dSJason Molenda 51d676074dSJason Molenda //---------------------------------------------------------------------- 52d676074dSJason Molenda // Get our program path and arguments from the remote connection. 53d676074dSJason Molenda // We will need to start up the remote connection without a PID, get the 54d676074dSJason Molenda // arguments, wait for the new process to finish launching and hit its 55d676074dSJason Molenda // entry point, and then return the run loop mode that should come next. 56d676074dSJason Molenda //---------------------------------------------------------------------- 57d676074dSJason Molenda RNBRunLoopMode 58d676074dSJason Molenda RNBRunLoopGetStartModeFromRemote (RNBRemoteSP &remoteSP) 59d676074dSJason Molenda { 60d676074dSJason Molenda std::string packet; 61d676074dSJason Molenda 62d676074dSJason Molenda if (remoteSP.get() != NULL) 63d676074dSJason Molenda { 64d676074dSJason Molenda RNBRemote* remote = remoteSP.get(); 65d676074dSJason Molenda RNBContext& ctx = remote->Context(); 66d676074dSJason Molenda uint32_t event_mask = RNBContext::event_read_packet_available; 67d676074dSJason Molenda 68d676074dSJason Molenda // Spin waiting to get the A packet. 69d676074dSJason Molenda while (1) 70d676074dSJason Molenda { 71d676074dSJason Molenda DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) ...",__FUNCTION__, event_mask); 72d676074dSJason Molenda nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); 73d676074dSJason Molenda DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) => 0x%08x", __FUNCTION__, event_mask, set_events); 74d676074dSJason Molenda 75d676074dSJason Molenda if (set_events & RNBContext::event_read_packet_available) 76d676074dSJason Molenda { 77d676074dSJason Molenda rnb_err_t err = rnb_err; 78d676074dSJason Molenda RNBRemote::PacketEnum type; 79d676074dSJason Molenda 80d676074dSJason Molenda err = remote->HandleReceivedPacket (&type); 81d676074dSJason Molenda 82d676074dSJason Molenda // check if we tried to attach to a process 83d676074dSJason Molenda if (type == RNBRemote::vattach || type == RNBRemote::vattachwait) 84d676074dSJason Molenda { 85d676074dSJason Molenda if (err == rnb_success) 86d676074dSJason Molenda return eRNBRunLoopModeInferiorExecuting; 87d676074dSJason Molenda else 88d676074dSJason Molenda { 89d676074dSJason Molenda RNBLogSTDERR ("error: attach failed."); 90d676074dSJason Molenda return eRNBRunLoopModeExit; 91d676074dSJason Molenda } 92d676074dSJason Molenda } 93d676074dSJason Molenda 94d676074dSJason Molenda 95d676074dSJason Molenda if (err == rnb_success) 96d676074dSJason Molenda { 97d676074dSJason Molenda DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Got success...",__FUNCTION__); 98d676074dSJason Molenda continue; 99d676074dSJason Molenda } 100d676074dSJason Molenda else if (err == rnb_not_connected) 101d676074dSJason Molenda { 102d676074dSJason Molenda RNBLogSTDERR ("error: connection lost."); 103d676074dSJason Molenda return eRNBRunLoopModeExit; 104d676074dSJason Molenda } 105d676074dSJason Molenda else 106d676074dSJason Molenda { 107d676074dSJason Molenda // a catch all for any other gdb remote packets that failed 108d676074dSJason Molenda DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.",__FUNCTION__); 109d676074dSJason Molenda continue; 110d676074dSJason Molenda } 111d676074dSJason Molenda 112d676074dSJason Molenda DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__); 113d676074dSJason Molenda } 114d676074dSJason Molenda else 115d676074dSJason Molenda { 116d676074dSJason Molenda DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Connection closed before getting \"A\" packet.", __FUNCTION__); 117d676074dSJason Molenda return eRNBRunLoopModeExit; 118d676074dSJason Molenda } 119d676074dSJason Molenda } 120d676074dSJason Molenda } 121d676074dSJason Molenda return eRNBRunLoopModeExit; 122d676074dSJason Molenda } 123d676074dSJason Molenda 124d676074dSJason Molenda 125d676074dSJason Molenda //---------------------------------------------------------------------- 126d676074dSJason Molenda // Watch for signals: 127d676074dSJason Molenda // SIGINT: so we can halt our inferior. (disabled for now) 128d676074dSJason Molenda // SIGPIPE: in case our child process dies 129d676074dSJason Molenda //---------------------------------------------------------------------- 130d676074dSJason Molenda nub_process_t g_pid; 131d676074dSJason Molenda int g_sigpipe_received = 0; 132d676074dSJason Molenda void 133d676074dSJason Molenda signal_handler(int signo) 134d676074dSJason Molenda { 135d676074dSJason Molenda DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (%s)", __FUNCTION__, SysSignal::Name(signo)); 136d676074dSJason Molenda 137d676074dSJason Molenda switch (signo) 138d676074dSJason Molenda { 139d676074dSJason Molenda // case SIGINT: 140d676074dSJason Molenda // DNBProcessKill (g_pid, signo); 141d676074dSJason Molenda // break; 142d676074dSJason Molenda 143d676074dSJason Molenda case SIGPIPE: 144d676074dSJason Molenda g_sigpipe_received = 1; 145d676074dSJason Molenda break; 146d676074dSJason Molenda } 147d676074dSJason Molenda } 148d676074dSJason Molenda 149d676074dSJason Molenda // Return the new run loop mode based off of the current process state 150d676074dSJason Molenda RNBRunLoopMode 151d676074dSJason Molenda HandleProcessStateChange (RNBRemoteSP &remote, bool initialize) 152d676074dSJason Molenda { 153d676074dSJason Molenda RNBContext& ctx = remote->Context(); 154d676074dSJason Molenda nub_process_t pid = ctx.ProcessID(); 155d676074dSJason Molenda 156d676074dSJason Molenda if (pid == INVALID_NUB_PROCESS) 157d676074dSJason Molenda { 158d676074dSJason Molenda DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s error: pid invalid, exiting...", __FUNCTION__); 159d676074dSJason Molenda return eRNBRunLoopModeExit; 160d676074dSJason Molenda } 161d676074dSJason Molenda nub_state_t pid_state = DNBProcessGetState (pid); 162d676074dSJason Molenda 163d676074dSJason Molenda DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state)); 164d676074dSJason Molenda 165d676074dSJason Molenda switch (pid_state) 166d676074dSJason Molenda { 167d676074dSJason Molenda case eStateInvalid: 168d676074dSJason Molenda case eStateUnloaded: 169d676074dSJason Molenda // Something bad happened 170d676074dSJason Molenda return eRNBRunLoopModeExit; 171d676074dSJason Molenda break; 172d676074dSJason Molenda 173d676074dSJason Molenda case eStateAttaching: 174d676074dSJason Molenda case eStateLaunching: 175d676074dSJason Molenda return eRNBRunLoopModeInferiorExecuting; 176d676074dSJason Molenda 177d676074dSJason Molenda case eStateSuspended: 178d676074dSJason Molenda case eStateCrashed: 179d676074dSJason Molenda case eStateStopped: 180d676074dSJason Molenda if (initialize == false) 181d676074dSJason Molenda { 182d676074dSJason Molenda // Compare the last stop count to our current notion of a stop count 183d676074dSJason Molenda // to make sure we don't notify more than once for a given stop. 184d676074dSJason Molenda nub_size_t prev_pid_stop_count = ctx.GetProcessStopCount(); 185d676074dSJason Molenda bool pid_stop_count_changed = ctx.SetProcessStopCount(DNBProcessGetStopCount(pid)); 186d676074dSJason Molenda if (pid_stop_count_changed) 187d676074dSJason Molenda { 188d676074dSJason Molenda remote->FlushSTDIO(); 189d676074dSJason Molenda 190d676074dSJason Molenda if (ctx.GetProcessStopCount() == 1) 191d676074dSJason Molenda { 192d676074dSJason Molenda 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); 193d676074dSJason Molenda } 194d676074dSJason Molenda else 195d676074dSJason Molenda { 196d676074dSJason Molenda 197d676074dSJason Molenda 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); 198d676074dSJason Molenda remote->NotifyThatProcessStopped (); 199d676074dSJason Molenda } 200d676074dSJason Molenda } 201d676074dSJason Molenda else 202d676074dSJason Molenda { 203d676074dSJason Molenda 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); 204d676074dSJason Molenda } 205d676074dSJason Molenda } 206d676074dSJason Molenda return eRNBRunLoopModeInferiorExecuting; 207d676074dSJason Molenda 208d676074dSJason Molenda case eStateStepping: 209d676074dSJason Molenda case eStateRunning: 210d676074dSJason Molenda return eRNBRunLoopModeInferiorExecuting; 211d676074dSJason Molenda 212d676074dSJason Molenda case eStateExited: 213d676074dSJason Molenda remote->HandlePacket_last_signal(NULL); 214d676074dSJason Molenda return eRNBRunLoopModeExit; 215d676074dSJason Molenda case eStateDetached: 216d676074dSJason Molenda return eRNBRunLoopModeExit; 217d676074dSJason Molenda 218d676074dSJason Molenda } 219d676074dSJason Molenda 220d676074dSJason Molenda // Catch all... 221d676074dSJason Molenda return eRNBRunLoopModeExit; 222d676074dSJason Molenda } 223d676074dSJason Molenda // This function handles the case where our inferior program is stopped and 224d676074dSJason Molenda // we are waiting for gdb remote protocol packets. When a packet occurs that 225d676074dSJason Molenda // makes the inferior run, we need to leave this function with a new state 226d676074dSJason Molenda // as the return code. 227d676074dSJason Molenda RNBRunLoopMode 228d676074dSJason Molenda RNBRunLoopInferiorExecuting (RNBRemoteSP &remote) 229d676074dSJason Molenda { 230d676074dSJason Molenda DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__); 231d676074dSJason Molenda RNBContext& ctx = remote->Context(); 232d676074dSJason Molenda 233d676074dSJason Molenda // Init our mode and set 'is_running' based on the current process state 234d676074dSJason Molenda RNBRunLoopMode mode = HandleProcessStateChange (remote, true); 235d676074dSJason Molenda 236d676074dSJason Molenda while (ctx.ProcessID() != INVALID_NUB_PROCESS) 237d676074dSJason Molenda { 238d676074dSJason Molenda 239d676074dSJason Molenda std::string set_events_str; 240d676074dSJason Molenda uint32_t event_mask = ctx.NormalEventBits(); 241d676074dSJason Molenda 242d676074dSJason Molenda if (!ctx.ProcessStateRunning()) 243d676074dSJason Molenda { 244d676074dSJason Molenda // Clear the stdio bits if we are not running so we don't send any async packets 245d676074dSJason Molenda event_mask &= ~RNBContext::event_proc_stdio_available; 246d676074dSJason Molenda } 247d676074dSJason Molenda 248d676074dSJason Molenda // We want to make sure we consume all process state changes and have 249d676074dSJason Molenda // whomever is notifying us to wait for us to reset the event bit before 250d676074dSJason Molenda // continuing. 251d676074dSJason Molenda //ctx.Events().SetResetAckMask (RNBContext::event_proc_state_changed); 252d676074dSJason Molenda 253d676074dSJason Molenda DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) ...",__FUNCTION__, event_mask); 254d676074dSJason Molenda nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); 255d676074dSJason Molenda 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)); 256d676074dSJason Molenda 257d676074dSJason Molenda if (set_events) 258d676074dSJason Molenda { 259d676074dSJason Molenda if ((set_events & RNBContext::event_proc_thread_exiting) || 260d676074dSJason Molenda (set_events & RNBContext::event_proc_stdio_available)) 261d676074dSJason Molenda { 262d676074dSJason Molenda remote->FlushSTDIO(); 263d676074dSJason Molenda } 264d676074dSJason Molenda 265d676074dSJason Molenda if (set_events & RNBContext::event_read_packet_available) 266d676074dSJason Molenda { 267d676074dSJason Molenda // handleReceivedPacket will take care of resetting the 268d676074dSJason Molenda // event_read_packet_available events when there are no more... 269d676074dSJason Molenda set_events ^= RNBContext::event_read_packet_available; 270d676074dSJason Molenda 271d676074dSJason Molenda if (ctx.ProcessStateRunning()) 272d676074dSJason Molenda { 273d676074dSJason Molenda if (remote->HandleAsyncPacket() == rnb_not_connected) 274d676074dSJason Molenda { 275d676074dSJason Molenda // TODO: connect again? Exit? 276d676074dSJason Molenda } 277d676074dSJason Molenda } 278d676074dSJason Molenda else 279d676074dSJason Molenda { 280d676074dSJason Molenda if (remote->HandleReceivedPacket() == rnb_not_connected) 281d676074dSJason Molenda { 282d676074dSJason Molenda // TODO: connect again? Exit? 283d676074dSJason Molenda } 284d676074dSJason Molenda } 285d676074dSJason Molenda } 286d676074dSJason Molenda 287d676074dSJason Molenda if (set_events & RNBContext::event_proc_state_changed) 288d676074dSJason Molenda { 289d676074dSJason Molenda mode = HandleProcessStateChange (remote, false); 290d676074dSJason Molenda ctx.Events().ResetEvents(RNBContext::event_proc_state_changed); 291d676074dSJason Molenda set_events ^= RNBContext::event_proc_state_changed; 292d676074dSJason Molenda } 293d676074dSJason Molenda 294d676074dSJason Molenda if (set_events & RNBContext::event_proc_thread_exiting) 295d676074dSJason Molenda { 296d676074dSJason Molenda mode = eRNBRunLoopModeExit; 297d676074dSJason Molenda } 298d676074dSJason Molenda 299d676074dSJason Molenda if (set_events & RNBContext::event_read_thread_exiting) 300d676074dSJason Molenda { 301d676074dSJason Molenda // Out remote packet receiving thread exited, exit for now. 302d676074dSJason Molenda if (ctx.HasValidProcessID()) 303d676074dSJason Molenda { 304d676074dSJason Molenda // TODO: We should add code that will leave the current process 305d676074dSJason Molenda // in its current state and listen for another connection... 306d676074dSJason Molenda if (ctx.ProcessStateRunning()) 307d676074dSJason Molenda { 308d676074dSJason Molenda DNBProcessKill (ctx.ProcessID(), SIGINT); 309d676074dSJason Molenda } 310d676074dSJason Molenda } 311d676074dSJason Molenda mode = eRNBRunLoopModeExit; 312d676074dSJason Molenda } 313d676074dSJason Molenda } 314d676074dSJason Molenda 315d676074dSJason Molenda // Reset all event bits that weren't reset for now... 316d676074dSJason Molenda if (set_events != 0) 317d676074dSJason Molenda ctx.Events().ResetEvents(set_events); 318d676074dSJason Molenda 319d676074dSJason Molenda if (mode != eRNBRunLoopModeInferiorExecuting) 320d676074dSJason Molenda break; 321d676074dSJason Molenda } 322d676074dSJason Molenda 323d676074dSJason Molenda return mode; 324d676074dSJason Molenda } 325d676074dSJason Molenda 326d676074dSJason Molenda void 327d676074dSJason Molenda ASLLogCallback(void *baton, uint32_t flags, const char *format, va_list args) 328d676074dSJason Molenda { 329d676074dSJason Molenda #if 0 330d676074dSJason Molenda vprintf(format, args); 331d676074dSJason Molenda #endif 332d676074dSJason Molenda } 333d676074dSJason Molenda 334d676074dSJason Molenda extern "C" int 335d676074dSJason Molenda debug_server_main(int fd) 336d676074dSJason Molenda { 337d676074dSJason Molenda #if 1 338d676074dSJason Molenda g_isatty = 0; 339d676074dSJason Molenda #else 340d676074dSJason Molenda g_isatty = ::isatty (STDIN_FILENO); 341d676074dSJason Molenda 342d676074dSJason Molenda DNBLogSetDebug(1); 343d676074dSJason Molenda DNBLogSetVerbose(1); 344d676074dSJason Molenda DNBLogSetLogMask(-1); 345d676074dSJason Molenda DNBLogSetLogCallback(ASLLogCallback, NULL); 346d676074dSJason Molenda #endif 347d676074dSJason Molenda 348d676074dSJason Molenda signal (SIGPIPE, signal_handler); 349d676074dSJason Molenda 350d676074dSJason Molenda g_remoteSP.reset (new RNBRemote); 351d676074dSJason Molenda 352d676074dSJason Molenda RNBRemote *remote = g_remoteSP.get(); 353d676074dSJason Molenda if (remote == NULL) 354d676074dSJason Molenda { 355d676074dSJason Molenda RNBLogSTDERR ("error: failed to create a remote connection class\n"); 356d676074dSJason Molenda return -1; 357d676074dSJason Molenda } 358d676074dSJason Molenda 359d676074dSJason Molenda 360d676074dSJason Molenda RNBRunLoopMode mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol; 361d676074dSJason Molenda 362d676074dSJason Molenda while (mode != eRNBRunLoopModeExit) 363d676074dSJason Molenda { 364d676074dSJason Molenda switch (mode) 365d676074dSJason Molenda { 366d676074dSJason Molenda case eRNBRunLoopModeGetStartModeFromRemoteProtocol: 367d676074dSJason Molenda if (g_remoteSP->Comm().useFD(fd) == rnb_success) { 368d676074dSJason Molenda RNBLogSTDOUT("Starting remote data thread.\n"); 369d676074dSJason Molenda g_remoteSP->StartReadRemoteDataThread(); 370d676074dSJason Molenda 371d676074dSJason Molenda RNBLogSTDOUT("Waiting for start mode from remote.\n"); 372d676074dSJason Molenda mode = RNBRunLoopGetStartModeFromRemote(g_remoteSP); 373d676074dSJason Molenda } 374d676074dSJason Molenda else 375d676074dSJason Molenda { 376d676074dSJason Molenda mode = eRNBRunLoopModeExit; 377d676074dSJason Molenda } 378d676074dSJason Molenda break; 379d676074dSJason Molenda 380d676074dSJason Molenda case eRNBRunLoopModeInferiorExecuting: 381d676074dSJason Molenda mode = RNBRunLoopInferiorExecuting(g_remoteSP); 382d676074dSJason Molenda break; 383d676074dSJason Molenda 384d676074dSJason Molenda default: 385d676074dSJason Molenda mode = eRNBRunLoopModeExit; 386d676074dSJason Molenda break; 387d676074dSJason Molenda 388d676074dSJason Molenda case eRNBRunLoopModeExit: 389d676074dSJason Molenda break; 390d676074dSJason Molenda } 391d676074dSJason Molenda } 392d676074dSJason Molenda 393d676074dSJason Molenda g_remoteSP->StopReadRemoteDataThread (); 394d676074dSJason Molenda g_remoteSP->Context().SetProcessID(INVALID_NUB_PROCESS); 395d676074dSJason Molenda 396d676074dSJason Molenda return 0; 397d676074dSJason Molenda } 398