diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | arch-x86-64.h | 29 | ||||
-rw-r--r-- | common.h | 16 | ||||
-rw-r--r-- | process.c | 22 | ||||
-rw-r--r-- | sctrace.c | 42 | ||||
-rw-r--r-- | tests/.gitignore | 3 | ||||
-rw-r--r-- | tests/Makefile | 54 | ||||
-rw-r--r-- | tests/fork.c | 4 | ||||
-rw-r--r-- | tests/signal.c | 4 |
9 files changed, 120 insertions, 55 deletions
@@ -12,6 +12,7 @@ OBJ =\ util.o HDR =\ + arch-x86-64.h\ arg.h\ common.h\ list-errnos.h\ diff --git a/arch-x86-64.h b/arch-x86-64.h new file mode 100644 index 0000000..044b73f --- /dev/null +++ b/arch-x86-64.h @@ -0,0 +1,29 @@ +struct i386_user_regs_struct +{ + uint32_t ebx; + uint32_t ecx; + uint32_t edx; + uint32_t esi; + uint32_t edi; + uint32_t ebp; + uint32_t eax; + uint32_t xds; + uint32_t xes; + uint32_t xfs; + uint32_t xgs; + uint32_t orig_eax; + uint32_t eip; + uint32_t xcs; + uint32_t eflags; + uint32_t esp; + uint32_t xss; +}; + +#define SYSCALL_NUM_REG orig_rax +#define SYSCALL_ARG1_REG rdi +#define SYSCALL_ARG2_REG rsi +#define SYSCALL_ARG3_REG rdx +#define SYSCALL_ARG4_REG r10 +#define SYSCALL_ARG5_REG r8 +#define SYSCALL_ARG6_REG r9 +#define SYSCALL_RET_REG rax @@ -1,9 +1,7 @@ /* See LICENSE file for copyright and license details. */ -#if !defined __x86_64__ || defined __IPL32__ -# error "This program is only implemented for x86-64" -#endif - +#include <linux/elf.h> #include <sys/ptrace.h> +#include <linux/ptrace.h> /* After <sys/ptrace.h> */ #include <sys/syscall.h> #include <sys/uio.h> #include <sys/user.h> @@ -19,6 +17,16 @@ #include <string.h> #include <unistd.h> +#if defined(__x86_64__) && !defined(__IPL32__) +# include "arch-x86-64.h" +#else +# error "This program is only implemented for x86-64" +#endif + +#if !defined(__linux__) +# error "This program is only implemented for Linux" +#endif + #include "arg.h" #include "list-errnos.h" #include "list-signums.h" @@ -9,7 +9,7 @@ static struct process tail; void init_process_list(void) { - head.next = &tail; + head.next = &tail; tail.prev = &head; } @@ -17,25 +17,25 @@ init_process_list(void) struct process * find_process(pid_t pid) { - struct process *p; - for (p = head.next; p->next; p = p->next) - if (p->pid == pid) - return p; - return NULL; + struct process *p; + for (p = head.next; p->next; p = p->next) + if (p->pid == pid) + return p; + return NULL; } struct process * add_process(pid_t pid, unsigned long int trace_options) { - struct process *proc; + struct process *proc; int status; - proc = calloc(1, sizeof(*proc)); + proc = calloc(1, sizeof(*proc)); if (!proc) - eprintf("calloc: %s\n"); - proc->pid = pid; - proc->next = &tail; + eprintf("calloc: %s\n"); + proc->pid = pid; + proc->next = &tail; proc->prev = tail.prev; proc->prev->next = proc; tail.prev = proc; @@ -18,19 +18,35 @@ static void handle_syscall(struct process *proc) { struct user_regs_struct regs; + struct iovec iov = { + .iov_base = ®s, + .iov_len = sizeof(regs), + }; switch ((int)proc->state) { default: /* Get system call arguments */ if (ptrace(PTRACE_GETREGS, proc->pid, NULL, ®s)) eprintf("ptrace PTRACE_GETREGS %ju NULL <buffer>:", (uintmax_t)proc->pid); - proc->scall = regs.orig_rax; - proc->args[0] = regs.rdi; - proc->args[1] = regs.rsi; - proc->args[2] = regs.rdx; - proc->args[3] = regs.r10; - proc->args[4] = regs.r8; - proc->args[5] = regs.r9; + proc->scall = regs.SYSCALL_NUM_REG; + proc->args[0] = regs.SYSCALL_ARG1_REG; + proc->args[1] = regs.SYSCALL_ARG2_REG; + proc->args[2] = regs.SYSCALL_ARG3_REG; + proc->args[3] = regs.SYSCALL_ARG4_REG; + proc->args[4] = regs.SYSCALL_ARG5_REG; + proc->args[5] = regs.SYSCALL_ARG6_REG; + + /* Check architecture */ + if (ptrace(PTRACE_GETREGSET, proc->pid, NT_PRSTATUS, &iov)) { + eprintf("ptrace PTRACE_GETREGSET %ju NT_PRSTATUS {.iov_base=<buffer>, .iov_len=%zu}:", + (uintmax_t)proc->pid, sizeof(regs)); + } else if (iov.iov_len != sizeof(regs)) { + tprintf(proc, "Process is running as i386, this is not yet supported\n"); + exit(1); + } else if (proc->scall & __X32_SYSCALL_BIT) { + tprintf(proc, "Process is running as x32, this is not yet supported\n"); + exit(1); + } /* Print system call */ print_systemcall(proc); @@ -51,9 +67,9 @@ handle_syscall(struct process *proc) /* Get or set return */ if (proc->state == Syscall) { - proc->ret = regs.rax; + proc->ret = regs.SYSCALL_RET_REG; } else { - regs.rax = proc->ret; + regs.SYSCALL_RET_REG = proc->ret; if (ptrace(PTRACE_SETREGS, proc->pid, NULL, ®s)) eprintf("ptrace PTRACE_SETREGS %ju NULL <buffer>:", (uintmax_t)proc->pid); if (ptrace(PTRACE_SYSCALL, proc->pid, NULL, 0)) @@ -104,7 +120,7 @@ handle_event(struct process *proc, int status) case PTRACE_EVENT_VFORK: tprintf(proc, "\nProcess stopped by vfork until child exits or exec(2)s\n"); - /* fall thought */ + /* fall through */ case PTRACE_EVENT_FORK: case PTRACE_EVENT_CLONE: if (ptrace(PTRACE_GETEVENTMSG, proc->pid, NULL, &event)) @@ -259,11 +275,11 @@ main(int argc, char **argv) exit_code = status; if (WIFEXITED(status)) { tprintf(proc, "\nProcess exited with value %i%s\n", WEXITSTATUS(status), - WCOREDUMP(status) ? ", core dumped" : ""); + WCOREDUMP(status) ? ", core dumped" : ""); } else { tprintf(proc, "\nProcess terminated by signal %i (%s: %s)%s\n", WTERMSIG(status), - get_signum_name(WTERMSIG(status)), strsignal(WTERMSIG(status)), - WCOREDUMP(status) ? ", core dumped" : ""); + get_signum_name(WTERMSIG(status)), strsignal(WTERMSIG(status)), + WCOREDUMP(status) ? ", core dumped" : ""); } proc2 = proc->continue_on_exit; remove_process(proc); diff --git a/tests/.gitignore b/tests/.gitignore index a8d6b6c..d961f3e 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1 +1,2 @@ -*.t +*.32 +*.64 diff --git a/tests/Makefile b/tests/Makefile index db5caa7..6e0d8da 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,32 +1,38 @@ .POSIX: -BIN =\ - abort.t\ - cont.t\ - exec.t\ - exit.t\ - fork.t\ - fork-stop.t\ - kill.t\ - raise.t\ - siginfo.t\ - signal.t\ - stop.t\ - threads.t\ - tstp.t\ - vfork.t\ - vfork-exec.t - -all: $(BIN) -$(BIN): $(@:.t=.c) - -.c.t: - $(CC) -static -pthread -Og -g -o $@ $< -D_XOPEN_SOURCE=700 +BIN_64 =\ + abort.64\ + cont.64\ + exec.64\ + exit.64\ + fork.64\ + fork-stop.64\ + kill.64\ + raise.64\ + siginfo.64\ + signal.64\ + stop.64\ + threads.64\ + tstp.64\ + vfork.64\ + vfork-exec.64 + +BIN_32 = $(BIN_64:.64=.32) + +all: $(BIN_64) $(BIN_32) +$(BIN_64): $(@:.64=.c) +$(BIN_32): $(@:.32=.c) + +.c.64: + $(CC) -static -pthread -Og -g -o $@ $< -D_XOPEN_SOURCE=700 -D_DEFAULT_SOURCE + +.c.32: + $(CC) -m32 -static -pthread -Og -g -o $@ $< -D_XOPEN_SOURCE=700 -D_DEFAULT_SOURCE clean: - -rm -f -- $(BIN) + -rm -f -- $(BIN_64) $(BIN_32) .SUFFIXES: -.SUFFIXES: .t .c +.SUFFIXES: .32 .64 .c .PHONY: all clean diff --git a/tests/fork.c b/tests/fork.c index 7bbc4c2..993e0d4 100644 --- a/tests/fork.c +++ b/tests/fork.c @@ -1,15 +1,17 @@ +#include <time.h> #include <unistd.h> int main(void) { + struct timespec ts = {0, 100000000L}; switch (fork()) { case -1: return -1; case 0: return 2; default: - usleep(100000U); + nanosleep(&ts, NULL); return 1; } } diff --git a/tests/signal.c b/tests/signal.c index e4862cd..a68edcd 100644 --- a/tests/signal.c +++ b/tests/signal.c @@ -1,4 +1,5 @@ #include <signal.h> +#include <time.h> #include <unistd.h> static void @@ -10,9 +11,10 @@ interrupt() int main(void) { + struct timespec ts = {0, 100000000L}; signal(SIGINT, interrupt); kill(getpid(), SIGINT); - usleep(100000U); + nanosleep(&ts, NULL); write(-1, "qwerty\n", 7); return 0; } |