summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp
diff options
context:
space:
mode:
authorAndrew Kaylor <andrew.kaylor@intel.com>2013-05-28 23:04:25 +0000
committerAndrew Kaylor <andrew.kaylor@intel.com>2013-05-28 23:04:25 +0000
commit93132f504f0d29ef1e1d90360977aa31c548d28e (patch)
tree52dec72376e6db0dc1ec0dd54325980ba61c9bab /lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp
parent6477e97af73a6bc036888d68b79d919f8b11cd2a (diff)
downloadbcm5719-llvm-93132f504f0d29ef1e1d90360977aa31c548d28e.tar.gz
bcm5719-llvm-93132f504f0d29ef1e1d90360977aa31c548d28e.zip
Adding support for stopping all threads of multithreaded inferiors on Linux. Also adding multithreaded test cases.
llvm-svn: 182809
Diffstat (limited to 'lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp')
-rw-r--r--lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp209
1 files changed, 203 insertions, 6 deletions
diff --git a/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp b/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp
index f2577e26227..0ba8840ad16 100644
--- a/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp
+++ b/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp
@@ -17,6 +17,7 @@
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/socket.h>
+#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -52,6 +53,10 @@
#define TRAP_HWBKPT 4
#endif
+// Try to define a macro to encapsulate the tgkill syscall
+// fall back on kill() if tgkill isn't available
+#define tgkill(pid, tid, sig) syscall(SYS_tgkill, pid, tid, sig)
+
using namespace lldb_private;
// FIXME: this code is host-dependent with respect to types and
@@ -724,7 +729,13 @@ ResumeOperation::Execute(ProcessMonitor *monitor)
data = m_signo;
if (PTRACE(PTRACE_CONT, m_tid, NULL, (void*)data, 0))
+ {
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("ResumeOperation (%" PRIu64 ") failed: %s", m_tid, strerror(errno));
m_result = false;
+ }
else
m_result = true;
}
@@ -1348,8 +1359,21 @@ ProcessMonitor::MonitorCallback(void *callback_baton,
siginfo_t info;
int ptrace_err;
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ if (exited)
+ {
+ if (log)
+ log->Printf ("ProcessMonitor::%s() got exit signal, tid = %" PRIu64, __FUNCTION__, pid);
+ message = ProcessMessage::Exit(pid, status);
+ process->SendMessage(message);
+ return pid == process->GetID();
+ }
+
if (!monitor->GetSignalInfo(pid, &info, ptrace_err)) {
if (ptrace_err == EINVAL) {
+ if (log)
+ log->Printf ("ProcessMonitor::%s() resuming from group-stop", __FUNCTION__);
// inferior process is in 'group-stop', so deliver SIGSTOP signal
if (!monitor->Resume(pid, SIGSTOP)) {
assert(0 && "SIGSTOP delivery failed while in 'group-stop' state");
@@ -1358,8 +1382,11 @@ ProcessMonitor::MonitorCallback(void *callback_baton,
} else {
// ptrace(GETSIGINFO) failed (but not due to group-stop). Most likely,
// this means the child pid is gone (or not being debugged) therefore
- // stop the monitor thread.
- stop_monitoring = true;
+ // stop the monitor thread if this is the main pid.
+ if (log)
+ log->Printf ("ProcessMonitor::%s() GetSignalInfo failed: %s, tid = %" PRIu64 ", signal = %d, status = %d",
+ __FUNCTION__, strerror(ptrace_err), pid, signal, status);
+ stop_monitoring = pid == monitor->m_process->GetID();
}
}
else {
@@ -1375,7 +1402,7 @@ ProcessMonitor::MonitorCallback(void *callback_baton,
}
process->SendMessage(message);
- stop_monitoring = !process->IsAlive();
+ stop_monitoring = false;
}
return stop_monitoring;
@@ -1387,6 +1414,8 @@ ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor,
{
ProcessMessage message;
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
assert(monitor);
assert(info && info->si_signo == SIGTRAP && "Unexpected child signal!");
@@ -1403,6 +1432,9 @@ ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor,
case (SIGTRAP | (PTRACE_EVENT_CLONE << 8)):
{
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received thread creation event, code = %d", __FUNCTION__, info->si_code ^ SIGTRAP);
+
unsigned long tid = 0;
if (!monitor->GetEventMessage(pid, &tid))
tid = -1;
@@ -1417,27 +1449,35 @@ ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor,
case (SIGTRAP | (PTRACE_EVENT_EXIT << 8)):
{
- // The inferior process is about to exit. Maintain the process in a
- // state of "limbo" until we are explicitly commanded to detach,
- // destroy, resume, etc.
+ // The inferior process or one of its threads is about to exit.
+ // Maintain the process or thread in a state of "limbo" until we are
+ // explicitly commanded to detach, destroy, resume, etc.
unsigned long data = 0;
if (!monitor->GetEventMessage(pid, &data))
data = -1;
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received exit event, data = %lx, pid = %" PRIu64, __FUNCTION__, data, pid);
message = ProcessMessage::Limbo(pid, (data >> 8));
break;
}
case 0:
case TRAP_TRACE:
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received trace event, pid = %" PRIu64, __FUNCTION__, pid);
message = ProcessMessage::Trace(pid);
break;
case SI_KERNEL:
case TRAP_BRKPT:
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received breakpoint event, pid = %" PRIu64, __FUNCTION__, pid);
message = ProcessMessage::Break(pid);
break;
case TRAP_HWBKPT:
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received watchpoint event, pid = %" PRIu64, __FUNCTION__, pid);
message = ProcessMessage::Watch(pid, (lldb::addr_t)info->si_addr);
break;
}
@@ -1452,6 +1492,8 @@ ProcessMonitor::MonitorSignal(ProcessMonitor *monitor,
ProcessMessage message;
int signo = info->si_signo;
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
// POSIX says that process behaviour is undefined after it ignores a SIGFPE,
// SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a
// kill(2) or raise(3). Similarly for tgkill(2) on Linux.
@@ -1462,12 +1504,22 @@ ProcessMonitor::MonitorSignal(ProcessMonitor *monitor,
// Similarly, ACK signals generated by this monitor.
if (info->si_code == SI_TKILL || info->si_code == SI_USER)
{
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received signal %s with code %s, pid = %" PRIu64,
+ __FUNCTION__,
+ monitor->m_process->GetUnixSignals().GetSignalAsCString (signo),
+ (info->si_code == SI_TKILL ? "SI_TKILL" : "SI_USER"),
+ info->si_pid);
+
if (info->si_pid == getpid())
return ProcessMessage::SignalDelivered(pid, signo);
else
return ProcessMessage::Signal(pid, signo);
}
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received signal %s", __FUNCTION__, monitor->m_process->GetUnixSignals().GetSignalAsCString (signo));
+
if (signo == SIGSEGV) {
lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
ProcessMessage::CrashReason reason = GetCrashReasonForSIGSEGV(info);
@@ -1497,6 +1549,144 @@ ProcessMonitor::MonitorSignal(ProcessMonitor *monitor,
return ProcessMessage::Signal(pid, signo);
}
+bool
+ProcessMonitor::StopThread(lldb::tid_t tid)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ // FIXME: Try to use tgkill or tkill
+ int ret = tgkill(m_pid, tid, SIGSTOP);
+ if (log)
+ log->Printf ("ProcessMonitor::%s(bp) stopping thread, tid = %" PRIu64 ", ret = %d", __FUNCTION__, tid, ret);
+
+ // This can happen if a thread exited while we were trying to stop it. That's OK.
+ // We'll get the signal for that later.
+ if (ret < 0)
+ return false;
+
+ // Wait for the thread to stop
+ while (true)
+ {
+ int status = -1;
+ if (log)
+ log->Printf ("ProcessMonitor::%s(bp) waitpid...", __FUNCTION__);
+ lldb::pid_t wait_pid = ::waitpid (-1*m_pid, &status, __WALL);
+ if (log)
+ log->Printf ("ProcessMonitor::%s(bp) waitpid, pid = %" PRIu64 ", status = %d", __FUNCTION__, wait_pid, status);
+
+ if (wait_pid == -1)
+ {
+ // If we got interrupted by a signal (in our process, not the
+ // inferior) try again.
+ if (errno == EINTR)
+ continue;
+ else
+ return false; // This is bad, but there's nothing we can do.
+ }
+
+ // If this is a thread exit, we won't get any more information.
+ if (WIFEXITED(status))
+ {
+ m_process->SendMessage(ProcessMessage::Exit(wait_pid, WEXITSTATUS(status)));
+ if (wait_pid == tid)
+ return true;
+ continue;
+ }
+
+ siginfo_t info;
+ int ptrace_err;
+ if (!GetSignalInfo(wait_pid, &info, ptrace_err))
+ {
+ if (log)
+ {
+ log->Printf ("ProcessMonitor::%s() GetSignalInfo failed.", __FUNCTION__);
+
+ // This would be a particularly interesting case
+ if (ptrace_err == EINVAL)
+ log->Printf ("ProcessMonitor::%s() in group-stop", __FUNCTION__);
+ }
+ return false;
+ }
+
+ // Handle events from other threads
+ if (log)
+ log->Printf ("ProcessMonitor::%s(bp) handling event, tid == %d", __FUNCTION__, wait_pid);
+
+ ProcessMessage message;
+ if (info.si_signo == SIGTRAP)
+ message = MonitorSIGTRAP(this, &info, wait_pid);
+ else
+ message = MonitorSignal(this, &info, wait_pid);
+
+ POSIXThread *thread = static_cast<POSIXThread*>(m_process->GetThreadList().FindThreadByID(wait_pid).get());
+
+ // When a new thread is created, we may get a SIGSTOP for the new thread
+ // just before we get the SIGTRAP that we use to add the thread to our
+ // process thread list. We don't need to worry about that signal here.
+ assert(thread || message.GetKind() == ProcessMessage::eSignalMessage);
+
+ if (!thread)
+ {
+ m_process->SendMessage(message);
+ continue;
+ }
+
+ switch (message.GetKind())
+ {
+ case ProcessMessage::eInvalidMessage:
+ break;
+
+ // These need special handling because we don't want to send a
+ // resume even if we already sent a SIGSTOP to this thread. In
+ // this case the resume will cause the thread to disappear. It is
+ // unlikely that we'll ever get eExitMessage here, but the same
+ // reasoning applies.
+ case ProcessMessage::eLimboMessage:
+ case ProcessMessage::eExitMessage:
+ if (log)
+ log->Printf ("ProcessMonitor::%s(bp) handling message", __FUNCTION__);
+ // SendMessage will set the thread state as needed.
+ m_process->SendMessage(message);
+ // If this is the thread we're waiting for, stop waiting. Even
+ // though this wasn't the signal we expected, it's the last
+ // signal we'll see while this thread is alive.
+ if (wait_pid == tid)
+ return true;
+ break;
+
+ case ProcessMessage::eSignalDeliveredMessage:
+ // This is the stop we're expecting.
+ if (wait_pid == tid && WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP && info.si_code == SI_TKILL)
+ {
+ if (log)
+ log->Printf ("ProcessMonitor::%s(bp) received signal, done waiting", __FUNCTION__);
+ thread->SetState(lldb::eStateStopped);
+ return true;
+ }
+ // else fall-through
+ case ProcessMessage::eSignalMessage:
+ case ProcessMessage::eBreakpointMessage:
+ case ProcessMessage::eTraceMessage:
+ case ProcessMessage::eWatchpointMessage:
+ case ProcessMessage::eCrashMessage:
+ case ProcessMessage::eNewThreadMessage:
+ if (log)
+ log->Printf ("ProcessMonitor::%s(bp) handling message", __FUNCTION__);
+ // SendMessage will set the thread state as needed.
+ m_process->SendMessage(message);
+ // This isn't the stop we were expecting, but the thread is
+ // stopped. SendMessage will handle processing of this event,
+ // but we need to resume here to get the stop we are waiting
+ // for (otherwise the thread will stop again immediately when
+ // we try to resume).
+ if (wait_pid == tid)
+ Resume(wait_pid, eResumeSignalNone);
+ break;
+ }
+ }
+ return false;
+}
+
ProcessMessage::CrashReason
ProcessMonitor::GetCrashReasonForSIGSEGV(const siginfo_t *info)
{
@@ -1808,8 +1998,15 @@ bool
ProcessMonitor::Resume(lldb::tid_t tid, uint32_t signo)
{
bool result;
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("ProcessMonitor::%s() resuming thread = %" PRIu64 " with signal %s", __FUNCTION__, tid,
+ m_process->GetUnixSignals().GetSignalAsCString (signo));
ResumeOperation op(tid, signo, result);
DoOperation(&op);
+ if (log)
+ log->Printf ("ProcessMonitor::%s() resuming result = %s", __FUNCTION__, result ? "true" : "false");
return result;
}
OpenPOWER on IntegriCloud