Index: usr.bin/truss/main.c =================================================================== --- usr.bin/truss/main.c +++ usr.bin/truss/main.c @@ -87,7 +87,6 @@ trussinfo->strsize = 32; trussinfo->curthread = NULL; LIST_INIT(&trussinfo->proclist); - init_syscalls(); while ((c = getopt(ac, av, "p:o:facedDs:SH")) != -1) { switch (c) { case 'p': /* specified pid */ @@ -204,6 +203,7 @@ print_summary(trussinfo); fflush(trussinfo->outfile); + free_seen_syscalls(); return (0); } Index: usr.bin/truss/setup.c =================================================================== --- usr.bin/truss/setup.c +++ usr.bin/truss/setup.c @@ -463,8 +463,8 @@ fprintf(info->outfile, "-- UNKNOWN %s SYSCALL %d --\n", t->proc->abi->type, t->cs.number); - t->cs.nargs = sc->nargs; - assert(sc->nargs <= nitems(t->cs.s_args)); + t->cs.nargs = sc->decode.nargs; + assert(sc->decode.nargs <= nitems(t->cs.s_args)); t->cs.sc = sc; @@ -476,15 +476,16 @@ * passed in *and* out, however. */ #if DEBUG - fprintf(stderr, "syscall %s(", sc->name); + fprintf(stderr, "syscall %d %s(", t->cs.number, sc->display_name); #endif for (i = 0; i < t->cs.nargs; i++) { #if DEBUG - fprintf(stderr, "0x%lx%s", t->cs.args[sc->args[i].offset], + fprintf(stderr, "%p%s", + (void *)t->cs.args[sc->decode.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], + if (!(sc->decode.args[i].type & OUT)) { + t->cs.s_args[i] = print_arg(&sc->decode.args[i], t->cs.args, NULL, info); } } @@ -542,19 +543,19 @@ * Here, we only look for arguments that have OUT masked in -- * otherwise, they were handled in enter_syscall(). */ - for (i = 0; i < sc->nargs; i++) { + for (i = 0; i < sc->decode.nargs; i++) { char *temp; - if (sc->args[i].type & OUT) { + if (sc->decode.args[i].type & OUT) { /* * If an error occurred, then don't bother * getting the data; it may not be valid. */ if (psr.sr_error != 0) { asprintf(&temp, "0x%lx", - t->cs.args[sc->args[i].offset]); + t->cs.args[sc->decode.args[i].offset]); } else { - temp = print_arg(&sc->args[i], + temp = print_arg(&sc->decode.args[i], t->cs.args, psr.sr_retval, info); } t->cs.s_args[i] = temp; Index: usr.bin/truss/syscall.h =================================================================== --- usr.bin/truss/syscall.h +++ usr.bin/truss/syscall.h @@ -216,18 +216,22 @@ _Static_assert(ARG_MASK > MAX_ARG_TYPE, "ARG_MASK overlaps with Argtype values"); -struct syscall_args { +struct syscall_arg { enum Argtype type; int offset; }; +struct syscall_decode { + const char *name; /* Name for lookup calling convention lookup */ + u_int ret_type; /* 0, 1, or 2 return values */ + u_int nargs; /* actual number of meaningful arguments */ + struct syscall_arg args[10]; /* Hopefully no syscalls with > 10 args */ +}; + struct syscall { STAILQ_ENTRY(syscall) entries; - const char *name; - u_int ret_type; /* 0, 1, or 2 return values */ - u_int nargs; /* actual number of meaningful arguments */ - /* Hopefully, no syscalls with > 10 args */ - struct syscall_args args[10]; + char *display_name; /* Name to be displayed, must be malloc()'d */ + struct syscall_decode decode; struct timespec time; /* Time spent for this call */ int ncalls; /* Number of calls */ int nerror; /* Number of calls that returned with error */ @@ -235,7 +239,7 @@ }; struct syscall *get_syscall(struct threadinfo *, u_int, u_int); -char *print_arg(struct syscall_args *, unsigned long*, register_t *, +char *print_arg(struct syscall_arg *, unsigned long *, register_t *, struct trussinfo *); /* @@ -278,7 +282,7 @@ char args_l_[PADL_(l_ulong)]; l_ulong args; char args_r_[PADR_(l_ulong)]; }; -void init_syscalls(void); void print_syscall(struct trussinfo *); void print_syscall_ret(struct trussinfo *, int, register_t *); void print_summary(struct trussinfo *trussinfo); +void free_seen_syscalls(void); Index: usr.bin/truss/syscalls.c =================================================================== --- usr.bin/truss/syscalls.c +++ usr.bin/truss/syscalls.c @@ -47,8 +47,10 @@ #include #include #include +#include #include #include +#include #include #define _WANT_FREEBSD11_STAT #include @@ -66,8 +68,6 @@ #define _WANT_KERNEL_ERRNO #include #include -#include -#include #include #include #include @@ -85,8 +85,13 @@ /* * This should probably be in its own file, sorted alphabetically. + * + * Note: We only scan this table on the initial syscall number to calling + * convention lookup, i.e. once each time a new syscall is encountered. This + * is unlikely to be a performance issue, but if it is we could sort this array + * and use a binary search instead. */ -static struct syscall decoded_syscalls[] = { +static const struct syscall_decode decoded_syscalls[] = { /* Native ABI */ { .name = "__acl_aclcheck_fd", .ret_type = 1, .nargs = 3, .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } }, @@ -702,10 +707,8 @@ { .name = "cloudabi_sys_thread_exit", .ret_type = 1, .nargs = 2, .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } }, { .name = "cloudabi_sys_thread_yield", .ret_type = 1, .nargs = 0 }, - - { .name = 0 }, }; -static STAILQ_HEAD(, syscall) syscalls; +static STAILQ_HEAD(, syscall) seen_syscalls; /* Xlat idea taken from strace */ struct xlat { @@ -965,7 +968,7 @@ * decoding arguments. */ static void -quad_fixup(struct syscall *sc) +quad_fixup(struct syscall_decode *sc) { int offset, prev; u_int i; @@ -1003,20 +1006,6 @@ } #endif -void -init_syscalls(void) -{ - struct syscall *sc; - - STAILQ_INIT(&syscalls); - for (sc = decoded_syscalls; sc->name != NULL; sc++) { -#ifndef __LP64__ - quad_fixup(sc); -#endif - STAILQ_INSERT_HEAD(&syscalls, sc, entries); - } -} - static struct syscall * find_syscall(struct procabi *abi, u_int number) { @@ -1036,6 +1025,11 @@ { struct extra_syscall *es; +#ifndef __LP64__ + /* FIXME: should be based on sycall ABI not truss ABI */ + quad_fixup(&sc->decode); +#endif + if (number < nitems(abi->syscalls)) { assert(abi->syscalls[number] == NULL); abi->syscalls[number] = sc; @@ -1045,6 +1039,8 @@ es->number = number; STAILQ_INSERT_TAIL(&abi->extra_syscalls, es, entries); } + + STAILQ_INSERT_HEAD(&seen_syscalls, sc, entries); } /* @@ -1055,24 +1051,27 @@ get_syscall(struct threadinfo *t, u_int number, u_int nargs) { struct syscall *sc; - const char *name; - char *new_name; + const char *sysdecode_name; + char *name; u_int i; 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) { + sysdecode_name = sysdecode_syscallname(t->proc->abi->abi, number); + if (sysdecode_name == NULL) + asprintf(&name, "#%d", number); + else + name = strdup(sysdecode_name); + + sc = calloc(1, sizeof(*sc)); + sc->display_name = name; + + for (i = 0; i < nitems(decoded_syscalls); i++) { + if (strcmp(name, decoded_syscalls[i].name) == 0) { + sc->decode = decoded_syscalls[i]; add_syscall(t->proc->abi, number, sc); - free(new_name); return (sc); } } @@ -1082,21 +1081,15 @@ fprintf(stderr, "unknown syscall %s -- setting args to %d\n", name, nargs); #endif - - sc = calloc(1, sizeof(struct syscall)); - sc->name = name; - if (new_name != NULL) - sc->unknown = true; - sc->ret_type = 1; - sc->nargs = nargs; + sc->unknown = sysdecode_name == NULL; + sc->decode.ret_type = 1; /* Assume 1 return value. */ + sc->decode.nargs = nargs; for (i = 0; i < nargs; i++) { - sc->args[i].offset = i; + sc->decode.args[i].offset = i; /* Treat all unknown arguments as LongHex. */ - sc->args[i].type = LongHex; + sc->decode.args[i].type = LongHex; } - STAILQ_INSERT_HEAD(&syscalls, sc, entries); add_syscall(t->proc->abi, number, sc); - return (sc); } @@ -1713,7 +1706,7 @@ * an array of all of the system call arguments. */ char * -print_arg(struct syscall_args *sc, unsigned long *args, register_t *retval, +print_arg(struct syscall_arg *sc, unsigned long *args, register_t *retval, struct trussinfo *trussinfo) { FILE *fp; @@ -2909,7 +2902,7 @@ t = trussinfo->curthread; - name = t->cs.sc->name; + name = t->cs.sc->display_name; nargs = t->cs.nargs; s_args = t->cs.s_args; @@ -2970,7 +2963,7 @@ strerror(error)); } #ifndef __LP64__ - else if (sc->ret_type == 2) { + else if (sc->decode.ret_type == 2) { off_t off; #if _BYTE_ORDER == _LITTLE_ENDIAN @@ -2997,17 +2990,30 @@ fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n", "syscall", "seconds", "calls", "errors"); ncall = nerror = 0; - STAILQ_FOREACH(sc, &syscalls, entries) + STAILQ_FOREACH(sc, &seen_syscalls, entries) { if (sc->ncalls) { fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n", - sc->name, (intmax_t)sc->time.tv_sec, + sc->display_name, (intmax_t)sc->time.tv_sec, sc->time.tv_nsec, sc->ncalls, sc->nerror); timespecadd(&total, &sc->time, &total); ncall += sc->ncalls; nerror += sc->nerror; } + } fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n", "", "-------------", "-------", "-------"); fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n", "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror); } + +void +free_seen_syscalls(void) +{ + struct syscall *sc; + struct syscall *sc_temp; + STAILQ_FOREACH_SAFE (sc, &seen_syscalls, entries, sc_temp) { + STAILQ_REMOVE(&seen_syscalls, sc, syscall, entries); + free(sc->display_name); + free(sc); + } +}