Consider test-case gdb.dwarf2/dw2-extend-inline-block.exp,
specifically the "contiguous block" prefix part, which can be stepped
through like this:
...
$ gdb -q outputs/gdb.dwarf2/dw2-extend-inline-block/dw2-extend-inline-block-5
Reading symbols from dw2-extend-inline-block-5...
(gdb) start
... snip ...
Temporary breakpoint 1, main () at dw2-extend-inline-block.c:35
35 /* main:2 */
(gdb) s
36 /* main:3 */ foo (); /* foo call line */
(gdb)
foo () at dw2-extend-inline-block.c:26
26 /* foo:1 */
(gdb) s
27 /* foo:2 */
(gdb) s
28 /* foo:3 */
(gdb) s
main () at dw2-extend-inline-block.c:37
37 /* main:4 */
(gdb)
...
If we slightly modify the line program:
...
DW_LNE_set_address main_4
+ DW_LNS_advance_line 1
DW_LNS_copy
DW_LNE_set_address main_5
- DW_LNS_advance_line 1
DW_LNS_negate_stmt
DW_LNS_copy
...
we change the 36/0x401165 entry into a 37/0x401165 entry:
...
File name Line number Starting address View Stmt
dw2-extend-inline-block.c 34 0x401116 x
dw2-extend-inline-block.c 35 0x401129 x
dw2-extend-inline-block.c 26 0x401138 x
dw2-extend-inline-block.c 27 0x401147 x
dw2-extend-inline-block.c 28 0x401156 x
dw2-extend-inline-block.c 36 0x401156
-dw2-extend-inline-block.c 36 0x401165
+dw2-extend-inline-block.c 37 0x401165
dw2-extend-inline-block.c 37 0x401174 x
dw2-extend-inline-block.c 38 0x401183 x
dw2-extend-inline-block.c 39 0x401192 x
dw2-extend-inline-block.c 40 0x4011a1 x
dw2-extend-inline-block.c - 0x4011b7
...
As it happens, the fix to extend truncated inlined function blocks
doesn't work in this case. This is PR gdb/33930.
We can work around this by making sure that the inlined function block
isn't truncated in the first place:
...
- DW_AT_high_pc main_3 addr
+ DW_AT_high_pc main_4 addr
...
But then we still run into PR gdb/33981: the problem that gdb doesn't
notify us when stepping out of foo:
...
(gdb) step^M
28 /* foo:3 */^M
(gdb) step^M
37 /* main:4 */^M
(gdb)
...
What happens is that the slightly different line program triggers a
different stepping path, which includes a case of "stepped to a
different frame, but it's not the start of a statement", which
refreshes the stepping info and consequently updates
tp->control.step_frame_id to the frame id of main.
So by the time we're stopped at line 37, and are trying to figure out
what to print in print_stop_location, this condition evaluates to
true:
...
if (tp->control.stop_step
&& (tp->control.step_frame_id
== get_frame_id (get_current_frame ()))
&& (tp->control.step_start_function
== find_symbol_for_pc (tp->stop_pc ())))
...
and we get:
...
/* Finished step in same frame and same file, just print source
line. */
source_flag = SRC_LINE;
...
It's good to realize here that because foo is inlined into main,
tp->control.step_start_function is not foo but main, so consequently
the step_start_function check (which checks if we are still in the
same function) also passes, even though we actually stepped from foo
into main.
The problem is the use of find_symbol_for_pc, this function
deliberately skips over inline frames and returns the symbol for the
innermost non-inline frame.
It might be tempting to think that we should switch to use
find_symbol_for_pc_sect_maybe_inline, which will return the symbol for
an inline frame, but this also has problems, specifically, attempting
this caused a regression in gdb.opt/inline-cmds.exp. The previous
version of this patch, which showed the regression can be found here:
https://inbox.sourceware.org/gdb-patches/
20260331132342.
1050954-1-tdevries@suse.de
At a given $pc the inferior might be reported as being within an
inline frame, or it might be reported as being in the containing
non-inline frame. When the user performs a 'step' the
step_start_function needs to be set based on the function symbol of
the frame the inferior is actually reported in. And we have a
function that gives us this information, get_frame_function. So
instead of looking up the step_start_function based on the $pc value,
set it based on the frame.
Test gdb.dwarf2/dw2-extend-inline-block.exp is extended with the
additional test case described above.
Tested on x86_64-linux.
Co-Authored-By: Andrew Burgess <aburgess@redhat.com>
Approved-By: Andrew Burgess <aburgess@redhat.com>
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33930
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33981
CORE_ADDR step_range_start = 0; /* Inclusive */
CORE_ADDR step_range_end = 0; /* Exclusive */
- /* Set m_step_start_function according to PC. */
- void set_step_start_function (CORE_ADDR pc)
+ /* Set m_step_start_function according to FRAME. */
+ void set_step_start_function (const frame_info_ptr &frame)
{
- m_step_start_function = find_symbol_for_pc (pc);
+ m_step_start_function = get_frame_function (frame);
}
/* Reset m_step_start_function. */
m_step_start_function = nullptr;
}
- /* Return true if the function symbol for PC matches
+ /* Return true if the function symbol of FRAME matches
m_step_start_function. */
- bool in_step_start_function (CORE_ADDR pc)
+ bool in_step_start_function (const frame_info_ptr &frame)
{
- return m_step_start_function == find_symbol_for_pc (pc);
+ return m_step_start_function == get_frame_function (frame);
}
/* Return true if m_step_start_function is set. */
symtab_and_line sal = find_frame_sal (frame);
set_step_info (tp, frame, sal);
- CORE_ADDR pc = get_frame_pc (frame);
- tp->control.set_step_start_function (pc);
+ tp->control.set_step_start_function (frame);
}
/* Step until outside of current statement. */
== ecs->event_thread->control.step_stack_frame_id)
&& ((ecs->event_thread->control.step_stack_frame_id
!= outer_frame_id)
- || !ecs->event_thread->control.in_step_start_function
- (ecs->event_thread->stop_pc ()))))
+ || !ecs->event_thread->control.in_step_start_function (frame))))
{
CORE_ADDR stop_pc = ecs->event_thread->stop_pc ();
CORE_ADDR real_stop_pc;
if (tp->control.stop_step
&& (tp->control.step_frame_id
== get_frame_id (get_current_frame ()))
- && tp->control.in_step_start_function (tp->stop_pc ()))
+ && tp->control.in_step_start_function (get_current_frame ()))
{
symtab_and_line sal = find_frame_sal (get_selected_frame (nullptr));
if (sal.symtab != tp->current_symtab)
# Create DWARF for the test. In this case, inline function 'foo' is created
# with a contiguous address range that needs extending.
-proc build_dwarf_for_contiguous_block { asm_file } {
+proc build_dwarf_for_contiguous_block { asm_file {range_correct 0} {variant 0} } {
Dwarf::assemble $asm_file {
+ upvar range_correct range_correct
+ upvar variant variant
+
declare_labels lines_table inline_func
cu { } {
DW_AT_call_file 1 data1
DW_AT_call_line $::foo_call_line data1
DW_AT_low_pc main_1 addr
- DW_AT_high_pc main_3 addr
+ if {$range_correct} {
+ DW_AT_high_pc main_4 addr
+ } else {
+ DW_AT_high_pc main_3 addr
+ }
}
}
}
DW_LNS_copy
DW_LNE_set_address main_4
+ if {$variant == 1} {
+ DW_LNS_advance_line 1
+ }
DW_LNS_copy
DW_LNE_set_address main_5
- DW_LNS_advance_line 1
+ if {$variant == 0} {
+ DW_LNS_advance_line 1
+ }
DW_LNS_negate_stmt
DW_LNS_copy
}
}
+# Like build_dwarf_for_contiguous_block, but use a slightly different line
+# info by setting variant == 1.
+# Use range_correct 1, so we're not testing the fix for PR33930.
+
+proc build_dwarf_for_contiguous_block_2 { asm_file } {
+ return [build_dwarf_for_contiguous_block $asm_file 1 1]
+}
+
+# Like build_dwarf_for_contiguous_block, but use a slightly different line
+# info by setting variant == 1.
+# Use range_correct 0, so we're testing the fix for PR33930.
+
+proc build_dwarf_for_contiguous_block_3 { asm_file } {
+ return [build_dwarf_for_contiguous_block $asm_file 0 1]
+}
+
# Assuming GDB is stopped at the entry $pc for 'foo', use 'maint info
# blocks' to check the block for 'foo' is correct. This function checks
# 'foo' created by 'build_dwarf_for_contiguous_block'.
[list "contiguous block" \
build_dwarf_for_contiguous_block \
check_contiguous_block] \
+ [list "contiguous block 2" \
+ build_dwarf_for_contiguous_block_2 \
+ check_contiguous_block] \
+ [list "contiguous block 3" \
+ build_dwarf_for_contiguous_block_3 \
+ check_contiguous_block] \
]
# Run all the tests.
set build_dwarf_func [lindex $test_spec 1]
set check_block_func [lindex $test_spec 2]
+ if {$build_dwarf_func == "build_dwarf_for_contiguous_block_3"} {
+ # Work around PR gdb/33930.
+ continue
+ }
+
with_test_prefix $prefix {
set asm_file [standard_output_file ${testfile}-${suffix}.S]
$build_dwarf_func $asm_file