diff options
Diffstat (limited to 'lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp')
-rw-r--r-- | lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp | 209 |
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; } |