diff options
| author | Robert O'Callahan <rocallahan@google.com> | 2025-01-22 20:37:17 +1300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-01-22 08:37:17 +0100 |
| commit | b7b9ccf44988edf49886743ae5c3cf4184db211f (patch) | |
| tree | 23a42c4f7287081feb4b958f53c1a7f9f49e9d08 /lldb/source/Target/ThreadList.cpp | |
| parent | 830bd0e8f263c6efcfd37f38cc621b0476582b83 (diff) | |
[lldb] Implement basic support for reverse-continue (#112079)
This commit adds support for a
`SBProcess::ContinueInDirection()` API. A user-accessible command for
this will follow in a later commit.
This feature depends on a gdbserver implementation (e.g. `rr`) providing
support for the `bc` and `bs` packets. `lldb-server` does not support
those packets, and there is no plan to change that. For testing
purposes, this commit adds a Python implementation of *very limited*
record-and-reverse-execute functionality, implemented as a proxy between
lldb and lldb-server in `lldbreverse.py`. This should not (and in
practice cannot) be used for anything except testing.
The tests here are quite minimal but we test that simple breakpoints and
watchpoints work as expected during reverse execution, and that
conditional breakpoints and watchpoints work when the condition calls a
function that must be executed in the forward direction.
Diffstat (limited to 'lldb/source/Target/ThreadList.cpp')
| -rw-r--r-- | lldb/source/Target/ThreadList.cpp | 32 |
1 files changed, 29 insertions, 3 deletions
diff --git a/lldb/source/Target/ThreadList.cpp b/lldb/source/Target/ThreadList.cpp index 6cbef330bf48..99e2c1204146 100644 --- a/lldb/source/Target/ThreadList.cpp +++ b/lldb/source/Target/ThreadList.cpp @@ -508,7 +508,7 @@ void ThreadList::DiscardThreadPlans() { (*pos)->DiscardThreadPlans(true); } -bool ThreadList::WillResume() { +bool ThreadList::WillResume(RunDirection &direction) { // Run through the threads and perform their momentary actions. But we only // do this for threads that are running, user suspended threads stay where // they are. @@ -566,6 +566,12 @@ bool ThreadList::WillResume() { } } + if (thread_to_run != nullptr) { + direction = thread_to_run->GetCurrentPlan()->GetDirection(); + } else { + direction = m_process.GetBaseDirection(); + } + // Give all the threads that are likely to run a last chance to set up their // state before we negotiate who is actually going to get a chance to run... // Don't set to resume suspended threads, and if any thread wanted to stop @@ -577,7 +583,12 @@ bool ThreadList::WillResume() { // "StopOthers" plans which would then get to be part of the who-gets-to-run // negotiation, but they're coming in after the fact, and the threads that // are already set up should take priority. - thread_to_run->SetupForResume(); + if (thread_to_run->SetupToStepOverBreakpointIfNeeded(direction)) { + // We only need to step over breakpoints when running forward, and the + // step-over-breakpoint plan itself wants to run forward, so this + // keeps our desired direction. + assert(thread_to_run->GetCurrentPlan()->GetDirection() == direction); + } } else { for (pos = m_threads.begin(); pos != end; ++pos) { ThreadSP thread_sp(*pos); @@ -585,7 +596,11 @@ bool ThreadList::WillResume() { if (thread_sp->IsOperatingSystemPluginThread() && !thread_sp->GetBackingThread()) continue; - if (thread_sp->SetupForResume()) { + if (thread_sp->SetupToStepOverBreakpointIfNeeded(direction)) { + // We only need to step over breakpoints when running forward, and the + // step-over-breakpoint plan itself wants to run forward, so this + // keeps our desired direction. + assert(thread_sp->GetCurrentPlan()->GetDirection() == direction); // You can't say "stop others" and also want yourself to be suspended. assert(thread_sp->GetCurrentPlan()->RunState() != eStateSuspended); thread_to_run = thread_sp; @@ -626,6 +641,17 @@ bool ThreadList::WillResume() { if (!thread_sp->ShouldResume(run_state)) need_to_resume = false; } + if (need_to_resume) { + // Ensure all threads are running in the right direction + for (pos = m_threads.begin(); pos != end; ++pos) { + ThreadSP thread_sp(*pos); + while (thread_sp->GetCurrentPlan()->GetDirection() != direction) { + // This can't discard the base plan because its direction is + // m_process.GetBaseDirection() i.e. `direction`. + thread_sp->DiscardPlan(); + } + } + } } else { for (pos = m_threads.begin(); pos != end; ++pos) { ThreadSP thread_sp(*pos); |
