Bug 28616 - GDB doesn't rollback displaced stepping state after a failure to insert hardware watchpoints
Summary: GDB doesn't rollback displaced stepping state after a failure to insert hardw...
Status: NEW
Alias: None
Product: gdb
Classification: Unclassified
Component: gdb (show other bugs)
Version: HEAD
: P2 normal
Target Milestone: ---
Assignee: Luis Machado
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2021-11-22 15:49 UTC by Luis Machado
Modified: 2023-05-31 09:47 UTC (History)
2 users (show)

See Also:
Host: x86_64-linux-gnu
Target: x86_64-linux-gnu
Build: x86_64-linux-gnu
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Luis Machado 2021-11-22 15:49:31 UTC
I first noticed this one on aarch64-linux-gnu, but it also reproduces on x86_64-linux-gnu. It is very likely this will reproduce on any native targets that implement/override the low_prepare_to_resume method and throw an error from it.

Follows a reproducer. The binary can be any dummy binary with a main function (I used a hello world).

---

./gdb/gdb /tmp/hello -ex "start" -ex "b" -ex "watch *0xffffffffdeadbeef"
GNU gdb (GDB) 12.0.50.20211119-git
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /tmp/hello...
Temporary breakpoint 1 at 0x115c: file /tmp/hello.c, line 5.
Starting program: /tmp/hello 

Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe558) at /tmp/hello.c:5
5	  printf ("Hello world!\n");
Breakpoint 2 at 0x55555555515c: file /tmp/hello.c, line 5.
Hardware watchpoint 3: *0xffffffffdeadbeef
(gdb) c
Continuing.
Couldn't write debug register: Invalid argument.
(gdb) bt
#0  0x0000555555555062 in _start ()
(gdb) 

---

So there are a few things going on:

1 - We are stopped on top of a breakpoint.
2 - Moving the program means we need to step over such a breakpoint.
3 - The target supports displaced stepping, and so stepping over the breakpoint means doing a displaced stepping.
4 - We have an impossible hardware watchpoint that will trigger an error when we attempt to move the program and thus write the proper debug register information.
5 - The code in infrun.c:keep_going_pass_signal, more specifically when it calls "resume", is not guarded against faults. "resume_1" is guarded, but doesn't handle this situation properly like infrun.c:keep_going_pass_signal does when calling "insert_breakpoints".

As shown above, GDB gets an unexpected error from the low_prepare_to_resume method, goes through infrun.c:resume_1's catch block and then re-throws the exception. So GDB never attempts to rollback the state of displaced stepping, leaving the PC pointing at the scratch pad location.

If we disable displaced stepping, we have the following:

---
./gdb/gdb /tmp/hello -ex "set displaced-stepping off" -ex "start" -ex "b" -ex "watch *0xffffffffdeadbeef"
GNU gdb (GDB) 12.0.50.20211119-git
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /tmp/hello...
Temporary breakpoint 1 at 0x115c: file /tmp/hello.c, line 5.
Starting program: /tmp/hello 

Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe558) at /tmp/hello.c:5
5	  printf ("Hello world!\n");
Breakpoint 2 at 0x55555555515c: file /tmp/hello.c, line 5.
Hardware watchpoint 3: *0xffffffffdeadbeef
(gdb) c
Continuing.
Couldn't write debug register: Invalid argument.
(gdb) bt
#0  main (argc=1, argv=0x7fffffffe558) at /tmp/hello.c:5
(gdb) 
---

I thought about this a little, and adding a displaced_step_finish call in one of the catch blocks of either resume/resume_1 seems to work. But I haven't done further testing with it. It didn't seem to have any regressions.

The documentation of low_prepare_to_resume doesn't mention anything about implementations being forbidden to throw, so I guess this is an oversight.
Comment 1 Joel Brobecker 2022-02-13 14:08:19 UTC
Hi Luis,

IIUC, I think you set the target milestone for this PR to 12.1. As a side-effect, this is taken as indicating this bug needs to be fixed before we can release GDB 12. Was that your intention, and if yes, can you provide more details why?
Comment 2 Joel Brobecker 2022-03-07 11:42:58 UTC
As discussed on gdb-patches: Removing target milestone date, to reflect the fact that this is not deemed release-blocking.
Comment 3 Luis Machado 2022-03-07 12:00:59 UTC
I dug this up and noticed I did send a patch to the ML, but unfortunately I received no feedback on it and it went to patch limbo. :-)

I'll pursue it again.

https://sourceware.org/pipermail/gdb-patches/2021-June/179691.html
Comment 4 Luis Machado 2022-03-07 12:02:56 UTC
Ah, nevermind. It was a similar issue. The one I posted was an earlier displaced-stepping-related bug as well.