llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Charles Zablit (charles-zablit)

<details>
<summary>Changes</summary>

This is a reland of https://github.com/llvm/llvm-project/pull/167550. Instead 
of relying on libcpp for testing, we emulate our own hidden frames. This was 
originally causing tests failures on Windows.


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


12 Files Affected:

- (modified) lldb/include/lldb/Core/Debugger.h (+2) 
- (modified) lldb/include/lldb/Target/StackFrame.h (+2-2) 
- (modified) lldb/include/lldb/Target/StackFrameList.h (+18-1) 
- (modified) lldb/packages/Python/lldbsuite/test/decorators.py (+29) 
- (modified) lldb/source/Core/CoreProperties.td (+4) 
- (modified) lldb/source/Core/Debugger.cpp (+7) 
- (modified) lldb/source/Target/StackFrame.cpp (+3-2) 
- (modified) lldb/source/Target/StackFrameList.cpp (+39-14) 
- (modified) lldb/source/Target/Thread.cpp (+15-8) 
- (added) lldb/test/API/terminal/hidden_frame_markers/Makefile (+3) 
- (added) lldb/test/API/terminal/hidden_frame_markers/TestHiddenFrameMarkers.py 
(+97) 
- (added) lldb/test/API/terminal/hidden_frame_markers/main.cpp (+12) 


``````````diff
diff --git a/lldb/include/lldb/Core/Debugger.h 
b/lldb/include/lldb/Core/Debugger.h
index 87a57f7f1a538..a38caa7ac594e 100644
--- a/lldb/include/lldb/Core/Debugger.h
+++ b/lldb/include/lldb/Core/Debugger.h
@@ -347,6 +347,8 @@ class Debugger : public 
std::enable_shared_from_this<Debugger>,
 
   bool SetUseSourceCache(bool use_source_cache);
 
+  bool GetMarkHiddenFrames() const;
+
   bool GetHighlightSource() const;
 
   lldb::StopShowColumn GetStopShowColumn() const;
diff --git a/lldb/include/lldb/Target/StackFrame.h 
b/lldb/include/lldb/Target/StackFrame.h
index 5cba9afe2a7e8..17563ee6ada98 100644
--- a/lldb/include/lldb/Target/StackFrame.h
+++ b/lldb/include/lldb/Target/StackFrame.h
@@ -363,7 +363,7 @@ class StackFrame : public ExecutionContextScope,
   /// \param [in] frame_marker
   ///   Optional string that will be prepended to the frame output description.
   virtual void DumpUsingSettingsFormat(Stream *strm, bool show_unique = false,
-                                       const char *frame_marker = nullptr);
+                                       const llvm::StringRef frame_marker = 
"");
 
   /// Print a description for this frame using a default format.
   ///
@@ -400,7 +400,7 @@ class StackFrame : public ExecutionContextScope,
   ///   Returns true if successful.
   virtual bool GetStatus(Stream &strm, bool show_frame_info, bool show_source,
                          bool show_unique = false,
-                         const char *frame_marker = nullptr);
+                         const llvm::StringRef frame_marker = "");
 
   /// Query whether this frame is a concrete frame on the call stack, or if it
   /// is an inlined frame derived from the debug information and presented by
diff --git a/lldb/include/lldb/Target/StackFrameList.h 
b/lldb/include/lldb/Target/StackFrameList.h
index 715781abb83a3..223aa3ddab731 100644
--- a/lldb/include/lldb/Target/StackFrameList.h
+++ b/lldb/include/lldb/Target/StackFrameList.h
@@ -50,6 +50,22 @@ class StackFrameList : public 
std::enable_shared_from_this<StackFrameList> {
   /// Resets the selected frame index of this object.
   void ClearSelectedFrameIndex();
 
+  /// Returns \p true if the next frame is hidden.
+  bool IsNextFrameHidden(lldb_private::StackFrame &frame);
+
+  /// Returns \p true if the previous frame is hidden.
+  bool IsPreviousFrameHidden(lldb_private::StackFrame &frame);
+
+  /// Returns the stack frame marker depending on if \p frame_sp:
+  /// @li is selected: *
+  /// @li is the first non hidden frame: ﹍
+  /// @li is the last non hidden frame: ﹉
+  ///
+  /// If the terminal does not support Unicode rendering, the hidden frame
+  /// markers are replaced with whitespaces.
+  std::string FrameMarker(lldb::StackFrameSP frame_sp,
+                          lldb::StackFrameSP selected_frame_sp);
+
   /// Get the currently selected frame index.
   /// We should only call SelectMostRelevantFrame if (a) the user hasn't 
already
   /// selected a frame, and (b) if this really is a user facing
@@ -97,7 +113,8 @@ class StackFrameList : public 
std::enable_shared_from_this<StackFrameList> {
   size_t GetStatus(Stream &strm, uint32_t first_frame, uint32_t num_frames,
                    bool show_frame_info, uint32_t num_frames_with_source,
                    bool show_unique = false, bool show_hidden = false,
-                   const char *frame_marker = nullptr);
+                   bool show_hidden_marker = true,
+                   bool show_selected_frame = false);
 
   /// Returns whether we have currently fetched all the frames of a stack.
   bool WereAllFramesFetched() const;
diff --git a/lldb/packages/Python/lldbsuite/test/decorators.py 
b/lldb/packages/Python/lldbsuite/test/decorators.py
index df0b2cba4c573..b4658b149af90 100644
--- a/lldb/packages/Python/lldbsuite/test/decorators.py
+++ b/lldb/packages/Python/lldbsuite/test/decorators.py
@@ -442,6 +442,35 @@ def impl(func):
     return impl
 
 
+def unicode_test(func):
+    """Decorate the item as a test which requires Unicode to be enabled.
+
+    lldb checks the value of the `LANG` environment variable for the substring 
"utf-8"
+    to determine if the terminal supports Unicode (except on Windows, were we 
assume
+    it's always supported).
+    This decorator sets LANG to `utf-8` before running the test and resets it 
to its
+    previous value afterwards.
+    """
+
+    def unicode_wrapped(*args, **kwargs):
+        import os
+
+        previous_lang = os.environ.get("LANG", None)
+        os.environ["LANG"] = "en_US.UTF-8"
+        try:
+            func(*args, **kwargs)
+        except Exception as err:
+            raise err
+        finally:
+            # Reset the value, whether the test failed or not.
+            if previous_lang is not None:
+                os.environ["LANG"] = previous_lang
+            else:
+                del os.environ["LANG"]
+
+    return unicode_wrapped
+
+
 def no_debug_info_test(func):
     """Decorate the item as a test what don't use any debug info. If this 
annotation is specified
     then the test runner won't generate a separate test for each debug info 
format."""
diff --git a/lldb/source/Core/CoreProperties.td 
b/lldb/source/Core/CoreProperties.td
index 383834eea22a5..e029da6467fce 100644
--- a/lldb/source/Core/CoreProperties.td
+++ b/lldb/source/Core/CoreProperties.td
@@ -128,6 +128,10 @@ let Definition = "debugger", Path = "" in {
     Global,
     DefaultTrue,
     Desc<"If true, LLDB will highlight the displayed source code.">;
+  def MarkHiddenFrames: Property<"mark-hidden-frames", "Boolean">,
+    Global,
+    DefaultTrue,
+    Desc<"If true, LLDB will add a marker to delimit hidden frames in 
backtraces.">;
   def StopShowColumn: Property<"stop-show-column", "Enum">,
     DefaultEnumValue<"eStopShowColumnAnsiOrCaret">,
     EnumValues<"OptionEnumValues(s_stop_show_column_values)">,
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp
index 00dea7da3497e..12f8039da947e 100644
--- a/lldb/source/Core/Debugger.cpp
+++ b/lldb/source/Core/Debugger.cpp
@@ -612,6 +612,13 @@ bool Debugger::SetUseSourceCache(bool b) {
   }
   return ret;
 }
+
+bool Debugger::GetMarkHiddenFrames() const {
+  const uint32_t idx = ePropertyMarkHiddenFrames;
+  return GetPropertyAtIndexAs<bool>(
+      idx, g_debugger_properties[idx].default_uint_value != 0);
+}
+
 bool Debugger::GetHighlightSource() const {
   const uint32_t idx = ePropertyHighlightSource;
   return GetPropertyAtIndexAs<bool>(
diff --git a/lldb/source/Target/StackFrame.cpp 
b/lldb/source/Target/StackFrame.cpp
index 340607e14abed..3ef96a46517c9 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -1945,7 +1945,7 @@ bool StackFrame::DumpUsingFormat(Stream &strm,
 }
 
 void StackFrame::DumpUsingSettingsFormat(Stream *strm, bool show_unique,
-                                         const char *frame_marker) {
+                                         const llvm::StringRef frame_marker) {
   if (strm == nullptr)
     return;
 
@@ -2044,7 +2044,8 @@ bool StackFrame::HasCachedData() const {
 }
 
 bool StackFrame::GetStatus(Stream &strm, bool show_frame_info, bool 
show_source,
-                           bool show_unique, const char *frame_marker) {
+                           bool show_unique,
+                           const llvm::StringRef frame_marker) {
   if (show_frame_info) {
     strm.Indent();
     DumpUsingSettingsFormat(&strm, show_unique, frame_marker);
diff --git a/lldb/source/Target/StackFrameList.cpp 
b/lldb/source/Target/StackFrameList.cpp
index 4f4b06f30460b..d573d23c318fb 100644
--- a/lldb/source/Target/StackFrameList.cpp
+++ b/lldb/source/Target/StackFrameList.cpp
@@ -27,6 +27,7 @@
 #include "lldb/Utility/LLDBLog.h"
 #include "lldb/Utility/Log.h"
 #include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Support/ConvertUTF.h"
 
 #include <memory>
 
@@ -947,11 +948,43 @@ 
StackFrameList::GetStackFrameSPForStackFramePtr(StackFrame *stack_frame_ptr) {
   return ret_sp;
 }
 
+bool StackFrameList::IsNextFrameHidden(lldb_private::StackFrame &frame) {
+  uint32_t frame_idx = frame.GetFrameIndex();
+  StackFrameSP frame_sp = GetFrameAtIndex(frame_idx + 1);
+  if (!frame_sp)
+    return false;
+  return frame_sp->IsHidden();
+}
+
+bool StackFrameList::IsPreviousFrameHidden(lldb_private::StackFrame &frame) {
+  uint32_t frame_idx = frame.GetFrameIndex();
+  if (frame_idx == 0)
+    return false;
+  StackFrameSP frame_sp = GetFrameAtIndex(frame_idx - 1);
+  if (!frame_sp)
+    return false;
+  return frame_sp->IsHidden();
+}
+
+std::string StackFrameList::FrameMarker(lldb::StackFrameSP frame_sp,
+                                        lldb::StackFrameSP selected_frame_sp) {
+  if (frame_sp == selected_frame_sp)
+    return Terminal::SupportsUnicode() ? u8" * " : u8"* ";
+  else if (!Terminal::SupportsUnicode())
+    return u8"  ";
+  else if (IsPreviousFrameHidden(*frame_sp))
+    return u8"﹉ ";
+  else if (IsNextFrameHidden(*frame_sp))
+    return u8"﹍ ";
+  return u8"   ";
+}
+
 size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame,
                                  uint32_t num_frames, bool show_frame_info,
                                  uint32_t num_frames_with_source,
                                  bool show_unique, bool show_hidden,
-                                 const char *selected_frame_marker) {
+                                 bool show_hidden_marker,
+                                 bool show_selected_frame) {
   size_t num_frames_displayed = 0;
 
   if (num_frames == 0)
@@ -969,25 +1002,17 @@ size_t StackFrameList::GetStatus(Stream &strm, uint32_t 
first_frame,
 
   StackFrameSP selected_frame_sp =
       m_thread.GetSelectedFrame(DoNoSelectMostRelevantFrame);
-  const char *unselected_marker = nullptr;
   std::string buffer;
-  if (selected_frame_marker) {
-    size_t len = strlen(selected_frame_marker);
-    buffer.insert(buffer.begin(), len, ' ');
-    unselected_marker = buffer.c_str();
-  }
-  const char *marker = nullptr;
+  std::string marker;
   for (frame_idx = first_frame; frame_idx < last_frame; ++frame_idx) {
     frame_sp = GetFrameAtIndex(frame_idx);
     if (!frame_sp)
       break;
 
-    if (selected_frame_marker != nullptr) {
-      if (frame_sp == selected_frame_sp)
-        marker = selected_frame_marker;
-      else
-        marker = unselected_marker;
-    }
+    if (show_selected_frame)
+      marker = FrameMarker(frame_sp, selected_frame_sp);
+    else
+      marker = FrameMarker(frame_sp, nullptr);
 
     // Hide uninteresting frames unless it's the selected frame.
     if (!show_hidden && frame_sp != selected_frame_sp && frame_sp->IsHidden())
diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp
index 44b664ac70d29..aa005a2b9b3db 100644
--- a/lldb/source/Target/Thread.cpp
+++ b/lldb/source/Target/Thread.cpp
@@ -1961,9 +1961,9 @@ size_t Thread::GetStatus(Stream &strm, uint32_t 
start_frame,
                          uint32_t num_frames, uint32_t num_frames_with_source,
                          bool stop_format, bool show_hidden, bool only_stacks) 
{
 
+  ExecutionContext exe_ctx(shared_from_this());
+  Target *target = exe_ctx.GetTargetPtr();
   if (!only_stacks) {
-    ExecutionContext exe_ctx(shared_from_this());
-    Target *target = exe_ctx.GetTargetPtr();
     Process *process = exe_ctx.GetProcessPtr();
     strm.Indent();
     bool is_selected = false;
@@ -1997,16 +1997,19 @@ size_t Thread::GetStatus(Stream &strm, uint32_t 
start_frame,
 
     const bool show_frame_info = true;
     const bool show_frame_unique = only_stacks;
-    const char *selected_frame_marker = nullptr;
+    bool show_selected_frame = false;
     if (num_frames == 1 || only_stacks ||
         (GetID() != 
GetProcess()->GetThreadList().GetSelectedThread()->GetID()))
       strm.IndentMore();
     else
-      selected_frame_marker = "* ";
+      show_selected_frame = true;
 
+    bool show_hidden_marker =
+        target && target->GetDebugger().GetMarkHiddenFrames();
     num_frames_shown = GetStackFrameList()->GetStatus(
         strm, start_frame, num_frames, show_frame_info, num_frames_with_source,
-        show_frame_unique, show_hidden, selected_frame_marker);
+        show_frame_unique, show_hidden, show_hidden_marker,
+        show_selected_frame);
     if (num_frames == 1)
       strm.IndentLess();
     strm.IndentLess();
@@ -2106,9 +2109,13 @@ size_t Thread::GetStackFrameStatus(Stream &strm, 
uint32_t first_frame,
                                    uint32_t num_frames, bool show_frame_info,
                                    uint32_t num_frames_with_source,
                                    bool show_hidden) {
-  return GetStackFrameList()->GetStatus(strm, first_frame, num_frames,
-                                        show_frame_info, 
num_frames_with_source,
-                                        /*show_unique*/ false, show_hidden);
+  ExecutionContext exe_ctx(shared_from_this());
+  Target *target = exe_ctx.GetTargetPtr();
+  bool show_hidden_marker =
+      target && target->GetDebugger().GetMarkHiddenFrames();
+  return GetStackFrameList()->GetStatus(
+      strm, first_frame, num_frames, show_frame_info, num_frames_with_source,
+      /*show_unique*/ false, show_hidden, show_hidden_marker);
 }
 
 Unwind &Thread::GetUnwinder() {
diff --git a/lldb/test/API/terminal/hidden_frame_markers/Makefile 
b/lldb/test/API/terminal/hidden_frame_markers/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ b/lldb/test/API/terminal/hidden_frame_markers/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git 
a/lldb/test/API/terminal/hidden_frame_markers/TestHiddenFrameMarkers.py 
b/lldb/test/API/terminal/hidden_frame_markers/TestHiddenFrameMarkers.py
new file mode 100644
index 0000000000000..178d97fce17c2
--- /dev/null
+++ b/lldb/test/API/terminal/hidden_frame_markers/TestHiddenFrameMarkers.py
@@ -0,0 +1,97 @@
+"""
+Test that hidden frames are delimited with markers.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class HiddenFrameMarkerTest(TestBase):
+    @unicode_test
+    def test_hidden_frame_markers(self):
+        """Test that hidden frame markers are rendered in backtraces"""
+        self.build()
+        lldbutil.run_to_source_breakpoint(
+            self, "// break here", lldb.SBFileSpec("main.cpp")
+        )
+        self.expect(
+            "bt",
+            substrs=[
+                "   * frame #0:",
+                "  ﹍ frame #1:",
+                "  ﹉ frame #7:",
+                "     frame #8:",
+                "     frame #9:",
+            ],
+        )
+
+        self.runCmd("f 1")
+        self.expect(
+            "bt",
+            substrs=[
+                "     frame #0:",
+                "   * frame #1:",
+                "  ﹉ frame #7:",
+                "     frame #8:",
+                "     frame #9:",
+            ],
+        )
+
+        self.runCmd("f 7")
+        self.expect(
+            "bt",
+            substrs=[
+                "     frame #0:",
+                "  ﹍ frame #1:",
+                "   * frame #7:",
+                "     frame #8:",
+                "     frame #9:",
+            ],
+        )
+
+    def test_hidden_frame_markers(self):
+        """
+        Test that hidden frame markers are not rendered in backtraces when
+        mark-hidden-frames is set to false
+        """
+        self.build()
+        self.runCmd("settings set mark-hidden-frames 0")
+        lldbutil.run_to_source_breakpoint(
+            self, "// break here", lldb.SBFileSpec("main.cpp")
+        )
+        self.expect(
+            "bt",
+            substrs=[
+                "  * frame #0:",
+                "    frame #1:",
+                "    frame #7:",
+                "    frame #8:",
+                "    frame #9:",
+            ],
+        )
+
+        self.runCmd("f 1")
+        self.expect(
+            "bt",
+            substrs=[
+                "    frame #0:",
+                "  * frame #1:",
+                "    frame #7:",
+                "    frame #8:",
+                "    frame #9:",
+            ],
+        )
+
+        self.runCmd("f 7")
+        self.expect(
+            "bt",
+            substrs=[
+                "    frame #0:",
+                "    frame #1:",
+                "  * frame #7:",
+                "    frame #8:",
+                "    frame #9:",
+            ],
+        )
diff --git a/lldb/test/API/terminal/hidden_frame_markers/main.cpp 
b/lldb/test/API/terminal/hidden_frame_markers/main.cpp
new file mode 100644
index 0000000000000..c0b7e0884538a
--- /dev/null
+++ b/lldb/test/API/terminal/hidden_frame_markers/main.cpp
@@ -0,0 +1,12 @@
+#include <functional>
+#include <iostream>
+
+static void target() {
+  int a = 0; // break here
+}
+
+int main() {
+  std::function<void()> fn = [] { target(); };
+  fn();
+  return 0;
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/181143
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to