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