]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commit
Always show locations for breakpoints & show canonical location spec
authorPedro Alves <pedro@palves.net>
Tue, 17 May 2022 12:12:04 +0000 (13:12 +0100)
committerPedro Alves <pedro@palves.net>
Mon, 23 May 2022 19:31:43 +0000 (20:31 +0100)
commit11d68f5901a633c30f989fe52c08311c90d028ae
tree06ac17db6424890deccf53788f96af976416a111
parente8123c847f61c7458200b349615c47e9df17a0ed
Always show locations for breakpoints & show canonical location spec

I've thought for a few years that "info breakpoints" should show BOTH
the canonical location spec behind each breakpoint, and the actual
resolved location(s) where the breakpoint is inserted.  It currently
only shows the latter.

Here are for example 3 breakpoints that I set while debugging gdb:

 (top-gdb) info breakpoints
 Num     Type           Disp Enb Address            What
 1       breakpoint     keep y   0x0000000000575127 in internal_error(char const*, int, char const*, ...) at src/gdb/common/errors.c:54
 2       breakpoint     keep y   0x0000000000575127 in internal_error(char const*, int, char const*, ...) at src/gdb/common/errors.c:54
 3       breakpoint     keep y   <MULTIPLE>
 3.1                         y   0x0000000000575127 in internal_error(char const*, int, char const*, ...) at src/gdb/common/errors.c:54
 3.2                         y   0x00007ffff6d50410 in PyErr_SetObject at /usr/src/debug/python2-2.7.15-4.fc27.x86_64/Python/errors.c:54
 (top-gdb)

From looking at those, you have no idea how I created the breakpoints
in the first place, which specs I used.  Breakpoints 1 and 2 look like
the same from that output, but really aren't.  I'll have forgotten
after a while which was which though.  And what's with the third
breakpoint, showing seemingly unrelated functions in its locations?

GDB of course knows all those breakpoints were set differently.  It
needs to remember the location specs in order to re_set the locations
properly.  And it needs to remember the spec in order to save the
breakpoints, like:

 (top-gdb) save breakpoints bpts.cmd
 Saved to file 'bpts.cmd'.

Let's look at the file, see how the breakpoints had been created:

 (top-gdb) shell cat bpts.cmd
 break internal_error
 break -qualified internal_error
 break errors.c:54
 (top-gdb)

Ah, the "-qualified" information for breakpoint 2 was lost from "info
breakpoints" output.  And now it's obvious why we have two locations
for breakpoint 3 -- that breakpoint was set by FILE:LINE, and GDB
resolved that to two locations in unrelated functions that happen to
be implemented in files with the same name.

I propose that we show this info in "info breakpoints" too, with a
conceptualy simple change that just removes special cases.  To get
there, let's observe a fact -- there are a couple cases where "info
breakpoints" prints the breakpoint's locations in their own rows:

#1 - when the breakpoint has multiple locations:

 (gdb) info breakpoints
 Num     Type           Disp Enb Address            What
 1       breakpoint     keep y   <MULTIPLE>
 1.1                         y   0x0000000000a2d874 in func(int) at func.c:51
 1.2                         y   0x0000000000b2d640 in func(int) at func2.c:51

#2 - when the breakpoint only has one location, but it is disabled,
     while the breakpoint itself is enabled.  E.g.:

 (gdb) info breakpoints
 Num     Type           Disp Enb Address            What
 1       breakpoint     keep y   0x0000000000a2d874 in func(int) at func.c:51
 (gdb) disable 1.1
 (gdb) info breakpoints
 Num     Type           Disp Enb Address            What
 1       breakpoint     keep y   <MULTIPLE>
 1.1                         n   0x0000000000a2d874 in func(int) at func.c:51

(the last example shows <MULTIPLE> when there's only one location, but
let's ignore that...)

Note that when we print the locations in a separate row, the "What"
column for the breakpoint header row is empty.  That seems to me to be
the perfect spot to put the breakpoint's location spec.

Then, if we make it such that breakpoints always print their locations
in separate rows, even if they only have one location, that space is
always there to use.  The result for the confusing example at the top
would be this:

 (top-gdb) info breakpoints
 Num     Type           Disp Enb Address            What
 1       breakpoint     keep y                      internal_error
 1.1                         y   0x00000000005755a5 in internal_error(char const*, int, char const*, ...) at src/gdb/common/errors.c:54
 2       breakpoint     keep y                      -qualified internal_error
 2.1                         y   0x00000000005755a5 in internal_error(char const*, int, char const*, ...) at src/gdb/common/errors.c:54
 3       breakpoint     keep y                      errors.c:54
 3.1                         y   0x00000000005755a5 in internal_error(char const*, int, char const*, ...) at src/gdb/common/errors.c:54
 3.2                         y   0x00007ffff6d50410 in PyErr_SetObject at /usr/src/debug/python2-2.7.15-4.fc27.x86_64/Python/errors.c:54

(Note: this looks better on a terminal with color.)

Breakpoints would no longer move from single-location to
multiple-location "display modes" as locations were added/removed
(e.g., when a shared library is loaded), they'd always be in
multi-location display mode.  And we'd get rid of the "breakpoint has
a single location that is disabled" special case.

Now, after using this for a while, I came to wish that the output
would give a better visual clue on each group of "breakpoint + its
locations".  This commit implements that by simply indenting the
location number by one space, like so:

 (top-gdb) info breakpoints
 Num     Type           Disp Enb Address            What
 1       breakpoint     keep y                      internal_error
  1.1                        y   0x00000000005755a5 in internal_error(char const*, int, char const*, ...) at src/gdb/common/errors.c:54
 2       breakpoint     keep y                      -qualified internal_error
  2.1                        y   0x00000000005755a5 in internal_error(char const*, int, char const*, ...) at src/gdb/common/errors.c:54
 3       breakpoint     keep y                      errors.c:54
  3.1                        y   0x00000000005755a5 in internal_error(char const*, int, char const*, ...) at src/gdb/common/errors.c:54
  3.2                        y   0x00007ffff6d50410 in PyErr_SetObject at /usr/src/debug/python2-2.7.15-4.fc27.x86_64/Python/errors.c:54

The need for grouping is clearer if you have breakpoints with dozens
of locations, such as when you do "b main" when debugging GDB.

Another interesting case where this commit helps is when the user sets
a breakpoint by line number, and the line corresponds to a comment or
empty line, or to code that was optimized away.  E.g., again when
debugging GDB:

 (top-gdb) b 27
 Breakpoint 4 at 0x469aa6: file src/gdb/gdb.c, line 28.

Note I asked for line 27 but got line 28.

"info breakpoints" currently says:

 (top-gdb) info breakpoints 4
 Num     Type           Disp Enb Address            What
 4       breakpoint     keep y   0x0000000000469aa6 in main(int, char**) at src/gdb/gdb.c:28

Again here we lost the info about the original location spec, line 27.
While after this commit, we get:

 (top-gdb) info breakpoints 4
 Num     Type           Disp Enb Address            What
 4       breakpoint     keep y                      src/gdb/gdb.c:27
  4.1                        y   0x0000000000469aa6 in main(int, char**) at src/gdb/gdb.c:28

Lancelot is working on a GDB change that will make GDB slide each
breakpoint location's line independently, so we could end up with
something like this, even:

 (top-gdb) info breakpoints 4
 Num     Type           Disp Enb Address            What
 4       breakpoint     keep y                      func.cc:27
  4.1                        y   0x0000000000469aa6 in func<float>(float) at func.cc:28
  4.2                        y   0x000000000047abb8 in func<int>(int) at func.cc:30

The output for watchpoints and catchpoints is unmodified, they will
continue being printed like before, as we never print locations for
those:

 Num     Type           Disp Enb Address            What
 2       catchpoint     keep y                      syscall "<any syscall>"
 3       hw watchpoint  keep y                      *main

Before this commit can go in, I'll need to address testsuite fallout,
of course.  I expect this will be a significant effort, so I'm hoping
we can come to agreement on whether the GDB change is OK before
wasting time adjusting the testsuite.

Documentation adjustments included.  They also clean up a few tangent
things in the area of the docs I was adjusting to better match
reality.

Change-Id: Ic42ad8565e79ca67bfebb22cbb4794ea816fd08b
gdb/breakpoint.c
gdb/doc/gdb.texinfo
gdb/doc/guile.texi
gdb/doc/python.texi