Teach truss about 32-bit FreeBSD and Linux binaries on amd64. Some

additional work is needed to handle ABI-specific syscall argument parsing,
but this gets the basic tracing working.

MFC after:	1 week
This commit is contained in:
John Baldwin 2008-05-16 15:34:06 +00:00
parent c1163871f6
commit 9a55503ec1
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=179051
7 changed files with 108 additions and 43 deletions

View File

@ -4,23 +4,12 @@ WARNS?= 6
NO_WERROR=
PROG= truss
SRCS= main.c setup.c syscalls.c syscalls.h ioctl.c ${MACHINE_ARCH}-fbsd.c
.if ${MACHINE_ARCH} == "i386"
SRCS+= i386-linux.c linux_syscalls.h
.endif
CFLAGS+= -I${.CURDIR} -I.
CLEANFILES=i386l-syscalls.master syscalls.master linux_syscalls.h \
syscalls.h ioctl.c
CLEANFILES= syscalls.master syscalls.h ioctl.c
.SUFFIXES: .master
i386l-syscalls.master: ${.CURDIR}/../../sys/i386/linux/syscalls.master
cat ${.ALLSRC} > i386l-syscalls.master
linux_syscalls.h: i386l-syscalls.master
/bin/sh ${.CURDIR}/../../sys/kern/makesyscalls.sh i386l-syscalls.master \
${.CURDIR}/i386linux.conf
syscalls.master: ${.CURDIR}/../../sys/kern/syscalls.master
cat ${.ALLSRC} > syscalls.master
@ -31,4 +20,38 @@ syscalls.h: syscalls.master
ioctl.c: ${.CURDIR}/../kdump/mkioctls
sh ${.CURDIR}/../kdump/mkioctls ${DESTDIR}/usr/include > ${.TARGET}
.if ${MACHINE_ARCH} == "i386"
SRCS+= i386-linux.c linux_syscalls.h
CLEANFILES+=i386l-syscalls.master linux_syscalls.h
i386l-syscalls.master: ${.CURDIR}/../../sys/i386/linux/syscalls.master
cat ${.ALLSRC} > ${.TARGET}
linux_syscalls.h: i386l-syscalls.master
/bin/sh ${.CURDIR}/../../sys/kern/makesyscalls.sh ${.ALLSRC} \
${.CURDIR}/i386linux.conf
.endif
.if ${MACHINE_ARCH} == "amd64"
SRCS+= amd64-linux32.c linux32_syscalls.h
CLEANFILES+=amd64l32-syscalls.master linux32_syscalls.h
amd64l32-syscalls.master: ${.CURDIR}/../../sys/amd64/linux32/syscalls.master
cat ${.ALLSRC} > ${.TARGET}
linux32_syscalls.h: amd64l32-syscalls.master
/bin/sh ${.CURDIR}/../../sys/kern/makesyscalls.sh ${.ALLSRC} \
${.CURDIR}/amd64linux32.conf
SRCS+= amd64-fbsd32.c freebsd32_syscalls.h
CLEANFILES+=fbsd32-syscalls.master freebsd32_syscalls.h
fbsd32-syscalls.master: ${.CURDIR}/../../sys/compat/freebsd32/syscalls.master
cat ${.ALLSRC} > ${.TARGET}
freebsd32_syscalls.h: fbsd32-syscalls.master
/bin/sh ${.CURDIR}/../../sys/kern/makesyscalls.sh ${.ALLSRC} \
${.CURDIR}/fbsd32.conf
.endif
.include <bsd.prog.mk>

View File

@ -64,9 +64,10 @@ static const char rcsid[] =
static int cpid = -1;
#include "syscalls.h"
#include "freebsd32_syscalls.h"
static int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]);
static int nsyscalls = sizeof(freebsd32_syscallnames) /
sizeof(freebsd32_syscallnames[0]);
/*
* This is what this particular file uses to keep track of a system call.
@ -77,11 +78,12 @@ static int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]);
* 'struct syscall' describes the system call; it may be NULL, however,
* if we don't know about this particular system call yet.
*/
static struct freebsd_syscall {
static struct freebsd32_syscall {
struct syscall *sc;
const char *name;
int number;
unsigned long *args;
unsigned int *args32;
int nargs; /* number of arguments -- *not* number of words! */
char **s_args; /* the printable arguments */
} fsc;
@ -92,6 +94,9 @@ clear_fsc(void) {
if (fsc.args) {
free(fsc.args);
}
if (fsc.args32) {
free(fsc.args32);
}
if (fsc.s_args) {
int i;
for (i = 0; i < fsc.nargs; i++)
@ -110,11 +115,11 @@ clear_fsc(void) {
*/
void
i386_syscall_entry(struct trussinfo *trussinfo, int nargs) {
amd64_fbsd32_syscall_entry(struct trussinfo *trussinfo, int nargs) {
struct reg regs;
int syscall_num;
int i;
unsigned int parm_offset;
unsigned long parm_offset;
struct syscall *sc = NULL;
struct ptrace_io_desc iorequest;
cpid = trussinfo->curthread->tid;
@ -126,14 +131,14 @@ i386_syscall_entry(struct trussinfo *trussinfo, int nargs) {
fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
return;
}
parm_offset = regs.r_esp + sizeof(int);
parm_offset = regs.r_rsp + sizeof(int);
/*
* FreeBSD has two special kinds of system call redirctions --
* SYS_syscall, and SYS___syscall. The former is the old syscall()
* routine, basicly; the latter is for quad-aligned arguments.
*/
syscall_num = regs.r_eax;
syscall_num = regs.r_rax;
switch (syscall_num) {
case SYS_syscall:
syscall_num = ptrace(PT_READ_D, cpid, (caddr_t)parm_offset, 0);
@ -147,7 +152,8 @@ i386_syscall_entry(struct trussinfo *trussinfo, int nargs) {
fsc.number = syscall_num;
fsc.name =
(syscall_num < 0 || syscall_num > nsyscalls) ? NULL : syscallnames[syscall_num];
(syscall_num < 0 || syscall_num > nsyscalls) ? NULL :
freebsd32_syscallnames[syscall_num];
if (!fsc.name) {
fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall_num);
}
@ -163,15 +169,19 @@ i386_syscall_entry(struct trussinfo *trussinfo, int nargs) {
if (nargs == 0)
return;
fsc.args = malloc((1+nargs) * sizeof(unsigned long));
fsc.args32 = malloc((1+nargs) * sizeof(unsigned int));
iorequest.piod_op = PIOD_READ_D;
iorequest.piod_offs = (void *)parm_offset;
iorequest.piod_addr = fsc.args;
iorequest.piod_len = (1+nargs) * sizeof(unsigned long);
iorequest.piod_addr = fsc.args32;
iorequest.piod_len = (1+nargs) * sizeof(unsigned int);
ptrace(PT_IO, cpid, (caddr_t)&iorequest, 0);
if (iorequest.piod_len == 0)
return;
fsc.args = malloc((1+nargs) * sizeof(unsigned long));
for (i = 0; i < nargs + 1; i++)
fsc.args[i] = fsc.args32[i];
if (fsc.name)
sc = get_syscall(fsc.name);
if (sc) {
@ -223,13 +233,13 @@ i386_syscall_entry(struct trussinfo *trussinfo, int nargs) {
#endif
if (fsc.name != NULL &&
(!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit"))) {
(!strcmp(fsc.name, "freebsd32_execve") || !strcmp(fsc.name, "exit"))) {
/* XXX
* This could be done in a more general
* manner but it still wouldn't be very pretty.
*/
if (!strcmp(fsc.name, "execve")) {
if (!strcmp(fsc.name, "freebsd32_execve")) {
if ((trussinfo->flags & EXECVEARGS) == 0)
if (fsc.s_args[1]) {
free(fsc.s_args[1]);
@ -255,7 +265,7 @@ i386_syscall_entry(struct trussinfo *trussinfo, int nargs) {
*/
long
i386_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
amd64_fbsd32_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
{
struct reg regs;
long retval;
@ -273,8 +283,8 @@ i386_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
return (-1);
}
retval = regs.r_eax;
errorp = !!(regs.r_eflags & PSL_C);
retval = regs.r_rax;
errorp = !!(regs.r_rflags & PSL_C);
/*
* This code, while simpler than the initial versions I used, could
@ -315,12 +325,12 @@ i386_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
if (!errorp && fsc.nargs == 0 && fsc.name && strcmp(fsc.name, "pipe") == 0) {
fsc.nargs = 1;
fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*));
asprintf(&fsc.s_args[0], "[%d,%d]", (int)retval, regs.r_edx);
asprintf(&fsc.s_args[0], "[%d,%d]", (int)retval, (int)regs.r_rdx);
retval = 0;
}
if (fsc.name != NULL &&
(!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit"))) {
(!strcmp(fsc.name, "freebsd32_execve") || !strcmp(fsc.name, "exit"))) {
trussinfo->curthread->in_syscall = 1;
}

View File

@ -61,10 +61,10 @@ static const char rcsid[] =
static int cpid = -1;
#include "linux_syscalls.h"
#include "linux32_syscalls.h"
static int nsyscalls =
sizeof(linux_syscallnames) / sizeof(linux_syscallnames[0]);
sizeof(linux32_syscallnames) / sizeof(linux32_syscallnames[0]);
/*
* This is what this particular file uses to keep track of a system call.
@ -105,7 +105,7 @@ clear_fsc(void) {
*/
void
i386_linux_syscall_entry(struct trussinfo *trussinfo, int nargs) {
amd64_linux32_syscall_entry(struct trussinfo *trussinfo, int nargs) {
struct reg regs;
int syscall_num;
int i;
@ -120,11 +120,11 @@ i386_linux_syscall_entry(struct trussinfo *trussinfo, int nargs) {
fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
return;
}
syscall_num = regs.r_eax;
syscall_num = regs.r_rax;
fsc.number = syscall_num;
fsc.name =
(syscall_num < 0 || syscall_num > nsyscalls) ? NULL : linux_syscallnames[syscall_num];
(syscall_num < 0 || syscall_num > nsyscalls) ? NULL : linux32_syscallnames[syscall_num];
if (!fsc.name) {
fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall_num);
}
@ -147,11 +147,11 @@ i386_linux_syscall_entry(struct trussinfo *trussinfo, int nargs) {
* that have more than five arguments?
*/
fsc.args[0] = regs.r_ebx;
fsc.args[1] = regs.r_ecx;
fsc.args[2] = regs.r_edx;
fsc.args[3] = regs.r_esi;
fsc.args[4] = regs.r_edi;
fsc.args[0] = regs.r_rbx;
fsc.args[1] = regs.r_rcx;
fsc.args[2] = regs.r_rdx;
fsc.args[3] = regs.r_rsi;
fsc.args[4] = regs.r_rdi;
sc = get_syscall(fsc.name);
if (sc) {
@ -242,7 +242,7 @@ const int bsd_to_linux_errno[] = {
};
long
i386_linux_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
amd64_linux32_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
{
struct reg regs;
long retval;
@ -260,8 +260,8 @@ i386_linux_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
return (-1);
}
retval = regs.r_eax;
errorp = !!(regs.r_eflags & PSL_C);
retval = regs.r_rax;
errorp = !!(regs.r_rflags & PSL_C);
/*
* This code, while simpler than the initial versions I used, could

View File

@ -0,0 +1,13 @@
# $FreeBSD$
sysnames="linux32_syscalls.h"
sysproto="/dev/null"
sysproto_h="/dev/null"
syshdr="/dev/null"
sysmk="/dev/null"
syssw="/dev/null"
syshide="/dev/null"
syscallprefix="SYS_"
switchname="sysent"
namesname="linux32_syscallnames"
systrace="/dev/null"

View File

@ -44,6 +44,10 @@ extern long alpha_syscall_exit(struct trussinfo *, int);
#ifdef __amd64__
extern void amd64_syscall_entry(struct trussinfo *, int);
extern long amd64_syscall_exit(struct trussinfo *, int);
extern void amd64_linux32_syscall_entry(struct trussinfo *, int);
extern long amd64_linux32_syscall_exit(struct trussinfo *, int);
extern void amd64_fbsd32_syscall_entry(struct trussinfo *, int);
extern long amd64_fbsd32_syscall_exit(struct trussinfo *, int);
#endif
#ifdef __i386__
extern void i386_syscall_entry(struct trussinfo *, int);

13
usr.bin/truss/fbsd32.conf Normal file
View File

@ -0,0 +1,13 @@
# $FreeBSD$
sysnames="freebsd32_syscalls.h"
sysproto="/dev/null"
sysproto_h="/dev/null"
syshdr="/dev/null"
sysmk="/dev/null"
syssw="/dev/null"
syshide="/dev/null"
syscallprefix="SYS_"
switchname="sysent"
namesname="freebsd32_syscallnames"
systrace="/dev/null"

View File

@ -83,6 +83,8 @@ struct ex_types {
#endif
#ifdef __amd64__
{ "FreeBSD ELF64", amd64_syscall_entry, amd64_syscall_exit },
{ "FreeBSD ELF32", amd64_fbsd32_syscall_entry, amd64_fbsd32_syscall_exit },
{ "Linux ELF32", amd64_linux32_syscall_entry, amd64_linux32_syscall_exit },
#endif
#ifdef __i386__
{ "FreeBSD a.out", i386_syscall_entry, i386_syscall_exit },