summaryrefslogtreecommitdiffstats
path: root/usr.bin/truss
diff options
context:
space:
mode:
authorbdrewery <bdrewery@FreeBSD.org>2015-10-05 18:08:35 +0000
committerbdrewery <bdrewery@FreeBSD.org>2015-10-05 18:08:35 +0000
commit1a8544448c1321d3c41eba2160e97919d6b25948 (patch)
tree53a718138dd748ebf142fbbbbb1f554f9aac8dda /usr.bin/truss
parent9dfa64e182dafd1ee7efd651d3ec0028cca55a0c (diff)
downloadFreeBSD-src-1a8544448c1321d3c41eba2160e97919d6b25948.zip
FreeBSD-src-1a8544448c1321d3c41eba2160e97919d6b25948.tar.gz
Fix tracking of unknown syscalls for 'truss -c'.
This is done by changing get_syscall() to either lookup the known syscall or add it into the list with the default handlers for printing. This also simplifies some code to not have to check if the syscall variable is set or NULL. Reviewed by: jhb Relnotes: yes Differential Revision: https://reviews.freebsd.org/D3792
Diffstat (limited to 'usr.bin/truss')
-rw-r--r--usr.bin/truss/main.c1
-rw-r--r--usr.bin/truss/setup.c59
-rw-r--r--usr.bin/truss/syscall.h4
-rw-r--r--usr.bin/truss/syscalls.c44
4 files changed, 61 insertions, 47 deletions
diff --git a/usr.bin/truss/main.c b/usr.bin/truss/main.c
index 55fdeda..d46d01e 100644
--- a/usr.bin/truss/main.c
+++ b/usr.bin/truss/main.c
@@ -94,6 +94,7 @@ main(int ac, char **av)
trussinfo->strsize = 32;
trussinfo->curthread = NULL;
LIST_INIT(&trussinfo->proclist);
+ init_syscalls();
while ((c = getopt(ac, av, "p:o:facedDs:S")) != -1) {
switch (c) {
case 'p': /* specified pid */
diff --git a/usr.bin/truss/setup.c b/usr.bin/truss/setup.c
index 4452f9f..74008e4 100644
--- a/usr.bin/truss/setup.c
+++ b/usr.bin/truss/setup.c
@@ -341,17 +341,9 @@ enter_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl)
fprintf(info->outfile, "-- UNKNOWN %s SYSCALL %d --\n",
t->proc->abi->type, t->cs.number);
- sc = get_syscall(t->cs.name);
- if (sc) {
- t->cs.nargs = sc->nargs;
- assert(sc->nargs <= nitems(t->cs.s_args));
- } else {
-#if DEBUG
- fprintf(stderr, "unknown syscall %s -- setting "
- "args to %d\n", t->cs.name, t->cs.nargs);
-#endif
- t->cs.nargs = narg;
- }
+ sc = get_syscall(t->cs.name, narg);
+ t->cs.nargs = sc->nargs;
+ assert(sc->nargs <= nitems(t->cs.s_args));
t->cs.sc = sc;
@@ -372,7 +364,7 @@ enter_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl)
t->cs.args[sc->args[i].offset] : t->cs.args[i],
i < (t->cs.nargs - 1) ? "," : "");
#endif
- if (sc && !(sc->args[i].type & OUT)) {
+ if (!(sc->args[i].type & OUT)) {
t->cs.s_args[i] = print_arg(&sc->args[i],
t->cs.args, 0, info);
}
@@ -407,31 +399,26 @@ exit_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl)
}
sc = t->cs.sc;
- if (sc == NULL) {
- for (i = 0; i < t->cs.nargs; i++)
- asprintf(&t->cs.s_args[i], "0x%lx", t->cs.args[i]);
- } else {
- /*
- * 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++) {
- char *temp;
-
- if (sc->args[i].type & OUT) {
- /*
- * If an error occurred, then don't bother
- * getting the data; it may not be valid.
- */
- if (errorp) {
- asprintf(&temp, "0x%lx",
- t->cs.args[sc->args[i].offset]);
- } else {
- temp = print_arg(&sc->args[i],
- t->cs.args, retval, info);
- }
- t->cs.s_args[i] = temp;
+ /*
+ * 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++) {
+ char *temp;
+
+ if (sc->args[i].type & OUT) {
+ /*
+ * If an error occurred, then don't bother
+ * getting the data; it may not be valid.
+ */
+ if (errorp) {
+ asprintf(&temp, "0x%lx",
+ t->cs.args[sc->args[i].offset]);
+ } else {
+ temp = print_arg(&sc->args[i],
+ t->cs.args, retval, info);
}
+ t->cs.s_args[i] = temp;
}
}
diff --git a/usr.bin/truss/syscall.h b/usr.bin/truss/syscall.h
index 18dd33f..3e3a1b9 100644
--- a/usr.bin/truss/syscall.h
+++ b/usr.bin/truss/syscall.h
@@ -55,6 +55,7 @@ struct syscall_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 */
@@ -65,7 +66,7 @@ struct syscall {
int nerror; /* Number of calls that returned with error */
};
-struct syscall *get_syscall(const char*);
+struct syscall *get_syscall(const char *, int nargs);
char *print_arg(struct syscall_args *, unsigned long*, long *, struct trussinfo *);
/*
@@ -108,6 +109,7 @@ struct linux_socketcall_args {
char args_l_[PADL_(l_ulong)]; l_ulong args; char args_r_[PADR_(l_ulong)];
};
+void init_syscalls(void);
void print_syscall(struct trussinfo *, const char *, int, char **);
void print_syscall_ret(struct trussinfo *, const char *, int, char **, int,
long *, struct syscall *);
diff --git a/usr.bin/truss/syscalls.c b/usr.bin/truss/syscalls.c
index 6211bae..8218b77 100644
--- a/usr.bin/truss/syscalls.c
+++ b/usr.bin/truss/syscalls.c
@@ -89,7 +89,7 @@ __FBSDID("$FreeBSD$");
/*
* This should probably be in its own file, sorted alphabetically.
*/
-static struct syscall syscalls[] = {
+static struct syscall decoded_syscalls[] = {
{ .name = "fcntl", .ret_type = 1, .nargs = 3,
.args = { { Int, 0 }, { Fcntl, 1 }, { Fcntlflag, 2 } } },
{ .name = "rfork", .ret_type = 1, .nargs = 1,
@@ -370,6 +370,7 @@ static struct syscall syscalls[] = {
.args = { { Ptr, 0 } } },
{ .name = 0 },
};
+static STAILQ_HEAD(, syscall) syscalls;
/* Xlat idea taken from strace */
struct xlat {
@@ -659,24 +660,49 @@ xlookup_bits(struct xlat *xlat, int val)
return (str);
}
+void
+init_syscalls(void)
+{
+ struct syscall *sc;
+
+ STAILQ_INIT(&syscalls);
+ for (sc = decoded_syscalls; sc->name != NULL; sc++)
+ STAILQ_INSERT_HEAD(&syscalls, sc, 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)
+get_syscall(const char *name, int nargs)
{
struct syscall *sc;
+ int i;
- sc = syscalls;
if (name == NULL)
return (NULL);
- while (sc->name) {
+ STAILQ_FOREACH(sc, &syscalls, entries)
if (strcmp(name, sc->name) == 0)
return (sc);
- sc++;
+
+ /* It is unknown. Add it into the list. */
+#if DEBUG
+ fprintf(stderr, "unknown syscall %s -- setting args to %d\n", name,
+ nargs);
+#endif
+
+ sc = calloc(1, sizeof(struct syscall));
+ sc->name = strdup(name);
+ sc->ret_type = 1;
+ sc->nargs = nargs;
+ for (i = 0; i < nargs; i++) {
+ sc->args[i].offset = i;
+ /* Treat all unknown arguments as LongHex. */
+ sc->args[i].type = LongHex;
}
- return (NULL);
+ STAILQ_INSERT_HEAD(&syscalls, sc, entries);
+
+ return (sc);
}
/*
@@ -1632,8 +1658,6 @@ print_syscall_ret(struct trussinfo *trussinfo, const char *name, int nargs,
struct timespec timediff;
if (trussinfo->flags & COUNTONLY) {
- if (!sc)
- return;
clock_gettime(CLOCK_REALTIME, &trussinfo->curthread->after);
timespecsubt(&trussinfo->curthread->after,
&trussinfo->curthread->before, &timediff);
@@ -1650,7 +1674,7 @@ print_syscall_ret(struct trussinfo *trussinfo, const char *name, int nargs,
fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0],
strerror(retval[0]));
#ifndef __LP64__
- else if (sc != NULL && sc->ret_type == 2) {
+ else if (sc->ret_type == 2) {
off_t off;
#if _BYTE_ORDER == _LITTLE_ENDIAN
@@ -1677,7 +1701,7 @@ print_summary(struct trussinfo *trussinfo)
fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
"syscall", "seconds", "calls", "errors");
ncall = nerror = 0;
- for (sc = syscalls; sc->name != NULL; sc++)
+ STAILQ_FOREACH(sc, &syscalls, entries)
if (sc->ncalls) {
fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
sc->name, (intmax_t)sc->time.tv_sec,
OpenPOWER on IntegriCloud