strace: Initial support for a ptrace() mechanism, strace tool
This commit is contained in:
parent
69391e5b51
commit
6899683bb4
@ -433,6 +433,12 @@ void tab_complete_func(rline_context_t * c) {
|
||||
command_adj += 1;
|
||||
}
|
||||
|
||||
/* So should strace */
|
||||
if (command_adj < argc && (!strcmp(argv[command_adj], "strace"))) {
|
||||
cursor_adj -= 1;
|
||||
command_adj += 1;
|
||||
}
|
||||
|
||||
/* initial tab completion should be commands, unless typing a file path */
|
||||
if (cursor_adj == 0 && !strchr(prefix,'/')) {
|
||||
complete_mode = COMPLETE_COMMAND;
|
||||
|
451
apps/strace.c
Normal file
451
apps/strace.c
Normal file
@ -0,0 +1,451 @@
|
||||
/**
|
||||
* @brief Process system call tracer.
|
||||
*
|
||||
* @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 <sys/ptrace.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/signal_defs.h>
|
||||
#include <sys/sysfunc.h>
|
||||
#include <syscall_nums.h>
|
||||
|
||||
struct regs {
|
||||
/* Pushed by common stub */
|
||||
uintptr_t r15, r14, r13, r12;
|
||||
uintptr_t r11, r10, r9, r8;
|
||||
uintptr_t rbp, rdi, rsi, rdx, rcx, rbx, rax;
|
||||
|
||||
/* Pushed by wrapper */
|
||||
uintptr_t int_no, err_code;
|
||||
|
||||
/* Pushed by interrupt */
|
||||
uintptr_t rip, cs, rflags, rsp, ss;
|
||||
};
|
||||
|
||||
/* System call names */
|
||||
const char * syscall_names[] = {
|
||||
[SYS_EXT] = "exit",
|
||||
[SYS_GETEUID] = "geteuid",
|
||||
[SYS_OPEN] = "open",
|
||||
[SYS_READ] = "read",
|
||||
[SYS_WRITE] = "write",
|
||||
[SYS_CLOSE] = "close",
|
||||
[SYS_GETTIMEOFDAY] = "gettimeofday",
|
||||
[SYS_GETPID] = "getpid",
|
||||
[SYS_SBRK] = "sbrk",
|
||||
[SYS_UNAME] = "uname",
|
||||
[SYS_SEEK] = "seek",
|
||||
[SYS_STAT] = "stat",
|
||||
[SYS_GETUID] = "getuid",
|
||||
[SYS_SETUID] = "setuid",
|
||||
[SYS_READDIR] = "readdir",
|
||||
[SYS_CHDIR] = "chdir",
|
||||
[SYS_GETCWD] = "getcwd",
|
||||
[SYS_SETHOSTNAME] = "sethostname",
|
||||
[SYS_GETHOSTNAME] = "gethostname",
|
||||
[SYS_MKDIR] = "mkdir",
|
||||
[SYS_GETTID] = "gettid",
|
||||
[SYS_SYSFUNC] = "sysfunc",
|
||||
[SYS_IOCTL] = "ioctl",
|
||||
[SYS_ACCESS] = "access",
|
||||
[SYS_STATF] = "statf",
|
||||
[SYS_CHMOD] = "chmod",
|
||||
[SYS_UMASK] = "umask",
|
||||
[SYS_UNLINK] = "unlink",
|
||||
[SYS_MOUNT] = "mount",
|
||||
[SYS_SYMLINK] = "symlink",
|
||||
[SYS_READLINK] = "readlink",
|
||||
[SYS_LSTAT] = "lstat",
|
||||
[SYS_CHOWN] = "chown",
|
||||
[SYS_SETSID] = "setsid",
|
||||
[SYS_SETPGID] = "setpgid",
|
||||
[SYS_GETPGID] = "getpgid",
|
||||
[SYS_DUP2] = "dup2",
|
||||
[SYS_EXECVE] = "execve",
|
||||
[SYS_FORK] = "fork",
|
||||
[SYS_WAITPID] = "waitpid",
|
||||
[SYS_YIELD] = "yield",
|
||||
[SYS_SLEEPABS] = "sleepabs",
|
||||
[SYS_SLEEP] = "sleep",
|
||||
[SYS_PIPE] = "pipe",
|
||||
[SYS_FSWAIT] = "fswait",
|
||||
[SYS_FSWAIT2] = "fswait_timeout",
|
||||
[SYS_FSWAIT3] = "fswait_multi",
|
||||
[SYS_CLONE] = "clone",
|
||||
[SYS_OPENPTY] = "openpty",
|
||||
[SYS_SHM_OBTAIN] = "shm_obtain",
|
||||
[SYS_SHM_RELEASE] = "shm_release",
|
||||
[SYS_SIGNAL] = "signal",
|
||||
[SYS_KILL] = "kill",
|
||||
[SYS_REBOOT] = "reboot",
|
||||
[SYS_GETGID] = "getgid",
|
||||
[SYS_GETEGID] = "getegid",
|
||||
[SYS_SETGID] = "setgid",
|
||||
[SYS_GETGROUPS] = "getgroups",
|
||||
[SYS_SETGROUPS] = "setgroups",
|
||||
[SYS_TIMES] = "times",
|
||||
[SYS_PTRACE] = "ptrace",
|
||||
[SYS_SOCKET] = "socket",
|
||||
[SYS_SETSOCKOPT] = "setsockopt",
|
||||
[SYS_BIND] = "bind",
|
||||
[SYS_ACCEPT] = "accept",
|
||||
[SYS_LISTEN] = "listen",
|
||||
[SYS_CONNECT] = "connect",
|
||||
[SYS_GETSOCKOPT] = "getsockopt",
|
||||
[SYS_RECV] = "recv",
|
||||
[SYS_SEND] = "send",
|
||||
[SYS_SHUTDOWN] = "shutdown",
|
||||
};
|
||||
|
||||
#if 0
|
||||
static void dump_regs(struct regs * r) {
|
||||
printf(
|
||||
" $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
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void open_flags(int flags) {
|
||||
if (!flags) {
|
||||
printf("O_RDONLY");
|
||||
return;
|
||||
}
|
||||
|
||||
/* That's all that's valid right now */
|
||||
flags &= 0xFFFF;
|
||||
|
||||
#define H(flg) do { if (flags & flg) { printf(#flg); flags &= (~flg); if (flags) printf("|"); } } while (0)
|
||||
|
||||
H(O_WRONLY);
|
||||
H(O_RDWR);
|
||||
H(O_APPEND);
|
||||
H(O_CREAT);
|
||||
H(O_TRUNC);
|
||||
H(O_EXCL);
|
||||
H(O_NOFOLLOW);
|
||||
H(O_PATH);
|
||||
H(O_NONBLOCK);
|
||||
H(O_DIRECTORY);
|
||||
|
||||
if (flags) {
|
||||
printf("(%#x)", flags);
|
||||
}
|
||||
}
|
||||
|
||||
static void string_arg(pid_t pid, uintptr_t ptr) {
|
||||
if (ptr == 0) {
|
||||
printf("NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("\"");
|
||||
|
||||
size_t size = 0;
|
||||
char buf = 0;
|
||||
|
||||
do {
|
||||
long result = ptrace(PTRACE_PEEKDATA, pid, (void*)ptr, &buf);
|
||||
if (result != 0) break;
|
||||
if (!buf) {
|
||||
printf("\"");
|
||||
return;
|
||||
}
|
||||
if (buf == '\\') {
|
||||
printf("\\\\");
|
||||
} else if (buf == '"') {
|
||||
printf("\\\"");
|
||||
} else if (buf >= ' ' && buf <= '~') {
|
||||
printf("%c", buf);
|
||||
} else if (buf) {
|
||||
printf("\\x%02x", buf);
|
||||
}
|
||||
ptr++;
|
||||
size++;
|
||||
if (size > 30) break;
|
||||
} while (buf);
|
||||
|
||||
printf("\"...");
|
||||
}
|
||||
|
||||
static void pointer_arg(uintptr_t ptr) {
|
||||
if (ptr == 0) printf("NULL");
|
||||
else printf("%#zx", ptr);
|
||||
}
|
||||
|
||||
static void uint_arg(size_t val) {
|
||||
printf("%zu", val);
|
||||
}
|
||||
|
||||
static void int_arg(size_t val) {
|
||||
printf("%zd", val);
|
||||
}
|
||||
|
||||
static void fd_arg(pid_t pid, int val) {
|
||||
/* TODO: Look up file in user data? */
|
||||
printf("%d", val);
|
||||
}
|
||||
|
||||
static void fds_arg(pid_t pid, size_t ecount, uintptr_t array) {
|
||||
printf("{");
|
||||
for (size_t count = 0; count < 10 && count < ecount; ++count) {
|
||||
char buf[sizeof(int)];
|
||||
for (unsigned int i = 0; i < sizeof(int); ++i) {
|
||||
if (ptrace(PTRACE_PEEKDATA, pid, (void*)array++, &buf[i])) {
|
||||
printf("?}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
int x = 0;
|
||||
memcpy(&x,buf,sizeof(int));
|
||||
printf("%d", x);
|
||||
if (count + 1 < ecount) printf(",");
|
||||
}
|
||||
printf("}");
|
||||
}
|
||||
|
||||
#define C(arg) case arg: printf(#arg); break
|
||||
|
||||
#define COMMA printf(", ");
|
||||
|
||||
static void handle_syscall(pid_t pid, struct regs * r) {
|
||||
printf("%s(", syscall_names[r->rax]);
|
||||
switch (r->rax) {
|
||||
case SYS_OPEN:
|
||||
string_arg(pid, r->rbx); COMMA;
|
||||
open_flags(r->rcx);
|
||||
break;
|
||||
case SYS_READ:
|
||||
fd_arg(pid, r->rbx); COMMA;
|
||||
pointer_arg(r->rcx); COMMA;
|
||||
uint_arg(r->rdx);
|
||||
break;
|
||||
case SYS_WRITE:
|
||||
fd_arg(pid, r->rbx); COMMA;
|
||||
pointer_arg(r->rcx); COMMA;
|
||||
uint_arg(r->rdx);
|
||||
break;
|
||||
case SYS_CLOSE:
|
||||
fd_arg(pid, r->rbx);
|
||||
break;
|
||||
case SYS_SBRK:
|
||||
uint_arg(r->rbx);
|
||||
break;
|
||||
case SYS_SEEK:
|
||||
fd_arg(pid, r->rbx); COMMA;
|
||||
int_arg(r->rcx); COMMA;
|
||||
switch (r->rdx) {
|
||||
case 0: printf("SEEK_SET"); break;
|
||||
case 1: printf("SEEK_CUR"); break;
|
||||
case 2: printf("SEEK_END"); break;
|
||||
default: int_arg(r->rdx); break;
|
||||
}
|
||||
break;
|
||||
case SYS_STATF:
|
||||
string_arg(pid, r->rbx); COMMA;
|
||||
pointer_arg(r->rcx);
|
||||
break;
|
||||
case SYS_LSTAT:
|
||||
string_arg(pid, r->rbx); COMMA;
|
||||
pointer_arg(r->rcx);
|
||||
break;
|
||||
case SYS_READDIR:
|
||||
fd_arg(pid, r->rbx); COMMA;
|
||||
int_arg(r->rcx); COMMA;
|
||||
pointer_arg(r->rdx);
|
||||
break;
|
||||
case SYS_KILL:
|
||||
int_arg(r->rbx); COMMA; /* pid_arg? */
|
||||
int_arg(r->rcx); /* TODO signal name */
|
||||
break;
|
||||
case SYS_CHDIR:
|
||||
string_arg(pid, r->rbx);
|
||||
break;
|
||||
case SYS_GETCWD:
|
||||
pointer_arg(r->rbx); COMMA; /* TODO syscall outputs */
|
||||
uint_arg(r->rcx);
|
||||
break;
|
||||
case SYS_CLONE:
|
||||
pointer_arg(r->rbx); COMMA;
|
||||
pointer_arg(r->rcx); COMMA;
|
||||
pointer_arg(r->rdx);
|
||||
break;
|
||||
case SYS_SETHOSTNAME:
|
||||
string_arg(pid, r->rbx);
|
||||
break;
|
||||
case SYS_GETHOSTNAME:
|
||||
pointer_arg(r->rbx);
|
||||
break;
|
||||
case SYS_MKDIR:
|
||||
string_arg(pid, r->rbx); COMMA;
|
||||
uint_arg(r->rcx);
|
||||
break;
|
||||
case SYS_SHUTDOWN:
|
||||
int_arg(r->rbx); COMMA;
|
||||
int_arg(r->rcx);
|
||||
break;
|
||||
case SYS_ACCESS:
|
||||
string_arg(pid, r->rbx); COMMA;
|
||||
int_arg(r->rcx);
|
||||
break;
|
||||
case SYS_PTRACE:
|
||||
switch (r->rbx) {
|
||||
C(PTRACE_ATTACH);
|
||||
C(PTRACE_CONT);
|
||||
C(PTRACE_DETACH);
|
||||
C(PTRACE_TRACEME);
|
||||
C(PTRACE_GETREGS);
|
||||
C(PTRACE_PEEKDATA);
|
||||
default: int_arg(r->rbx); break;
|
||||
} COMMA;
|
||||
int_arg(r->rcx); COMMA;
|
||||
pointer_arg(r->rdx); COMMA;
|
||||
pointer_arg(r->rsi);
|
||||
break;
|
||||
case SYS_EXECVE:
|
||||
string_arg(pid, r->rbx); COMMA;
|
||||
pointer_arg(r->rcx); COMMA;
|
||||
pointer_arg(r->rdx);
|
||||
break;
|
||||
case SYS_SHM_OBTAIN:
|
||||
string_arg(pid, r->rbx); COMMA;
|
||||
pointer_arg(r->rcx);
|
||||
break;
|
||||
case SYS_SHM_RELEASE:
|
||||
string_arg(pid, r->rbx);
|
||||
break;
|
||||
case SYS_SIGNAL:
|
||||
int_arg(r->rbx); COMMA; /* TODO signal name */
|
||||
pointer_arg(r->rcx);
|
||||
break;
|
||||
case SYS_SYSFUNC:
|
||||
switch (r->rbx) {
|
||||
C(TOARU_SYS_FUNC_SYNC);
|
||||
C(TOARU_SYS_FUNC_LOGHERE);
|
||||
C(TOARU_SYS_FUNC_KDEBUG);
|
||||
C(TOARU_SYS_FUNC_INSMOD);
|
||||
C(TOARU_SYS_FUNC_SETHEAP);
|
||||
C(TOARU_SYS_FUNC_MMAP);
|
||||
C(TOARU_SYS_FUNC_THREADNAME);
|
||||
C(TOARU_SYS_FUNC_SETGSBASE);
|
||||
C(TOARU_SYS_FUNC_NPROC);
|
||||
default: int_arg(r->rbx); break;
|
||||
} COMMA;
|
||||
pointer_arg(r->rcx);
|
||||
break;
|
||||
case SYS_FSWAIT:
|
||||
int_arg(r->rbx); COMMA;
|
||||
fds_arg(pid, r->rbx, r->rcx);
|
||||
break;
|
||||
case SYS_FSWAIT2:
|
||||
int_arg(r->rbx); COMMA;
|
||||
fds_arg(pid, r->rbx, r->rcx); COMMA;
|
||||
int_arg(r->rdx);
|
||||
break;
|
||||
case SYS_FSWAIT3:
|
||||
int_arg(r->rbx); COMMA;
|
||||
fds_arg(pid, r->rbx, r->rcx); COMMA;
|
||||
int_arg(r->rdx); COMMA;
|
||||
pointer_arg(r->rsi);
|
||||
break;
|
||||
case SYS_IOCTL:
|
||||
fd_arg(pid, r->rbx); COMMA;
|
||||
int_arg(r->rcx); COMMA;
|
||||
pointer_arg(r->rdx);
|
||||
break;
|
||||
case SYS_WAITPID:
|
||||
int_arg(r->rbx); COMMA;
|
||||
pointer_arg(r->rcx); COMMA;
|
||||
int_arg(r->rdx); /* TODO waitpid options */
|
||||
break;
|
||||
case SYS_EXT:
|
||||
int_arg(r->rbx);
|
||||
printf(") = ?\n");
|
||||
return;
|
||||
/* These have no arguments: */
|
||||
case SYS_YIELD:
|
||||
case SYS_FORK:
|
||||
case SYS_GETEUID:
|
||||
case SYS_GETPID:
|
||||
case SYS_GETUID:
|
||||
case SYS_REBOOT:
|
||||
case SYS_GETTID:
|
||||
case SYS_SETSID:
|
||||
case SYS_GETGID:
|
||||
case SYS_GETEGID:
|
||||
break;
|
||||
default:
|
||||
printf("...");
|
||||
break;
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
|
||||
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[1], &argv[1]);
|
||||
return 1;
|
||||
} else {
|
||||
while (1) {
|
||||
int status = 0;
|
||||
pid_t res = waitpid(p, &status, WSTOPPED);
|
||||
|
||||
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);
|
||||
|
||||
/* Event type */
|
||||
int event = (status >> 16) & 0xFF;
|
||||
switch (event) {
|
||||
case PTRACE_EVENT_SYSCALL_ENTER:
|
||||
handle_syscall(p, ®s);
|
||||
break;
|
||||
case PTRACE_EVENT_SYSCALL_EXIT:
|
||||
printf(") = %ld\n", regs.rax);
|
||||
break;
|
||||
default:
|
||||
printf("Unknown event.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
ptrace(PTRACE_CONT, p, NULL, NULL);
|
||||
|
||||
} else if (WIFEXITED(status)) {
|
||||
fprintf(stderr, "%s: %d has exited\n", argv[0], res);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -20,7 +20,7 @@ uintptr_t mmu_first_frame(void);
|
||||
void mmu_frame_allocate(union PML * page, unsigned int flags);
|
||||
void mmu_frame_map_address(union PML * page, unsigned int flags, uintptr_t physAddr);
|
||||
void mmu_frame_free(union PML * page);
|
||||
uintptr_t mmu_map_to_physical(uintptr_t virtAddr);
|
||||
uintptr_t mmu_map_to_physical(union PML * root, uintptr_t virtAddr);
|
||||
union PML * mmu_get_page(uintptr_t virtAddr, int flags);
|
||||
void mmu_set_directory(union PML * new_pml);
|
||||
void mmu_free(union PML * from);
|
||||
|
@ -67,6 +67,7 @@ typedef struct file_descriptors {
|
||||
#define PROC_FLAG_RUNNING 0x08
|
||||
#define PROC_FLAG_SLEEP_INT 0x10
|
||||
#define PROC_FLAG_SUSPENDED 0x20
|
||||
#define PROC_FLAG_TRACED 0x40
|
||||
|
||||
typedef struct process {
|
||||
pid_t id; /* PID */
|
||||
@ -130,6 +131,9 @@ typedef struct process {
|
||||
uint64_t time_children; /* sum of user times from waited-for children */
|
||||
uint64_t time_sys_children; /* sum of sys times from waited-for children */
|
||||
uint16_t usage[4]; /* four permille samples over some period (currently 4Hz) */
|
||||
|
||||
/* Tracing */
|
||||
pid_t tracer;
|
||||
} process_t;
|
||||
|
||||
typedef struct {
|
||||
|
6
base/usr/include/kernel/ptrace.h
Normal file
6
base/usr/include/kernel/ptrace.h
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
long ptrace_attach(pid_t pid);
|
||||
long ptrace_self(void);
|
||||
long ptrace_signal(int reason);
|
||||
long ptrace_continue(pid_t pid);
|
26
base/usr/include/sys/ptrace.h
Normal file
26
base/usr/include/sys/ptrace.h
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <_cheader.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
_Begin_C_Header
|
||||
|
||||
enum __ptrace_request {
|
||||
PTRACE_ATTACH,
|
||||
PTRACE_CONT,
|
||||
PTRACE_DETACH,
|
||||
PTRACE_TRACEME,
|
||||
PTRACE_GETREGS,
|
||||
PTRACE_PEEKDATA
|
||||
};
|
||||
|
||||
enum __ptrace_event {
|
||||
PTRACE_EVENT_SYSCALL_ENTER,
|
||||
PTRACE_EVENT_SYSCALL_EXIT,
|
||||
};
|
||||
|
||||
#ifndef __kernel__
|
||||
extern long ptrace(enum __ptrace_request request, pid_t pid, void * addr, void * data);
|
||||
#endif
|
||||
|
||||
_End_C_Header
|
@ -130,6 +130,7 @@ DECL_SYSCALL1(setgid, unsigned int);
|
||||
DECL_SYSCALL2(getgroups, int, int*);
|
||||
DECL_SYSCALL2(setgroups, int, const int*);
|
||||
DECL_SYSCALL1(times, struct tms*);
|
||||
DECL_SYSCALL4(ptrace, int, int, void*, void*);
|
||||
|
||||
_End_C_Header
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#define SYS_CLONE 30
|
||||
#define SYS_SETHOSTNAME 31
|
||||
#define SYS_GETHOSTNAME 32
|
||||
#define SYS_PTRACE 33
|
||||
#define SYS_MKDIR 34
|
||||
#define SYS_SHM_OBTAIN 35
|
||||
#define SYS_SHM_RELEASE 36
|
||||
|
@ -202,7 +202,7 @@ void * mmu_map_from_physical(uintptr_t frameaddress) {
|
||||
* is returned indicating which level of the page directory is
|
||||
* unmapped from -1 (no PDP) to -4 (page not present in table).
|
||||
*/
|
||||
uintptr_t mmu_map_to_physical(uintptr_t virtAddr) {
|
||||
uintptr_t mmu_map_to_physical(union PML * root, uintptr_t virtAddr) {
|
||||
uintptr_t realBits = virtAddr & CANONICAL_MASK;
|
||||
uintptr_t pageAddr = realBits >> PAGE_SHIFT;
|
||||
unsigned int pml4_entry = (pageAddr >> 27) & ENTRY_MASK;
|
||||
@ -210,8 +210,6 @@ uintptr_t mmu_map_to_physical(uintptr_t virtAddr) {
|
||||
unsigned int pd_entry = (pageAddr >> 9) & ENTRY_MASK;
|
||||
unsigned int pt_entry = (pageAddr) & ENTRY_MASK;
|
||||
|
||||
union PML * root = this_core->current_pml;
|
||||
|
||||
/* Get the PML4 entry for this address */
|
||||
if (!root[pml4_entry].bits.present) return (uintptr_t)-1;
|
||||
|
||||
|
110
kernel/sys/ptrace.c
Normal file
110
kernel/sys/ptrace.c
Normal file
@ -0,0 +1,110 @@
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <kernel/printf.h>
|
||||
#include <kernel/process.h>
|
||||
#include <kernel/string.h>
|
||||
#include <kernel/signal.h>
|
||||
#include <kernel/syscall.h>
|
||||
#include <kernel/ptrace.h>
|
||||
#include <kernel/args.h>
|
||||
|
||||
#include <kernel/arch/x86_64/regs.h>
|
||||
#include <kernel/arch/x86_64/mmu.h>
|
||||
|
||||
long ptrace_attach(pid_t pid) {
|
||||
process_t * tracee = process_from_pid(pid);
|
||||
if (!tracee) return -ESRCH;
|
||||
if (this_core->current_process->user != 0 && this_core->current_process->user != tracee->user) return -EPERM;
|
||||
__sync_or_and_fetch(&tracee->flags, PROC_FLAG_TRACED);
|
||||
tracee->tracer = this_core->current_process->id;
|
||||
send_signal(pid, SIGSTOP, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
long ptrace_self(void) {
|
||||
process_t * parent = process_get_parent((process_t*)this_core->current_process);
|
||||
if (!parent) return -EINVAL;
|
||||
|
||||
__sync_or_and_fetch(&this_core->current_process->flags, PROC_FLAG_TRACED);
|
||||
this_core->current_process->tracer = parent->id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Trigger a ptrace event on the currently executing thread.
|
||||
*/
|
||||
long ptrace_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);
|
||||
|
||||
process_t * parent = process_from_pid(this_core->current_process->tracer);
|
||||
if (parent && !(parent->flags & PROC_FLAG_FINISHED)) {
|
||||
wakeup_queue(parent->wait_queue);
|
||||
}
|
||||
switch_task(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long ptrace_continue(pid_t pid) {
|
||||
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;
|
||||
make_process_ready(tracee);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long ptrace_getregs(pid_t pid, void * data) {
|
||||
if (!data || ptr_validate(data, "ptrace")) return -EFAULT;
|
||||
process_t * tracee = process_from_pid(pid);
|
||||
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));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long ptrace_peek(pid_t pid, void * addr, void * data) {
|
||||
if (!data || ptr_validate(data, "ptrace")) return -EFAULT;
|
||||
process_t * tracee = process_from_pid(pid);
|
||||
if (!tracee || (tracee->tracer != this_core->current_process->id) || !(tracee->flags & PROC_FLAG_SUSPENDED)) return -ESRCH;
|
||||
|
||||
/* Figure out where *addr is...
|
||||
* TODO: We don't ever really page things to disk, and we don't have file
|
||||
* mappings that may be not-present, so this is fairly straightforward for now... */
|
||||
uintptr_t mapped_address = mmu_map_to_physical(tracee->thread.page_directory->directory, (uintptr_t)addr);
|
||||
|
||||
if ((intptr_t)mapped_address < 0 && (intptr_t)mapped_address > -10) return -EFAULT;
|
||||
|
||||
uintptr_t blarg = (uintptr_t)mmu_map_from_physical(mapped_address);
|
||||
|
||||
/* Yeah, uh, one byte. That works. */
|
||||
*(char*)data = *(char*)blarg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long ptrace_handle(long request, pid_t pid, void * addr, void * data) {
|
||||
switch (request) {
|
||||
case PTRACE_ATTACH:
|
||||
return ptrace_attach(pid);
|
||||
case PTRACE_TRACEME:
|
||||
return ptrace_self();
|
||||
case PTRACE_GETREGS:
|
||||
return ptrace_getregs(pid,data);
|
||||
case PTRACE_CONT:
|
||||
return ptrace_continue(pid);
|
||||
case PTRACE_PEEKDATA:
|
||||
return ptrace_peek(pid,addr,data);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/times.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <syscall_nums.h>
|
||||
#include <kernel/printf.h>
|
||||
#include <kernel/process.h>
|
||||
@ -19,6 +20,7 @@
|
||||
#include <kernel/time.h>
|
||||
#include <kernel/syscall.h>
|
||||
#include <kernel/misc.h>
|
||||
#include <kernel/ptrace.h>
|
||||
|
||||
static char hostname[256];
|
||||
static size_t hostname_len = 0;
|
||||
@ -1045,6 +1047,8 @@ extern long net_recv();
|
||||
extern long net_send();
|
||||
extern long net_shutdown();
|
||||
|
||||
extern long ptrace_handle(long,pid_t,void*,void*);
|
||||
|
||||
static long (*syscalls[])() = {
|
||||
/* System Call Table */
|
||||
[SYS_EXT] = sys_exit,
|
||||
@ -1107,6 +1111,7 @@ static long (*syscalls[])() = {
|
||||
[SYS_GETGROUPS] = sys_getgroups,
|
||||
[SYS_SETGROUPS] = sys_setgroups,
|
||||
[SYS_TIMES] = sys_times,
|
||||
[SYS_PTRACE] = ptrace_handle,
|
||||
|
||||
[SYS_SOCKET] = net_socket,
|
||||
[SYS_SETSOCKOPT] = net_setsockopt,
|
||||
@ -1132,7 +1137,16 @@ void syscall_handler(struct regs * r) {
|
||||
|
||||
scall_func func = syscalls[arch_syscall_number(r)];
|
||||
this_core->current_process->syscall_registers = r;
|
||||
|
||||
if (this_core->current_process->flags & PROC_FLAG_TRACED) {
|
||||
ptrace_signal(PTRACE_EVENT_SYSCALL_ENTER);
|
||||
}
|
||||
|
||||
arch_syscall_return(r, func(
|
||||
arch_syscall_arg0(r), arch_syscall_arg1(r), arch_syscall_arg2(r),
|
||||
arch_syscall_arg3(r), arch_syscall_arg4(r)));
|
||||
|
||||
if (this_core->current_process->flags & PROC_FLAG_TRACED) {
|
||||
ptrace_signal(PTRACE_EVENT_SYSCALL_EXIT);
|
||||
}
|
||||
}
|
||||
|
10
libc/sys/ptrace.c
Normal file
10
libc/sys/ptrace.c
Normal file
@ -0,0 +1,10 @@
|
||||
#include <syscall.h>
|
||||
#include <syscall_nums.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <errno.h>
|
||||
|
||||
DEFN_SYSCALL4(ptrace, SYS_PTRACE, int, int, void *, void *);
|
||||
|
||||
long ptrace(enum __ptrace_request request, pid_t pid, void * addr, void * data) {
|
||||
__sets_errno(syscall_ptrace(request,pid,addr,data));
|
||||
}
|
Loading…
Reference in New Issue
Block a user