diff options
author | sef <sef@FreeBSD.org> | 1997-12-06 05:23:12 +0000 |
---|---|---|
committer | sef <sef@FreeBSD.org> | 1997-12-06 05:23:12 +0000 |
commit | 9e9a114f06c905e161ecc38cc4dc8af9b94ebb1e (patch) | |
tree | 700ff37c19e14441400de713fc6c2d0bce947daf /usr.bin/truss/syscalls.c | |
parent | bfd5e43c20b17aed3a09d69833c3db05c8a68609 (diff) | |
download | FreeBSD-src-9e9a114f06c905e161ecc38cc4dc8af9b94ebb1e.zip FreeBSD-src-9e9a114f06c905e161ecc38cc4dc8af9b94ebb1e.tar.gz |
Truss program. Requires procfs.
Diffstat (limited to 'usr.bin/truss/syscalls.c')
-rw-r--r-- | usr.bin/truss/syscalls.c | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/usr.bin/truss/syscalls.c b/usr.bin/truss/syscalls.c new file mode 100644 index 0000000..98dadca --- /dev/null +++ b/usr.bin/truss/syscalls.c @@ -0,0 +1,194 @@ +/* + * This file has routines used to print out system calls and their + * arguments. + */ +/* + * $Id$ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include "syscall.h" + +/* + * This should probably be in its own file. + */ + +struct syscall syscalls[] = { + { "readlink", 1, 3, + { { String, 0 } , { String | OUT, 1 }, { Int, 2 }}}, + { "lseek", 2, 3, + { { Int, 0 }, {Quad, 2 }, { Int, 4 }}}, + { "mmap", 2, 6, + { { Hex, 0 }, {Int, 1}, {Hex, 2}, {Hex, 3}, {Int, 4}, {Quad, 6}}}, + { "open", 1, 3, + { { String | IN, 0} , { Int, 1}, {Octal, 2}}}, + { "linux_open", 1, 3, + { { String, 0 }, { Int, 1}, { Octal, 2 }}}, + { "close", 1, 1, { { Int, 0 } } }, + { "fstat", 1, 2, + { { Int, 0}, {Ptr | OUT , 1 }}}, + { "stat", 1, 2, + { { String | IN, 0 }, { Ptr | OUT, 1 }}}, + { "linux_newstat", 1, 2, + { { String | IN, 0 }, { Ptr | OUT, 1 }}}, + { "linux_newfstat", 1, 2, + { { Int, 0 }, { Ptr | OUT, 1 }}}, + { "write", 1, 3, + { { Int, 0}, { Ptr | IN, 1 }, { Int, 2 }}}, + { "break", 1, 1, { { Hex, 0 }}}, + { "exit", 0, 1, { { Hex, 0 }}}, + { 0, 0, 0, { 0, 0 } }, +}; + +/* + * 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) { + struct syscall *sc = syscalls; + + while (sc->name) { + if (!strcmp(name, sc->name)) + return sc; + sc++; + } + return NULL; +} + +/* + * get_string + * Copy a string from the process. Note that it is + * expected to be a C string, but if max is set, it will + * only get that much. + */ + +char * +get_string(int procfd, void *offset, int max) { + char *buf, *tmp; + int size, len, c; + FILE *p; + + if ((p = fdopen(procfd, "r")) == NULL) { + perror("fdopen"); + exit(1); + } + buf = malloc( size = (max ? max : 64 ) ); + len = 0; + fseek(p, (long)offset, SEEK_SET); + while ((c = fgetc(p)) != EOF) { + buf[len++] = c; + if (c == 0 || len == max) { + buf[len] = 0; + break; + } + if (len == size) { + char *tmp = buf; + tmp = realloc(buf, size+64); + if (tmp == NULL) { + buf[len] = 0; + return buf; + } + size += 64; + } + } + return buf; +} + + +/* + * Gag. This is really unportable. Multiplication is more portable. + * But slower, from the code I saw. + */ + +static long long +make_quad(unsigned long p1, unsigned long p2) { + union { + long long ll; + unsigned long l[2]; + } t; + t.l[0] = p1; + t.l[1] = p2; + return t.ll; +} + + +/* + * print_arg + * Converts a syscall argument into a string. Said string is + * allocated via malloc(), so needs to be free()'d. The file + * descriptor is for the process' memory (via /proc), and is used + * to get any data (where the argument is a pointer). sc is + * a pointer to the syscall description (see above); args is + * an array of all of the system call arguments. + */ + +char * +print_arg(int fd, struct syscall_args *sc, unsigned long *args) { + char *tmp; + switch (sc->type & ARG_MASK) { + case Hex: + tmp = malloc(12); + sprintf(tmp, "0x%x", args[sc->offset]); + break; + case Octal: + tmp = malloc(13); + sprintf(tmp, "0%o", args[sc->offset]); + break; + case Int: + tmp = malloc(12); + sprintf(tmp, "%d", args[sc->offset]); + break; + case String: + { + char *tmp2; + tmp2 = get_string(fd, (void*)args[sc->offset], 0); + tmp = malloc(strlen(tmp2) + 3); + sprintf(tmp, "\"%s\"", tmp2); + free(tmp2); + } + break; + case Quad: + { + unsigned long long t; + unsigned long l1, l2; + l1 = args[sc->offset]; + l2 = args[sc->offset+1]; + t = make_quad(l1, l2); + tmp = malloc(24); + sprintf(tmp, "0x%qx", t); + break; + } + case Ptr: + tmp = malloc(12); + sprintf(tmp, "0x%x", args[sc->offset]); + break; + } + return tmp; +} + +/* + * print_syscall + * Print (to outfile) the system call and its arguments. Note that + * nargs is the number of arguments (not the number of words; this is + * potentially confusing, I know). + */ + +void +print_syscall(FILE *outfile, const char *name, int nargs, char **s_args) { + int i; + fprintf(outfile, "syscall %s(", name); + for (i = 0; i < nargs; i++) { + if (s_args[i]) + fprintf(outfile, "%s", s_args[i]); + else + fprintf(outfile, "<missing argument>"); + fprintf(outfile, "%s", i < (nargs - 1) ? "," : ""); + } + fprintf(outfile, ")\n\t"); +} |