[Lldb-commits] [lldb] [lldb] Rework how we pass the execution context to the statusline (PR #159887)
Jonas Devlieghere via lldb-commits
lldb-commits at lists.llvm.org
Tue Sep 23 11:32:44 PDT 2025
https://github.com/JDevlieghere updated https://github.com/llvm/llvm-project/pull/159887
>From 4fe7308f3caf0449d9ee03dbf3969cffc867e969 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Fri, 19 Sep 2025 21:37:05 +0000
Subject: [PATCH 1/3] [lldb] Rework how we pass the execution context to the
statusline
Currently, we always pass the "selected" execution context to the
statusline. When handling a process or thread event, we can be more
precise, and build an execution context from the event data.
---
lldb/include/lldb/Core/Debugger.h | 13 +++++--
lldb/include/lldb/Core/Statusline.h | 17 ++++++---
lldb/source/Core/Debugger.cpp | 56 ++++++++++++++++++----------
lldb/source/Core/IOHandler.cpp | 2 +-
lldb/source/Core/Statusline.cpp | 57 +++++++++++++----------------
5 files changed, 85 insertions(+), 60 deletions(-)
diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h
index 250ad64b76d9a..5fe96f759607b 100644
--- a/lldb/include/lldb/Core/Debugger.h
+++ b/lldb/include/lldb/Core/Debugger.h
@@ -181,7 +181,14 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
return m_target_list.GetSelectedTarget();
}
+ /// Get the execution context for the selected target.
ExecutionContext GetSelectedExecutionContext();
+
+ /// Similar to GetSelectedExecutionContext but returns a
+ /// ExecutionContextRef, and will hold the dummy target if no target is
+ /// currently selected.
+ ExecutionContextRef GetSelectedExecutionContextRef();
+
/// Get accessor for the target list.
///
/// The target list is part of the global debugger object. This the single
@@ -419,7 +426,7 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
void CancelInterruptRequest();
/// Redraw the statusline if enabled.
- void RedrawStatusline(bool update = true);
+ void RedrawStatusline(std::optional<ExecutionContextRef> exe_ctx_ref);
/// This is the correct way to query the state of Interruption.
/// If you are on the RunCommandInterpreter thread, it will check the
@@ -701,9 +708,9 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
void HandleBreakpointEvent(const lldb::EventSP &event_sp);
- void HandleProcessEvent(const lldb::EventSP &event_sp);
+ lldb::ProcessSP HandleProcessEvent(const lldb::EventSP &event_sp);
- void HandleThreadEvent(const lldb::EventSP &event_sp);
+ lldb::ThreadSP HandleThreadEvent(const lldb::EventSP &event_sp);
void HandleProgressEvent(const lldb::EventSP &event_sp);
diff --git a/lldb/include/lldb/Core/Statusline.h b/lldb/include/lldb/Core/Statusline.h
index 6bda153f822d2..a5ab1927b57f5 100644
--- a/lldb/include/lldb/Core/Statusline.h
+++ b/lldb/include/lldb/Core/Statusline.h
@@ -9,6 +9,8 @@
#ifndef LLDB_CORE_STATUSLINE_H
#define LLDB_CORE_STATUSLINE_H
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/ExecutionContext.h"
#include "lldb/lldb-forward.h"
#include <cstdint>
#include <string>
@@ -19,15 +21,16 @@ class Statusline {
Statusline(Debugger &debugger);
~Statusline();
+ using Context = std::pair<ExecutionContextRef, SymbolContext>;
+
/// Reduce the scroll window and draw the statusline.
- void Enable();
+ void Enable(std::optional<ExecutionContextRef> exe_ctx_ref);
/// Hide the statusline and extend the scroll window.
void Disable();
- /// Redraw the statusline. If update is false, this will redraw the last
- /// string.
- void Redraw(bool update = true);
+ /// Redraw the statusline.
+ void Redraw(std::optional<ExecutionContextRef> exe_ctx_ref);
/// Inform the statusline that the terminal dimensions have changed.
void TerminalSizeChanged();
@@ -46,7 +49,11 @@ class Statusline {
void UpdateScrollWindow(ScrollWindowMode mode);
Debugger &m_debugger;
- std::string m_last_str;
+
+ /// Cached copy of the execution context that allows us to redraw the
+ /// statusline.
+ ExecutionContextRef m_exe_ctx_ref;
+
uint64_t m_terminal_width = 0;
uint64_t m_terminal_height = 0;
};
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp
index ed674ee1275c7..c761d39d40030 100644
--- a/lldb/source/Core/Debugger.cpp
+++ b/lldb/source/Core/Debugger.cpp
@@ -253,16 +253,18 @@ Status Debugger::SetPropertyValue(const ExecutionContext *exe_ctx,
// Statusline setting changed. If we have a statusline instance, update it
// now. Otherwise it will get created in the default event handler.
std::lock_guard<std::mutex> guard(m_statusline_mutex);
- if (StatuslineSupported())
+ if (StatuslineSupported()) {
m_statusline.emplace(*this);
- else
+ m_statusline->Enable(GetSelectedExecutionContextRef());
+ } else {
m_statusline.reset();
+ }
} else if (property_path ==
g_debugger_properties[ePropertyStatuslineFormat].name ||
property_path ==
g_debugger_properties[ePropertySeparator].name) {
// Statusline format changed. Redraw the statusline.
- RedrawStatusline();
+ RedrawStatusline(std::nullopt);
} else if (property_path ==
g_debugger_properties[ePropertyUseSourceCache].name) {
// use-source-cache changed. Wipe out the cache contents if it was
@@ -501,7 +503,7 @@ FormatEntity::Entry Debugger::GetStatuslineFormat() const {
bool Debugger::SetStatuslineFormat(const FormatEntity::Entry &format) {
constexpr uint32_t idx = ePropertyStatuslineFormat;
bool ret = SetPropertyAtIndex(idx, format);
- RedrawStatusline();
+ RedrawStatusline(std::nullopt);
return ret;
}
@@ -526,7 +528,7 @@ llvm::StringRef Debugger::GetDisabledAnsiSuffix() const {
bool Debugger::SetSeparator(llvm::StringRef s) {
constexpr uint32_t idx = ePropertySeparator;
bool ret = SetPropertyAtIndex(idx, s);
- RedrawStatusline();
+ RedrawStatusline(std::nullopt);
return ret;
}
@@ -1210,14 +1212,18 @@ void Debugger::RestoreInputTerminalState() {
{
std::lock_guard<std::mutex> guard(m_statusline_mutex);
if (m_statusline)
- m_statusline->Enable();
+ m_statusline->Enable(GetSelectedExecutionContext());
}
}
-void Debugger::RedrawStatusline(bool update) {
+void Debugger::RedrawStatusline(
+ std::optional<ExecutionContextRef> exe_ctx_ref) {
std::lock_guard<std::mutex> guard(m_statusline_mutex);
- if (m_statusline)
- m_statusline->Redraw(update);
+
+ if (!m_statusline)
+ return;
+
+ m_statusline->Redraw(GetSelectedExecutionContextRef());
}
ExecutionContext Debugger::GetSelectedExecutionContext() {
@@ -1226,6 +1232,13 @@ ExecutionContext Debugger::GetSelectedExecutionContext() {
return ExecutionContext(exe_ctx_ref);
}
+ExecutionContextRef Debugger::GetSelectedExecutionContextRef() {
+ if (TargetSP selected_target_sp = GetSelectedTarget())
+ return ExecutionContextRef(selected_target_sp.get(),
+ /*adopt_selected=*/true);
+ return ExecutionContextRef(m_dummy_target_sp.get(), /*adopt_selected=*/false);
+}
+
void Debugger::DispatchInputInterrupt() {
std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
IOHandlerSP reader_sp(m_io_handler_stack.Top());
@@ -1941,8 +1954,7 @@ void Debugger::FlushProcessOutput(Process &process, bool flush_stdout,
}
// This function handles events that were broadcast by the process.
-void Debugger::HandleProcessEvent(const EventSP &event_sp) {
- using namespace lldb;
+ProcessSP Debugger::HandleProcessEvent(const EventSP &event_sp) {
const uint32_t event_type = event_sp->GetType();
ProcessSP process_sp =
(event_type == Process::eBroadcastBitStructuredData)
@@ -2024,23 +2036,24 @@ void Debugger::HandleProcessEvent(const EventSP &event_sp) {
if (pop_process_io_handler)
process_sp->PopProcessIOHandler();
}
+ return process_sp;
}
-void Debugger::HandleThreadEvent(const EventSP &event_sp) {
+ThreadSP Debugger::HandleThreadEvent(const EventSP &event_sp) {
// At present the only thread event we handle is the Frame Changed event, and
// all we do for that is just reprint the thread status for that thread.
- using namespace lldb;
const uint32_t event_type = event_sp->GetType();
const bool stop_format = true;
+ ThreadSP thread_sp;
if (event_type == Thread::eBroadcastBitStackChanged ||
event_type == Thread::eBroadcastBitThreadSelected) {
- ThreadSP thread_sp(
- Thread::ThreadEventData::GetThreadFromEvent(event_sp.get()));
+ thread_sp = Thread::ThreadEventData::GetThreadFromEvent(event_sp.get());
if (thread_sp) {
thread_sp->GetStatus(*GetAsyncOutputStream(), 0, 1, 1, stop_format,
/*show_hidden*/ true);
}
}
+ return thread_sp;
}
bool Debugger::IsForwardingEvents() { return (bool)m_forward_listener_sp; }
@@ -2109,28 +2122,33 @@ lldb::thread_result_t Debugger::DefaultEventHandler() {
if (StatuslineSupported()) {
std::lock_guard<std::mutex> guard(m_statusline_mutex);
- if (!m_statusline)
+ if (!m_statusline) {
m_statusline.emplace(*this);
+ m_statusline->Enable(GetSelectedExecutionContextRef());
+ }
}
bool done = false;
while (!done) {
EventSP event_sp;
if (listener_sp->GetEvent(event_sp, std::nullopt)) {
+ std::optional<ExecutionContextRef> exe_ctx_ref = std::nullopt;
if (event_sp) {
Broadcaster *broadcaster = event_sp->GetBroadcaster();
if (broadcaster) {
uint32_t event_type = event_sp->GetType();
ConstString broadcaster_class(broadcaster->GetBroadcasterClass());
if (broadcaster_class == broadcaster_class_process) {
- HandleProcessEvent(event_sp);
+ if (ProcessSP process_sp = HandleProcessEvent(event_sp))
+ exe_ctx_ref = ExecutionContext(process_sp);
} else if (broadcaster_class == broadcaster_class_target) {
if (Breakpoint::BreakpointEventData::GetEventDataFromEvent(
event_sp.get())) {
HandleBreakpointEvent(event_sp);
}
} else if (broadcaster_class == broadcaster_class_thread) {
- HandleThreadEvent(event_sp);
+ if (ThreadSP thread_sp = HandleThreadEvent(event_sp))
+ exe_ctx_ref = ExecutionContext(thread_sp);
} else if (broadcaster == m_command_interpreter_up.get()) {
if (event_type &
CommandInterpreter::eBroadcastBitQuitCommandReceived) {
@@ -2168,7 +2186,7 @@ lldb::thread_result_t Debugger::DefaultEventHandler() {
if (m_forward_listener_sp)
m_forward_listener_sp->AddEvent(event_sp);
}
- RedrawStatusline();
+ RedrawStatusline(exe_ctx_ref);
}
}
diff --git a/lldb/source/Core/IOHandler.cpp b/lldb/source/Core/IOHandler.cpp
index f65a1113f3592..57819eeade6e8 100644
--- a/lldb/source/Core/IOHandler.cpp
+++ b/lldb/source/Core/IOHandler.cpp
@@ -442,7 +442,7 @@ void IOHandlerEditline::AutoCompleteCallback(CompletionRequest &request) {
}
void IOHandlerEditline::RedrawCallback() {
- m_debugger.RedrawStatusline(/*update=*/false);
+ m_debugger.RedrawStatusline(std::nullopt);
}
#endif
diff --git a/lldb/source/Core/Statusline.cpp b/lldb/source/Core/Statusline.cpp
index 393d427241021..d765bf852922c 100644
--- a/lldb/source/Core/Statusline.cpp
+++ b/lldb/source/Core/Statusline.cpp
@@ -35,9 +35,7 @@ using namespace lldb_private;
Statusline::Statusline(Debugger &debugger)
: m_debugger(debugger), m_terminal_width(m_debugger.GetTerminalWidth()),
- m_terminal_height(m_debugger.GetTerminalHeight()) {
- Enable();
-}
+ m_terminal_height(m_debugger.GetTerminalHeight()) {}
Statusline::~Statusline() { Disable(); }
@@ -47,16 +45,16 @@ void Statusline::TerminalSizeChanged() {
UpdateScrollWindow(ResizeStatusline);
- // Draw the old statusline.
- Redraw(/*update=*/false);
+ // Redraw the old statusline.
+ Redraw(std::nullopt);
}
-void Statusline::Enable() {
+void Statusline::Enable(std::optional<ExecutionContextRef> exe_ctx_ref) {
// Reduce the scroll window to make space for the status bar below.
UpdateScrollWindow(EnableStatusline);
// Draw the statusline.
- Redraw(/*update=*/true);
+ Redraw(exe_ctx_ref);
}
void Statusline::Disable() {
@@ -69,8 +67,6 @@ void Statusline::Draw(std::string str) {
if (!stream_sp)
return;
- m_last_str = str;
-
str = ansi::TrimAndPad(str, m_terminal_width);
LockedStreamFile locked_stream = stream_sp->Lock();
@@ -127,33 +123,30 @@ void Statusline::UpdateScrollWindow(ScrollWindowMode mode) {
m_debugger.RefreshIOHandler();
}
-void Statusline::Redraw(bool update) {
- if (!update) {
- Draw(m_last_str);
- return;
- }
-
- ExecutionContext exe_ctx = m_debugger.GetSelectedExecutionContext();
-
- // For colors and progress events, the format entity needs access to the
- // debugger, which requires a target in the execution context.
- if (!exe_ctx.HasTargetScope())
- exe_ctx.SetTargetPtr(&m_debugger.GetSelectedOrDummyTarget());
-
- SymbolContext symbol_ctx;
- if (ProcessSP process_sp = exe_ctx.GetProcessSP()) {
- // Check if the process is stopped, and if it is, make sure it remains
- // stopped until we've computed the symbol context.
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process_sp->GetRunLock())) {
- if (auto frame_sp = exe_ctx.GetFrameSP())
- symbol_ctx = frame_sp->GetSymbolContext(eSymbolContextEverything);
- }
+void Statusline::Redraw(std::optional<ExecutionContextRef> exe_ctx_ref) {
+ // Update the cached execution context.
+ if (exe_ctx_ref)
+ m_exe_ctx_ref = *exe_ctx_ref;
+
+ // Lock the execution context.
+ ExecutionContext exe_ctx =
+ m_exe_ctx_ref.Lock(/*thread_and_frame_only_if_stopped=*/true);
+
+ // Compute the symbol context if we're stopped.
+ SymbolContext sym_ctx;
+ llvm::Expected<StoppedExecutionContext> stopped_exe_ctx =
+ GetStoppedExecutionContext(&m_exe_ctx_ref);
+ if (stopped_exe_ctx) {
+ if (auto frame_sp = stopped_exe_ctx->GetFrameSP())
+ sym_ctx = frame_sp->GetSymbolContext(eSymbolContextEverything);
+ } else {
+ // We can draw the statusline without being stopped.
+ llvm::consumeError(stopped_exe_ctx.takeError());
}
StreamString stream;
FormatEntity::Entry format = m_debugger.GetStatuslineFormat();
- FormatEntity::Format(format, stream, &symbol_ctx, &exe_ctx, nullptr, nullptr,
+ FormatEntity::Format(format, stream, &sym_ctx, &exe_ctx, nullptr, nullptr,
false, false);
Draw(stream.GetString().str());
>From afdf9a700df198fc2394552445a72636cf26db71 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Mon, 22 Sep 2025 16:41:09 -0700
Subject: [PATCH 2/3] Address Jim's feedback
---
lldb/include/lldb/Core/Debugger.h | 3 +-
lldb/include/lldb/Target/ExecutionContext.h | 17 +++-
lldb/source/Core/Debugger.cpp | 8 +-
lldb/source/Core/Statusline.cpp | 2 +-
lldb/source/Target/ExecutionContext.cpp | 95 +++++++++++++--------
5 files changed, 80 insertions(+), 45 deletions(-)
diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h
index 5fe96f759607b..06136ed40471d 100644
--- a/lldb/include/lldb/Core/Debugger.h
+++ b/lldb/include/lldb/Core/Debugger.h
@@ -181,7 +181,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
return m_target_list.GetSelectedTarget();
}
- /// Get the execution context for the selected target.
+ /// Get the execution context representing the selected entities in the
+ /// selected target.
ExecutionContext GetSelectedExecutionContext();
/// Similar to GetSelectedExecutionContext but returns a
diff --git a/lldb/include/lldb/Target/ExecutionContext.h b/lldb/include/lldb/Target/ExecutionContext.h
index f105e38fa69aa..fe8bce7f69713 100644
--- a/lldb/include/lldb/Target/ExecutionContext.h
+++ b/lldb/include/lldb/Target/ExecutionContext.h
@@ -92,10 +92,21 @@ class ExecutionContextRef {
/// Construct using the target and all the selected items inside of it (the
/// process and its selected thread, and the thread's selected frame). If
- /// there is no selected thread, default to the first thread If there is no
+ /// there is no selected thread, default to the first thread. If there is no
/// selected frame, default to the first frame.
ExecutionContextRef(Target *target, bool adopt_selected);
+ /// Construct using the process and all the selected items inside of it (
+ /// the selected thread, and the thread's selected frame). If
+ /// there is no selected thread, default to the first thread. If there is no
+ /// selected frame, default to the first frame.
+ ExecutionContextRef(Process *process, bool adopt_selected);
+
+ /// Construct using the thread and all the selected items inside of it ( the
+ /// selected frame). If there is no selected frame, default to the first
+ /// frame.
+ ExecutionContextRef(Thread *thread, bool adopt_selected);
+
/// Construct using an execution context scope.
///
/// If the ExecutionContextScope object is valid and refers to a frame, make
@@ -199,9 +210,9 @@ class ExecutionContextRef {
void SetTargetPtr(Target *target, bool adopt_selected);
- void SetProcessPtr(Process *process);
+ void SetProcessPtr(Process *process, bool adopt_selected = false);
- void SetThreadPtr(Thread *thread);
+ void SetThreadPtr(Thread *thread, bool adopt_selected = false);
void SetFramePtr(StackFrame *frame);
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp
index c761d39d40030..c3273dd44ca5e 100644
--- a/lldb/source/Core/Debugger.cpp
+++ b/lldb/source/Core/Debugger.cpp
@@ -1223,7 +1223,7 @@ void Debugger::RedrawStatusline(
if (!m_statusline)
return;
- m_statusline->Redraw(GetSelectedExecutionContextRef());
+ m_statusline->Redraw(exe_ctx_ref);
}
ExecutionContext Debugger::GetSelectedExecutionContext() {
@@ -2140,7 +2140,8 @@ lldb::thread_result_t Debugger::DefaultEventHandler() {
ConstString broadcaster_class(broadcaster->GetBroadcasterClass());
if (broadcaster_class == broadcaster_class_process) {
if (ProcessSP process_sp = HandleProcessEvent(event_sp))
- exe_ctx_ref = ExecutionContext(process_sp);
+ exe_ctx_ref = ExecutionContextRef(process_sp.get(),
+ /*adopt_selected=*/true);
} else if (broadcaster_class == broadcaster_class_target) {
if (Breakpoint::BreakpointEventData::GetEventDataFromEvent(
event_sp.get())) {
@@ -2148,7 +2149,8 @@ lldb::thread_result_t Debugger::DefaultEventHandler() {
}
} else if (broadcaster_class == broadcaster_class_thread) {
if (ThreadSP thread_sp = HandleThreadEvent(event_sp))
- exe_ctx_ref = ExecutionContext(thread_sp);
+ exe_ctx_ref =
+ ExecutionContextRef(thread_sp.get(), /*adopt_selected=*/true);
} else if (broadcaster == m_command_interpreter_up.get()) {
if (event_type &
CommandInterpreter::eBroadcastBitQuitCommandReceived) {
diff --git a/lldb/source/Core/Statusline.cpp b/lldb/source/Core/Statusline.cpp
index d765bf852922c..09d48baae7193 100644
--- a/lldb/source/Core/Statusline.cpp
+++ b/lldb/source/Core/Statusline.cpp
@@ -130,7 +130,7 @@ void Statusline::Redraw(std::optional<ExecutionContextRef> exe_ctx_ref) {
// Lock the execution context.
ExecutionContext exe_ctx =
- m_exe_ctx_ref.Lock(/*thread_and_frame_only_if_stopped=*/true);
+ m_exe_ctx_ref.Lock(/*thread_and_frame_only_if_stopped=*/false);
// Compute the symbol context if we're stopped.
SymbolContext sym_ctx;
diff --git a/lldb/source/Target/ExecutionContext.cpp b/lldb/source/Target/ExecutionContext.cpp
index 9d232e420f71c..a795913047639 100644
--- a/lldb/source/Target/ExecutionContext.cpp
+++ b/lldb/source/Target/ExecutionContext.cpp
@@ -429,6 +429,16 @@ ExecutionContextRef::ExecutionContextRef(Target *target, bool adopt_selected)
SetTargetPtr(target, adopt_selected);
}
+ExecutionContextRef::ExecutionContextRef(Process *process, bool adopt_selected)
+ : m_target_wp(), m_process_wp(), m_thread_wp(), m_stack_id() {
+ SetProcessPtr(process, adopt_selected);
+}
+
+ExecutionContextRef::ExecutionContextRef(Thread *thread, bool adopt_selected)
+ : m_target_wp(), m_process_wp(), m_thread_wp(), m_stack_id() {
+ SetThreadPtr(thread, adopt_selected);
+}
+
ExecutionContextRef::ExecutionContextRef(const ExecutionContextRef &rhs)
= default;
@@ -513,55 +523,66 @@ void ExecutionContextRef::SetFrameSP(const lldb::StackFrameSP &frame_sp) {
void ExecutionContextRef::SetTargetPtr(Target *target, bool adopt_selected) {
Clear();
if (target) {
- lldb::TargetSP target_sp(target->shared_from_this());
- if (target_sp) {
- m_target_wp = target_sp;
- if (adopt_selected) {
- lldb::ProcessSP process_sp(target_sp->GetProcessSP());
- if (process_sp) {
- m_process_wp = process_sp;
- if (process_sp) {
- // Only fill in the thread and frame if our process is stopped
- // Don't just check the state, since we might be in the middle of
- // resuming.
- Process::StopLocker stop_locker;
-
- if (stop_locker.TryLock(&process_sp->GetRunLock()) &&
- StateIsStoppedState(process_sp->GetState(), true)) {
- lldb::ThreadSP thread_sp(
- process_sp->GetThreadList().GetSelectedThread());
- if (!thread_sp)
- thread_sp = process_sp->GetThreadList().GetThreadAtIndex(0);
-
- if (thread_sp) {
- SetThreadSP(thread_sp);
- lldb::StackFrameSP frame_sp(
- thread_sp->GetSelectedFrame(DoNoSelectMostRelevantFrame));
- if (!frame_sp)
- frame_sp = thread_sp->GetStackFrameAtIndex(0);
- if (frame_sp)
- SetFrameSP(frame_sp);
- }
- }
- }
- }
- }
+ lldb::TargetSP target_sp = target->shared_from_this();
+ SetTargetSP(target_sp);
+ if (adopt_selected) {
+ if (lldb::ProcessSP process_sp = target_sp->GetProcessSP())
+ SetProcessPtr(process_sp.get(), adopt_selected);
}
}
}
-void ExecutionContextRef::SetProcessPtr(Process *process) {
+void ExecutionContextRef::SetProcessPtr(Process *process, bool adopt_selected) {
if (process) {
- SetProcessSP(process->shared_from_this());
+ lldb::ProcessSP process_sp = process->shared_from_this();
+ SetProcessSP(process_sp);
+ if (adopt_selected) {
+ // Only fill in the thread if our process is stopped.
+ // Don't just check the state, since we might be in the middle of
+ // resuming.
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process_sp->GetRunLock()) &&
+ StateIsStoppedState(process_sp->GetState(), true)) {
+ lldb::ThreadSP thread_sp(
+ process_sp->GetThreadList().GetSelectedThread());
+ if (!thread_sp)
+ thread_sp = process_sp->GetThreadList().GetThreadAtIndex(0);
+ if (thread_sp) {
+ SetThreadSP(thread_sp);
+ lldb::StackFrameSP frame_sp =
+ thread_sp->GetSelectedFrame(DoNoSelectMostRelevantFrame);
+ if (!frame_sp)
+ frame_sp = thread_sp->GetStackFrameAtIndex(0);
+ if (frame_sp)
+ SetFrameSP(frame_sp);
+ }
+ }
+ }
} else {
m_process_wp.reset();
m_target_wp.reset();
}
}
-void ExecutionContextRef::SetThreadPtr(Thread *thread) {
+void ExecutionContextRef::SetThreadPtr(Thread *thread, bool adopt_selected) {
if (thread) {
- SetThreadSP(thread->shared_from_this());
+ lldb::ThreadSP thread_sp = thread->shared_from_this();
+ SetThreadSP(thread_sp);
+ if (adopt_selected) {
+ // Only fill in the frame if our process is stopped.
+ // Don't just check the state, since we might be in the middle of
+ // resuming.
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&thread->GetProcess()->GetRunLock()) &&
+ StateIsStoppedState(thread->GetProcess()->GetState(), true)) {
+ lldb::StackFrameSP frame_sp =
+ thread_sp->GetSelectedFrame(DoNoSelectMostRelevantFrame);
+ if (!frame_sp)
+ frame_sp = thread_sp->GetStackFrameAtIndex(0);
+ if (frame_sp)
+ SetFrameSP(frame_sp);
+ }
+ }
} else {
ClearThread();
m_process_wp.reset();
>From 06817bbb3e27ba333fca93a32b37fc50d0f1d16d Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Tue, 23 Sep 2025 18:32:27 +0000
Subject: [PATCH 3/3] Add workaround for issue #160216
---
lldb/source/Core/Debugger.cpp | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp
index c3273dd44ca5e..568cd9d3d03b6 100644
--- a/lldb/source/Core/Debugger.cpp
+++ b/lldb/source/Core/Debugger.cpp
@@ -2081,6 +2081,11 @@ bool Debugger::StatuslineSupported() {
return false;
}
+static bool RequiresFollowChildWorkaround(const Process &process) {
+ // FIXME: https://github.com/llvm/llvm-project/issues/160216
+ return process.GetFollowForkMode() == eFollowChild;
+}
+
lldb::thread_result_t Debugger::DefaultEventHandler() {
ListenerSP listener_sp(GetListener());
ConstString broadcaster_class_target(Target::GetStaticBroadcasterClass());
@@ -2140,8 +2145,9 @@ lldb::thread_result_t Debugger::DefaultEventHandler() {
ConstString broadcaster_class(broadcaster->GetBroadcasterClass());
if (broadcaster_class == broadcaster_class_process) {
if (ProcessSP process_sp = HandleProcessEvent(event_sp))
- exe_ctx_ref = ExecutionContextRef(process_sp.get(),
- /*adopt_selected=*/true);
+ if (!RequiresFollowChildWorkaround(*process_sp))
+ exe_ctx_ref = ExecutionContextRef(process_sp.get(),
+ /*adopt_selected=*/true);
} else if (broadcaster_class == broadcaster_class_target) {
if (Breakpoint::BreakpointEventData::GetEventDataFromEvent(
event_sp.get())) {
@@ -2149,8 +2155,9 @@ lldb::thread_result_t Debugger::DefaultEventHandler() {
}
} else if (broadcaster_class == broadcaster_class_thread) {
if (ThreadSP thread_sp = HandleThreadEvent(event_sp))
- exe_ctx_ref =
- ExecutionContextRef(thread_sp.get(), /*adopt_selected=*/true);
+ if (!RequiresFollowChildWorkaround(*thread_sp->GetProcess()))
+ exe_ctx_ref = ExecutionContextRef(thread_sp.get(),
+ /*adopt_selected=*/true);
} else if (broadcaster == m_command_interpreter_up.get()) {
if (event_type &
CommandInterpreter::eBroadcastBitQuitCommandReceived) {
More information about the lldb-commits
mailing list