From ee936125622325a4b33bafe336b44e44a24ce1aa Mon Sep 17 00:00:00 2001 From: Malfurious Date: Mon, 9 Oct 2023 16:08:34 -0400 Subject: Handle PTRACE_EVENT_EXIT to capture a final state snapshot Also, it is now possible for interrupt_all_threads to fail to stop threads in uninterruptable sleep (eg: the main thread during execve). This may happen in more general cases as well, but it is now common enough in that case to worry about. Signed-off-by: Malfurious --- debugger.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/debugger.c b/debugger.c index 5981660..18f91e1 100644 --- a/debugger.c +++ b/debugger.c @@ -16,6 +16,7 @@ static const int PTRACE_OPTIONS = PTRACE_O_TRACECLONE | PTRACE_O_TRACEEXEC | + PTRACE_O_TRACEEXIT | PTRACE_O_TRACESYSGOOD; static const int PTRACE_CHILD_OPTIONS = PTRACE_OPTIONS | PTRACE_O_EXITKILL; @@ -258,7 +259,7 @@ static void resume_threads(struct process *proc) { int once = 0; for (struct thread *th = threads->head; th != threads->end; th = th->next) { - if (th->doing == PTRACE_SINGLESTEP) { + if (th->stopped && th->doing == PTRACE_SINGLESTEP) { ptrace(PTRACE_SINGLESTEP, th->id, NULL, th->signal); th->stopped = 0; th->signal = 0; @@ -267,7 +268,7 @@ static void resume_threads(struct process *proc) { } for (struct thread *th = threads->head; th != threads->end; th = th->next) { - if (th->doing && th->doing != PTRACE_SINGLESTEP) { + if (th->stopped && th->doing && th->doing != PTRACE_SINGLESTEP) { if (!once) { usleep(SCHEDULER_DELAY); once = 1; @@ -349,6 +350,15 @@ static int wait_thread(struct thread *th) { th->state = NULL; return 1; + case SIGTRAP | (PTRACE_EVENT_EXIT << 8): + th->stopped = 1; + th->signal = 0; + th->doing = PTRACE_CONT; + th->donext = 0; + strcpy(th->status, "EXITING"); + th->state = NULL; + return 1; + case SIGTRAP | (PTRACE_EVENT_STOP << 8): th->stopped = 1; th->signal = 0; -- cgit v1.2.3