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 ::strncpy(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 ::strncpy(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 'FDSC'}, // 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 while ((ch = getopt_long_only(argc, argv, short_options, g_long_options, 1024 &long_option_index)) != -1) { 1025 DNBLogDebug("option: ch == %c (0x%2.2x) --%s%c%s\n", ch, (uint8_t)ch, 1026 g_long_options[long_option_index].name, 1027 g_long_options[long_option_index].has_arg ? '=' : ' ', 1028 optarg ? optarg : ""); 1029 switch (ch) { 1030 case 0: // Any optional that auto set themselves will return 0 1031 break; 1032 1033 case 'A': 1034 if (optarg && optarg[0]) 1035 arch_name.assign(optarg); 1036 break; 1037 1038 case 'a': 1039 if (optarg && optarg[0]) { 1040 if (isdigit(optarg[0])) { 1041 char *end = NULL; 1042 attach_pid = static_cast<int>(strtoul(optarg, &end, 0)); 1043 if (end == NULL || *end != '\0') { 1044 RNBLogSTDERR("error: invalid pid option '%s'\n", optarg); 1045 exit(4); 1046 } 1047 } else { 1048 attach_pid_name = optarg; 1049 } 1050 start_mode = eRNBRunLoopModeInferiorAttaching; 1051 } 1052 break; 1053 1054 // --waitfor=NAME 1055 case 'w': 1056 if (optarg && optarg[0]) { 1057 waitfor_pid_name = optarg; 1058 start_mode = eRNBRunLoopModeInferiorAttaching; 1059 } 1060 break; 1061 1062 // --waitfor-interval=USEC 1063 case 'i': 1064 if (optarg && optarg[0]) { 1065 char *end = NULL; 1066 waitfor_interval = static_cast<useconds_t>(strtoul(optarg, &end, 0)); 1067 if (end == NULL || *end != '\0') { 1068 RNBLogSTDERR("error: invalid waitfor-interval option value '%s'.\n", 1069 optarg); 1070 exit(6); 1071 } 1072 } 1073 break; 1074 1075 // --waitfor-duration=SEC 1076 case 'd': 1077 if (optarg && optarg[0]) { 1078 char *end = NULL; 1079 waitfor_duration = static_cast<useconds_t>(strtoul(optarg, &end, 0)); 1080 if (end == NULL || *end != '\0') { 1081 RNBLogSTDERR("error: invalid waitfor-duration option value '%s'.\n", 1082 optarg); 1083 exit(7); 1084 } 1085 } 1086 break; 1087 1088 case 'K': 1089 g_detach_on_error = false; 1090 break; 1091 case 'W': 1092 if (optarg && optarg[0]) 1093 working_dir.assign(optarg); 1094 break; 1095 1096 case 'x': 1097 if (optarg && optarg[0]) { 1098 if (strcasecmp(optarg, "auto") == 0) 1099 g_launch_flavor = eLaunchFlavorDefault; 1100 else if (strcasestr(optarg, "posix") == optarg) 1101 g_launch_flavor = eLaunchFlavorPosixSpawn; 1102 else if (strcasestr(optarg, "fork") == optarg) 1103 g_launch_flavor = eLaunchFlavorForkExec; 1104 #ifdef WITH_SPRINGBOARD 1105 else if (strcasestr(optarg, "spring") == optarg) 1106 g_launch_flavor = eLaunchFlavorSpringBoard; 1107 #endif 1108 #ifdef WITH_BKS 1109 else if (strcasestr(optarg, "backboard") == optarg) 1110 g_launch_flavor = eLaunchFlavorBKS; 1111 #endif 1112 #ifdef WITH_FBS 1113 else if (strcasestr(optarg, "frontboard") == optarg) 1114 g_launch_flavor = eLaunchFlavorFBS; 1115 #endif 1116 1117 else { 1118 RNBLogSTDERR("error: invalid TYPE for the --launch=TYPE (-x TYPE) " 1119 "option: '%s'\n", 1120 optarg); 1121 RNBLogSTDERR("Valid values TYPE are:\n"); 1122 RNBLogSTDERR( 1123 " auto Auto-detect the best launch method to use.\n"); 1124 RNBLogSTDERR( 1125 " posix Launch the executable using posix_spawn.\n"); 1126 RNBLogSTDERR( 1127 " fork Launch the executable using fork and exec.\n"); 1128 #ifdef WITH_SPRINGBOARD 1129 RNBLogSTDERR( 1130 " spring Launch the executable through Springboard.\n"); 1131 #endif 1132 #ifdef WITH_BKS 1133 RNBLogSTDERR(" backboard Launch the executable through BackBoard " 1134 "Services.\n"); 1135 #endif 1136 #ifdef WITH_FBS 1137 RNBLogSTDERR(" frontboard Launch the executable through FrontBoard " 1138 "Services.\n"); 1139 #endif 1140 exit(5); 1141 } 1142 } 1143 break; 1144 1145 case 'l': // Set Log File 1146 if (optarg && optarg[0]) { 1147 if (strcasecmp(optarg, "stdout") == 0) 1148 log_file = stdout; 1149 else if (strcasecmp(optarg, "stderr") == 0) 1150 log_file = stderr; 1151 else { 1152 log_file = fopen(optarg, "w"); 1153 if (log_file != NULL) 1154 setlinebuf(log_file); 1155 } 1156 1157 if (log_file == NULL) { 1158 const char *errno_str = strerror(errno); 1159 RNBLogSTDERR( 1160 "Failed to open log file '%s' for writing: errno = %i (%s)", 1161 optarg, errno, errno_str ? errno_str : "unknown error"); 1162 } 1163 } 1164 break; 1165 1166 case 'f': // Log Flags 1167 if (optarg && optarg[0]) 1168 log_flags = static_cast<uint32_t>(strtoul(optarg, NULL, 0)); 1169 break; 1170 1171 case 'g': 1172 debug = 1; 1173 DNBLogSetDebug(debug); 1174 break; 1175 1176 case 't': 1177 g_applist_opt = 1; 1178 break; 1179 1180 case 'k': 1181 g_lockdown_opt = 1; 1182 break; 1183 1184 case 'r': 1185 // Do nothing, native regs is the default these days 1186 break; 1187 1188 case 'R': 1189 reverse_connect = true; 1190 break; 1191 case 'v': 1192 DNBLogSetVerbose(1); 1193 break; 1194 1195 case 's': 1196 ctx.GetSTDIN().assign(optarg); 1197 ctx.GetSTDOUT().assign(optarg); 1198 ctx.GetSTDERR().assign(optarg); 1199 break; 1200 1201 case 'I': 1202 ctx.GetSTDIN().assign(optarg); 1203 break; 1204 1205 case 'O': 1206 ctx.GetSTDOUT().assign(optarg); 1207 break; 1208 1209 case 'E': 1210 ctx.GetSTDERR().assign(optarg); 1211 break; 1212 1213 case 'n': 1214 no_stdio = true; 1215 break; 1216 1217 case 'S': 1218 // Put debugserver into a new session. Terminals group processes 1219 // into sessions and when a special terminal key sequences 1220 // (like control+c) are typed they can cause signals to go out to 1221 // all processes in a session. Using this --setsid (-S) option 1222 // will cause debugserver to run in its own sessions and be free 1223 // from such issues. 1224 // 1225 // This is useful when debugserver is spawned from a command 1226 // line application that uses debugserver to do the debugging, 1227 // yet that application doesn't want debugserver receiving the 1228 // signals sent to the session (i.e. dying when anyone hits ^C). 1229 setsid(); 1230 break; 1231 case 'D': 1232 g_disable_aslr = 1; 1233 break; 1234 1235 case 'p': 1236 start_mode = eRNBRunLoopModePlatformMode; 1237 break; 1238 1239 case 'u': 1240 unix_socket_name.assign(optarg); 1241 break; 1242 1243 case 'P': 1244 named_pipe_path.assign(optarg); 1245 break; 1246 1247 case 'e': 1248 // Pass a single specified environment variable down to the process that 1249 // gets launched 1250 remote->Context().PushEnvironment(optarg); 1251 break; 1252 1253 case 'F': 1254 // Pass the current environment down to the process that gets launched 1255 { 1256 char **host_env = *_NSGetEnviron(); 1257 char *env_entry; 1258 size_t i; 1259 for (i = 0; (env_entry = host_env[i]) != NULL; ++i) 1260 remote->Context().PushEnvironment(env_entry); 1261 } 1262 break; 1263 1264 case 'FDSC': 1265 // File descriptor passed to this process during fork/exec and is already 1266 // open and ready for communication. 1267 communication_fd = atoi(optarg); 1268 break; 1269 } 1270 } 1271 1272 if (arch_name.empty()) { 1273 #if defined(__arm__) 1274 arch_name.assign("arm"); 1275 #endif 1276 } else { 1277 DNBSetArchitecture(arch_name.c_str()); 1278 } 1279 1280 // if (arch_name.empty()) 1281 // { 1282 // fprintf(stderr, "error: no architecture was specified\n"); 1283 // exit (8); 1284 // } 1285 // Skip any options we consumed with getopt_long_only 1286 argc -= optind; 1287 argv += optind; 1288 1289 if (!working_dir.empty()) { 1290 if (remote->Context().SetWorkingDirectory(working_dir.c_str()) == false) { 1291 RNBLogSTDERR("error: working directory doesn't exist '%s'.\n", 1292 working_dir.c_str()); 1293 exit(8); 1294 } 1295 } 1296 1297 remote->Context().SetDetachOnError(g_detach_on_error); 1298 1299 remote->Initialize(); 1300 1301 // It is ok for us to set NULL as the logfile (this will disable any logging) 1302 1303 if (log_file != NULL) { 1304 DNBLogSetLogCallback(FileLogCallback, log_file); 1305 // If our log file was set, yet we have no log flags, log everything! 1306 if (log_flags == 0) 1307 log_flags = LOG_ALL | LOG_RNB_ALL; 1308 1309 DNBLogSetLogMask(log_flags); 1310 } else { 1311 // Enable DNB logging 1312 1313 // if os_log() support is available, log through that. 1314 auto log_callback = OsLogger::GetLogFunction(); 1315 if (log_callback) { 1316 DNBLogSetLogCallback(log_callback, nullptr); 1317 DNBLog("debugserver will use os_log for internal logging."); 1318 } else { 1319 // Fall back to ASL support. 1320 DNBLogSetLogCallback(ASLLogCallback, NULL); 1321 DNBLog("debugserver will use ASL for internal logging."); 1322 } 1323 DNBLogSetLogMask(log_flags); 1324 } 1325 1326 if (DNBLogEnabled()) { 1327 for (i = 0; i < argc; i++) 1328 DNBLogDebug("argv[%i] = %s", i, argv[i]); 1329 } 1330 1331 // as long as we're dropping remotenub in as a replacement for gdbserver, 1332 // explicitly note that this is not gdbserver. 1333 1334 RNBLogSTDOUT("%s-%s %sfor %s.\n", DEBUGSERVER_PROGRAM_NAME, 1335 DEBUGSERVER_VERSION_STR, compile_options.c_str(), RNB_ARCH); 1336 1337 std::string host; 1338 int port = INT32_MAX; 1339 char str[PATH_MAX]; 1340 str[0] = '\0'; 1341 1342 if (g_lockdown_opt == 0 && g_applist_opt == 0 && communication_fd == -1) { 1343 // Make sure we at least have port 1344 if (argc < 1) { 1345 show_usage_and_exit(1); 1346 } 1347 // accept 'localhost:' prefix on port number 1348 std::string host_specifier = argv[0]; 1349 auto colon_location = host_specifier.rfind(':'); 1350 if (colon_location != std::string::npos) { 1351 host = host_specifier.substr(0, colon_location); 1352 std::string port_str = 1353 host_specifier.substr(colon_location + 1, std::string::npos); 1354 char *end_ptr; 1355 port = strtoul(port_str.c_str(), &end_ptr, 0); 1356 if (end_ptr < port_str.c_str() + port_str.size()) 1357 show_usage_and_exit(2); 1358 if (host.front() == '[' && host.back() == ']') 1359 host = host.substr(1, host.size() - 2); 1360 DNBLogDebug("host = '%s' port = %i", host.c_str(), port); 1361 } else { 1362 // No hostname means "localhost" 1363 int items_scanned = ::sscanf(argv[0], "%i", &port); 1364 if (items_scanned == 1) { 1365 host = "127.0.0.1"; 1366 DNBLogDebug("host = '%s' port = %i", host.c_str(), port); 1367 } else if (argv[0][0] == '/') { 1368 port = INT32_MAX; 1369 strncpy(str, argv[0], sizeof(str)); 1370 } else { 1371 show_usage_and_exit(2); 1372 } 1373 } 1374 1375 // We just used the 'host:port' or the '/path/file' arg... 1376 argc--; 1377 argv++; 1378 } 1379 1380 // If we know we're waiting to attach, we don't need any of this other info. 1381 if (start_mode != eRNBRunLoopModeInferiorAttaching && 1382 start_mode != eRNBRunLoopModePlatformMode) { 1383 if (argc == 0 || g_lockdown_opt) { 1384 if (g_lockdown_opt != 0) { 1385 // Work around for SIGPIPE crashes due to posix_spawn issue. 1386 // We have to close STDOUT and STDERR, else the first time we 1387 // try and do any, we get SIGPIPE and die as posix_spawn is 1388 // doing bad things with our file descriptors at the moment. 1389 int null = open("/dev/null", O_RDWR); 1390 dup2(null, STDOUT_FILENO); 1391 dup2(null, STDERR_FILENO); 1392 } else if (g_applist_opt != 0) { 1393 // List all applications we are able to see 1394 std::string applist_plist; 1395 int err = ListApplications(applist_plist, false, false); 1396 if (err == 0) { 1397 fputs(applist_plist.c_str(), stdout); 1398 } else { 1399 RNBLogSTDERR("error: ListApplications returned error %i\n", err); 1400 } 1401 // Exit with appropriate error if we were asked to list the applications 1402 // with no other args were given (and we weren't trying to do this over 1403 // lockdown) 1404 return err; 1405 } 1406 1407 DNBLogDebug("Get args from remote protocol..."); 1408 start_mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol; 1409 } else { 1410 start_mode = eRNBRunLoopModeInferiorLaunching; 1411 // Fill in the argv array in the context from the rest of our args. 1412 // Skip the name of this executable and the port number 1413 for (int i = 0; i < argc; i++) { 1414 DNBLogDebug("inferior_argv[%i] = '%s'", i, argv[i]); 1415 ctx.PushArgument(argv[i]); 1416 } 1417 } 1418 } 1419 1420 if (start_mode == eRNBRunLoopModeExit) 1421 return -1; 1422 1423 RNBRunLoopMode mode = start_mode; 1424 char err_str[1024] = {'\0'}; 1425 1426 while (mode != eRNBRunLoopModeExit) { 1427 switch (mode) { 1428 case eRNBRunLoopModeGetStartModeFromRemoteProtocol: 1429 #ifdef WITH_LOCKDOWN 1430 if (g_lockdown_opt) { 1431 if (!remote->Comm().IsConnected()) { 1432 if (remote->Comm().ConnectToService() != rnb_success) { 1433 RNBLogSTDERR( 1434 "Failed to get connection from a remote gdb process.\n"); 1435 mode = eRNBRunLoopModeExit; 1436 } else if (g_applist_opt != 0) { 1437 // List all applications we are able to see 1438 std::string applist_plist; 1439 if (ListApplications(applist_plist, false, false) == 0) { 1440 DNBLogDebug("Task list: %s", applist_plist.c_str()); 1441 1442 remote->Comm().Write(applist_plist.c_str(), applist_plist.size()); 1443 // Issue a read that will never yield any data until the other 1444 // side 1445 // closes the socket so this process doesn't just exit and cause 1446 // the 1447 // socket to close prematurely on the other end and cause data 1448 // loss. 1449 std::string buf; 1450 remote->Comm().Read(buf); 1451 } 1452 remote->Comm().Disconnect(false); 1453 mode = eRNBRunLoopModeExit; 1454 break; 1455 } else { 1456 // Start watching for remote packets 1457 remote->StartReadRemoteDataThread(); 1458 } 1459 } 1460 } else 1461 #endif 1462 if (port != INT32_MAX) { 1463 if (!ConnectRemote(remote, host.c_str(), port, reverse_connect, 1464 named_pipe_path.c_str(), unix_socket_name.c_str())) 1465 mode = eRNBRunLoopModeExit; 1466 } else if (str[0] == '/') { 1467 if (remote->Comm().OpenFile(str)) 1468 mode = eRNBRunLoopModeExit; 1469 } else if (communication_fd >= 0) { 1470 // We were passed a file descriptor to use during fork/exec that is 1471 // already open 1472 // in our process, so lets just use it! 1473 if (remote->Comm().useFD(communication_fd)) 1474 mode = eRNBRunLoopModeExit; 1475 else 1476 remote->StartReadRemoteDataThread(); 1477 } 1478 1479 if (mode != eRNBRunLoopModeExit) { 1480 RNBLogSTDOUT("Got a connection, waiting for process information for " 1481 "launching or attaching.\n"); 1482 1483 mode = RNBRunLoopGetStartModeFromRemote(remote); 1484 } 1485 break; 1486 1487 case eRNBRunLoopModeInferiorAttaching: 1488 if (!waitfor_pid_name.empty()) { 1489 // Set our end wait time if we are using a waitfor-duration 1490 // option that may have been specified 1491 struct timespec attach_timeout_abstime, *timeout_ptr = NULL; 1492 if (waitfor_duration != 0) { 1493 DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 1494 0); 1495 timeout_ptr = &attach_timeout_abstime; 1496 } 1497 nub_launch_flavor_t launch_flavor = g_launch_flavor; 1498 if (launch_flavor == eLaunchFlavorDefault) { 1499 // Our default launch method is posix spawn 1500 launch_flavor = eLaunchFlavorPosixSpawn; 1501 1502 #if defined WITH_FBS 1503 // Check if we have an app bundle, if so launch using SpringBoard. 1504 if (waitfor_pid_name.find(".app") != std::string::npos) { 1505 launch_flavor = eLaunchFlavorFBS; 1506 } 1507 #elif defined WITH_BKS 1508 // Check if we have an app bundle, if so launch using SpringBoard. 1509 if (waitfor_pid_name.find(".app") != std::string::npos) { 1510 launch_flavor = eLaunchFlavorBKS; 1511 } 1512 #elif defined WITH_SPRINGBOARD 1513 // Check if we have an app bundle, if so launch using SpringBoard. 1514 if (waitfor_pid_name.find(".app") != std::string::npos) { 1515 launch_flavor = eLaunchFlavorSpringBoard; 1516 } 1517 #endif 1518 } 1519 1520 ctx.SetLaunchFlavor(launch_flavor); 1521 bool ignore_existing = false; 1522 RNBLogSTDOUT("Waiting to attach to process %s...\n", 1523 waitfor_pid_name.c_str()); 1524 nub_process_t pid = DNBProcessAttachWait( 1525 waitfor_pid_name.c_str(), launch_flavor, ignore_existing, 1526 timeout_ptr, waitfor_interval, err_str, sizeof(err_str)); 1527 g_pid = pid; 1528 1529 if (pid == INVALID_NUB_PROCESS) { 1530 ctx.LaunchStatus().SetError(-1, DNBError::Generic); 1531 if (err_str[0]) 1532 ctx.LaunchStatus().SetErrorString(err_str); 1533 RNBLogSTDERR("error: failed to attach to process named: \"%s\" %s\n", 1534 waitfor_pid_name.c_str(), err_str); 1535 mode = eRNBRunLoopModeExit; 1536 } else { 1537 ctx.SetProcessID(pid); 1538 mode = eRNBRunLoopModeInferiorExecuting; 1539 } 1540 } else if (attach_pid != INVALID_NUB_PROCESS) { 1541 1542 RNBLogSTDOUT("Attaching to process %i...\n", attach_pid); 1543 nub_process_t attached_pid; 1544 mode = RNBRunLoopLaunchAttaching(remote, attach_pid, attached_pid); 1545 if (mode != eRNBRunLoopModeInferiorExecuting) { 1546 const char *error_str = remote->Context().LaunchStatus().AsString(); 1547 RNBLogSTDERR("error: failed to attach process %i: %s\n", attach_pid, 1548 error_str ? error_str : "unknown error."); 1549 mode = eRNBRunLoopModeExit; 1550 } 1551 } else if (!attach_pid_name.empty()) { 1552 struct timespec attach_timeout_abstime, *timeout_ptr = NULL; 1553 if (waitfor_duration != 0) { 1554 DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 1555 0); 1556 timeout_ptr = &attach_timeout_abstime; 1557 } 1558 1559 RNBLogSTDOUT("Attaching to process %s...\n", attach_pid_name.c_str()); 1560 nub_process_t pid = DNBProcessAttachByName( 1561 attach_pid_name.c_str(), timeout_ptr, err_str, sizeof(err_str)); 1562 g_pid = pid; 1563 if (pid == INVALID_NUB_PROCESS) { 1564 ctx.LaunchStatus().SetError(-1, DNBError::Generic); 1565 if (err_str[0]) 1566 ctx.LaunchStatus().SetErrorString(err_str); 1567 RNBLogSTDERR("error: failed to attach to process named: \"%s\" %s\n", 1568 waitfor_pid_name.c_str(), err_str); 1569 mode = eRNBRunLoopModeExit; 1570 } else { 1571 ctx.SetProcessID(pid); 1572 mode = eRNBRunLoopModeInferiorExecuting; 1573 } 1574 1575 } else { 1576 RNBLogSTDERR( 1577 "error: asked to attach with empty name and invalid PID.\n"); 1578 mode = eRNBRunLoopModeExit; 1579 } 1580 1581 if (mode != eRNBRunLoopModeExit) { 1582 if (port != INT32_MAX) { 1583 if (!ConnectRemote(remote, host.c_str(), port, reverse_connect, 1584 named_pipe_path.c_str(), unix_socket_name.c_str())) 1585 mode = eRNBRunLoopModeExit; 1586 } else if (str[0] == '/') { 1587 if (remote->Comm().OpenFile(str)) 1588 mode = eRNBRunLoopModeExit; 1589 } else if (communication_fd >= 0) { 1590 // We were passed a file descriptor to use during fork/exec that is 1591 // already open 1592 // in our process, so lets just use it! 1593 if (remote->Comm().useFD(communication_fd)) 1594 mode = eRNBRunLoopModeExit; 1595 else 1596 remote->StartReadRemoteDataThread(); 1597 } 1598 1599 if (mode != eRNBRunLoopModeExit) 1600 RNBLogSTDOUT("Waiting for debugger instructions for process %d.\n", 1601 attach_pid); 1602 } 1603 break; 1604 1605 case eRNBRunLoopModeInferiorLaunching: { 1606 mode = RNBRunLoopLaunchInferior(remote, ctx.GetSTDINPath(), 1607 ctx.GetSTDOUTPath(), ctx.GetSTDERRPath(), 1608 no_stdio); 1609 1610 if (mode == eRNBRunLoopModeInferiorExecuting) { 1611 if (port != INT32_MAX) { 1612 if (!ConnectRemote(remote, host.c_str(), port, reverse_connect, 1613 named_pipe_path.c_str(), unix_socket_name.c_str())) 1614 mode = eRNBRunLoopModeExit; 1615 } else if (str[0] == '/') { 1616 if (remote->Comm().OpenFile(str)) 1617 mode = eRNBRunLoopModeExit; 1618 } else if (communication_fd >= 0) { 1619 // We were passed a file descriptor to use during fork/exec that is 1620 // already open 1621 // in our process, so lets just use it! 1622 if (remote->Comm().useFD(communication_fd)) 1623 mode = eRNBRunLoopModeExit; 1624 else 1625 remote->StartReadRemoteDataThread(); 1626 } 1627 1628 if (mode != eRNBRunLoopModeExit) { 1629 const char *proc_name = "<unknown>"; 1630 if (ctx.ArgumentCount() > 0) 1631 proc_name = ctx.ArgumentAtIndex(0); 1632 RNBLogSTDOUT("Got a connection, launched process %s (pid = %d).\n", 1633 proc_name, ctx.ProcessID()); 1634 } 1635 } else { 1636 const char *error_str = remote->Context().LaunchStatus().AsString(); 1637 RNBLogSTDERR("error: failed to launch process %s: %s\n", argv_sub_zero, 1638 error_str ? error_str : "unknown error."); 1639 } 1640 } break; 1641 1642 case eRNBRunLoopModeInferiorExecuting: 1643 mode = RNBRunLoopInferiorExecuting(remote); 1644 break; 1645 1646 case eRNBRunLoopModePlatformMode: 1647 if (port != INT32_MAX) { 1648 if (!ConnectRemote(remote, host.c_str(), port, reverse_connect, 1649 named_pipe_path.c_str(), unix_socket_name.c_str())) 1650 mode = eRNBRunLoopModeExit; 1651 } else if (str[0] == '/') { 1652 if (remote->Comm().OpenFile(str)) 1653 mode = eRNBRunLoopModeExit; 1654 } else if (communication_fd >= 0) { 1655 // We were passed a file descriptor to use during fork/exec that is 1656 // already open 1657 // in our process, so lets just use it! 1658 if (remote->Comm().useFD(communication_fd)) 1659 mode = eRNBRunLoopModeExit; 1660 else 1661 remote->StartReadRemoteDataThread(); 1662 } 1663 1664 if (mode != eRNBRunLoopModeExit) 1665 mode = RNBRunLoopPlatform(remote); 1666 break; 1667 1668 default: 1669 mode = eRNBRunLoopModeExit; 1670 case eRNBRunLoopModeExit: 1671 break; 1672 } 1673 } 1674 1675 remote->StopReadRemoteDataThread(); 1676 remote->Context().SetProcessID(INVALID_NUB_PROCESS); 1677 RNBLogSTDOUT("Exiting.\n"); 1678 1679 return 0; 1680 } 1681