summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/Target/Process.h2
-rw-r--r--lldb/source/API/SBProcess.cpp10
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp16
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h12
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp124
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h9
-rw-r--r--lldb/source/Target/Process.cpp55
-rw-r--r--lldb/tools/debugserver/source/DNB.cpp17
-rw-r--r--lldb/tools/debugserver/source/DNB.h14
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachProcess.cpp32
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachProcess.h25
-rw-r--r--lldb/tools/debugserver/source/RNBContext.cpp20
-rw-r--r--lldb/tools/debugserver/source/RNBContext.h11
-rw-r--r--lldb/tools/debugserver/source/RNBRemote.cpp1
-rw-r--r--lldb/tools/debugserver/source/debugserver.cpp147
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;
}
OpenPOWER on IntegriCloud