diff options
| author | jimingham <jingham@apple.com> | 2025-05-01 13:46:19 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-05-01 13:46:19 -0700 |
| commit | 4fdb8cb42f73ebec9a3bdd37b2f27c222f9afd87 (patch) | |
| tree | 2aa248832488e93bb90af39a49417a4099ec0598 /lldb/source/Target/Target.cpp | |
| parent | 42f5d716cbb8b391203eb880ac81f6272fd611f1 (diff) | |
Make stop-hooks fire when lldb first gains control of a process. (#137410)
stop-hooks are supposed to trigger every time the process stops, but as
initially implemented they would only fire when control was returned to
the user. So for instance when a process was launched the stop hook
would only trigger when the process hit a breakpoint or crashed.
However, it would be really useful to be able to trigger a stop hook
when lldb first gains control over the process. One way to do that would
be to implement general "target lifecycle events" and then send process
created events that users could bind actions to.
OTOH, extending the stop hooks to fire when lldb first gains control
over the process is a pretty natural extension to the notion of a stop
hook. So this patch takes the shorter route to that ability by making
stop-hooks fire when lldb first gains control over the process.
I also added the ability to specify whether to trigger the stop hook "on
gaining control". I'm on the fence about whether to set the default to
be "trigger on gaining control" or "don't trigger on gaining control".
Since I think it's a generally useful feature, I've set the default to
"trigger on gaining control".
Diffstat (limited to 'lldb/source/Target/Target.cpp')
| -rw-r--r-- | lldb/source/Target/Target.cpp | 38 |
1 files changed, 33 insertions, 5 deletions
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 0fa61b20e19b..e90e748191a7 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -3038,7 +3038,7 @@ void Target::SetAllStopHooksActiveState(bool active_state) { } } -bool Target::RunStopHooks() { +bool Target::RunStopHooks(bool at_initial_stop) { if (m_suppress_stop_hooks) return false; @@ -3047,14 +3047,19 @@ bool Target::RunStopHooks() { // Somebody might have restarted the process: // Still return false, the return value is about US restarting the target. - if (m_process_sp->GetState() != eStateStopped) + lldb::StateType state = m_process_sp->GetState(); + if (!(state == eStateStopped || state == eStateAttaching)) return false; if (m_stop_hooks.empty()) return false; bool no_active_hooks = - llvm::none_of(m_stop_hooks, [](auto &p) { return p.second->IsActive(); }); + llvm::none_of(m_stop_hooks, [at_initial_stop](auto &p) { + bool should_run_now = + !at_initial_stop || p.second->GetRunAtInitialStop(); + return p.second->IsActive() && should_run_now; + }); if (no_active_hooks) return false; @@ -3084,9 +3089,22 @@ bool Target::RunStopHooks() { } // If no threads stopped for a reason, don't run the stop-hooks. + // However, if this is the FIRST stop for this process, then we are in the + // state where an attach or a core file load was completed without designating + // a particular thread as responsible for the stop. In that case, we do + // want to run the stop hooks, but do so just on one thread. size_t num_exe_ctx = exc_ctx_with_reasons.size(); - if (num_exe_ctx == 0) - return false; + if (num_exe_ctx == 0) { + if (at_initial_stop && num_threads > 0) { + lldb::ThreadSP thread_to_use_sp = cur_threadlist.GetThreadAtIndex(0); + exc_ctx_with_reasons.emplace_back( + m_process_sp.get(), thread_to_use_sp.get(), + thread_to_use_sp->GetStackFrameAtIndex(0).get()); + num_exe_ctx = 1; + } else { + return false; + } + } StreamSP output_sp = m_debugger.GetAsyncOutputStream(); auto on_exit = llvm::make_scope_exit([output_sp] { output_sp->Flush(); }); @@ -3100,6 +3118,8 @@ bool Target::RunStopHooks() { StopHookSP cur_hook_sp = stop_entry.second; if (!cur_hook_sp->IsActive()) continue; + if (at_initial_stop && !cur_hook_sp->GetRunAtInitialStop()) + continue; bool any_thread_matched = false; for (auto exc_ctx : exc_ctx_with_reasons) { @@ -3426,10 +3446,14 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) { m_process_sp->RestoreProcessEvents(); if (rebroadcast_first_stop) { + // We don't need to run the stop hooks by hand here, they will get + // triggered when this rebroadcast event gets fetched. assert(first_stop_event_sp); m_process_sp->BroadcastEvent(first_stop_event_sp); return error; } + // Run the stop hooks that want to run at entry. + RunStopHooks(true /* at entry point */); switch (state) { case eStateStopped: { @@ -3582,6 +3606,10 @@ Status Target::Attach(ProcessAttachInfo &attach_info, Stream *stream) { true, SelectMostRelevantFrame); process_sp->RestoreProcessEvents(); + // Run the stop hooks here. Since we were hijacking the events, they + // wouldn't have gotten run as part of event delivery. + RunStopHooks(/* at_initial_stop= */ true); + if (state != eStateStopped) { const char *exit_desc = process_sp->GetExitDescription(); if (exit_desc) |
