mirror of
https://github.com/intel/llvm.git
synced 2026-01-13 19:08:21 +08:00
[lldb] When starting in a hidden frame, don't skip over hidden frames when navigating up/down (#166394)
When stopped in a hidden frame (either because we selected the hidden frame or hit a breakpoint inside it), a user most likely is intersted in exploring the immediate frames around it. But currently issuing `up`/`down` commands will unconditionally skip over all hidden frames. This patch makes it so `up`/`down` commands don't skip hidden frames if the frame we started it was a hidden frame.
This commit is contained in:
@@ -265,6 +265,29 @@ public:
|
||||
|
||||
Options *GetOptions() override { return &m_options; }
|
||||
|
||||
private:
|
||||
void SkipHiddenFrames(Thread &thread, uint32_t frame_idx) {
|
||||
uint32_t candidate_idx = frame_idx;
|
||||
const unsigned max_depth = 12;
|
||||
for (unsigned num_try = 0; num_try < max_depth; ++num_try) {
|
||||
if (candidate_idx == 0 && *m_options.relative_frame_offset == -1) {
|
||||
candidate_idx = UINT32_MAX;
|
||||
break;
|
||||
}
|
||||
candidate_idx += *m_options.relative_frame_offset;
|
||||
if (auto candidate_sp = thread.GetStackFrameAtIndex(candidate_idx)) {
|
||||
if (candidate_sp->IsHidden())
|
||||
continue;
|
||||
// Now candidate_idx is the first non-hidden frame.
|
||||
break;
|
||||
}
|
||||
candidate_idx = UINT32_MAX;
|
||||
break;
|
||||
};
|
||||
if (candidate_idx != UINT32_MAX)
|
||||
m_options.relative_frame_offset = candidate_idx - frame_idx;
|
||||
}
|
||||
|
||||
protected:
|
||||
void DoExecute(Args &command, CommandReturnObject &result) override {
|
||||
// No need to check "thread" for validity as eCommandRequiresThread ensures
|
||||
@@ -278,28 +301,13 @@ protected:
|
||||
if (frame_idx == UINT32_MAX)
|
||||
frame_idx = 0;
|
||||
|
||||
// If moving up/down by one, skip over hidden frames.
|
||||
if (*m_options.relative_frame_offset == 1 ||
|
||||
*m_options.relative_frame_offset == -1) {
|
||||
uint32_t candidate_idx = frame_idx;
|
||||
const unsigned max_depth = 12;
|
||||
for (unsigned num_try = 0; num_try < max_depth; ++num_try) {
|
||||
if (candidate_idx == 0 && *m_options.relative_frame_offset == -1) {
|
||||
candidate_idx = UINT32_MAX;
|
||||
break;
|
||||
}
|
||||
candidate_idx += *m_options.relative_frame_offset;
|
||||
if (auto candidate_sp = thread->GetStackFrameAtIndex(candidate_idx)) {
|
||||
if (candidate_sp->IsHidden())
|
||||
continue;
|
||||
// Now candidate_idx is the first non-hidden frame.
|
||||
break;
|
||||
}
|
||||
candidate_idx = UINT32_MAX;
|
||||
break;
|
||||
};
|
||||
if (candidate_idx != UINT32_MAX)
|
||||
m_options.relative_frame_offset = candidate_idx - frame_idx;
|
||||
// If moving up/down by one, skip over hidden frames, unless we started
|
||||
// in a hidden frame.
|
||||
if ((*m_options.relative_frame_offset == 1 ||
|
||||
*m_options.relative_frame_offset == -1)) {
|
||||
if (auto current_frame_sp = thread->GetStackFrameAtIndex(frame_idx);
|
||||
!current_frame_sp->IsHidden())
|
||||
SkipHiddenFrames(*thread, frame_idx);
|
||||
}
|
||||
|
||||
if (*m_options.relative_frame_offset < 0) {
|
||||
|
||||
3
lldb/test/API/commands/frame/select-hidden/Makefile
Normal file
3
lldb/test/API/commands/frame/select-hidden/Makefile
Normal file
@@ -0,0 +1,3 @@
|
||||
CXX_SOURCES := main.cpp
|
||||
|
||||
include Makefile.rules
|
||||
@@ -0,0 +1,32 @@
|
||||
import lldb
|
||||
from lldbsuite.test.decorators import *
|
||||
from lldbsuite.test.lldbtest import *
|
||||
from lldbsuite.test import lldbutil
|
||||
|
||||
|
||||
class NavigateHiddenFrameTestCase(TestBase):
|
||||
NO_DEBUG_INFO_TESTCASE = True
|
||||
|
||||
@add_test_categories(["libc++"])
|
||||
def test(self):
|
||||
"""Test going up/down a backtrace but we started in a hidden frame."""
|
||||
self.build()
|
||||
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
|
||||
self, "Break here", lldb.SBFileSpec("main.cpp")
|
||||
)
|
||||
# up
|
||||
self.assertIn("__impl2", thread.selected_frame.GetFunctionName())
|
||||
self.expect("up")
|
||||
self.assertIn("__impl1", thread.selected_frame.GetFunctionName())
|
||||
self.expect("up")
|
||||
self.assertIn("__impl", thread.selected_frame.GetFunctionName())
|
||||
self.expect("up")
|
||||
self.assertIn("non_impl", thread.selected_frame.GetFunctionName())
|
||||
|
||||
# Back down again.
|
||||
self.expect("down")
|
||||
self.assertIn("__impl", thread.selected_frame.GetFunctionName())
|
||||
self.expect("down")
|
||||
self.assertIn("__impl1", thread.selected_frame.GetFunctionName())
|
||||
self.expect("down")
|
||||
self.assertIn("__impl2", thread.selected_frame.GetFunctionName())
|
||||
13
lldb/test/API/commands/frame/select-hidden/main.cpp
Normal file
13
lldb/test/API/commands/frame/select-hidden/main.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace std {
|
||||
namespace __1 {
|
||||
static const char *__impl2() { return "Break here"; }
|
||||
static const char *__impl1() { return __impl2(); }
|
||||
static const char *__impl() { return __impl1(); }
|
||||
static const char *non_impl() { return __impl(); }
|
||||
} // namespace __1
|
||||
} // namespace std
|
||||
|
||||
int main() {
|
||||
std::__1::non_impl();
|
||||
__builtin_debugtrap();
|
||||
}
|
||||
Reference in New Issue
Block a user