summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins')
-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
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp6
5 files changed, 229 insertions, 42 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 ();
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
index bb3b32d3c10..e3aadf1bc25 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
@@ -3396,10 +3396,8 @@ GDBRemoteCommunicationServer::Handle_interrupt (StringExtractorGDBRemote &packet
return SendErrorResponse (0x15);
}
- // Build the ResumeActionList - stop everything.
- lldb_private::ResumeActionList actions (StateType::eStateStopped, 0);
-
- Error error = m_debugged_process_sp->Resume (actions);
+ // Interrupt the process.
+ Error error = m_debugged_process_sp->Interrupt ();
if (error.Fail ())
{
if (log)
OpenPOWER on IntegriCloud