Skip to content

[lldb] Always compute the execution & symbol context #148994

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

JDevlieghere
Copy link
Member

Always compute the execution and symbol context, regardless of whether the statusline is enabled. This code gets called from the default event handler thread and has uncovered threading issues that otherwise only reproduce when the statusline is enabled.

@JDevlieghere JDevlieghere requested a review from jimingham July 15, 2025 23:55
@llvmbot llvmbot added the lldb label Jul 15, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 15, 2025

@llvm/pr-subscribers-lldb

Author: Jonas Devlieghere (JDevlieghere)

Changes

Always compute the execution and symbol context, regardless of whether the statusline is enabled. This code gets called from the default event handler thread and has uncovered threading issues that otherwise only reproduce when the statusline is enabled.


Full diff: https://github.com/llvm/llvm-project/pull/148994.diff

3 Files Affected:

  • (modified) lldb/include/lldb/Core/Statusline.h (+3-3)
  • (modified) lldb/source/Core/Debugger.cpp (+29-1)
  • (modified) lldb/source/Core/Statusline.cpp (+7-24)
diff --git a/lldb/include/lldb/Core/Statusline.h b/lldb/include/lldb/Core/Statusline.h
index 6bda153f822d2..13866a9083c63 100644
--- a/lldb/include/lldb/Core/Statusline.h
+++ b/lldb/include/lldb/Core/Statusline.h
@@ -25,9 +25,9 @@ class Statusline {
   /// 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. If both exe_ctx and sym_ctx are NULL, this redraws
+  /// the last string.
+  void Redraw(const ExecutionContext *exe_ctx, const SymbolContext *sym_ctx);
 
   /// Inform the statusline that the terminal dimensions have changed.
   void TerminalSizeChanged();
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp
index ed674ee1275c7..1bf4dbd0e9691 100644
--- a/lldb/source/Core/Debugger.cpp
+++ b/lldb/source/Core/Debugger.cpp
@@ -1216,8 +1216,36 @@ void Debugger::RestoreInputTerminalState() {
 
 void Debugger::RedrawStatusline(bool update) {
   std::lock_guard<std::mutex> guard(m_statusline_mutex);
+
+  if (!update && m_statusline) {
+    m_statusline->Redraw(nullptr, nullptr);
+    return;
+  }
+
+  // Always compute the execution and symbol context, regardless of whether the
+  // statusline is enabled. This code gets called from the default event handler
+  // thread and has uncovered threading issues that otherwise only reproduce
+  // when the statusline is enabled.
+  ExecutionContext exe_ctx = 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(&GetSelectedOrDummyTarget());
+
+  SymbolContext sym_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())
+        sym_ctx = frame_sp->GetSymbolContext(eSymbolContextEverything);
+    }
+  }
+
   if (m_statusline)
-    m_statusline->Redraw(update);
+    m_statusline->Redraw(&exe_ctx, &sym_ctx);
 }
 
 ExecutionContext Debugger::GetSelectedExecutionContext() {
diff --git a/lldb/source/Core/Statusline.cpp b/lldb/source/Core/Statusline.cpp
index 393d427241021..08374abd94aa8 100644
--- a/lldb/source/Core/Statusline.cpp
+++ b/lldb/source/Core/Statusline.cpp
@@ -48,15 +48,15 @@ void Statusline::TerminalSizeChanged() {
   UpdateScrollWindow(ResizeStatusline);
 
   // Draw the old statusline.
-  Redraw(/*update=*/false);
+  Redraw(nullptr, nullptr);
 }
 
 void Statusline::Enable() {
   // Reduce the scroll window to make space for the status bar below.
   UpdateScrollWindow(EnableStatusline);
 
-  // Draw the statusline.
-  Redraw(/*update=*/true);
+  // Draw the old statusline.
+  Redraw(nullptr, nullptr);
 }
 
 void Statusline::Disable() {
@@ -127,33 +127,16 @@ void Statusline::UpdateScrollWindow(ScrollWindowMode mode) {
   m_debugger.RefreshIOHandler();
 }
 
-void Statusline::Redraw(bool update) {
-  if (!update) {
+void Statusline::Redraw(const ExecutionContext *exe_ctx,
+                        const SymbolContext *sym_ctx) {
+  if (!exe_ctx && !sym_ctx) {
     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);
-    }
-  }
-
   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());

@jimingham
Copy link
Collaborator

This code seems fine to me. I was imagining that we would only always do this work when running in the TestSuite, so maybe controlled by a setting? OTOH, this is only on public stops and someone is bound to have computed the stop Symbol & Execution contexts so we aren't adding that much work, just doing it at the proper slightly unpredictable times. So this simpler version is fine.

@JDevlieghere
Copy link
Member Author

This code seems fine to me. I was imagining that we would only always do this work when running in the TestSuite, so maybe controlled by a setting? OTOH, this is only on public stops and someone is bound to have computed the stop Symbol & Execution contexts so we aren't adding that much work, just doing it at the proper slightly unpredictable times. So this simpler version is fine.

Another potential alternative is to only do this unconditionally when asserts are enabled, but I came to the same conclusion that it's likely simple enough to do it everywhere, as well as eliminate the same variance in release builds.

@jimingham
Copy link
Collaborator

Except for the quibble that "current" is ambiguous, and it's better to use the explicit "currently selected" this looks fine.

Copy link
Collaborator

@jimingham jimingham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@JDevlieghere
Copy link
Member Author

As intended, this is uncovering a non-deterministic issue in LLDB when running fork-follow-child-softbp.test. I'm able to reproduce it locally (on Linux) but I haven't figured out the cause yet.

@jimingham
Copy link
Collaborator

As intended, this is uncovering a non-deterministic issue in LLDB when running fork-follow-child-softbp.test. I'm able to reproduce it locally (on Linux) but I haven't figured out the cause yet.

It's actually pretty encouraging that we only saw one test failure from this change!

Always compute the execution and symbol context, regardless of whether
the statusline is enabled. This code gets called from the default event
handler thread and has uncovered threading issues that otherwise only
reproduce when the statusline is enabled.
@jimingham
Copy link
Collaborator

Only getting a new symbol & execution context if the process is stopped seems right.
You might have GetSelectedContext also return a "was-updated" or something. I can imagine, for instance, that I would want the status line to be slightly greyed out if you couldn't fetch the state when you went to update - to indicate that it is not current. So that would be a useful bit of information.

Other than that, this looks good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants