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