diff options
author | Greg Clayton <gclayton@apple.com> | 2010-07-09 20:39:50 +0000 |
---|---|---|
committer | Greg Clayton <gclayton@apple.com> | 2010-07-09 20:39:50 +0000 |
commit | c982c768d248b21b82fbd70b61a4cc824cd82ddc (patch) | |
tree | 68c5d417ce51994a2d393e5a5a7f0025b6e4ed35 /lldb/source/Plugins/Process/gdb-remote/GDBServer.cpp | |
parent | 2a5725b1a324639d0e16e9c125f5713acfabca60 (diff) | |
download | bcm5719-llvm-c982c768d248b21b82fbd70b61a4cc824cd82ddc.tar.gz bcm5719-llvm-c982c768d248b21b82fbd70b61a4cc824cd82ddc.zip |
Merged Eli Friedman's linux build changes where he added Makefile files that
enabled LLVM make style building and made this compile LLDB on Mac OS X. We
can now iterate on this to make the build work on both linux and macosx.
llvm-svn: 108009
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote/GDBServer.cpp')
-rw-r--r-- | lldb/source/Plugins/Process/gdb-remote/GDBServer.cpp | 1148 |
1 files changed, 0 insertions, 1148 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBServer.cpp deleted file mode 100644 index a88ec7b09d4..00000000000 --- a/lldb/source/Plugins/Process/gdb-remote/GDBServer.cpp +++ /dev/null @@ -1,1148 +0,0 @@ -//===-- GDBServer.cpp -------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include <sys/socket.h> -#include <sys/types.h> -#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 "GDBServerLog.h" -#include "GDBRemoteSession.h" - -using namespace lldb; - -//---------------------------------------------------------------------- -// Run loop modes which determine which run loop function will be called -//---------------------------------------------------------------------- -typedef enum -{ - eDCGSRunLoopModeInvalid = 0, - eDCGSRunLoopModeGetStartModeFromRemoteProtocol, - eDCGSRunLoopModeInferiorAttaching, - eDCGSRunLoopModeInferiorLaunching, - eDCGSRunLoopModeInferiorExecuting, - eDCGSRunLoopModeInferiorKillOrDetach, - eDCGSRunLoopModeExit -} GSRunLoopMode; - -typedef enum -{ - eLaunchFlavorDefault = 0, - eLaunchFlavorPosixSpawn, -#if defined (__arm__) - eLaunchFlavorSpringBoard, -#endif - eLaunchFlavorForkExec, -} GSLaunchFlavor; - -typedef lldb::shared_ptr<GDBRemoteSession> GDBRemoteSP; - -typedef struct HandleBroadcastEventInfo -{ - TargetSP target_sp; - GDBRemoteSP remote_sp; - GSRunLoopMode mode; - - Target * - GetTarget () - { - return target_sp.get(); - } - - Process * - GetProcess() - { - if (target_sp.get()) - return target_sp->GetProcess().get(); - return NULL; - } - - GDBRemoteSession * - GetRemote () - { - return remote_sp.get(); - } - -}; - - -//---------------------------------------------------------------------- -// Global Variables -//---------------------------------------------------------------------- -static int g_lockdown_opt = 0; -static int g_applist_opt = 0; -static GSLaunchFlavor g_launch_flavor = eLaunchFlavorDefault; -int g_isatty = 0; - -//---------------------------------------------------------------------- -// Run Loop function prototypes -//---------------------------------------------------------------------- -void GSRunLoopGetStartModeFromRemote (HandleBroadcastEventInfo *info); -void GSRunLoopInferiorExecuting (HandleBroadcastEventInfo *info); - - -//---------------------------------------------------------------------- -// Get our program path and arguments from the remote connection. -// We will need to start up the remote connection without a PID, get the -// 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. -//---------------------------------------------------------------------- -void -GSRunLoopGetStartModeFromRemote (HandleBroadcastEventInfo *info) -{ - std::string packet; - - Target *target = info->GetTarget(); - GDBRemoteSession *remote = info->GetRemote(); - if (target != NULL && remote != NULL) - { - // Spin waiting to get the A packet. - while (1) - { - gdb_err_t err = gdb_err; - GDBRemoteSession::PacketEnum type; - - err = remote->HandleReceivedPacket (&type); - - // check if we tried to attach to a process - if (type == GDBRemoteSession::vattach || type == GDBRemoteSession::vattachwait) - { - if (err == gdb_success) - { - info->mode = eDCGSRunLoopModeInferiorExecuting; - return; - } - else - { - Log::STDERR ("error: attach failed."); - info->mode = eDCGSRunLoopModeExit; - return; - } - } - - if (err == gdb_success) - { - // If we got our arguments we are ready to launch using the arguments - // and any environment variables we received. - if (type == GDBRemoteSession::set_argv) - { - info->mode = eDCGSRunLoopModeInferiorLaunching; - return; - } - } - else if (err == gdb_not_connected) - { - Log::STDERR ("error: connection lost."); - info->mode = eDCGSRunLoopModeExit; - return; - } - else - { - // a catch all for any other gdb remote packets that failed - GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s Error getting packet.",__FUNCTION__); - continue; - } - - GDBServerLog::LogIf (GS_LOG_MINIMAL, "#### %s", __FUNCTION__); - } - } - info->mode = eDCGSRunLoopModeExit; -} - - -//---------------------------------------------------------------------- -// 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. -//---------------------------------------------------------------------- -GSRunLoopMode -GSRunLoopLaunchInferior (HandleBroadcastEventInfo *info) -{ - // The Process stuff takes a c array, the GSContext has a vector... - // So make up a c array. - Target *target = info->GetTarget(); - GDBRemoteSession *remote = info->GetRemote(); - Process* process = info->GetProcess(); - - if (process == NULL) - return eDCGSRunLoopModeExit; - - GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s Launching '%s'...", __FUNCTION__, target->GetExecutableModule()->GetFileSpec().GetFilename().AsCString()); - - // Our launch type hasn't been set to anything concrete, so we need to - // figure our how we are going to launch automatically. - - GSLaunchFlavor launch_flavor = g_launch_flavor; - if (launch_flavor == eLaunchFlavorDefault) - { - // Our default launch method is posix spawn - launch_flavor = eLaunchFlavorPosixSpawn; - -#if defined (__arm__) - // Check if we have an app bundle, if so launch using SpringBoard. - if (strstr(inferior_argv[0], ".app")) - { - launch_flavor = eLaunchFlavorSpringBoard; - } -#endif - } - - //ctx.SetLaunchFlavor(launch_flavor); - - const char *stdio_file = NULL; - lldb::pid_t pid = process->Launch (remote->GetARGV(), remote->GetENVP(), stdio_file, stdio_file, stdio_file); - - if (pid == LLDB_INVALID_PROCESS_ID) - { - Log::STDERR ("error: process launch failed: %s", process->GetError().AsCString()); - } - else - { - if (remote->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. - gdb_err_t err = gdb_err; - GDBRemoteSession::PacketEnum type; - - err = remote->HandleReceivedPacket (&type); - - if (err != gdb_success) - { - GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s Error getting packet.", __FUNCTION__); - return eDCGSRunLoopModeExit; - } - if (type != GDBRemoteSession::query_launch_success) - { - GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s Didn't get the expected qLaunchSuccess packet.", __FUNCTION__); - } - } - } - - Listener listener("GSRunLoopLaunchInferior"); - listener.StartListeningForEvents (process, Process::eBroadcastBitStateChanged); - while (process->GetID() != LLDB_INVALID_PROCESS_ID) - { - uint32_t event_mask = 0; - while (listener.WaitForEvent(NULL, &event_mask)) - { - if (event_mask & Process::eBroadcastBitStateChanged) - { - Event event; - StateType event_state; - while ((event_state = process->GetNextEvent (&event))) - if (StateIsStoppedState(event_state)) - { - GDBServerLog::LogIf (GS_LOG_EVENTS, "%s process %4.4x stopped with state %s", __FUNCTION__, pid, StateAsCString(event_state)); - - switch (event_state) - { - default: - 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: - return eDCGSRunLoopModeInferiorExecuting; - - case eStateDetached: - case eStateExited: - pid = LLDB_INVALID_PROCESS_ID; - return eDCGSRunLoopModeExit; - } - } - - if (event_state = eStateInvalid) - break; - } - } - } - - return eDCGSRunLoopModeExit; -} - - -//---------------------------------------------------------------------- -// 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. -//---------------------------------------------------------------------- -GSRunLoopMode -GSRunLoopLaunchAttaching (HandleBroadcastEventInfo *info, lldb::pid_t& pid) -{ - Process* process = info->GetProcess(); - - GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s Attaching to pid %i...", __FUNCTION__, pid); - pid = process->Attach(pid); - - if (pid == LLDB_INVALID_PROCESS_ID) - return eDCGSRunLoopModeExit; - return eDCGSRunLoopModeInferiorExecuting; -} - -//---------------------------------------------------------------------- -// Watch for signals: -// SIGINT: so we can halt our inferior. (disabled for now) -// SIGPIPE: in case our child process dies -//---------------------------------------------------------------------- -lldb::pid_t g_pid; -int g_sigpipe_received = 0; -void -signal_handler(int signo) -{ - GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s (%s)", __FUNCTION__, Host::GetSignalAsCString(signo)); - - switch (signo) - { -// case SIGINT: -// DNBProcessKill (g_pid, signo); -// break; - - case SIGPIPE: - g_sigpipe_received = 1; - break; - } -} - -// Return the new run loop mode based off of the current process state -void -HandleProcessStateChange (HandleBroadcastEventInfo *info, bool initialize) -{ - Process *process = info->GetProcess(); - if (process == NULL) - { - info->mode = eDCGSRunLoopModeExit; - return; - } - - if (process->GetID() == LLDB_INVALID_PROCESS_ID) - { - GDBServerLog::LogIf (GS_LOG_MINIMAL, "#### %s error: pid invalid, exiting...", __FUNCTION__); - info->mode = eDCGSRunLoopModeExit; - return; - } - StateType pid_state = process->GetState (); - - GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s (info, initialize=%i) pid_state = %s", __FUNCTION__, (int)initialize, StateAsCString(pid_state)); - - switch (pid_state) - { - case eStateInvalid: - case eStateUnloaded: - // Something bad happened - info->mode = eDCGSRunLoopModeExit; - return; - - case eStateAttaching: - case eStateLaunching: - info->mode = eDCGSRunLoopModeInferiorExecuting; - return; - - case eStateSuspended: - case eStateCrashed: - case eStateStopped: - 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. - static uint32_t g_prev_stop_id = 0; - uint32_t stop_id = process->GetStopID(); - bool pid_stop_count_changed = g_prev_stop_id != stop_id; - if (pid_stop_count_changed) - { - info->GetRemote()->FlushSTDIO(); - - if (stop_id == 1) - { - GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %u (old %u)) Notify??? no, first stop...", __FUNCTION__, (int)initialize, StateAsCString (pid_state), stop_id, g_prev_stop_id); - } - else - { - - GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %u (old %u)) Notify??? YES!!!", __FUNCTION__, (int)initialize, StateAsCString (pid_state), stop_id, g_prev_stop_id); - info->GetRemote()->NotifyThatProcessStopped (); - } - } - else - { - GDBServerLog::LogIf (GS_LOG_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %u (old %u)) Notify??? skipping...", __FUNCTION__, (int)initialize, StateAsCString (pid_state), stop_id, g_prev_stop_id); - } - } - info->mode = eDCGSRunLoopModeInferiorExecuting; - return; - - case eStateStepping: - case eStateRunning: - info->mode = eDCGSRunLoopModeInferiorExecuting; - return; - - case eStateExited: - info->GetRemote()->HandlePacket_last_signal (NULL); - info->mode = eDCGSRunLoopModeExit; - return; - - } - - // Catch all... - info->mode = eDCGSRunLoopModeExit; -} - -bool -CommunicationHandleBroadcastEvent (Broadcaster *broadcaster, uint32_t event_mask, void *baton) -{ - HandleBroadcastEventInfo *info = (HandleBroadcastEventInfo *)baton; - Process *process = info->GetProcess(); - - if (process == NULL) - { - info->mode = eDCGSRunLoopModeExit; - return true; - } - - if (event_mask & Communication::eBroadcastBitPacketAvailable) - { - if (process->IsRunning()) - { - if (info->GetRemote()->HandleAsyncPacket() == gdb_not_connected) - info->mode = eDCGSRunLoopModeExit; - } - else - { - if (info->GetRemote()->HandleReceivedPacket() == gdb_not_connected) - info->mode = eDCGSRunLoopModeExit; - } - } - if (event_mask & Communication::eBroadcastBitReadThreadDidExit) - { - info->mode = eDCGSRunLoopModeExit; - } - if (event_mask & Communication::eBroadcastBitDisconnected) - { - info->mode = eDCGSRunLoopModeExit; - } - - return true; - -} - -bool -ProcessHandleBroadcastEvent (Broadcaster *broadcaster, uint32_t event_mask, void *baton) -{ - HandleBroadcastEventInfo *info = (HandleBroadcastEventInfo *)baton; - Process *process = info->GetProcess(); - if (process == NULL) - { - info->mode = eDCGSRunLoopModeExit; - return true; - } - - if (event_mask & Process::eBroadcastBitStateChanged) - { - // Consume all available process events with no timeout - Event event; - StateType process_state; - while ((process_state = process->GetNextEvent (&event)) != eStateInvalid) - { - if (StateIsStoppedState(process_state)) - info->GetRemote()->FlushSTDIO(); - HandleProcessStateChange (info, false); - - if (info->mode != eDCGSRunLoopModeInferiorExecuting) - break; - } - } - else - if (event_mask & (Process::eBroadcastBitSTDOUT | Process::eBroadcastBitSTDERR)) - { - info->GetRemote()->FlushSTDIO(); - } - return true; -} - -// 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. -void -GSRunLoopInferiorExecuting (HandleBroadcastEventInfo *info) -{ - GDBServerLog::LogIf (GS_LOG_MINIMAL, "#### %s", __FUNCTION__); - - // Init our mode and set 'is_running' based on the current process state - HandleProcessStateChange (info, true); - - uint32_t desired_mask, acquired_mask; - Listener listener("GSRunLoopInferiorExecuting"); - - desired_mask = Communication::eBroadcastBitPacketAvailable | - Communication::eBroadcastBitReadThreadDidExit | - Communication::eBroadcastBitDisconnected; - - acquired_mask = listener.StartListeningForEvents (&(info->GetRemote()->GetPacketComm()), - desired_mask, - CommunicationHandleBroadcastEvent, - info); - - assert (acquired_mask == desired_mask); - desired_mask = GDBRemotePacket::eBroadcastBitPacketAvailable; - - acquired_mask = listener.StartListeningForEvents (&(info->GetRemote()->GetPacketComm()), - desired_mask, - CommunicationHandleBroadcastEvent, - info); - - assert (acquired_mask == desired_mask); - - desired_mask = Process::eBroadcastBitStateChanged | - Process::eBroadcastBitSTDOUT | - Process::eBroadcastBitSTDERR ; - acquired_mask = listener.StartListeningForEvents (info->GetProcess (), - desired_mask, - ProcessHandleBroadcastEvent, - info); - - assert (acquired_mask == desired_mask); - - Process *process = info->GetProcess(); - - while (process->IsAlive()) - { - if (!info->GetRemote()->IsConnected()) - { - info->mode = eDCGSRunLoopModeInferiorKillOrDetach; - break; - } - - // 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 (GSContext::event_proc_state_changed); - uint32_t event_mask = 0; - Broadcaster *broadcaster = listener.WaitForEvent(NULL, &event_mask); - if (broadcaster) - { - listener.HandleBroadcastEvent(broadcaster, event_mask); - } - } -} - - -//---------------------------------------------------------------------- -// Convenience function to set up the remote listening port -// Returns 1 for success 0 for failure. -//---------------------------------------------------------------------- - -static bool -StartListening (HandleBroadcastEventInfo *info, int listen_port) -{ - if (!info->GetRemote()->IsConnected()) - { - Log::STDOUT ("Listening to port %i...\n", listen_port); - char connect_url[256]; - snprintf(connect_url, sizeof(connect_url), "listen://%i", listen_port); - - Communication &comm = info->remote_sp->GetPacketComm(); - comm.SetConnection (new ConnectionFileDescriptor); - - if (comm.Connect (connect_url)) - { - if (comm.StartReadThread()) - return true; - - Log::STDERR ("Failed to start the communication read thread.\n", connect_url); - comm.Disconnect(); - } - else - { - Log::STDERR ("Failed to connection to %s.\n", connect_url); - } - return false; - } - return true; -} - -//---------------------------------------------------------------------- -// ASL Logging callback that can be registered with DNBLogSetLogDCScriptInterpreter::Type -//---------------------------------------------------------------------- -//void -//ASLLogDCScriptInterpreter::Type(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.dc-gdbserver-%g", dc_gdbserverVersionNumber); -// ::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 -// DNBLogSetLogDCScriptInterpreter::Type -//---------------------------------------------------------------------- -void -FileLogDCScriptInterpreter::Type(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"); -} - -//---------------------------------------------------------------------- -// option descriptors for getopt_long() -//---------------------------------------------------------------------- -static struct option g_long_options[] = -{ - { "arch", required_argument, NULL, 'c' }, - { "attach", required_argument, NULL, 'a' }, - { "debug", no_argument, NULL, 'g' }, - { "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 namet 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 - { NULL, 0, NULL, 0 } -}; - -extern const double dc_gdbserverVersionNumber; -int -main (int argc, char *argv[]) -{ - Initialize(); - Host::ThreadCreated ("[main]"); - - g_isatty = ::isatty (STDIN_FILENO); - -// signal (SIGINT, signal_handler); - signal (SIGPIPE, signal_handler); - - Log *log = GDBServerLog::GetLogIfAllCategoriesSet(GS_LOG_ALL); - const char *this_exe_name = argv[0]; - int i; - int attach_pid = LLDB_INVALID_PROCESS_ID; - for (i=0; i<argc; i++) - GDBServerLog::LogIf(GS_LOG_DEBUG, "argv[%i] = %s", i, argv[i]); - - FILE* log_file = NULL; - uint32_t log_flags = 0; - // Parse our options - int ch; - int long_option_index = 0; - int debug = 0; - std::string waitfor_pid_name; // Wait for a process that starts with this name - std::string attach_pid_name; - 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. - ArchSpec arch; - GSRunLoopMode start_mode = eDCGSRunLoopModeExit; - - while ((ch = getopt_long(argc, argv, "a:c:d:gi:vktl:f:w:x:", 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 'c': - arch.SetArch(optarg); - if (!arch.IsValid()) - { - Log::STDERR ("error: invalid arch string '%s'\n", optarg); - exit (8); - } - break; - - case 'a': - if (optarg && optarg[0]) - { - if (isdigit(optarg[0])) - { - char *end = NULL; - attach_pid = strtoul(optarg, &end, 0); - if (end == NULL || *end != '\0') - { - Log::STDERR ("error: invalid pid option '%s'\n", optarg); - exit (4); - } - } - else - { - attach_pid_name = optarg; - } - start_mode = eDCGSRunLoopModeInferiorAttaching; - } - break; - - // --waitfor=NAME - case 'w': - if (optarg && optarg[0]) - { - waitfor_pid_name = optarg; - start_mode = eDCGSRunLoopModeInferiorAttaching; - } - break; - - // --waitfor-interval=USEC - case 'i': - if (optarg && optarg[0]) - { - char *end = NULL; - waitfor_interval = strtoul(optarg, &end, 0); - if (end == NULL || *end != '\0') - { - Log::STDERR ("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 = strtoul(optarg, &end, 0); - if (end == NULL || *end != '\0') - { - Log::STDERR ("error: invalid waitfor-duration option value '%s'.\n", optarg); - exit (7); - } - } - 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; -#if defined (__arm__) - else if (strcasestr(optarg, "spring") == optarg) - g_launch_flavor = eLaunchFlavorSpringBoard; -#endif - else - { - Log::STDERR ("error: invalid TYPE for the --launch=TYPE (-x TYPE) option: '%s'\n", optarg); - Log::STDERR ("Valid values TYPE are:\n"); - Log::STDERR (" auto Auto-detect the best launch method to use.\n"); - Log::STDERR (" posix Launch the executable using posix_spawn.\n"); - Log::STDERR (" fork Launch the executable using fork and exec.\n"); -#if defined (__arm__) - Log::STDERR (" spring Launch the executable through Springboard.\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) - { - const char *errno_str = strerror(errno); - Log::STDERR ("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 = strtoul(optarg, NULL, 0); - break; - - case 'g': - debug = 1; - //DNBLogSetDebug(1); - break; - - case 't': - g_applist_opt = 1; - break; - - case 'k': - g_lockdown_opt = 1; - break; - - case 'v': - //DNBLogSetVerbose(1); - break; - } - } - - // Skip any options we consumed with getopt_long - argc -= optind; - argv += optind; - - // It is ok for us to set NULL as the logfile (this will disable any logging) - -// if (log_file != NULL) -// { -// DNBLogSetLogDCScriptInterpreter::Type(FileLogDCScriptInterpreter::Type, 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_DCGS_ALL; -// -// DNBLogSetLogMask (log_flags); -// } -// else -// { -// // Enable DNB logging -// DNBLogSetLogDCScriptInterpreter::Type(ASLLogDCScriptInterpreter::Type, NULL); -// DNBLogSetLogMask (log_flags); -// -// } - - // as long as we're dropping remotenub in as a replacement for gdbserver, - // explicitly note that this is not gdbserver. - - Log::STDOUT ("debugserver-%g \n", dc_gdbserverVersionNumber); - int listen_port = -1; - if (g_lockdown_opt == 0 && g_applist_opt == 0) - { - // Make sure we at least have port - if (argc < 1) - { - Log::STDERR ("Usage: %s host:port [program-name program-arg1 program-arg2 ...]\n", this_exe_name); - exit (1); - } - // accept 'localhost:' prefix on port number - - std::string host_str; - std::string port_str(argv[0]); - - // We just used the host:port arg... - argc--; - argv++; - - size_t port_idx = port_str.find(':'); - if (port_idx != std::string::npos) - { - host_str.assign(port_str, 0, port_idx); - port_str.erase(0, port_idx + 1); - } - - if (port_str.empty()) - { - Log::STDERR ("error: no port specified\nUsage: %s host:port [program-name program-arg1 program-arg2 ...]\n", this_exe_name); - exit (2); - } - else if (port_str.find_first_not_of("0123456789") != std::string::npos) - { - Log::STDERR ("error: port must be an integer: %s\nUsage: %s host:port [program-name program-arg1 program-arg2 ...]\n", port_str.c_str(), this_exe_name); - exit (3); - } - //DNBLogDebug("host_str = '%s' port_str = '%s'", host_str.c_str(), port_str.c_str()); - listen_port = atoi (port_str.c_str()); - } - - - // We must set up some communications now. - - FileSpec exe_spec; - if (argv[0]) - exe_spec.SetFile (argv[0]); - - HandleBroadcastEventInfo info; - info.target_sp = TargetList::SharedList().CreateTarget(&exe_spec, &arch); - ProcessSP process_sp (info.target_sp->CreateProcess ()); - info.remote_sp.reset (new GDBRemoteSession (process_sp)); - - info.remote_sp->SetLog (log); - StreamString sstr; - sstr.Printf("ConnectionFileDescriptor(%s)", argv[0]); - - if (info.remote_sp.get() == NULL) - { - Log::STDERR ("error: failed to create a GDBRemoteSession class\n"); - return -1; - } - - - - // If we know we're waiting to attach, we don't need any of this other info. - if (start_mode != eDCGSRunLoopModeInferiorAttaching) - { - 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 -// { -// Log::STDERR ("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; - return 0; - } - - //DNBLogDebug("Get args from remote protocol..."); - start_mode = eDCGSRunLoopModeGetStartModeFromRemoteProtocol; - } - else - { - start_mode = eDCGSRunLoopModeInferiorLaunching; - // Fill in the argv array in the context from the rest of our args. - // Skip the name of this executable and the port number - info.remote_sp->SetArguments (argc, argv); - } - } - - if (start_mode == eDCGSRunLoopModeExit) - return -1; - - info.mode = start_mode; - - while (info.mode != eDCGSRunLoopModeExit) - { - switch (info.mode) - { - case eDCGSRunLoopModeGetStartModeFromRemoteProtocol: - #if defined (__arm__) - if (g_lockdown_opt) - { - if (!info.remote_sp->GetCommunication()->IsConnected()) - { - if (info.remote_sp->GetCommunication()->ConnectToService () != gdb_success) - { - Log::STDERR ("Failed to get connection from a remote gdb process.\n"); - info.mode = eDCGSRunLoopModeExit; - } - 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()); - - info.remote_sp->GetCommunication()->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; - info.remote_sp->GetCommunication()->Read(buf); - } - info.remote_sp->GetCommunication()->Disconnect(false); - info.mode = eDCGSRunLoopModeExit; - break; - } - else - { - // Start watching for remote packets - info.remote_sp->StartReadRemoteDataThread(); - } - } - } - else -#endif - { - if (StartListening (&info, listen_port)) - Log::STDOUT ("Got a connection, waiting for process information for launching or attaching.\n"); - else - info.mode = eDCGSRunLoopModeExit; - } - - if (info.mode != eDCGSRunLoopModeExit) - GSRunLoopGetStartModeFromRemote (&info); - break; - - case eDCGSRunLoopModeInferiorAttaching: - if (!waitfor_pid_name.empty()) - { - // Set our end wait time if we are using a waitfor-duration - // option that may have been specified - - TimeValue attach_timeout_abstime; - if (waitfor_duration != 0) - { - attach_timeout_abstime = TimeValue::Now(); - attach_timeout_abstime.OffsetWithSeconds (waitfor_duration); - } - GSLaunchFlavor launch_flavor = g_launch_flavor; - if (launch_flavor == eLaunchFlavorDefault) - { - // Our default launch method is posix spawn - launch_flavor = eLaunchFlavorPosixSpawn; - -#if defined (__arm__) - // 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); - - - lldb::pid_t pid = info.GetProcess()->Attach (waitfor_pid_name.c_str()); - if (pid == LLDB_INVALID_PROCESS_ID) - { - info.GetRemote()->GetLaunchError() = info.GetProcess()->GetError(); - Log::STDERR ("error: failed to attach to process named: \"%s\" %s", waitfor_pid_name.c_str(), info.GetRemote()->GetLaunchError().AsCString()); - info.mode = eDCGSRunLoopModeExit; - } - else - { - info.mode = eDCGSRunLoopModeInferiorExecuting; - } - } - else if (attach_pid != LLDB_INVALID_PROCESS_ID) - { - Log::STDOUT ("Attaching to process %i...\n", attach_pid); - info.mode = GSRunLoopLaunchAttaching (&info, attach_pid); - if (info.mode != eDCGSRunLoopModeInferiorExecuting) - { - const char *error_str = info.GetRemote()->GetLaunchError().AsCString(); - Log::STDERR ("error: failed to attach process %i: %s\n", attach_pid, error_str ? error_str : "unknown error."); - info.mode = eDCGSRunLoopModeExit; - } - } - else if (!attach_pid_name.empty ()) - { - lldb::pid_t pid = info.GetProcess()->Attach (waitfor_pid_name.c_str()); - if (pid == LLDB_INVALID_PROCESS_ID) - { - info.GetRemote()->GetLaunchError() = info.GetProcess()->GetError(); - Log::STDERR ("error: failed to attach to process named: \"%s\" %s", waitfor_pid_name.c_str(), info.GetRemote()->GetLaunchError().AsCString()); - info.mode = eDCGSRunLoopModeExit; - } - else - { - info.mode = eDCGSRunLoopModeInferiorExecuting; - } - } - else - { - Log::STDERR ("error: asked to attach with empty name and invalid PID."); - info.mode = eDCGSRunLoopModeExit; - } - - if (info.mode != eDCGSRunLoopModeExit) - { - if (StartListening (&info, listen_port)) - Log::STDOUT ("Got a connection, waiting for debugger instructions for process %d.\n", attach_pid); - else - info.mode = eDCGSRunLoopModeExit; - } - break; - - case eDCGSRunLoopModeInferiorLaunching: - info.mode = GSRunLoopLaunchInferior (&info); - - if (info.mode == eDCGSRunLoopModeInferiorExecuting) - { - if (StartListening (&info, listen_port)) - Log::STDOUT ("Got a connection, waiting for debugger instructions for task \"%s\".\n", argv[0]); - else - info.mode = eDCGSRunLoopModeExit; - } - else - { - Log::STDERR ("error: failed to launch process %s: %s\n", argv[0], info.GetRemote()->GetLaunchError().AsCString()); - } - break; - - case eDCGSRunLoopModeInferiorExecuting: - GSRunLoopInferiorExecuting (&info); - break; - - case eDCGSRunLoopModeInferiorKillOrDetach: - { - Process *process = info.GetProcess(); - if (process && process->IsAlive()) - { - process->Kill(SIGCONT); - process->Kill(SIGKILL); - } - } - info.mode = eDCGSRunLoopModeExit; - break; - - default: - info.mode = eDCGSRunLoopModeExit; - case eDCGSRunLoopModeExit: - break; - } - } - - return 0; -} |