diff options
author | Malfurious <m@lfurio.us> | 2024-04-27 12:53:38 -0400 |
---|---|---|
committer | Malfurious <m@lfurio.us> | 2024-04-27 12:53:38 -0400 |
commit | ac95555111931d77b46ca6ad9fff51ae7db61be9 (patch) | |
tree | 3a95a169608dca3740f21af2cdb3dc0df545ed56 /debugger.c | |
parent | b3adf1817b24bdcff3b2ecc1128ec5fa9e57fd23 (diff) | |
download | misplays-ac95555111931d77b46ca6ad9fff51ae7db61be9.tar.gz misplays-ac95555111931d77b46ca6ad9fff51ae7db61be9.zip |
Fix removal of temporary breakpoints when rapidly restarting thread
This bug would occur when the debugger keeps rapidly hitting a
breakpoint and restarting execution (and the breakpoint is temporary /
one-time). For example, stepping over a long recursive call.
It would be possible for the user to manually interrupt execution at the
precise moment that the debugee was returning from a single step over
the breakpoint. In this scenario, the thread would correctly remain
stopped as requested, however the temporary breakpoint would incorrectly
remain in the breakpoint list. The cause of this issue is that
uninstall_breakpoints only considered removing temporaries if they were
currently installed for use.
This makes sense, as we have used the b->installed flag as a sort of
check to see if we have YET installed the breakpoint (rather than "is it
STILL installed?") to ensure that we don't remove it too soon.
The more accurate logic here is to acctually check whether the
breakpoint has EVER been installed and only then consider it for removal
if it is temporary. This fixes the case in question without breaking
behavior when performing an initial run single step.
Signed-off-by: Malfurious <m@lfurio.us>
Diffstat (limited to 'debugger.c')
-rw-r--r-- | debugger.c | 19 |
1 files changed, 10 insertions, 9 deletions
@@ -79,6 +79,7 @@ static void install_breakpoints(struct thread *th) { word = (word & ~0xff) | BREAKPOINT_INSN; ptrace(PTRACE_POKETEXT, th->id, b->address, word); b->installed = 1; + b->previously_installed = 1; } } } @@ -89,16 +90,15 @@ static void uninstall_breakpoints(struct thread *th) { if (b->installed) { ptrace(PTRACE_POKETEXT, th->id, b->address, b->text); b->installed = 0; + } - if (b->enabled < 0) { - struct thread *t; - if (b->tid == 0 || - ((t = thread_by_id(th->proc, b->tid)) && !t->doing)) { - struct breakpoint *del = b; - b = b->next; - list_remove(del); - free(del); - } + if (b->previously_installed && b->enabled < 0) { + struct thread *t = NULL; + if (b->tid == 0 || ((t = thread_by_id(th->proc, b->tid)) && !t->doing)) { + struct breakpoint *del = b; + b = b->next; + list_remove(del); + free(del); } } } @@ -434,6 +434,7 @@ struct breakpoint *add_breakpoint(struct process *proc, unsigned long address) { b->address = address; b->text = 0; b->installed = 0; + b->previously_installed = 0; b->hits = 0; b->user = 1; b->stack = 0; |