aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--arch-x86-64.h29
-rw-r--r--common.h16
-rw-r--r--process.c22
-rw-r--r--sctrace.c42
-rw-r--r--tests/.gitignore3
-rw-r--r--tests/Makefile54
-rw-r--r--tests/fork.c4
-rw-r--r--tests/signal.c4
9 files changed, 120 insertions, 55 deletions
diff --git a/Makefile b/Makefile
index 6687ce7..44c177b 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/common.h b/common.h
index 458d4f9..0c9ff8f 100644
--- a/common.h
+++ b/common.h
@@ -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"
diff --git a/process.c b/process.c
index f979e21..117fd6a 100644
--- a/process.c
+++ b/process.c
@@ -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;
diff --git a/sctrace.c b/sctrace.c
index 55ce808..9bab8ff 100644
--- a/sctrace.c
+++ b/sctrace.c
@@ -18,19 +18,35 @@ static void
handle_syscall(struct process *proc)
{
struct user_regs_struct regs;
+ struct iovec iov = {
+ .iov_base = &regs,
+ .iov_len = sizeof(regs),
+ };
switch ((int)proc->state) {
default:
/* Get system call arguments */
if (ptrace(PTRACE_GETREGS, proc->pid, NULL, &regs))
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, &regs))
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;
}