diff --git a/usr.bin/truss/aarch64-cloudabi64.c b/usr.bin/truss/aarch64-cloudabi64.c index 6a1694a965df..ee81a5321a81 100644 --- a/usr.bin/truss/aarch64-cloudabi64.c +++ b/usr.bin/truss/aarch64-cloudabi64.c @@ -80,7 +80,9 @@ static struct procabi aarch64_cloudabi64 = { "CloudABI ELF64", SYSDECODE_ABI_CLOUDABI64, aarch64_cloudabi64_fetch_args, - aarch64_cloudabi64_fetch_retval + aarch64_cloudabi64_fetch_retval, + STAILQ_HEAD_INITIALIZER(aarch64_cloudabi64.extra_syscalls), + { NULL } }; PROCABI(aarch64_cloudabi64); diff --git a/usr.bin/truss/aarch64-freebsd.c b/usr.bin/truss/aarch64-freebsd.c index a9944f52f4fd..b47d0f8e1011 100644 --- a/usr.bin/truss/aarch64-freebsd.c +++ b/usr.bin/truss/aarch64-freebsd.c @@ -102,7 +102,9 @@ static struct procabi aarch64_freebsd = { "FreeBSD ELF64", SYSDECODE_ABI_FREEBSD, aarch64_fetch_args, - aarch64_fetch_retval + aarch64_fetch_retval, + STAILQ_HEAD_INITIALIZER(aarch64_freebsd.extra_syscalls), + { NULL } }; PROCABI(aarch64_freebsd); diff --git a/usr.bin/truss/amd64-cloudabi64.c b/usr.bin/truss/amd64-cloudabi64.c index 06de94474c1e..d0caaec67679 100644 --- a/usr.bin/truss/amd64-cloudabi64.c +++ b/usr.bin/truss/amd64-cloudabi64.c @@ -89,7 +89,9 @@ static struct procabi amd64_cloudabi64 = { "CloudABI ELF64", SYSDECODE_ABI_CLOUDABI64, amd64_cloudabi64_fetch_args, - amd64_cloudabi64_fetch_retval + amd64_cloudabi64_fetch_retval, + STAILQ_HEAD_INITIALIZER(amd64_cloudabi64.extra_syscalls), + { NULL } }; PROCABI(amd64_cloudabi64); diff --git a/usr.bin/truss/amd64-freebsd.c b/usr.bin/truss/amd64-freebsd.c index fa844fa09340..7e2ed160a90d 100644 --- a/usr.bin/truss/amd64-freebsd.c +++ b/usr.bin/truss/amd64-freebsd.c @@ -124,7 +124,9 @@ static struct procabi amd64_freebsd = { "FreeBSD ELF64", SYSDECODE_ABI_FREEBSD, amd64_fetch_args, - amd64_fetch_retval + amd64_fetch_retval, + STAILQ_HEAD_INITIALIZER(amd64_freebsd.extra_syscalls), + { NULL } }; PROCABI(amd64_freebsd); diff --git a/usr.bin/truss/amd64-freebsd32.c b/usr.bin/truss/amd64-freebsd32.c index adbc3e74c0c5..66ca417e9495 100644 --- a/usr.bin/truss/amd64-freebsd32.c +++ b/usr.bin/truss/amd64-freebsd32.c @@ -120,7 +120,9 @@ static struct procabi amd64_freebsd32 = { "FreeBSD ELF32", SYSDECODE_ABI_FREEBSD32, amd64_freebsd32_fetch_args, - amd64_freebsd32_fetch_retval + amd64_freebsd32_fetch_retval, + STAILQ_HEAD_INITIALIZER(amd64_freebsd32.extra_syscalls), + { NULL } }; PROCABI(amd64_freebsd32); @@ -129,7 +131,9 @@ static struct procabi amd64_freebsd32_aout = { "FreeBSD a.out", SYSDECODE_ABI_FREEBSD32, amd64_freebsd32_fetch_args, - amd64_freebsd32_fetch_retval + amd64_freebsd32_fetch_retval, + STAILQ_HEAD_INITIALIZER(amd64_freebsd32.extra_syscalls), + { NULL } }; PROCABI(amd64_freebsd32_aout); diff --git a/usr.bin/truss/amd64-linux.c b/usr.bin/truss/amd64-linux.c index 94a3d6abce94..00eb06ff75f8 100644 --- a/usr.bin/truss/amd64-linux.c +++ b/usr.bin/truss/amd64-linux.c @@ -99,7 +99,9 @@ static struct procabi amd64_linux = { "Linux ELF64", SYSDECODE_ABI_LINUX, amd64_linux_fetch_args, - amd64_linux_fetch_retval + amd64_linux_fetch_retval, + STAILQ_HEAD_INITIALIZER(amd64_linux.extra_syscalls), + { NULL } }; PROCABI(amd64_linux); diff --git a/usr.bin/truss/amd64-linux32.c b/usr.bin/truss/amd64-linux32.c index 3f32c8473f37..70e201adfe91 100644 --- a/usr.bin/truss/amd64-linux32.c +++ b/usr.bin/truss/amd64-linux32.c @@ -109,7 +109,9 @@ static struct procabi amd64_linux32 = { "Linux ELF32", SYSDECODE_ABI_LINUX32, amd64_linux32_fetch_args, - amd64_linux32_fetch_retval + amd64_linux32_fetch_retval, + STAILQ_HEAD_INITIALIZER(amd64_linux32.extra_syscalls), + { NULL } }; PROCABI(amd64_linux32); diff --git a/usr.bin/truss/arm-freebsd.c b/usr.bin/truss/arm-freebsd.c index 826a8d838294..753829005946 100644 --- a/usr.bin/truss/arm-freebsd.c +++ b/usr.bin/truss/arm-freebsd.c @@ -131,7 +131,9 @@ static struct procabi arm_freebsd = { "FreeBSD ELF32", SYSDECODE_ABI_FREEBSD, arm_fetch_args, - arm_fetch_retval + arm_fetch_retval, + STAILQ_HEAD_INITIALIZER(arm_freebsd.extra_syscalls), + { NULL } }; PROCABI(arm_freebsd); diff --git a/usr.bin/truss/i386-freebsd.c b/usr.bin/truss/i386-freebsd.c index 469ab7de9b7a..8103ca7beead 100644 --- a/usr.bin/truss/i386-freebsd.c +++ b/usr.bin/truss/i386-freebsd.c @@ -113,7 +113,9 @@ static struct procabi i386_freebsd = { "FreeBSD ELF32", SYSDECODE_ABI_FREEBSD, i386_fetch_args, - i386_fetch_retval + i386_fetch_retval, + STAILQ_HEAD_INITIALIZER(i386_freebsd.extra_syscalls), + { NULL } }; PROCABI(i386_freebsd); @@ -122,7 +124,9 @@ static struct procabi i386_freebsd_aout = { "FreeBSD a.out", SYSDECODE_ABI_FREEBSD, i386_fetch_args, - i386_fetch_retval + i386_fetch_retval, + STAILQ_HEAD_INITIALIZER(i386_freebsd_aout.extra_syscalls), + { NULL } }; PROCABI(i386_freebsd_aout); diff --git a/usr.bin/truss/i386-linux.c b/usr.bin/truss/i386-linux.c index 56fab65cefb7..e96db16c7a91 100644 --- a/usr.bin/truss/i386-linux.c +++ b/usr.bin/truss/i386-linux.c @@ -106,7 +106,9 @@ static struct procabi i386_linux = { "Linux ELF", SYSDECODE_ABI_LINUX, i386_linux_fetch_args, - i386_linux_fetch_retval + i386_linux_fetch_retval, + STAILQ_HEAD_INITIALIZER(i386_linux.extra_syscalls), + { NULL } }; PROCABI(i386_linux); diff --git a/usr.bin/truss/mips-freebsd.c b/usr.bin/truss/mips-freebsd.c index ac803b942f27..e3f2a04e97fb 100644 --- a/usr.bin/truss/mips-freebsd.c +++ b/usr.bin/truss/mips-freebsd.c @@ -134,7 +134,9 @@ static struct procabi mips_freebsd = { #endif SYSDECODE_ABI_FREEBSD, mips_fetch_args, - mips_fetch_retval + mips_fetch_retval, + STAILQ_HEAD_INITIALIZER(mips_freebsd.extra_syscalls), + { NULL } }; PROCABI(mips_freebsd); diff --git a/usr.bin/truss/powerpc-freebsd.c b/usr.bin/truss/powerpc-freebsd.c index dbeba2b36baf..f60c3339fdd1 100644 --- a/usr.bin/truss/powerpc-freebsd.c +++ b/usr.bin/truss/powerpc-freebsd.c @@ -115,7 +115,9 @@ static struct procabi powerpc_freebsd = { "FreeBSD ELF32", SYSDECODE_ABI_FREEBSD, powerpc_fetch_args, - powerpc_fetch_retval + powerpc_fetch_retval, + STAILQ_HEAD_INITIALIZER(powerpc_freebsd.extra_syscalls), + { NULL } }; PROCABI(powerpc_freebsd); diff --git a/usr.bin/truss/powerpc64-freebsd.c b/usr.bin/truss/powerpc64-freebsd.c index a8927bb5cc7c..ca2e108a2a82 100644 --- a/usr.bin/truss/powerpc64-freebsd.c +++ b/usr.bin/truss/powerpc64-freebsd.c @@ -111,7 +111,9 @@ static struct procabi powerpc64_freebsd = { "FreeBSD ELF64", SYSDECODE_ABI_FREEBSD, powerpc64_fetch_args, - powerpc64_fetch_retval + powerpc64_fetch_retval, + STAILQ_HEAD_INITIALIZER(powerpc64_freebsd.extra_syscalls), + { NULL } }; PROCABI(powerpc64_freebsd); diff --git a/usr.bin/truss/powerpc64-freebsd32.c b/usr.bin/truss/powerpc64-freebsd32.c index bc8d2fc97a7f..cddf492acd6a 100644 --- a/usr.bin/truss/powerpc64-freebsd32.c +++ b/usr.bin/truss/powerpc64-freebsd32.c @@ -120,7 +120,9 @@ static struct procabi powerpc64_freebsd32 = { "FreeBSD ELF32", SYSDECODE_ABI_FREEBSD32, powerpc64_freebsd32_fetch_args, - powerpc64_freebsd32_fetch_retval + powerpc64_freebsd32_fetch_retval, + STAILQ_HEAD_INITIALIZER(powerpc64_freebsd32.extra_syscalls), + { NULL } }; PROCABI(powerpc64_freebsd32); diff --git a/usr.bin/truss/setup.c b/usr.bin/truss/setup.c index 036cb8f40ccc..24e028a98186 100644 --- a/usr.bin/truss/setup.c +++ b/usr.bin/truss/setup.c @@ -344,7 +344,7 @@ alloc_syscall(struct threadinfo *t, struct ptrace_lwpinfo *pl) assert(t->in_syscall == 0); assert(t->cs.number == 0); - assert(t->cs.name == NULL); + assert(t->cs.sc == NULL); assert(t->cs.nargs == 0); for (i = 0; i < nitems(t->cs.s_args); i++) assert(t->cs.s_args[i] == NULL); @@ -378,12 +378,11 @@ enter_syscall(struct trussinfo *info, struct threadinfo *t, return; } - t->cs.name = sysdecode_syscallname(t->proc->abi->abi, t->cs.number); - if (t->cs.name == NULL) + sc = get_syscall(t, t->cs.number, narg); + if (sc->unknown) fprintf(info->outfile, "-- UNKNOWN %s SYSCALL %d --\n", t->proc->abi->type, t->cs.number); - sc = get_syscall(t->cs.name, narg); t->cs.nargs = sc->nargs; assert(sc->nargs <= nitems(t->cs.s_args)); @@ -396,25 +395,22 @@ enter_syscall(struct trussinfo *info, struct threadinfo *t, * now. This doesn't currently support arguments that are * passed in *and* out, however. */ - if (t->cs.name != NULL) { #if DEBUG - fprintf(stderr, "syscall %s(", t->cs.name); + fprintf(stderr, "syscall %s(", sc->name); #endif - for (i = 0; i < t->cs.nargs; i++) { + for (i = 0; i < t->cs.nargs; i++) { #if DEBUG - fprintf(stderr, "0x%lx%s", sc ? - t->cs.args[sc->args[i].offset] : t->cs.args[i], - i < (t->cs.nargs - 1) ? "," : ""); + fprintf(stderr, "0x%lx%s", t->cs.args[sc->args[i].offset], + i < (t->cs.nargs - 1) ? "," : ""); #endif - if (!(sc->args[i].type & OUT)) { - t->cs.s_args[i] = print_arg(&sc->args[i], - t->cs.args, 0, info); - } + if (!(sc->args[i].type & OUT)) { + t->cs.s_args[i] = print_arg(&sc->args[i], + t->cs.args, 0, info); } -#if DEBUG - fprintf(stderr, ")\n"); -#endif } +#if DEBUG + fprintf(stderr, ")\n"); +#endif clock_gettime(CLOCK_REALTIME, &t->before); } diff --git a/usr.bin/truss/sparc64-freebsd.c b/usr.bin/truss/sparc64-freebsd.c index 3cbad50df70b..d1ae89685de7 100644 --- a/usr.bin/truss/sparc64-freebsd.c +++ b/usr.bin/truss/sparc64-freebsd.c @@ -118,7 +118,9 @@ static struct procabi sparc64_freebsd = { "FreeBSD ELF64", SYSDECODE_ABI_FREEBSD, sparc64_fetch_args, - sparc64_fetch_retval + sparc64_fetch_retval, + STAILQ_HEAD_INITIALIZER(sparc64_freebsd.extra_syscalls), + { NULL } }; PROCABI(sparc64_freebsd); diff --git a/usr.bin/truss/syscall.h b/usr.bin/truss/syscall.h index 0cd752d77a03..90b0e8aa94cd 100644 --- a/usr.bin/truss/syscall.h +++ b/usr.bin/truss/syscall.h @@ -72,9 +72,10 @@ struct syscall { struct timespec time; /* Time spent for this call */ int ncalls; /* Number of calls */ int nerror; /* Number of calls that returned with error */ + bool unknown; /* Unknown system call */ }; -struct syscall *get_syscall(const char *, int nargs); +struct syscall *get_syscall(struct threadinfo *, u_int, u_int); char *print_arg(struct syscall_args *, unsigned long*, long *, struct trussinfo *); /* diff --git a/usr.bin/truss/syscalls.c b/usr.bin/truss/syscalls.c index 46bc87f9575b..2aeafcb224a6 100644 --- a/usr.bin/truss/syscalls.c +++ b/usr.bin/truss/syscalls.c @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -819,21 +820,66 @@ init_syscalls(void) for (sc = decoded_syscalls; sc->name != NULL; sc++) STAILQ_INSERT_HEAD(&syscalls, sc, entries); } + +static struct syscall * +find_syscall(struct procabi *abi, u_int number) +{ + struct extra_syscall *es; + + if (number < nitems(abi->syscalls)) + return (abi->syscalls[number]); + STAILQ_FOREACH(es, &abi->extra_syscalls, entries) { + if (es->number == number) + return (es->sc); + } + return (NULL); +} + +static void +add_syscall(struct procabi *abi, u_int number, struct syscall *sc) +{ + struct extra_syscall *es; + + if (number < nitems(abi->syscalls)) { + assert(abi->syscalls[number] == NULL); + abi->syscalls[number] = sc; + } else { + es = malloc(sizeof(*es)); + es->sc = sc; + es->number = number; + STAILQ_INSERT_TAIL(&abi->extra_syscalls, es, entries); + } +} + /* * If/when the list gets big, it might be desirable to do it * as a hash table or binary search. */ struct syscall * -get_syscall(const char *name, int nargs) +get_syscall(struct threadinfo *t, u_int number, u_int nargs) { struct syscall *sc; - int i; + const char *name; + char *new_name; + u_int i; - if (name == NULL) - return (NULL); - STAILQ_FOREACH(sc, &syscalls, entries) - if (strcmp(name, sc->name) == 0) + sc = find_syscall(t->proc->abi, number); + if (sc != NULL) + return (sc); + + name = sysdecode_syscallname(t->proc->abi->abi, number); + if (name == NULL) { + asprintf(&new_name, "#%d", number); + name = new_name; + } else + new_name = NULL; + STAILQ_FOREACH(sc, &syscalls, entries) { + if (strcmp(name, sc->name) == 0) { + add_syscall(t->proc->abi, number, sc); + free(new_name); return (sc); + } + } /* It is unknown. Add it into the list. */ #if DEBUG @@ -842,7 +888,9 @@ get_syscall(const char *name, int nargs) #endif sc = calloc(1, sizeof(struct syscall)); - sc->name = strdup(name); + sc->name = name; + if (new_name != NULL) + sc->unknown = true; sc->ret_type = 1; sc->nargs = nargs; for (i = 0; i < nargs; i++) { @@ -851,6 +899,7 @@ get_syscall(const char *name, int nargs) sc->args[i].type = LongHex; } STAILQ_INSERT_HEAD(&syscalls, sc, entries); + add_syscall(t->proc->abi, number, sc); return (sc); } @@ -1866,7 +1915,7 @@ print_syscall(struct trussinfo *trussinfo) t = trussinfo->curthread; - name = t->cs.name; + name = t->cs.sc->name; nargs = t->cs.nargs; s_args = t->cs.s_args; diff --git a/usr.bin/truss/truss.h b/usr.bin/truss/truss.h index dee2155dfb22..53282965cc93 100644 --- a/usr.bin/truss/truss.h +++ b/usr.bin/truss/truss.h @@ -38,13 +38,29 @@ #define DISPLAYTIDS 0x00000080 struct procinfo; +struct syscall; struct trussinfo; +/* + * The lookup of normal system calls are optimized by using a fixed + * array for the first 1024 system calls that can be indexed directly. + * Unknown system calls with other IDs are stored in a linked list. + */ +#define SYSCALL_NORMAL_COUNT 1024 + +struct extra_syscall { + STAILQ_ENTRY(extra_syscall) entries; + struct syscall *sc; + u_int number; +}; + struct procabi { const char *type; enum sysdecode_abi abi; int (*fetch_args)(struct trussinfo *, u_int); int (*fetch_retval)(struct trussinfo *, long *, int *); + STAILQ_HEAD(, extra_syscall) extra_syscalls; + struct syscall *syscalls[SYSCALL_NORMAL_COUNT]; }; #define PROCABI(abi) DATA_SET(procabi, abi) @@ -64,10 +80,9 @@ struct procabi { */ struct current_syscall { struct syscall *sc; - const char *name; - int number; - unsigned long args[10]; + unsigned int number; unsigned int nargs; + unsigned long args[10]; char *s_args[10]; /* the printable arguments */ };