Re: [PATCH 7/7] Reset Windows hardware breakpoints on executable's entry point

Pedro Alves
2020-05-27T12:07:13Z

On 5/25/20 7:56 PM, Hannes Domani via Gdb-patches wrote:
> Fixes these testsuite fails on Windows (actually more, but the others are
> cascading failures):
> FAIL: gdb.base/hbreak2.exp: hardware breakpoint insertion (the program exited)
> FAIL: gdb.base/hbreak2.exp: run until function breakpoint (the program exited)
> FAIL: gdb.base/hbreak2.exp: run to factorial(6) (the program exited)
> FAIL: gdb.base/hbreak2.exp: run until hardware function breakpoint, optimized file (the program exited)
>
> The problem happens if you only have hardware breakpoints active when
> (re-)starting the program:
>
> (gdb) start
> Temporary breakpoint 1 at 0x401650: file C:/src/repos/binutils-gdb.git/gdb/tests
> uite/gdb.base/break.c, line 43.
> Starting program: C:\gdb\build64\gdb-git\gdb\testsuite\outputs\gdb.base\hbreak2\
> hbreak2.exe
>
> Temporary breakpoint 1, main (argc=1, argv=0x7e2120, envp=0x7e2900)
> at C:/src/repos/binutils-gdb.git/gdb/testsuite/gdb.base/break.c:43
> 43 if (argc == 12345) { /* an unlikely value < 2^16, in case uninited
> */ /* set breakpoint 6 here */
> (gdb) hb factorial
> Hardware assisted breakpoint 2 at 0x401703: file C:/src/repos/binutils-gdb.git/g
> db/testsuite/gdb.base/break.c, line 63.
> (gdb) r
> The program being debugged has been started already.
> Start it from the beginning? (y or n) y
> Starting program: C:\gdb\build64\gdb-git\gdb\testsuite\outputs\gdb.base\hbreak2\
> hbreak2.exe
> 720
> [Inferior 1 (process 7836) exited normally]
>
> But if you stopped just once before reaching the hardware breakpoint, it
> works fine:
>
> (gdb) start
> Temporary breakpoint 3 at 0x401650: file C:/src/repos/binutils-gdb.git/gdb/tests
> uite/gdb.base/break.c, line 43.
> Starting program: C:\gdb\build64\gdb-git\gdb\testsuite\outputs\gdb.base\hbreak2\
> hbreak2.exe
>
> Temporary breakpoint 3, main (argc=1, argv=0x322120, envp=0x322900)
> at C:/src/repos/binutils-gdb.git/gdb/testsuite/gdb.base/break.c:43
> 43 if (argc == 12345) { /* an unlikely value < 2^16, in case uninited
> */ /* set breakpoint 6 here */
> (gdb) c
> Continuing.
>
> Breakpoint 2, factorial (value=6)
> at C:/src/repos/binutils-gdb.git/gdb/testsuite/gdb.base/break.c:63
> 63 if (value > 1) { /* set breakpoint 7 here */
>
> I found out that cdb writes this error when trying to do the same:
>
> Unable to set breakpoint error
> The system resets thread contexts after the process
> breakpoint so hardware breakpoints cannot be set.
> Go to the executable's entry point and set it then.
>
> So all the hardware breakpoints that were set before (or rather, their
> debug register information) are practically lost when the process entry
> point is reached.
>
> This patch creates an internal breakpoint on the process entry point, which
> when it is reached, resets all active hardware breakpoints, and continues
> execution.

Eh, I always assumed that the initial breakpoint the Windows debug API emits
during process initialization _was_ the entry point. Where does the PC
point at when the initial breakpoint is reached?

You can use "starti" to check that. "starti" spawns the process with
target_create_inferior, and then just does not run any other instruction,
It presents the stop where target_create_inferior left the process, which
is supposedly the process's entry point.

If Windows indeed resets the thread context after the initial
process breakpoint, then it sounds like we also lose any change to
the registers you make after "starti".

E.g., if you do "starti" + "p $rax = 0xabc" + "stepi", or something like
that.

It it sounding to me like we should be running to the entry point
in the initialization loop, from within do_initial_windows_stuff?

Thanks,
Pedro Alves