]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commit
Fix GDB reverse-step and reverse-next command behavior
authorCarl Love <cel@linux.ibm.com>
Tue, 2 Jan 2024 22:46:12 +0000 (17:46 -0500)
committerCarl Love <cel@linux.ibm.com>
Tue, 2 Jan 2024 22:46:12 +0000 (17:46 -0500)
commitd04ead7406f5fe8b2079497355b700afa4034645
treef367886e477f16e4de6b6b8dd9df7c73147c7d22
parentfe6356def678a93121a68147bdf93b6980bbf75d
Fix GDB reverse-step and reverse-next command behavior

Currently GDB when executing in reverse over multiple statements in a single
line of source code, GDB stops in the middle of the line.  Thus requiring
multiple commands to reach the previous line.  GDB should stop at the first
instruction of the line, not in the middle of the line.

The following description of the incorrect behavior was taken from an
earlier message by Pedro Alves <pedro@palves.net>:

https://sourceware.org/pipermail/gdb-patches/2023-January/196110.html

---------------------------------

The source line looks like:

   func1 ();  func2 ();

in the test case:

(gdb) list 1
1       void func1 ()
2       {
3       }
4
5       void func2 ()
6       {
7       }
8
9       int main ()
10      {
11        func1 (); func2 ();
12      }

compiled with:

 $ gcc reverse.c -o reverse -g3 -O0
 $ gcc -v
 ...
 gcc version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04)

Now let's debug it with target record, using current gdb git master
(f3d8ae90b236),

 $ gdb ~/reverse
 GNU gdb (GDB) 14.0.50.20230124-git
 ...
 Reading symbols from /home/pedro/reverse...
 (gdb) start
 Temporary breakpoint 1 at 0x1147: file reverse.c, line 11.
 Starting program: /home/pedro/reverse
 [Thread debugging using libthread_db enabled]
 Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

 Temporary breakpoint 1, main () at reverse.c:11
 11        func1 (); func2 ();
 (gdb) record

 (gdb) disassemble /s
 Dump of assembler code for function main:
 reverse.c:
 10      {
    0x000055555555513f <+0>:     endbr64
    0x0000555555555143 <+4>:     push   %rbp
    0x0000555555555144 <+5>:     mov    %rsp,%rbp

 11        func1 (); func2 ();
 => 0x0000555555555147 <+8>:     mov    $0x0,%eax
    0x000055555555514c <+13>:    call   0x555555555129 <func1>
    0x0000555555555151 <+18>:    mov    $0x0,%eax
    0x0000555555555156 <+23>:    call   0x555555555134 <func2>
    0x000055555555515b <+28>:    mov    $0x0,%eax

 12      }
    0x0000555555555160 <+33>:    pop    %rbp
    0x0000555555555161 <+34>:    ret
 End of assembler dump.

 (gdb) n
 12      }

So far so good, a "next" stepped over the whole of line 11 and stopped at
line 12.

Let's confirm where we are now:

 (gdb) disassemble /s
 Dump of assembler code for function main:
 reverse.c:
 10      {
    0x000055555555513f <+0>:     endbr64
    0x0000555555555143 <+4>:     push   %rbp
    0x0000555555555144 <+5>:     mov    %rsp,%rbp

 11        func1 (); func2 ();
    0x0000555555555147 <+8>:     mov    $0x0,%eax
    0x000055555555514c <+13>:    call   0x555555555129 <func1>
    0x0000555555555151 <+18>:    mov    $0x0,%eax
    0x0000555555555156 <+23>:    call   0x555555555134 <func2>
    0x000055555555515b <+28>:    mov    $0x0,%eax

 12      }
 => 0x0000555555555160 <+33>:    pop    %rbp
    0x0000555555555161 <+34>:    ret
 End of assembler dump.

Good, we're at the first instruction of line 12.

Now let's undo the "next", with "reverse-next":

 (gdb) reverse-next
 11        func1 (); func2 ();

Seemingly stopped at line 11.  Let's see exactly where:

 (gdb) disassemble /s
 Dump of assembler code for function main:
 reverse.c:
 10      {
    0x000055555555513f <+0>:     endbr64
    0x0000555555555143 <+4>:     push   %rbp
    0x0000555555555144 <+5>:     mov    %rsp,%rbp

 11        func1 (); func2 ();
    0x0000555555555147 <+8>:     mov    $0x0,%eax
    0x000055555555514c <+13>:    call   0x555555555129 <func1>
 => 0x0000555555555151 <+18>:    mov    $0x0,%eax
    0x0000555555555156 <+23>:    call   0x555555555134 <func2>
    0x000055555555515b <+28>:    mov    $0x0,%eax

 12      }
    0x0000555555555160 <+33>:    pop    %rbp
    0x0000555555555161 <+34>:    ret
 End of assembler dump.
 (gdb)

And lo, we stopped in the middle of line 11!  That is a bug, we should have
stepped back all the way to the beginning of the line.  The "reverse-next"
should have fully undone the prior "next" command.

--------------------

This patch fixes the incorrect GDB behavior by ensuring that GDB  stops at
the first instruction in the line.

The test case gdb.reverse/func-map-to-same-line.exp is added to testsuite
to verify this fix when the line table information is and is not available.
gdb/infcmd.c
gdb/testsuite/gdb.mi/mi-reverse.exp
gdb/testsuite/gdb.reverse/finish-reverse-next.exp
gdb/testsuite/gdb.reverse/func-map-to-same-line.c [new file with mode: 0644]
gdb/testsuite/gdb.reverse/func-map-to-same-line.exp [new file with mode: 0644]