/* Copyright, 1988-1992, Russell Nelson, Crynwr Software */ /* This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, version 1. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* comments are an admission that your code isn't clear enough */ /* History:86,1 */ /* Fri Dec 15 11:08:53 1989 send_pkt was also dumping two bytes too many. */ /* Thu Dec 14 14:31:36 1989 receive_upcall was dumping another two bytes too many */ /* Wed Aug 09 12:22:30 1989 receive_upcall was dumping two bytes too many */ #include #include /* the format of the following struct is dependent upon trace.asm */ struct { unsigned length; unsigned char function; unsigned long time; unsigned char error; union { int handle; unsigned char bytes[2000]; struct { unsigned version; unsigned char class; unsigned type; unsigned char number; unsigned char basic; } di; struct { unsigned char if_class; unsigned if_type; unsigned char if_number; unsigned typelen; unsigned handle; } at; struct { unsigned handle; unsigned length; } ga; struct { unsigned handle; unsigned mode; } srm; } data; } record; char *functions[] = { "function_0", "driver_info", "access_type", "release_type", "send_pkt", "terminate", "get_address", "reset_interface", "function_8", "function_9", "get_parameters", "as_send_pkt", "function_12", "function_13", "function_14", "function_15", "function_16", "function_17", "function_18", "function_19", "set_rcv_mode", "get_rcv_mode", "set_multicast_list", "get_multicast_list", "get_statistics", "set_address", }; enum { bad_function, driver_info, access_type, release_type, send_pkt, terminate, get_address, reset_interface, get_parameters = 8, as_send_pkt, set_rcv_mode = 20, get_rcv_mode, set_multicast_list, get_multicast_list, get_statistics, set_address, receive_upcall = 255 }; char *errors[] = { "no_error", "bad_handle", "no_class", "no_type", "no_number", "bad_type", "no_multicast", "cant_terminate", "bad_mode", "no_space", "type_inuse", "bad_command", "cant_send", "cant_set", "bad_address", }; main() { FILE *inf; static first_time = 1; unsigned long time_zero; char args[80], results[80]; inf = fopen("trace.out", "rb"); if (!inf) { fprintf(stderr, "dump: cannot open \"trace.out\"\n"); exit(1); } setvbuf(stdout, NULL, _IOFBF, 4096); for(;;) { if (fread(&record.length, 2, 1, inf) != 1) break; fread(&record.function, 1, record.length - 2, inf); if (first_time) { first_time = 0; time_zero = record.time; } args[0] = '\0'; switch(record.function) { case get_statistics: case terminate: case reset_interface: case release_type: case get_address: case receive_upcall: sprintf(args, "%d", record.data.handle); break; case set_rcv_mode: sprintf(args, "%d %d", record.data.srm.handle, record.data.srm.mode); break; case access_type: sprintf(args, "%d %d %d %d", record.data.at.if_class, record.data.at.if_type, record.data.at.if_number, record.data.at.typelen); break; default: strcpy(args, ""); } if (record.error != 0) { sprintf(results, "%s (%d)", record.error >= (sizeof errors)/(sizeof errors[0])?"?":errors[record.error], record.error); } else switch(record.function) { case driver_info: sprintf(results, "%d %d %d %d %d", record.data.di.version, record.data.di.class, record.data.di.type, record.data.di.number, record.data.di.basic); break; case access_type: sprintf(results, "%d", record.data.at.handle); break; case send_pkt: sprintf(results, "%d bytes", record.length - 8); break; case receive_upcall: sprintf(results, "%d bytes", record.length - 10); break; default: strcpy(results, errors[0]); } printf("%7.2f %s(%s) = %s\n", (float)(record.time - time_zero) / 18.2, record.function == receive_upcall?"receive_upcall": functions[record.function], args, results); switch(record.function) { case get_address: dump_bytes(&record.data.bytes[4], record.data.ga.length); break; case receive_upcall: dump_bytes(&record.data.bytes[2], record.length - 10); break; case send_pkt: dump_bytes(&record.data.bytes[0], record.length - 8); break; } } } dump_bytes(unsigned char *bytes, int count) { int n; char buf[16]; int address; void fmtline(); address = 0; while(count){ if (count > 16) n = 16; else n = count; fmtline(address,bytes,n); address += n; count -= n; bytes += n; } } /* Print a buffer up to 16 bytes long in formatted hex with ascii * translation, e.g., * 0000: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 0123456789:;<=>? */ void fmtline(addr,buf,len) int addr; char *buf; int len; { char line[80]; register char *aptr,*cptr; unsigned register char c; void ctohex(); memset(line,' ',sizeof(line)); ctohex(line,addr >> 8); ctohex(line+2,addr & 0xff); aptr = &line[6]; cptr = &line[55]; while(len-- != 0){ c = *buf++; ctohex(aptr,c); aptr += 3; c &= 0x7f; *cptr++ = isprint(c) ? c : '.'; } *cptr++ = '\n'; fwrite(line,1,(unsigned)(cptr-line),stdout); } /* Convert byte to two ascii-hex characters */ static void ctohex(buf,c) register char *buf; register int c; { static char hex[] = "0123456789abcdef"; *buf++ = hex[c >> 4]; *buf = hex[c & 0xf]; }