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