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