[Lldb-commits] [lldb] r183049 - Add ability to attach/detach to multi-threaded inferiors on Linux.
Matt Kopec
Matt.Kopec at intel.com
Fri May 31 15:00:07 PDT 2013
Author: mkopec
Date: Fri May 31 17:00:07 2013
New Revision: 183049
URL: http://llvm.org/viewvc/llvm-project?rev=183049&view=rev
Log:
Add ability to attach/detach to multi-threaded inferiors on Linux.
All running threads will be detected and stopped on attach and all threads get resumed on detach.
Modified:
lldb/trunk/include/lldb/Host/Host.h
lldb/trunk/source/Host/common/Host.cpp
lldb/trunk/source/Host/linux/Host.cpp
lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp
lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h
lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
Modified: lldb/trunk/include/lldb/Host/Host.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/Host.h?rev=183049&r1=183048&r2=183049&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Host/Host.h (original)
+++ lldb/trunk/include/lldb/Host/Host.h Fri May 31 17:00:07 2013
@@ -13,6 +13,7 @@
#include <stdarg.h>
+#include <map>
#include <string>
#include "lldb/lldb-private.h"
@@ -414,7 +415,12 @@ public:
static uint32_t
FindProcesses (const ProcessInstanceInfoMatch &match_info,
ProcessInstanceInfoList &proc_infos);
-
+
+ typedef std::map<lldb::pid_t, bool> TidMap;
+ typedef std::pair<lldb::pid_t, bool> TidPair;
+ static bool
+ FindProcessThreads (const lldb::pid_t pid, TidMap &tids_to_attach);
+
static bool
GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &proc_info);
Modified: lldb/trunk/source/Host/common/Host.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/Host.cpp?rev=183049&r1=183048&r2=183049&view=diff
==============================================================================
--- lldb/trunk/source/Host/common/Host.cpp (original)
+++ lldb/trunk/source/Host/common/Host.cpp Fri May 31 17:00:07 2013
@@ -1238,6 +1238,14 @@ Host::GetProcessInfo (lldb::pid_t pid, P
}
#endif
+#if !defined(__linux__)
+bool
+Host::FindProcessThreads (const lldb::pid_t pid, TidMap &tids_to_attach)
+{
+ return false;
+}
+#endif
+
lldb::TargetSP
Host::GetDummyTarget (lldb_private::Debugger &debugger)
{
Modified: lldb/trunk/source/Host/linux/Host.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/linux/Host.cpp?rev=183049&r1=183048&r2=183049&view=diff
==============================================================================
--- lldb/trunk/source/Host/linux/Host.cpp (original)
+++ lldb/trunk/source/Host/linux/Host.cpp Fri May 31 17:00:07 2013
@@ -295,6 +295,37 @@ Host::FindProcesses (const ProcessInstan
return process_infos.GetSize();
}
+bool
+Host::FindProcessThreads (const lldb::pid_t pid, TidMap &tids_to_attach)
+{
+ bool tids_changed = false;
+ static const char procdir[] = "/proc/";
+ static const char taskdir[] = "/task/";
+ std::string process_task_dir = procdir + std::to_string(pid) + taskdir;
+ DIR *dirproc = opendir (process_task_dir.c_str());
+
+ if (dirproc)
+ {
+ struct dirent *direntry = NULL;
+ while ((direntry = readdir (dirproc)) != NULL)
+ {
+ if (direntry->d_type != DT_DIR || !IsDirNumeric (direntry->d_name))
+ continue;
+
+ lldb::tid_t tid = atoi(direntry->d_name);
+ TidMap::iterator it = tids_to_attach.find(tid);
+ if (it == tids_to_attach.end())
+ {
+ tids_to_attach.insert(TidPair(tid, false));
+ tids_changed = true;
+ }
+ }
+ closedir (dirproc);
+ }
+
+ return tids_changed;
+}
+
static bool
GetELFProcessCPUType (const char *exe_path, ProcessInstanceInfo &process_info)
{
Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp?rev=183049&r1=183048&r2=183049&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp Fri May 31 17:00:07 2013
@@ -857,22 +857,20 @@ KillOperation::Execute(ProcessMonitor *m
class DetachOperation : public Operation
{
public:
- DetachOperation(Error &result) : m_error(result) { }
+ DetachOperation(lldb::tid_t tid, Error &result) : m_tid(tid), m_error(result) { }
void Execute(ProcessMonitor *monitor);
private:
+ lldb::tid_t m_tid;
Error &m_error;
};
void
DetachOperation::Execute(ProcessMonitor *monitor)
{
- lldb::pid_t pid = monitor->GetPID();
-
- if (ptrace(PT_DETACH, pid, NULL, 0) < 0)
+ if (ptrace(PT_DETACH, m_tid, NULL, 0) < 0)
m_error.SetErrorToErrno();
-
}
ProcessMonitor::OperationArgs::OperationArgs(ProcessMonitor *monitor)
@@ -1098,7 +1096,6 @@ ProcessMonitor::Launch(LaunchArgs *args)
const size_t err_len = 1024;
char err_str[err_len];
lldb::pid_t pid;
- long ptrace_opts = 0;
lldb::ThreadSP inferior;
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
@@ -1214,20 +1211,7 @@ ProcessMonitor::Launch(LaunchArgs *args)
assert(WIFSTOPPED(status) && wpid == pid &&
"Could not sync with inferior process.");
- // Have the child raise an event on exit. This is used to keep the child in
- // limbo until it is destroyed.
- ptrace_opts |= PTRACE_O_TRACEEXIT;
-
- // Have the tracer trace threads which spawn in the inferior process.
- // TODO: if we want to support tracing the inferiors' child, add the
- // appropriate ptrace flags here (PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK)
- ptrace_opts |= PTRACE_O_TRACECLONE;
-
- // Have the tracer notify us before execve returns
- // (needed to disable legacy SIGTRAP generation)
- ptrace_opts |= PTRACE_O_TRACEEXEC;
-
- if (PTRACE(PTRACE_SETOPTIONS, pid, NULL, (void*)ptrace_opts, 0) < 0)
+ if (!SetDefaultPtraceOpts(pid))
{
args->m_error.SetErrorToErrno();
goto FINISH;
@@ -1308,6 +1292,9 @@ ProcessMonitor::Attach(AttachArgs *args)
lldb::ThreadSP inferior;
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+ // Use a map to keep track of the threads which we have attached/need to attach.
+ Host::TidMap tids_to_attach;
+
if (pid <= 1)
{
args->m_error.SetErrorToGenericError();
@@ -1315,33 +1302,103 @@ ProcessMonitor::Attach(AttachArgs *args)
goto FINISH;
}
- // Attach to the requested process.
- if (PTRACE(PTRACE_ATTACH, pid, NULL, NULL, 0) < 0)
+ while (Host::FindProcessThreads(pid, tids_to_attach))
{
- args->m_error.SetErrorToErrno();
- goto FINISH;
+ for (Host::TidMap::iterator it = tids_to_attach.begin();
+ it != tids_to_attach.end(); ++it)
+ {
+ if (it->second == false)
+ {
+ lldb::tid_t tid = it->first;
+
+ // Attach to the requested process.
+ // An attach will cause the thread to stop with a SIGSTOP.
+ if (PTRACE(PTRACE_ATTACH, tid, NULL, NULL, 0) < 0)
+ {
+ // No such thread. The thread may have exited.
+ // More error handling may be needed.
+ if (errno == ESRCH)
+ {
+ tids_to_attach.erase(it);
+ continue;
+ }
+ else
+ {
+ args->m_error.SetErrorToErrno();
+ goto FINISH;
+ }
+ }
+
+ int status;
+ // Need to use __WALL otherwise we receive an error with errno=ECHLD
+ // At this point we should have a thread stopped if waitpid succeeds.
+ if ((status = waitpid(tid, NULL, __WALL)) < 0)
+ {
+ // No such thread. The thread may have exited.
+ // More error handling may be needed.
+ if (errno == ESRCH)
+ {
+ tids_to_attach.erase(it);
+ continue;
+ }
+ else
+ {
+ args->m_error.SetErrorToErrno();
+ goto FINISH;
+ }
+ }
+
+ if (!SetDefaultPtraceOpts(tid))
+ {
+ args->m_error.SetErrorToErrno();
+ goto FINISH;
+ }
+
+ // Update the process thread list with the attached thread.
+ inferior.reset(new POSIXThread(process, tid));
+ if (log)
+ log->Printf ("ProcessMonitor::%s() adding tid = %" PRIu64, __FUNCTION__, tid);
+ process.GetThreadList().AddThread(inferior);
+ it->second = true;
+ }
+ }
}
- int status;
- if ((status = waitpid(pid, NULL, 0)) < 0)
+ if (tids_to_attach.size() > 0)
{
- args->m_error.SetErrorToErrno();
- goto FINISH;
+ monitor->m_pid = pid;
+ // Let our process instance know the thread has stopped.
+ process.SendMessage(ProcessMessage::Trace(pid));
+ }
+ else
+ {
+ args->m_error.SetErrorToGenericError();
+ args->m_error.SetErrorString("No such process.");
}
- monitor->m_pid = pid;
+ FINISH:
+ return args->m_error.Success();
+}
- // Update the process thread list with the attached thread.
- inferior.reset(new POSIXThread(process, pid));
- if (log)
- log->Printf ("ProcessMonitor::%s() adding tid = %" PRIu64, __FUNCTION__, pid);
- process.GetThreadList().AddThread(inferior);
+bool
+ProcessMonitor::SetDefaultPtraceOpts(lldb::pid_t pid)
+{
+ long ptrace_opts = 0;
- // Let our process instance know the thread has stopped.
- process.SendMessage(ProcessMessage::Trace(pid));
+ // Have the child raise an event on exit. This is used to keep the child in
+ // limbo until it is destroyed.
+ ptrace_opts |= PTRACE_O_TRACEEXIT;
- FINISH:
- return args->m_error.Success();
+ // Have the tracer trace threads which spawn in the inferior process.
+ // TODO: if we want to support tracing the inferiors' child, add the
+ // appropriate ptrace flags here (PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK)
+ ptrace_opts |= PTRACE_O_TRACECLONE;
+
+ // Have the tracer notify us before execve returns
+ // (needed to disable legacy SIGTRAP generation)
+ ptrace_opts |= PTRACE_O_TRACEEXEC;
+
+ return PTRACE(PTRACE_SETOPTIONS, pid, NULL, (void*)ptrace_opts, 0) >= 0;
}
bool
@@ -2047,11 +2104,12 @@ ProcessMonitor::GetEventMessage(lldb::ti
}
lldb_private::Error
-ProcessMonitor::Detach()
+ProcessMonitor::Detach(lldb::tid_t tid)
{
lldb_private::Error error;
- if (m_pid != LLDB_INVALID_PROCESS_ID) {
- DetachOperation op(error);
+ if (tid != LLDB_INVALID_THREAD_ID)
+ {
+ DetachOperation op(tid, error);
DoOperation(&op);
}
return error;
Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h?rev=183049&r1=183048&r2=183049&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h Fri May 31 17:00:07 2013
@@ -175,7 +175,7 @@ public:
BringProcessIntoLimbo();
lldb_private::Error
- Detach();
+ Detach(lldb::tid_t tid);
/// Stops the requested thread and waits for the stop signal.
bool
@@ -262,6 +262,9 @@ private:
static bool
Attach(AttachArgs *args);
+ static bool
+ SetDefaultPtraceOpts(const lldb::pid_t);
+
static void
ServeOperation(OperationArgs *args);
Modified: lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp?rev=183049&r1=183048&r2=183049&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp Fri May 31 17:00:07 2013
@@ -329,7 +329,14 @@ ProcessPOSIX::DoDetach(bool keep_stopped
return error;
}
- error = m_monitor->Detach();
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ error = m_monitor->Detach(thread->GetID());
+ }
+
if (error.Success())
SetPrivateState(eStateDetached);
@@ -393,7 +400,7 @@ ProcessPOSIX::SendMessage(const ProcessM
if (m_exit_now)
{
SetPrivateState(eStateExited);
- m_monitor->Detach();
+ m_monitor->Detach(GetID());
}
else
{
More information about the lldb-commits
mailing list