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