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:
parent
c1163871f6
commit
9a55503ec1
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=179051
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
13
usr.bin/truss/amd64linux32.conf
Normal file
13
usr.bin/truss/amd64linux32.conf
Normal 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"
|
@ -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
13
usr.bin/truss/fbsd32.conf
Normal 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"
|
@ -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 },
|
||||
|
Loading…
Reference in New Issue
Block a user