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