Skip to content

Commit f0ba8aa

Browse files
committed
More refinement of call site handling in stepping. (llvm#114628)
When you set a "next branch breakpoint" and run to it while stepping, you have to claim the stop at that breakpoint to be the top of the inlined call stack, or you will seem to "step in" and then plans might try to step back out again. This records the PrefferedLineEntry for next branch breakpoints and adds a test to make sure this works. (cherry picked from commit 23a01a4)
1 parent ba101ac commit f0ba8aa

File tree

2 files changed

+66
-5
lines changed

2 files changed

+66
-5
lines changed

lldb/source/Target/ThreadPlanStepRange.cpp

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -358,10 +358,10 @@ bool ThreadPlanStepRange::SetNextBranchBreakpoint() {
358358
!m_next_branch_bp_sp->HasResolvedLocations())
359359
m_could_not_resolve_hw_bp = true;
360360

361+
BreakpointLocationSP bp_loc =
362+
m_next_branch_bp_sp->GetLocationAtIndex(0);
361363
if (log) {
362364
lldb::break_id_t bp_site_id = LLDB_INVALID_BREAK_ID;
363-
BreakpointLocationSP bp_loc =
364-
m_next_branch_bp_sp->GetLocationAtIndex(0);
365365
if (bp_loc) {
366366
BreakpointSiteSP bp_site = bp_loc->GetBreakpointSite();
367367
if (bp_site) {
@@ -374,7 +374,51 @@ bool ThreadPlanStepRange::SetNextBranchBreakpoint() {
374374
m_next_branch_bp_sp->GetID(), bp_site_id,
375375
run_to_address.GetLoadAddress(&m_process.GetTarget()));
376376
}
377-
377+
// The "next branch breakpoint might land on a virtual inlined call
378+
// stack. If that's true, we should always stop at the top of the
379+
// inlined call stack. Only virtual steps should walk deeper into the
380+
// inlined call stack.
381+
Block *block = run_to_address.CalculateSymbolContextBlock();
382+
if (bp_loc && block) {
383+
LineEntry top_most_line_entry;
384+
lldb::addr_t run_to_addr = run_to_address.GetFileAddress();
385+
for (Block *inlined_parent = block->GetContainingInlinedBlock();
386+
inlined_parent;
387+
inlined_parent = inlined_parent->GetInlinedParent()) {
388+
AddressRange range;
389+
if (!inlined_parent->GetRangeContainingAddress(run_to_address,
390+
range))
391+
break;
392+
Address range_start_address = range.GetBaseAddress();
393+
// Only compare addresses here, we may have different symbol
394+
// contexts (for virtual inlined stacks), but we just want to know
395+
// that they are all at the same address.
396+
if (range_start_address.GetFileAddress() != run_to_addr)
397+
break;
398+
const InlineFunctionInfo *inline_info =
399+
inlined_parent->GetInlinedFunctionInfo();
400+
if (!inline_info)
401+
break;
402+
const Declaration &call_site = inline_info->GetCallSite();
403+
top_most_line_entry.line = call_site.GetLine();
404+
top_most_line_entry.column = call_site.GetColumn();
405+
FileSpec call_site_file_spec = call_site.GetFile();
406+
top_most_line_entry.original_file_sp.reset(
407+
new SupportFile(call_site_file_spec));
408+
top_most_line_entry.range = range;
409+
top_most_line_entry.file_sp.reset();
410+
top_most_line_entry.ApplyFileMappings(
411+
GetThread().CalculateTarget());
412+
if (!top_most_line_entry.file_sp)
413+
top_most_line_entry.file_sp =
414+
top_most_line_entry.original_file_sp;
415+
}
416+
if (top_most_line_entry.IsValid()) {
417+
LLDB_LOG(log, "Setting preferred line entry: {0}:{1}",
418+
top_most_line_entry.GetFile(), top_most_line_entry.line);
419+
bp_loc->SetPreferredLineEntry(top_most_line_entry);
420+
}
421+
}
378422
m_next_branch_bp_sp->SetThreadID(m_tid);
379423
m_next_branch_bp_sp->SetBreakpointKind("next-branch-location");
380424

lldb/test/API/functionalities/inline-stepping/TestInlineStepping.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ class TestInlineStepping(TestBase):
1414
compiler="icc",
1515
bugnumber="# Not really a bug. ICC combines two inlined functions.",
1616
)
17-
1817
@skipIf(oslist=["linux"], archs=["arm"]) # Fails for 32 bit arm
1918
def test_with_python_api(self):
2019
"""Test stepping over and into inlined functions."""
@@ -293,7 +292,7 @@ def inline_stepping_step_over(self):
293292
break_1_in_main = target.BreakpointCreateBySourceRegex(
294293
"// At second call of caller_ref_1 in main.", self.main_source_spec
295294
)
296-
self.assertTrue(break_1_in_main, VALID_BREAKPOINT)
295+
self.assertGreater(break_1_in_main.GetNumLocations(), 0, VALID_BREAKPOINT)
297296

298297
# Now launch the process, and do not stop at entry point.
299298
self.process = target.LaunchSimple(
@@ -319,6 +318,24 @@ def inline_stepping_step_over(self):
319318
]
320319
self.run_step_sequence(step_sequence)
321320

321+
# Now make sure that next to a virtual inlined call stack
322+
# gets the call stack depth correct.
323+
break_2_in_main = target.BreakpointCreateBySourceRegex(
324+
"// Call max_value specialized", self.main_source_spec
325+
)
326+
self.assertGreater(break_2_in_main.GetNumLocations(), 0, VALID_BREAKPOINT)
327+
threads = lldbutil.continue_to_breakpoint(self.process, break_2_in_main)
328+
self.assertEqual(len(threads), 1, "Hit our second breakpoint")
329+
self.assertEqual(threads[0].id, self.thread.id, "Stopped at right thread")
330+
self.thread.StepOver()
331+
frame_0 = self.thread.frames[0]
332+
line_entry = frame_0.line_entry
333+
self.assertEqual(
334+
line_entry.file.basename, self.main_source_spec.basename, "File matches"
335+
)
336+
target_line = line_number("calling.cpp", "// At caller_trivial_inline_1")
337+
self.assertEqual(line_entry.line, target_line, "Lines match as well.")
338+
322339
def step_in_template(self):
323340
"""Use Python APIs to test stepping in to templated functions."""
324341
exe = self.getBuildArtifact("a.out")

0 commit comments

Comments
 (0)