diff options
author | Matt Hunter <m@lfurio.us> | 2025-09-03 01:21:34 -0400 |
---|---|---|
committer | Matt Hunter <m@lfurio.us> | 2025-09-07 21:03:26 -0400 |
commit | 0096d1896083f0df73e086b1e086ec52f610b7bf (patch) | |
tree | 91cc89f685a6dedc7ef57e784ff1c3c80df24b03 | |
parent | 95364d5a74eb9977b946b4a520eb2624f2c788ab (diff) | |
download | misplays-0096d1896083f0df73e086b1e086ec52f610b7bf.tar.gz misplays-0096d1896083f0df73e086b1e086ec52f610b7bf.zip |
Previously, there was a bug on PTRACE_EVENT_FORK in which the forked
child process inherits all installed breakpoints due to their interrupt
instructions being resident in memory at the time of the fork, but the
debugger initializes the new process model with an empty list of
breakpoints.
There are some differing opinions on what the correct behavior ought to
be here, but at a minimum these two realities must be brought into sync
to prevent data corruption or any process crash of the fork child.
For the time being, manually "uninstall" the residual breakpoint
interrupts from a newly forked child that we attach to, leaving it with
no breakpoints of any kind. Process model initialization in the
debugger is left as-is.
Signed-off-by: Matt Hunter <m@lfurio.us>
-rw-r--r-- | debugger.c | 11 |
1 files changed, 11 insertions, 0 deletions
@@ -113,6 +113,15 @@ static void uninstall_breakpoints(struct thread *th) { } } +static void clean_fork_breakpoints(struct thread *th, const struct process *parent) { + const struct list *breaks = &parent->breakpoints; + for (struct breakpoint *b = breaks->tail; b != breaks->end; b = b->prev) { + if (b->installed) { + ptrace(PTRACE_POKETEXT, th->id, b->address, b->text); + } + } +} + static int detect_breakpoint(struct thread *th, int *restart) { int is_bp = 0; /* at least 1 effective breakpoint at this PC */ int is_user = 0; /* at least 1 user-defined bp at this PC */ @@ -393,6 +402,8 @@ static int wait_thread(struct thread *th) { //while (!wait_thread(eventth)) {} dbg_sync(eventproc); + clean_fork_breakpoints(eventth, th->proc); + th->stopped = 1; th->signal = 0; th->doing = 0; |