gdb: fix missing print frame when stepping out of function

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
4 files changed