#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/pioctl.h>
#include <sys/syscall.h>
#include <machine/reg.h>
#include <machine/psl.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "truss.h"
#include "extern.h"
#include "syscall.h"
static int fd = -1;
static int cpid = -1;
#include "syscalls.h"
static int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]);
static struct freebsd_syscall {
struct syscall *sc;
const char *name;
int number;
unsigned long *args;
int nargs;
char **s_args;
} fsc;
static inline void
clear_fsc(void) {
free(fsc.args);
if (fsc.s_args) {
int i;
for (i = 0; i < fsc.nargs; i++)
free(fsc.s_args[i]);
free(fsc.s_args);
}
memset(&fsc, 0, sizeof(fsc));
}
void
x86_64_syscall_entry(struct trussinfo *trussinfo, int nargs) {
char *buf;
struct reg regs = { .r_err = 0 };
int syscall_num;
int i, reg;
int is_xsyscall;
struct syscall *sc;
if (fd == -1 || trussinfo->pid != cpid) {
asprintf(&buf, "%s/%d/regs", procfs_path, trussinfo->pid);
if (buf == NULL)
err(1, "Out of memory");
fd = open(buf, O_RDWR);
free(buf);
if (fd == -1) {
fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
return;
}
cpid = trussinfo->pid;
}
clear_fsc();
i = pread(fd, ®s, sizeof(regs), 0L);
reg = 0;
syscall_num = regs.r_rax;
is_xsyscall = 0;
switch (syscall_num) {
case SYS_syscall:
case SYS___syscall:
is_xsyscall = 1;
syscall_num = regs.r_rdi;
reg++;
break;
}
fsc.number = syscall_num;
fsc.name =
(syscall_num < 0 || syscall_num >= nsyscalls) ? NULL : syscallnames[syscall_num];
if (!fsc.name) {
fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall_num);
}
sc = fsc.name ? get_syscall(fsc.name) : NULL;
if (sc) {
fsc.nargs = sc->nargs;
} else {
#ifdef DEBUG
fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n",
fsc.name, nargs);
#endif
fsc.nargs = nargs;
}
if (is_xsyscall) {
if (nargs == 0)
nargs = fsc.nargs;
}
if (nargs == 0) {
return;
}
fsc.args = malloc((1+nargs) * sizeof(unsigned long));
for (i = 0; i < nargs && reg < 6; i++, reg++) {
switch (reg) {
case 0: fsc.args[i] = regs.r_rdi; break;
case 1: fsc.args[i] = regs.r_rsi; break;
case 2: fsc.args[i] = regs.r_rdx; break;
case 3: fsc.args[i] = regs.r_rcx; break;
case 4: fsc.args[i] = regs.r_r8; break;
case 5: fsc.args[i] = regs.r_r9; break;
}
}
if (nargs > i) {
if (pread(Procfd, &fsc.args[i], (nargs-i) * sizeof(register_t),
regs.r_rsp + 2*sizeof(register_t)) == -1) {
free(fsc.args);
return;
}
}
fsc.s_args = calloc(1+fsc.nargs, sizeof(char*));
fsc.sc = sc;
if (fsc.name) {
#ifdef DEBUG
fprintf(stderr, "syscall %s(", fsc.name);
#endif
for (i = 0; i < fsc.nargs; i++) {
#ifdef DEBUG
fprintf(stderr, "0x%lx%s",
sc
? fsc.args[sc->args[i].offset]
: fsc.args[i],
i < (fsc.nargs -1) ? "," : "");
#endif
if (sc && !(sc->args[i].type & OUT)) {
fsc.s_args[i] = print_arg(Procfd, &sc->args[i], fsc.args);
}
}
#ifdef DEBUG
fprintf(stderr, ")\n");
#endif
}
#ifdef DEBUG
fprintf(trussinfo->outfile, "\n");
#endif
if (fsc.name != NULL &&
(!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit"))) {
print_syscall(trussinfo, fsc.name, fsc.nargs, fsc.s_args);
}
if (sc != NULL && sc->ret_type == 0)
fprintf(trussinfo->outfile, "\n");
return;
}
int
x86_64_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) {
char *buf;
struct reg regs;
int retval;
int i;
int errorp;
struct syscall *sc;
if (fsc.name == NULL)
return 0;
if (fd == -1 || trussinfo->pid != cpid) {
asprintf(&buf, "%s/%d/regs", procfs_path, trussinfo->pid);
if (buf == NULL)
err(1, "Out of memory");
fd = open(buf, O_RDONLY);
free(buf);
if (fd == -1) {
fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
return 0;
}
cpid = trussinfo->pid;
}
if (pread(fd, ®s, sizeof(regs), 0L) != sizeof(regs)) {
fprintf(trussinfo->outfile, "\n");
return 0;
}
retval = regs.r_rax;
errorp = !!(regs.r_rflags & PSL_C);
sc = fsc.sc;
if (!sc) {
for (i = 0; i < fsc.nargs; i++)
asprintf(&fsc.s_args[i], "0x%lx", fsc.args[i]);
} else {
for (i = 0; i < sc->nargs; i++) {
char *temp;
if (sc->args[i].type & OUT) {
if (errorp) {
asprintf(&temp, "0x%lx", fsc.args[sc->args[i].offset]);
} else {
temp = print_arg(Procfd, &sc->args[i], fsc.args);
}
fsc.s_args[i] = temp;
}
}
}
print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, retval);
clear_fsc();
return (retval);
}