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