]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commit
gdb: don't show incorrect source file in source window
authorTom de Vries <tdevries@suse.de>
Wed, 29 Jan 2025 10:21:02 +0000 (11:21 +0100)
committerAndrew Burgess <aburgess@redhat.com>
Tue, 25 Feb 2025 10:56:36 +0000 (10:56 +0000)
commit1e9bd86ccda976c0f7ef513cb5e9ee3eff460768
tree60bd79ce4c792df44514d8691a0e59e6a09e34c7
parentf40b59b91240886003b679ff4a3fd51b6b60696a
gdb: don't show incorrect source file in source window

Consider the test-case sources main.c and foo.c:

  $ cat main.c
  extern int foo (void);

  int
  main (void)
  {
    return foo ();
  }
  $ cat foo.c
  extern int foo (void);

  int
  foo (void)
  {
    return 0;
  }

and main.c compiled with debug info, and foo.c without:

  $ gcc -g main.c -c
  $ gcc foo.c -c
  $ gcc -g main.o foo.o

In TUI mode, if we run to foo:

  $ gdb -q a.out -tui -ex "b foo" -ex run

it gets us "[ No Source Available ]":

  ┌─main.c─────────────────────────────────────────┐
  │                                                │
  │                                                │
  │                                                │
  │            [ No Source Available ]             │
  │                                                │
  │                                                │
  └────────────────────────────────────────────────┘
  (src) In: foo                  L??   PC: 0x400566
  ...
  Breakpoint 1, 0x0000000000400566 in foo ()
  (gdb)

But after resizing (pressing ctrl-<minus> in the gnome-terminal), we
get instead the source for main.c:

  ┌─main.c─────────────────────────────────────────┐
  │        3 int                                   │
  │        4 main (void)                           │
  │        5 {                                     │
  │        6   return foo ();                      │
  │        7 }                                     │
  │                                                │
  │                                                │
  └────────────────────────────────────────────────┘
  (src) In: foo                   L??   PC: 0x400566
  ...
  Breakpoint 1, 0x0000000000400566 in foo ()
  (gdb)

which is inappropriate because we're stopped in function foo, which is
not in main.c.

The problem is that, when the window is resized, GDB ends up calling
tui_source_window_base::rerender.  The rerender function has three
cases, one for when the window already has some source code
content (which is not the case here), a case for when the inferior is
active, and we have a selected frame (which is the case that applies
here), and a final case for when the inferior is not running.

For the case which we end up in, the source code window has no
content, but the inferior is running, so we have a selected frame, GDB
calls the get_current_source_symtab_and_line() function to get the
symtab_and_line for the current location.

The get_current_source_symtab_and_line() will actually return the last
recorded symtab and line location, not the current symtab and line
location.

What this means, is that, if the current location has no debug
information, get_current_source_symtab_and_line() will return any
previously recorded location, or failing that, the default (main)
location.

This behaviour of get_current_source_symtab_and_line() also causes
problems for the 'list' command.  Consider this pure CLI session:

  (gdb) break foo
  Breakpoint 1 at 0x40110a
  (gdb) run
  Starting program: /tmp/a.out

  Breakpoint 1, 0x000000000040110a in foo ()
  (gdb) list
  1 extern int foo (void);
  2
  3 int
  4 main (void)
  5 {
  6   return foo ();
  7 }
  (gdb) list .
  Insufficient debug info for showing source lines at current PC (0x40110a).
  (gdb)

However, if we look at how GDB's TUI updates the source window during
a normal stop, we see that GDB does a better job of displaying the
expected contents.  Going back to our original example, when we start
GDB with:

  $ gdb -q a.out -tui -ex "b foo" -ex run

we do get the "[ No Source Available ]" message as expected.  Why is
that?

The answer is that, in this case GDB uses tui_show_frame_info to
update the source window, tui_show_frame_info is called each time a
prompt is displayed, like this:

  #0  tui_show_frame_info (fi=...) at ../../src/gdb/tui/tui-status.c:269
  #1  0x0000000000f55975 in tui_refresh_frame_and_register_information () at ../../src/gdb/tui/tui-hooks.c:118
  #2  0x0000000000f55ae8 in tui_before_prompt (current_gdb_prompt=0x31ef930 <top_prompt+16> "(gdb) ") at ../../src/gdb/tui/tui-hooks.c:165
  #3  0x000000000090ea45 in std::_Function_handler<void(char const*), void (*)(char const*)>::_M_invoke (__functor=..., __args#0=@0x7ffc955106b0: 0x31ef930 <top_prompt+16> "(gdb) ") at /usr/include/c++/9/bits/std_function.h:300
  #4  0x00000000009020df in std::function<void(char const*)>::operator() (this=0x5281260, __args#0=0x31ef930 <top_prompt+16> "(gdb) ") at /usr/include/c++/9/bits/std_function.h:688
  #5  0x0000000000901c35 in gdb::observers::observable<char const*>::notify (this=0x31dda00 <gdb::observers::before_prompt>, args#0=0x31ef930 <top_prompt+16> "(gdb) ") at ../../src/gdb/../gdbsupport/observable.h:166
  #6  0x00000000008ffed8 in notify_before_prompt (prompt=0x31ef930 <top_prompt+16> "(gdb) ") at ../../src/gdb/event-top.c:518
  #7  0x00000000008fff08 in top_level_prompt () at ../../src/gdb/event-top.c:534
  #8  0x00000000008ffdeb in display_gdb_prompt (new_prompt=0x0) at ../../src/gdb/event-top.c:487

If we look at how tui_show_frame_info figures out what source to
display, it doesn't use get_current_source_symtab_and_line(), instead,
it finds a symtab_and_line directly from a frame_info_pt.  This means
we are not dependent on get_current_source_symtab_and_line() returning
the current location (which it does not).

I propose that we change tui_source_window_base::rerender() so that,
for the case we are discussing here (the inferior has a selected
frame, but the source window has no contents), we move away from using
get_current_source_symtab_and_line(), and instead use find_frame_sal
instead, like tui_show_frame_info does.

This means that we will always use the inferior's current location.

Tested on x86_64-linux.

Reviewed-By: Tom de Vries <tdevries@suse.de>
Reported-By: Andrew Burgess <aburgess@redhat.com>
Co-Authored-By: Andrew Burgess <aburgess@redhat.com>
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32614
gdb/testsuite/gdb.tui/resize-3-foo.c [new file with mode: 0644]
gdb/testsuite/gdb.tui/resize-3-main.c [new file with mode: 0644]
gdb/testsuite/gdb.tui/resize-3.exp [new file with mode: 0644]
gdb/tui/tui-winsource.c