https://github.com/charles-zablit updated https://github.com/llvm/llvm-project/pull/167550
>From 8615f3d2a10a106f45815f28340ae3e8770f6186 Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Tue, 11 Nov 2025 18:09:05 +0100 Subject: [PATCH 1/6] [lldb] add a marker before skipped frames --- lldb/include/lldb/Target/StackFrame.h | 21 +++++++++++++++--- lldb/include/lldb/Target/StackFrameList.h | 8 +++++++ lldb/source/Target/StackFrame.cpp | 22 +++++++++++++------ lldb/source/Target/StackFrameList.cpp | 26 +++++++++++++++++++++-- 4 files changed, 66 insertions(+), 11 deletions(-) diff --git a/lldb/include/lldb/Target/StackFrame.h b/lldb/include/lldb/Target/StackFrame.h index cdbe8ae3c6779..c3e3c945e114c 100644 --- a/lldb/include/lldb/Target/StackFrame.h +++ b/lldb/include/lldb/Target/StackFrame.h @@ -335,11 +335,16 @@ class StackFrame : public ExecutionContextScope, /// \param[in] frame_marker /// Optional string that will be prepended to the frame output description. /// + /// \param[in] skipped_frame_marker + /// Optional string that will be prepended to the first or last non skipped + /// frame output description. + /// /// \return /// \b true if and only if dumping with the given \p format worked. bool DumpUsingFormat(Stream &strm, const lldb_private::FormatEntity::Entry *format, - llvm::StringRef frame_marker = {}); + llvm::StringRef frame_marker = {}, + llvm::StringRef skipped_frame_marker = {}); /// Print a description for this frame using the frame-format formatter /// settings. If the current frame-format settings are invalid, then the @@ -353,8 +358,13 @@ class StackFrame : public ExecutionContextScope, /// /// \param [in] frame_marker /// Optional string that will be prepended to the frame output description. + /// + /// \param[in] skipped_frame_marker + /// Optional string that will be prepended to the first or last non skipped + /// frame output description. void DumpUsingSettingsFormat(Stream *strm, bool show_unique = false, - const char *frame_marker = nullptr); + const char *frame_marker = nullptr, + const std::wstring skipped_frame_marker = L""); /// Print a description for this frame using a default format. /// @@ -387,10 +397,15 @@ class StackFrame : public ExecutionContextScope, /// \param[in] frame_marker /// Passed to DumpUsingSettingsFormat() for the frame info printing. /// + /// + /// \param[in] skipped_frame_marker + /// Optional string that will be prepended to the first or last non skipped + /// frame output description. /// \return /// Returns true if successful. bool GetStatus(Stream &strm, bool show_frame_info, bool show_source, - bool show_unique = false, const char *frame_marker = nullptr); + bool show_unique = false, const char *frame_marker = nullptr, + const std::wstring skipped_frame_marker = L""); /// 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 5b0df0ddb3e29..8d6b8fc284336 100644 --- a/lldb/include/lldb/Target/StackFrameList.h +++ b/lldb/include/lldb/Target/StackFrameList.h @@ -49,6 +49,14 @@ class StackFrameList { /// Resets the selected frame index of this object. void ClearSelectedFrameIndex(); + /// Return \code true if the next frame is hidden. False otherwise or if it's + /// the last frame. + bool IsNextFrameHidden(lldb_private::StackFrame &frame); + + /// Return \code true if the previous frame is hidden. False otherwise or if + /// it's the first frame. + bool IsPreviousFrameHidden(lldb_private::StackFrame &frame); + /// 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 diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp index 78f67d21d6600..362980f17d689 100644 --- a/lldb/source/Target/StackFrame.cpp +++ b/lldb/source/Target/StackFrame.cpp @@ -37,6 +37,7 @@ #include "lldb/ValueObject/ValueObjectConstResult.h" #include "lldb/ValueObject/ValueObjectMemory.h" #include "lldb/ValueObject/ValueObjectVariable.h" +#include "llvm/Support/ConvertUTF.h" #include "lldb/lldb-enumerations.h" @@ -1920,11 +1921,13 @@ void StackFrame::CalculateExecutionContext(ExecutionContext &exe_ctx) { bool StackFrame::DumpUsingFormat(Stream &strm, const FormatEntity::Entry *format, - llvm::StringRef frame_marker) { + llvm::StringRef frame_marker, + llvm::StringRef skipped_frame_marker) { GetSymbolContext(eSymbolContextEverything); ExecutionContext exe_ctx(shared_from_this()); StreamString s; s.PutCString(frame_marker); + s.PutCString(skipped_frame_marker); if (format && FormatEntity::Format(*format, s, &m_sc, &exe_ctx, nullptr, nullptr, false, false)) { @@ -1934,8 +1937,9 @@ bool StackFrame::DumpUsingFormat(Stream &strm, return false; } -void StackFrame::DumpUsingSettingsFormat(Stream *strm, bool show_unique, - const char *frame_marker) { +void StackFrame::DumpUsingSettingsFormat( + Stream *strm, bool show_unique, const char *frame_marker, + const std::wstring skipped_frame_marker) { if (strm == nullptr) return; @@ -1953,7 +1957,11 @@ void StackFrame::DumpUsingSettingsFormat(Stream *strm, bool show_unique, frame_format = &format_entry; } } - if (!DumpUsingFormat(*strm, frame_format, frame_marker)) { + + std::string skipped_frame_delimiter_utf8; + llvm::convertWideToUTF8(skipped_frame_marker, skipped_frame_delimiter_utf8); + if (!DumpUsingFormat(*strm, frame_format, frame_marker, + skipped_frame_delimiter_utf8)) { Dump(strm, true, false); strm->EOL(); } @@ -2034,10 +2042,12 @@ 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 char *frame_marker, + const std::wstring skipped_frame_marker) { if (show_frame_info) { strm.Indent(); - DumpUsingSettingsFormat(&strm, show_unique, frame_marker); + DumpUsingSettingsFormat(&strm, show_unique, frame_marker, + skipped_frame_marker); } if (show_source) { diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp index ccf874fc03ebd..80f77e2bcee16 100644 --- a/lldb/source/Target/StackFrameList.cpp +++ b/lldb/source/Target/StackFrameList.cpp @@ -879,6 +879,24 @@ 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(); +} + size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame, uint32_t num_frames, bool show_frame_info, uint32_t num_frames_with_source, @@ -920,6 +938,11 @@ size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame, else marker = unselected_marker; } + std::wstring skipped_frame_marker = L" "; + if (IsPreviousFrameHidden(*frame_sp)) + skipped_frame_marker = L"﹈"; + else if (IsNextFrameHidden(*frame_sp)) + skipped_frame_marker = L"﹇"; // Hide uninteresting frames unless it's the selected frame. if (!show_hidden && frame_sp != selected_frame_sp && frame_sp->IsHidden()) @@ -933,10 +956,9 @@ size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame, m_thread.GetID(), num_frames_displayed)) break; - if (!frame_sp->GetStatus(strm, show_frame_info, num_frames_with_source > (first_frame - frame_idx), - show_unique, marker)) + show_unique, marker, skipped_frame_marker)) break; ++num_frames_displayed; } >From 0247666cc8a7b9bf4f32788c7f162c9ccf8e6438 Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Tue, 18 Nov 2025 19:35:05 +0100 Subject: [PATCH 2/6] align all markers --- .../lldb/Host/common/DiagnosticsRendering.h | 11 +++++ lldb/include/lldb/Target/StackFrame.h | 8 ++-- lldb/include/lldb/Target/StackFrameList.h | 5 ++- .../Host/common/DiagnosticsRendering.cpp | 17 +++++++- lldb/source/Target/StackFrame.cpp | 22 ++++------ lldb/source/Target/StackFrameList.cpp | 42 ++++++++++--------- lldb/source/Target/Thread.cpp | 6 +-- 7 files changed, 67 insertions(+), 44 deletions(-) diff --git a/lldb/include/lldb/Host/common/DiagnosticsRendering.h b/lldb/include/lldb/Host/common/DiagnosticsRendering.h index dd33d671c24a5..3dfa9b0880f70 100644 --- a/lldb/include/lldb/Host/common/DiagnosticsRendering.h +++ b/lldb/include/lldb/Host/common/DiagnosticsRendering.h @@ -64,6 +64,17 @@ void RenderDiagnosticDetails(Stream &stream, bool show_inline, llvm::ArrayRef<DiagnosticDetail> details); +/// Returns whether or not the current terminal supports Unicode rendering. +/// +/// The value is cached after the first computation. +/// +/// On POSIX systems, we check if the LANG environment variable contains the +/// substring "UTF-8"; +/// +/// On Windows, we check that we are running from the Windows Terminal +/// application. +bool TerminalSupportsUnicode(); + class DiagnosticError : public llvm::ErrorInfo<DiagnosticError, CloneableECError> { public: diff --git a/lldb/include/lldb/Target/StackFrame.h b/lldb/include/lldb/Target/StackFrame.h index c3e3c945e114c..7cae4d6e69972 100644 --- a/lldb/include/lldb/Target/StackFrame.h +++ b/lldb/include/lldb/Target/StackFrame.h @@ -343,8 +343,7 @@ class StackFrame : public ExecutionContextScope, /// \b true if and only if dumping with the given \p format worked. bool DumpUsingFormat(Stream &strm, const lldb_private::FormatEntity::Entry *format, - llvm::StringRef frame_marker = {}, - llvm::StringRef skipped_frame_marker = {}); + llvm::StringRef frame_marker = {}); /// Print a description for this frame using the frame-format formatter /// settings. If the current frame-format settings are invalid, then the @@ -363,8 +362,7 @@ class StackFrame : public ExecutionContextScope, /// Optional string that will be prepended to the first or last non skipped /// frame output description. void DumpUsingSettingsFormat(Stream *strm, bool show_unique = false, - const char *frame_marker = nullptr, - const std::wstring skipped_frame_marker = L""); + const std::wstring frame_marker = L""); /// Print a description for this frame using a default format. /// @@ -404,7 +402,7 @@ class StackFrame : public ExecutionContextScope, /// \return /// Returns true if successful. bool GetStatus(Stream &strm, bool show_frame_info, bool show_source, - bool show_unique = false, const char *frame_marker = nullptr, + bool show_unique = false, const std::wstring skipped_frame_marker = L""); /// Query whether this frame is a concrete frame on the call stack, or if it diff --git a/lldb/include/lldb/Target/StackFrameList.h b/lldb/include/lldb/Target/StackFrameList.h index 8d6b8fc284336..953b3c323f609 100644 --- a/lldb/include/lldb/Target/StackFrameList.h +++ b/lldb/include/lldb/Target/StackFrameList.h @@ -57,6 +57,9 @@ class StackFrameList { /// it's the first frame. bool IsPreviousFrameHidden(lldb_private::StackFrame &frame); + std::wstring 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 @@ -104,7 +107,7 @@ class 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_selected_frame = false); /// Returns whether we have currently fetched all the frames of a stack. bool WereAllFramesFetched() const; diff --git a/lldb/source/Host/common/DiagnosticsRendering.cpp b/lldb/source/Host/common/DiagnosticsRendering.cpp index f2cd3968967fb..b37f93aefa51d 100644 --- a/lldb/source/Host/common/DiagnosticsRendering.cpp +++ b/lldb/source/Host/common/DiagnosticsRendering.cpp @@ -102,7 +102,7 @@ void RenderDiagnosticDetails(Stream &stream, // characters. In the future it might make sense to move this into // Host so it can be customized for a specific platform. llvm::StringRef cursor, underline, vbar, joint, hbar, spacer; - if (stream.AsRawOstream().colors_enabled()) { + if (TerminalSupportsUnicode()) { cursor = "˄"; underline = "˜"; vbar = "│"; @@ -232,4 +232,19 @@ void RenderDiagnosticDetails(Stream &stream, } } +bool TerminalSupportsUnicode() { + static std::optional<bool> result; + if (result) + return result.value(); +#ifndef _WIN32 + if (const char *lang_var = std::getenv("LANG")) + result = std::string(lang_var).find("UTF-8"); + else + result = false; +#else + result = std::getenv("WT_SESSION") != nullptr; +#endif + return result.value(); +} + } // namespace lldb_private diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp index 362980f17d689..303325927aff1 100644 --- a/lldb/source/Target/StackFrame.cpp +++ b/lldb/source/Target/StackFrame.cpp @@ -1921,13 +1921,11 @@ void StackFrame::CalculateExecutionContext(ExecutionContext &exe_ctx) { bool StackFrame::DumpUsingFormat(Stream &strm, const FormatEntity::Entry *format, - llvm::StringRef frame_marker, - llvm::StringRef skipped_frame_marker) { + llvm::StringRef frame_marker) { GetSymbolContext(eSymbolContextEverything); ExecutionContext exe_ctx(shared_from_this()); StreamString s; s.PutCString(frame_marker); - s.PutCString(skipped_frame_marker); if (format && FormatEntity::Format(*format, s, &m_sc, &exe_ctx, nullptr, nullptr, false, false)) { @@ -1937,9 +1935,8 @@ bool StackFrame::DumpUsingFormat(Stream &strm, return false; } -void StackFrame::DumpUsingSettingsFormat( - Stream *strm, bool show_unique, const char *frame_marker, - const std::wstring skipped_frame_marker) { +void StackFrame::DumpUsingSettingsFormat(Stream *strm, bool show_unique, + const std::wstring frame_marker) { if (strm == nullptr) return; @@ -1958,10 +1955,9 @@ void StackFrame::DumpUsingSettingsFormat( } } - std::string skipped_frame_delimiter_utf8; - llvm::convertWideToUTF8(skipped_frame_marker, skipped_frame_delimiter_utf8); - if (!DumpUsingFormat(*strm, frame_format, frame_marker, - skipped_frame_delimiter_utf8)) { + std::string frame_marker_utf8; + llvm::convertWideToUTF8(frame_marker, frame_marker_utf8); + if (!DumpUsingFormat(*strm, frame_format, frame_marker_utf8)) { Dump(strm, true, false); strm->EOL(); } @@ -2042,12 +2038,10 @@ bool StackFrame::HasCachedData() const { } bool StackFrame::GetStatus(Stream &strm, bool show_frame_info, bool show_source, - bool show_unique, const char *frame_marker, - const std::wstring skipped_frame_marker) { + bool show_unique, const std::wstring frame_marker) { if (show_frame_info) { strm.Indent(); - DumpUsingSettingsFormat(&strm, show_unique, frame_marker, - skipped_frame_marker); + DumpUsingSettingsFormat(&strm, show_unique, frame_marker); } if (show_source) { diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp index 80f77e2bcee16..97374ee7123f0 100644 --- a/lldb/source/Target/StackFrameList.cpp +++ b/lldb/source/Target/StackFrameList.cpp @@ -23,6 +23,7 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/Unwind.h" +#include "lldb/Utility/DiagnosticsRendering.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "llvm/ADT/SmallPtrSet.h" @@ -897,11 +898,25 @@ bool StackFrameList::IsPreviousFrameHidden(lldb_private::StackFrame &frame) { return frame_sp->IsHidden(); } +std::wstring StackFrameList::FrameMarker(lldb::StackFrameSP frame_sp, + lldb::StackFrameSP selected_frame_sp) { + if (frame_sp == selected_frame_sp) { + return TerminalSupportsUnicode() ? L" * " : L"* "; + } else if (!TerminalSupportsUnicode()) { + return L" "; + } else if (IsPreviousFrameHidden(*frame_sp)) { + return L" ﹉"; + } else if (IsNextFrameHidden(*frame_sp)) { + return L" ﹍"; + } + return L" "; +} + 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_selected_frame) { size_t num_frames_displayed = 0; if (num_frames == 0) @@ -919,30 +934,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::wstring 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; - } - std::wstring skipped_frame_marker = L" "; - if (IsPreviousFrameHidden(*frame_sp)) - skipped_frame_marker = L"﹈"; - else if (IsNextFrameHidden(*frame_sp)) - skipped_frame_marker = L"﹇"; + 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()) @@ -958,7 +960,7 @@ size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame, if (!frame_sp->GetStatus(strm, show_frame_info, num_frames_with_source > (first_frame - frame_idx), - show_unique, marker, skipped_frame_marker)) + show_unique, marker)) break; ++num_frames_displayed; } diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index 8c3e19725f8cb..e1b3fde77c40e 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -1817,16 +1817,16 @@ 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; 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_selected_frame); if (num_frames == 1) strm.IndentLess(); strm.IndentLess(); >From 90a7ebd314162bff10c14065f4404b320a52e3f3 Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Tue, 18 Nov 2025 19:38:55 +0100 Subject: [PATCH 3/6] remove unused comments --- lldb/include/lldb/Target/StackFrame.h | 16 ++-------------- lldb/include/lldb/Target/StackFrameList.h | 6 ++---- lldb/source/Target/StackFrame.cpp | 4 ++-- 3 files changed, 6 insertions(+), 20 deletions(-) diff --git a/lldb/include/lldb/Target/StackFrame.h b/lldb/include/lldb/Target/StackFrame.h index 7cae4d6e69972..2f48d8fb74751 100644 --- a/lldb/include/lldb/Target/StackFrame.h +++ b/lldb/include/lldb/Target/StackFrame.h @@ -335,10 +335,6 @@ class StackFrame : public ExecutionContextScope, /// \param[in] frame_marker /// Optional string that will be prepended to the frame output description. /// - /// \param[in] skipped_frame_marker - /// Optional string that will be prepended to the first or last non skipped - /// frame output description. - /// /// \return /// \b true if and only if dumping with the given \p format worked. bool DumpUsingFormat(Stream &strm, @@ -357,12 +353,8 @@ class StackFrame : public ExecutionContextScope, /// /// \param [in] frame_marker /// Optional string that will be prepended to the frame output description. - /// - /// \param[in] skipped_frame_marker - /// Optional string that will be prepended to the first or last non skipped - /// frame output description. void DumpUsingSettingsFormat(Stream *strm, bool show_unique = false, - const std::wstring frame_marker = L""); + const std::wstring &frame_marker = L""); /// Print a description for this frame using a default format. /// @@ -395,15 +387,11 @@ class StackFrame : public ExecutionContextScope, /// \param[in] frame_marker /// Passed to DumpUsingSettingsFormat() for the frame info printing. /// - /// - /// \param[in] skipped_frame_marker - /// Optional string that will be prepended to the first or last non skipped - /// frame output description. /// \return /// Returns true if successful. bool GetStatus(Stream &strm, bool show_frame_info, bool show_source, bool show_unique = false, - const std::wstring skipped_frame_marker = L""); + const std::wstring &frame_marker = L""); /// 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 953b3c323f609..92905728de69a 100644 --- a/lldb/include/lldb/Target/StackFrameList.h +++ b/lldb/include/lldb/Target/StackFrameList.h @@ -49,12 +49,10 @@ class StackFrameList { /// Resets the selected frame index of this object. void ClearSelectedFrameIndex(); - /// Return \code true if the next frame is hidden. False otherwise or if it's - /// the last frame. + /// Return \code true if the next frame is hidden. bool IsNextFrameHidden(lldb_private::StackFrame &frame); - /// Return \code true if the previous frame is hidden. False otherwise or if - /// it's the first frame. + /// Return \code true if the previous frame is hidden. bool IsPreviousFrameHidden(lldb_private::StackFrame &frame); std::wstring FrameMarker(lldb::StackFrameSP frame_sp, diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp index 303325927aff1..b4d5f7ea28b92 100644 --- a/lldb/source/Target/StackFrame.cpp +++ b/lldb/source/Target/StackFrame.cpp @@ -1936,7 +1936,7 @@ bool StackFrame::DumpUsingFormat(Stream &strm, } void StackFrame::DumpUsingSettingsFormat(Stream *strm, bool show_unique, - const std::wstring frame_marker) { + const std::wstring &frame_marker) { if (strm == nullptr) return; @@ -2038,7 +2038,7 @@ bool StackFrame::HasCachedData() const { } bool StackFrame::GetStatus(Stream &strm, bool show_frame_info, bool show_source, - bool show_unique, const std::wstring frame_marker) { + bool show_unique, const std::wstring &frame_marker) { if (show_frame_info) { strm.Indent(); DumpUsingSettingsFormat(&strm, show_unique, frame_marker); >From 3c61ed5a8950826fb3ac29b2dc90079b743493f9 Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Tue, 18 Nov 2025 19:43:56 +0100 Subject: [PATCH 4/6] make APIs use std::string instead of std::wstring --- lldb/include/lldb/Target/StackFrame.h | 4 ++-- lldb/source/Target/StackFrame.cpp | 9 +++------ lldb/source/Target/StackFrameList.cpp | 5 ++++- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lldb/include/lldb/Target/StackFrame.h b/lldb/include/lldb/Target/StackFrame.h index 2f48d8fb74751..f57c989468afd 100644 --- a/lldb/include/lldb/Target/StackFrame.h +++ b/lldb/include/lldb/Target/StackFrame.h @@ -354,7 +354,7 @@ class StackFrame : public ExecutionContextScope, /// \param [in] frame_marker /// Optional string that will be prepended to the frame output description. void DumpUsingSettingsFormat(Stream *strm, bool show_unique = false, - const std::wstring &frame_marker = L""); + const std::string &frame_marker = ""); /// Print a description for this frame using a default format. /// @@ -391,7 +391,7 @@ class StackFrame : public ExecutionContextScope, /// Returns true if successful. bool GetStatus(Stream &strm, bool show_frame_info, bool show_source, bool show_unique = false, - const std::wstring &frame_marker = L""); + const std::string &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/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp index b4d5f7ea28b92..6fd8e24f43293 100644 --- a/lldb/source/Target/StackFrame.cpp +++ b/lldb/source/Target/StackFrame.cpp @@ -37,7 +37,6 @@ #include "lldb/ValueObject/ValueObjectConstResult.h" #include "lldb/ValueObject/ValueObjectMemory.h" #include "lldb/ValueObject/ValueObjectVariable.h" -#include "llvm/Support/ConvertUTF.h" #include "lldb/lldb-enumerations.h" @@ -1936,7 +1935,7 @@ bool StackFrame::DumpUsingFormat(Stream &strm, } void StackFrame::DumpUsingSettingsFormat(Stream *strm, bool show_unique, - const std::wstring &frame_marker) { + const std::string &frame_marker) { if (strm == nullptr) return; @@ -1955,9 +1954,7 @@ void StackFrame::DumpUsingSettingsFormat(Stream *strm, bool show_unique, } } - std::string frame_marker_utf8; - llvm::convertWideToUTF8(frame_marker, frame_marker_utf8); - if (!DumpUsingFormat(*strm, frame_format, frame_marker_utf8)) { + if (!DumpUsingFormat(*strm, frame_format, frame_marker)) { Dump(strm, true, false); strm->EOL(); } @@ -2038,7 +2035,7 @@ bool StackFrame::HasCachedData() const { } bool StackFrame::GetStatus(Stream &strm, bool show_frame_info, bool show_source, - bool show_unique, const std::wstring &frame_marker) { + bool show_unique, const std::string &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 97374ee7123f0..b696ff39bbd45 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> @@ -958,9 +959,11 @@ size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame, m_thread.GetID(), num_frames_displayed)) break; + std::string marker_utf8; + llvm::convertWideToUTF8(marker, marker_utf8); if (!frame_sp->GetStatus(strm, show_frame_info, num_frames_with_source > (first_frame - frame_idx), - show_unique, marker)) + show_unique, marker_utf8)) break; ++num_frames_displayed; } >From e9462bed68c3a1555700e40a85b50676e0997b18 Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Tue, 18 Nov 2025 20:43:12 +0100 Subject: [PATCH 5/6] [lldb] improve the heuristics for checking if a terminal supports Unicode --- lldb/include/lldb/Host/Terminal.h | 12 ++++++++++++ .../Host/common/DiagnosticsRendering.cpp | 19 ++----------------- lldb/source/Host/common/Terminal.cpp | 15 +++++++++++++++ lldb/source/Target/StackFrameList.cpp | 5 ++--- 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/lldb/include/lldb/Host/Terminal.h b/lldb/include/lldb/Host/Terminal.h index da0d05e8bd265..3d66515c18812 100644 --- a/lldb/include/lldb/Host/Terminal.h +++ b/lldb/include/lldb/Host/Terminal.h @@ -68,6 +68,18 @@ class Terminal { llvm::Error SetHardwareFlowControl(bool enabled); + /// Returns whether or not the current terminal supports Unicode rendering. + /// + /// The value is cached after the first computation. + /// + /// On POSIX systems, we check if the LANG environment variable contains the + /// substring "UTF-8", case insensitive. + /// + /// On Windows, we always return true since we use the `WriteConsoleW` API + /// internally. Note that the default Windows codepage (437) does not support + /// all Unicode characters. This function does not check the codepage. + static bool SupportsUnicode(); + protected: struct Data; diff --git a/lldb/source/Host/common/DiagnosticsRendering.cpp b/lldb/source/Host/common/DiagnosticsRendering.cpp index b37f93aefa51d..006bbe545e9b3 100644 --- a/lldb/source/Host/common/DiagnosticsRendering.cpp +++ b/lldb/source/Host/common/DiagnosticsRendering.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/common/DiagnosticsRendering.h" +#include "lldb/Host/Terminal.h" #include <cstdint> using namespace lldb_private; @@ -102,7 +103,7 @@ void RenderDiagnosticDetails(Stream &stream, // characters. In the future it might make sense to move this into // Host so it can be customized for a specific platform. llvm::StringRef cursor, underline, vbar, joint, hbar, spacer; - if (TerminalSupportsUnicode()) { + if (Terminal::SupportsUnicode()) { cursor = "˄"; underline = "˜"; vbar = "│"; @@ -231,20 +232,4 @@ void RenderDiagnosticDetails(Stream &stream, stream << detail.rendered << '\n'; } } - -bool TerminalSupportsUnicode() { - static std::optional<bool> result; - if (result) - return result.value(); -#ifndef _WIN32 - if (const char *lang_var = std::getenv("LANG")) - result = std::string(lang_var).find("UTF-8"); - else - result = false; -#else - result = std::getenv("WT_SESSION") != nullptr; -#endif - return result.value(); -} - } // namespace lldb_private diff --git a/lldb/source/Host/common/Terminal.cpp b/lldb/source/Host/common/Terminal.cpp index 436dfd8130d9b..dd1dc75133f45 100644 --- a/lldb/source/Host/common/Terminal.cpp +++ b/lldb/source/Host/common/Terminal.cpp @@ -400,6 +400,21 @@ llvm::Error Terminal::SetHardwareFlowControl(bool enabled) { #endif // LLDB_ENABLE_TERMIOS } +bool Terminal::SupportsUnicode() { + static std::optional<bool> result; + if (result) + return result.value(); +#ifdef _WIN32 + return true; +#else + const char *lang_var = std::getenv("LANG"); + if (!lang_var) + return false; + result = llvm::StringRef(lang_var).lower().find("utf-8") != std::string::npos; +#endif + return result.value(); +} + TerminalState::TerminalState(Terminal term, bool save_process_group) : m_tty(term) { Save(term, save_process_group); diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp index b696ff39bbd45..e60019307bd18 100644 --- a/lldb/source/Target/StackFrameList.cpp +++ b/lldb/source/Target/StackFrameList.cpp @@ -23,7 +23,6 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/Unwind.h" -#include "lldb/Utility/DiagnosticsRendering.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "llvm/ADT/SmallPtrSet.h" @@ -902,8 +901,8 @@ bool StackFrameList::IsPreviousFrameHidden(lldb_private::StackFrame &frame) { std::wstring StackFrameList::FrameMarker(lldb::StackFrameSP frame_sp, lldb::StackFrameSP selected_frame_sp) { if (frame_sp == selected_frame_sp) { - return TerminalSupportsUnicode() ? L" * " : L"* "; - } else if (!TerminalSupportsUnicode()) { + return Terminal::SupportsUnicode() ? L" * " : L"* "; + } else if (!Terminal::SupportsUnicode()) { return L" "; } else if (IsPreviousFrameHidden(*frame_sp)) { return L" ﹉"; >From 3ef49dbc1a36af4921d4d78e9c32bca74e0d1085 Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Wed, 26 Nov 2025 15:33:42 +0000 Subject: [PATCH 6/6] address comments --- lldb/include/lldb/Target/StackFrame.h | 5 ++--- lldb/source/Target/StackFrame.cpp | 4 ++-- lldb/source/Target/StackFrameList.cpp | 9 ++++----- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/lldb/include/lldb/Target/StackFrame.h b/lldb/include/lldb/Target/StackFrame.h index f57c989468afd..0b8374cba3460 100644 --- a/lldb/include/lldb/Target/StackFrame.h +++ b/lldb/include/lldb/Target/StackFrame.h @@ -354,7 +354,7 @@ class StackFrame : public ExecutionContextScope, /// \param [in] frame_marker /// Optional string that will be prepended to the frame output description. void DumpUsingSettingsFormat(Stream *strm, bool show_unique = false, - const std::string &frame_marker = ""); + llvm::StringRef frame_marker = ""); /// Print a description for this frame using a default format. /// @@ -390,8 +390,7 @@ class StackFrame : public ExecutionContextScope, /// \return /// Returns true if successful. bool GetStatus(Stream &strm, bool show_frame_info, bool show_source, - bool show_unique = false, - const std::string &frame_marker = ""); + bool show_unique = false, 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/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp index 6fd8e24f43293..4cef2d0aae32e 100644 --- a/lldb/source/Target/StackFrame.cpp +++ b/lldb/source/Target/StackFrame.cpp @@ -1935,7 +1935,7 @@ bool StackFrame::DumpUsingFormat(Stream &strm, } void StackFrame::DumpUsingSettingsFormat(Stream *strm, bool show_unique, - const std::string &frame_marker) { + llvm::StringRef frame_marker) { if (strm == nullptr) return; @@ -2035,7 +2035,7 @@ bool StackFrame::HasCachedData() const { } bool StackFrame::GetStatus(Stream &strm, bool show_frame_info, bool show_source, - bool show_unique, const std::string &frame_marker) { + bool show_unique, 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 e60019307bd18..1f731e2fe847b 100644 --- a/lldb/source/Target/StackFrameList.cpp +++ b/lldb/source/Target/StackFrameList.cpp @@ -900,15 +900,14 @@ bool StackFrameList::IsPreviousFrameHidden(lldb_private::StackFrame &frame) { std::wstring StackFrameList::FrameMarker(lldb::StackFrameSP frame_sp, lldb::StackFrameSP selected_frame_sp) { - if (frame_sp == selected_frame_sp) { + if (frame_sp == selected_frame_sp) return Terminal::SupportsUnicode() ? L" * " : L"* "; - } else if (!Terminal::SupportsUnicode()) { + else if (!Terminal::SupportsUnicode()) return L" "; - } else if (IsPreviousFrameHidden(*frame_sp)) { + else if (IsPreviousFrameHidden(*frame_sp)) return L" ﹉"; - } else if (IsNextFrameHidden(*frame_sp)) { + else if (IsNextFrameHidden(*frame_sp)) return L" ﹍"; - } return L" "; } _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
