summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/Linux
diff options
context:
space:
mode:
authorTodd Fiala <todd.fiala@gmail.com>2014-09-11 23:29:14 +0000
committerTodd Fiala <todd.fiala@gmail.com>2014-09-11 23:29:14 +0000
commit511e5cdce4020e221d3a8609492004e908ccfc1a (patch)
tree3eb6c795c832cc84797dac0c63a87955458e97d4 /lldb/source/Plugins/Process/Linux
parent3d7260e7b21b6630ac42e1838c582a84c57e8a95 (diff)
downloadbcm5719-llvm-511e5cdce4020e221d3a8609492004e908ccfc1a.tar.gz
bcm5719-llvm-511e5cdce4020e221d3a8609492004e908ccfc1a.zip
llgs: fix Ctrl-C inferior interrupt handling to do the right thing.
* Sends a SIGSTOP to the process. * Fixes busted SIGSTOP handling. Now builds a list of non-stopped that we wait for the PTRACE group-stop for. When the final must-stop tid gets its group stop, we propagate the process state change. Only the signal receiving the notification of the pending SIGSTOP is marked with the SIGSTOP signal. All the rest, if they weren't already stopped, are marked as stopped with signal 0. * Fixes a few broken tests. * Marks the Linux test I added earlier as expect-pass (no longer XFAIL). Implements fix for http://llvm.org/bugs/show_bug.cgi?id=20908. llvm-svn: 217647
Diffstat (limited to 'lldb/source/Plugins/Process/Linux')
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp224
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeProcessLinux.h16
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp19
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeThreadLinux.h6
4 files changed, 227 insertions, 38 deletions
diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
index 1bfeb54c3da..5de973196de 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -1216,6 +1216,10 @@ NativeProcessLinux::NativeProcessLinux () :
m_operation_done (),
m_wait_for_stop_tids (),
m_wait_for_stop_tids_mutex (),
+ m_wait_for_group_stop_tids (),
+ m_group_stop_signal_tid (LLDB_INVALID_THREAD_ID),
+ m_group_stop_signal (LLDB_INVALID_SIGNAL_NUMBER),
+ m_wait_for_group_stop_tids_mutex (),
m_supports_mem_region (eLazyBoolCalculate),
m_mem_region_cache (),
m_mem_region_cache_mutex ()
@@ -1495,7 +1499,7 @@ NativeProcessLinux::Launch(LaunchArgs *args)
if (log)
{
const int error_code = errno;
- log->Printf ("NativeProcessLinux::%s inferior setpgid() failed, errno=%d (%s), continuing with existing proccess group %" PRIu64,
+ log->Printf ("NativeProcessLinux::%s inferior setpgid() failed, errno=%d (%s), continuing with existing process group %" PRIu64,
__FUNCTION__,
error_code,
strerror (error_code),
@@ -1949,32 +1953,7 @@ NativeProcessLinux::MonitorCallback(void *callback_baton,
{
if (ptrace_err == EINVAL)
{
- // This is the first part of the Linux ptrace group-stop mechanism.
- // (The other thing it can conceivably be is a call on a pid that no
- // longer exists for some reason).
- // The tracer (i.e. NativeProcessLinux) is expected to inject the signal
- // into the tracee (i.e. inferior) at this point.
- if (log)
- log->Printf ("NativeProcessLinux::%s resuming from group-stop", __FUNCTION__);
-
- // The inferior process is in 'group-stop', so deliver the stopping signal.
- const bool signal_delivered = process->Resume (pid, info.si_signo);
- if (log)
- log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " group-stop signal delivery of signal 0x%x (%s) - %s", __FUNCTION__, pid, info.si_signo, GetUnixSignals ().GetSignalAsCString (info.si_signo), signal_delivered ? "success" : "failed");
-
- if (signal_delivered)
- {
- // All is well.
- stop_monitoring = false;
- }
- else
- {
- if (log)
- log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " something looks horribly wrong - like the process we're monitoring died. Stop monitoring it.", __FUNCTION__, pid);
-
- // Stop monitoring now.
- return true;
- }
+ process->OnGroupStop (pid);
}
else
{
@@ -2061,12 +2040,12 @@ NativeProcessLinux::MonitorSIGTRAP(const siginfo_t *info, lldb::pid_t pid)
// If we don't track the thread yet: create it, mark as stopped.
// If we do track it, this is the wait we needed. Now resume the new thread.
// In all cases, resume the current (i.e. main process) thread.
- bool already_tracked = false;
- thread_sp = GetOrCreateThread (tid, already_tracked);
+ bool created_now = false;
+ thread_sp = GetOrCreateThread (tid, created_now);
assert (thread_sp.get() && "failed to get or create the tracking data for newly created inferior thread");
// If the thread was already tracked, it means the created thread already received its SI_USER notification of creation.
- if (already_tracked)
+ if (!created_now)
{
// FIXME loops like we want to stop all theads here.
// StopAllThreads
@@ -2275,7 +2254,12 @@ NativeProcessLinux::MonitorSIGTRAP(const siginfo_t *info, lldb::pid_t pid)
void
NativeProcessLinux::MonitorSignal(const siginfo_t *info, lldb::pid_t pid, bool exited)
{
- int signo = info->si_signo;
+ assert (info && "null info");
+ if (!info)
+ return;
+
+ const int signo = info->si_signo;
+ const bool is_from_llgs = info->si_pid == getpid ();
Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
@@ -2306,7 +2290,7 @@ NativeProcessLinux::MonitorSignal(const siginfo_t *info, lldb::pid_t pid, bool e
signo,
(info->si_code == SI_TKILL ? "SI_TKILL" : "SI_USER"),
info->si_pid,
- (info->si_pid == getpid ()) ? "is monitor" : "is not monitor",
+ is_from_llgs ? "from llgs" : "not from llgs",
pid);
}
@@ -2320,12 +2304,12 @@ NativeProcessLinux::MonitorSignal(const siginfo_t *info, lldb::pid_t pid, bool e
__FUNCTION__, GetID (), pid);
// Did we already create the thread?
- bool already_tracked = false;
- thread_sp = GetOrCreateThread (pid, already_tracked);
+ bool created_now = false;
+ thread_sp = GetOrCreateThread (pid, created_now);
assert (thread_sp.get() && "failed to get or create the tracking data for newly created inferior thread");
// If the thread was already tracked, it means the main thread already received its SIGTRAP for the create.
- if (already_tracked)
+ if (!created_now)
{
// We can now resume this thread up since it is fully created.
reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetRunning ();
@@ -2343,7 +2327,7 @@ NativeProcessLinux::MonitorSignal(const siginfo_t *info, lldb::pid_t pid, bool e
}
// Check for thread stop notification.
- if ((info->si_pid == getpid ()) && (info->si_code == SI_TKILL) && (signo == SIGSTOP))
+ if (is_from_llgs && (info->si_code == SI_TKILL) && (signo == SIGSTOP))
{
// This is a tgkill()-based stop.
if (thread_sp)
@@ -2451,13 +2435,177 @@ NativeProcessLinux::MonitorSignal(const siginfo_t *info, lldb::pid_t pid, bool e
}
break;
+ case SIGSTOP:
+ {
+ if (log)
+ {
+ if (is_from_llgs)
+ log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " received SIGSTOP from llgs, most likely an interrupt", __FUNCTION__, GetID (), pid);
+ else
+ log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " received SIGSTOP from outside of debugger", __FUNCTION__, GetID (), pid);
+ }
+
+ // Save group stop tids to wait for.
+ SetGroupStopTids (pid, SIGSTOP);
+ // Fall through to deliver signal to thread.
+ // This will trigger a group stop sequence, after which we'll notify the process that everything stopped.
+ }
+
default:
- if (log)
- log->Printf ("NativeProcessLinux::%s unhandled signal %s (%d)", __FUNCTION__, GetUnixSignals ().GetSignalAsCString (signo), signo);
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " resuming thread with signal %s (%d)", __FUNCTION__, GetID (), pid, GetUnixSignals().GetSignalAsCString (signo), signo);
+
+ // Pass the signal on to the inferior.
+ const bool resume_success = Resume (pid, signo);
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " resume %s", __FUNCTION__, GetID (), pid, resume_success ? "SUCCESS" : "FAILURE");
+
+ }
break;
}
}
+void
+NativeProcessLinux::SetGroupStopTids (lldb::tid_t signaled_thread_tid, int signo)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+ // Lock 1 - thread lock.
+ {
+ Mutex::Locker locker (m_threads_mutex);
+ // Lock 2 - group stop tids
+ {
+ Mutex::Locker locker (m_wait_for_group_stop_tids_mutex);
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " loading up known threads in set%s",
+ __FUNCTION__,
+ GetID (),
+ signaled_thread_tid,
+ m_wait_for_group_stop_tids.empty () ? " (currently empty)"
+ : "(group_stop_tids not empty?!?)");
+
+ // Add all known threads not already stopped into the wait for group-stop tids.
+ for (auto thread_sp : m_threads)
+ {
+ int unused_signo = LLDB_INVALID_SIGNAL_NUMBER;
+ if (thread_sp && !((NativeThreadLinux*)thread_sp.get())->IsStopped (&unused_signo))
+ {
+ // Wait on this thread for a group stop before we notify the delegate about the process state change.
+ m_wait_for_group_stop_tids.insert (thread_sp->GetID ());
+ }
+ }
+
+ m_group_stop_signal_tid = signaled_thread_tid;
+ m_group_stop_signal = signo;
+ }
+ }
+}
+
+void
+NativeProcessLinux::OnGroupStop (lldb::tid_t tid)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ bool should_tell_delegate = false;
+
+ // Lock 1 - thread lock.
+ {
+ Mutex::Locker locker (m_threads_mutex);
+ // Lock 2 - group stop tids
+ {
+ Mutex::Locker locker (m_wait_for_group_stop_tids_mutex);
+
+ // Remove this thread from the set.
+ auto remove_result = m_wait_for_group_stop_tids.erase (tid);
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " tried to remove tid from group-stop set: %s",
+ __FUNCTION__,
+ GetID (),
+ tid,
+ remove_result > 0 ? "SUCCESS" : "FAILURE");
+
+ // Grab the thread metadata for this thread.
+ NativeThreadProtocolSP thread_sp = GetThreadByIDUnlocked (tid);
+ if (thread_sp)
+ {
+ NativeThreadLinux *const linux_thread = static_cast<NativeThreadLinux*> (thread_sp.get ());
+ if (thread_sp->GetID () == m_group_stop_signal_tid)
+ {
+ linux_thread->SetStoppedBySignal (m_group_stop_signal);
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " set group stop tid to state 'stopped by signal %d'",
+ __FUNCTION__,
+ GetID (),
+ tid,
+ m_group_stop_signal);
+ }
+ else
+ {
+ int stopping_signal = LLDB_INVALID_SIGNAL_NUMBER;
+ if (linux_thread->IsStopped (&stopping_signal))
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " thread is already stopped with signal %d, not clearing",
+ __FUNCTION__,
+ GetID (),
+ tid,
+ stopping_signal);
+
+ }
+ else
+ {
+ linux_thread->SetStoppedBySignal (0);
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " set stopped by signal with signal 0 (i.e. debugger-initiated stop)",
+ __FUNCTION__,
+ GetID (),
+ tid);
+
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " WARNING failed to find thread metadata for tid",
+ __FUNCTION__,
+ GetID (),
+ tid);
+
+ }
+
+ // If there are no more threads we're waiting on for group stop, signal the process.
+ if (m_wait_for_group_stop_tids.empty ())
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " done waiting for group stop, will notify delegate of process state change",
+ __FUNCTION__,
+ GetID (),
+ tid);
+
+ SetCurrentThreadID (m_group_stop_signal_tid);
+
+ // Tell the delegate about the stop event, after we release our mutexes.
+ should_tell_delegate = true;
+ }
+ }
+ }
+
+ // If we're ready to broadcast the process event change, do it now that we're no longer
+ // holding any locks. Note this does introduce a potential race, we should think about
+ // adding a notification queue.
+ if (should_tell_delegate)
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " done waiting for group stop, notifying delegate of process state change",
+ __FUNCTION__,
+ GetID (),
+ tid);
+ SetState (StateType::eStateStopped, true);
+ }
+}
+
Error
NativeProcessLinux::Resume (const ResumeActionList &resume_actions)
{
diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
index c94a78bd2ea..a13570f63ef 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
@@ -189,6 +189,11 @@ namespace lldb_private
std::unordered_set<lldb::tid_t> m_wait_for_stop_tids;
lldb_private::Mutex m_wait_for_stop_tids_mutex;
+ std::unordered_set<lldb::tid_t> m_wait_for_group_stop_tids;
+ lldb::tid_t m_group_stop_signal_tid;
+ int m_group_stop_signal;
+ lldb_private::Mutex m_wait_for_group_stop_tids_mutex;
+
lldb_private::LazyBool m_supports_mem_region;
std::vector<MemoryRegionInfo> m_mem_region_cache;
lldb_private::Mutex m_mem_region_cache_mutex;
@@ -375,6 +380,17 @@ namespace lldb_private
bool
SingleStep(lldb::tid_t tid, uint32_t signo);
+ /// Safely mark all existing threads as waiting for group stop.
+ /// When the final group stop comes in from the set of group stop threads,
+ /// we'll mark the current thread as signaled_thread_tid and set its stop
+ /// reason as the given signo. All other threads from group stop notification
+ /// will have thread stop reason marked as signaled with no signo.
+ void
+ SetGroupStopTids (lldb::tid_t signaled_thread_tid, int signo);
+
+ void
+ OnGroupStop (lldb::tid_t tid);
+
lldb_private::Error
Detach(lldb::tid_t tid);
};
diff --git a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
index 8e010a55d85..4158e3d1e14 100644
--- a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
@@ -259,6 +259,25 @@ NativeThreadLinux::SetStoppedBySignal (uint32_t signo)
m_stop_info.details.signal.signo = signo;
}
+bool
+NativeThreadLinux::IsStopped (int *signo)
+{
+ if (!StateIsStoppedState (m_state, false))
+ return false;
+
+ // If we are stopped by a signal, return the signo.
+ if (signo &&
+ m_state == StateType::eStateStopped &&
+ m_stop_info.reason == StopReason::eStopReasonSignal)
+ {
+ *signo = m_stop_info.details.signal.signo;
+ }
+
+ // Regardless, we are stopped.
+ return true;
+}
+
+
void
NativeThreadLinux::SetStoppedByExec ()
{
diff --git a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
index bed530dbe9f..8a042f22b22 100644
--- a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
+++ b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
@@ -64,6 +64,12 @@ namespace lldb_private
void
SetStoppedBySignal (uint32_t signo);
+ /// Return true if the thread is stopped.
+ /// If stopped by a signal, indicate the signo in the signo argument.
+ /// Otherwise, return LLDB_INVALID_SIGNAL_NUMBER.
+ bool
+ IsStopped (int *signo);
+
void
SetStoppedByExec ();
OpenPOWER on IntegriCloud