ptrace: Catch signals, start work on debugger
This commit is contained in:
parent
7bf635c492
commit
470b2bfabb
227
apps/dbg.c
Normal file
227
apps/dbg.c
Normal file
@ -0,0 +1,227 @@
|
||||
/**
|
||||
* @brief Debugger.
|
||||
*
|
||||
* @copyright
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2021 K. Lange
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/signal_defs.h>
|
||||
#include <sys/sysfunc.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/time.h>
|
||||
#include <syscall_nums.h>
|
||||
|
||||
#include <toaru/rline.h>
|
||||
|
||||
struct regs {
|
||||
uintptr_t r15, r14, r13, r12;
|
||||
uintptr_t r11, r10, r9, r8;
|
||||
uintptr_t rbp, rdi, rsi, rdx, rcx, rbx, rax;
|
||||
uintptr_t int_no, err_code;
|
||||
uintptr_t rip, cs, rflags, rsp, ss;
|
||||
};
|
||||
|
||||
static void dump_regs(struct regs * r) {
|
||||
fprintf(stdout,
|
||||
" $rip=0x%016lx\n"
|
||||
" $rsi=0x%016lx,$rdi=0x%016lx,$rbp=0x%016lx,$rsp=0x%016lx\n"
|
||||
" $rax=0x%016lx,$rbx=0x%016lx,$rcx=0x%016lx,$rdx=0x%016lx\n"
|
||||
" $r8= 0x%016lx,$r9= 0x%016lx,$r10=0x%016lx,$r11=0x%016lx\n"
|
||||
" $r12=0x%016lx,$r13=0x%016lx,$r14=0x%016lx,$r15=0x%016lx\n"
|
||||
" cs=0x%016lx ss=0x%016lx rflags=0x%016lx int=0x%02lx err=0x%02lx\n",
|
||||
r->rip,
|
||||
r->rsi, r->rdi, r->rbp, r->rsp,
|
||||
r->rax, r->rbx, r->rcx, r->rdx,
|
||||
r->r8, r->r9, r->r10, r->r11,
|
||||
r->r12, r->r13, r->r14, r->r15,
|
||||
r->cs, r->ss, r->rflags, r->int_no, r->err_code
|
||||
);
|
||||
}
|
||||
|
||||
#define M(e) [e] = #e
|
||||
const char * signal_names[256] = {
|
||||
M(SIGHUP),
|
||||
M(SIGINT),
|
||||
M(SIGQUIT),
|
||||
M(SIGILL),
|
||||
M(SIGTRAP),
|
||||
M(SIGABRT),
|
||||
M(SIGEMT),
|
||||
M(SIGFPE),
|
||||
M(SIGKILL),
|
||||
M(SIGBUS),
|
||||
M(SIGSEGV),
|
||||
M(SIGSYS),
|
||||
M(SIGPIPE),
|
||||
M(SIGALRM),
|
||||
M(SIGTERM),
|
||||
M(SIGUSR1),
|
||||
M(SIGUSR2),
|
||||
M(SIGCHLD),
|
||||
M(SIGPWR),
|
||||
M(SIGWINCH),
|
||||
M(SIGURG),
|
||||
M(SIGPOLL),
|
||||
M(SIGSTOP),
|
||||
M(SIGTSTP),
|
||||
M(SIGCONT),
|
||||
M(SIGTTIN),
|
||||
M(SIGTTOUT),
|
||||
M(SIGVTALRM),
|
||||
M(SIGPROF),
|
||||
M(SIGXCPU),
|
||||
M(SIGXFSZ),
|
||||
M(SIGWAITING),
|
||||
M(SIGDIAF),
|
||||
M(SIGHATE),
|
||||
M(SIGWINEVENT),
|
||||
M(SIGCAT),
|
||||
};
|
||||
|
||||
static char * last_command = NULL;
|
||||
static void show_commandline(pid_t pid, int status, struct regs * regs) {
|
||||
|
||||
fprintf(stderr, "[Process %d, $rip=%#zx]\n",
|
||||
pid, regs->rip);
|
||||
|
||||
while (1) {
|
||||
char buf[4096] = {0};
|
||||
rline_exit_string = "";
|
||||
rline_exp_set_prompts("(dbg) ", "", 6, 0);
|
||||
rline_exp_set_syntax("dbg");
|
||||
rline_exp_set_tab_complete_func(NULL); /* TODO */
|
||||
if (rline(buf, 4096) == 0) goto _exitDebugger;
|
||||
|
||||
char *nl = strstr(buf, "\n");
|
||||
if (nl) *nl = '\0';
|
||||
if (!strlen(buf)) {
|
||||
if (last_command) {
|
||||
strcpy(buf, last_command);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
rline_history_insert(strdup(buf));
|
||||
rline_scroll = 0;
|
||||
if (last_command) free(last_command);
|
||||
last_command = strdup(buf);
|
||||
}
|
||||
|
||||
/* Tokenize just the first command */
|
||||
char * arg = NULL;
|
||||
char * sp = strstr(buf, " ");
|
||||
if (sp) {
|
||||
*sp = '\0';
|
||||
arg = sp + 1;
|
||||
}
|
||||
|
||||
if (!strcmp(buf, "show")) {
|
||||
if (!arg) {
|
||||
fprintf(stderr, "Things that can be shown:\n");
|
||||
fprintf(stderr, " regs\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(arg, "regs")) {
|
||||
dump_regs(regs);
|
||||
} else {
|
||||
fprintf(stderr, "Don't know how to show '%s'\n", arg);
|
||||
}
|
||||
} else if (!strcmp(buf, "continue") || !strcmp(buf,"c")) {
|
||||
int signum = WSTOPSIG(status);
|
||||
if (signum == SIGINT) signum = 0;
|
||||
ptrace(PTRACE_CONT, pid, NULL, (void*)(uintptr_t)signum);
|
||||
return;
|
||||
} else {
|
||||
fprintf(stderr, "dbg: unrecognized command '%s'\n", buf);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
_exitDebugger:
|
||||
fprintf(stderr, "Exiting.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static int usage(char * argv[]) {
|
||||
#define T_I "\033[3m"
|
||||
#define T_O "\033[0m"
|
||||
fprintf(stderr, "usage: %s command...\n"
|
||||
" -h " T_I "Show this help text." T_O "\n",
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "o:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
return (usage(argv), 0);
|
||||
case '?':
|
||||
return usage(argv);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind == argc) {
|
||||
return usage(argv);
|
||||
}
|
||||
|
||||
/* TODO find argv[optind] */
|
||||
/* TODO load symbols from it, and from its dependencies... with offsets... from ld.so... */
|
||||
|
||||
pid_t p = fork();
|
||||
if (!p) {
|
||||
if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) < 0) {
|
||||
fprintf(stderr, "%s: ptrace: %s\n", argv[0], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
execvp(argv[optind], &argv[optind]);
|
||||
return 1;
|
||||
} else {
|
||||
signal(SIGINT, SIG_IGN);
|
||||
|
||||
while (1) {
|
||||
int status = 0;
|
||||
pid_t res = waitpid(p, &status, WSTOPPED);
|
||||
|
||||
if (res < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
fprintf(stderr, "%s: waitpid: %s\n", argv[0], strerror(errno));
|
||||
} else {
|
||||
if (WIFSTOPPED(status)) {
|
||||
if (WSTOPSIG(status) == SIGTRAP) {
|
||||
/* Don't care about TRAP right now */
|
||||
ptrace(PTRACE_CONT, p, NULL, NULL);
|
||||
} else {
|
||||
printf("Program received signal %s.\n", signal_names[WSTOPSIG(status)]);
|
||||
|
||||
struct regs regs;
|
||||
ptrace(PTRACE_GETREGS, res, NULL, ®s);
|
||||
|
||||
show_commandline(res, status, ®s);
|
||||
}
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
fprintf(stderr, "Process %d was killed by %s.\n", res, signal_names[WTERMSIG(status)]);
|
||||
return 0;
|
||||
} else if (WIFEXITED(status)) {
|
||||
fprintf(stderr, "Process %d exited normally.\n", res);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
22
apps/sh.c
22
apps/sh.c
@ -422,19 +422,15 @@ void tab_complete_func(rline_context_t * c) {
|
||||
command_adj += 1;
|
||||
}
|
||||
|
||||
if (command_adj < argc && (!strcmp(argv[command_adj], "time"))) {
|
||||
cursor_adj -= 1;
|
||||
command_adj += 1;
|
||||
}
|
||||
|
||||
/* sudo should shift commands */
|
||||
if (command_adj < argc && (!strcmp(argv[command_adj], "sudo") || !strcmp(argv[command_adj], "gsudo"))) {
|
||||
cursor_adj -= 1;
|
||||
command_adj += 1;
|
||||
}
|
||||
|
||||
/* So should strace */
|
||||
if (command_adj < argc && (!strcmp(argv[command_adj], "strace"))) {
|
||||
/* Various commands are generally prefixes */
|
||||
if (command_adj < argc && (
|
||||
!strcmp(argv[command_adj], "sudo") ||
|
||||
!strcmp(argv[command_adj], "gsudo") ||
|
||||
!strcmp(argv[command_adj], "time") ||
|
||||
/* TODO: Both of these may take additional arguments... */
|
||||
!strcmp(argv[command_adj], "strace") ||
|
||||
!strcmp(argv[command_adj], "dbg")
|
||||
)) {
|
||||
cursor_adj -= 1;
|
||||
command_adj += 1;
|
||||
}
|
||||
|
319
apps/strace.c
319
apps/strace.c
@ -111,124 +111,163 @@ const char * syscall_names[] = {
|
||||
[SYS_SHUTDOWN] = "shutdown",
|
||||
};
|
||||
|
||||
#define M(e) [e] = #e
|
||||
const char * errno_names[256] = {
|
||||
#define ERRNO(e) [e] = #e
|
||||
ERRNO(EPERM),
|
||||
ERRNO(ENOENT),
|
||||
ERRNO(ESRCH),
|
||||
ERRNO(EINTR),
|
||||
ERRNO(EIO),
|
||||
ERRNO(ENXIO),
|
||||
ERRNO(E2BIG),
|
||||
ERRNO(ENOEXEC),
|
||||
ERRNO(EBADF),
|
||||
ERRNO(ECHILD),
|
||||
ERRNO(EAGAIN),
|
||||
ERRNO(ENOMEM),
|
||||
ERRNO(EACCES),
|
||||
ERRNO(EFAULT),
|
||||
ERRNO(ENOTBLK),
|
||||
ERRNO(EBUSY),
|
||||
ERRNO(EEXIST),
|
||||
ERRNO(EXDEV),
|
||||
ERRNO(ENODEV),
|
||||
ERRNO(ENOTDIR),
|
||||
ERRNO(EISDIR),
|
||||
ERRNO(EINVAL),
|
||||
ERRNO(ENFILE),
|
||||
ERRNO(EMFILE),
|
||||
ERRNO(ENOTTY),
|
||||
ERRNO(ETXTBSY),
|
||||
ERRNO(EFBIG),
|
||||
ERRNO(ENOSPC),
|
||||
ERRNO(ESPIPE),
|
||||
ERRNO(EROFS),
|
||||
ERRNO(EMLINK),
|
||||
ERRNO(EPIPE),
|
||||
ERRNO(EDOM),
|
||||
ERRNO(ERANGE),
|
||||
ERRNO(ENOMSG),
|
||||
ERRNO(EIDRM),
|
||||
ERRNO(ECHRNG),
|
||||
ERRNO(EL2NSYNC),
|
||||
ERRNO(EL3HLT),
|
||||
ERRNO(EL3RST),
|
||||
ERRNO(ELNRNG),
|
||||
ERRNO(EUNATCH),
|
||||
ERRNO(ENOCSI),
|
||||
ERRNO(EL2HLT),
|
||||
ERRNO(EDEADLK),
|
||||
ERRNO(ENOLCK),
|
||||
ERRNO(EBADE),
|
||||
ERRNO(EBADR),
|
||||
ERRNO(EXFULL),
|
||||
ERRNO(ENOANO),
|
||||
ERRNO(EBADRQC),
|
||||
ERRNO(EBADSLT),
|
||||
ERRNO(EDEADLOCK),
|
||||
ERRNO(EBFONT),
|
||||
ERRNO(ENOSTR),
|
||||
ERRNO(ENODATA),
|
||||
ERRNO(ETIME),
|
||||
ERRNO(ENOSR),
|
||||
ERRNO(ENONET),
|
||||
ERRNO(ENOPKG),
|
||||
ERRNO(EREMOTE),
|
||||
ERRNO(ENOLINK),
|
||||
ERRNO(EADV),
|
||||
ERRNO(ESRMNT),
|
||||
ERRNO(ECOMM),
|
||||
ERRNO(EPROTO),
|
||||
ERRNO(EMULTIHOP),
|
||||
ERRNO(ELBIN),
|
||||
ERRNO(EDOTDOT),
|
||||
ERRNO(EBADMSG),
|
||||
ERRNO(EFTYPE),
|
||||
ERRNO(ENOTUNIQ),
|
||||
ERRNO(EBADFD),
|
||||
ERRNO(EREMCHG),
|
||||
ERRNO(ELIBACC),
|
||||
ERRNO(ELIBBAD),
|
||||
ERRNO(ELIBSCN),
|
||||
ERRNO(ELIBMAX),
|
||||
ERRNO(ELIBEXEC),
|
||||
ERRNO(ENOSYS),
|
||||
ERRNO(ENOTEMPTY),
|
||||
ERRNO(ENAMETOOLONG),
|
||||
ERRNO(ELOOP),
|
||||
ERRNO(EOPNOTSUPP),
|
||||
ERRNO(EPFNOSUPPORT),
|
||||
ERRNO(ECONNRESET),
|
||||
ERRNO(ENOBUFS),
|
||||
ERRNO(EAFNOSUPPORT),
|
||||
ERRNO(EPROTOTYPE),
|
||||
ERRNO(ENOTSOCK),
|
||||
ERRNO(ENOPROTOOPT),
|
||||
ERRNO(ESHUTDOWN),
|
||||
ERRNO(ECONNREFUSED),
|
||||
ERRNO(EADDRINUSE),
|
||||
ERRNO(ECONNABORTED),
|
||||
ERRNO(ENETUNREACH),
|
||||
ERRNO(ENETDOWN),
|
||||
ERRNO(ETIMEDOUT),
|
||||
ERRNO(EHOSTDOWN),
|
||||
ERRNO(EHOSTUNREACH),
|
||||
ERRNO(EINPROGRESS),
|
||||
ERRNO(EALREADY),
|
||||
ERRNO(EDESTADDRREQ),
|
||||
ERRNO(EMSGSIZE),
|
||||
ERRNO(EPROTONOSUPPORT),
|
||||
ERRNO(ESOCKTNOSUPPORT),
|
||||
ERRNO(EADDRNOTAVAIL),
|
||||
ERRNO(EISCONN),
|
||||
ERRNO(ENOTCONN),
|
||||
ERRNO(ENOTSUP),
|
||||
ERRNO(EOVERFLOW),
|
||||
ERRNO(ECANCELED),
|
||||
ERRNO(ENOTRECOVERABLE),
|
||||
ERRNO(EOWNERDEAD),
|
||||
ERRNO(ESTRPIPE),
|
||||
#undef ERRNO
|
||||
M(EPERM),
|
||||
M(ENOENT),
|
||||
M(ESRCH),
|
||||
M(EINTR),
|
||||
M(EIO),
|
||||
M(ENXIO),
|
||||
M(E2BIG),
|
||||
M(ENOEXEC),
|
||||
M(EBADF),
|
||||
M(ECHILD),
|
||||
M(EAGAIN),
|
||||
M(ENOMEM),
|
||||
M(EACCES),
|
||||
M(EFAULT),
|
||||
M(ENOTBLK),
|
||||
M(EBUSY),
|
||||
M(EEXIST),
|
||||
M(EXDEV),
|
||||
M(ENODEV),
|
||||
M(ENOTDIR),
|
||||
M(EISDIR),
|
||||
M(EINVAL),
|
||||
M(ENFILE),
|
||||
M(EMFILE),
|
||||
M(ENOTTY),
|
||||
M(ETXTBSY),
|
||||
M(EFBIG),
|
||||
M(ENOSPC),
|
||||
M(ESPIPE),
|
||||
M(EROFS),
|
||||
M(EMLINK),
|
||||
M(EPIPE),
|
||||
M(EDOM),
|
||||
M(ERANGE),
|
||||
M(ENOMSG),
|
||||
M(EIDRM),
|
||||
M(ECHRNG),
|
||||
M(EL2NSYNC),
|
||||
M(EL3HLT),
|
||||
M(EL3RST),
|
||||
M(ELNRNG),
|
||||
M(EUNATCH),
|
||||
M(ENOCSI),
|
||||
M(EL2HLT),
|
||||
M(EDEADLK),
|
||||
M(ENOLCK),
|
||||
M(EBADE),
|
||||
M(EBADR),
|
||||
M(EXFULL),
|
||||
M(ENOANO),
|
||||
M(EBADRQC),
|
||||
M(EBADSLT),
|
||||
M(EDEADLOCK),
|
||||
M(EBFONT),
|
||||
M(ENOSTR),
|
||||
M(ENODATA),
|
||||
M(ETIME),
|
||||
M(ENOSR),
|
||||
M(ENONET),
|
||||
M(ENOPKG),
|
||||
M(EREMOTE),
|
||||
M(ENOLINK),
|
||||
M(EADV),
|
||||
M(ESRMNT),
|
||||
M(ECOMM),
|
||||
M(EPROTO),
|
||||
M(EMULTIHOP),
|
||||
M(ELBIN),
|
||||
M(EDOTDOT),
|
||||
M(EBADMSG),
|
||||
M(EFTYPE),
|
||||
M(ENOTUNIQ),
|
||||
M(EBADFD),
|
||||
M(EREMCHG),
|
||||
M(ELIBACC),
|
||||
M(ELIBBAD),
|
||||
M(ELIBSCN),
|
||||
M(ELIBMAX),
|
||||
M(ELIBEXEC),
|
||||
M(ENOSYS),
|
||||
M(ENOTEMPTY),
|
||||
M(ENAMETOOLONG),
|
||||
M(ELOOP),
|
||||
M(EOPNOTSUPP),
|
||||
M(EPFNOSUPPORT),
|
||||
M(ECONNRESET),
|
||||
M(ENOBUFS),
|
||||
M(EAFNOSUPPORT),
|
||||
M(EPROTOTYPE),
|
||||
M(ENOTSOCK),
|
||||
M(ENOPROTOOPT),
|
||||
M(ESHUTDOWN),
|
||||
M(ECONNREFUSED),
|
||||
M(EADDRINUSE),
|
||||
M(ECONNABORTED),
|
||||
M(ENETUNREACH),
|
||||
M(ENETDOWN),
|
||||
M(ETIMEDOUT),
|
||||
M(EHOSTDOWN),
|
||||
M(EHOSTUNREACH),
|
||||
M(EINPROGRESS),
|
||||
M(EALREADY),
|
||||
M(EDESTADDRREQ),
|
||||
M(EMSGSIZE),
|
||||
M(EPROTONOSUPPORT),
|
||||
M(ESOCKTNOSUPPORT),
|
||||
M(EADDRNOTAVAIL),
|
||||
M(EISCONN),
|
||||
M(ENOTCONN),
|
||||
M(ENOTSUP),
|
||||
M(EOVERFLOW),
|
||||
M(ECANCELED),
|
||||
M(ENOTRECOVERABLE),
|
||||
M(EOWNERDEAD),
|
||||
M(ESTRPIPE),
|
||||
};
|
||||
|
||||
|
||||
const char * signal_names[256] = {
|
||||
M(SIGHUP),
|
||||
M(SIGINT),
|
||||
M(SIGQUIT),
|
||||
M(SIGILL),
|
||||
M(SIGTRAP),
|
||||
M(SIGABRT),
|
||||
M(SIGEMT),
|
||||
M(SIGFPE),
|
||||
M(SIGKILL),
|
||||
M(SIGBUS),
|
||||
M(SIGSEGV),
|
||||
M(SIGSYS),
|
||||
M(SIGPIPE),
|
||||
M(SIGALRM),
|
||||
M(SIGTERM),
|
||||
M(SIGUSR1),
|
||||
M(SIGUSR2),
|
||||
M(SIGCHLD),
|
||||
M(SIGPWR),
|
||||
M(SIGWINCH),
|
||||
M(SIGURG),
|
||||
M(SIGPOLL),
|
||||
M(SIGSTOP),
|
||||
M(SIGTSTP),
|
||||
M(SIGCONT),
|
||||
M(SIGTTIN),
|
||||
M(SIGTTOUT),
|
||||
M(SIGVTALRM),
|
||||
M(SIGPROF),
|
||||
M(SIGXCPU),
|
||||
M(SIGXFSZ),
|
||||
M(SIGWAITING),
|
||||
M(SIGDIAF),
|
||||
M(SIGHATE),
|
||||
M(SIGWINEVENT),
|
||||
M(SIGCAT),
|
||||
};
|
||||
|
||||
#if 0
|
||||
@ -741,29 +780,35 @@ int main(int argc, char * argv[]) {
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "%s: waitpid: %s\n", argv[0], strerror(errno));
|
||||
} else {
|
||||
if (WSTOPSIG(status) == SIGTRAP) {
|
||||
struct regs regs;
|
||||
ptrace(PTRACE_GETREGS, p, NULL, ®s);
|
||||
if (WIFSTOPPED(status)) {
|
||||
if (WSTOPSIG(status) == SIGTRAP) {
|
||||
struct regs regs;
|
||||
ptrace(PTRACE_GETREGS, p, NULL, ®s);
|
||||
|
||||
/* Event type */
|
||||
int event = (status >> 16) & 0xFF;
|
||||
switch (event) {
|
||||
case PTRACE_EVENT_SYSCALL_ENTER:
|
||||
previous_syscall = regs.rax;
|
||||
handle_syscall(p, ®s);
|
||||
break;
|
||||
case PTRACE_EVENT_SYSCALL_EXIT:
|
||||
finish_syscall(p, previous_syscall, ®s);
|
||||
break;
|
||||
default:
|
||||
fprintf(logfile, "Unknown event.\n");
|
||||
break;
|
||||
/* Event type */
|
||||
int event = (status >> 16) & 0xFF;
|
||||
switch (event) {
|
||||
case PTRACE_EVENT_SYSCALL_ENTER:
|
||||
previous_syscall = regs.rax;
|
||||
handle_syscall(p, ®s);
|
||||
break;
|
||||
case PTRACE_EVENT_SYSCALL_EXIT:
|
||||
finish_syscall(p, previous_syscall, ®s);
|
||||
break;
|
||||
default:
|
||||
fprintf(logfile, "Unknown event.\n");
|
||||
break;
|
||||
}
|
||||
ptrace(PTRACE_CONT, p, NULL, NULL);
|
||||
} else {
|
||||
fprintf(logfile, "--- %s ---\n", signal_names[WSTOPSIG(status)]);
|
||||
ptrace(PTRACE_CONT, p, NULL, (void*)(uintptr_t)WSTOPSIG(status));
|
||||
}
|
||||
|
||||
ptrace(PTRACE_CONT, p, NULL, NULL);
|
||||
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
fprintf(logfile, "+++ killed by %s +++\n", signal_names[WTERMSIG(status)]);
|
||||
return 0;
|
||||
} else if (WIFEXITED(status)) {
|
||||
fprintf(logfile, "pid %d has exited\n", res);
|
||||
fprintf(logfile, "+++ exited with %d +++\n", WEXITSTATUS(status));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
4
apps/test-sigsegv.c
Normal file
4
apps/test-sigsegv.c
Normal file
@ -0,0 +1,4 @@
|
||||
int main(int argc, char * argv[]) {
|
||||
*(volatile int*)0x12345 = 42;
|
||||
return 0;
|
||||
}
|
@ -2,5 +2,5 @@
|
||||
|
||||
long ptrace_attach(pid_t pid);
|
||||
long ptrace_self(void);
|
||||
long ptrace_signal(int reason);
|
||||
long ptrace_continue(pid_t pid);
|
||||
long ptrace_signal(int signal, int reason);
|
||||
long ptrace_continue(pid_t pid, int signum);
|
||||
|
@ -16,9 +16,6 @@
|
||||
#include <kernel/arch/x86_64/regs.h>
|
||||
#include <kernel/arch/x86_64/irq.h>
|
||||
|
||||
#undef DEBUG_FAULTS
|
||||
#define LOUD_SEGFAULTS
|
||||
|
||||
static struct idt_pointer idtp;
|
||||
static idt_entry_t idt[256];
|
||||
|
||||
@ -205,30 +202,14 @@ struct regs * isr_handler(struct regs * r) {
|
||||
map_more_stack(faulting_address & 0xFFFFffffFFFFf000);
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG_FAULTS
|
||||
arch_fatal();
|
||||
#else
|
||||
# ifdef LOUD_SEGFAULTS
|
||||
printf("Page fault in pid=%d (%s; cpu=%d) at %#zx\n", (int)this_core->current_process->id, this_core->current_process->name, this_core->cpu_id, faulting_address);
|
||||
dump_regs(r);
|
||||
# endif
|
||||
send_signal(this_core->current_process->id, SIGSEGV, 1);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case 13: /* GPF */ {
|
||||
#ifdef DEBUG_FAULTS
|
||||
arch_fatal();
|
||||
#else
|
||||
if (!this_core->current_process || r->cs == 0x08) {
|
||||
arch_fatal();
|
||||
}
|
||||
# ifdef LOUD_SEGFAULTS
|
||||
printf("GPF in userspace on CPU %d\n", this_core->cpu_id);
|
||||
dump_regs(r);
|
||||
# endif
|
||||
send_signal(this_core->current_process->id, SIGSEGV, 1);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case 8: /* Double fault */ {
|
||||
@ -250,14 +231,10 @@ struct regs * isr_handler(struct regs * r) {
|
||||
}
|
||||
default: {
|
||||
if (r->int_no < 32) {
|
||||
#ifdef DEBUG_FAULTS
|
||||
arch_fatal();
|
||||
#else
|
||||
if (!this_core->current_process || r->cs == 0x08) {
|
||||
arch_fatal();
|
||||
}
|
||||
send_signal(this_core->current_process->id, SIGILL, 1);
|
||||
#endif
|
||||
} else {
|
||||
for (size_t i = 0; i < IRQ_CHAIN_DEPTH; i++) {
|
||||
irq_handler_chain_t handler = irq_routines[i * IRQ_CHAIN_SIZE + (r->int_no - 32)];
|
||||
|
@ -35,9 +35,9 @@ long ptrace_self(void) {
|
||||
/**
|
||||
* @brief Trigger a ptrace event on the currently executing thread.
|
||||
*/
|
||||
long ptrace_signal(int reason) {
|
||||
long ptrace_signal(int signal, int reason) {
|
||||
__sync_or_and_fetch(&this_core->current_process->flags, PROC_FLAG_SUSPENDED);
|
||||
this_core->current_process->status = 0x7F | (SIGTRAP << 8) | (reason << 16);
|
||||
this_core->current_process->status = 0x7F | (signal << 8) | (reason << 16);
|
||||
|
||||
process_t * parent = process_from_pid(this_core->current_process->tracer);
|
||||
if (parent && !(parent->flags & PROC_FLAG_FINISHED)) {
|
||||
@ -45,16 +45,18 @@ long ptrace_signal(int reason) {
|
||||
}
|
||||
switch_task(0);
|
||||
|
||||
return 0;
|
||||
int signum = (this_core->current_process->status >> 8);
|
||||
this_core->current_process->status = 0;
|
||||
return signum;
|
||||
}
|
||||
|
||||
long ptrace_continue(pid_t pid) {
|
||||
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 = 0;
|
||||
tracee->status = (sig << 8);
|
||||
make_process_ready(tracee);
|
||||
|
||||
return 0;
|
||||
@ -66,7 +68,7 @@ long ptrace_getregs(pid_t pid, void * data) {
|
||||
if (!tracee || (tracee->tracer != this_core->current_process->id) || !(tracee->flags & PROC_FLAG_SUSPENDED)) return -ESRCH;
|
||||
|
||||
/* Copy registers */
|
||||
memcpy(data, tracee->syscall_registers, sizeof(struct regs));
|
||||
memcpy(data, tracee->interrupt_registers ? tracee->interrupt_registers : tracee->syscall_registers, sizeof(struct regs));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -100,7 +102,7 @@ long ptrace_handle(long request, pid_t pid, void * addr, void * data) {
|
||||
case PTRACE_GETREGS:
|
||||
return ptrace_getregs(pid,data);
|
||||
case PTRACE_CONT:
|
||||
return ptrace_continue(pid);
|
||||
return ptrace_continue(pid,(uintptr_t)data);
|
||||
case PTRACE_PEEKDATA:
|
||||
return ptrace_peek(pid,addr,data);
|
||||
default:
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <kernel/process.h>
|
||||
#include <kernel/signal.h>
|
||||
#include <kernel/spinlock.h>
|
||||
#include <kernel/ptrace.h>
|
||||
|
||||
static spin_lock_t sig_lock;
|
||||
static spin_lock_t sig_lock_b;
|
||||
@ -76,6 +77,11 @@ void handle_signal(process_t * proc, signal_t * sig) {
|
||||
uintptr_t signum = sig->signum;
|
||||
free(sig);
|
||||
|
||||
/* Are we being traced? */
|
||||
if (this_core->current_process->flags & PROC_FLAG_TRACED) {
|
||||
signum = ptrace_signal(signum, 0);
|
||||
}
|
||||
|
||||
if (proc->flags & PROC_FLAG_FINISHED) {
|
||||
return;
|
||||
}
|
||||
|
@ -1139,7 +1139,7 @@ void syscall_handler(struct regs * r) {
|
||||
this_core->current_process->syscall_registers = r;
|
||||
|
||||
if (this_core->current_process->flags & PROC_FLAG_TRACED) {
|
||||
ptrace_signal(PTRACE_EVENT_SYSCALL_ENTER);
|
||||
ptrace_signal(SIGTRAP, PTRACE_EVENT_SYSCALL_ENTER);
|
||||
}
|
||||
|
||||
arch_syscall_return(r, func(
|
||||
@ -1147,6 +1147,6 @@ void syscall_handler(struct regs * r) {
|
||||
arch_syscall_arg3(r), arch_syscall_arg4(r)));
|
||||
|
||||
if (this_core->current_process->flags & PROC_FLAG_TRACED) {
|
||||
ptrace_signal(PTRACE_EVENT_SYSCALL_EXIT);
|
||||
ptrace_signal(SIGTRAP, PTRACE_EVENT_SYSCALL_EXIT);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user