diff options
author | Carl Love <cel@linux.ibm.com> | 2024-01-02 17:46:12 -0500 |
---|---|---|
committer | Carl Love <cel@linux.ibm.com> | 2024-01-02 17:46:12 -0500 |
commit | d04ead7406f5fe8b2079497355b700afa4034645 (patch) | |
tree | f367886e477f16e4de6b6b8dd9df7c73147c7d22 /gdb/infcmd.c | |
parent | fe6356def678a93121a68147bdf93b6980bbf75d (diff) | |
download | fsf-binutils-gdb-d04ead7406f5fe8b2079497355b700afa4034645.zip fsf-binutils-gdb-d04ead7406f5fe8b2079497355b700afa4034645.tar.gz fsf-binutils-gdb-d04ead7406f5fe8b2079497355b700afa4034645.tar.bz2 |
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.
Diffstat (limited to 'gdb/infcmd.c')
-rw-r--r-- | gdb/infcmd.c | 13 |
1 files changed, 13 insertions, 0 deletions
diff --git a/gdb/infcmd.c b/gdb/infcmd.c index 511cf5f..a3c3279 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -976,6 +976,19 @@ prepare_one_step (thread_info *tp, struct step_command_fsm *sm) &tp->control.step_range_start, &tp->control.step_range_end); + if (execution_direction == EXEC_REVERSE) + { + symtab_and_line sal = find_pc_line (pc, 0); + symtab_and_line sal_start + = find_pc_line (tp->control.step_range_start, 0); + + if (sal.line == sal_start.line) + /* Executing in reverse, the step_range_start address is in + the same line. We want to stop in the previous line so + move step_range_start before the current line. */ + tp->control.step_range_start--; + } + /* There's a problem in gcc (PR gcc/98780) that causes missing line table entries, which results in a too large stepping range. Use inlined_subroutine info to make the range more narrow. */ |