diff -uNr strace-4.1/Makefile.in strace-4.1-ioctldefs/Makefile.in --- strace-4.1/Makefile.in Fri Nov 19 21:10:23 1999 +++ strace-4.1-ioctldefs/Makefile.in Sat Jan 22 23:10:00 2000 @@ -50,7 +50,8 @@ ALL_SUBDIRS = test linux linux/alpha linux/powerpc sunos4 svr4 OBJ = strace.o version.o syscall.o util.o \ desc.o file.o ipc.o io.o ioctl.o mem.o net.o process.o bjm.o \ - resource.o signal.o sock.o system.o term.o time.o proc.o stream.o + resource.o signal.o sock.o system.o term.o time.o proc.o stream.o \ + ioctldefs.o all: strace @@ -104,3 +105,4 @@ system.o: system.c defs.h config.h time.o: time.c defs.h config.h util.o: util.c defs.h config.h +ioctldefs.o: defs.h diff -uNr strace-4.1/README-ioctl.defs strace-4.1-ioctldefs/README-ioctl.defs --- strace-4.1/README-ioctl.defs Wed Dec 31 19:00:00 1969 +++ strace-4.1-ioctldefs/README-ioctl.defs Sun Jan 23 00:04:02 2000 @@ -0,0 +1,71 @@ +Ioctl.Defs Functionality in Strace +================================== + +Tom Rothamel + +The -I option causes strace to interprate the file given as a +list of ioctl names and a list of commands for printing the structure +pointed to by the third argument of the corresponding ioctl. This +helps the debugging of ioctl calls in programs. + +Each line of the file should consist of one of the following. +- An ioctl name, as printed out by strace, followed by a format string + used to print out the ioctl. (This can look something like + "SNDCTL_DSP_GETOSPACE dddd".) +- A line beginning with a '#', marking a comment. ("# Comment") +- A blank line. + +Invalid lines are silently ignored. + +The table that follows is the list of data printing commands. Each +entry contains a short description of the output format, as well as +which data types this is useful for. + +d Print out a normal-size integer as a decimal number. (int) +ld Print out a long integer as a decimal number. (long) +x Print out a normal-size integer as a hex number. (int) +lx Print out a long integer as a hex number. (long) +h Print out a short integer as a decimal number. (short) +C Print out a char as a decimal integer. (char) +c Print out a char as a character code. (char) +p Print out a pointer. (void *, foo *, bar **, etc...) +s Print out a string pointed to by a char *. (char *) +S Print out a string array in this structure of length num. + (char string[]) +{ Start the definition of a sub-structure that will be printed + provided the pointer to it is not NULL. The definition ends + with a '}'. Please note that this is only used for pointers to + structures... complete structures should be included in the + structure definition. +- Disable the automatic insertion of padding to the + command list. Normally, strace will try to take into account the + alignment restrictions on structure members imposed by your + processor/compiler. If this is given, these padding bytes will + need to be inserted manually using the '_' command. This will + need to be repeated in each sub-structure definition. ({} pair.) ++ Re-enable the automatic insertion of padding into the command + list. +_ Insert a byte of padding. This should only be used if the + automatic insertion of padding is turned off. + +For example, if NEW_IOCTL takes a struct foo, and the following +definitions are in the appropriate header: + + struct bar { + int a; + int b; + }; + + struct foo { + char *name; + char id[20]; + struct bar bar1; + struct bar *bar2; + struct bar *bar3; + }; + +then in the ioctl.defs file one should place. + + NEW_IOCTL s20Sii{ii}{ii} + +For more information, please email Tom Rothamel \ No newline at end of file diff -uNr strace-4.1/defs.h strace-4.1-ioctldefs/defs.h --- strace-4.1/defs.h Fri Nov 19 21:10:23 1999 +++ strace-4.1-ioctldefs/defs.h Sat Jan 15 01:14:36 2000 @@ -290,6 +290,7 @@ extern int nprocs; extern int max_strlen; extern struct tcb *tcp_last; +extern int ioctldef_wanted; #ifdef __STDC__ #define P(args) args @@ -347,6 +348,9 @@ extern int sock_ioctl P((struct tcb *, long, long)); extern int proc_ioctl P((struct tcb *, int, int)); extern int stream_ioctl P((struct tcb *, int, int)); + +extern int ioctldef_dump P((struct tcb *, long, long)); +extern void ioctldef_load P((char *)); extern void tv_tv P((struct timeval *, int, int)); extern int tv_nz P((struct timeval *)); diff -uNr strace-4.1/ioctl.c strace-4.1-ioctldefs/ioctl.c --- strace-4.1/ioctl.c Sun Aug 29 19:15:07 1999 +++ strace-4.1-ioctldefs/ioctl.c Sat Jan 15 01:10:32 2000 @@ -120,6 +120,11 @@ default: break; } + + if (ioctldef_wanted) { + return ioctldef_dump(tcp, code, arg); + } + return 0; } diff -uNr strace-4.1/ioctldefs.c strace-4.1-ioctldefs/ioctldefs.c --- strace-4.1/ioctldefs.c Wed Dec 31 19:00:00 1969 +++ strace-4.1-ioctldefs/ioctldefs.c Sun Jan 23 00:10:28 2000 @@ -0,0 +1,529 @@ +/* + * Copyright 2000 Tom Rothamel + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "defs.h" +#include +#include +#include +#include + +struct ioctl_dump_info { + char *name; + char *pspec; +}; + +typedef struct ioctl_dump_info IDI; + +int idialloc = 0; +int idinum = 0; +IDI **iditab = NULL; + +/* Create a new idi, strduping the strings given. */ +IDI *idi_new(name, pspec) +char *name; +char *pspec; +{ + IDI *idi; + + idi = malloc(sizeof(IDI)); + idi->name = strdup(name); + idi->pspec = strdup(pspec); + + return idi; +} + +/* Frees an idi, and associated strings. */ +void idi_free(idi) +IDI *idi; +{ + free(idi->name); + free(idi->pspec); + free(idi); +} + +/* Creates a new idi and adds it to the iditab. */ +void idi_add(name, pspec) +char *name; +char *pspec; +{ + IDI *idi; + + idi = idi_new(name, pspec); + + if (idialloc < idinum + 1) { + idialloc = 2 * (idinum + 1); + iditab = realloc(iditab, idialloc * sizeof(IDI *)); + } + + iditab[idinum++] = idi; +} + +/* Compares two idis by name. */ +int idi_compare(idi1, idi2) +IDI **idi1; +IDI **idi2; +{ + return strcmp((*idi1)->name, (*idi2)->name); +} + +/* Compares a string and an idi. */ +int idi_strcompare(s, idi2) +char *s; +IDI **idi2; +{ + return strcmp(s, (*idi2)->name); +} + +/* Sort the iditab. */ +void iditab_sort() +{ + if (!iditab) return; + + qsort(iditab, idinum, sizeof(IDI *), + (int (*)(const void *, const void *)) idi_compare); +} + +/* Search the iditab. */ +char *iditab_search(s) +char *s; +{ + IDI **idi; + + if (!iditab) return NULL; + + idi = bsearch(s, iditab, idinum , sizeof(IDI *), + (int (*)(const void *, const void *)) idi_strcompare); + + if (!idi) return NULL; + + return (*idi)->pspec; +} + +/* Prints the iditab. Really for debugging use only.*/ +void iditab_print() +{ + int i; + + for (i = 0; i < idinum; i++) { + printf("IDI: %d %p name = %s pspec = %s\n", i, iditab[i], + iditab[i]->name, iditab[i]->pspec); + } +} + +/* Frees the iditab. */ +void iditab_free() +{ + int i; + + if (!iditab) return; + + for (i = 0; i < idinum; i++) { + idi_free(iditab[i]); + } + + iditab = 0; + idialloc = 0; + iditab = NULL; +} + +/* Removes comments from the string */ +void iop_strcomment(s) +char *s; +{ + while (*s) { + if (*s == '#') { + *s = 0; + return; + } + + s++; + } +} + +/* Tries to split a string into parts on whitespace. If it can do so, it + returns the second half, and it replaces the first whitespace character + with a NUL. Otherwise, it returns NULL. */ +char *iop_strsplit(s) +char *s; +{ + while (*s) { + if (isspace(*s)) break; + s++; + } + + if (!*s) return NULL; + + *s = 0; + s++; + + while (*s) { + if (!isspace(*s)) break; + s++; + } + + if (!*s) return NULL; + return s; +} + +/* Removes newilines from a line. */ +void iop_chomp(s) +char *s; +{ + while (*s) { + if (*s == '\n') *s = 0; + s++; + } +} + +/* Load in the file containing the pspecs for the different ioctls. */ +void ioctldef_load(fn) +char *fn; +{ + FILE *f; + char buf[256]; + char *pspec; + + f = fopen(fn, "r"); + if (!f) { + fprintf(stderr, "Couldn't open ioctl def file '%s'.\n", + fn); + exit(-1); + } + + while (fgets(buf, 256, f)) { + iop_chomp(buf); + iop_strcomment(buf); + pspec = iop_strsplit(buf); + + if (!*buf) continue; + if (!pspec) continue; + + idi_add(buf, pspec); + } + + fclose(f); + + iditab_sort(); +} + +/* Prints an int found at addr. fmt is a format string containing a + printf-style specifier for an int. */ +void iout_printint(tcp, fmt, addr) +struct tcb *tcp; +char *fmt; +long addr; +{ + long i = 0; + + if (umoven(tcp, addr, sizeof(long), (char *) &i) == -1) { + tprintf("(err: getting int)"); + return; + } + + tprintf(fmt, i); +} + +/* Ditto the above, but for a short integer rather than an int or long. */ +void iout_shortint(tcp, fmt, addr) +struct tcb *tcp; +char *fmt; +long addr; +{ + short i = 0; + + if (umoven(tcp, addr, sizeof(short), (char *) &i) == -1) { + tprintf("(err: getting int)"); + return; + } + + tprintf(fmt, i); +} + +/* This prints out a char * and the string that it points to. */ +void iout_charptr(tcp, addr) +struct tcb *tcp; +long addr; +{ + long straddr; + + if(umoven(tcp, addr, sizeof(char *), (char *) &straddr) == -1) { + tprintf("(err: getting char *)"); + return; + } + + if (!straddr) { + tprintf("NULL"); + } + + tprintf("%p = ", straddr); + printstr(tcp, straddr, -1); +} + +/* This prints out a single character, as per a format. */ +void iout_char(tcp, fmt, addr) +struct tcb *tcp; +char *fmt; +long addr; +{ + char i; + + if (umoven(tcp, addr, sizeof(char), (char *) &i) == -1) { + tprintf("(err: getting char)"); + return; + } + + tprintf(fmt, i); +} + +/* The strategy for padding: + + We assume that if we create a structure that has first a single char + and then another type, the offset of that second member is the alignment + that that type must be at in a structure. Using the alignment, it's simple + to calculate the number of padding bytes needed. + + I've only tested this on the ix86, but it works there. (It may break if + the compiler used to compile strace and the traced program differs.) +*/ + +#define pads(n,t) struct pad_ ## n { char a; t b; } + +pads(char, char); +pads(int, int); +pads(short, short); +pads(long, long); +pads(charptr, char *); +pads(voidptr, void *); + +/* This macro attempts to handle the padding that the compiler puts + into structures. Cross fingers and hope it works on your platform. */ +#define pad(n) { \ + int align; \ + \ + if (smartpad) { \ + align = offsetof(struct pad_ ## n, b); \ + /* tprintf(" " # n "(%d %ld %ld) ", align, addr % align, align - (addr % align)); */ \ + if (addr % align) addr += align - (addr % align); \ + } \ +} + +#define reset longf = 0; width = 0 +#define comma if (needcomma++) { tprintf(", "); } + +char *iout_runstruct(struct tcb *tcp, char *s, long addr); + +/* This runs a printspec on a known-valid structure. All of the + formatting codes are defined in the big switch in this function. */ +char *iout_runstr(tcp, s, addr) +struct tcb *tcp; +char *s; +unsigned long addr; +{ + int needcomma = 0; + int smartpad = 1; + int longf = 0; + int width = 0; + unsigned long naddr; + char c; + + while ((c = *s)) { + switch(*s++) { + case '+': + smartpad = 1; + break; + case '-': + smartpad = 0; + break; + case '_': + addr += 1; + break; + case 'l': + longf = 1; + break; + + case 'c': + comma; + pad(char); + iout_char(tcp, "'%c'", addr); + addr += 1; + reset; + break; + case 'C': + comma; + pad(char); + iout_char(tcp, "%d", addr); + addr += 1; + reset; + break; + case 'h': + comma; + pad(short); + iout_shortint(tcp, "%hd", addr); + addr += sizeof(short int); + reset; + break; + case 'd': + comma; + if (longf) { + pad(long); + iout_printint(tcp, "%ld", addr); + addr += sizeof(long); + } else { + pad(int); + iout_printint(tcp, "%d", addr); + addr += sizeof(int); + } + reset; + break; + case 'x': + comma; + if (longf) { + pad(long); + iout_printint(tcp, "%#lx", addr); + addr += sizeof(long); + } else { + pad(int); + iout_printint(tcp, "%#x", addr); + addr += sizeof(int); + } + reset; + break; + case 'p': + comma; + pad(voidptr); + iout_printint(tcp, "%p", addr); + addr += sizeof(void *); + reset; + break; + case 's': + comma; + pad(charptr); + iout_charptr(tcp, addr); + addr += sizeof(char *); + reset; + break; + case 'S': + comma; + if (width == 0) { + tprintf("(err: no string size)"); + } else { + /* This handles the null-termination for us. */ + printpathn(tcp, addr, width); + } + addr += width; + reset; + break; + case '{': + comma; + pad(voidptr); + if (umoven(tcp, addr, sizeof(void *), (char *) &naddr) == -1) { + tprintf("(err: couldn't get struct *)"); + break; + } + s = iout_runstruct(tcp, s, naddr); + addr += sizeof(void *); + reset; + break; + case '}': + return s; + } + + if (c >= '0' && c <= '9') { + width *= 10; + width += (c - '0'); + } + } + + return s; +} + +/* This checks to see if a structure is valid. If it is (ie. the pointer to + it isn't NULL), it prints it. Otherwise, it skips over it in the printspec. +*/ +char *iout_runstruct(tcp, s, addr) +struct tcb *tcp; +char *s; +long addr; +{ + char *rv; + int braced; + char c; + + if (addr == 0) { + tprintf("NULL"); + + braced = 0; + while ((c = *s++)) { + if (c == '{') { + braced++; + } + if (c == '}') { + braced--; + if (braced < 0) return s; + } + } + + return s; + } + + tprintf("%#lx = {", addr); + rv = iout_runstr(tcp, s, addr); + tprintf("}"); + + return rv; +} + + +/* This function looks up the ioctl name in the iditab. If it's there, + it dispatches a pointer to the structure to runstruct so that it can + be printed according to the printspec. */ +int ioctldef_dump(tcp, dump, arg) +struct tcb *tcp; +long dump; +long arg; +{ + char *name; + char name_buf[20]; + char *pspec; + + if (entering(tcp)) return 0; + + if (!(name = ioctl_lookup(dump))) { + sprintf(name_buf, "%#lx", dump); + name = name_buf; + } + + pspec = iditab_search(name); + if (!pspec) return 0; + + tprintf(", "); + iout_runstruct(tcp, pspec, tcp->u_arg[2]); + + return 1; +} + + diff -uNr strace-4.1/strace.1 strace-4.1-ioctldefs/strace.1 --- strace-4.1/strace.1 Fri Jul 9 14:55:09 1999 +++ strace-4.1-ioctldefs/strace.1 Sun Jan 23 00:02:58 2000 @@ -66,6 +66,9 @@ .BI \-u username ] [ +.BI \-I ioctl-defs-file +] +[ .I command [ .I arg @@ -436,6 +439,14 @@ .BR write (2) system call which is controlled by the option .BR "\-e trace=write" . +.TP +.BI "\-I " filename +This causes strace to read in +.I filename +and use the definitions contained within to print the third argument +of ioctls. (Please see the file README-ioctl.defs that came with the +strace distribution for more details, including the format of this +file.) .TP .BI "\-o " filename Write the trace output to the file diff -uNr strace-4.1/strace.c strace-4.1-ioctldefs/strace.c --- strace-4.1/strace.c Sat Oct 16 20:57:34 1999 +++ strace-4.1-ioctldefs/strace.c Sat Jan 15 01:04:23 2000 @@ -69,6 +69,8 @@ extern char version[]; extern char **environ; +int ioctldef_wanted = 0; + static struct tcb *pid2tcb P((int pid)); static int trace P((void)); static void cleanup P((void)); @@ -136,6 +138,7 @@ -a column -- alignment COLUMN for printing syscall results (default %d)\n\ -e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\ options: trace, abbrev, verbose, raw, signal, read, or write\n\ +-I file -- use information from FILE to print ioctls.\n\ -o file -- send trace output to FILE instead of stderr\n\ -O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\ -p pid -- trace process with process id PID, may be repeated\n\ @@ -178,7 +181,7 @@ set_sortby(DEFAULT_SORTBY); set_personality(DEFAULT_PERSONALITY); while ((c = getopt(argc, argv, - "+cdfFhiqrtTvVxa:e:o:O:p:s:S:u:")) != EOF) { + "+cdfFhiqrtTvVxa:e:I:o:O:p:s:S:u:")) != EOF) { switch (c) { case 'c': cflag++; @@ -227,6 +230,10 @@ break; case 'e': qualify(optarg); + break; + case 'I': + ioctldef_load(optarg); + ioctldef_wanted = 1; break; case 'o': outfname = strdup(optarg);