1 //===-- debugserver.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 #include <string> 18 #include <vector> 19 #include <asl.h> 20 #include <arpa/inet.h> 21 #include <netdb.h> 22 #include <netinet/in.h> 23 #include <netinet/tcp.h> 24 #include <sys/un.h> 25 #include <sys/types.h> 26 27 #include "CFString.h" 28 #include "DNB.h" 29 #include "DNBLog.h" 30 #include "DNBTimer.h" 31 #include "PseudoTerminal.h" 32 #include "RNBContext.h" 33 #include "RNBServices.h" 34 #include "RNBSocket.h" 35 #include "RNBRemote.h" 36 #include "SysSignal.h" 37 38 // Global PID in case we get a signal and need to stop the process... 39 nub_process_t g_pid = INVALID_NUB_PROCESS; 40 41 //---------------------------------------------------------------------- 42 // Run loop modes which determine which run loop function will be called 43 //---------------------------------------------------------------------- 44 typedef enum 45 { 46 eRNBRunLoopModeInvalid = 0, 47 eRNBRunLoopModeGetStartModeFromRemoteProtocol, 48 eRNBRunLoopModeInferiorAttaching, 49 eRNBRunLoopModeInferiorLaunching, 50 eRNBRunLoopModeInferiorExecuting, 51 eRNBRunLoopModePlatformMode, 52 eRNBRunLoopModeExit 53 } RNBRunLoopMode; 54 55 56 //---------------------------------------------------------------------- 57 // Global Variables 58 //---------------------------------------------------------------------- 59 RNBRemoteSP g_remoteSP; 60 static int g_lockdown_opt = 0; 61 static int g_applist_opt = 0; 62 static nub_launch_flavor_t g_launch_flavor = eLaunchFlavorDefault; 63 int g_disable_aslr = 0; 64 65 int g_isatty = 0; 66 bool g_detach_on_error = true; 67 68 #define RNBLogSTDOUT(fmt, ...) do { if (g_isatty) { fprintf(stdout, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0) 69 #define RNBLogSTDERR(fmt, ...) do { if (g_isatty) { fprintf(stderr, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0) 70 71 //---------------------------------------------------------------------- 72 // Get our program path and arguments from the remote connection. 73 // We will need to start up the remote connection without a PID, get the 74 // arguments, wait for the new process to finish launching and hit its 75 // entry point, and then return the run loop mode that should come next. 76 //---------------------------------------------------------------------- 77 RNBRunLoopMode 78 RNBRunLoopGetStartModeFromRemote (RNBRemote* remote) 79 { 80 std::string packet; 81 82 if (remote) 83 { 84 RNBContext& ctx = remote->Context(); 85 uint32_t event_mask = RNBContext::event_read_packet_available | 86 RNBContext::event_read_thread_exiting; 87 88 // Spin waiting to get the A packet. 89 while (1) 90 { 91 DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) ...",__FUNCTION__, event_mask); 92 nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); 93 DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) => 0x%08x", __FUNCTION__, event_mask, set_events); 94 95 if (set_events & RNBContext::event_read_thread_exiting) 96 { 97 RNBLogSTDERR ("error: packet read thread exited.\n"); 98 return eRNBRunLoopModeExit; 99 } 100 101 if (set_events & RNBContext::event_read_packet_available) 102 { 103 rnb_err_t err = rnb_err; 104 RNBRemote::PacketEnum type; 105 106 err = remote->HandleReceivedPacket (&type); 107 108 // check if we tried to attach to a process 109 if (type == RNBRemote::vattach || type == RNBRemote::vattachwait || type == RNBRemote::vattachorwait) 110 { 111 if (err == rnb_success) 112 { 113 RNBLogSTDOUT ("Attach succeeded, ready to debug.\n"); 114 return eRNBRunLoopModeInferiorExecuting; 115 } 116 else 117 { 118 RNBLogSTDERR ("error: attach failed.\n"); 119 return eRNBRunLoopModeExit; 120 } 121 } 122 123 if (err == rnb_success) 124 { 125 // If we got our arguments we are ready to launch using the arguments 126 // and any environment variables we received. 127 if (type == RNBRemote::set_argv) 128 { 129 return eRNBRunLoopModeInferiorLaunching; 130 } 131 } 132 else if (err == rnb_not_connected) 133 { 134 RNBLogSTDERR ("error: connection lost.\n"); 135 return eRNBRunLoopModeExit; 136 } 137 else 138 { 139 // a catch all for any other gdb remote packets that failed 140 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.",__FUNCTION__); 141 continue; 142 } 143 144 DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__); 145 } 146 else 147 { 148 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Connection closed before getting \"A\" packet.", __FUNCTION__); 149 return eRNBRunLoopModeExit; 150 } 151 } 152 } 153 return eRNBRunLoopModeExit; 154 } 155 156 157 //---------------------------------------------------------------------- 158 // This run loop mode will wait for the process to launch and hit its 159 // entry point. It will currently ignore all events except for the 160 // process state changed event, where it watches for the process stopped 161 // or crash process state. 162 //---------------------------------------------------------------------- 163 RNBRunLoopMode 164 RNBRunLoopLaunchInferior (RNBRemote *remote, const char *stdin_path, const char *stdout_path, const char *stderr_path, bool no_stdio) 165 { 166 RNBContext& ctx = remote->Context(); 167 168 // The Process stuff takes a c array, the RNBContext has a vector... 169 // So make up a c array. 170 171 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Launching '%s'...", __FUNCTION__, ctx.ArgumentAtIndex(0)); 172 173 size_t inferior_argc = ctx.ArgumentCount(); 174 // Initialize inferior_argv with inferior_argc + 1 NULLs 175 std::vector<const char *> inferior_argv(inferior_argc + 1, NULL); 176 177 size_t i; 178 for (i = 0; i < inferior_argc; i++) 179 inferior_argv[i] = ctx.ArgumentAtIndex(i); 180 181 // Pass the environment array the same way: 182 183 size_t inferior_envc = ctx.EnvironmentCount(); 184 // Initialize inferior_argv with inferior_argc + 1 NULLs 185 std::vector<const char *> inferior_envp(inferior_envc + 1, NULL); 186 187 for (i = 0; i < inferior_envc; i++) 188 inferior_envp[i] = ctx.EnvironmentAtIndex(i); 189 190 // Our launch type hasn't been set to anything concrete, so we need to 191 // figure our how we are going to launch automatically. 192 193 nub_launch_flavor_t launch_flavor = g_launch_flavor; 194 if (launch_flavor == eLaunchFlavorDefault) 195 { 196 // Our default launch method is posix spawn 197 launch_flavor = eLaunchFlavorPosixSpawn; 198 199 #ifdef WITH_SPRINGBOARD 200 // Check if we have an app bundle, if so launch using SpringBoard. 201 if (strstr(inferior_argv[0], ".app")) 202 { 203 launch_flavor = eLaunchFlavorSpringBoard; 204 } 205 #endif 206 } 207 208 ctx.SetLaunchFlavor(launch_flavor); 209 char resolved_path[PATH_MAX]; 210 211 // If we fail to resolve the path to our executable, then just use what we 212 // were given and hope for the best 213 if ( !DNBResolveExecutablePath (inferior_argv[0], resolved_path, sizeof(resolved_path)) ) 214 ::strncpy(resolved_path, inferior_argv[0], sizeof(resolved_path)); 215 216 char launch_err_str[PATH_MAX]; 217 launch_err_str[0] = '\0'; 218 const char * cwd = (ctx.GetWorkingDirPath() != NULL ? ctx.GetWorkingDirPath() 219 : ctx.GetWorkingDirectory()); 220 nub_process_t pid = DNBProcessLaunch (resolved_path, 221 &inferior_argv[0], 222 &inferior_envp[0], 223 cwd, 224 stdin_path, 225 stdout_path, 226 stderr_path, 227 no_stdio, 228 launch_flavor, 229 g_disable_aslr, 230 launch_err_str, 231 sizeof(launch_err_str)); 232 233 g_pid = pid; 234 235 if (pid == INVALID_NUB_PROCESS && strlen (launch_err_str) > 0) 236 { 237 DNBLogThreaded ("%s DNBProcessLaunch() returned error: '%s'", __FUNCTION__, launch_err_str); 238 ctx.LaunchStatus().SetError(-1, DNBError::Generic); 239 ctx.LaunchStatus().SetErrorString(launch_err_str); 240 } 241 else if (pid == INVALID_NUB_PROCESS) 242 { 243 DNBLogThreaded ("%s DNBProcessLaunch() failed to launch process, unknown failure", __FUNCTION__); 244 ctx.LaunchStatus().SetError(-1, DNBError::Generic); 245 ctx.LaunchStatus().SetErrorString(launch_err_str); 246 } 247 else 248 { 249 ctx.LaunchStatus().Clear(); 250 } 251 252 if (remote->Comm().IsConnected()) 253 { 254 // It we are connected already, the next thing gdb will do is ask 255 // whether the launch succeeded, and if not, whether there is an 256 // error code. So we need to fetch one packet from gdb before we wait 257 // on the stop from the target. 258 259 uint32_t event_mask = RNBContext::event_read_packet_available; 260 nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); 261 262 if (set_events & RNBContext::event_read_packet_available) 263 { 264 rnb_err_t err = rnb_err; 265 RNBRemote::PacketEnum type; 266 267 err = remote->HandleReceivedPacket (&type); 268 269 if (err != rnb_success) 270 { 271 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.", __FUNCTION__); 272 return eRNBRunLoopModeExit; 273 } 274 if (type != RNBRemote::query_launch_success) 275 { 276 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Didn't get the expected qLaunchSuccess packet.", __FUNCTION__); 277 } 278 } 279 } 280 281 while (pid != INVALID_NUB_PROCESS) 282 { 283 // Wait for process to start up and hit entry point 284 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE)...", __FUNCTION__, pid); 285 nub_event_t set_events = DNBProcessWaitForEvents (pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, NULL); 286 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE) => 0x%8.8x", __FUNCTION__, pid, set_events); 287 288 if (set_events == 0) 289 { 290 pid = INVALID_NUB_PROCESS; 291 g_pid = pid; 292 } 293 else 294 { 295 if (set_events & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged)) 296 { 297 nub_state_t pid_state = DNBProcessGetState (pid); 298 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s process %4.4x state changed (eEventProcessStateChanged): %s", __FUNCTION__, pid, DNBStateAsString(pid_state)); 299 300 switch (pid_state) 301 { 302 default: 303 case eStateInvalid: 304 case eStateUnloaded: 305 case eStateAttaching: 306 case eStateLaunching: 307 case eStateSuspended: 308 break; // Ignore 309 310 case eStateRunning: 311 case eStateStepping: 312 // Still waiting to stop at entry point... 313 break; 314 315 case eStateStopped: 316 case eStateCrashed: 317 ctx.SetProcessID(pid); 318 return eRNBRunLoopModeInferiorExecuting; 319 320 case eStateDetached: 321 case eStateExited: 322 pid = INVALID_NUB_PROCESS; 323 g_pid = pid; 324 return eRNBRunLoopModeExit; 325 } 326 } 327 328 DNBProcessResetEvents(pid, set_events); 329 } 330 } 331 332 return eRNBRunLoopModeExit; 333 } 334 335 336 //---------------------------------------------------------------------- 337 // This run loop mode will wait for the process to launch and hit its 338 // entry point. It will currently ignore all events except for the 339 // process state changed event, where it watches for the process stopped 340 // or crash process state. 341 //---------------------------------------------------------------------- 342 RNBRunLoopMode 343 RNBRunLoopLaunchAttaching (RNBRemote *remote, nub_process_t attach_pid, nub_process_t& pid) 344 { 345 RNBContext& ctx = remote->Context(); 346 347 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Attaching to pid %i...", __FUNCTION__, attach_pid); 348 char err_str[1024]; 349 pid = DNBProcessAttach (attach_pid, NULL, err_str, sizeof(err_str)); 350 g_pid = pid; 351 352 if (pid == INVALID_NUB_PROCESS) 353 { 354 ctx.LaunchStatus().SetError(-1, DNBError::Generic); 355 if (err_str[0]) 356 ctx.LaunchStatus().SetErrorString(err_str); 357 return eRNBRunLoopModeExit; 358 } 359 else 360 { 361 ctx.SetProcessID(pid); 362 return eRNBRunLoopModeInferiorExecuting; 363 } 364 } 365 366 //---------------------------------------------------------------------- 367 // Watch for signals: 368 // SIGINT: so we can halt our inferior. (disabled for now) 369 // SIGPIPE: in case our child process dies 370 //---------------------------------------------------------------------- 371 int g_sigint_received = 0; 372 int g_sigpipe_received = 0; 373 void 374 signal_handler(int signo) 375 { 376 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (%s)", __FUNCTION__, SysSignal::Name(signo)); 377 378 switch (signo) 379 { 380 case SIGINT: 381 g_sigint_received++; 382 if (g_pid != INVALID_NUB_PROCESS) 383 { 384 // Only send a SIGINT once... 385 if (g_sigint_received == 1) 386 { 387 switch (DNBProcessGetState (g_pid)) 388 { 389 case eStateRunning: 390 case eStateStepping: 391 DNBProcessSignal (g_pid, SIGSTOP); 392 return; 393 default: 394 break; 395 } 396 } 397 } 398 exit (SIGINT); 399 break; 400 401 case SIGPIPE: 402 g_sigpipe_received = 1; 403 break; 404 } 405 } 406 407 // Return the new run loop mode based off of the current process state 408 RNBRunLoopMode 409 HandleProcessStateChange (RNBRemote *remote, bool initialize) 410 { 411 RNBContext& ctx = remote->Context(); 412 nub_process_t pid = ctx.ProcessID(); 413 414 if (pid == INVALID_NUB_PROCESS) 415 { 416 DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s error: pid invalid, exiting...", __FUNCTION__); 417 return eRNBRunLoopModeExit; 418 } 419 nub_state_t pid_state = DNBProcessGetState (pid); 420 421 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state)); 422 423 switch (pid_state) 424 { 425 case eStateInvalid: 426 case eStateUnloaded: 427 // Something bad happened 428 return eRNBRunLoopModeExit; 429 break; 430 431 case eStateAttaching: 432 case eStateLaunching: 433 return eRNBRunLoopModeInferiorExecuting; 434 435 case eStateSuspended: 436 case eStateCrashed: 437 case eStateStopped: 438 // If we stop due to a signal, so clear the fact that we got a SIGINT 439 // so we can stop ourselves again (but only while our inferior 440 // process is running..) 441 g_sigint_received = 0; 442 if (initialize == false) 443 { 444 // Compare the last stop count to our current notion of a stop count 445 // to make sure we don't notify more than once for a given stop. 446 nub_size_t prev_pid_stop_count = ctx.GetProcessStopCount(); 447 bool pid_stop_count_changed = ctx.SetProcessStopCount(DNBProcessGetStopCount(pid)); 448 if (pid_stop_count_changed) 449 { 450 remote->FlushSTDIO(); 451 452 if (ctx.GetProcessStopCount() == 1) 453 { 454 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %llu (old %llu)) Notify??? no, first stop...", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), (uint64_t)ctx.GetProcessStopCount(), (uint64_t)prev_pid_stop_count); 455 } 456 else 457 { 458 459 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %llu (old %llu)) Notify??? YES!!!", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), (uint64_t)ctx.GetProcessStopCount(), (uint64_t)prev_pid_stop_count); 460 remote->NotifyThatProcessStopped (); 461 } 462 } 463 else 464 { 465 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %llu (old %llu)) Notify??? skipping...", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), (uint64_t)ctx.GetProcessStopCount(), (uint64_t)prev_pid_stop_count); 466 } 467 } 468 return eRNBRunLoopModeInferiorExecuting; 469 470 case eStateStepping: 471 case eStateRunning: 472 return eRNBRunLoopModeInferiorExecuting; 473 474 case eStateExited: 475 remote->HandlePacket_last_signal(NULL); 476 case eStateDetached: 477 return eRNBRunLoopModeExit; 478 479 } 480 481 // Catch all... 482 return eRNBRunLoopModeExit; 483 } 484 // This function handles the case where our inferior program is stopped and 485 // we are waiting for gdb remote protocol packets. When a packet occurs that 486 // makes the inferior run, we need to leave this function with a new state 487 // as the return code. 488 RNBRunLoopMode 489 RNBRunLoopInferiorExecuting (RNBRemote *remote) 490 { 491 DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__); 492 RNBContext& ctx = remote->Context(); 493 494 // Init our mode and set 'is_running' based on the current process state 495 RNBRunLoopMode mode = HandleProcessStateChange (remote, true); 496 497 while (ctx.ProcessID() != INVALID_NUB_PROCESS) 498 { 499 500 std::string set_events_str; 501 uint32_t event_mask = ctx.NormalEventBits(); 502 503 if (!ctx.ProcessStateRunning()) 504 { 505 // Clear some bits if we are not running so we don't send any async packets 506 event_mask &= ~RNBContext::event_proc_stdio_available; 507 event_mask &= ~RNBContext::event_proc_profile_data; 508 } 509 510 // We want to make sure we consume all process state changes and have 511 // whomever is notifying us to wait for us to reset the event bit before 512 // continuing. 513 //ctx.Events().SetResetAckMask (RNBContext::event_proc_state_changed); 514 515 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) ...",__FUNCTION__, event_mask); 516 nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); 517 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)); 518 519 if (set_events) 520 { 521 if ((set_events & RNBContext::event_proc_thread_exiting) || 522 (set_events & RNBContext::event_proc_stdio_available)) 523 { 524 remote->FlushSTDIO(); 525 } 526 527 if (set_events & RNBContext::event_proc_profile_data) 528 { 529 remote->SendAsyncProfileData(); 530 } 531 532 if (set_events & RNBContext::event_read_packet_available) 533 { 534 // handleReceivedPacket will take care of resetting the 535 // event_read_packet_available events when there are no more... 536 set_events ^= RNBContext::event_read_packet_available; 537 538 if (ctx.ProcessStateRunning()) 539 { 540 if (remote->HandleAsyncPacket() == rnb_not_connected) 541 { 542 // TODO: connect again? Exit? 543 } 544 } 545 else 546 { 547 if (remote->HandleReceivedPacket() == rnb_not_connected) 548 { 549 // TODO: connect again? Exit? 550 } 551 } 552 } 553 554 if (set_events & RNBContext::event_proc_state_changed) 555 { 556 mode = HandleProcessStateChange (remote, false); 557 ctx.Events().ResetEvents(RNBContext::event_proc_state_changed); 558 set_events ^= RNBContext::event_proc_state_changed; 559 } 560 561 if (set_events & RNBContext::event_proc_thread_exiting) 562 { 563 mode = eRNBRunLoopModeExit; 564 } 565 566 if (set_events & RNBContext::event_read_thread_exiting) 567 { 568 // Out remote packet receiving thread exited, exit for now. 569 if (ctx.HasValidProcessID()) 570 { 571 // TODO: We should add code that will leave the current process 572 // in its current state and listen for another connection... 573 if (ctx.ProcessStateRunning()) 574 { 575 if (ctx.GetDetachOnError()) 576 { 577 DNBLog ("debugserver's event read thread is exiting, detaching from the inferior process."); 578 DNBProcessDetach (ctx.ProcessID()); 579 } 580 else 581 { 582 DNBLog ("debugserver's event read thread is exiting, killing the inferior process."); 583 DNBProcessKill (ctx.ProcessID()); 584 } 585 } 586 else 587 { 588 if (ctx.GetDetachOnError()) 589 { 590 DNBLog ("debugserver's event read thread is exiting, detaching from the inferior process."); 591 DNBProcessDetach (ctx.ProcessID()); 592 } 593 } 594 } 595 mode = eRNBRunLoopModeExit; 596 } 597 } 598 599 // Reset all event bits that weren't reset for now... 600 if (set_events != 0) 601 ctx.Events().ResetEvents(set_events); 602 603 if (mode != eRNBRunLoopModeInferiorExecuting) 604 break; 605 } 606 607 return mode; 608 } 609 610 611 RNBRunLoopMode 612 RNBRunLoopPlatform (RNBRemote *remote) 613 { 614 RNBRunLoopMode mode = eRNBRunLoopModePlatformMode; 615 RNBContext& ctx = remote->Context(); 616 617 while (mode == eRNBRunLoopModePlatformMode) 618 { 619 std::string set_events_str; 620 const uint32_t event_mask = RNBContext::event_read_packet_available | 621 RNBContext::event_read_thread_exiting; 622 623 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) ...",__FUNCTION__, event_mask); 624 nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); 625 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)); 626 627 if (set_events) 628 { 629 if (set_events & RNBContext::event_read_packet_available) 630 { 631 if (remote->HandleReceivedPacket() == rnb_not_connected) 632 mode = eRNBRunLoopModeExit; 633 } 634 635 if (set_events & RNBContext::event_read_thread_exiting) 636 { 637 mode = eRNBRunLoopModeExit; 638 } 639 ctx.Events().ResetEvents(set_events); 640 } 641 } 642 return eRNBRunLoopModeExit; 643 } 644 645 //---------------------------------------------------------------------- 646 // Convenience function to set up the remote listening port 647 // Returns 1 for success 0 for failure. 648 //---------------------------------------------------------------------- 649 650 static void 651 PortWasBoundCallbackUnixSocket (const void *baton, in_port_t port) 652 { 653 //::printf ("PortWasBoundCallbackUnixSocket (baton = %p, port = %u)\n", baton, port); 654 655 const char *unix_socket_name = (const char *)baton; 656 657 if (unix_socket_name && unix_socket_name[0]) 658 { 659 // We were given a unix socket name to use to communicate the port 660 // that we ended up binding to back to our parent process 661 struct sockaddr_un saddr_un; 662 int s = ::socket (AF_UNIX, SOCK_STREAM, 0); 663 if (s < 0) 664 { 665 perror("error: socket (AF_UNIX, SOCK_STREAM, 0)"); 666 exit(1); 667 } 668 669 saddr_un.sun_family = AF_UNIX; 670 ::strncpy(saddr_un.sun_path, unix_socket_name, sizeof(saddr_un.sun_path) - 1); 671 saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0'; 672 saddr_un.sun_len = SUN_LEN (&saddr_un); 673 674 if (::connect (s, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0) 675 { 676 perror("error: connect (socket, &saddr_un, saddr_un_len)"); 677 exit(1); 678 } 679 680 //::printf ("connect () sucess!!\n"); 681 682 683 // We were able to connect to the socket, now write our PID so whomever 684 // launched us will know this process's ID 685 RNBLogSTDOUT ("Listening to port %i...\n", port); 686 687 char pid_str[64]; 688 const int pid_str_len = ::snprintf (pid_str, sizeof(pid_str), "%u", port); 689 const int bytes_sent = ::send (s, pid_str, pid_str_len, 0); 690 691 if (pid_str_len != bytes_sent) 692 { 693 perror("error: send (s, pid_str, pid_str_len, 0)"); 694 exit (1); 695 } 696 697 //::printf ("send () sucess!!\n"); 698 699 // We are done with the socket 700 close (s); 701 } 702 } 703 704 static void 705 PortWasBoundCallbackNamedPipe (const void *baton, uint16_t port) 706 { 707 const char *named_pipe = (const char *)baton; 708 if (named_pipe && named_pipe[0]) 709 { 710 int fd = ::open(named_pipe, O_WRONLY); 711 if (fd > -1) 712 { 713 char port_str[64]; 714 const ssize_t port_str_len = ::snprintf (port_str, sizeof(port_str), "%u", port); 715 // Write the port number as a C string with the NULL terminator 716 ::write (fd, port_str, port_str_len + 1); 717 close (fd); 718 } 719 } 720 } 721 722 static int 723 ConnectRemote (RNBRemote *remote, 724 const char *host, 725 int port, 726 bool reverse_connect, 727 const char *named_pipe_path, 728 const char *unix_socket_name) 729 { 730 if (!remote->Comm().IsConnected()) 731 { 732 if (reverse_connect) 733 { 734 if (port == 0) 735 { 736 DNBLogThreaded("error: invalid port supplied for reverse connection: %i.\n", port); 737 return 0; 738 } 739 if (remote->Comm().Connect(host, port) != rnb_success) 740 { 741 DNBLogThreaded("Failed to reverse connect to %s:%i.\n", host, port); 742 return 0; 743 } 744 } 745 else 746 { 747 if (port != 0) 748 RNBLogSTDOUT ("Listening to port %i for a connection from %s...\n", port, host ? host : "127.0.0.1"); 749 if (unix_socket_name && unix_socket_name[0]) 750 { 751 if (remote->Comm().Listen(host, port, PortWasBoundCallbackUnixSocket, unix_socket_name) != rnb_success) 752 { 753 RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n"); 754 return 0; 755 } 756 } 757 else 758 { 759 if (remote->Comm().Listen(host, port, PortWasBoundCallbackNamedPipe, named_pipe_path) != rnb_success) 760 { 761 RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n"); 762 return 0; 763 } 764 } 765 } 766 remote->StartReadRemoteDataThread(); 767 } 768 return 1; 769 } 770 771 //---------------------------------------------------------------------- 772 // ASL Logging callback that can be registered with DNBLogSetLogCallback 773 //---------------------------------------------------------------------- 774 void 775 ASLLogCallback(void *baton, uint32_t flags, const char *format, va_list args) 776 { 777 if (format == NULL) 778 return; 779 static aslmsg g_aslmsg = NULL; 780 if (g_aslmsg == NULL) 781 { 782 g_aslmsg = ::asl_new (ASL_TYPE_MSG); 783 char asl_key_sender[PATH_MAX]; 784 snprintf(asl_key_sender, sizeof(asl_key_sender), "com.apple.%s-%s", DEBUGSERVER_PROGRAM_NAME, DEBUGSERVER_VERSION_STR); 785 ::asl_set (g_aslmsg, ASL_KEY_SENDER, asl_key_sender); 786 } 787 788 int asl_level; 789 if (flags & DNBLOG_FLAG_FATAL) asl_level = ASL_LEVEL_CRIT; 790 else if (flags & DNBLOG_FLAG_ERROR) asl_level = ASL_LEVEL_ERR; 791 else if (flags & DNBLOG_FLAG_WARNING) asl_level = ASL_LEVEL_WARNING; 792 else if (flags & DNBLOG_FLAG_VERBOSE) asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_INFO; 793 else asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_DEBUG; 794 795 ::asl_vlog (NULL, g_aslmsg, asl_level, format, args); 796 } 797 798 //---------------------------------------------------------------------- 799 // FILE based Logging callback that can be registered with 800 // DNBLogSetLogCallback 801 //---------------------------------------------------------------------- 802 void 803 FileLogCallback(void *baton, uint32_t flags, const char *format, va_list args) 804 { 805 if (baton == NULL || format == NULL) 806 return; 807 808 ::vfprintf ((FILE *)baton, format, args); 809 ::fprintf ((FILE *)baton, "\n"); 810 } 811 812 813 void 814 show_usage_and_exit (int exit_code) 815 { 816 RNBLogSTDERR ("Usage:\n %s host:port [program-name program-arg1 program-arg2 ...]\n", DEBUGSERVER_PROGRAM_NAME); 817 RNBLogSTDERR (" %s /path/file [program-name program-arg1 program-arg2 ...]\n", DEBUGSERVER_PROGRAM_NAME); 818 RNBLogSTDERR (" %s host:port --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME); 819 RNBLogSTDERR (" %s /path/file --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME); 820 RNBLogSTDERR (" %s host:port --attach=<process_name>\n", DEBUGSERVER_PROGRAM_NAME); 821 RNBLogSTDERR (" %s /path/file --attach=<process_name>\n", DEBUGSERVER_PROGRAM_NAME); 822 exit (exit_code); 823 } 824 825 826 //---------------------------------------------------------------------- 827 // option descriptors for getopt_long_only() 828 //---------------------------------------------------------------------- 829 static struct option g_long_options[] = 830 { 831 { "attach", required_argument, NULL, 'a' }, 832 { "arch", required_argument, NULL, 'A' }, 833 { "debug", no_argument, NULL, 'g' }, 834 { "kill-on-error", no_argument, NULL, 'K' }, 835 { "verbose", no_argument, NULL, 'v' }, 836 { "lockdown", no_argument, &g_lockdown_opt, 1 }, // short option "-k" 837 { "applist", no_argument, &g_applist_opt, 1 }, // short option "-t" 838 { "log-file", required_argument, NULL, 'l' }, 839 { "log-flags", required_argument, NULL, 'f' }, 840 { "launch", required_argument, NULL, 'x' }, // Valid values are "auto", "posix-spawn", "fork-exec", "springboard" (arm only) 841 { "waitfor", required_argument, NULL, 'w' }, // Wait for a process whose name starts with ARG 842 { "waitfor-interval", required_argument, NULL, 'i' }, // Time in usecs to wait between sampling the pid list when waiting for a process by name 843 { "waitfor-duration", required_argument, NULL, 'd' }, // The time in seconds to wait for a process to show up by name 844 { "native-regs", no_argument, NULL, 'r' }, // Specify to use the native registers instead of the gdb defaults for the architecture. 845 { "stdio-path", required_argument, NULL, 's' }, // Set the STDIO path to be used when launching applications (STDIN, STDOUT and STDERR) (only if debugserver launches the process) 846 { "stdin-path", required_argument, NULL, 'I' }, // Set the STDIN path to be used when launching applications (only if debugserver launches the process) 847 { "stdout-path", required_argument, NULL, 'O' }, // Set the STDOUT path to be used when launching applications (only if debugserver launches the process) 848 { "stderr-path", required_argument, NULL, 'E' }, // Set the STDERR path to be used when launching applications (only if debugserver launches the process) 849 { "no-stdio", no_argument, NULL, 'n' }, // Do not set up any stdio (perhaps the program is a GUI program) (only if debugserver launches the process) 850 { "setsid", no_argument, NULL, 'S' }, // call setsid() to make debugserver run in its own session 851 { "disable-aslr", no_argument, NULL, 'D' }, // Use _POSIX_SPAWN_DISABLE_ASLR to avoid shared library randomization 852 { "working-dir", required_argument, NULL, 'W' }, // The working directory that the inferior process should have (only if debugserver launches the process) 853 { "platform", required_argument, NULL, 'p' }, // Put this executable into a remote platform mode 854 { "unix-socket", required_argument, NULL, 'u' }, // If we need to handshake with our parent process, an option will be passed down that specifies a unix socket name to use 855 { "named-pipe", required_argument, NULL, 'P' }, 856 { "reverse-connect", no_argument, NULL, 'R' }, 857 { NULL, 0, NULL, 0 } 858 }; 859 860 861 //---------------------------------------------------------------------- 862 // main 863 //---------------------------------------------------------------------- 864 int 865 main (int argc, char *argv[]) 866 { 867 const char *argv_sub_zero = argv[0]; // save a copy of argv[0] for error reporting post-launch 868 869 g_isatty = ::isatty (STDIN_FILENO); 870 871 // ::printf ("uid=%u euid=%u gid=%u egid=%u\n", 872 // getuid(), 873 // geteuid(), 874 // getgid(), 875 // getegid()); 876 877 878 // signal (SIGINT, signal_handler); 879 signal (SIGPIPE, signal_handler); 880 signal (SIGHUP, signal_handler); 881 882 g_remoteSP.reset (new RNBRemote ()); 883 884 885 RNBRemote *remote = g_remoteSP.get(); 886 if (remote == NULL) 887 { 888 RNBLogSTDERR ("error: failed to create a remote connection class\n"); 889 return -1; 890 } 891 892 RNBContext& ctx = remote->Context(); 893 894 int i; 895 int attach_pid = INVALID_NUB_PROCESS; 896 897 FILE* log_file = NULL; 898 uint32_t log_flags = 0; 899 // Parse our options 900 int ch; 901 int long_option_index = 0; 902 int debug = 0; 903 std::string compile_options; 904 std::string waitfor_pid_name; // Wait for a process that starts with this name 905 std::string attach_pid_name; 906 std::string arch_name; 907 std::string working_dir; // The new working directory to use for the inferior 908 std::string unix_socket_name; // If we need to handshake with our parent process, an option will be passed down that specifies a unix socket name to use 909 std::string named_pipe_path; // If we need to handshake with our parent process, an option will be passed down that specifies a named pipe to use 910 useconds_t waitfor_interval = 1000; // Time in usecs between process lists polls when waiting for a process by name, default 1 msec. 911 useconds_t waitfor_duration = 0; // Time in seconds to wait for a process by name, 0 means wait forever. 912 bool no_stdio = false; 913 bool reverse_connect = false; // Set to true by an option to indicate we should reverse connect to the host:port supplied as the first debugserver argument 914 915 #if !defined (DNBLOG_ENABLED) 916 compile_options += "(no-logging) "; 917 #endif 918 919 RNBRunLoopMode start_mode = eRNBRunLoopModeExit; 920 921 char short_options[512]; 922 uint32_t short_options_idx = 0; 923 924 // Handle the two case that don't have short options in g_long_options 925 short_options[short_options_idx++] = 'k'; 926 short_options[short_options_idx++] = 't'; 927 928 for (i=0; g_long_options[i].name != NULL; ++i) 929 { 930 if (isalpha(g_long_options[i].val)) 931 { 932 short_options[short_options_idx++] = g_long_options[i].val; 933 switch (g_long_options[i].has_arg) 934 { 935 default: 936 case no_argument: 937 break; 938 939 case optional_argument: 940 short_options[short_options_idx++] = ':'; 941 // Fall through to required_argument case below... 942 case required_argument: 943 short_options[short_options_idx++] = ':'; 944 break; 945 } 946 } 947 } 948 // NULL terminate the short option string. 949 short_options[short_options_idx++] = '\0'; 950 951 #if __GLIBC__ 952 optind = 0; 953 #else 954 optreset = 1; 955 optind = 1; 956 #endif 957 958 while ((ch = getopt_long_only(argc, argv, short_options, g_long_options, &long_option_index)) != -1) 959 { 960 DNBLogDebug("option: ch == %c (0x%2.2x) --%s%c%s\n", 961 ch, (uint8_t)ch, 962 g_long_options[long_option_index].name, 963 g_long_options[long_option_index].has_arg ? '=' : ' ', 964 optarg ? optarg : ""); 965 switch (ch) 966 { 967 case 0: // Any optional that auto set themselves will return 0 968 break; 969 970 case 'A': 971 if (optarg && optarg[0]) 972 arch_name.assign(optarg); 973 break; 974 975 case 'a': 976 if (optarg && optarg[0]) 977 { 978 if (isdigit(optarg[0])) 979 { 980 char *end = NULL; 981 attach_pid = strtoul(optarg, &end, 0); 982 if (end == NULL || *end != '\0') 983 { 984 RNBLogSTDERR ("error: invalid pid option '%s'\n", optarg); 985 exit (4); 986 } 987 } 988 else 989 { 990 attach_pid_name = optarg; 991 } 992 start_mode = eRNBRunLoopModeInferiorAttaching; 993 } 994 break; 995 996 // --waitfor=NAME 997 case 'w': 998 if (optarg && optarg[0]) 999 { 1000 waitfor_pid_name = optarg; 1001 start_mode = eRNBRunLoopModeInferiorAttaching; 1002 } 1003 break; 1004 1005 // --waitfor-interval=USEC 1006 case 'i': 1007 if (optarg && optarg[0]) 1008 { 1009 char *end = NULL; 1010 waitfor_interval = strtoul(optarg, &end, 0); 1011 if (end == NULL || *end != '\0') 1012 { 1013 RNBLogSTDERR ("error: invalid waitfor-interval option value '%s'.\n", optarg); 1014 exit (6); 1015 } 1016 } 1017 break; 1018 1019 // --waitfor-duration=SEC 1020 case 'd': 1021 if (optarg && optarg[0]) 1022 { 1023 char *end = NULL; 1024 waitfor_duration = strtoul(optarg, &end, 0); 1025 if (end == NULL || *end != '\0') 1026 { 1027 RNBLogSTDERR ("error: invalid waitfor-duration option value '%s'.\n", optarg); 1028 exit (7); 1029 } 1030 } 1031 break; 1032 1033 case 'K': 1034 g_detach_on_error = false; 1035 1036 case 'W': 1037 if (optarg && optarg[0]) 1038 working_dir.assign(optarg); 1039 break; 1040 1041 case 'x': 1042 if (optarg && optarg[0]) 1043 { 1044 if (strcasecmp(optarg, "auto") == 0) 1045 g_launch_flavor = eLaunchFlavorDefault; 1046 else if (strcasestr(optarg, "posix") == optarg) 1047 g_launch_flavor = eLaunchFlavorPosixSpawn; 1048 else if (strcasestr(optarg, "fork") == optarg) 1049 g_launch_flavor = eLaunchFlavorForkExec; 1050 #ifdef WITH_SPRINGBOARD 1051 else if (strcasestr(optarg, "spring") == optarg) 1052 g_launch_flavor = eLaunchFlavorSpringBoard; 1053 #endif 1054 else 1055 { 1056 RNBLogSTDERR ("error: invalid TYPE for the --launch=TYPE (-x TYPE) option: '%s'\n", optarg); 1057 RNBLogSTDERR ("Valid values TYPE are:\n"); 1058 RNBLogSTDERR (" auto Auto-detect the best launch method to use.\n"); 1059 RNBLogSTDERR (" posix Launch the executable using posix_spawn.\n"); 1060 RNBLogSTDERR (" fork Launch the executable using fork and exec.\n"); 1061 #ifdef WITH_SPRINGBOARD 1062 RNBLogSTDERR (" spring Launch the executable through Springboard.\n"); 1063 #endif 1064 exit (5); 1065 } 1066 } 1067 break; 1068 1069 case 'l': // Set Log File 1070 if (optarg && optarg[0]) 1071 { 1072 if (strcasecmp(optarg, "stdout") == 0) 1073 log_file = stdout; 1074 else if (strcasecmp(optarg, "stderr") == 0) 1075 log_file = stderr; 1076 else 1077 { 1078 log_file = fopen(optarg, "w"); 1079 if (log_file != NULL) 1080 setlinebuf(log_file); 1081 } 1082 1083 if (log_file == NULL) 1084 { 1085 const char *errno_str = strerror(errno); 1086 RNBLogSTDERR ("Failed to open log file '%s' for writing: errno = %i (%s)", optarg, errno, errno_str ? errno_str : "unknown error"); 1087 } 1088 } 1089 break; 1090 1091 case 'f': // Log Flags 1092 if (optarg && optarg[0]) 1093 log_flags = strtoul(optarg, NULL, 0); 1094 break; 1095 1096 case 'g': 1097 debug = 1; 1098 DNBLogSetDebug(debug); 1099 break; 1100 1101 case 't': 1102 g_applist_opt = 1; 1103 break; 1104 1105 case 'k': 1106 g_lockdown_opt = 1; 1107 break; 1108 1109 case 'r': 1110 // Do nothing, native regs is the default these days 1111 break; 1112 1113 case 'R': 1114 reverse_connect = true; 1115 break; 1116 case 'v': 1117 DNBLogSetVerbose(1); 1118 break; 1119 1120 case 's': 1121 ctx.GetSTDIN().assign(optarg); 1122 ctx.GetSTDOUT().assign(optarg); 1123 ctx.GetSTDERR().assign(optarg); 1124 break; 1125 1126 case 'I': 1127 ctx.GetSTDIN().assign(optarg); 1128 break; 1129 1130 case 'O': 1131 ctx.GetSTDOUT().assign(optarg); 1132 break; 1133 1134 case 'E': 1135 ctx.GetSTDERR().assign(optarg); 1136 break; 1137 1138 case 'n': 1139 no_stdio = true; 1140 break; 1141 1142 case 'S': 1143 // Put debugserver into a new session. Terminals group processes 1144 // into sessions and when a special terminal key sequences 1145 // (like control+c) are typed they can cause signals to go out to 1146 // all processes in a session. Using this --setsid (-S) option 1147 // will cause debugserver to run in its own sessions and be free 1148 // from such issues. 1149 // 1150 // This is useful when debugserver is spawned from a command 1151 // line application that uses debugserver to do the debugging, 1152 // yet that application doesn't want debugserver receiving the 1153 // signals sent to the session (i.e. dying when anyone hits ^C). 1154 setsid(); 1155 break; 1156 case 'D': 1157 g_disable_aslr = 1; 1158 break; 1159 1160 case 'p': 1161 start_mode = eRNBRunLoopModePlatformMode; 1162 break; 1163 1164 case 'u': 1165 unix_socket_name.assign (optarg); 1166 break; 1167 1168 case 'P': 1169 named_pipe_path.assign (optarg); 1170 break; 1171 1172 } 1173 } 1174 1175 if (arch_name.empty()) 1176 { 1177 #if defined (__arm__) 1178 arch_name.assign ("arm"); 1179 #endif 1180 } 1181 else 1182 { 1183 DNBSetArchitecture (arch_name.c_str()); 1184 } 1185 1186 // if (arch_name.empty()) 1187 // { 1188 // fprintf(stderr, "error: no architecture was specified\n"); 1189 // exit (8); 1190 // } 1191 // Skip any options we consumed with getopt_long_only 1192 argc -= optind; 1193 argv += optind; 1194 1195 1196 if (!working_dir.empty()) 1197 { 1198 if (remote->Context().SetWorkingDirectory (working_dir.c_str()) == false) 1199 { 1200 RNBLogSTDERR ("error: working directory doesn't exist '%s'.\n", working_dir.c_str()); 1201 exit (8); 1202 } 1203 } 1204 1205 remote->Context().SetDetachOnError(g_detach_on_error); 1206 1207 remote->Initialize(); 1208 1209 // It is ok for us to set NULL as the logfile (this will disable any logging) 1210 1211 if (log_file != NULL) 1212 { 1213 DNBLogSetLogCallback(FileLogCallback, log_file); 1214 // If our log file was set, yet we have no log flags, log everything! 1215 if (log_flags == 0) 1216 log_flags = LOG_ALL | LOG_RNB_ALL; 1217 1218 DNBLogSetLogMask (log_flags); 1219 } 1220 else 1221 { 1222 // Enable DNB logging 1223 DNBLogSetLogCallback(ASLLogCallback, NULL); 1224 DNBLogSetLogMask (log_flags); 1225 1226 } 1227 1228 if (DNBLogEnabled()) 1229 { 1230 for (i=0; i<argc; i++) 1231 DNBLogDebug("argv[%i] = %s", i, argv[i]); 1232 } 1233 1234 // as long as we're dropping remotenub in as a replacement for gdbserver, 1235 // explicitly note that this is not gdbserver. 1236 1237 RNBLogSTDOUT ("%s-%s %sfor %s.\n", 1238 DEBUGSERVER_PROGRAM_NAME, 1239 DEBUGSERVER_VERSION_STR, 1240 compile_options.c_str(), 1241 RNB_ARCH); 1242 1243 std::string host; 1244 int port = INT32_MAX; 1245 char str[PATH_MAX]; 1246 str[0] = '\0'; 1247 1248 if (g_lockdown_opt == 0 && g_applist_opt == 0) 1249 { 1250 // Make sure we at least have port 1251 if (argc < 1) 1252 { 1253 show_usage_and_exit (1); 1254 } 1255 // accept 'localhost:' prefix on port number 1256 1257 int items_scanned = ::sscanf (argv[0], "%[^:]:%i", str, &port); 1258 if (items_scanned == 2) 1259 { 1260 host = str; 1261 DNBLogDebug("host = '%s' port = %i", host.c_str(), port); 1262 } 1263 else 1264 { 1265 // No hostname means "localhost" 1266 int items_scanned = ::sscanf (argv[0], "%i", &port); 1267 if (items_scanned == 1) 1268 { 1269 host = "127.0.0.1"; 1270 DNBLogDebug("host = '%s' port = %i", host.c_str(), port); 1271 } 1272 else if (argv[0][0] == '/') 1273 { 1274 port = INT32_MAX; 1275 strncpy(str, argv[0], sizeof(str)); 1276 } 1277 else 1278 { 1279 show_usage_and_exit (2); 1280 } 1281 } 1282 1283 // We just used the 'host:port' or the '/path/file' arg... 1284 argc--; 1285 argv++; 1286 1287 } 1288 1289 // If we know we're waiting to attach, we don't need any of this other info. 1290 if (start_mode != eRNBRunLoopModeInferiorAttaching && 1291 start_mode != eRNBRunLoopModePlatformMode) 1292 { 1293 if (argc == 0 || g_lockdown_opt) 1294 { 1295 if (g_lockdown_opt != 0) 1296 { 1297 // Work around for SIGPIPE crashes due to posix_spawn issue. 1298 // We have to close STDOUT and STDERR, else the first time we 1299 // try and do any, we get SIGPIPE and die as posix_spawn is 1300 // doing bad things with our file descriptors at the moment. 1301 int null = open("/dev/null", O_RDWR); 1302 dup2(null, STDOUT_FILENO); 1303 dup2(null, STDERR_FILENO); 1304 } 1305 else if (g_applist_opt != 0) 1306 { 1307 // List all applications we are able to see 1308 std::string applist_plist; 1309 int err = ListApplications(applist_plist, false, false); 1310 if (err == 0) 1311 { 1312 fputs (applist_plist.c_str(), stdout); 1313 } 1314 else 1315 { 1316 RNBLogSTDERR ("error: ListApplications returned error %i\n", err); 1317 } 1318 // Exit with appropriate error if we were asked to list the applications 1319 // with no other args were given (and we weren't trying to do this over 1320 // lockdown) 1321 return err; 1322 } 1323 1324 DNBLogDebug("Get args from remote protocol..."); 1325 start_mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol; 1326 } 1327 else 1328 { 1329 start_mode = eRNBRunLoopModeInferiorLaunching; 1330 // Fill in the argv array in the context from the rest of our args. 1331 // Skip the name of this executable and the port number 1332 for (int i = 0; i < argc; i++) 1333 { 1334 DNBLogDebug("inferior_argv[%i] = '%s'", i, argv[i]); 1335 ctx.PushArgument (argv[i]); 1336 } 1337 } 1338 } 1339 1340 if (start_mode == eRNBRunLoopModeExit) 1341 return -1; 1342 1343 RNBRunLoopMode mode = start_mode; 1344 char err_str[1024] = {'\0'}; 1345 1346 while (mode != eRNBRunLoopModeExit) 1347 { 1348 switch (mode) 1349 { 1350 case eRNBRunLoopModeGetStartModeFromRemoteProtocol: 1351 #ifdef WITH_LOCKDOWN 1352 if (g_lockdown_opt) 1353 { 1354 if (!remote->Comm().IsConnected()) 1355 { 1356 if (remote->Comm().ConnectToService () != rnb_success) 1357 { 1358 RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n"); 1359 mode = eRNBRunLoopModeExit; 1360 } 1361 else if (g_applist_opt != 0) 1362 { 1363 // List all applications we are able to see 1364 std::string applist_plist; 1365 if (ListApplications(applist_plist, false, false) == 0) 1366 { 1367 DNBLogDebug("Task list: %s", applist_plist.c_str()); 1368 1369 remote->Comm().Write(applist_plist.c_str(), applist_plist.size()); 1370 // Issue a read that will never yield any data until the other side 1371 // closes the socket so this process doesn't just exit and cause the 1372 // socket to close prematurely on the other end and cause data loss. 1373 std::string buf; 1374 remote->Comm().Read(buf); 1375 } 1376 remote->Comm().Disconnect(false); 1377 mode = eRNBRunLoopModeExit; 1378 break; 1379 } 1380 else 1381 { 1382 // Start watching for remote packets 1383 remote->StartReadRemoteDataThread(); 1384 } 1385 } 1386 } 1387 else 1388 #endif 1389 if (port != INT32_MAX) 1390 { 1391 if (!ConnectRemote (remote, host.c_str(), port, reverse_connect, named_pipe_path.c_str(), unix_socket_name.c_str())) 1392 mode = eRNBRunLoopModeExit; 1393 } 1394 else if (str[0] == '/') 1395 { 1396 if (remote->Comm().OpenFile (str)) 1397 mode = eRNBRunLoopModeExit; 1398 } 1399 1400 if (mode != eRNBRunLoopModeExit) 1401 { 1402 RNBLogSTDOUT ("Got a connection, waiting for process information for launching or attaching.\n"); 1403 1404 mode = RNBRunLoopGetStartModeFromRemote (remote); 1405 } 1406 break; 1407 1408 case eRNBRunLoopModeInferiorAttaching: 1409 if (!waitfor_pid_name.empty()) 1410 { 1411 // Set our end wait time if we are using a waitfor-duration 1412 // option that may have been specified 1413 struct timespec attach_timeout_abstime, *timeout_ptr = NULL; 1414 if (waitfor_duration != 0) 1415 { 1416 DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0); 1417 timeout_ptr = &attach_timeout_abstime; 1418 } 1419 nub_launch_flavor_t launch_flavor = g_launch_flavor; 1420 if (launch_flavor == eLaunchFlavorDefault) 1421 { 1422 // Our default launch method is posix spawn 1423 launch_flavor = eLaunchFlavorPosixSpawn; 1424 1425 #ifdef WITH_SPRINGBOARD 1426 // Check if we have an app bundle, if so launch using SpringBoard. 1427 if (waitfor_pid_name.find (".app") != std::string::npos) 1428 { 1429 launch_flavor = eLaunchFlavorSpringBoard; 1430 } 1431 #endif 1432 } 1433 1434 ctx.SetLaunchFlavor(launch_flavor); 1435 bool ignore_existing = false; 1436 RNBLogSTDOUT ("Waiting to attach to process %s...\n", waitfor_pid_name.c_str()); 1437 nub_process_t pid = DNBProcessAttachWait (waitfor_pid_name.c_str(), launch_flavor, ignore_existing, timeout_ptr, waitfor_interval, err_str, sizeof(err_str)); 1438 g_pid = pid; 1439 1440 if (pid == INVALID_NUB_PROCESS) 1441 { 1442 ctx.LaunchStatus().SetError(-1, DNBError::Generic); 1443 if (err_str[0]) 1444 ctx.LaunchStatus().SetErrorString(err_str); 1445 RNBLogSTDERR ("error: failed to attach to process named: \"%s\" %s\n", waitfor_pid_name.c_str(), err_str); 1446 mode = eRNBRunLoopModeExit; 1447 } 1448 else 1449 { 1450 ctx.SetProcessID(pid); 1451 mode = eRNBRunLoopModeInferiorExecuting; 1452 } 1453 } 1454 else if (attach_pid != INVALID_NUB_PROCESS) 1455 { 1456 1457 RNBLogSTDOUT ("Attaching to process %i...\n", attach_pid); 1458 nub_process_t attached_pid; 1459 mode = RNBRunLoopLaunchAttaching (remote, attach_pid, attached_pid); 1460 if (mode != eRNBRunLoopModeInferiorExecuting) 1461 { 1462 const char *error_str = remote->Context().LaunchStatus().AsString(); 1463 RNBLogSTDERR ("error: failed to attach process %i: %s\n", attach_pid, error_str ? error_str : "unknown error."); 1464 mode = eRNBRunLoopModeExit; 1465 } 1466 } 1467 else if (!attach_pid_name.empty ()) 1468 { 1469 struct timespec attach_timeout_abstime, *timeout_ptr = NULL; 1470 if (waitfor_duration != 0) 1471 { 1472 DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0); 1473 timeout_ptr = &attach_timeout_abstime; 1474 } 1475 1476 RNBLogSTDOUT ("Attaching to process %s...\n", attach_pid_name.c_str()); 1477 nub_process_t pid = DNBProcessAttachByName (attach_pid_name.c_str(), timeout_ptr, err_str, sizeof(err_str)); 1478 g_pid = pid; 1479 if (pid == INVALID_NUB_PROCESS) 1480 { 1481 ctx.LaunchStatus().SetError(-1, DNBError::Generic); 1482 if (err_str[0]) 1483 ctx.LaunchStatus().SetErrorString(err_str); 1484 RNBLogSTDERR ("error: failed to attach to process named: \"%s\" %s\n", waitfor_pid_name.c_str(), err_str); 1485 mode = eRNBRunLoopModeExit; 1486 } 1487 else 1488 { 1489 ctx.SetProcessID(pid); 1490 mode = eRNBRunLoopModeInferiorExecuting; 1491 } 1492 1493 } 1494 else 1495 { 1496 RNBLogSTDERR ("error: asked to attach with empty name and invalid PID.\n"); 1497 mode = eRNBRunLoopModeExit; 1498 } 1499 1500 if (mode != eRNBRunLoopModeExit) 1501 { 1502 if (port != INT32_MAX) 1503 { 1504 if (!ConnectRemote (remote, host.c_str(), port, reverse_connect, named_pipe_path.c_str(), unix_socket_name.c_str())) 1505 mode = eRNBRunLoopModeExit; 1506 } 1507 else if (str[0] == '/') 1508 { 1509 if (remote->Comm().OpenFile (str)) 1510 mode = eRNBRunLoopModeExit; 1511 } 1512 if (mode != eRNBRunLoopModeExit) 1513 RNBLogSTDOUT ("Waiting for debugger instructions for process %d.\n", attach_pid); 1514 } 1515 break; 1516 1517 case eRNBRunLoopModeInferiorLaunching: 1518 { 1519 mode = RNBRunLoopLaunchInferior (remote, 1520 ctx.GetSTDINPath(), 1521 ctx.GetSTDOUTPath(), 1522 ctx.GetSTDERRPath(), 1523 no_stdio); 1524 1525 if (mode == eRNBRunLoopModeInferiorExecuting) 1526 { 1527 if (port != INT32_MAX) 1528 { 1529 if (!ConnectRemote (remote, host.c_str(), port, reverse_connect, named_pipe_path.c_str(), unix_socket_name.c_str())) 1530 mode = eRNBRunLoopModeExit; 1531 } 1532 else if (str[0] == '/') 1533 { 1534 if (remote->Comm().OpenFile (str)) 1535 mode = eRNBRunLoopModeExit; 1536 } 1537 1538 if (mode != eRNBRunLoopModeExit) 1539 { 1540 const char *proc_name = "<unknown>"; 1541 if (ctx.ArgumentCount() > 0) 1542 proc_name = ctx.ArgumentAtIndex(0); 1543 RNBLogSTDOUT ("Got a connection, launched process %s (pid = %d).\n", proc_name, ctx.ProcessID()); 1544 } 1545 } 1546 else 1547 { 1548 const char *error_str = remote->Context().LaunchStatus().AsString(); 1549 RNBLogSTDERR ("error: failed to launch process %s: %s\n", argv_sub_zero, error_str ? error_str : "unknown error."); 1550 } 1551 } 1552 break; 1553 1554 case eRNBRunLoopModeInferiorExecuting: 1555 mode = RNBRunLoopInferiorExecuting(remote); 1556 break; 1557 1558 case eRNBRunLoopModePlatformMode: 1559 if (port != INT32_MAX) 1560 { 1561 if (!ConnectRemote (remote, host.c_str(), port, reverse_connect, named_pipe_path.c_str(), unix_socket_name.c_str())) 1562 mode = eRNBRunLoopModeExit; 1563 } 1564 else if (str[0] == '/') 1565 { 1566 if (remote->Comm().OpenFile (str)) 1567 mode = eRNBRunLoopModeExit; 1568 } 1569 1570 if (mode != eRNBRunLoopModeExit) 1571 mode = RNBRunLoopPlatform (remote); 1572 break; 1573 1574 default: 1575 mode = eRNBRunLoopModeExit; 1576 case eRNBRunLoopModeExit: 1577 break; 1578 } 1579 } 1580 1581 remote->StopReadRemoteDataThread (); 1582 remote->Context().SetProcessID(INVALID_NUB_PROCESS); 1583 RNBLogSTDOUT ("Exiting.\n"); 1584 1585 return 0; 1586 } 1587