diff options
author | Kate Stone <katherine.stone@apple.com> | 2016-09-06 20:57:50 +0000 |
---|---|---|
committer | Kate Stone <katherine.stone@apple.com> | 2016-09-06 20:57:50 +0000 |
commit | b9c1b51e45b845debb76d8658edabca70ca56079 (patch) | |
tree | dfcb5a13ef2b014202340f47036da383eaee74aa /lldb/tools/debugserver/source/debugserver.cpp | |
parent | d5aa73376966339caad04013510626ec2e42c760 (diff) | |
download | llvm-b9c1b51e45b845debb76d8658edabca70ca56079.zip llvm-b9c1b51e45b845debb76d8658edabca70ca56079.tar.gz llvm-b9c1b51e45b845debb76d8658edabca70ca56079.tar.bz2 |
*** This commit represents a complete reformatting of the LLDB source code
*** to conform to clang-format’s LLVM style. This kind of mass change has
*** two obvious implications:
Firstly, merging this particular commit into a downstream fork may be a huge
effort. Alternatively, it may be worth merging all changes up to this commit,
performing the same reformatting operation locally, and then discarding the
merge for this particular commit. The commands used to accomplish this
reformatting were as follows (with current working directory as the root of
the repository):
find . \( -iname "*.c" -or -iname "*.cpp" -or -iname "*.h" -or -iname "*.mm" \) -exec clang-format -i {} +
find . -iname "*.py" -exec autopep8 --in-place --aggressive --aggressive {} + ;
The version of clang-format used was 3.9.0, and autopep8 was 1.2.4.
Secondly, “blame” style tools will generally point to this commit instead of
a meaningful prior commit. There are alternatives available that will attempt
to look through this change and find the appropriate prior commit. YMMV.
llvm-svn: 280751
Diffstat (limited to 'lldb/tools/debugserver/source/debugserver.cpp')
-rw-r--r-- | lldb/tools/debugserver/source/debugserver.cpp | 2942 |
1 files changed, 1435 insertions, 1507 deletions
diff --git a/lldb/tools/debugserver/source/debugserver.cpp b/lldb/tools/debugserver/source/debugserver.cpp index e1ee2c1..0cb72f4 100644 --- a/lldb/tools/debugserver/source/debugserver.cpp +++ b/lldb/tools/debugserver/source/debugserver.cpp @@ -7,27 +7,28 @@ // //===----------------------------------------------------------------------===// -#include <sys/socket.h> -#include <sys/types.h> +#include <arpa/inet.h> +#include <asl.h> +#include <crt_externs.h> // for _NSGetEnviron() #include <errno.h> #include <getopt.h> -#include <netinet/in.h> -#include <sys/select.h> -#include <sys/sysctl.h> -#include <string> -#include <vector> -#include <asl.h> -#include <arpa/inet.h> #include <netdb.h> #include <netinet/in.h> +#include <netinet/in.h> #include <netinet/tcp.h> -#include <sys/un.h> +#include <string> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/sysctl.h> #include <sys/types.h> -#include <crt_externs.h> // for _NSGetEnviron() +#include <sys/types.h> +#include <sys/un.h> +#include <vector> -#if defined (__APPLE__) +#if defined(__APPLE__) #include <sched.h> -extern "C" int proc_set_wakemon_params(pid_t, int, int); // <libproc_internal.h> SPI +extern "C" int proc_set_wakemon_params(pid_t, int, + int); // <libproc_internal.h> SPI #endif #include "CFString.h" @@ -37,9 +38,9 @@ extern "C" int proc_set_wakemon_params(pid_t, int, int); // <libproc_internal.h> #include "OsLogger.h" #include "PseudoTerminal.h" #include "RNBContext.h" +#include "RNBRemote.h" #include "RNBServices.h" #include "RNBSocket.h" -#include "RNBRemote.h" #include "SysSignal.h" // Global PID in case we get a signal and need to stop the process... @@ -48,23 +49,21 @@ nub_process_t g_pid = INVALID_NUB_PROCESS; //---------------------------------------------------------------------- // Run loop modes which determine which run loop function will be called //---------------------------------------------------------------------- -typedef enum -{ - eRNBRunLoopModeInvalid = 0, - eRNBRunLoopModeGetStartModeFromRemoteProtocol, - eRNBRunLoopModeInferiorAttaching, - eRNBRunLoopModeInferiorLaunching, - eRNBRunLoopModeInferiorExecuting, - eRNBRunLoopModePlatformMode, - eRNBRunLoopModeExit +typedef enum { + eRNBRunLoopModeInvalid = 0, + eRNBRunLoopModeGetStartModeFromRemoteProtocol, + eRNBRunLoopModeInferiorAttaching, + eRNBRunLoopModeInferiorLaunching, + eRNBRunLoopModeInferiorExecuting, + eRNBRunLoopModePlatformMode, + eRNBRunLoopModeExit } RNBRunLoopMode; - //---------------------------------------------------------------------- // Global Variables //---------------------------------------------------------------------- RNBRemoteSP g_remoteSP; -static int g_lockdown_opt = 0; +static int g_lockdown_opt = 0; static int g_applist_opt = 0; static nub_launch_flavor_t g_launch_flavor = eLaunchFlavorDefault; int g_disable_aslr = 0; @@ -72,8 +71,22 @@ int g_disable_aslr = 0; int g_isatty = 0; bool g_detach_on_error = true; -#define RNBLogSTDOUT(fmt, ...) do { if (g_isatty) { fprintf(stdout, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0) -#define RNBLogSTDERR(fmt, ...) do { if (g_isatty) { fprintf(stderr, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0) +#define RNBLogSTDOUT(fmt, ...) \ + do { \ + if (g_isatty) { \ + fprintf(stdout, fmt, ##__VA_ARGS__); \ + } else { \ + _DNBLog(0, fmt, ##__VA_ARGS__); \ + } \ + } while (0) +#define RNBLogSTDERR(fmt, ...) \ + do { \ + if (g_isatty) { \ + fprintf(stderr, fmt, ##__VA_ARGS__); \ + } else { \ + _DNBLog(0, fmt, ##__VA_ARGS__); \ + } \ + } while (0) //---------------------------------------------------------------------- // Get our program path and arguments from the remote connection. @@ -81,306 +94,290 @@ bool g_detach_on_error = true; // arguments, wait for the new process to finish launching and hit its // entry point, and then return the run loop mode that should come next. //---------------------------------------------------------------------- -RNBRunLoopMode -RNBRunLoopGetStartModeFromRemote (RNBRemote* remote) -{ - std::string packet; - - if (remote) - { - RNBContext& ctx = remote->Context(); - uint32_t event_mask = RNBContext::event_read_packet_available | - RNBContext::event_read_thread_exiting; - - // Spin waiting to get the A packet. - while (1) - { - DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) ...",__FUNCTION__, event_mask); - nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); - DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) => 0x%08x", __FUNCTION__, event_mask, set_events); - - if (set_events & RNBContext::event_read_thread_exiting) - { - RNBLogSTDERR ("error: packet read thread exited.\n"); - return eRNBRunLoopModeExit; - } +RNBRunLoopMode RNBRunLoopGetStartModeFromRemote(RNBRemote *remote) { + std::string packet; + + if (remote) { + RNBContext &ctx = remote->Context(); + uint32_t event_mask = RNBContext::event_read_packet_available | + RNBContext::event_read_thread_exiting; + + // Spin waiting to get the A packet. + while (1) { + DNBLogThreadedIf(LOG_RNB_MAX, + "%s ctx.Events().WaitForSetEvents( 0x%08x ) ...", + __FUNCTION__, event_mask); + nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); + DNBLogThreadedIf(LOG_RNB_MAX, + "%s ctx.Events().WaitForSetEvents( 0x%08x ) => 0x%08x", + __FUNCTION__, event_mask, set_events); + + if (set_events & RNBContext::event_read_thread_exiting) { + RNBLogSTDERR("error: packet read thread exited.\n"); + return eRNBRunLoopModeExit; + } - if (set_events & RNBContext::event_read_packet_available) - { - rnb_err_t err = rnb_err; - RNBRemote::PacketEnum type; - - err = remote->HandleReceivedPacket (&type); - - // check if we tried to attach to a process - if (type == RNBRemote::vattach || type == RNBRemote::vattachwait || type == RNBRemote::vattachorwait) - { - if (err == rnb_success) - { - RNBLogSTDOUT ("Attach succeeded, ready to debug.\n"); - return eRNBRunLoopModeInferiorExecuting; - } - else - { - RNBLogSTDERR ("error: attach failed.\n"); - return eRNBRunLoopModeExit; - } - } - - if (err == rnb_success) - { - // If we got our arguments we are ready to launch using the arguments - // and any environment variables we received. - if (type == RNBRemote::set_argv) - { - return eRNBRunLoopModeInferiorLaunching; - } - } - else if (err == rnb_not_connected) - { - RNBLogSTDERR ("error: connection lost.\n"); - return eRNBRunLoopModeExit; - } - else - { - // a catch all for any other gdb remote packets that failed - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.",__FUNCTION__); - continue; - } - - DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__); - } - else - { - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Connection closed before getting \"A\" packet.", __FUNCTION__); - return eRNBRunLoopModeExit; - } + if (set_events & RNBContext::event_read_packet_available) { + rnb_err_t err = rnb_err; + RNBRemote::PacketEnum type; + + err = remote->HandleReceivedPacket(&type); + + // check if we tried to attach to a process + if (type == RNBRemote::vattach || type == RNBRemote::vattachwait || + type == RNBRemote::vattachorwait) { + if (err == rnb_success) { + RNBLogSTDOUT("Attach succeeded, ready to debug.\n"); + return eRNBRunLoopModeInferiorExecuting; + } else { + RNBLogSTDERR("error: attach failed.\n"); + return eRNBRunLoopModeExit; + } } + + if (err == rnb_success) { + // If we got our arguments we are ready to launch using the arguments + // and any environment variables we received. + if (type == RNBRemote::set_argv) { + return eRNBRunLoopModeInferiorLaunching; + } + } else if (err == rnb_not_connected) { + RNBLogSTDERR("error: connection lost.\n"); + return eRNBRunLoopModeExit; + } else { + // a catch all for any other gdb remote packets that failed + DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s Error getting packet.", + __FUNCTION__); + continue; + } + + DNBLogThreadedIf(LOG_RNB_MINIMAL, "#### %s", __FUNCTION__); + } else { + DNBLogThreadedIf(LOG_RNB_MINIMAL, + "%s Connection closed before getting \"A\" packet.", + __FUNCTION__); + return eRNBRunLoopModeExit; + } } - return eRNBRunLoopModeExit; + } + return eRNBRunLoopModeExit; } - //---------------------------------------------------------------------- // This run loop mode will wait for the process to launch and hit its // entry point. It will currently ignore all events except for the // process state changed event, where it watches for the process stopped // or crash process state. //---------------------------------------------------------------------- -RNBRunLoopMode -RNBRunLoopLaunchInferior (RNBRemote *remote, const char *stdin_path, const char *stdout_path, const char *stderr_path, bool no_stdio) -{ - RNBContext& ctx = remote->Context(); +RNBRunLoopMode RNBRunLoopLaunchInferior(RNBRemote *remote, + const char *stdin_path, + const char *stdout_path, + const char *stderr_path, + bool no_stdio) { + RNBContext &ctx = remote->Context(); - // The Process stuff takes a c array, the RNBContext has a vector... - // So make up a c array. + // The Process stuff takes a c array, the RNBContext has a vector... + // So make up a c array. - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Launching '%s'...", __FUNCTION__, ctx.ArgumentAtIndex(0)); + DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s Launching '%s'...", __FUNCTION__, + ctx.ArgumentAtIndex(0)); - size_t inferior_argc = ctx.ArgumentCount(); - // Initialize inferior_argv with inferior_argc + 1 NULLs - std::vector<const char *> inferior_argv(inferior_argc + 1, NULL); + size_t inferior_argc = ctx.ArgumentCount(); + // Initialize inferior_argv with inferior_argc + 1 NULLs + std::vector<const char *> inferior_argv(inferior_argc + 1, NULL); - size_t i; - for (i = 0; i < inferior_argc; i++) - inferior_argv[i] = ctx.ArgumentAtIndex(i); + size_t i; + for (i = 0; i < inferior_argc; i++) + inferior_argv[i] = ctx.ArgumentAtIndex(i); - // Pass the environment array the same way: + // Pass the environment array the same way: - size_t inferior_envc = ctx.EnvironmentCount(); - // Initialize inferior_argv with inferior_argc + 1 NULLs - std::vector<const char *> inferior_envp(inferior_envc + 1, NULL); + size_t inferior_envc = ctx.EnvironmentCount(); + // Initialize inferior_argv with inferior_argc + 1 NULLs + std::vector<const char *> inferior_envp(inferior_envc + 1, NULL); - for (i = 0; i < inferior_envc; i++) - inferior_envp[i] = ctx.EnvironmentAtIndex(i); + for (i = 0; i < inferior_envc; i++) + inferior_envp[i] = ctx.EnvironmentAtIndex(i); - // Our launch type hasn't been set to anything concrete, so we need to - // figure our how we are going to launch automatically. + // Our launch type hasn't been set to anything concrete, so we need to + // figure our how we are going to launch automatically. - nub_launch_flavor_t launch_flavor = g_launch_flavor; - if (launch_flavor == eLaunchFlavorDefault) - { - // Our default launch method is posix spawn - launch_flavor = eLaunchFlavorPosixSpawn; + nub_launch_flavor_t launch_flavor = g_launch_flavor; + if (launch_flavor == eLaunchFlavorDefault) { + // Our default launch method is posix spawn + launch_flavor = eLaunchFlavorPosixSpawn; #if defined WITH_FBS - // Check if we have an app bundle, if so launch using BackBoard Services. - if (strstr(inferior_argv[0], ".app")) - { - launch_flavor = eLaunchFlavorFBS; - } -#elif defined WITH_BKS - // Check if we have an app bundle, if so launch using BackBoard Services. - if (strstr(inferior_argv[0], ".app")) - { - launch_flavor = eLaunchFlavorBKS; - } -#elif defined WITH_SPRINGBOARD - // Check if we have an app bundle, if so launch using SpringBoard. - if (strstr(inferior_argv[0], ".app")) - { - launch_flavor = eLaunchFlavorSpringBoard; - } -#endif + // Check if we have an app bundle, if so launch using BackBoard Services. + if (strstr(inferior_argv[0], ".app")) { + launch_flavor = eLaunchFlavorFBS; } - - ctx.SetLaunchFlavor(launch_flavor); - char resolved_path[PATH_MAX]; - - // If we fail to resolve the path to our executable, then just use what we - // were given and hope for the best - if ( !DNBResolveExecutablePath (inferior_argv[0], resolved_path, sizeof(resolved_path)) ) - ::strncpy(resolved_path, inferior_argv[0], sizeof(resolved_path)); - - char launch_err_str[PATH_MAX]; - launch_err_str[0] = '\0'; - const char * cwd = (ctx.GetWorkingDirPath() != NULL ? ctx.GetWorkingDirPath() - : ctx.GetWorkingDirectory()); - const char *process_event = ctx.GetProcessEvent(); - nub_process_t pid = DNBProcessLaunch (resolved_path, - &inferior_argv[0], - &inferior_envp[0], - cwd, - stdin_path, - stdout_path, - stderr_path, - no_stdio, - launch_flavor, - g_disable_aslr, - process_event, - launch_err_str, - sizeof(launch_err_str)); - - g_pid = pid; - - if (pid == INVALID_NUB_PROCESS && strlen (launch_err_str) > 0) - { - DNBLogThreaded ("%s DNBProcessLaunch() returned error: '%s'", __FUNCTION__, launch_err_str); - ctx.LaunchStatus().SetError(-1, DNBError::Generic); - ctx.LaunchStatus().SetErrorString(launch_err_str); +#elif defined WITH_BKS + // Check if we have an app bundle, if so launch using BackBoard Services. + if (strstr(inferior_argv[0], ".app")) { + launch_flavor = eLaunchFlavorBKS; } - else if (pid == INVALID_NUB_PROCESS) - { - DNBLogThreaded ("%s DNBProcessLaunch() failed to launch process, unknown failure", __FUNCTION__); - ctx.LaunchStatus().SetError(-1, DNBError::Generic); - ctx.LaunchStatus().SetErrorString("<unknown failure>"); +#elif defined WITH_SPRINGBOARD + // Check if we have an app bundle, if so launch using SpringBoard. + if (strstr(inferior_argv[0], ".app")) { + launch_flavor = eLaunchFlavorSpringBoard; } - else - { - ctx.LaunchStatus().Clear(); +#endif + } + + ctx.SetLaunchFlavor(launch_flavor); + char resolved_path[PATH_MAX]; + + // If we fail to resolve the path to our executable, then just use what we + // were given and hope for the best + if (!DNBResolveExecutablePath(inferior_argv[0], resolved_path, + sizeof(resolved_path))) + ::strncpy(resolved_path, inferior_argv[0], sizeof(resolved_path)); + + char launch_err_str[PATH_MAX]; + launch_err_str[0] = '\0'; + const char *cwd = + (ctx.GetWorkingDirPath() != NULL ? ctx.GetWorkingDirPath() + : ctx.GetWorkingDirectory()); + const char *process_event = ctx.GetProcessEvent(); + nub_process_t pid = DNBProcessLaunch( + resolved_path, &inferior_argv[0], &inferior_envp[0], cwd, stdin_path, + stdout_path, stderr_path, no_stdio, launch_flavor, g_disable_aslr, + process_event, launch_err_str, sizeof(launch_err_str)); + + g_pid = pid; + + if (pid == INVALID_NUB_PROCESS && strlen(launch_err_str) > 0) { + DNBLogThreaded("%s DNBProcessLaunch() returned error: '%s'", __FUNCTION__, + launch_err_str); + ctx.LaunchStatus().SetError(-1, DNBError::Generic); + ctx.LaunchStatus().SetErrorString(launch_err_str); + } else if (pid == INVALID_NUB_PROCESS) { + DNBLogThreaded( + "%s DNBProcessLaunch() failed to launch process, unknown failure", + __FUNCTION__); + ctx.LaunchStatus().SetError(-1, DNBError::Generic); + ctx.LaunchStatus().SetErrorString("<unknown failure>"); + } else { + ctx.LaunchStatus().Clear(); + } + + if (remote->Comm().IsConnected()) { + // It we are connected already, the next thing gdb will do is ask + // whether the launch succeeded, and if not, whether there is an + // error code. So we need to fetch one packet from gdb before we wait + // on the stop from the target. + + uint32_t event_mask = RNBContext::event_read_packet_available; + nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); + + if (set_events & RNBContext::event_read_packet_available) { + rnb_err_t err = rnb_err; + RNBRemote::PacketEnum type; + + err = remote->HandleReceivedPacket(&type); + + if (err != rnb_success) { + DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s Error getting packet.", + __FUNCTION__); + return eRNBRunLoopModeExit; + } + if (type != RNBRemote::query_launch_success) { + DNBLogThreadedIf(LOG_RNB_MINIMAL, + "%s Didn't get the expected qLaunchSuccess packet.", + __FUNCTION__); + } } + } + + while (pid != INVALID_NUB_PROCESS) { + // Wait for process to start up and hit entry point + DNBLogThreadedIf(LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, " + "eEventProcessRunningStateChanged | " + "eEventProcessStoppedStateChanged, true, " + "INFINITE)...", + __FUNCTION__, pid); + nub_event_t set_events = + DNBProcessWaitForEvents(pid, eEventProcessRunningStateChanged | + eEventProcessStoppedStateChanged, + true, NULL); + DNBLogThreadedIf(LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, " + "eEventProcessRunningStateChanged | " + "eEventProcessStoppedStateChanged, true, " + "INFINITE) => 0x%8.8x", + __FUNCTION__, pid, set_events); + + if (set_events == 0) { + pid = INVALID_NUB_PROCESS; + g_pid = pid; + } else { + if (set_events & (eEventProcessRunningStateChanged | + eEventProcessStoppedStateChanged)) { + nub_state_t pid_state = DNBProcessGetState(pid); + DNBLogThreadedIf( + LOG_RNB_EVENTS, + "%s process %4.4x state changed (eEventProcessStateChanged): %s", + __FUNCTION__, pid, DNBStateAsString(pid_state)); + + switch (pid_state) { + case eStateInvalid: + case eStateUnloaded: + case eStateAttaching: + case eStateLaunching: + case eStateSuspended: + break; // Ignore - if (remote->Comm().IsConnected()) - { - // It we are connected already, the next thing gdb will do is ask - // whether the launch succeeded, and if not, whether there is an - // error code. So we need to fetch one packet from gdb before we wait - // on the stop from the target. - - uint32_t event_mask = RNBContext::event_read_packet_available; - nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); - - if (set_events & RNBContext::event_read_packet_available) - { - rnb_err_t err = rnb_err; - RNBRemote::PacketEnum type; - - err = remote->HandleReceivedPacket (&type); + case eStateRunning: + case eStateStepping: + // Still waiting to stop at entry point... + break; - if (err != rnb_success) - { - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.", __FUNCTION__); - return eRNBRunLoopModeExit; - } - if (type != RNBRemote::query_launch_success) - { - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Didn't get the expected qLaunchSuccess packet.", __FUNCTION__); - } - } - } + case eStateStopped: + case eStateCrashed: + ctx.SetProcessID(pid); + return eRNBRunLoopModeInferiorExecuting; - while (pid != INVALID_NUB_PROCESS) - { - // Wait for process to start up and hit entry point - DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE)...", __FUNCTION__, pid); - nub_event_t set_events = DNBProcessWaitForEvents (pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, NULL); - DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE) => 0x%8.8x", __FUNCTION__, pid, set_events); - - if (set_events == 0) - { - pid = INVALID_NUB_PROCESS; - g_pid = pid; + case eStateDetached: + case eStateExited: + pid = INVALID_NUB_PROCESS; + g_pid = pid; + return eRNBRunLoopModeExit; } - else - { - if (set_events & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged)) - { - nub_state_t pid_state = DNBProcessGetState (pid); - DNBLogThreadedIf (LOG_RNB_EVENTS, "%s process %4.4x state changed (eEventProcessStateChanged): %s", __FUNCTION__, pid, DNBStateAsString(pid_state)); - - switch (pid_state) - { - case eStateInvalid: - case eStateUnloaded: - case eStateAttaching: - case eStateLaunching: - case eStateSuspended: - break; // Ignore - - case eStateRunning: - case eStateStepping: - // Still waiting to stop at entry point... - break; - - case eStateStopped: - case eStateCrashed: - ctx.SetProcessID(pid); - return eRNBRunLoopModeInferiorExecuting; - - case eStateDetached: - case eStateExited: - pid = INVALID_NUB_PROCESS; - g_pid = pid; - return eRNBRunLoopModeExit; - } - } + } - DNBProcessResetEvents(pid, set_events); - } + DNBProcessResetEvents(pid, set_events); } + } - return eRNBRunLoopModeExit; + return eRNBRunLoopModeExit; } - //---------------------------------------------------------------------- // This run loop mode will wait for the process to launch and hit its // entry point. It will currently ignore all events except for the // process state changed event, where it watches for the process stopped // or crash process state. //---------------------------------------------------------------------- -RNBRunLoopMode -RNBRunLoopLaunchAttaching (RNBRemote *remote, nub_process_t attach_pid, nub_process_t& pid) -{ - RNBContext& ctx = remote->Context(); - - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Attaching to pid %i...", __FUNCTION__, attach_pid); - char err_str[1024]; - pid = DNBProcessAttach (attach_pid, NULL, err_str, sizeof(err_str)); - g_pid = pid; - - if (pid == INVALID_NUB_PROCESS) - { - ctx.LaunchStatus().SetError(-1, DNBError::Generic); - if (err_str[0]) - ctx.LaunchStatus().SetErrorString(err_str); - return eRNBRunLoopModeExit; - } - else - { - ctx.SetProcessID(pid); - return eRNBRunLoopModeInferiorExecuting; - } +RNBRunLoopMode RNBRunLoopLaunchAttaching(RNBRemote *remote, + nub_process_t attach_pid, + nub_process_t &pid) { + RNBContext &ctx = remote->Context(); + + DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s Attaching to pid %i...", __FUNCTION__, + attach_pid); + char err_str[1024]; + pid = DNBProcessAttach(attach_pid, NULL, err_str, sizeof(err_str)); + g_pid = pid; + + if (pid == INVALID_NUB_PROCESS) { + ctx.LaunchStatus().SetError(-1, DNBError::Generic); + if (err_str[0]) + ctx.LaunchStatus().SetErrorString(err_str); + return eRNBRunLoopModeExit; + } else { + ctx.SetProcessID(pid); + return eRNBRunLoopModeInferiorExecuting; + } } //---------------------------------------------------------------------- @@ -390,284 +387,271 @@ RNBRunLoopLaunchAttaching (RNBRemote *remote, nub_process_t attach_pid, nub_proc //---------------------------------------------------------------------- int g_sigint_received = 0; int g_sigpipe_received = 0; -void -signal_handler(int signo) -{ - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (%s)", __FUNCTION__, SysSignal::Name(signo)); - - switch (signo) - { - case SIGINT: - g_sigint_received++; - if (g_pid != INVALID_NUB_PROCESS) - { - // Only send a SIGINT once... - if (g_sigint_received == 1) - { - switch (DNBProcessGetState (g_pid)) - { - case eStateRunning: - case eStateStepping: - DNBProcessSignal (g_pid, SIGSTOP); - return; - default: - break; - } - } - } - exit (SIGINT); - break; - - case SIGPIPE: - g_sigpipe_received = 1; - break; +void signal_handler(int signo) { + DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s (%s)", __FUNCTION__, + SysSignal::Name(signo)); + + switch (signo) { + case SIGINT: + g_sigint_received++; + if (g_pid != INVALID_NUB_PROCESS) { + // Only send a SIGINT once... + if (g_sigint_received == 1) { + switch (DNBProcessGetState(g_pid)) { + case eStateRunning: + case eStateStepping: + DNBProcessSignal(g_pid, SIGSTOP); + return; + default: + break; + } + } } + exit(SIGINT); + break; + + case SIGPIPE: + g_sigpipe_received = 1; + break; + } } // Return the new run loop mode based off of the current process state -RNBRunLoopMode -HandleProcessStateChange (RNBRemote *remote, bool initialize) -{ - RNBContext& ctx = remote->Context(); - nub_process_t pid = ctx.ProcessID(); - - if (pid == INVALID_NUB_PROCESS) - { - DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s error: pid invalid, exiting...", __FUNCTION__); - return eRNBRunLoopModeExit; - } - nub_state_t pid_state = DNBProcessGetState (pid); - - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state)); - - switch (pid_state) - { - case eStateInvalid: - case eStateUnloaded: - // Something bad happened - return eRNBRunLoopModeExit; - break; - - case eStateAttaching: - case eStateLaunching: - return eRNBRunLoopModeInferiorExecuting; +RNBRunLoopMode HandleProcessStateChange(RNBRemote *remote, bool initialize) { + RNBContext &ctx = remote->Context(); + nub_process_t pid = ctx.ProcessID(); - case eStateSuspended: - case eStateCrashed: - case eStateStopped: - // If we stop due to a signal, so clear the fact that we got a SIGINT - // so we can stop ourselves again (but only while our inferior - // process is running..) - g_sigint_received = 0; - if (initialize == false) - { - // Compare the last stop count to our current notion of a stop count - // to make sure we don't notify more than once for a given stop. - nub_size_t prev_pid_stop_count = ctx.GetProcessStopCount(); - bool pid_stop_count_changed = ctx.SetProcessStopCount(DNBProcessGetStopCount(pid)); - if (pid_stop_count_changed) - { - remote->FlushSTDIO(); - - if (ctx.GetProcessStopCount() == 1) - { - 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); - } - else - { - - 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); - remote->NotifyThatProcessStopped (); - } - } - else - { - 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); - } - } - return eRNBRunLoopModeInferiorExecuting; - - case eStateStepping: - case eStateRunning: - return eRNBRunLoopModeInferiorExecuting; + if (pid == INVALID_NUB_PROCESS) { + DNBLogThreadedIf(LOG_RNB_MINIMAL, "#### %s error: pid invalid, exiting...", + __FUNCTION__); + return eRNBRunLoopModeExit; + } + nub_state_t pid_state = DNBProcessGetState(pid); - case eStateExited: - remote->HandlePacket_last_signal(NULL); - case eStateDetached: - return eRNBRunLoopModeExit; + DNBLogThreadedIf(LOG_RNB_MINIMAL, + "%s (&remote, initialize=%i) pid_state = %s", __FUNCTION__, + (int)initialize, DNBStateAsString(pid_state)); + switch (pid_state) { + case eStateInvalid: + case eStateUnloaded: + // Something bad happened + return eRNBRunLoopModeExit; + break; + + case eStateAttaching: + case eStateLaunching: + return eRNBRunLoopModeInferiorExecuting; + + case eStateSuspended: + case eStateCrashed: + case eStateStopped: + // If we stop due to a signal, so clear the fact that we got a SIGINT + // so we can stop ourselves again (but only while our inferior + // process is running..) + g_sigint_received = 0; + if (initialize == false) { + // Compare the last stop count to our current notion of a stop count + // to make sure we don't notify more than once for a given stop. + nub_size_t prev_pid_stop_count = ctx.GetProcessStopCount(); + bool pid_stop_count_changed = + ctx.SetProcessStopCount(DNBProcessGetStopCount(pid)); + if (pid_stop_count_changed) { + remote->FlushSTDIO(); + + if (ctx.GetProcessStopCount() == 1) { + 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); + } else { + + 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); + remote->NotifyThatProcessStopped(); + } + } else { + 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); + } } + return eRNBRunLoopModeInferiorExecuting; + + case eStateStepping: + case eStateRunning: + return eRNBRunLoopModeInferiorExecuting; - // Catch all... + case eStateExited: + remote->HandlePacket_last_signal(NULL); + case eStateDetached: return eRNBRunLoopModeExit; + } + + // Catch all... + return eRNBRunLoopModeExit; } // This function handles the case where our inferior program is stopped and // we are waiting for gdb remote protocol packets. When a packet occurs that // makes the inferior run, we need to leave this function with a new state // as the return code. -RNBRunLoopMode -RNBRunLoopInferiorExecuting (RNBRemote *remote) -{ - DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__); - RNBContext& ctx = remote->Context(); - - // Init our mode and set 'is_running' based on the current process state - RNBRunLoopMode mode = HandleProcessStateChange (remote, true); - - while (ctx.ProcessID() != INVALID_NUB_PROCESS) - { - - std::string set_events_str; - uint32_t event_mask = ctx.NormalEventBits(); - - if (!ctx.ProcessStateRunning()) - { - // Clear some bits if we are not running so we don't send any async packets - event_mask &= ~RNBContext::event_proc_stdio_available; - event_mask &= ~RNBContext::event_proc_profile_data; - // When we enable async structured data packets over another logical channel, - // this can be relaxed. - event_mask &= ~RNBContext::event_darwin_log_data_available; - } - - // We want to make sure we consume all process state changes and have - // whomever is notifying us to wait for us to reset the event bit before - // continuing. - //ctx.Events().SetResetAckMask (RNBContext::event_proc_state_changed); - - DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) ...",__FUNCTION__, event_mask); - nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); - 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)); - - if (set_events) - { - if ((set_events & RNBContext::event_proc_thread_exiting) || - (set_events & RNBContext::event_proc_stdio_available)) - { - remote->FlushSTDIO(); - } - - if (set_events & RNBContext::event_proc_profile_data) - { - remote->SendAsyncProfileData(); - } - - if (set_events & RNBContext::event_darwin_log_data_available) - { - remote->SendAsyncDarwinLogData(); - } - - if (set_events & RNBContext::event_read_packet_available) - { - // handleReceivedPacket will take care of resetting the - // event_read_packet_available events when there are no more... - set_events ^= RNBContext::event_read_packet_available; - - if (ctx.ProcessStateRunning()) - { - if (remote->HandleAsyncPacket() == rnb_not_connected) - { - // TODO: connect again? Exit? - } - } - else - { - if (remote->HandleReceivedPacket() == rnb_not_connected) - { - // TODO: connect again? Exit? - } - } - } - - if (set_events & RNBContext::event_proc_state_changed) - { - mode = HandleProcessStateChange (remote, false); - ctx.Events().ResetEvents(RNBContext::event_proc_state_changed); - set_events ^= RNBContext::event_proc_state_changed; - } +RNBRunLoopMode RNBRunLoopInferiorExecuting(RNBRemote *remote) { + DNBLogThreadedIf(LOG_RNB_MINIMAL, "#### %s", __FUNCTION__); + RNBContext &ctx = remote->Context(); + + // Init our mode and set 'is_running' based on the current process state + RNBRunLoopMode mode = HandleProcessStateChange(remote, true); + + while (ctx.ProcessID() != INVALID_NUB_PROCESS) { + + std::string set_events_str; + uint32_t event_mask = ctx.NormalEventBits(); + + if (!ctx.ProcessStateRunning()) { + // Clear some bits if we are not running so we don't send any async + // packets + event_mask &= ~RNBContext::event_proc_stdio_available; + event_mask &= ~RNBContext::event_proc_profile_data; + // When we enable async structured data packets over another logical + // channel, + // this can be relaxed. + event_mask &= ~RNBContext::event_darwin_log_data_available; + } - if (set_events & RNBContext::event_proc_thread_exiting) - { - mode = eRNBRunLoopModeExit; + // We want to make sure we consume all process state changes and have + // whomever is notifying us to wait for us to reset the event bit before + // continuing. + // ctx.Events().SetResetAckMask (RNBContext::event_proc_state_changed); + + DNBLogThreadedIf(LOG_RNB_EVENTS, + "%s ctx.Events().WaitForSetEvents(0x%08x) ...", + __FUNCTION__, event_mask); + nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); + 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)); + + if (set_events) { + if ((set_events & RNBContext::event_proc_thread_exiting) || + (set_events & RNBContext::event_proc_stdio_available)) { + remote->FlushSTDIO(); + } + + if (set_events & RNBContext::event_proc_profile_data) { + remote->SendAsyncProfileData(); + } + + if (set_events & RNBContext::event_darwin_log_data_available) { + remote->SendAsyncDarwinLogData(); + } + + if (set_events & RNBContext::event_read_packet_available) { + // handleReceivedPacket will take care of resetting the + // event_read_packet_available events when there are no more... + set_events ^= RNBContext::event_read_packet_available; + + if (ctx.ProcessStateRunning()) { + if (remote->HandleAsyncPacket() == rnb_not_connected) { + // TODO: connect again? Exit? + } + } else { + if (remote->HandleReceivedPacket() == rnb_not_connected) { + // TODO: connect again? Exit? + } + } + } + + if (set_events & RNBContext::event_proc_state_changed) { + mode = HandleProcessStateChange(remote, false); + ctx.Events().ResetEvents(RNBContext::event_proc_state_changed); + set_events ^= RNBContext::event_proc_state_changed; + } + + if (set_events & RNBContext::event_proc_thread_exiting) { + mode = eRNBRunLoopModeExit; + } + + if (set_events & RNBContext::event_read_thread_exiting) { + // Out remote packet receiving thread exited, exit for now. + if (ctx.HasValidProcessID()) { + // TODO: We should add code that will leave the current process + // in its current state and listen for another connection... + if (ctx.ProcessStateRunning()) { + if (ctx.GetDetachOnError()) { + DNBLog("debugserver's event read thread is exiting, detaching " + "from the inferior process."); + DNBProcessDetach(ctx.ProcessID()); + } else { + DNBLog("debugserver's event read thread is exiting, killing the " + "inferior process."); + DNBProcessKill(ctx.ProcessID()); } - - if (set_events & RNBContext::event_read_thread_exiting) - { - // Out remote packet receiving thread exited, exit for now. - if (ctx.HasValidProcessID()) - { - // TODO: We should add code that will leave the current process - // in its current state and listen for another connection... - if (ctx.ProcessStateRunning()) - { - if (ctx.GetDetachOnError()) - { - DNBLog ("debugserver's event read thread is exiting, detaching from the inferior process."); - DNBProcessDetach (ctx.ProcessID()); - } - else - { - DNBLog ("debugserver's event read thread is exiting, killing the inferior process."); - DNBProcessKill (ctx.ProcessID()); - } - } - else - { - if (ctx.GetDetachOnError()) - { - DNBLog ("debugserver's event read thread is exiting, detaching from the inferior process."); - DNBProcessDetach (ctx.ProcessID()); - } - } - } - mode = eRNBRunLoopModeExit; + } else { + if (ctx.GetDetachOnError()) { + DNBLog("debugserver's event read thread is exiting, detaching " + "from the inferior process."); + DNBProcessDetach(ctx.ProcessID()); } + } } - - // Reset all event bits that weren't reset for now... - if (set_events != 0) - ctx.Events().ResetEvents(set_events); - - if (mode != eRNBRunLoopModeInferiorExecuting) - break; + mode = eRNBRunLoopModeExit; + } } - return mode; -} + // Reset all event bits that weren't reset for now... + if (set_events != 0) + ctx.Events().ResetEvents(set_events); + if (mode != eRNBRunLoopModeInferiorExecuting) + break; + } -RNBRunLoopMode -RNBRunLoopPlatform (RNBRemote *remote) -{ - RNBRunLoopMode mode = eRNBRunLoopModePlatformMode; - RNBContext& ctx = remote->Context(); - - while (mode == eRNBRunLoopModePlatformMode) - { - std::string set_events_str; - const uint32_t event_mask = RNBContext::event_read_packet_available | - RNBContext::event_read_thread_exiting; - - DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) ...",__FUNCTION__, event_mask); - nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); - 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)); - - if (set_events) - { - if (set_events & RNBContext::event_read_packet_available) - { - if (remote->HandleReceivedPacket() == rnb_not_connected) - mode = eRNBRunLoopModeExit; - } + return mode; +} - if (set_events & RNBContext::event_read_thread_exiting) - { - mode = eRNBRunLoopModeExit; - } - ctx.Events().ResetEvents(set_events); - } +RNBRunLoopMode RNBRunLoopPlatform(RNBRemote *remote) { + RNBRunLoopMode mode = eRNBRunLoopModePlatformMode; + RNBContext &ctx = remote->Context(); + + while (mode == eRNBRunLoopModePlatformMode) { + std::string set_events_str; + const uint32_t event_mask = RNBContext::event_read_packet_available | + RNBContext::event_read_thread_exiting; + + DNBLogThreadedIf(LOG_RNB_EVENTS, + "%s ctx.Events().WaitForSetEvents(0x%08x) ...", + __FUNCTION__, event_mask); + nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); + 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)); + + if (set_events) { + if (set_events & RNBContext::event_read_packet_available) { + if (remote->HandleReceivedPacket() == rnb_not_connected) + mode = eRNBRunLoopModeExit; + } + + if (set_events & RNBContext::event_read_thread_exiting) { + mode = eRNBRunLoopModeExit; + } + ctx.Events().ResetEvents(set_events); } - return eRNBRunLoopModeExit; + } + return eRNBRunLoopModeExit; } //---------------------------------------------------------------------- @@ -675,1070 +659,1014 @@ RNBRunLoopPlatform (RNBRemote *remote) // Returns 1 for success 0 for failure. //---------------------------------------------------------------------- -static void -PortWasBoundCallbackUnixSocket (const void *baton, in_port_t port) -{ - //::printf ("PortWasBoundCallbackUnixSocket (baton = %p, port = %u)\n", baton, port); - - const char *unix_socket_name = (const char *)baton; - - if (unix_socket_name && unix_socket_name[0]) - { - // We were given a unix socket name to use to communicate the port - // that we ended up binding to back to our parent process - struct sockaddr_un saddr_un; - int s = ::socket (AF_UNIX, SOCK_STREAM, 0); - if (s < 0) - { - perror("error: socket (AF_UNIX, SOCK_STREAM, 0)"); - exit(1); - } - - saddr_un.sun_family = AF_UNIX; - ::strncpy(saddr_un.sun_path, unix_socket_name, sizeof(saddr_un.sun_path) - 1); - saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0'; - saddr_un.sun_len = SUN_LEN (&saddr_un); +static void PortWasBoundCallbackUnixSocket(const void *baton, in_port_t port) { + //::printf ("PortWasBoundCallbackUnixSocket (baton = %p, port = %u)\n", baton, + //port); - if (::connect (s, (struct sockaddr *)&saddr_un, static_cast<socklen_t>(SUN_LEN (&saddr_un))) < 0) - { - perror("error: connect (socket, &saddr_un, saddr_un_len)"); - exit(1); - } + const char *unix_socket_name = (const char *)baton; - //::printf ("connect () sucess!!\n"); + if (unix_socket_name && unix_socket_name[0]) { + // We were given a unix socket name to use to communicate the port + // that we ended up binding to back to our parent process + struct sockaddr_un saddr_un; + int s = ::socket(AF_UNIX, SOCK_STREAM, 0); + if (s < 0) { + perror("error: socket (AF_UNIX, SOCK_STREAM, 0)"); + exit(1); + } + saddr_un.sun_family = AF_UNIX; + ::strncpy(saddr_un.sun_path, unix_socket_name, + sizeof(saddr_un.sun_path) - 1); + saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0'; + saddr_un.sun_len = SUN_LEN(&saddr_un); - // We were able to connect to the socket, now write our PID so whomever - // launched us will know this process's ID - RNBLogSTDOUT ("Listening to port %i...\n", port); + if (::connect(s, (struct sockaddr *)&saddr_un, + static_cast<socklen_t>(SUN_LEN(&saddr_un))) < 0) { + perror("error: connect (socket, &saddr_un, saddr_un_len)"); + exit(1); + } - char pid_str[64]; - const int pid_str_len = ::snprintf (pid_str, sizeof(pid_str), "%u", port); - const ssize_t bytes_sent = ::send (s, pid_str, pid_str_len, 0); + //::printf ("connect () sucess!!\n"); - if (pid_str_len != bytes_sent) - { - perror("error: send (s, pid_str, pid_str_len, 0)"); - exit (1); - } + // We were able to connect to the socket, now write our PID so whomever + // launched us will know this process's ID + RNBLogSTDOUT("Listening to port %i...\n", port); - //::printf ("send () sucess!!\n"); + char pid_str[64]; + const int pid_str_len = ::snprintf(pid_str, sizeof(pid_str), "%u", port); + const ssize_t bytes_sent = ::send(s, pid_str, pid_str_len, 0); - // We are done with the socket - close (s); + if (pid_str_len != bytes_sent) { + perror("error: send (s, pid_str, pid_str_len, 0)"); + exit(1); } + + //::printf ("send () sucess!!\n"); + + // We are done with the socket + close(s); + } } -static void -PortWasBoundCallbackNamedPipe (const void *baton, uint16_t port) -{ - const char *named_pipe = (const char *)baton; - if (named_pipe && named_pipe[0]) - { - int fd = ::open(named_pipe, O_WRONLY); - if (fd > -1) - { - char port_str[64]; - const ssize_t port_str_len = ::snprintf (port_str, sizeof(port_str), "%u", port); - // Write the port number as a C string with the NULL terminator - ::write (fd, port_str, port_str_len + 1); - close (fd); - } +static void PortWasBoundCallbackNamedPipe(const void *baton, uint16_t port) { + const char *named_pipe = (const char *)baton; + if (named_pipe && named_pipe[0]) { + int fd = ::open(named_pipe, O_WRONLY); + if (fd > -1) { + char port_str[64]; + const ssize_t port_str_len = + ::snprintf(port_str, sizeof(port_str), "%u", port); + // Write the port number as a C string with the NULL terminator + ::write(fd, port_str, port_str_len + 1); + close(fd); } + } } -static int -ConnectRemote (RNBRemote *remote, - const char *host, - int port, - bool reverse_connect, - const char *named_pipe_path, - const char *unix_socket_name) -{ - if (!remote->Comm().IsConnected()) - { - if (reverse_connect) - { - if (port == 0) - { - DNBLogThreaded("error: invalid port supplied for reverse connection: %i.\n", port); - return 0; - } - if (remote->Comm().Connect(host, port) != rnb_success) - { - DNBLogThreaded("Failed to reverse connect to %s:%i.\n", host, port); - return 0; - } +static int ConnectRemote(RNBRemote *remote, const char *host, int port, + bool reverse_connect, const char *named_pipe_path, + const char *unix_socket_name) { + if (!remote->Comm().IsConnected()) { + if (reverse_connect) { + if (port == 0) { + DNBLogThreaded( + "error: invalid port supplied for reverse connection: %i.\n", port); + return 0; + } + if (remote->Comm().Connect(host, port) != rnb_success) { + DNBLogThreaded("Failed to reverse connect to %s:%i.\n", host, port); + return 0; + } + } else { + if (port != 0) + RNBLogSTDOUT("Listening to port %i for a connection from %s...\n", port, + host ? host : "127.0.0.1"); + if (unix_socket_name && unix_socket_name[0]) { + if (remote->Comm().Listen(host, port, PortWasBoundCallbackUnixSocket, + unix_socket_name) != rnb_success) { + RNBLogSTDERR("Failed to get connection from a remote gdb process.\n"); + return 0; } - else - { - if (port != 0) - RNBLogSTDOUT ("Listening to port %i for a connection from %s...\n", port, host ? host : "127.0.0.1"); - if (unix_socket_name && unix_socket_name[0]) - { - if (remote->Comm().Listen(host, port, PortWasBoundCallbackUnixSocket, unix_socket_name) != rnb_success) - { - RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n"); - return 0; - } - } - else - { - if (remote->Comm().Listen(host, port, PortWasBoundCallbackNamedPipe, named_pipe_path) != rnb_success) - { - RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n"); - return 0; - } - } + } else { + if (remote->Comm().Listen(host, port, PortWasBoundCallbackNamedPipe, + named_pipe_path) != rnb_success) { + RNBLogSTDERR("Failed to get connection from a remote gdb process.\n"); + return 0; } - remote->StartReadRemoteDataThread(); + } } - return 1; + remote->StartReadRemoteDataThread(); + } + return 1; } //---------------------------------------------------------------------- // ASL Logging callback that can be registered with DNBLogSetLogCallback //---------------------------------------------------------------------- -void -ASLLogCallback(void *baton, uint32_t flags, const char *format, va_list args) -{ - if (format == NULL) - return; - static aslmsg g_aslmsg = NULL; - if (g_aslmsg == NULL) - { - g_aslmsg = ::asl_new (ASL_TYPE_MSG); - char asl_key_sender[PATH_MAX]; - snprintf(asl_key_sender, sizeof(asl_key_sender), "com.apple.%s-%s", DEBUGSERVER_PROGRAM_NAME, DEBUGSERVER_VERSION_STR); - ::asl_set (g_aslmsg, ASL_KEY_SENDER, asl_key_sender); - } - - int asl_level; - if (flags & DNBLOG_FLAG_FATAL) asl_level = ASL_LEVEL_CRIT; - else if (flags & DNBLOG_FLAG_ERROR) asl_level = ASL_LEVEL_ERR; - else if (flags & DNBLOG_FLAG_WARNING) asl_level = ASL_LEVEL_WARNING; - else if (flags & DNBLOG_FLAG_VERBOSE) asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_INFO; - else asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_DEBUG; - - ::asl_vlog (NULL, g_aslmsg, asl_level, format, args); +void ASLLogCallback(void *baton, uint32_t flags, const char *format, + va_list args) { + if (format == NULL) + return; + static aslmsg g_aslmsg = NULL; + if (g_aslmsg == NULL) { + g_aslmsg = ::asl_new(ASL_TYPE_MSG); + char asl_key_sender[PATH_MAX]; + snprintf(asl_key_sender, sizeof(asl_key_sender), "com.apple.%s-%s", + DEBUGSERVER_PROGRAM_NAME, DEBUGSERVER_VERSION_STR); + ::asl_set(g_aslmsg, ASL_KEY_SENDER, asl_key_sender); + } + + int asl_level; + if (flags & DNBLOG_FLAG_FATAL) + asl_level = ASL_LEVEL_CRIT; + else if (flags & DNBLOG_FLAG_ERROR) + asl_level = ASL_LEVEL_ERR; + else if (flags & DNBLOG_FLAG_WARNING) + asl_level = ASL_LEVEL_WARNING; + else if (flags & DNBLOG_FLAG_VERBOSE) + asl_level = ASL_LEVEL_WARNING; // ASL_LEVEL_INFO; + else + asl_level = ASL_LEVEL_WARNING; // ASL_LEVEL_DEBUG; + + ::asl_vlog(NULL, g_aslmsg, asl_level, format, args); } //---------------------------------------------------------------------- // FILE based Logging callback that can be registered with // DNBLogSetLogCallback //---------------------------------------------------------------------- -void -FileLogCallback(void *baton, uint32_t flags, const char *format, va_list args) -{ - if (baton == NULL || format == NULL) - return; - - ::vfprintf((FILE *)baton, format, args); - ::fprintf((FILE *)baton, "\n"); - ::fflush((FILE *)baton); +void FileLogCallback(void *baton, uint32_t flags, const char *format, + va_list args) { + if (baton == NULL || format == NULL) + return; + + ::vfprintf((FILE *)baton, format, args); + ::fprintf((FILE *)baton, "\n"); + ::fflush((FILE *)baton); } - -void -show_usage_and_exit (int exit_code) -{ - RNBLogSTDERR ("Usage:\n %s host:port [program-name program-arg1 program-arg2 ...]\n", DEBUGSERVER_PROGRAM_NAME); - RNBLogSTDERR (" %s /path/file [program-name program-arg1 program-arg2 ...]\n", DEBUGSERVER_PROGRAM_NAME); - RNBLogSTDERR (" %s host:port --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME); - RNBLogSTDERR (" %s /path/file --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME); - RNBLogSTDERR (" %s host:port --attach=<process_name>\n", DEBUGSERVER_PROGRAM_NAME); - RNBLogSTDERR (" %s /path/file --attach=<process_name>\n", DEBUGSERVER_PROGRAM_NAME); - exit (exit_code); +void show_usage_and_exit(int exit_code) { + RNBLogSTDERR( + "Usage:\n %s host:port [program-name program-arg1 program-arg2 ...]\n", + DEBUGSERVER_PROGRAM_NAME); + RNBLogSTDERR(" %s /path/file [program-name program-arg1 program-arg2 ...]\n", + DEBUGSERVER_PROGRAM_NAME); + RNBLogSTDERR(" %s host:port --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME); + RNBLogSTDERR(" %s /path/file --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME); + RNBLogSTDERR(" %s host:port --attach=<process_name>\n", + DEBUGSERVER_PROGRAM_NAME); + RNBLogSTDERR(" %s /path/file --attach=<process_name>\n", + DEBUGSERVER_PROGRAM_NAME); + exit(exit_code); } - //---------------------------------------------------------------------- // option descriptors for getopt_long_only() //---------------------------------------------------------------------- -static struct option g_long_options[] = -{ - { "attach", required_argument, NULL, 'a' }, - { "arch", required_argument, NULL, 'A' }, - { "debug", no_argument, NULL, 'g' }, - { "kill-on-error", no_argument, NULL, 'K' }, - { "verbose", no_argument, NULL, 'v' }, - { "lockdown", no_argument, &g_lockdown_opt, 1 }, // short option "-k" - { "applist", no_argument, &g_applist_opt, 1 }, // short option "-t" - { "log-file", required_argument, NULL, 'l' }, - { "log-flags", required_argument, NULL, 'f' }, - { "launch", required_argument, NULL, 'x' }, // Valid values are "auto", "posix-spawn", "fork-exec", "springboard" (arm only) - { "waitfor", required_argument, NULL, 'w' }, // Wait for a process whose name starts with ARG - { "waitfor-interval", required_argument, NULL, 'i' }, // Time in usecs to wait between sampling the pid list when waiting for a process by name - { "waitfor-duration", required_argument, NULL, 'd' }, // The time in seconds to wait for a process to show up by name - { "native-regs", no_argument, NULL, 'r' }, // Specify to use the native registers instead of the gdb defaults for the architecture. - { "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) - { "stdin-path", required_argument, NULL, 'I' }, // Set the STDIN path to be used when launching applications (only if debugserver launches the process) - { "stdout-path", required_argument, NULL, 'O' }, // Set the STDOUT path to be used when launching applications (only if debugserver launches the process) - { "stderr-path", required_argument, NULL, 'E' }, // Set the STDERR path to be used when launching applications (only if debugserver launches the process) - { "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) - { "setsid", no_argument, NULL, 'S' }, // call setsid() to make debugserver run in its own session - { "disable-aslr", no_argument, NULL, 'D' }, // Use _POSIX_SPAWN_DISABLE_ASLR to avoid shared library randomization - { "working-dir", required_argument, NULL, 'W' }, // The working directory that the inferior process should have (only if debugserver launches the process) - { "platform", required_argument, NULL, 'p' }, // Put this executable into a remote platform mode - { "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 - { "fd", required_argument, NULL, 'FDSC' }, // A file descriptor was passed to this process when spawned that is already open and ready for communication - { "named-pipe", required_argument, NULL, 'P' }, - { "reverse-connect", no_argument, NULL, 'R' }, - { "env", required_argument, NULL, 'e' }, // When debugserver launches the process, set a single environment entry as specified by the option value ("./debugserver -e FOO=1 -e BAR=2 localhost:1234 -- /bin/ls") - { "forward-env", no_argument, NULL, 'F' }, // When debugserver launches the process, forward debugserver's current environment variables to the child process ("./debugserver -F localhost:1234 -- /bin/ls" - { NULL, 0, NULL, 0 } -}; - +static struct option g_long_options[] = { + {"attach", required_argument, NULL, 'a'}, + {"arch", required_argument, NULL, 'A'}, + {"debug", no_argument, NULL, 'g'}, + {"kill-on-error", no_argument, NULL, 'K'}, + {"verbose", no_argument, NULL, 'v'}, + {"lockdown", no_argument, &g_lockdown_opt, 1}, // short option "-k" + {"applist", no_argument, &g_applist_opt, 1}, // short option "-t" + {"log-file", required_argument, NULL, 'l'}, + {"log-flags", required_argument, NULL, 'f'}, + {"launch", required_argument, NULL, 'x'}, // Valid values are "auto", + // "posix-spawn", "fork-exec", + // "springboard" (arm only) + {"waitfor", required_argument, NULL, + 'w'}, // Wait for a process whose name starts with ARG + {"waitfor-interval", required_argument, NULL, + 'i'}, // Time in usecs to wait between sampling the pid list when waiting + // for a process by name + {"waitfor-duration", required_argument, NULL, + 'd'}, // The time in seconds to wait for a process to show up by name + {"native-regs", no_argument, NULL, 'r'}, // Specify to use the native + // registers instead of the gdb + // defaults for the architecture. + {"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) + {"stdin-path", required_argument, NULL, + 'I'}, // Set the STDIN path to be used when launching applications (only if + // debugserver launches the process) + {"stdout-path", required_argument, NULL, + 'O'}, // Set the STDOUT path to be used when launching applications (only + // if debugserver launches the process) + {"stderr-path", required_argument, NULL, + 'E'}, // Set the STDERR path to be used when launching applications (only + // if debugserver launches the process) + {"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) + {"setsid", no_argument, NULL, + 'S'}, // call setsid() to make debugserver run in its own session + {"disable-aslr", no_argument, NULL, 'D'}, // Use _POSIX_SPAWN_DISABLE_ASLR + // to avoid shared library + // randomization + {"working-dir", required_argument, NULL, + 'W'}, // The working directory that the inferior process should have (only + // if debugserver launches the process) + {"platform", required_argument, NULL, + 'p'}, // Put this executable into a remote platform mode + {"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 + {"fd", required_argument, NULL, + 'FDSC'}, // A file descriptor was passed to this process when spawned that + // is already open and ready for communication + {"named-pipe", required_argument, NULL, 'P'}, + {"reverse-connect", no_argument, NULL, 'R'}, + {"env", required_argument, NULL, + 'e'}, // When debugserver launches the process, set a single environment + // entry as specified by the option value ("./debugserver -e FOO=1 -e + // BAR=2 localhost:1234 -- /bin/ls") + {"forward-env", no_argument, NULL, + 'F'}, // When debugserver launches the process, forward debugserver's + // current environment variables to the child process ("./debugserver + // -F localhost:1234 -- /bin/ls" + {NULL, 0, NULL, 0}}; //---------------------------------------------------------------------- // main //---------------------------------------------------------------------- -int -main (int argc, char *argv[]) -{ - // If debugserver is launched with DYLD_INSERT_LIBRARIES, unset it so we - // don't spawn child processes with this enabled. - unsetenv("DYLD_INSERT_LIBRARIES"); - - const char *argv_sub_zero = argv[0]; // save a copy of argv[0] for error reporting post-launch - -#if defined (__APPLE__) - pthread_setname_np ("main thread"); -#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__) - struct sched_param thread_param; - int thread_sched_policy; - if (pthread_getschedparam(pthread_self(), &thread_sched_policy, &thread_param) == 0) - { - thread_param.sched_priority = 47; - pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param); - } - - ::proc_set_wakemon_params (getpid(), 500, 0); // Allow up to 500 wakeups/sec to avoid EXC_RESOURCE for normal use. +int main(int argc, char *argv[]) { + // If debugserver is launched with DYLD_INSERT_LIBRARIES, unset it so we + // don't spawn child processes with this enabled. + unsetenv("DYLD_INSERT_LIBRARIES"); + + const char *argv_sub_zero = + argv[0]; // save a copy of argv[0] for error reporting post-launch + +#if defined(__APPLE__) + pthread_setname_np("main thread"); +#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) + struct sched_param thread_param; + int thread_sched_policy; + if (pthread_getschedparam(pthread_self(), &thread_sched_policy, + &thread_param) == 0) { + thread_param.sched_priority = 47; + pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param); + } + + ::proc_set_wakemon_params( + getpid(), 500, + 0); // Allow up to 500 wakeups/sec to avoid EXC_RESOURCE for normal use. #endif #endif - g_isatty = ::isatty (STDIN_FILENO); - - // ::printf ("uid=%u euid=%u gid=%u egid=%u\n", - // getuid(), - // geteuid(), - // getgid(), - // getegid()); - - - // signal (SIGINT, signal_handler); - signal (SIGPIPE, signal_handler); - signal (SIGHUP, signal_handler); - - // We're always sitting in waitpid or kevent waiting on our target process' death, - // we don't need no stinking SIGCHLD's... - - sigset_t sigset; - sigemptyset(&sigset); - sigaddset(&sigset, SIGCHLD); - sigprocmask(SIG_BLOCK, &sigset, NULL); - - g_remoteSP.reset (new RNBRemote ()); - - - RNBRemote *remote = g_remoteSP.get(); - if (remote == NULL) - { - RNBLogSTDERR ("error: failed to create a remote connection class\n"); - return -1; - } - - RNBContext& ctx = remote->Context(); - - int i; - int attach_pid = INVALID_NUB_PROCESS; - - FILE* log_file = NULL; - uint32_t log_flags = 0; - // Parse our options - int ch; - int long_option_index = 0; - int debug = 0; - int communication_fd = -1; - std::string compile_options; - std::string waitfor_pid_name; // Wait for a process that starts with this name - std::string attach_pid_name; - std::string arch_name; - std::string working_dir; // The new working directory to use for the inferior - 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 - std::string named_pipe_path; // If we need to handshake with our parent process, an option will be passed down that specifies a named pipe to use - useconds_t waitfor_interval = 1000; // Time in usecs between process lists polls when waiting for a process by name, default 1 msec. - useconds_t waitfor_duration = 0; // Time in seconds to wait for a process by name, 0 means wait forever. - bool no_stdio = false; - bool reverse_connect = false; // Set to true by an option to indicate we should reverse connect to the host:port supplied as the first debugserver argument - -#if !defined (DNBLOG_ENABLED) - compile_options += "(no-logging) "; + g_isatty = ::isatty(STDIN_FILENO); + + // ::printf ("uid=%u euid=%u gid=%u egid=%u\n", + // getuid(), + // geteuid(), + // getgid(), + // getegid()); + + // signal (SIGINT, signal_handler); + signal(SIGPIPE, signal_handler); + signal(SIGHUP, signal_handler); + + // We're always sitting in waitpid or kevent waiting on our target process' + // death, + // we don't need no stinking SIGCHLD's... + + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGCHLD); + sigprocmask(SIG_BLOCK, &sigset, NULL); + + g_remoteSP.reset(new RNBRemote()); + + RNBRemote *remote = g_remoteSP.get(); + if (remote == NULL) { + RNBLogSTDERR("error: failed to create a remote connection class\n"); + return -1; + } + + RNBContext &ctx = remote->Context(); + + int i; + int attach_pid = INVALID_NUB_PROCESS; + + FILE *log_file = NULL; + uint32_t log_flags = 0; + // Parse our options + int ch; + int long_option_index = 0; + int debug = 0; + int communication_fd = -1; + std::string compile_options; + std::string waitfor_pid_name; // Wait for a process that starts with this name + std::string attach_pid_name; + std::string arch_name; + std::string working_dir; // The new working directory to use for the inferior + 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 + std::string named_pipe_path; // If we need to handshake with our parent + // process, an option will be passed down that + // specifies a named pipe to use + useconds_t waitfor_interval = 1000; // Time in usecs between process lists + // polls when waiting for a process by + // name, default 1 msec. + useconds_t waitfor_duration = + 0; // Time in seconds to wait for a process by name, 0 means wait forever. + bool no_stdio = false; + bool reverse_connect = false; // Set to true by an option to indicate we + // should reverse connect to the host:port + // supplied as the first debugserver argument + +#if !defined(DNBLOG_ENABLED) + compile_options += "(no-logging) "; #endif - RNBRunLoopMode start_mode = eRNBRunLoopModeExit; - - char short_options[512]; - uint32_t short_options_idx = 0; - - // Handle the two case that don't have short options in g_long_options - short_options[short_options_idx++] = 'k'; - short_options[short_options_idx++] = 't'; - - for (i=0; g_long_options[i].name != NULL; ++i) - { - if (isalpha(g_long_options[i].val)) - { - short_options[short_options_idx++] = g_long_options[i].val; - switch (g_long_options[i].has_arg) - { - default: - case no_argument: - break; - - case optional_argument: - short_options[short_options_idx++] = ':'; - // Fall through to required_argument case below... - case required_argument: - short_options[short_options_idx++] = ':'; - break; - } - } + RNBRunLoopMode start_mode = eRNBRunLoopModeExit; + + char short_options[512]; + uint32_t short_options_idx = 0; + + // Handle the two case that don't have short options in g_long_options + short_options[short_options_idx++] = 'k'; + short_options[short_options_idx++] = 't'; + + for (i = 0; g_long_options[i].name != NULL; ++i) { + if (isalpha(g_long_options[i].val)) { + short_options[short_options_idx++] = g_long_options[i].val; + switch (g_long_options[i].has_arg) { + default: + case no_argument: + break; + + case optional_argument: + short_options[short_options_idx++] = ':'; + // Fall through to required_argument case below... + case required_argument: + short_options[short_options_idx++] = ':'; + break; + } } - // NULL terminate the short option string. - short_options[short_options_idx++] = '\0'; + } + // NULL terminate the short option string. + short_options[short_options_idx++] = '\0'; #if __GLIBC__ - optind = 0; + optind = 0; #else - optreset = 1; - optind = 1; + optreset = 1; + optind = 1; #endif - while ((ch = getopt_long_only(argc, argv, short_options, g_long_options, &long_option_index)) != -1) - { - DNBLogDebug("option: ch == %c (0x%2.2x) --%s%c%s\n", - ch, (uint8_t)ch, - g_long_options[long_option_index].name, - g_long_options[long_option_index].has_arg ? '=' : ' ', - optarg ? optarg : ""); - switch (ch) - { - case 0: // Any optional that auto set themselves will return 0 - break; - - case 'A': - if (optarg && optarg[0]) - arch_name.assign(optarg); - break; - - case 'a': - if (optarg && optarg[0]) - { - if (isdigit(optarg[0])) - { - char *end = NULL; - attach_pid = static_cast<int>(strtoul(optarg, &end, 0)); - if (end == NULL || *end != '\0') - { - RNBLogSTDERR ("error: invalid pid option '%s'\n", optarg); - exit (4); - } - } - else - { - attach_pid_name = optarg; - } - start_mode = eRNBRunLoopModeInferiorAttaching; - } - break; - - // --waitfor=NAME - case 'w': - if (optarg && optarg[0]) - { - waitfor_pid_name = optarg; - start_mode = eRNBRunLoopModeInferiorAttaching; - } - break; - - // --waitfor-interval=USEC - case 'i': - if (optarg && optarg[0]) - { - char *end = NULL; - waitfor_interval = static_cast<useconds_t>(strtoul(optarg, &end, 0)); - if (end == NULL || *end != '\0') - { - RNBLogSTDERR ("error: invalid waitfor-interval option value '%s'.\n", optarg); - exit (6); - } - } - break; - - // --waitfor-duration=SEC - case 'd': - if (optarg && optarg[0]) - { - char *end = NULL; - waitfor_duration = static_cast<useconds_t>(strtoul(optarg, &end, 0)); - if (end == NULL || *end != '\0') - { - RNBLogSTDERR ("error: invalid waitfor-duration option value '%s'.\n", optarg); - exit (7); - } - } - break; - - case 'K': - g_detach_on_error = false; - break; - case 'W': - if (optarg && optarg[0]) - working_dir.assign(optarg); - break; - - case 'x': - if (optarg && optarg[0]) - { - if (strcasecmp(optarg, "auto") == 0) - g_launch_flavor = eLaunchFlavorDefault; - else if (strcasestr(optarg, "posix") == optarg) - g_launch_flavor = eLaunchFlavorPosixSpawn; - else if (strcasestr(optarg, "fork") == optarg) - g_launch_flavor = eLaunchFlavorForkExec; + while ((ch = getopt_long_only(argc, argv, short_options, g_long_options, + &long_option_index)) != -1) { + DNBLogDebug("option: ch == %c (0x%2.2x) --%s%c%s\n", ch, (uint8_t)ch, + g_long_options[long_option_index].name, + g_long_options[long_option_index].has_arg ? '=' : ' ', + optarg ? optarg : ""); + switch (ch) { + case 0: // Any optional that auto set themselves will return 0 + break; + + case 'A': + if (optarg && optarg[0]) + arch_name.assign(optarg); + break; + + case 'a': + if (optarg && optarg[0]) { + if (isdigit(optarg[0])) { + char *end = NULL; + attach_pid = static_cast<int>(strtoul(optarg, &end, 0)); + if (end == NULL || *end != '\0') { + RNBLogSTDERR("error: invalid pid option '%s'\n", optarg); + exit(4); + } + } else { + attach_pid_name = optarg; + } + start_mode = eRNBRunLoopModeInferiorAttaching; + } + break; + + // --waitfor=NAME + case 'w': + if (optarg && optarg[0]) { + waitfor_pid_name = optarg; + start_mode = eRNBRunLoopModeInferiorAttaching; + } + break; + + // --waitfor-interval=USEC + case 'i': + if (optarg && optarg[0]) { + char *end = NULL; + waitfor_interval = static_cast<useconds_t>(strtoul(optarg, &end, 0)); + if (end == NULL || *end != '\0') { + RNBLogSTDERR("error: invalid waitfor-interval option value '%s'.\n", + optarg); + exit(6); + } + } + break; + + // --waitfor-duration=SEC + case 'd': + if (optarg && optarg[0]) { + char *end = NULL; + waitfor_duration = static_cast<useconds_t>(strtoul(optarg, &end, 0)); + if (end == NULL || *end != '\0') { + RNBLogSTDERR("error: invalid waitfor-duration option value '%s'.\n", + optarg); + exit(7); + } + } + break; + + case 'K': + g_detach_on_error = false; + break; + case 'W': + if (optarg && optarg[0]) + working_dir.assign(optarg); + break; + + case 'x': + if (optarg && optarg[0]) { + if (strcasecmp(optarg, "auto") == 0) + g_launch_flavor = eLaunchFlavorDefault; + else if (strcasestr(optarg, "posix") == optarg) + g_launch_flavor = eLaunchFlavorPosixSpawn; + else if (strcasestr(optarg, "fork") == optarg) + g_launch_flavor = eLaunchFlavorForkExec; #ifdef WITH_SPRINGBOARD - else if (strcasestr(optarg, "spring") == optarg) - g_launch_flavor = eLaunchFlavorSpringBoard; + else if (strcasestr(optarg, "spring") == optarg) + g_launch_flavor = eLaunchFlavorSpringBoard; #endif #ifdef WITH_BKS - else if (strcasestr(optarg, "backboard") == optarg) - g_launch_flavor = eLaunchFlavorBKS; + else if (strcasestr(optarg, "backboard") == optarg) + g_launch_flavor = eLaunchFlavorBKS; #endif #ifdef WITH_FBS - else if (strcasestr(optarg, "frontboard") == optarg) - g_launch_flavor = eLaunchFlavorFBS; + else if (strcasestr(optarg, "frontboard") == optarg) + g_launch_flavor = eLaunchFlavorFBS; #endif - else - { - RNBLogSTDERR ("error: invalid TYPE for the --launch=TYPE (-x TYPE) option: '%s'\n", optarg); - RNBLogSTDERR ("Valid values TYPE are:\n"); - RNBLogSTDERR (" auto Auto-detect the best launch method to use.\n"); - RNBLogSTDERR (" posix Launch the executable using posix_spawn.\n"); - RNBLogSTDERR (" fork Launch the executable using fork and exec.\n"); + else { + RNBLogSTDERR("error: invalid TYPE for the --launch=TYPE (-x TYPE) " + "option: '%s'\n", + optarg); + RNBLogSTDERR("Valid values TYPE are:\n"); + RNBLogSTDERR( + " auto Auto-detect the best launch method to use.\n"); + RNBLogSTDERR( + " posix Launch the executable using posix_spawn.\n"); + RNBLogSTDERR( + " fork Launch the executable using fork and exec.\n"); #ifdef WITH_SPRINGBOARD - RNBLogSTDERR (" spring Launch the executable through Springboard.\n"); + RNBLogSTDERR( + " spring Launch the executable through Springboard.\n"); #endif #ifdef WITH_BKS - RNBLogSTDERR (" backboard Launch the executable through BackBoard Services.\n"); + RNBLogSTDERR(" backboard Launch the executable through BackBoard " + "Services.\n"); #endif #ifdef WITH_FBS - RNBLogSTDERR (" frontboard Launch the executable through FrontBoard Services.\n"); + RNBLogSTDERR(" frontboard Launch the executable through FrontBoard " + "Services.\n"); #endif - exit (5); - } - } - break; - - case 'l': // Set Log File - if (optarg && optarg[0]) - { - if (strcasecmp(optarg, "stdout") == 0) - log_file = stdout; - else if (strcasecmp(optarg, "stderr") == 0) - log_file = stderr; - else - { - log_file = fopen(optarg, "w"); - if (log_file != NULL) - setlinebuf(log_file); - } - - if (log_file == NULL) - { - const char *errno_str = strerror(errno); - RNBLogSTDERR ("Failed to open log file '%s' for writing: errno = %i (%s)", optarg, errno, errno_str ? errno_str : "unknown error"); - } - } - break; - - case 'f': // Log Flags - if (optarg && optarg[0]) - log_flags = static_cast<uint32_t>(strtoul(optarg, NULL, 0)); - break; - - case 'g': - debug = 1; - DNBLogSetDebug(debug); - break; - - case 't': - g_applist_opt = 1; - break; - - case 'k': - g_lockdown_opt = 1; - break; - - case 'r': - // Do nothing, native regs is the default these days - break; - - case 'R': - reverse_connect = true; - break; - case 'v': - DNBLogSetVerbose(1); - break; - - case 's': - ctx.GetSTDIN().assign(optarg); - ctx.GetSTDOUT().assign(optarg); - ctx.GetSTDERR().assign(optarg); - break; - - case 'I': - ctx.GetSTDIN().assign(optarg); - break; - - case 'O': - ctx.GetSTDOUT().assign(optarg); - break; - - case 'E': - ctx.GetSTDERR().assign(optarg); - break; - - case 'n': - no_stdio = true; - break; - - case 'S': - // Put debugserver into a new session. Terminals group processes - // into sessions and when a special terminal key sequences - // (like control+c) are typed they can cause signals to go out to - // all processes in a session. Using this --setsid (-S) option - // will cause debugserver to run in its own sessions and be free - // from such issues. - // - // This is useful when debugserver is spawned from a command - // line application that uses debugserver to do the debugging, - // yet that application doesn't want debugserver receiving the - // signals sent to the session (i.e. dying when anyone hits ^C). - setsid(); - break; - case 'D': - g_disable_aslr = 1; - break; - - case 'p': - start_mode = eRNBRunLoopModePlatformMode; - break; - - case 'u': - unix_socket_name.assign (optarg); - break; - - case 'P': - named_pipe_path.assign (optarg); - break; - - case 'e': - // Pass a single specified environment variable down to the process that gets launched - remote->Context().PushEnvironment(optarg); - break; - - case 'F': - // Pass the current environment down to the process that gets launched - { - char **host_env = *_NSGetEnviron(); - char *env_entry; - size_t i; - for (i=0; (env_entry = host_env[i]) != NULL; ++i) - remote->Context().PushEnvironment(env_entry); - } - break; - - case 'FDSC': - // File descriptor passed to this process during fork/exec and is already - // open and ready for communication. - communication_fd = atoi(optarg); - break; + exit(5); } + } + break; + + case 'l': // Set Log File + if (optarg && optarg[0]) { + if (strcasecmp(optarg, "stdout") == 0) + log_file = stdout; + else if (strcasecmp(optarg, "stderr") == 0) + log_file = stderr; + else { + log_file = fopen(optarg, "w"); + if (log_file != NULL) + setlinebuf(log_file); + } + + if (log_file == NULL) { + const char *errno_str = strerror(errno); + RNBLogSTDERR( + "Failed to open log file '%s' for writing: errno = %i (%s)", + optarg, errno, errno_str ? errno_str : "unknown error"); + } + } + break; + + case 'f': // Log Flags + if (optarg && optarg[0]) + log_flags = static_cast<uint32_t>(strtoul(optarg, NULL, 0)); + break; + + case 'g': + debug = 1; + DNBLogSetDebug(debug); + break; + + case 't': + g_applist_opt = 1; + break; + + case 'k': + g_lockdown_opt = 1; + break; + + case 'r': + // Do nothing, native regs is the default these days + break; + + case 'R': + reverse_connect = true; + break; + case 'v': + DNBLogSetVerbose(1); + break; + + case 's': + ctx.GetSTDIN().assign(optarg); + ctx.GetSTDOUT().assign(optarg); + ctx.GetSTDERR().assign(optarg); + break; + + case 'I': + ctx.GetSTDIN().assign(optarg); + break; + + case 'O': + ctx.GetSTDOUT().assign(optarg); + break; + + case 'E': + ctx.GetSTDERR().assign(optarg); + break; + + case 'n': + no_stdio = true; + break; + + case 'S': + // Put debugserver into a new session. Terminals group processes + // into sessions and when a special terminal key sequences + // (like control+c) are typed they can cause signals to go out to + // all processes in a session. Using this --setsid (-S) option + // will cause debugserver to run in its own sessions and be free + // from such issues. + // + // This is useful when debugserver is spawned from a command + // line application that uses debugserver to do the debugging, + // yet that application doesn't want debugserver receiving the + // signals sent to the session (i.e. dying when anyone hits ^C). + setsid(); + break; + case 'D': + g_disable_aslr = 1; + break; + + case 'p': + start_mode = eRNBRunLoopModePlatformMode; + break; + + case 'u': + unix_socket_name.assign(optarg); + break; + + case 'P': + named_pipe_path.assign(optarg); + break; + + case 'e': + // Pass a single specified environment variable down to the process that + // gets launched + remote->Context().PushEnvironment(optarg); + break; + + case 'F': + // Pass the current environment down to the process that gets launched + { + char **host_env = *_NSGetEnviron(); + char *env_entry; + size_t i; + for (i = 0; (env_entry = host_env[i]) != NULL; ++i) + remote->Context().PushEnvironment(env_entry); + } + break; + + case 'FDSC': + // File descriptor passed to this process during fork/exec and is already + // open and ready for communication. + communication_fd = atoi(optarg); + break; } + } - if (arch_name.empty()) - { -#if defined (__arm__) - arch_name.assign ("arm"); + if (arch_name.empty()) { +#if defined(__arm__) + arch_name.assign("arm"); #endif + } else { + DNBSetArchitecture(arch_name.c_str()); + } + + // if (arch_name.empty()) + // { + // fprintf(stderr, "error: no architecture was specified\n"); + // exit (8); + // } + // Skip any options we consumed with getopt_long_only + argc -= optind; + argv += optind; + + if (!working_dir.empty()) { + if (remote->Context().SetWorkingDirectory(working_dir.c_str()) == false) { + RNBLogSTDERR("error: working directory doesn't exist '%s'.\n", + working_dir.c_str()); + exit(8); } - else - { - DNBSetArchitecture (arch_name.c_str()); - } + } -// if (arch_name.empty()) -// { -// fprintf(stderr, "error: no architecture was specified\n"); -// exit (8); -// } - // Skip any options we consumed with getopt_long_only - argc -= optind; - argv += optind; - - - if (!working_dir.empty()) - { - if (remote->Context().SetWorkingDirectory (working_dir.c_str()) == false) - { - RNBLogSTDERR ("error: working directory doesn't exist '%s'.\n", working_dir.c_str()); - exit (8); - } - } + remote->Context().SetDetachOnError(g_detach_on_error); - remote->Context().SetDetachOnError(g_detach_on_error); + remote->Initialize(); - remote->Initialize(); + // It is ok for us to set NULL as the logfile (this will disable any logging) - // It is ok for us to set NULL as the logfile (this will disable any logging) + if (log_file != NULL) { + DNBLogSetLogCallback(FileLogCallback, log_file); + // If our log file was set, yet we have no log flags, log everything! + if (log_flags == 0) + log_flags = LOG_ALL | LOG_RNB_ALL; - if (log_file != NULL) - { - DNBLogSetLogCallback(FileLogCallback, log_file); - // If our log file was set, yet we have no log flags, log everything! - if (log_flags == 0) - log_flags = LOG_ALL | LOG_RNB_ALL; + DNBLogSetLogMask(log_flags); + } else { + // Enable DNB logging - DNBLogSetLogMask (log_flags); + // if os_log() support is available, log through that. + auto log_callback = OsLogger::GetLogFunction(); + if (log_callback) { + DNBLogSetLogCallback(log_callback, nullptr); + DNBLog("debugserver will use os_log for internal logging."); + } else { + // Fall back to ASL support. + DNBLogSetLogCallback(ASLLogCallback, NULL); + DNBLog("debugserver will use ASL for internal logging."); } - else - { - // Enable DNB logging - - // if os_log() support is available, log through that. - auto log_callback = OsLogger::GetLogFunction(); - if (log_callback) - { - DNBLogSetLogCallback(log_callback, nullptr); - DNBLog("debugserver will use os_log for internal logging."); - } - else - { - // Fall back to ASL support. - DNBLogSetLogCallback(ASLLogCallback, NULL); - DNBLog("debugserver will use ASL for internal logging."); - } - DNBLogSetLogMask (log_flags); + DNBLogSetLogMask(log_flags); + } - } - - if (DNBLogEnabled()) - { - for (i=0; i<argc; i++) - DNBLogDebug("argv[%i] = %s", i, argv[i]); - } + if (DNBLogEnabled()) { + for (i = 0; i < argc; i++) + DNBLogDebug("argv[%i] = %s", i, argv[i]); + } - // as long as we're dropping remotenub in as a replacement for gdbserver, - // explicitly note that this is not gdbserver. - - RNBLogSTDOUT ("%s-%s %sfor %s.\n", - DEBUGSERVER_PROGRAM_NAME, - DEBUGSERVER_VERSION_STR, - compile_options.c_str(), - RNB_ARCH); - - std::string host; - int port = INT32_MAX; - char str[PATH_MAX]; - str[0] = '\0'; - - if (g_lockdown_opt == 0 && g_applist_opt == 0 && communication_fd == -1) - { - // Make sure we at least have port - if (argc < 1) - { - show_usage_and_exit (1); - } - // accept 'localhost:' prefix on port number + // as long as we're dropping remotenub in as a replacement for gdbserver, + // explicitly note that this is not gdbserver. - int items_scanned = ::sscanf (argv[0], "%[^:]:%i", str, &port); - if (items_scanned == 2) - { - host = str; - DNBLogDebug("host = '%s' port = %i", host.c_str(), port); - } - else - { - // No hostname means "localhost" - int items_scanned = ::sscanf (argv[0], "%i", &port); - if (items_scanned == 1) - { - host = "127.0.0.1"; - DNBLogDebug("host = '%s' port = %i", host.c_str(), port); - } - else if (argv[0][0] == '/') - { - port = INT32_MAX; - strncpy(str, argv[0], sizeof(str)); - } - else - { - show_usage_and_exit (2); - } - } + RNBLogSTDOUT("%s-%s %sfor %s.\n", DEBUGSERVER_PROGRAM_NAME, + DEBUGSERVER_VERSION_STR, compile_options.c_str(), RNB_ARCH); - // We just used the 'host:port' or the '/path/file' arg... - argc--; - argv++; + std::string host; + int port = INT32_MAX; + char str[PATH_MAX]; + str[0] = '\0'; + if (g_lockdown_opt == 0 && g_applist_opt == 0 && communication_fd == -1) { + // Make sure we at least have port + if (argc < 1) { + show_usage_and_exit(1); + } + // accept 'localhost:' prefix on port number + + int items_scanned = ::sscanf(argv[0], "%[^:]:%i", str, &port); + if (items_scanned == 2) { + host = str; + DNBLogDebug("host = '%s' port = %i", host.c_str(), port); + } else { + // No hostname means "localhost" + int items_scanned = ::sscanf(argv[0], "%i", &port); + if (items_scanned == 1) { + host = "127.0.0.1"; + DNBLogDebug("host = '%s' port = %i", host.c_str(), port); + } else if (argv[0][0] == '/') { + port = INT32_MAX; + strncpy(str, argv[0], sizeof(str)); + } else { + show_usage_and_exit(2); + } } - // If we know we're waiting to attach, we don't need any of this other info. - if (start_mode != eRNBRunLoopModeInferiorAttaching && - start_mode != eRNBRunLoopModePlatformMode) - { - if (argc == 0 || g_lockdown_opt) - { - if (g_lockdown_opt != 0) - { - // Work around for SIGPIPE crashes due to posix_spawn issue. - // We have to close STDOUT and STDERR, else the first time we - // try and do any, we get SIGPIPE and die as posix_spawn is - // doing bad things with our file descriptors at the moment. - int null = open("/dev/null", O_RDWR); - dup2(null, STDOUT_FILENO); - dup2(null, STDERR_FILENO); - } - else if (g_applist_opt != 0) - { - // List all applications we are able to see - std::string applist_plist; - int err = ListApplications(applist_plist, false, false); - if (err == 0) - { - fputs (applist_plist.c_str(), stdout); - } - else - { - RNBLogSTDERR ("error: ListApplications returned error %i\n", err); - } - // Exit with appropriate error if we were asked to list the applications - // with no other args were given (and we weren't trying to do this over - // lockdown) - return err; - } - - DNBLogDebug("Get args from remote protocol..."); - start_mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol; - } - else - { - start_mode = eRNBRunLoopModeInferiorLaunching; - // Fill in the argv array in the context from the rest of our args. - // Skip the name of this executable and the port number - for (int i = 0; i < argc; i++) - { - DNBLogDebug("inferior_argv[%i] = '%s'", i, argv[i]); - ctx.PushArgument (argv[i]); - } + // We just used the 'host:port' or the '/path/file' arg... + argc--; + argv++; + } + + // If we know we're waiting to attach, we don't need any of this other info. + if (start_mode != eRNBRunLoopModeInferiorAttaching && + start_mode != eRNBRunLoopModePlatformMode) { + if (argc == 0 || g_lockdown_opt) { + if (g_lockdown_opt != 0) { + // Work around for SIGPIPE crashes due to posix_spawn issue. + // We have to close STDOUT and STDERR, else the first time we + // try and do any, we get SIGPIPE and die as posix_spawn is + // doing bad things with our file descriptors at the moment. + int null = open("/dev/null", O_RDWR); + dup2(null, STDOUT_FILENO); + dup2(null, STDERR_FILENO); + } else if (g_applist_opt != 0) { + // List all applications we are able to see + std::string applist_plist; + int err = ListApplications(applist_plist, false, false); + if (err == 0) { + fputs(applist_plist.c_str(), stdout); + } else { + RNBLogSTDERR("error: ListApplications returned error %i\n", err); } + // Exit with appropriate error if we were asked to list the applications + // with no other args were given (and we weren't trying to do this over + // lockdown) + return err; + } + + DNBLogDebug("Get args from remote protocol..."); + start_mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol; + } else { + start_mode = eRNBRunLoopModeInferiorLaunching; + // Fill in the argv array in the context from the rest of our args. + // Skip the name of this executable and the port number + for (int i = 0; i < argc; i++) { + DNBLogDebug("inferior_argv[%i] = '%s'", i, argv[i]); + ctx.PushArgument(argv[i]); + } } + } - if (start_mode == eRNBRunLoopModeExit) - return -1; + if (start_mode == eRNBRunLoopModeExit) + return -1; - RNBRunLoopMode mode = start_mode; - char err_str[1024] = {'\0'}; + RNBRunLoopMode mode = start_mode; + char err_str[1024] = {'\0'}; - while (mode != eRNBRunLoopModeExit) - { - switch (mode) - { - case eRNBRunLoopModeGetStartModeFromRemoteProtocol: + while (mode != eRNBRunLoopModeExit) { + switch (mode) { + case eRNBRunLoopModeGetStartModeFromRemoteProtocol: #ifdef WITH_LOCKDOWN - if (g_lockdown_opt) - { - if (!remote->Comm().IsConnected()) - { - if (remote->Comm().ConnectToService () != rnb_success) - { - RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n"); - mode = eRNBRunLoopModeExit; - } - else if (g_applist_opt != 0) - { - // List all applications we are able to see - std::string applist_plist; - if (ListApplications(applist_plist, false, false) == 0) - { - DNBLogDebug("Task list: %s", applist_plist.c_str()); - - remote->Comm().Write(applist_plist.c_str(), applist_plist.size()); - // Issue a read that will never yield any data until the other side - // closes the socket so this process doesn't just exit and cause the - // socket to close prematurely on the other end and cause data loss. - std::string buf; - remote->Comm().Read(buf); - } - remote->Comm().Disconnect(false); - mode = eRNBRunLoopModeExit; - break; - } - else - { - // Start watching for remote packets - remote->StartReadRemoteDataThread(); - } - } - } - else + if (g_lockdown_opt) { + if (!remote->Comm().IsConnected()) { + if (remote->Comm().ConnectToService() != rnb_success) { + RNBLogSTDERR( + "Failed to get connection from a remote gdb process.\n"); + mode = eRNBRunLoopModeExit; + } else if (g_applist_opt != 0) { + // List all applications we are able to see + std::string applist_plist; + if (ListApplications(applist_plist, false, false) == 0) { + DNBLogDebug("Task list: %s", applist_plist.c_str()); + + remote->Comm().Write(applist_plist.c_str(), applist_plist.size()); + // Issue a read that will never yield any data until the other + // side + // closes the socket so this process doesn't just exit and cause + // the + // socket to close prematurely on the other end and cause data + // loss. + std::string buf; + remote->Comm().Read(buf); + } + remote->Comm().Disconnect(false); + mode = eRNBRunLoopModeExit; + break; + } else { + // Start watching for remote packets + remote->StartReadRemoteDataThread(); + } + } + } else #endif - if (port != INT32_MAX) - { - if (!ConnectRemote (remote, host.c_str(), port, reverse_connect, named_pipe_path.c_str(), unix_socket_name.c_str())) - mode = eRNBRunLoopModeExit; - } - else if (str[0] == '/') - { - if (remote->Comm().OpenFile (str)) - mode = eRNBRunLoopModeExit; - } - else if (communication_fd >= 0) - { - // We were passed a file descriptor to use during fork/exec that is already open - // in our process, so lets just use it! - if (remote->Comm().useFD(communication_fd)) - mode = eRNBRunLoopModeExit; - else - remote->StartReadRemoteDataThread(); - } - - if (mode != eRNBRunLoopModeExit) - { - RNBLogSTDOUT ("Got a connection, waiting for process information for launching or attaching.\n"); - - mode = RNBRunLoopGetStartModeFromRemote (remote); - } - break; - - case eRNBRunLoopModeInferiorAttaching: - if (!waitfor_pid_name.empty()) - { - // Set our end wait time if we are using a waitfor-duration - // option that may have been specified - struct timespec attach_timeout_abstime, *timeout_ptr = NULL; - if (waitfor_duration != 0) - { - DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0); - timeout_ptr = &attach_timeout_abstime; - } - nub_launch_flavor_t launch_flavor = g_launch_flavor; - if (launch_flavor == eLaunchFlavorDefault) - { - // Our default launch method is posix spawn - launch_flavor = eLaunchFlavorPosixSpawn; + if (port != INT32_MAX) { + if (!ConnectRemote(remote, host.c_str(), port, reverse_connect, + named_pipe_path.c_str(), unix_socket_name.c_str())) + mode = eRNBRunLoopModeExit; + } else if (str[0] == '/') { + if (remote->Comm().OpenFile(str)) + mode = eRNBRunLoopModeExit; + } else if (communication_fd >= 0) { + // We were passed a file descriptor to use during fork/exec that is + // already open + // in our process, so lets just use it! + if (remote->Comm().useFD(communication_fd)) + mode = eRNBRunLoopModeExit; + else + remote->StartReadRemoteDataThread(); + } + + if (mode != eRNBRunLoopModeExit) { + RNBLogSTDOUT("Got a connection, waiting for process information for " + "launching or attaching.\n"); + + mode = RNBRunLoopGetStartModeFromRemote(remote); + } + break; + + case eRNBRunLoopModeInferiorAttaching: + if (!waitfor_pid_name.empty()) { + // Set our end wait time if we are using a waitfor-duration + // option that may have been specified + struct timespec attach_timeout_abstime, *timeout_ptr = NULL; + if (waitfor_duration != 0) { + DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, + 0); + timeout_ptr = &attach_timeout_abstime; + } + nub_launch_flavor_t launch_flavor = g_launch_flavor; + if (launch_flavor == eLaunchFlavorDefault) { + // Our default launch method is posix spawn + launch_flavor = eLaunchFlavorPosixSpawn; #if defined WITH_FBS - // Check if we have an app bundle, if so launch using SpringBoard. - if (waitfor_pid_name.find (".app") != std::string::npos) - { - launch_flavor = eLaunchFlavorFBS; - } + // Check if we have an app bundle, if so launch using SpringBoard. + if (waitfor_pid_name.find(".app") != std::string::npos) { + launch_flavor = eLaunchFlavorFBS; + } #elif defined WITH_BKS - // Check if we have an app bundle, if so launch using SpringBoard. - if (waitfor_pid_name.find (".app") != std::string::npos) - { - launch_flavor = eLaunchFlavorBKS; - } + // Check if we have an app bundle, if so launch using SpringBoard. + if (waitfor_pid_name.find(".app") != std::string::npos) { + launch_flavor = eLaunchFlavorBKS; + } #elif defined WITH_SPRINGBOARD - // Check if we have an app bundle, if so launch using SpringBoard. - if (waitfor_pid_name.find (".app") != std::string::npos) - { - launch_flavor = eLaunchFlavorSpringBoard; - } + // Check if we have an app bundle, if so launch using SpringBoard. + if (waitfor_pid_name.find(".app") != std::string::npos) { + launch_flavor = eLaunchFlavorSpringBoard; + } #endif - } - - ctx.SetLaunchFlavor(launch_flavor); - bool ignore_existing = false; - RNBLogSTDOUT ("Waiting to attach to process %s...\n", waitfor_pid_name.c_str()); - nub_process_t pid = DNBProcessAttachWait (waitfor_pid_name.c_str(), launch_flavor, ignore_existing, timeout_ptr, waitfor_interval, err_str, sizeof(err_str)); - g_pid = pid; - - if (pid == INVALID_NUB_PROCESS) - { - ctx.LaunchStatus().SetError(-1, DNBError::Generic); - if (err_str[0]) - ctx.LaunchStatus().SetErrorString(err_str); - RNBLogSTDERR ("error: failed to attach to process named: \"%s\" %s\n", waitfor_pid_name.c_str(), err_str); - mode = eRNBRunLoopModeExit; - } - else - { - ctx.SetProcessID(pid); - mode = eRNBRunLoopModeInferiorExecuting; - } - } - else if (attach_pid != INVALID_NUB_PROCESS) - { - - RNBLogSTDOUT ("Attaching to process %i...\n", attach_pid); - nub_process_t attached_pid; - mode = RNBRunLoopLaunchAttaching (remote, attach_pid, attached_pid); - if (mode != eRNBRunLoopModeInferiorExecuting) - { - const char *error_str = remote->Context().LaunchStatus().AsString(); - RNBLogSTDERR ("error: failed to attach process %i: %s\n", attach_pid, error_str ? error_str : "unknown error."); - mode = eRNBRunLoopModeExit; - } - } - else if (!attach_pid_name.empty ()) - { - struct timespec attach_timeout_abstime, *timeout_ptr = NULL; - if (waitfor_duration != 0) - { - DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0); - timeout_ptr = &attach_timeout_abstime; - } - - RNBLogSTDOUT ("Attaching to process %s...\n", attach_pid_name.c_str()); - nub_process_t pid = DNBProcessAttachByName (attach_pid_name.c_str(), timeout_ptr, err_str, sizeof(err_str)); - g_pid = pid; - if (pid == INVALID_NUB_PROCESS) - { - ctx.LaunchStatus().SetError(-1, DNBError::Generic); - if (err_str[0]) - ctx.LaunchStatus().SetErrorString(err_str); - RNBLogSTDERR ("error: failed to attach to process named: \"%s\" %s\n", waitfor_pid_name.c_str(), err_str); - mode = eRNBRunLoopModeExit; - } - else - { - ctx.SetProcessID(pid); - mode = eRNBRunLoopModeInferiorExecuting; - } - - } - else - { - RNBLogSTDERR ("error: asked to attach with empty name and invalid PID.\n"); - mode = eRNBRunLoopModeExit; - } - - if (mode != eRNBRunLoopModeExit) - { - if (port != INT32_MAX) - { - if (!ConnectRemote (remote, host.c_str(), port, reverse_connect, named_pipe_path.c_str(), unix_socket_name.c_str())) - mode = eRNBRunLoopModeExit; - } - else if (str[0] == '/') - { - if (remote->Comm().OpenFile (str)) - mode = eRNBRunLoopModeExit; - } - else if (communication_fd >= 0) - { - // We were passed a file descriptor to use during fork/exec that is already open - // in our process, so lets just use it! - if (remote->Comm().useFD(communication_fd)) - mode = eRNBRunLoopModeExit; - else - remote->StartReadRemoteDataThread(); - } - - if (mode != eRNBRunLoopModeExit) - RNBLogSTDOUT ("Waiting for debugger instructions for process %d.\n", attach_pid); - } - break; - - case eRNBRunLoopModeInferiorLaunching: - { - mode = RNBRunLoopLaunchInferior (remote, - ctx.GetSTDINPath(), - ctx.GetSTDOUTPath(), - ctx.GetSTDERRPath(), - no_stdio); - - if (mode == eRNBRunLoopModeInferiorExecuting) - { - if (port != INT32_MAX) - { - if (!ConnectRemote (remote, host.c_str(), port, reverse_connect, named_pipe_path.c_str(), unix_socket_name.c_str())) - mode = eRNBRunLoopModeExit; - } - else if (str[0] == '/') - { - if (remote->Comm().OpenFile (str)) - mode = eRNBRunLoopModeExit; - } - else if (communication_fd >= 0) - { - // We were passed a file descriptor to use during fork/exec that is already open - // in our process, so lets just use it! - if (remote->Comm().useFD(communication_fd)) - mode = eRNBRunLoopModeExit; - else - remote->StartReadRemoteDataThread(); - } - - if (mode != eRNBRunLoopModeExit) - { - const char *proc_name = "<unknown>"; - if (ctx.ArgumentCount() > 0) - proc_name = ctx.ArgumentAtIndex(0); - RNBLogSTDOUT ("Got a connection, launched process %s (pid = %d).\n", proc_name, ctx.ProcessID()); - } - } - else - { - const char *error_str = remote->Context().LaunchStatus().AsString(); - RNBLogSTDERR ("error: failed to launch process %s: %s\n", argv_sub_zero, error_str ? error_str : "unknown error."); - } - } - break; - - case eRNBRunLoopModeInferiorExecuting: - mode = RNBRunLoopInferiorExecuting(remote); - break; - - case eRNBRunLoopModePlatformMode: - if (port != INT32_MAX) - { - if (!ConnectRemote (remote, host.c_str(), port, reverse_connect, named_pipe_path.c_str(), unix_socket_name.c_str())) - mode = eRNBRunLoopModeExit; - } - else if (str[0] == '/') - { - if (remote->Comm().OpenFile (str)) - mode = eRNBRunLoopModeExit; - } - else if (communication_fd >= 0) - { - // We were passed a file descriptor to use during fork/exec that is already open - // in our process, so lets just use it! - if (remote->Comm().useFD(communication_fd)) - mode = eRNBRunLoopModeExit; - else - remote->StartReadRemoteDataThread(); - } - - if (mode != eRNBRunLoopModeExit) - mode = RNBRunLoopPlatform (remote); - break; - - default: - mode = eRNBRunLoopModeExit; - case eRNBRunLoopModeExit: - break; } + + ctx.SetLaunchFlavor(launch_flavor); + bool ignore_existing = false; + RNBLogSTDOUT("Waiting to attach to process %s...\n", + waitfor_pid_name.c_str()); + nub_process_t pid = DNBProcessAttachWait( + waitfor_pid_name.c_str(), launch_flavor, ignore_existing, + timeout_ptr, waitfor_interval, err_str, sizeof(err_str)); + g_pid = pid; + + if (pid == INVALID_NUB_PROCESS) { + ctx.LaunchStatus().SetError(-1, DNBError::Generic); + if (err_str[0]) + ctx.LaunchStatus().SetErrorString(err_str); + RNBLogSTDERR("error: failed to attach to process named: \"%s\" %s\n", + waitfor_pid_name.c_str(), err_str); + mode = eRNBRunLoopModeExit; + } else { + ctx.SetProcessID(pid); + mode = eRNBRunLoopModeInferiorExecuting; + } + } else if (attach_pid != INVALID_NUB_PROCESS) { + + RNBLogSTDOUT("Attaching to process %i...\n", attach_pid); + nub_process_t attached_pid; + mode = RNBRunLoopLaunchAttaching(remote, attach_pid, attached_pid); + if (mode != eRNBRunLoopModeInferiorExecuting) { + const char *error_str = remote->Context().LaunchStatus().AsString(); + RNBLogSTDERR("error: failed to attach process %i: %s\n", attach_pid, + error_str ? error_str : "unknown error."); + mode = eRNBRunLoopModeExit; + } + } else if (!attach_pid_name.empty()) { + struct timespec attach_timeout_abstime, *timeout_ptr = NULL; + if (waitfor_duration != 0) { + DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, + 0); + timeout_ptr = &attach_timeout_abstime; + } + + RNBLogSTDOUT("Attaching to process %s...\n", attach_pid_name.c_str()); + nub_process_t pid = DNBProcessAttachByName( + attach_pid_name.c_str(), timeout_ptr, err_str, sizeof(err_str)); + g_pid = pid; + if (pid == INVALID_NUB_PROCESS) { + ctx.LaunchStatus().SetError(-1, DNBError::Generic); + if (err_str[0]) + ctx.LaunchStatus().SetErrorString(err_str); + RNBLogSTDERR("error: failed to attach to process named: \"%s\" %s\n", + waitfor_pid_name.c_str(), err_str); + mode = eRNBRunLoopModeExit; + } else { + ctx.SetProcessID(pid); + mode = eRNBRunLoopModeInferiorExecuting; + } + + } else { + RNBLogSTDERR( + "error: asked to attach with empty name and invalid PID.\n"); + mode = eRNBRunLoopModeExit; + } + + if (mode != eRNBRunLoopModeExit) { + if (port != INT32_MAX) { + if (!ConnectRemote(remote, host.c_str(), port, reverse_connect, + named_pipe_path.c_str(), unix_socket_name.c_str())) + mode = eRNBRunLoopModeExit; + } else if (str[0] == '/') { + if (remote->Comm().OpenFile(str)) + mode = eRNBRunLoopModeExit; + } else if (communication_fd >= 0) { + // We were passed a file descriptor to use during fork/exec that is + // already open + // in our process, so lets just use it! + if (remote->Comm().useFD(communication_fd)) + mode = eRNBRunLoopModeExit; + else + remote->StartReadRemoteDataThread(); + } + + if (mode != eRNBRunLoopModeExit) + RNBLogSTDOUT("Waiting for debugger instructions for process %d.\n", + attach_pid); + } + break; + + case eRNBRunLoopModeInferiorLaunching: { + mode = RNBRunLoopLaunchInferior(remote, ctx.GetSTDINPath(), + ctx.GetSTDOUTPath(), ctx.GetSTDERRPath(), + no_stdio); + + if (mode == eRNBRunLoopModeInferiorExecuting) { + if (port != INT32_MAX) { + if (!ConnectRemote(remote, host.c_str(), port, reverse_connect, + named_pipe_path.c_str(), unix_socket_name.c_str())) + mode = eRNBRunLoopModeExit; + } else if (str[0] == '/') { + if (remote->Comm().OpenFile(str)) + mode = eRNBRunLoopModeExit; + } else if (communication_fd >= 0) { + // We were passed a file descriptor to use during fork/exec that is + // already open + // in our process, so lets just use it! + if (remote->Comm().useFD(communication_fd)) + mode = eRNBRunLoopModeExit; + else + remote->StartReadRemoteDataThread(); + } + + if (mode != eRNBRunLoopModeExit) { + const char *proc_name = "<unknown>"; + if (ctx.ArgumentCount() > 0) + proc_name = ctx.ArgumentAtIndex(0); + RNBLogSTDOUT("Got a connection, launched process %s (pid = %d).\n", + proc_name, ctx.ProcessID()); + } + } else { + const char *error_str = remote->Context().LaunchStatus().AsString(); + RNBLogSTDERR("error: failed to launch process %s: %s\n", argv_sub_zero, + error_str ? error_str : "unknown error."); + } + } break; + + case eRNBRunLoopModeInferiorExecuting: + mode = RNBRunLoopInferiorExecuting(remote); + break; + + case eRNBRunLoopModePlatformMode: + if (port != INT32_MAX) { + if (!ConnectRemote(remote, host.c_str(), port, reverse_connect, + named_pipe_path.c_str(), unix_socket_name.c_str())) + mode = eRNBRunLoopModeExit; + } else if (str[0] == '/') { + if (remote->Comm().OpenFile(str)) + mode = eRNBRunLoopModeExit; + } else if (communication_fd >= 0) { + // We were passed a file descriptor to use during fork/exec that is + // already open + // in our process, so lets just use it! + if (remote->Comm().useFD(communication_fd)) + mode = eRNBRunLoopModeExit; + else + remote->StartReadRemoteDataThread(); + } + + if (mode != eRNBRunLoopModeExit) + mode = RNBRunLoopPlatform(remote); + break; + + default: + mode = eRNBRunLoopModeExit; + case eRNBRunLoopModeExit: + break; } + } - remote->StopReadRemoteDataThread (); - remote->Context().SetProcessID(INVALID_NUB_PROCESS); - RNBLogSTDOUT ("Exiting.\n"); + remote->StopReadRemoteDataThread(); + remote->Context().SetProcessID(INVALID_NUB_PROCESS); + RNBLogSTDOUT("Exiting.\n"); - return 0; + return 0; } |