diff -u --new-file -r strace-4.2/Makefile.in strace-4.2-ioctldefs/Makefile.in --- strace-4.2/Makefile.in Sat Nov 27 20:56:12 1999 +++ strace-4.2-ioctldefs/Makefile.in Thu Apr 20 11:31:37 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 -u --new-file -r strace-4.2/README-ioctl.defs strace-4.2-ioctldefs/README-ioctl.defs --- strace-4.2/README-ioctl.defs Wed Dec 31 19:00:00 1969 +++ strace-4.2-ioctldefs/README-ioctl.defs Thu Apr 20 22:06:48 2000 @@ -0,0 +1,101 @@ +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 will cause a warning message to be printed at load +time. Invalid format codes will cause a warning message to be printed +at run time. + +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. +[ Prints a literal '[', useful for indicating the start of included + arrays. +] Prints a literal ']', useful for indicating the end of included + arrays. + +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} + + +h2ioctldefs.pl +============== + +Included in this distribution is a perl script, h2ioctldefs.pl, that +attempts to convert a header file from the linux kernel distribution +into an ioctl.defs file. It's quite limited in what it can convert, +but it still provides a fairly decent first shot at conversion. + +It takes two arguments. The first is a c file that includes the header +and everything needed to compile it, the second is the h file +itself. h2ioctldefs first uses pstruct to scan the files for +structures that may be used by the ioctls, then it looks for _IOW, +_IOR, and _IOWR definition that indicate ioctls. It then outputs a +file in the appropriate format. + + +ioctl.defs.oss-sound +==================== + +This is a sample ioctl.defs file, that includes information for the +OSS sound ioctls under Linux. + + +For more information, please email Tom Rothamel \ No newline at end of file diff -u --new-file -r strace-4.2/defs.h strace-4.2-ioctldefs/defs.h --- strace-4.2/defs.h Thu Dec 23 10:08:17 1999 +++ strace-4.2-ioctldefs/defs.h Thu Apr 20 11:31:37 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 @@ -350,6 +351,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 -u --new-file -r strace-4.2/h2ioctldefs.pl strace-4.2-ioctldefs/h2ioctldefs.pl --- strace-4.2/h2ioctldefs.pl Wed Dec 31 19:00:00 1969 +++ strace-4.2-ioctldefs/h2ioctldefs.pl Thu Apr 20 17:27:50 2000 @@ -0,0 +1,190 @@ +#!/usr/bin/perl -w + +# This doesn't handle properly: +# - Arrays of structs. +# - Unsigned numbers. (It converts to signed.) +# - Bitfields. +# +# Occasionally, pstruct can't figure out what type a type is. In that case, +# padding is emitted to skip the member. + +sub getsmcode { + my $type = shift; + my $number = shift; + my $totsize = shift; + my $name = shift; + + # We don't support unsigned, so remove it now. + $type =~ s/unsigned//g; + $type =~ s/signed//g; + + # Now, fix the spacing again, + $type =~ s/^\s+//; + $type =~ s/\s+$//; + $type =~ s/\s+/ /g; + + if ($type eq "char" && $number > 0) { + return $number . "S"; + } + + my $code; + + if ($type =~ /struct (\w+)$/) { + if ($number > 1) { + print STDERR "Warning: Handling $name:\n"; + print STDERR "Warning: Arrays of struct $1 don't work right.\n"; + } + return ""; # We'll pick up the members later. + } + + if ($type eq "char *") { + $code = 's'; + } elsif ($type =~ /\*/) { + $code = 'p'; + } elsif ($type eq "long long int") { + $code = 'ld'; + } elsif ($type eq "long long") { + $code = 'ld'; + } elsif ($type eq "long int") { + $code = 'ld'; + } elsif ($type eq "long") { + $code = 'ld'; + } elsif ($type eq "short int") { + $code = 'h'; + } elsif ($type eq "short") { + $code = 'h'; + } elsif ($type eq "int") { + $code = 'd'; + } elsif ($type eq "char") { + $code = 'C'; + } else { + print STDERR "Warning: Handling $name:\n"; + print STDERR "Warning: I don't know how to handle type '$type'.\n"; + print STDERR "Warning: Replacing with $totsize bytes of padding.\n"; + return "_" x $totsize; + } + + if ($number > 1) { + $code = '[' . $code x $number . ']'; + } + + + return $code; +# print $type, "\n"; +} + +my $structfile = $ARGV[0]; +my $ioctlfile = $ARGV[1] || $structfile; + +die "Not enough arguments" unless $ioctlfile; + +open(PSTRUCT, "pstruct $structfile|") or die "Couldn't open '$structfile'"; + +my $struct = "not a real struct"; +my %structdefs = (); + +while ($_ = ) { + chomp; + + if (/^struct (.+) \{/) { + $struct = $1; +# print STDERR "\n", $struct, "\n"; + next; + } + + if (/^\}/) { + $struct = "not a real struct"; + next; + } + + next if $struct eq "complex int"; + next if $struct eq "not a real struct"; + +# print STDERR $_, "\n"; + + + if (/\s+(.*?)\s+([^\s]+)(\[(\d+)\])\s+(\d+)\s+(\d+)$/) { + $structdefs{$struct} .= getsmcode($1, $4, $6, $2); + next; + } + + if (/\s+(.*?)\s+([^\s]+)\s+(\d+)\s+(\d+)$/) { + $structdefs{$struct} .= getsmcode($1, 0, $4, $2); + next; + } + + print STDERR "Warning: Can't handle $_\n"; +} + +close PSTRUCT; + +open IO, "<$ioctlfile"; + + + + +sub gotioctl { + my $name = shift; + my $arg = shift; + + $arg =~ s/struct//; + $arg =~ s/^\s+//; + $arg =~ s/\s+$//; + $arg =~ s/\s+//; + + my $num = 0; + + if ($arg =~ /^(.*)\[(\d+)\]$/) { + $arg = $1; + $num = $2; + } + + print "# $name takes as an argument $arg\n"; + + if (exists $structdefs{$arg}) { + $code = $structdefs{$arg}; + if ($num > 1) { + $code = '[' . $code x $num . ']'; + } + } else { + $code = getsmcode($arg, $num, 0, $name); + } + + print $name, " ", $code, "\n\n"; + +} + +while () { + chomp; + + next unless (/^\#define/); + + s{/\*.*?\*/}{}g; + s/\s+/ /g; + s/ $//; + s/ \(/\(/g; + + s/(\s+)_SIO/$1_IO/; + +# print $_, "\n"; + + if (/^\#define (\w+) _IOW\([^,]+,[^,]+,([^,]+)\)$/) { + gotioctl($1, $2); + next; + } + + if (/^\#define (\w+) _IOR\([^,]+,[^,]+,([^,]+)\)$/) { + gotioctl($1, $2); + next; + } + + if (/^\#define (\w+) _IOWR\([^,]+,[^,]+,([^,]+)\)$/) { + gotioctl($1, $2); + next; + } + + + +} + + diff -u --new-file -r strace-4.2/ioctl.c strace-4.2-ioctldefs/ioctl.c --- strace-4.2/ioctl.c Thu Dec 23 09:20:15 1999 +++ strace-4.2-ioctldefs/ioctl.c Thu Apr 20 11:31:37 2000 @@ -121,6 +121,11 @@ default: break; } + + if (ioctldef_wanted) { + return ioctldef_dump(tcp, code, arg); + } + return 0; } diff -u --new-file -r strace-4.2/ioctl.defs.oss-sound strace-4.2-ioctldefs/ioctl.defs.oss-sound --- strace-4.2/ioctl.defs.oss-sound Wed Dec 31 19:00:00 1969 +++ strace-4.2-ioctldefs/ioctl.defs.oss-sound Thu Apr 20 18:03:15 2000 @@ -0,0 +1,296 @@ +# ioctl.defs.sample file +# +# This is a useful sample of ioctl.defs. It implements all of the ioctls +# defined in soundcard.h (That is, the OSS sound control ioctls.) It was +# created by first running h2ioctldefs.pl on soundcard.h, and then going +# in manually to look for duplicate name for the ioctls, as well as adding +# in some of the ioctls that aren't defined using the _SIO macros. + + +# SNDCTL_SYNTH_INFO takes as an argument synth_info +SNDCTL_SYNTH_INFO 30Sdddddddd[ddddddddddddddddddd] + +# SNDCTL_SEQ_CTRLRATE takes as an argument int +SNDCTL_SEQ_CTRLRATE d + +# SNDCTL_SEQ_GETOUTCOUNT takes as an argument int +SNDCTL_SEQ_GETOUTCOUNT d + +# SNDCTL_SEQ_GETINCOUNT takes as an argument int +SNDCTL_SEQ_GETINCOUNT d + +# SNDCTL_SEQ_PERCMODE takes as an argument int +SNDCTL_SEQ_PERCMODE d + +# SNDCTL_FM_LOAD_INSTR takes as an argument sbi_instrument +SNDCTL_FM_LOAD_INSTR hhd________________________________ + +# SNDCTL_SEQ_TESTMIDI takes as an argument int +SNDCTL_SEQ_TESTMIDI d + +# SNDCTL_SEQ_RESETSAMPLES takes as an argument int +SNDCTL_SEQ_RESETSAMPLES d + +# SNDCTL_SEQ_NRSYNTHS takes as an argument int +SNDCTL_SEQ_NRSYNTHS d + +# SNDCTL_SEQ_NRMIDIS takes as an argument int +SNDCTL_SEQ_NRMIDIS d + +# SNDCTL_MIDI_INFO takes as an argument midi_info +SNDCTL_MIDI_INFO 30Sddd[dddddddddddddddddd] + +# SNDCTL_SEQ_THRESHOLD takes as an argument int +SNDCTL_SEQ_THRESHOLD d + +# SNDCTL_SYNTH_MEMAVL takes as an argument int +SNDCTL_SYNTH_MEMAVL d + +# SNDCTL_FM_4OP_ENABLE takes as an argument int +SNDCTL_FM_4OP_ENABLE d + +# SNDCTL_SEQ_OUTOFBAND takes as an argument seq_event_rec +SNDCTL_SEQ_OUTOFBAND 8S + +# SNDCTL_SEQ_GETTIME takes as an argument int +SNDCTL_SEQ_GETTIME d + +# SNDCTL_SYNTH_ID takes as an argument synth_info +SNDCTL_SYNTH_ID 30Sdddddddd[ddddddddddddddddddd] + +# SNDCTL_SYNTH_CONTROL takes as an argument synth_control +SNDCTL_SYNTH_CONTROL d4000S + +# SNDCTL_SYNTH_REMOVESAMPLE takes as an argument remove_sample +SNDCTL_SYNTH_REMOVESAMPLE ddd + +# SNDCTL_TMR_TIMEBASE takes as an argument int +SNDCTL_TMR_TIMEBASE d + +# SNDCTL_TMR_TEMPO takes as an argument int +SNDCTL_TMR_TEMPO d + +# SNDCTL_TMR_SOURCE takes as an argument int +SNDCTL_TMR_SOURCE d + +# SNDCTL_TMR_METRONOME takes as an argument int +SNDCTL_TMR_METRONOME d + +# SNDCTL_TMR_SELECT takes as an argument int +SNDCTL_TMR_SELECT d + +# SNDCTL_MIDI_PRETIME takes as an argument int +SNDCTL_MIDI_PRETIME d + +# SNDCTL_MIDI_MPUMODE takes as an argument int +SNDCTL_MIDI_MPUMODE d + +# SNDCTL_MIDI_MPUCMD takes as an argument mpu_command_rec +SNDCTL_MIDI_MPUCMD + +# SNDCTL_DSP_SPEED takes as an argument int +SNDCTL_DSP_SPEED d + +# SNDCTL_DSP_STEREO takes as an argument int +SNDCTL_DSP_STEREO d + +# SNDCTL_DSP_GETBLKSIZE takes as an argument int +SNDCTL_DSP_GETBLKSIZE d + +# SNDCTL_DSP_CHANNELS takes as an argument int +SNDCTL_DSP_CHANNELS d + +# SOUND_PCM_WRITE_FILTER takes as an argument int +SOUND_PCM_WRITE_FILTER d + +# SNDCTL_DSP_SUBDIVIDE takes as an argument int +SNDCTL_DSP_SUBDIVIDE d + +# SNDCTL_DSP_SETFRAGMENT takes as an argument int +SNDCTL_DSP_SETFRAGMENT d + +# SNDCTL_DSP_GETFMTS takes as an argument int +SNDCTL_DSP_GETFMTS d + +# SNDCTL_DSP_SETFMT takes as an argument int +SNDCTL_DSP_SETFMT d + +# SNDCTL_DSP_GETOSPACE takes as an argument audio_buf_info +SNDCTL_DSP_GETOSPACE dddd + +# SNDCTL_DSP_GETISPACE takes as an argument audio_buf_info +SNDCTL_DSP_GETISPACE dddd + +# SNDCTL_DSP_GETCAPS takes as an argument int +SNDCTL_DSP_GETCAPS d + +# SNDCTL_DSP_GETTRIGGER takes as an argument int +SNDCTL_DSP_GETTRIGGER d + +# SNDCTL_DSP_SETTRIGGER takes as an argument int +SNDCTL_DSP_SETTRIGGER d + +# SNDCTL_DSP_GETIPTR takes as an argument count_info +SNDCTL_DSP_GETIPTR ddd + +# SNDCTL_DSP_GETOPTR takes as an argument count_info +SNDCTL_DSP_GETOPTR ddd + +# SNDCTL_DSP_MAPINBUF takes as an argument buffmem_desc +SNDCTL_DSP_MAPINBUF pd + +# SNDCTL_DSP_MAPOUTBUF takes as an argument buffmem_desc +SNDCTL_DSP_MAPOUTBUF pd + +# SNDCTL_DSP_GETODELAY takes as an argument int +SNDCTL_DSP_GETODELAY d + +# SNDCTL_DSP_PROFILE takes as an argument int +SNDCTL_DSP_PROFILE d + +# SOUND_PCM_READ_RATE takes as an argument int +SOUND_PCM_READ_RATE d + +# SOUND_PCM_READ_CHANNELS takes as an argument int +SOUND_PCM_READ_CHANNELS d + +# SOUND_PCM_READ_BITS takes as an argument int +SOUND_PCM_READ_BITS d + +# SOUND_PCM_READ_FILTER takes as an argument int +SOUND_PCM_READ_FILTER d + +# SNDCTL_COPR_LOAD takes as an argument copr_buffer +SNDCTL_COPR_LOAD dddd4000S + +# SNDCTL_COPR_RDATA takes as an argument copr_debug_buf +SNDCTL_COPR_RDATA ddddd + +# SNDCTL_COPR_RCODE takes as an argument copr_debug_buf +SNDCTL_COPR_RCODE ddddd + +# SNDCTL_COPR_WDATA takes as an argument copr_debug_buf +SNDCTL_COPR_WDATA ddddd + +# SNDCTL_COPR_WCODE takes as an argument copr_debug_buf +SNDCTL_COPR_WCODE ddddd + +# SNDCTL_COPR_RUN takes as an argument copr_debug_buf +SNDCTL_COPR_RUN ddddd + +# SNDCTL_COPR_HALT takes as an argument copr_debug_buf +SNDCTL_COPR_HALT ddddd + +# SNDCTL_COPR_SENDMSG takes as an argument copr_msg +SNDCTL_COPR_SENDMSG d4000S + +# SNDCTL_COPR_RCVMSG takes as an argument copr_msg +SNDCTL_COPR_RCVMSG d4000S + +# SOUND_MIXER_INFO takes as an argument mixer_info +SOUND_MIXER_INFO 16S32Sd[dddddddddd] + +# SOUND_OLD_MIXER_INFO takes as an argument _old_mixer_info +SOUND_OLD_MIXER_INFO 16S32S + +# SOUND_MIXER_ACCESS takes as an argument mixer_record +SOUND_MIXER_ACCESS + +# SOUND_MIXER_AGC takes as an argument int +SOUND_MIXER_AGC d + +# SOUND_MIXER_3DSE takes as an argument int +SOUND_MIXER_3DSE d + +# SOUND_MIXER_PRIVATE1 takes as an argument int +SOUND_MIXER_PRIVATE1 d + +# SOUND_MIXER_PRIVATE2 takes as an argument int +SOUND_MIXER_PRIVATE2 d + +# SOUND_MIXER_PRIVATE3 takes as an argument int +SOUND_MIXER_PRIVATE3 d + +# SOUND_MIXER_PRIVATE4 takes as an argument int +SOUND_MIXER_PRIVATE4 d + +# SOUND_MIXER_PRIVATE5 takes as an argument int +SOUND_MIXER_PRIVATE5 d + +# SOUND_MIXER_GETLEVELS takes as an argument mixer_vol_table +SOUND_MIXER_GETLEVELS d32S[dddddddddddddddddddddddddddddddd] + +# SOUND_MIXER_SETLEVELS takes as an argument mixer_vol_table +SOUND_MIXER_SETLEVELS d32S[dddddddddddddddddddddddddddddddd] + +# OSS_GETVERSION takes as an argument int +OSS_GETVERSION d + + +# The following are aliases for some of the ioctls given above. +SNDCTL_DSP_SAMPLESIZE d +SOUND_PCM_WRITE_CHANNELS d +SOUND_PCM_WRITE_BITS d +SOUND_PCM_WRITE_RATE d +SOUND_PCM_SUBDIVIDE d +SOUND_PCM_SETFRAGMENT d +SOUND_PCM_GETFMTS d +SOUND_PCM_SETFMT d +SOUND_PCM_GETOSPACE dddd +SOUND_PCM_GETISPACE dddd +SOUND_PCM_GETCAPS d +SOUND_PCM_GETTRIGGER d +SOUND_PCM_SETTRIGGER d +SOUND_PCM_GETIPTR ddd +SOUND_PCM_GETOPTR ddd +SOUND_PCM_MAPINBUF pd +SOUND_PCM_MAPOUTBUF pd + +# The following are not defined with the varios _SIO macros, but instead are +# defined using MIXER_READ and MIXER_WRITE. +SOUND_MIXER_READ_VOLUME d +SOUND_MIXER_READ_BASS d +SOUND_MIXER_READ_TREBLE d +SOUND_MIXER_READ_SYNTH d +SOUND_MIXER_READ_PCM d +SOUND_MIXER_READ_SPEAKER d +SOUND_MIXER_READ_LINE d +SOUND_MIXER_READ_MIC d +SOUND_MIXER_READ_CD d +SOUND_MIXER_READ_IMIX d +SOUND_MIXER_READ_ALTPCM d +SOUND_MIXER_READ_RECLEV d +SOUND_MIXER_READ_IGAIN d +SOUND_MIXER_READ_OGAIN d +SOUND_MIXER_READ_LINE1 d +SOUND_MIXER_READ_LINE2 d +SOUND_MIXER_READ_LINE3 d +SOUND_MIXER_READ_MUTE d +SOUND_MIXER_READ_ENHANCE d +SOUND_MIXER_READ_LOUD d +SOUND_MIXER_READ_RECSRC d +SOUND_MIXER_READ_DEVMASK d +SOUND_MIXER_READ_RECMASK d +SOUND_MIXER_READ_STEREODEVS d +SOUND_MIXER_READ_CAPS d +SOUND_MIXER_WRITE_VOLUME d +SOUND_MIXER_WRITE_BASS d +SOUND_MIXER_WRITE_TREBLE d +SOUND_MIXER_WRITE_SYNTH d +SOUND_MIXER_WRITE_PCM d +SOUND_MIXER_WRITE_SPEAKER d +SOUND_MIXER_WRITE_LINE d +SOUND_MIXER_WRITE_MIC d +SOUND_MIXER_WRITE_CD d +SOUND_MIXER_WRITE_IMIX d +SOUND_MIXER_WRITE_ALTPCM d +SOUND_MIXER_WRITE_RECLEV d +SOUND_MIXER_WRITE_IGAIN d +SOUND_MIXER_WRITE_OGAIN d +SOUND_MIXER_WRITE_LINE1 d +SOUND_MIXER_WRITE_LINE2 d +SOUND_MIXER_WRITE_LINE3 d +SOUND_MIXER_WRITE_MUTE d +SOUND_MIXER_WRITE_ENHANCE d +SOUND_MIXER_WRITE_LOUD d +SOUND_MIXER_WRITE_RECSRC d diff -u --new-file -r strace-4.2/ioctldefs.c strace-4.2-ioctldefs/ioctldefs.c --- strace-4.2/ioctldefs.c Wed Dec 31 19:00:00 1969 +++ strace-4.2-ioctldefs/ioctldefs.c Thu Apr 20 22:04:47 2000 @@ -0,0 +1,589 @@ +/* + * 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. + * + */ + +/* Changes on 2000-04-20: + * - Added out-of-memory checking to malloc, strdup, and realloc calls. + * - Added diagnosis of invalid format codes. + */ + + +#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; + +/* Safe memory allocation functions */ + +static char *safe_strdup(char *s) { + char *ns; + + ns = strdup(s); + if (!ns) { + fprintf(stderr, "safe_strdup: out of memory."); + exit(-1); + } + + return ns; +} + +static void *safe_malloc(size_t size) { + void *m; + + m = malloc(size); + if (!m) { + fprintf(stderr, "safe_malloc: out of memory."); + exit(-1); + } + + return m; +} + +static void *safe_realloc(void *m, size_t size) { + + m = realloc(m, size); + if (!m) { + fprintf(stderr, "safe_realloc: out of memory."); + exit(-1); + } + + return m; +} + + +/* Create a new idi, strduping the strings given. */ +IDI *idi_new(name, pspec) +char *name; +char *pspec; +{ + IDI *idi; + + idi = safe_malloc(sizeof(IDI)); + idi->name = safe_strdup(name); + idi->pspec = safe_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 = safe_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; + int line = 0; + + f = fopen(fn, "r"); + if (!f) { + fprintf(stderr, "Couldn't open ioctl def file '%s'.\n", + fn); + exit(-1); + } + + while (fgets(buf, 256, f)) { + line++; + iop_chomp(buf); + iop_strcomment(buf); + pspec = iop_strsplit(buf); + + if (!*buf) continue; + if (!pspec) { + fprintf(stderr, "%s line %d is invalid.\n", fn, line); + 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 = ", (void *) 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; + case '[': + comma; + needcomma = 0; + tprintf("["); + break; + case ']': + tprintf("]"); + needcomma = 1; + break; + default: + tprintf("(err: unknown format character '%c'.)", c); + } + + 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 -u --new-file -r strace-4.2/strace.1 strace-4.2-ioctldefs/strace.1 --- strace-4.2/strace.1 Thu Dec 23 09:20:15 1999 +++ strace-4.2-ioctldefs/strace.1 Thu Apr 20 11:31:37 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 -u --new-file -r strace-4.2/strace.c strace-4.2-ioctldefs/strace.c --- strace-4.2/strace.c Thu Dec 23 09:20:15 1999 +++ strace-4.2-ioctldefs/strace.c Thu Apr 20 11:31:37 2000 @@ -70,6 +70,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)); @@ -137,6 +139,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\ @@ -179,7 +182,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++; @@ -228,6 +231,10 @@ break; case 'e': qualify(optarg); + break; + case 'I': + ioctldef_load(optarg); + ioctldef_wanted = 1; break; case 'o': outfname = strdup(optarg);