From 187b331e9ed9d5927b7896bc82d927380df83681 Mon Sep 17 00:00:00 2001 From: "K. Lange" Date: Wed, 2 Feb 2022 20:53:23 +0900 Subject: [PATCH] ptrace: fix delivery of final signals, improve dbg --- apps/dbg.c | 51 ++++++++++++++++++++++++++++++++++++++++++++- kernel/sys/ptrace.c | 34 ++++++++++++++++++++++++++---- 2 files changed, 80 insertions(+), 5 deletions(-) diff --git a/apps/dbg.c b/apps/dbg.c index 45accebb..7299afea 100644 --- a/apps/dbg.c +++ b/apps/dbg.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -422,6 +423,32 @@ static void attempt_backtrace(pid_t pid, struct regs * regs) { } } +static int imatch(const char * a, const char * b) { + do { + if (!*a && !*b) return 1; + if (tolower(*a) != tolower(*b)) return 0; + a++; + b++; + } while (1); +} + +static int signal_from_string(const char * str) { + if (isdigit(*str)) { + return strtoul(str,NULL,0); + } else if (str[0] == 'S' && str[1] == 'I' && str[2] == 'G') { + for (int i = 0; i < 256; ++i) { + if (signal_names[i] && imatch(signal_names[i], str)) return i; + } + return -1; + } else { + for (int i = 0; i < 256; ++i) { + if (signal_names[i] && imatch(signal_names[i]+3, str)) return i; + } + return -1; + } + + return -1; +} static void show_commandline(pid_t pid, int status, struct regs * regs) { @@ -492,6 +519,18 @@ static void show_commandline(pid_t pid, int status, struct regs * regs) { if (signum == SIGINT) signum = 0; ptrace(PTRACE_CONT, pid, NULL, (void*)(uintptr_t)signum); return; + } else if (!strcmp(buf, "signal")) { + if (!arg) { + fprintf(stderr, "'signal' needs an argument\n"); + continue; + } + int signum = signal_from_string(arg); + if (signum == -1) { + fprintf(stderr, "'%s' is not a recognized signal\n", arg); + continue; + } + ptrace(PTRACE_CONT, pid, NULL, (void*)(uintptr_t)signum); + return; } else if (!strcmp(buf, "step") || !strcmp(buf,"s")) { int signum = WSTOPSIG(status); if (signum == SIGINT) signum = 0; @@ -566,6 +605,16 @@ static void show_commandline(pid_t pid, int status, struct regs * regs) { } } printf("\n"); + } else if (!strcmp(buf, "help")) { + printf("commands:\n" + " show (regs, libs)\n" + " backtrace\n" + " continue\n" + " signal signum\n" + " step\n" + " poke addr byte\n" + " print fmt addr\n"); + continue; } else { fprintf(stderr, "dbg: unrecognized command '%s'\n", buf); continue; @@ -575,7 +624,7 @@ static void show_commandline(pid_t pid, int status, struct regs * regs) { _exitDebugger: if (binary_is_child) { fprintf(stderr, "Terminating child process '%d'.\n", pid); - ptrace(PTRACE_CONT, pid, NULL, (void*)(uintptr_t)SIGKILL); + ptrace(PTRACE_DETACH, pid, NULL, (void*)(uintptr_t)SIGKILL); } exit(0); } diff --git a/kernel/sys/ptrace.c b/kernel/sys/ptrace.c index 8ddcb949..4cb95697 100644 --- a/kernel/sys/ptrace.c +++ b/kernel/sys/ptrace.c @@ -86,14 +86,38 @@ long ptrace_signal(int signal, int reason) { return signum; } +static void signal_and_continue(pid_t pid, process_t * tracee, int sig) { + /* Unsuspend */ + __sync_and_and_fetch(&tracee->flags, ~(PROC_FLAG_SUSPENDED)); + + /* Does the process have a pending signal? */ + if ((tracee->status >> 8) & 0xFF && !(tracee->status >> 16)) { + tracee->status = (sig << 8); + make_process_ready(tracee); + } else if (sig) { + send_signal(pid, sig,1); + } else { + make_process_ready(tracee); + } +} + long ptrace_continue(pid_t pid, int sig) { process_t * tracee = process_from_pid(pid); if (!tracee || (tracee->tracer != this_core->current_process->id) || !(tracee->flags & PROC_FLAG_SUSPENDED)) return -ESRCH; - /* Unsuspend */ - __sync_and_and_fetch(&tracee->flags, ~(PROC_FLAG_SUSPENDED)); - tracee->status = (sig << 8); - make_process_ready(tracee); + signal_and_continue(pid,tracee,sig); + + return 0; +} + +long ptrace_detach(pid_t pid, int sig) { + process_t * tracee = process_from_pid(pid); + if (!tracee || (tracee->tracer != this_core->current_process->id) || !(tracee->flags & PROC_FLAG_SUSPENDED)) return -ESRCH; + + /* Mark us not the tracer. */ + tracee->tracer = 0; + + signal_and_continue(pid,tracee,sig); return 0; } @@ -200,6 +224,8 @@ long ptrace_handle(long request, pid_t pid, void * addr, void * data) { return ptrace_signals_only(pid); case PTRACE_SINGLESTEP: return ptrace_singlestep(pid,(uintptr_t)data); + case PTRACE_DETACH: + return ptrace_detach(pid,(uintptr_t)data); default: return -EINVAL; }