Skip to content

Commit 22188a0

Browse files
authored
Merge pull request #11756 from swiftlang/lldb/hidden-frame-to-21.x
🍒[lldb] When starting in a hidden frame, don't skip over hidden frames when navigating up/down 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. (cherry picked from commit 4749bf5)
2 parents 3a9f8e2 + ecad203 commit 22188a0

File tree

4 files changed

+78
-22
lines changed

4 files changed

+78
-22
lines changed

lldb/source/Commands/CommandObjectFrame.cpp

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,29 @@ class CommandObjectFrameSelect : public CommandObjectParsed {
265265

266266
Options *GetOptions() override { return &m_options; }
267267

268+
private:
269+
void SkipHiddenFrames(Thread &thread, uint32_t frame_idx) {
270+
uint32_t candidate_idx = frame_idx;
271+
const unsigned max_depth = 12;
272+
for (unsigned num_try = 0; num_try < max_depth; ++num_try) {
273+
if (candidate_idx == 0 && *m_options.relative_frame_offset == -1) {
274+
candidate_idx = UINT32_MAX;
275+
break;
276+
}
277+
candidate_idx += *m_options.relative_frame_offset;
278+
if (auto candidate_sp = thread.GetStackFrameAtIndex(candidate_idx)) {
279+
if (candidate_sp->IsHidden())
280+
continue;
281+
// Now candidate_idx is the first non-hidden frame.
282+
break;
283+
}
284+
candidate_idx = UINT32_MAX;
285+
break;
286+
};
287+
if (candidate_idx != UINT32_MAX)
288+
m_options.relative_frame_offset = candidate_idx - frame_idx;
289+
}
290+
268291
protected:
269292
void DoExecute(Args &command, CommandReturnObject &result) override {
270293
// No need to check "thread" for validity as eCommandRequiresThread ensures
@@ -278,28 +301,13 @@ class CommandObjectFrameSelect : public CommandObjectParsed {
278301
if (frame_idx == UINT32_MAX)
279302
frame_idx = 0;
280303

281-
// If moving up/down by one, skip over hidden frames.
282-
if (*m_options.relative_frame_offset == 1 ||
283-
*m_options.relative_frame_offset == -1) {
284-
uint32_t candidate_idx = frame_idx;
285-
const unsigned max_depth = 12;
286-
for (unsigned num_try = 0; num_try < max_depth; ++num_try) {
287-
if (candidate_idx == 0 && *m_options.relative_frame_offset == -1) {
288-
candidate_idx = UINT32_MAX;
289-
break;
290-
}
291-
candidate_idx += *m_options.relative_frame_offset;
292-
if (auto candidate_sp = thread->GetStackFrameAtIndex(candidate_idx)) {
293-
if (candidate_sp->IsHidden())
294-
continue;
295-
// Now candidate_idx is the first non-hidden frame.
296-
break;
297-
}
298-
candidate_idx = UINT32_MAX;
299-
break;
300-
};
301-
if (candidate_idx != UINT32_MAX)
302-
m_options.relative_frame_offset = candidate_idx - frame_idx;
304+
// If moving up/down by one, skip over hidden frames, unless we started
305+
// in a hidden frame.
306+
if ((*m_options.relative_frame_offset == 1 ||
307+
*m_options.relative_frame_offset == -1)) {
308+
if (auto current_frame_sp = thread->GetStackFrameAtIndex(frame_idx);
309+
!current_frame_sp->IsHidden())
310+
SkipHiddenFrames(*thread, frame_idx);
303311
}
304312

305313
if (*m_options.relative_frame_offset < 0) {
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CXX_SOURCES := main.cpp
2+
3+
include Makefile.rules
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import lldb
2+
from lldbsuite.test.decorators import *
3+
from lldbsuite.test.lldbtest import *
4+
from lldbsuite.test import lldbutil
5+
6+
7+
class NavigateHiddenFrameTestCase(TestBase):
8+
NO_DEBUG_INFO_TESTCASE = True
9+
10+
@add_test_categories(["libc++"])
11+
def test(self):
12+
"""Test going up/down a backtrace but we started in a hidden frame."""
13+
self.build()
14+
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
15+
self, "Break here", lldb.SBFileSpec("main.cpp")
16+
)
17+
# up
18+
self.assertIn("__impl2", thread.selected_frame.GetFunctionName())
19+
self.expect("up")
20+
self.assertIn("__impl1", thread.selected_frame.GetFunctionName())
21+
self.expect("up")
22+
self.assertIn("__impl", thread.selected_frame.GetFunctionName())
23+
self.expect("up")
24+
self.assertIn("non_impl", thread.selected_frame.GetFunctionName())
25+
26+
# Back down again.
27+
self.expect("down")
28+
self.assertIn("__impl", thread.selected_frame.GetFunctionName())
29+
self.expect("down")
30+
self.assertIn("__impl1", thread.selected_frame.GetFunctionName())
31+
self.expect("down")
32+
self.assertIn("__impl2", thread.selected_frame.GetFunctionName())
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace std {
2+
namespace __1 {
3+
static const char *__impl2() { return "Break here"; }
4+
static const char *__impl1() { return __impl2(); }
5+
static const char *__impl() { return __impl1(); }
6+
static const char *non_impl() { return __impl(); }
7+
} // namespace __1
8+
} // namespace std
9+
10+
int main() {
11+
std::__1::non_impl();
12+
__builtin_debugtrap();
13+
}

0 commit comments

Comments
 (0)