Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lldb/include/lldb/Target/StackFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -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
Expand Down
18 changes: 17 additions & 1 deletion lldb/include/lldb/Target/StackFrameList.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,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::wstring FrameMarker(lldb::StackFrameSP frame_sp,
Copy link
Member

Choose a reason for hiding this comment

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

To the best of my knowledge, we don't pass around std::wstring anywhere in LLDB that isn't Windows specific. This would be the first place that we do.

Can you help me understand why that's necessary and why we can't do the same that we do elsewhere which is passing around UTF-8 strings and only convert them to UTF-16 at the very end? Dealing with Unicode is pretty hard as it is and I fully acknowledge that there's plenty of room for improvement in LLDB. However, I want to avoid having to add another level of complexity if it can be avoided and learn from what we've done in LLVM, which is pretty good about this stuff.

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
Expand Down Expand Up @@ -96,7 +112,7 @@ 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_selected_frame = false);

/// Returns whether we have currently fetched all the frames of a stack.
bool WereAllFramesFetched() const;
Expand Down
29 changes: 29 additions & 0 deletions lldb/packages/Python/lldbsuite/test/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,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."""
Expand Down
5 changes: 3 additions & 2 deletions lldb/source/Target/StackFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down
57 changes: 41 additions & 16 deletions lldb/source/Target/StackFrameList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down Expand Up @@ -928,11 +929,42 @@ 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::wstring StackFrameList::FrameMarker(lldb::StackFrameSP frame_sp,
lldb::StackFrameSP selected_frame_sp) {
if (frame_sp == selected_frame_sp)
return Terminal::SupportsUnicode() ? L" * " : L"* ";
else if (!Terminal::SupportsUnicode())
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)
Expand All @@ -950,25 +982,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;
}
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())
Expand All @@ -982,10 +1006,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;
}
Expand Down
6 changes: 3 additions & 3 deletions lldb/source/Target/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1887,16 +1887,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();
Expand Down
3 changes: 3 additions & 0 deletions lldb/test/API/terminal/hidden_frame_markers/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CXX_SOURCES := main.cpp

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""
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:",
],
)
12 changes: 12 additions & 0 deletions lldb/test/API/terminal/hidden_frame_markers/main.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
Copy link
Member

Choose a reason for hiding this comment

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

Missing newline

Loading