ptrace: fix delivery of final signals, improve dbg

This commit is contained in:
K. Lange 2022-02-02 20:53:23 +09:00
parent 4c04e01f61
commit 187b331e9e
2 changed files with 80 additions and 5 deletions

View File

@ -13,6 +13,7 @@
#include <fcntl.h>
#include <getopt.h>
#include <signal.h>
#include <ctype.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/signal.h>
@ -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);
}

View File

@ -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;
}