diff options
-rw-r--r-- | lldb/include/lldb/Target/Process.h | 2 | ||||
-rw-r--r-- | lldb/source/API/SBProcess.cpp | 10 | ||||
-rw-r--r-- | lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp | 16 | ||||
-rw-r--r-- | lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h | 12 | ||||
-rw-r--r-- | lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp | 124 | ||||
-rw-r--r-- | lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h | 9 | ||||
-rw-r--r-- | lldb/source/Target/Process.cpp | 55 | ||||
-rw-r--r-- | lldb/tools/debugserver/source/DNB.cpp | 17 | ||||
-rw-r--r-- | lldb/tools/debugserver/source/DNB.h | 14 | ||||
-rw-r--r-- | lldb/tools/debugserver/source/MacOSX/MachProcess.cpp | 32 | ||||
-rw-r--r-- | lldb/tools/debugserver/source/MacOSX/MachProcess.h | 25 | ||||
-rw-r--r-- | lldb/tools/debugserver/source/RNBContext.cpp | 20 | ||||
-rw-r--r-- | lldb/tools/debugserver/source/RNBContext.h | 11 | ||||
-rw-r--r-- | lldb/tools/debugserver/source/RNBRemote.cpp | 1 | ||||
-rw-r--r-- | lldb/tools/debugserver/source/debugserver.cpp | 147 |
15 files changed, 366 insertions, 129 deletions
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index 772eefb0ac1..0076da13076 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -1260,7 +1260,7 @@ public: /// /// @see lldb::StateType //------------------------------------------------------------------ - virtual void + virtual bool SetExitStatus (int exit_status, const char *cstr); //------------------------------------------------------------------ diff --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp index bfdf8578b1c..2a3d415a7b9 100644 --- a/lldb/source/API/SBProcess.cpp +++ b/lldb/source/API/SBProcess.cpp @@ -421,11 +421,12 @@ SBProcess::Continue () SBError SBProcess::Destroy () { - Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex()); - SBError sb_error; if (m_opaque_sp) + { + Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex()); sb_error.SetError(m_opaque_sp->Destroy()); + } else sb_error.SetErrorString ("SBProcess is invalid"); @@ -434,7 +435,10 @@ SBProcess::Destroy () { SBStream sstr; sb_error.GetDescription (sstr); - log->Printf ("SBProcess(%p)::Destroy () => SBError (%p): %s", m_opaque_sp.get(), sb_error.get(), sstr.GetData()); + log->Printf ("SBProcess(%p)::Destroy () => SBError (%p): %s", + m_opaque_sp.get(), + sb_error.get(), + sstr.GetData()); } return sb_error; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 38b823f77aa..a779db25756 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -511,6 +511,18 @@ GDBRemoteCommunication::SendInterrupt return false; } +bool +GDBRemoteCommunication::WaitForNotRunning (const TimeValue *timeout_ptr) +{ + return m_public_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL); +} + +bool +GDBRemoteCommunication::WaitForNotRunningPrivate (const TimeValue *timeout_ptr) +{ + return m_private_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL); +} + size_t GDBRemoteCommunication::WaitForPacket (StringExtractorGDBRemote &response, uint32_t timeout_seconds) { @@ -522,14 +534,14 @@ GDBRemoteCommunication::WaitForPacket (StringExtractorGDBRemote &response, uint3 } size_t -GDBRemoteCommunication::WaitForPacket (StringExtractorGDBRemote &response, TimeValue* timeout_time_ptr) +GDBRemoteCommunication::WaitForPacket (StringExtractorGDBRemote &response, const TimeValue* timeout_time_ptr) { Mutex::Locker locker(m_sequence_mutex); return WaitForPacketNoLock (response, timeout_time_ptr); } size_t -GDBRemoteCommunication::WaitForPacketNoLock (StringExtractorGDBRemote &response, TimeValue* timeout_time_ptr) +GDBRemoteCommunication::WaitForPacketNoLock (StringExtractorGDBRemote &response, const TimeValue* timeout_time_ptr) { bool checksum_error = false; response.Clear (); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index bcbaeb5ebd9..3ebabeb7085 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -81,7 +81,7 @@ public: // wait indefinitely. size_t WaitForPacket (StringExtractorGDBRemote &response, - lldb_private::TimeValue* timeout); + const lldb_private::TimeValue* timeout); char GetAck (uint32_t timeout_seconds); @@ -222,7 +222,10 @@ public: { return m_public_is_running.GetValue(); } - + + bool + WaitForNotRunning (const lldb_private::TimeValue *timeout_ptr); + bool GetHostInfo (uint32_t timeout_seconds); @@ -256,7 +259,10 @@ protected: size_t WaitForPacketNoLock (StringExtractorGDBRemote &response, - lldb_private::TimeValue* timeout_time_ptr); + const lldb_private::TimeValue* timeout_ptr); + + bool + WaitForNotRunningPrivate (const lldb_private::TimeValue *timeout_ptr); //------------------------------------------------------------------ // Classes that inherit from GDBRemoteCommunication can see and modify these diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 5abe070f962..fe4e06820fc 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -1157,7 +1157,13 @@ ProcessGDBRemote::DoHalt (bool &caused_stop) } Error -ProcessGDBRemote::WillDetach () +ProcessGDBRemote::InterruptIfRunning +( + bool discard_thread_plans, + bool catch_stop_event, + bool resume_private_state_thread, + EventSP &stop_event_sp +) { Error error; @@ -1166,30 +1172,54 @@ ProcessGDBRemote::WillDetach () bool timed_out = false; bool sent_interrupt = false; Mutex::Locker locker; - PausePrivateStateThread(); - m_thread_list.DiscardThreadPlans(); - m_debugserver_pid = LLDB_INVALID_PROCESS_ID; - if (!m_gdb_comm.SendInterrupt (locker, 2, sent_interrupt, timed_out)) + + if (catch_stop_event) + PausePrivateStateThread(); + + if (discard_thread_plans) + m_thread_list.DiscardThreadPlans(); + + //m_debugserver_pid = LLDB_INVALID_PROCESS_ID; + if (!m_gdb_comm.SendInterrupt (locker, 1, sent_interrupt, timed_out)) { if (timed_out) error.SetErrorString("timed out sending interrupt packet"); else error.SetErrorString("unknown error sending interrupt packet"); - ResumePrivateStateThread(); + if (catch_stop_event) + ResumePrivateStateThread(); + return error; } - TimeValue timeout_time; - timeout_time = TimeValue::Now(); - timeout_time.OffsetWithSeconds(2); + + + if (catch_stop_event) + { + TimeValue timeout_time; + timeout_time = TimeValue::Now(); + timeout_time.OffsetWithSeconds(1); + StateType state = WaitForProcessStopPrivate (&timeout_time, stop_event_sp); - EventSP event_sp; - StateType state = WaitForStateChangedEventsPrivate (&timeout_time, event_sp); - if (state != eStateStopped) - error.SetErrorString("unable to stop target"); + if (state == eStateInvalid) + error.SetErrorString("unable to verify target stopped"); + } + + if (catch_stop_event && resume_private_state_thread) + ResumePrivateStateThread(); } return error; } Error +ProcessGDBRemote::WillDetach () +{ + bool discard_thread_plans = true; + bool catch_stop_event = true; + bool resume_private_state_thread = false; // DoDetach will resume the thread + EventSP event_sp; + return InterruptIfRunning (discard_thread_plans, catch_stop_event, resume_private_state_thread, event_sp); +} + +Error ProcessGDBRemote::DoDetach() { Error error; @@ -1223,6 +1253,16 @@ ProcessGDBRemote::DoDetach() } Error +ProcessGDBRemote::WillDestroy () +{ + bool discard_thread_plans = true; + bool catch_stop_event = true; + bool resume_private_state_thread = true; + EventSP event_sp; + return InterruptIfRunning (discard_thread_plans, catch_stop_event, resume_private_state_thread, event_sp); +} + +Error ProcessGDBRemote::DoDestroy () { Error error; @@ -1233,10 +1273,40 @@ ProcessGDBRemote::DoDestroy () // Interrupt if our inferior is running... if (m_gdb_comm.IsConnected()) { - // Don't get a response when killing our - m_gdb_comm.SendPacket ("k", 1); + m_continue_packet.Clear(); + m_continue_packet.Printf("k"); + Listener listener ("gdb-remote.kill-packet-sent"); + if (listener.StartListeningForEvents (&m_gdb_comm, GDBRemoteCommunication::eBroadcastBitRunPacketSent)) + { + EventSP event_sp; + TimeValue timeout; + timeout = TimeValue::Now(); + timeout.OffsetWithSeconds (1); + m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (m_continue_packet.GetData(), m_continue_packet.GetSize())); + + // Wait for the async thread to send the "k" packet + if (listener.WaitForEvent (&timeout, event_sp)) + { + if (log) + log->Printf ("ProcessGDBRemote::DoDestroy() got confirmation the \"k\" packet was sent"); + } + else + { + if (log) + log->Printf ("ProcessGDBRemote::DoDestroy() timed out waiting for \"k\" packet to be sent"); + error.SetErrorString("Resume timed out."); + } + + // Wait for the async thread to exit which will indicate we stopped. + // Hopefully the stop will be a process exited state since we are + // asking the process to go away. + if (!m_gdb_comm.WaitForNotRunning (&timeout)) + { + if (log) + log->Printf ("ProcessGDBRemote::DoDestroy() timed out waiting for \"k\" stop reply packet"); + } + } } - StopAsyncThread (); m_gdb_comm.StopReadThread(); KillDebugserverProcess (); @@ -1851,14 +1921,14 @@ ProcessGDBRemote::StartDebugserverProcess log->Printf("%s arguments:\n%s", debugserver_args.GetArgumentAtIndex(0), strm.GetData()); } - error.SetError(::posix_spawnp (&m_debugserver_pid, - debugserver_path, - file_actions_err.Success() ? &file_actions : NULL, - &attr, - debugserver_args.GetArgumentVector(), - (char * const*)inferior_envp), - eErrorTypePOSIX); - + error.SetError (::posix_spawnp (&m_debugserver_pid, + debugserver_path, + file_actions_err.Success() ? &file_actions : NULL, + &attr, + debugserver_args.GetArgumentVector(), + (char * const*)inferior_envp), + eErrorTypePOSIX); + ::posix_spawnattr_destroy (&attr); @@ -1907,7 +1977,11 @@ ProcessGDBRemote::MonitorDebugserverProcess // debugserver that we are tracking... ProcessGDBRemote *process = (ProcessGDBRemote *)callback_baton; - + + LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf ("ProcessGDBRemote::MonitorDebugserverProcess (baton=%p, pid=%i, signo=%i (0x%x), exit_status=%i)", callback_baton, debugserver_pid, signo, signo, exit_status); + if (process) { // Sleep for a half a second to make sure our inferior process has diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index ebb4cca23d4..d8a2cebbd33 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -149,6 +149,9 @@ public: DoSignal (int signal); virtual lldb_private::Error + WillDestroy (); + + virtual lldb_private::Error DoDestroy (); virtual void @@ -382,6 +385,12 @@ protected: const char *bytes, size_t bytes_len); + lldb_private::Error + InterruptIfRunning (bool discard_thread_plans, + bool catch_stop_event, + bool resume_private_state_thread, + lldb::EventSP &stop_event_sp); + private: //------------------------------------------------------------------ // For ProcessGDBRemote only diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 90ea0b6cb18..c3b9dfbdd23 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -452,17 +452,22 @@ Process::WaitForStateChangedEventsPrivate (const TimeValue *timeout, EventSP &ev log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__, timeout); StateType state = eStateInvalid; - if (m_private_state_listener.WaitForEventForBroadcasterWithType(timeout, - &m_private_state_broadcaster, - eBroadcastBitStateChanged, - event_sp)) + if (m_private_state_listener.WaitForEventForBroadcasterWithType (timeout, + &m_private_state_broadcaster, + eBroadcastBitStateChanged, + event_sp)) state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); // This is a bit of a hack, but when we wait here we could very well return // to the command-line, and that could disable the log, which would render the // log we got above invalid. if (log) - log->Printf ("Process::%s (timeout = %p, event_sp) => %s", __FUNCTION__, timeout, StateAsCString(state)); + { + if (state == eStateInvalid) + log->Printf ("Process::%s (timeout = %p, event_sp) => TIMEOUT", __FUNCTION__, timeout); + else + log->Printf ("Process::%s (timeout = %p, event_sp) => %s", __FUNCTION__, timeout, StateAsCString(state)); + } return state; } @@ -547,21 +552,23 @@ Process::GetExitDescription () return NULL; } -void +bool Process::SetExitStatus (int status, const char *cstr) { - if (m_private_state.GetValue() != eStateExited) - { - m_exit_status = status; - if (cstr) - m_exit_string = cstr; - else - m_exit_string.clear(); + // We were already in the exited state + if (m_private_state.GetValue() == eStateExited) + return false; + + m_exit_status = status; + if (cstr) + m_exit_string = cstr; + else + m_exit_string.clear(); - DidExit (); + DidExit (); - SetPrivateState (eStateExited); - } + SetPrivateState (eStateExited); + return true; } // This static callback can be used to watch for local child processes on @@ -1425,11 +1432,17 @@ Process::WaitForProcessStopPrivate (const TimeValue *timeout, EventSP &event_sp) // call DidLaunch: while (1) { - // FIXME: Might want to put a timeout in here: - state = WaitForStateChangedEventsPrivate (NULL, event_sp); - if (state == eStateStopped || state == eStateCrashed || state == eStateExited) + event_sp.reset(); + state = WaitForStateChangedEventsPrivate (timeout, event_sp); + + if (StateIsStoppedState(state)) break; - else + + // If state is invalid, then we timed out + if (state == eStateInvalid) + break; + + if (event_sp) HandlePrivateEvent (event_sp); } return state; @@ -1744,7 +1757,7 @@ Process::Halt () // Wait for 2 seconds for the process to stop. TimeValue timeout_time; timeout_time = TimeValue::Now(); - timeout_time.OffsetWithSeconds(2); + timeout_time.OffsetWithSeconds(1); StateType state = WaitForStateChangedEventsPrivate (&timeout_time, event_sp); if (state == eStateInvalid) diff --git a/lldb/tools/debugserver/source/DNB.cpp b/lldb/tools/debugserver/source/DNB.cpp index 0a8eb59b114..92cdf582039 100644 --- a/lldb/tools/debugserver/source/DNB.cpp +++ b/lldb/tools/debugserver/source/DNB.cpp @@ -175,7 +175,10 @@ nub_process_t DNBProcessLaunch (const char *path, char const *argv[], const char *envp[], - const char *stdio_path, + const char *working_directory, // NULL => dont' change, non-NULL => set working directory for inferior to this + const char *stdin_path, + const char *stdout_path, + const char *stderr_path, bool no_stdio, nub_launch_flavor_t launch_flavor, int disable_aslr, @@ -199,7 +202,17 @@ DNBProcessLaunch (const char *path, if (processSP.get()) { DNBError launch_err; - pid_t pid = processSP->LaunchForDebug(path, argv, envp, stdio_path, no_stdio, launch_flavor, disable_aslr, launch_err); + pid_t pid = processSP->LaunchForDebug (path, + argv, + envp, + working_directory, + stdin_path, + stdout_path, + stderr_path, + no_stdio, + launch_flavor, + disable_aslr, + launch_err); if (err_str) { *err_str = '\0'; diff --git a/lldb/tools/debugserver/source/DNB.h b/lldb/tools/debugserver/source/DNB.h index f5eb17b3afd..2b2389d9cdc 100644 --- a/lldb/tools/debugserver/source/DNB.h +++ b/lldb/tools/debugserver/source/DNB.h @@ -33,7 +33,19 @@ nub_bool_t DNBSetArchitecture (const char *arch); //---------------------------------------------------------------------- // Process control //---------------------------------------------------------------------- -nub_process_t DNBProcessLaunch (const char *path, char const *argv[], const char *envp[], const char *stdio_path, bool no_stdio, nub_launch_flavor_t launch_flavor, int disable_aslr, char *err_str, size_t err_len) DNB_EXPORT; +nub_process_t DNBProcessLaunch (const char *path, + char const *argv[], + const char *envp[], + const char *working_directory, // NULL => dont' change, non-NULL => set working directory for inferior to this + const char *stdin_path, + const char *stdout_path, + const char *stderr_path, + bool no_stdio, + nub_launch_flavor_t launch_flavor, + int disable_aslr, + char *err_str, + size_t err_len) DNB_EXPORT; + nub_process_t DNBProcessAttach (nub_process_t pid, struct timespec *timeout, char *err_str, size_t err_len) DNB_EXPORT; nub_process_t DNBProcessAttachByName (const char *name, struct timespec *timeout, char *err_str, size_t err_len) DNB_EXPORT; nub_process_t DNBProcessAttachWait (const char *wait_name, nub_launch_flavor_t launch_flavor, struct timespec *timeout, useconds_t interval, char *err_str, size_t err_len, DNBShouldCancelCallback should_cancel = NULL, void *callback_data = NULL) DNB_EXPORT; diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.cpp b/lldb/tools/debugserver/source/MacOSX/MachProcess.cpp index aa3465b0f6a..8b4c61b433b 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachProcess.cpp +++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.cpp @@ -1491,7 +1491,10 @@ MachProcess::LaunchForDebug const char *path, char const *argv[], char const *envp[], - const char *stdio_path, + const char *working_directory, // NULL => dont' change, non-NULL => set working directory for inferior to this + const char *stdin_path, + const char *stdout_path, + const char *stderr_path, bool no_stdio, nub_launch_flavor_t launch_flavor, int disable_aslr, @@ -1517,7 +1520,10 @@ MachProcess::LaunchForDebug DNBArchProtocol::GetArchitecture (), argv, envp, - stdio_path, + working_directory, + stdin_path, + stdout_path, + stderr_path, no_stdio, this, disable_aslr, @@ -1607,7 +1613,10 @@ MachProcess::PosixSpawnChildForPTraceDebugging cpu_type_t cpu_type, char const *argv[], char const *envp[], - const char *stdio_path, + const char *working_directory, + const char *stdin_path, + const char *stdout_path, + const char *stderr_path, bool no_stdio, MachProcess* process, int disable_aslr, @@ -1665,14 +1674,13 @@ MachProcess::PosixSpawnChildForPTraceDebugging pid_t pid = INVALID_NUB_PROCESS; if (file_actions_valid) { - if (stdio_path == NULL && !no_stdio) + if (stdin_path == NULL && stdout_path == NULL && stderr_path == NULL && !no_stdio) { pty_error = pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY); if (pty_error == PseudoTerminal::success) - stdio_path = pty.SlaveName(); - // Make sure we were able to get the slave name - if (stdio_path == NULL) - stdio_path = "/dev/null"; + { + stdin_path = stdout_path = stderr_path = pty.SlaveName(); + } } // if no_stdio, then do open file actions, opening /dev/null. @@ -1693,11 +1701,11 @@ MachProcess::PosixSpawnChildForPTraceDebugging if (err.Fail() || DNBLogCheckLogBit (LOG_PROCESS)) err.LogThreaded ("::posix_spawn_file_actions_addopen (&file_actions, filedes=STDERR_FILENO, path=/dev/null)"); } - else if (stdio_path != NULL) + else { - int slave_fd_err = open (stdio_path, O_RDWR, 0); - int slave_fd_in = open (stdio_path, O_RDONLY, 0); - int slave_fd_out = open (stdio_path, O_WRONLY, 0); + int slave_fd_err = open (stderr_path ? stderr_path : "/dev/null", O_RDWR , 0); + int slave_fd_in = open (stdin_path ? stdin_path : "/dev/null", O_RDONLY, 0); + int slave_fd_out = open (stdout_path ? stdout_path : "/dev/null", O_WRONLY, 0); err.SetError( ::posix_spawn_file_actions_adddup2(&file_actions, slave_fd_err, STDERR_FILENO), DNBError::POSIX); if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.h b/lldb/tools/debugserver/source/MacOSX/MachProcess.h index 0c6f2371f2b..85a8b467382 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachProcess.h +++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.h @@ -47,9 +47,30 @@ public: // Child process control //---------------------------------------------------------------------- pid_t AttachForDebug (pid_t pid, char *err_str, size_t err_len); - pid_t LaunchForDebug (const char *path, char const *argv[], char const *envp[], const char *stdio_path, bool no_stdio, nub_launch_flavor_t launch_flavor, int disable_aslr, DNBError &err); + pid_t LaunchForDebug (const char *path, + char const *argv[], + char const *envp[], + const char *working_directory, + const char *stdin_path, + const char *stdout_path, + const char *stderr_path, + bool no_stdio, + nub_launch_flavor_t launch_flavor, + int disable_aslr, + DNBError &err); static pid_t ForkChildForPTraceDebugging (const char *path, char const *argv[], char const *envp[], MachProcess* process, DNBError &err); - static pid_t PosixSpawnChildForPTraceDebugging (const char *path, cpu_type_t cpu_type, char const *argv[], char const *envp[], const char *stdio_path, bool no_stdio, MachProcess* process, int disable_aslr, DNBError& err); + static pid_t PosixSpawnChildForPTraceDebugging (const char *path, + cpu_type_t cpu_type, + char const *argv[], + char const *envp[], + const char *working_directory, + const char *stdin_path, + const char *stdout_path, + const char *stderr_path, + bool no_stdio, + MachProcess* process, + int disable_aslr, + DNBError& err); nub_addr_t GetDYLDAllImageInfosAddress (); static const void * PrepareForAttach (const char *path, nub_launch_flavor_t launch_flavor, bool waitfor, DNBError &err_str); static void CleanupAfterAttach (const void *attach_token, bool success, DNBError &err_str); diff --git a/lldb/tools/debugserver/source/RNBContext.cpp b/lldb/tools/debugserver/source/RNBContext.cpp index de850dba409..29bc6388e2a 100644 --- a/lldb/tools/debugserver/source/RNBContext.cpp +++ b/lldb/tools/debugserver/source/RNBContext.cpp @@ -12,11 +12,15 @@ //===----------------------------------------------------------------------===// #include "RNBContext.h" + +#include <sys/stat.h> +#include <sstream> + #include "RNBRemote.h" #include "DNB.h" #include "DNBLog.h" #include "CFString.h" -#include <sstream> + //---------------------------------------------------------------------- // Destructor @@ -49,6 +53,20 @@ RNBContext::ArgumentAtIndex (int index) return NULL; } +bool +RNBContext::SetWorkingDirectory (const char *path) +{ + struct stat working_directory_stat; + if (::stat (path, &working_directory_stat) != 0) + { + m_working_directory.clear(); + return false; + } + m_working_directory.assign(path); + return true; +} + + void RNBContext::SetProcessID (nub_process_t pid) { diff --git a/lldb/tools/debugserver/source/RNBContext.h b/lldb/tools/debugserver/source/RNBContext.h index 4b5f5ae2cc9..93b98de9a7d 100644 --- a/lldb/tools/debugserver/source/RNBContext.h +++ b/lldb/tools/debugserver/source/RNBContext.h @@ -95,6 +95,16 @@ public: const char * LaunchStatusAsString (std::string& s); nub_launch_flavor_t LaunchFlavor () const { return m_launch_flavor; } void SetLaunchFlavor (nub_launch_flavor_t flavor) { m_launch_flavor = flavor; } + + const char * GetWorkingDirectory () const + { + if (!m_working_directory.empty()) + return m_working_directory.c_str(); + return NULL; + } + + bool SetWorkingDirectory (const char *path); + protected: //------------------------------------------------------------------ // Classes that inherit from RNBContext can see and modify these @@ -107,6 +117,7 @@ protected: DNBError m_launch_status; // This holds the status from the last launch attempt. std::vector<std::string> m_arg_vec; std::vector<std::string> m_env_vec; // This will be unparsed - entries FOO=value + std::string m_working_directory; void StartProcessStatusThread(); void StopProcessStatusThread(); diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp index 235f9a7e047..8a94570da61 100644 --- a/lldb/tools/debugserver/source/RNBRemote.cpp +++ b/lldb/tools/debugserver/source/RNBRemote.cpp @@ -3126,6 +3126,7 @@ RNBRemote::HandlePacket_k (const char *p) // No response to should be sent to the kill packet if (m_ctx.HasValidProcessID()) DNBProcessKill (m_ctx.ProcessID()); + SendPacket ("W09"); return rnb_success; } diff --git a/lldb/tools/debugserver/source/debugserver.cpp b/lldb/tools/debugserver/source/debugserver.cpp index 6b08b1bf9c1..49f1f0c9f10 100644 --- a/lldb/tools/debugserver/source/debugserver.cpp +++ b/lldb/tools/debugserver/source/debugserver.cpp @@ -61,26 +61,18 @@ int g_isatty = 0; #define RNBLogSTDERR(fmt, ...) do { if (g_isatty) { fprintf(stderr, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0) //---------------------------------------------------------------------- -// Run Loop function prototypes -//---------------------------------------------------------------------- -RNBRunLoopMode RNBRunLoopGetStartModeFromRemote (RNBRemoteSP &remote); -RNBRunLoopMode RNBRunLoopInferiorExecuting (RNBRemoteSP &remote); - - -//---------------------------------------------------------------------- // 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. //---------------------------------------------------------------------- RNBRunLoopMode -RNBRunLoopGetStartModeFromRemote (RNBRemoteSP &remoteSP) +RNBRunLoopGetStartModeFromRemote (RNBRemote* remote) { std::string packet; - if (remoteSP.get() != NULL) + if (remote) { - RNBRemote* remote = remoteSP.get(); RNBContext& ctx = remote->Context(); uint32_t event_mask = RNBContext::event_read_packet_available; @@ -151,7 +143,7 @@ RNBRunLoopGetStartModeFromRemote (RNBRemoteSP &remoteSP) // or crash process state. //---------------------------------------------------------------------- RNBRunLoopMode -RNBRunLoopLaunchInferior (RNBRemoteSP &remote, const char *stdio_path, bool no_stdio) +RNBRunLoopLaunchInferior (RNBRemote *remote, const char *stdin_path, const char *stdout_path, const char *stderr_path, bool no_stdio) { RNBContext& ctx = remote->Context(); @@ -208,7 +200,10 @@ RNBRunLoopLaunchInferior (RNBRemoteSP &remote, const char *stdio_path, bool no_s nub_process_t pid = DNBProcessLaunch (resolved_path, &inferior_argv[0], &inferior_envp[0], - stdio_path, + ctx.GetWorkingDirectory(), + stdin_path, + stdout_path, + stderr_path, no_stdio, launch_flavor, g_disable_aslr, @@ -317,7 +312,7 @@ RNBRunLoopLaunchInferior (RNBRemoteSP &remote, const char *stdio_path, bool no_s // or crash process state. //---------------------------------------------------------------------- RNBRunLoopMode -RNBRunLoopLaunchAttaching (RNBRemoteSP &remote, nub_process_t attach_pid, nub_process_t& pid) +RNBRunLoopLaunchAttaching (RNBRemote *remote, nub_process_t attach_pid, nub_process_t& pid) { RNBContext& ctx = remote->Context(); @@ -381,7 +376,7 @@ signal_handler(int signo) // Return the new run loop mode based off of the current process state RNBRunLoopMode -HandleProcessStateChange (RNBRemoteSP &remote, bool initialize) +HandleProcessStateChange (RNBRemote *remote, bool initialize) { RNBContext& ctx = remote->Context(); nub_process_t pid = ctx.ProcessID(); @@ -460,7 +455,7 @@ HandleProcessStateChange (RNBRemoteSP &remote, bool initialize) // makes the inferior run, we need to leave this function with a new state // as the return code. RNBRunLoopMode -RNBRunLoopInferiorExecuting (RNBRemoteSP &remote) +RNBRunLoopInferiorExecuting (RNBRemote *remote) { DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__); RNBContext& ctx = remote->Context(); @@ -565,19 +560,19 @@ RNBRunLoopInferiorExecuting (RNBRemoteSP &remote) //---------------------------------------------------------------------- static int -StartListening (RNBRemoteSP remoteSP, int listen_port) +StartListening (RNBRemote *remote, int listen_port) { - if (!remoteSP->Comm().IsConnected()) + if (!remote->Comm().IsConnected()) { RNBLogSTDOUT ("Listening to port %i...\n", listen_port); - if (remoteSP->Comm().Listen(listen_port) != rnb_success) + if (remote->Comm().Listen(listen_port) != rnb_success) { RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n"); return 0; } else { - remoteSP->StartReadRemoteDataThread(); + remote->StartReadRemoteDataThread(); } } return 1; @@ -656,10 +651,14 @@ static struct option g_long_options[] = { "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 + { "stdio-path", required_argument, NULL, 's' }, // Set the STDIO path to be used when launching applications (STDIN, STDOUT and STDERR) + { "stdin-path", required_argument, NULL, 'I' }, // Set the STDIN path to be used when launching applications + { "stdout-path", required_argument, NULL, 'O' }, // Set the STDIN path to be used when launching applications + { "stderr-path", required_argument, NULL, 'E' }, // Set the STDIN path to be used when launching applications { "no-stdio", no_argument, NULL, 'n' }, // Do not set up any stdio (perhaps the program is a GUI program) { "setsid", no_argument, NULL, 'S' }, // call setsid() to make debugserver run in its own sessions { "disable-aslr", no_argument, NULL, 'D' }, // Use _POSIX_SPAWN_DISABLE_ASLR to avoid shared library randomization + { "chdir", no_argument, NULL, 'c' }, // Use _POSIX_SPAWN_DISABLE_ASLR to avoid shared library randomization { NULL, 0, NULL, 0 } }; @@ -696,8 +695,11 @@ main (int argc, char *argv[]) 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 stdio_path; + std::string stdin_path; + std::string stdout_path; + std::string stderr_path; std::string arch_name; + std::string working_directory; // The new working directory to use for the inferior 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; @@ -783,6 +785,11 @@ main (int argc, char *argv[]) } break; + case 'c': + if (optarg && optarg[0]) + working_directory.assign(optarg); + break; + case 'x': if (optarg && optarg[0]) { @@ -856,7 +863,21 @@ main (int argc, char *argv[]) break; case 's': - stdio_path = optarg; + stdin_path.assign(optarg); + stdout_path.assign(optarg); + stderr_path.assign(optarg); + break; + + case 'I': + stdin_path.assign(optarg); + break; + + case 'O': + stdout_path.assign(optarg); + break; + + case 'E': + stderr_path.assign(optarg); break; case 'n': @@ -910,7 +931,6 @@ main (int argc, char *argv[]) g_remoteSP.reset (new RNBRemote (use_native_registers, arch_name.c_str())); - RNBRemote *remote = g_remoteSP.get(); if (remote == NULL) { @@ -918,7 +938,16 @@ main (int argc, char *argv[]) return -1; } - g_remoteSP->Initialize(); + if (!working_directory.empty()) + { + if (remote->Context().SetWorkingDirectory (working_directory.c_str()) == false) + { + RNBLogSTDERR ("error: working directory doesn't exist '%s'.\n", working_directory.c_str()); + exit (8); + } + } + + remote->Initialize(); RNBContext& ctx = remote->Context(); @@ -1054,9 +1083,9 @@ main (int argc, char *argv[]) #if defined (__arm__) if (g_lockdown_opt) { - if (!g_remoteSP->Comm().IsConnected()) + if (!remote->Comm().IsConnected()) { - if (g_remoteSP->Comm().ConnectToService () != rnb_success) + if (remote->Comm().ConnectToService () != rnb_success) { RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n"); mode = eRNBRunLoopModeExit; @@ -1069,21 +1098,21 @@ main (int argc, char *argv[]) { DNBLogDebug("Task list: %s", applist_plist.c_str()); - g_remoteSP->Comm().Write(applist_plist.c_str(), applist_plist.size()); + 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; - g_remoteSP->Comm().Read(buf); + remote->Comm().Read(buf); } - g_remoteSP->Comm().Disconnect(false); + remote->Comm().Disconnect(false); mode = eRNBRunLoopModeExit; break; } else { // Start watching for remote packets - g_remoteSP->StartReadRemoteDataThread(); + remote->StartReadRemoteDataThread(); } } } @@ -1091,19 +1120,19 @@ main (int argc, char *argv[]) #endif if (listen_port != INT32_MAX) { - if (!StartListening (g_remoteSP, listen_port)) + if (!StartListening (remote, listen_port)) mode = eRNBRunLoopModeExit; } else if (str[0] == '/') { - if (g_remoteSP->Comm().OpenFile (str)) + if (remote->Comm().OpenFile (str)) mode = eRNBRunLoopModeExit; } if (mode != eRNBRunLoopModeExit) { RNBLogSTDOUT ("Got a connection, waiting for process information for launching or attaching.\n"); - mode = RNBRunLoopGetStartModeFromRemote (g_remoteSP); + mode = RNBRunLoopGetStartModeFromRemote (remote); } break; @@ -1157,7 +1186,7 @@ main (int argc, char *argv[]) RNBLogSTDOUT ("Attaching to process %i...\n", attach_pid); nub_process_t attached_pid; - mode = RNBRunLoopLaunchAttaching (g_remoteSP, attach_pid, attached_pid); + mode = RNBRunLoopLaunchAttaching (remote, attach_pid, attached_pid); if (mode != eRNBRunLoopModeInferiorExecuting) { const char *error_str = remote->Context().LaunchStatus().AsString(); @@ -1201,12 +1230,12 @@ main (int argc, char *argv[]) { if (listen_port != INT32_MAX) { - if (!StartListening (g_remoteSP, listen_port)) + if (!StartListening (remote, listen_port)) mode = eRNBRunLoopModeExit; } else if (str[0] == '/') { - if (g_remoteSP->Comm().OpenFile (str)) + if (remote->Comm().OpenFile (str)) mode = eRNBRunLoopModeExit; } if (mode != eRNBRunLoopModeExit) @@ -1215,33 +1244,39 @@ main (int argc, char *argv[]) break; case eRNBRunLoopModeInferiorLaunching: - mode = RNBRunLoopLaunchInferior (g_remoteSP, stdio_path.empty() ? NULL : stdio_path.c_str(), no_stdio); - - if (mode == eRNBRunLoopModeInferiorExecuting) { - if (listen_port != INT32_MAX) + mode = RNBRunLoopLaunchInferior (remote, + stdin_path.empty() ? NULL : stdin_path.c_str(), + stdout_path.empty() ? NULL : stdout_path.c_str(), + stderr_path.empty() ? NULL : stderr_path.c_str(), + no_stdio); + + if (mode == eRNBRunLoopModeInferiorExecuting) { - if (!StartListening (g_remoteSP, listen_port)) - mode = eRNBRunLoopModeExit; + if (listen_port != INT32_MAX) + { + if (!StartListening (remote, listen_port)) + mode = eRNBRunLoopModeExit; + } + else if (str[0] == '/') + { + if (remote->Comm().OpenFile (str)) + mode = eRNBRunLoopModeExit; + } + + if (mode != eRNBRunLoopModeExit) + RNBLogSTDOUT ("Got a connection, waiting for debugger instructions.\n"); } - else if (str[0] == '/') + else { - if (g_remoteSP->Comm().OpenFile (str)) - mode = eRNBRunLoopModeExit; + const char *error_str = remote->Context().LaunchStatus().AsString(); + RNBLogSTDERR ("error: failed to launch process %s: %s\n", argv[0], error_str ? error_str : "unknown error."); } - - if (mode != eRNBRunLoopModeExit) - RNBLogSTDOUT ("Got a connection, waiting for debugger instructions.\n"); - } - else - { - const char *error_str = remote->Context().LaunchStatus().AsString(); - RNBLogSTDERR ("error: failed to launch process %s: %s\n", argv[0], error_str ? error_str : "unknown error."); } break; case eRNBRunLoopModeInferiorExecuting: - mode = RNBRunLoopInferiorExecuting(g_remoteSP); + mode = RNBRunLoopInferiorExecuting(remote); break; default: @@ -1251,8 +1286,8 @@ main (int argc, char *argv[]) } } - g_remoteSP->StopReadRemoteDataThread (); - g_remoteSP->Context().SetProcessID(INVALID_NUB_PROCESS); + remote->StopReadRemoteDataThread (); + remote->Context().SetProcessID(INVALID_NUB_PROCESS); return 0; } |