home *** CD-ROM | disk | FTP | other *** search
/ Netware Super Library / Netware Super Library.iso / mis_util / trace27 / trace.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-01  |  37.1 KB  |  1,505 lines

  1. /*
  2.  * trace - trace DOS system calls
  3.  *
  4.  * (C) Copyright 1991-1994 Diomidis Spinellis.  All rights reserved.
  5.  *
  6.  * $Id: trace.c%v 1.28 1994/10/01 11:32:56 dds Exp $
  7.  *
  8.  * Permission to use, copy, and distribute this software and its
  9.  * documentation for any purpose and without fee is hereby granted,
  10.  * provided that the above copyright notice appear in all copies and that
  11.  * both that copyright notice and this permission notice appear in
  12.  * supporting documentation.
  13.  * 
  14.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  15.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  16.  * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  17.  */
  18.  
  19. #include <stddef.h>
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <stdarg.h>
  23. #include <string.h>
  24. #include <fcntl.h>
  25. #include <io.h>
  26. #include <dos.h>
  27. #include <process.h>
  28. #include <ctype.h>
  29. #include <time.h>
  30. #include <signal.h>
  31. #include <bios.h>
  32. #include <errno.h>
  33.  
  34. #ifndef lint
  35. static char rcsid[] = "$Id: trace.c%v 1.28 1994/10/01 11:32:56 dds Exp $";
  36. #endif
  37.  
  38. #define MAXBUFF 1025
  39.  
  40. /*
  41.  * Program options.  See main() for explanation.
  42.  */
  43. static stringprint, hexprint, otherprint, nameprint, regdump, tracechildren;
  44. static timeprint, count, tracetsr, tsrpsp, numprint, worderror, pspprint;
  45. static branchprint, append;
  46. static unsigned datalen = 15;
  47. static someprefix;
  48. static char *fname = "trace.log";
  49.  
  50. static mypsp, tracedpsp;        /* PSP of us and traced program */
  51. static execed;                /* True after we run */
  52. static char _far *critsectflag;        /* DOS critical section flag */
  53. static char _far *criterrflag;        /* DOS citical error flag */
  54.  
  55. /* DOS interrupt */
  56. #define DOS_INT    0x21
  57.  
  58. /* Old dos handler to chain to */
  59. static void (_interrupt _far _cdecl *old_dos_handler)();
  60.  
  61. /* Output file descriptor */
  62. static int fd;
  63.  
  64. #pragma check_stack(off)
  65. #pragma intrinsic(strlen)
  66.  
  67. /*
  68.  * Output a string to the trace file
  69.  */
  70. static void
  71. tputs(char *s)
  72. {
  73.     int len = strlen(s);
  74.     int sseg, soff;
  75.     char far *p = s;
  76.  
  77.     sseg = FP_SEG(p);
  78.     soff = FP_OFF(p);
  79.     _asm {
  80.         mov bx, fd
  81.         mov cx, len
  82.         mov ax, sseg
  83.         mov dx, soff
  84.         push ds
  85.         mov ds, ax
  86.         mov ah, 40h
  87.         int 21h
  88.         pop ds
  89.     }
  90. }
  91.  
  92. int _doprnt(char *fmt, va_list marker, FILE *f);
  93.  
  94. /*
  95.  * Print a formated string to the trace file
  96.  */
  97. int
  98. tprintf(char *fmt, ...)
  99. {
  100.     va_list marker;
  101.     int result;
  102.     static char msg[200];
  103.     static FILE f;
  104.  
  105.     f._ptr = f._base = msg;
  106.     f._cnt = 32000;
  107.     f._flag = _IOWRT | _IOFBF;
  108.     va_start(marker, fmt);
  109.     result = _doprnt(fmt, marker, &f);
  110.     *f._ptr = '\0';
  111.     va_end(marker);
  112.     tputs(msg);
  113.     return result;
  114. }
  115.  
  116. /*
  117.  * Convert a high low pair into a long
  118.  */
  119. static long
  120. makelong(unsigned high, unsigned low)
  121. {
  122.     union {
  123.         struct {
  124.             unsigned low;
  125.             unsigned high;
  126.         } hl;
  127.         long l;
  128.     } v;
  129.  
  130.     v.hl.high = high;
  131.     v.hl.low = low;
  132.     return v.l;
  133. }
  134.  
  135.  
  136. /*
  137.  * Convert a segment offset pair into a far pointer.
  138.  */
  139. static void _far *
  140. makefptr(unsigned seg, unsigned off)
  141. {
  142.     union {
  143.         struct {
  144.             unsigned off;
  145.             unsigned seg;
  146.         } so;
  147.         void _far *ptr;
  148.     } v;
  149.  
  150.     v.so.seg = seg;
  151.     v.so.off = off;
  152.     return v.ptr;
  153. }
  154.  
  155. static char buff[MAXBUFF];
  156.  
  157. /*
  158.  * Convert a $ terminated string to a 0 terminated one
  159.  */
  160. static char *
  161. makestring(unsigned sseg, unsigned soff)
  162. {
  163.     char _far *p, *s;
  164.     unsigned count = 0;
  165.  
  166.     p = makefptr(sseg, soff);
  167.     s = buff;
  168.     while (*p != '$' && count < datalen) {
  169.         *s++ = *p++;
  170.         count++;
  171.     }
  172.     *s = '\0';
  173.     return buff;
  174. }
  175.  
  176. /*
  177.  * Return day of week
  178.  */
  179. static char *
  180. weekday(int n)
  181. {
  182.     switch (n) {
  183.         case 0: return "Sun";
  184.         case 1: return "Mon";
  185.         case 2: return "Tue";
  186.         case 3: return "Wed";
  187.         case 4: return "Thu";
  188.         case 5: return "Fri";
  189.         case 6: return "Sat";
  190.     }
  191. }
  192.  
  193. /*
  194.  * Decode device information as for ioctl 0
  195.  */
  196. static void
  197. devinfo(unsigned n)
  198. {
  199.     if (n & 0x80) {
  200.         tputs("\tCHARDEV: ");
  201.         if (n & 0x01) tputs("STDIN ");
  202.         if (n & 0x02) tputs("STDOUT ");
  203.         if (n & 0x04) tputs("NUL ");
  204.         if (n & 0x08) tputs("CLOCK$ ");
  205.         if (n & 0x10) tputs("SPECIAL ");
  206.         if (n & 0x20) tputs("RAW ");
  207.         if (n & 0x40) tputs("NOT_EOF "); else tputs("EOF ");
  208.         if (n & 0x1000) tputs("REMOTE "); else tputs("LOCAL ");
  209.         if (n & 0x4000) tputs("CAN_IOCTL"); else tputs("NO_IOCTL");
  210.     } else {
  211.         tputs("\tFILE: ");
  212.         tprintf("device=%u ", n & 0x1f);
  213.         if (n & 0x40) tputs("NOT_WRITTEN "); else tputs("WRITTEN ");
  214.         if (n & 0x800) tputs("FIXED "); else tputs("REMOVABLE ");
  215.         if (n & 0x4000) tputs("KEEP_DATE "); else tputs("UPDATE_DATE ");
  216.         if (n & 0x8000) tputs("REMOTE"); else tputs("LOCAL");
  217.     }
  218.     tputs("\r\n");
  219. }
  220.  
  221. /*
  222.  * Convert a boolean variable to on / off.
  223.  */
  224. static char *
  225. makeonoff(int n)
  226. {
  227.     switch (n) {
  228.     case 0:
  229.         return "off";
  230.     case 1:
  231.         return "on";
  232.     default:
  233.         return itoa(n, buff, 10);
  234.     }
  235. }
  236.  
  237.  
  238. /*
  239.  * Print the string contained in the buffer specified of len bytes.
  240.  */
  241. static void
  242. outbuff(unsigned sseg, unsigned soff, unsigned len)
  243. {
  244.     char _far *p;
  245.     unsigned l, i;
  246.     char *s = buff;
  247.     int hex = 0;
  248.     static char hexnum[] = "0123456789abcdef";
  249.  
  250.     p = makefptr(sseg, soff);
  251.     l = min(datalen, len);
  252.     for (i = 0; i < l; i++)
  253.         if (!isascii(p[i]))
  254.             if (hexprint)
  255.                 hex = 1;
  256.             else
  257.                 return;
  258.     *s++ = '\t';
  259.     if (hex) {
  260.         *s++ = '{';
  261.         for (i = 0; i < l; i++) {
  262.             *s++ = '0';
  263.             *s++ = 'x';
  264.             *s++ = hexnum[(unsigned char)p[i]>>4];
  265.             *s++ = hexnum[p[i] & 0xf];
  266.             *s++ = ',';
  267.         }
  268.         if (l < len) { *s++ = '.'; *s++ = '.'; *s++ = '.';}
  269.         *s++ = '}';
  270.     } else {
  271.         *s++ = '"';
  272.         for (i = 0; i < l; i++)
  273.             switch (p[i]) {
  274.             case '\n': *s++ = '\\'; *s++ = 'n'; break;
  275.             case '\t': *s++ = '\\'; *s++ = 't'; break;
  276.             case '\b': *s++ = '\\'; *s++ = 'b'; break;
  277.             case '\r': *s++ = '\\'; *s++ = 'r'; break;
  278.             case '\f': *s++ = '\\'; *s++ = 'f'; break;
  279.             case '\v': *s++ = '\\'; *s++ = 'v'; break;
  280.             case '\a': *s++ = '\\'; *s++ = 'a'; break;
  281.             default:
  282.                 if (iscntrl(p[i])) {
  283.                     *s++ = '\\'; *s++ = 'x';
  284.                     *s++ = hexnum[(unsigned)p[i]>>4];
  285.                     *s++ = hexnum[p[i] & 0xf];
  286.                 } else
  287.                     *s++ = p[i];
  288.             }
  289.         if (l < len) { *s++ = '.'; *s++ = '.'; *s++ = '.';}
  290.         *s++ = '"';
  291.     }
  292.     *s++ = '\0';
  293.     tputs(buff);
  294. }
  295.  
  296.     
  297. /*
  298.  * Return executing programs PSP
  299.  */
  300. static unsigned
  301. getpsp(void)
  302. {
  303.     _asm mov ah, 51h
  304.     _asm int 21h
  305.     _asm mov ax, bx
  306. }
  307.  
  308. /*
  309.  * Set executing programs PSP
  310.  */
  311. static void
  312. setpsp(unsigned psp)
  313. {
  314.     _asm mov ah, 50h
  315.     _asm mov bx, psp
  316.     _asm int 21h
  317. }
  318.  
  319. /*
  320.  * Return the DOS critical section flag pointer.
  321.  */
  322. static char _far *
  323. getcritsectflag(void)
  324. {
  325.     unsigned sseg, soff;
  326.  
  327.     _asm mov ah, 34h
  328.     _asm int 21h
  329.     _asm mov ax, es
  330.     _asm mov sseg, ax
  331.     _asm mov soff, bx
  332.     return makefptr(sseg, soff);
  333. }
  334.  
  335. /*
  336.  * Return the DOS Data Transfer Address (DTA)
  337.  */
  338. static void _far *
  339. getdta(void)
  340. {
  341.     unsigned sseg, soff;
  342.  
  343.     _asm mov ah, 2fh
  344.     _asm int 21h
  345.     _asm mov ax, es
  346.     _asm mov sseg, ax
  347.     _asm mov soff, bx
  348.     return makefptr(sseg, soff);
  349. }
  350.  
  351. /*
  352.  * Convert a file mode number into a Unix ls -l like string.
  353.  */
  354. static char *
  355. strmode(unsigned mode)
  356. {
  357.     char *p = buff;
  358.  
  359.     if (!stringprint)
  360.         return "";
  361.     *p++ = '[';
  362.     if (mode & 0x20) *p++ = 'a'; else *p++ = '-';
  363.     if (mode & 0x10) *p++ = 'd'; else *p++ = '-';
  364.     if (mode & 0x08) *p++ = 'v'; else *p++ = '-';
  365.     if (mode & 0x04) *p++ = 's'; else *p++ = '-';
  366.     if (mode & 0x02) *p++ = 'h'; else *p++ = '-';
  367.     if (mode & 0x01) *p++ = 'r'; else *p++ = '-';
  368.     *p++ = ']';
  369.     *p++ = '\0';
  370.     return buff;
  371. }
  372.  
  373. /*
  374.  * Print the DTA contents as filled by the find first / find next functions
  375.  */
  376. static void
  377. outdta(void)
  378. {
  379.     struct s_dta {
  380.         char reserve[21];
  381.         unsigned char mode;
  382.         unsigned short time;
  383.         unsigned short date;
  384.         long size;
  385.         char name[13];
  386.     } _far *d;
  387.     int psp;
  388.  
  389.     psp = getpsp();
  390.     setpsp(tracedpsp);
  391.     d = getdta();
  392.     setpsp(psp);
  393.     tprintf("ok\t(%-12Fs %10lu %2u/%2u/%2u %2u:%02u.%-2u %s)\r\n", d->name, d->size, (d->date >> 9) + 80, (d->date >> 5) & 0xf, d->date & 0x1f, d->time >> 11, (d->time >> 5) & 0x3f, d->time & 0x1f, strmode(d->mode));
  394. }
  395.  
  396. char *errcodes[] = {
  397.     "Error 0",
  398.     "Invalid function code",
  399.     "File not found",
  400.     "Path not found",
  401.     "Too many open files",
  402.     "Access denied",
  403.     "Invalid handle",
  404.     "Memory control blocks destroyed",
  405.     "Insufficient memory",
  406.     "Invalid memory block address",
  407.     "Invalid environment",
  408.     "Invalid format",
  409.     "Invalid access code",
  410.     "Invalid data",
  411.     "Reserved 14",
  412.     "Invalid drive",
  413.     "Attempt to remove current directory",
  414.     "Not same device",
  415.     "No more files",
  416.     "Disk is write-protected",
  417.     "Bad disk unit",
  418.     "Drive not ready",
  419.     "Invalid disk command",
  420.     "CRC error",
  421.     "Invalid length",
  422.     "Seek error",
  423.     "Not an MS-DOS disk",
  424.     "Sector not found",
  425.     "Out of paper",
  426.     "Write fault",
  427.     "Read fault",
  428.     "General failure",
  429.     "Sharing violation",
  430.     "Lock violation",
  431.     "Wrong disk",
  432.     "FCB unavailable",
  433. };
  434.  
  435. /*
  436.  * Print error without newline
  437.  */
  438. static void
  439. errprint(int err)
  440. {
  441.     if (worderror && err <= 35)
  442.         tprintf("Error (%s)", errcodes[err]);
  443.     else
  444.         tprintf("Error (%u)", err);
  445. }
  446.  
  447. /*
  448.  * Print error with newline
  449.  */
  450. static void
  451. errprintln(int err)
  452. {
  453.     if (worderror && err <= 35)
  454.         tprintf("Error (%s)\r\n", errcodes[err]);
  455.     else
  456.         tprintf("Error (%u)\r\n", err);
  457. }
  458.  
  459. /*
  460.  * Print error or ok
  461.  */
  462. static void
  463. okerrorproc(unsigned flags, unsigned ax)
  464. {
  465.     if (flags & 1)
  466.         errprintln(ax);
  467.     else
  468.         tputs("ok\r\n");
  469. }
  470.  
  471. /*
  472.  * Print error
  473.  */
  474. static void
  475. nerrorproc(unsigned flags, unsigned ax)
  476. {
  477.     if (flags & 1)
  478.         errprintln(ax);
  479.     else
  480.         tprintf("%u\r\n", ax);
  481. }
  482.  
  483. /*
  484.  * Print memory allocation strategy
  485.  */
  486. static void
  487. print_memory_strategy(unsigned str)
  488. {
  489.     if (str & 0x40)
  490.         tputs("high memory ");
  491.     else if (str & 0x80)
  492.         tputs("high then low memory ");
  493.     else 
  494.         tputs("low memory ");
  495.     switch (str & 7) {
  496.     case 0: tputs("first fit"); break;
  497.     case 1: tputs("best fit"); break;
  498.     case 2: tputs("last fit"); break;
  499.     }
  500. }
  501.  
  502. /*
  503.  * Print date and time as packed in DOS format
  504.  */
  505. static void
  506. print_dtim(int date, int time)
  507. {
  508.     tprintf("%2u/%2u/%2u %2u:%02u.%-2u",
  509.         (date >> 9) + 80, (date >> 5) & 0xf, date & 0x1f,
  510.         time >> 11, (time >> 5) & 0x3f, time & 0x1f);
  511. }
  512.  
  513. /*
  514.  * Print time of day.
  515.  */
  516. static void
  517. print_time(void)
  518. {
  519.     _strtime(buff);
  520.     buff[8] = ' ';
  521.     buff[9] = '\0';
  522.     tputs(buff);
  523. }
  524.  
  525. #pragma check_stack()
  526.  
  527. struct s_func {
  528.     char *name;
  529.     unsigned count;
  530. } funcs[256] =
  531. {
  532.     {"terminate", 0},        /* 00H    DOS1 - TERMINATE PROGRAM */
  533.     {"key_in_echo", 0},        /* 01H    DOS1 - KEYBOARD INPUT WITH ECHO */
  534.     {"disp_out", 0},        /* 02H    DOS1 - DISPLAY OUTPUT */
  535.     {"serial_in", 0},        /* 03H    DOS1 - SERIAL INPUT */
  536.     {"serial_out", 0},        /* 04H    DOS1 - SERIAL OUTPUT */
  537.     {"printer_out", 0},        /* 05H    DOS1 - PRINTER OUTPUT */
  538.     {"direct_out", 0},        /* 06H    DOS1 - DIRECT CONSOLE OUT */
  539.     {"dir_key_in", 0},        /* 07H    DOS1 - DIRECT KEYBOARD INPUT */
  540.     {"key_in", 0},            /* 08H    DOS1 - KEYBOARD INPUT WITHOUT ECHO */
  541.     {"disp_string", 0},        /* 09H    DOS1 - DISPLAY STRING */
  542.     {"buf_key_in", 0},        /* 0AH    DOS1 - BUFFERED KEYBOARD INPUT */
  543.     {"chk_key_stat", 0},        /* 0BH    DOS1 - CHECK KEYBOARD STATUS */
  544.     {"clr_key_func", 0},        /* 0CH    DOS1 - CLEAR KEY BUFFER AND PERFORM FUNCTION */
  545.     {"flush", 0},            /* 0DH    DOS1 - DISK RESET */
  546.     {"sel_drive", 0},        /* 0EH    DOS1 - SELECT CURRENT DRIVE */
  547.     {"open_file", 0},        /* 0FH    DOS1 - OPEN FILE */
  548.     {"close_file", 0},        /* 10H    DOS1 - CLOSE FILE */
  549.     {"search_first", 0},        /* 11H    DOS1 - SEARCH FOR FIRST MATCHING FILE */
  550.     {"search_next", 0},        /* 12H    DOS1 - SEARCH FOR NEXT MATCHING FILE */
  551.     {"delete_file", 0},        /* 13H    DOS1 - DELETE FILE */
  552.     {"rd_seq_rec", 0},        /* 14H    DOS1 - READ SEQUENTIAL RECORD */
  553.     {"wr_seq_rec", 0},        /* 15H    DOS1 - WRITE SEQUENTIAL RECORD */
  554.     {"create_file", 0},        /* 16H    DOS1 - CREATE FILE */
  555.     {"rename_file", 0},        /* 17H    DOS1 - RENAME FILE */
  556.     {"reserved 0x18", 0},        /* 18h */
  557.     {"rd_cur_drive", 0},        /* 19H    DOS1 - REPORT CURRENT DRIVE */
  558.     {"set_dta", 0},            /* 1AH    DOS1 - SET DISK TRANSFER AREA FUCNTION */
  559.     {"rd_fat_1", 0},        /* 1BH    DOS1 - READ CURRENT DRIVE'S FAT */
  560.     {"drive_info", 0},        /* 1CH    DOS1 - READ ANY DRIVE'S FAT */
  561.     {"reserved 0x1d", 0},        /* 1dh */
  562.     {"reserved 0x1e", 0},        /* 1eh */
  563.     {"reserved 0x1f", 0},        /* 1fh */
  564.     {"reserved 0x20", 0},        /* 20h */
  565.     {"rd_ran_rec1", 0},        /* 21H    DOS1 - READ RANDOM FILE RECORD */
  566.     {"wr_ran_rec1", 0},        /* 22H    DOS1 - WRITE RANDOM FILE RECORD */
  567.     {"rd_file_size", 0},        /* 23H    DOS1 - REPORT FILE SIZE */
  568.     {"set_ran_rec", 0},        /* 24H    DOS1 - SET RANDOM RECORD FIELD SIZE */
  569.     {"set_int_vec", 0},        /* 25H    DOS1 - SET INTERRUPT VECTOR */
  570.     {"create_seg", 0},        /* 26H    DOS1 - CREATE PROGRAM SEGMENT FUCNTION */
  571.     {"rd_ran_rec2", 0},        /* 27H    DOS1 - READ RANDOM FILE RECORD */
  572.     {"wr_ran_rec2", 0},        /* 28H    DOS1 - WRITE RANDOM FILE RECORD FUCNTION */
  573.     {"parse_name", 0},        /* 29H    DOS1 - PARSE FILENAME */
  574.     {"get_date", 0},        /* 2AH    DOS1 - GET DATE */
  575.     {"set_date", 0},        /* 2BH    DOS1 - SET DATE */
  576.     {"get_time", 0},        /* 2CH    DOS1 - GET TIME */
  577.     {"set_time", 0},        /* 2DH    DOS1 - SET TIME */
  578.     {"set_verify", 0},        /* 2EH    DOS1 - SET DISK WRITE VERIFICATION MODE */
  579.     {"get_dta", 0},            /* 2FH    DOS2 - GET DISK TRANSFER AREA ADDRESS */
  580.     {"get_ver", 0},            /* 30H    DOS2 - GET DOS VERSION NUMBER */
  581.     {"keep", 0},            /* 31H    DOS2 - ADVANCED TERMINATE BUT STAY RESIDENT */
  582.     {"reserved 0x32", 0},        /* 32h */
  583.     {"cntrl_brk", 0},        /* 33H    DOS2 - GET/SET CONTROL BREAK STATUS */
  584.     {"critical_flag", 0},        /* 34h */
  585.     {"get_int_vec", 0},        /* 35H    DOS2 - GET INTERRUPT VECTOR */
  586.     {"get_space", 0},        /* 36H    DOS2 - GET DISK FREE SPACE */
  587.     {"switchar", 0},            /* 37h */
  588.     {"get_country", 0},        /* 38H    DOS2 - GET COUNTRY INFORMATION */
  589.     {"mkdir", 0},            /* 39H    DOS2 - MAKE DIRECTORY */
  590.     {"rmdir", 0},            /* 3AH    DOS2 - REMOVE DIRECTORY */
  591.     {"chdir", 0},            /* 3BH    DOS2 - CHANGE CURRENT DIRECTORY FUCNTION */
  592.     {"create", 0},            /* 3CH    DOS2 - CREATE FILE */
  593.     {"open", 0},            /* 3DH    DOS2 - OPEN FILE */
  594.     {"close", 0},            /* 3EH    DOS2 - CLOSE FILE */
  595.     {"read", 0},            /* 3FH    DOS2 - READ FILE/DEVICE */
  596.     {"write", 0},            /* 40H    DOS2 - WRITE FILE/DEVICE */
  597.     {"delete", 0},            /* 41H    DOS2 - DELETE FILE */
  598.     {"lseek", 0},            /* 42H    DOS2 - MOVE FILE POINTER */
  599.     {"chmod", 0},            /* 43H    DOS2 - CHANGE FILE MODE */
  600.     {"ioctl", 0},            /* 44H    DOS2 - DEVICE I/O CONTROL */
  601.     {"dup", 0},            /* 45H    DOS2 - DUPLICATE FILE HANDLE */
  602.     {"cdup", 0},            /* 46H    DOS2 - FORCE FILE HANDLE DUPLICATION */
  603.     {"get_dir", 0},            /* 47H    DOS2 - GET CURRENT DIRECTORY */
  604.     {"allocate", 0},        /* 48H    DOS2 - ALLOCATE MEMORY */
  605.     {"free", 0},            /* 49H    DOS2 - FREE MEMORY */
  606.     {"set_block", 0},        /* 4AH    DOS2 - MODIFY ALLOCATED MEMORY BLOCK */
  607.     {"exec", 0},            /* 4BH    DOS2 - LOAD/EXECUTE PROGRAM */
  608.     {"term_proc", 0},        /* 4CH    DOS2 - TERMINATE PROCESS */
  609.     {"get_code", 0},        /* 4DH    DOS2 - GET SUBPROGRAM RETURN CODE */
  610.     {"find_first", 0},        /* 4EH    DOS2 - FIND FIRST FILE MATCH */
  611.     {"find_next", 0},        /* 4FH    DOS2 - FIND NEXT FILE MATCH */
  612.     {"set_psp", 0},            /* 50h */
  613.     {"get_psp", 0},            /* 51h */
  614.     {"sysvars", 0},            /* 52h GET LIST OF LISTS */
  615.     {"reserved 0x53", 0},        /* 53h */
  616.     {"get_verify", 0},        /* 54H    DOS2 - GET FILE WRITE VERIFY STATE */
  617.     {"reserved 0x55", 0},        /* 55h */
  618.     {"rename", 0},            /* 56H    DOS2 - RENAME FILE */
  619.     {"date_time", 0},        /* 57H    DOS2 - GET/SET FILE DATE/TIME */
  620.     {"alloc_strategy", 0},        /* 58h */
  621.     {"get_err", 0},            /* 59H    DOS3 - GET EXTENDED RETURN CODE */
  622.     {"create_temp", 0},        /* 5AH    DOS3 - CREATE TEMPORARY FILE */
  623.     {"create_new", 0},        /* 5BH    DOS3 - CREATE NEW FILE */
  624.     {"file_lock", 0},        /* 5CH    DOS3 - LOCK/UNLOCK FILE ACCESS */
  625.     {"reserved 0x5d", 0},        /* 5dh */
  626.     {"machine_name", 0},        /* 5eh */
  627.     {"assign_list", 0},        /* 5fh */
  628.     {"reserved 0x60", 0},        /* 60h */
  629.     {"reserved 0x61", 0},        /* 61h */
  630.     {"get_psp", 0},            /* 62H    DOS3 - GET PROGRAM SEGMENT PREFIX ADDRESS */
  631. };
  632.  
  633.  
  634. /*
  635.  * Print any prefixes specified by the user before the actual function call.
  636.  */
  637. static void
  638. prefix(int fun, unsigned cs, unsigned ip)
  639. {
  640.     if (timeprint)
  641.         print_time();
  642.     if (pspprint)
  643.         tprintf("%04x ", tracedpsp);
  644.     if (numprint)
  645.         tprintf("%02x ", fun);
  646.     if (branchprint)
  647.         tprintf("%04X:%04X ", cs, ip - 2);
  648. }
  649.  
  650.  
  651. /* 
  652.  * The new DOS interrupt handler 
  653.  */
  654. static void _cdecl _interrupt _far
  655. dos_handler(
  656.     unsigned _es,
  657.     unsigned _ds,
  658.     unsigned _di,
  659.     unsigned _si,
  660.     unsigned _bp,
  661.     unsigned _sp,
  662.     unsigned _bx,
  663.     unsigned _dx,
  664.     unsigned _cx,
  665.     unsigned _ax,
  666.     unsigned _ip,
  667.     unsigned _cs,
  668.     unsigned _flags)
  669. {
  670.     static trace = 1;
  671.     static int fun, funl;
  672.  
  673.     /* Filter out interrupts generated by us */
  674.     if (!execed) {
  675.         if ((_ax >>8) == 0x4b)        /* Exec */
  676.             execed = 1;
  677.         _chain_intr(old_dos_handler);
  678.     }
  679.     if (!trace || *critsectflag || *criterrflag)
  680.         _chain_intr(old_dos_handler);
  681.     trace = 0;
  682.     tracedpsp = getpsp();
  683.     if (tracetsr && tracedpsp != tsrpsp) {
  684.         trace = 1;
  685.         _chain_intr(old_dos_handler);
  686.     }
  687.     fun = _ax >> 8;
  688.     if (count) {
  689.         funcs[fun].count++;
  690.         trace = 1;
  691.         _chain_intr(old_dos_handler);
  692.     }
  693.     setpsp(mypsp);
  694.     if (someprefix)
  695.         prefix(fun, _cs, _ip);
  696.     switch (fun) {
  697.     case 0x02:                /* disp_out */
  698.         tprintf("display_char('%c')\r\n", _dx & 0xff);
  699.         break;
  700.     case 0x06:                /* direct_out */
  701.         tprintf("direct_out('%c')\r\n", _dx & 0xff);
  702.         break;
  703.     case 0x09:                /* disp_string */
  704.         if (stringprint)
  705.             tprintf("display(\"%s\")\r\n", makestring(_ds, _dx));
  706.         else
  707.             tprintf("display(%04X:%04X)\r\n", _ds, _dx);
  708.         break;
  709.     case 0x0d:
  710.         tputs("flush()\r\n");
  711.         break;
  712.     case 0x0e:                /* set_current_disk */
  713.         tprintf("set_current_disk(%c:) = ", (_dx & 0xff) < 27 ? (_dx & 0xff) + 'A' : '.');
  714.         break;
  715.     case 0x19:                /* get_current_disk */
  716.         break;
  717.     case 0x1a:                /* set_dta */
  718.         tprintf("set_dta(%04X:%04X)\r\n", _ds, _dx);
  719.         break;
  720.     case 0x1c:                /* drive information */
  721.         tprintf("drive_info(%d) = ", _dx & 0xff);
  722.         break;
  723.     case 0x25:                /* set_vector */
  724.         tprintf("set_vector(%#x, %04X:%04X)\r\n", _ax & 0xff, _ds, _dx);
  725.         break;
  726.     case 0x29:                /* parse_name */
  727.         tprintf("parse_name(%04X:%04X, %d, %04X:%04X) = ",
  728.             _ds, _si, _ax & 0xff, _es, _di);
  729.         break;
  730.     case 0x2a:                /* get_date */
  731.     case 0x2c:                /* get_time */
  732.         break;
  733.     case 0x2d:                /* set_time */
  734.         tprintf("set_time(%02d:%02d:%02d.%d) = ", _cx >> 8, _cx & 0xff, _dx >> 8, _dx & 0xff);
  735.         break;
  736.     case 0x2f:                /* get_dta */
  737.     case 0x30:                /* get_version */
  738.         break;
  739.     case 0x33:                /* cntrl_brk */
  740.         switch (funl = (_ax & 0xff)) {
  741.         case 0:
  742.             break;
  743.         case 1:
  744.             tprintf("set_break(%s)\r\n", makeonoff(_dx & 0xff));
  745.             break;
  746.         case 2:
  747.             tprintf("getset_break(%s) = ", makeonoff(_dx & 0xff));
  748.             break;
  749.         default:
  750.             goto aka_default;
  751.         }
  752.         break;
  753.     case 0x34:                /* critical_flag */
  754.         break;
  755.     case 0x35:                /* get_vector */
  756.         tprintf("get_vector(%#x) = ", _ax & 0xff);
  757.         break;
  758.     case 0x39:                /* Mkdir */
  759.         tprintf("mkdir(\"%Fs\") = ", makefptr(_ds, _dx));
  760.         break;
  761.     case 0x3a:                /* Rmdir */
  762.         tprintf("rmdir(\"%Fs\") = ", makefptr(_ds, _dx));
  763.         break;
  764.     case 0x3b:                /* Chdir */
  765.         tprintf("chdir(\"%Fs\") = ", makefptr(_ds, _dx));
  766.         break;
  767.     case 0x3c:                /* Creat */
  768.         tprintf("creat(\"%Fs\", %02x%s) = ", makefptr(_ds, _dx), _cx, strmode(_cx));
  769.         break;
  770.     case 0x3d:                /* Open */
  771.         tprintf("open(\"%Fs\", %d) = ", makefptr(_ds, _dx), _ax & 0xff);
  772.         break;
  773.     case 0x3e:                /* Close */
  774.         tprintf("close(%u) = ", _bx);
  775.         break;
  776.     case 0x3f:                /* Read */
  777.         tprintf("read(%u, %04X:%04X, %u) = ", _bx, _ds, _dx, _cx);
  778.         break;
  779.     case 0x40:                /* Write */
  780.         tprintf("write(%u, %04X:%04X, %u) = ", _bx, _ds, _dx, _cx);
  781.         break;
  782.     case 0x41:                /* Unlink */
  783.         tprintf("chdir(\"%Fs\") = ", makefptr(_ds, _dx));
  784.         break;
  785.     case 0x42:                /* Lseek */
  786.         tprintf("lseek(%u, %ld, %d) = ",_bx, makelong(_cx, _dx), _ax & 0xff);
  787.         break;
  788.     case 0x43:                /* Chmod / getmod */
  789.         switch (funl = (_ax & 0xff)) {
  790.         case 0:
  791.             tputs("getmod(\"");
  792.             break;
  793.         case 1:
  794.             tputs("chmod(\"");
  795.             break;
  796.         default:
  797.             goto aka_default;
  798.         }
  799.         tprintf("%Fs", makefptr(_ds, _dx));
  800.         if ((_ax & 0xff) == 1)
  801.             tprintf("\", %#x%s", _cx, strmode(_cx));
  802.         tputs(") = ");
  803.         break;
  804.     case 0x44:                /* ioctl */
  805.         switch (funl = (_ax & 0xff)) {
  806.         default:
  807.             goto aka_default;
  808.         case 0x00:            /* get device info */
  809.             tprintf("ioctl(GET_DEV_INFO, %d) = ", _bx);
  810.             break;
  811.         case 0x02:            /* read from chdev control */
  812.             tprintf("ioctl(READ_CHDEV_CCHAN, %d, %u, %04X:%04X) = ",
  813.                 _bx, _cx, _ds, _dx);
  814.             break;
  815.         case 0x07:            /* get output status */
  816.             tprintf("ioctl(GET_OUTPUT_STATUS, %d) = ", _bx);
  817.             break;
  818.         case 0x08:            /* check if removable */
  819.             tprintf("ioctl(BD_ISREMOVABLE, %d) = ", _bx & 0xff);
  820.             break;
  821.         case 0x09:            /* check if remote */
  822.             tprintf("ioctl(BD_ISREMOTE, %d) = ", _bx & 0xff);
  823.             break;
  824.         case 0x0a:            /* check if remote */
  825.             tprintf("ioctl(HAN_ISREMOTE, %d) = ", _bx);
  826.             break;
  827.         case 0x0e:            /* get logical map */
  828.             tprintf("ioctl(GET_LMAP, %d) = ", _bx & 0xff);
  829.             break;
  830.         case 0x0f:            /* set logical map */
  831.             tprintf("ioctl(SET_LMAP, %d) = ", _bx & 0xff);
  832.             break;
  833.         }
  834.         break;
  835.     case 0x45:                /* Dup */
  836.         tprintf("dup(%u) = ", _bx);
  837.         break;
  838.     case 0x46:                /* Dup2 */
  839.         tprintf("dup2(%u, %u) = ", _bx, _cx);
  840.         break;
  841.     case 0x47:                /* Getcwd */
  842.         tprintf("getcwd(%d, %04X:%04X) = ", _dx & 0xff, _ds, _si);
  843.         break;
  844.     case 0x48:                /* Alloc */
  845.         tprintf("alloc(%#x0)= ", _bx);
  846.         break;
  847.     case 0x49:                /* Free */
  848.         tprintf("free(%04X:0000) = ", _es);
  849.         break;
  850.     case 0x4a:                /* Realloc */
  851.         tprintf("realloc(%04X:0000, %#x0) = ", _es, _bx);
  852.         break;
  853.     case 0x4b:                /* Exec */
  854.         tprintf("exec(\"%Fs", makefptr(_ds, _dx));
  855.         if (tracechildren)
  856.             tputs("\") = ...\r\n");
  857.         else
  858.             tputs("\") = ");
  859.         if (tracechildren) {
  860.             trace = 1;
  861.             setpsp(tracedpsp);
  862.             _chain_intr(old_dos_handler);
  863.         }
  864.         break;
  865.     case 0x4c:                /* Exit */
  866.         tprintf("exit(%d)\r\n", _ax & 0xff);
  867.         if (tracechildren) {
  868.             trace = 1;
  869.             setpsp(tracedpsp);
  870.             _chain_intr(old_dos_handler);
  871.         }
  872.         break;
  873.     case 0x4d:                /* Get return code */
  874.         break;
  875.     case 0x4e:                /* Findfirst */
  876.         tprintf("findfirst(\"%Fs\", %#x%s) = ", makefptr(_ds, _dx), _cx, strmode(_cx));
  877.         break;
  878.     case 0x4f:                /* Findnext */
  879.         tputs("findnext() = ");
  880.         break;
  881.     case 0x50:                /* set_psp */
  882.         tprintf("set_psp(%04X)\r\n", _bx);
  883.         break;
  884.     case 0x51:                /* get_psp */
  885.         break;
  886.     case 0x52:                /* sysvars */
  887.         tputs("sysvars() = ");
  888.         break;
  889.     case 0x57:                /* get/set date time */
  890.         switch (funl = (_ax & 0xff)) {
  891.         case 0:                /* get time */
  892.             tprintf("get_time(%d) = ", _bx);
  893.             break;
  894.         case 1:                /* set time */
  895.             tprintf("set_time(%d, ");
  896.             print_dtim(_dx, _cx);
  897.             tputs(") = ");
  898.             break;
  899.         default:
  900.             goto aka_default;
  901.         }
  902.         break;
  903.     case 0x58:                /* memory allocation */
  904.         switch (funl = (_ax & 0xff)) {
  905.         case 0:                /* get strategy */
  906.             tputs("get_alloc_str() = ");
  907.             break;
  908.         case 1:                /* set strategy */
  909.             tputs("set_alloc_str(");
  910.             print_memory_strategy(_bx & 0xff);
  911.             tputs(") = ");
  912.             break;
  913.         case 2:                /* get umb state */
  914.             tputs("get_umb_state() = ");
  915.             break;
  916.         case 3:                /* set umb state */
  917.             tprintf("set_umb_state(%d) = ", _bx);
  918.             break;
  919.         default:
  920.             goto aka_default;
  921.         }
  922.         break;
  923.     case 0x5b:                /* Creat new */
  924.         tprintf("creat_new(\"%Fs\", %02x%s) = ", makefptr(_ds, _dx),
  925.              _cx, strmode(_cx));
  926.         break;
  927.     case 0x62:                /* get_psp */
  928.         break;
  929.     case 0x55:                /* Create child PSP */
  930.         tprintf("child_psp(%04X, %04X) = ", _dx, _si);
  931.         break;
  932.     case 0x5a:                /* Tmpfile */
  933.         tprintf("tmpfile(\"%Fs\", %#x) = ", makefptr(_ds, _dx),
  934.             _cx & 0xff);
  935.         break;
  936.     case 0x6c:                /* Open */
  937.         tprintf("open4(\"%Fs\", %d, %s, %d) = ", makefptr(_ds, _si), _bx, strmode(_cx), _dx);
  938.         break;
  939.  
  940.     aka_default:            /* All unknown functions arrive here */
  941.     default:
  942.         if (otherprint) {
  943.             if (nameprint && fun <= 0x62)
  944.                 tputs(funcs[fun].name);
  945.             else
  946.                 tprintf("%02x", fun);
  947.             if (regdump)
  948.                 tprintf(" :ax=%04X bx=%04X cx=%04X dx=%04X si=%04X di=%04X ds=%04X es=%04X\r\n", _ax, _bx, _cx, _dx, _si, _di, _ds, _es);
  949.             else
  950.                 tputs("\r\n");
  951.         }
  952.         setpsp(tracedpsp);
  953.         trace = 1;
  954.         _chain_intr(old_dos_handler);
  955.     }
  956.     /*
  957.      * This is the best place to flush the file.
  958.      * We have printed the function and its parameters, so if the
  959.      * systems crashes the information will be saved.
  960.      */
  961.     if (append) {
  962.         close(fd);
  963.         if ((fd = open(fname, O_TEXT | O_APPEND | O_WRONLY, 0666)) == -1) {
  964.             fd = 1;
  965.             tprintf("ERROR %s \r\n", sys_errlist[errno]);
  966.         }
  967.         lseek(fd, 0l, SEEK_END);
  968.     }
  969.     /*
  970.      * Call the DOS interrupt.  Transfer all function variables to the
  971.      * machine registers, call DOS and transfer the machine registers
  972.      * back to the function variables.
  973.      */
  974.     setpsp(tracedpsp);
  975.     _asm {
  976.         pushf
  977.         push ds
  978.         mov ax, _flags
  979.         push ax
  980.         popf
  981.         mov ax, _es
  982.         mov es, ax
  983.         mov ax, _ds
  984.         mov ds, ax
  985.         mov ax, _ax
  986.         mov bx, _bx
  987.         mov cx, _cx
  988.         mov dx, _dx
  989.         mov si, _si
  990.         mov di, _di
  991.         int 21h
  992.         mov _ax, ax
  993.         mov _bx, bx
  994.         mov _cx, cx
  995.         mov _dx, dx
  996.         mov _si, si
  997.         mov _di, di
  998.         mov ax, es
  999.         mov _es, ax
  1000.         mov ax, ds
  1001.         mov es, ax
  1002.         pushf
  1003.         pop ax
  1004.         mov _flags, ax
  1005.         pop ds
  1006.         popf
  1007.     }
  1008.     setpsp(mypsp);
  1009.     switch (fun) {
  1010.     case 0x02:                /* disp_out */
  1011.     case 0x06:                /* direct_out */
  1012.     case 0x09:                /* disp_string */
  1013.     case 0x0d:                /* flush */
  1014.         break;
  1015.     case 0x0e:                /* set_current_disk */
  1016.         tprintf("%d\r\n", _ax & 0xff);
  1017.         break;
  1018.     case 0x19:                /* get_current_disk */
  1019.         tprintf("get_current_disk() = %c:\r\n", (_ax & 0xff) + 'A');
  1020.         break;
  1021.     case 0x1a:                /* set_dta */
  1022.         break;
  1023.     case 0x1c:                /* drive information */
  1024.         tprintf("s/c=%u b/s=%u nc=%u ty=", _ax & 0xff, _cx, _dx);
  1025.         switch (*(unsigned char *)makefptr(_ds, _bx)) {
  1026.         case 0xff: tputs("320K\r\n"); break;
  1027.         case 0xfe: tputs("160K\r\n"); break;
  1028.         case 0xfd: tputs("360K\r\n"); break;
  1029.         case 0xfc: tputs("180K\r\n"); break;
  1030.         case 0xf9: tputs("1.2M\r\n"); break;
  1031.         case 0xf8: tputs("HD\r\n"); break;
  1032.         default: tputs("other\r\n"); break;
  1033.         }
  1034.         break;
  1035.     case 0x25:                /* set_vector */
  1036.         break;
  1037.     case 0x29:                /* parse_name */
  1038.         tprintf("%d (%04X:%04X)\r\n", _ax & 0xff, _ds, _si);
  1039.         break;
  1040.     case 0x2a:                /* get_date */
  1041.         tprintf("get_date() = %2u/%2u/%2u (%s)\r\n", _cx, _dx >> 8,  _dx & 0xff, weekday(_ax & 0xff));
  1042.         break;
  1043.     case 0x2c:                /* get_time */
  1044.         tprintf("get_time() = %02d:%02d:%02d.%d\r\n", _cx >> 8, _cx & 0xff, _dx >> 8, _dx & 0xff);
  1045.         break;
  1046.     case 0x2d:                /* set_time */
  1047.         if ((_ax & 0xff) == 0)
  1048.             tputs("ok\r\n");
  1049.         else
  1050.             tputs("invalid\r\n");
  1051.         break;
  1052.     case 0x2f:                /* get_dta */
  1053.         tprintf("get_dta() = %04X:%04X\r\n", _es, _bx);
  1054.         break;
  1055.     case 0x30:                /* get_version */
  1056.         tprintf("get_version() = %u.%u\r\n", _ax & 0xff, _ax >> 8);
  1057.         break;
  1058.     case 0x33:                /* cntrl_brk */
  1059.         switch (funl) {
  1060.         case 0:
  1061.             tprintf("get_break() = %s\r\n", makeonoff(_dx & 0xff));
  1062.             break;
  1063.         case 1:
  1064.             break;
  1065.         case 2:
  1066.             tprintf("%s\r\n", makeonoff(_dx & 0xff));
  1067.             break;
  1068.         }
  1069.         break;
  1070.     case 0x34:                /* critical_flag */
  1071.         tprintf("critical_flag() = %04X:%04X\r\n", _es, _bx);
  1072.         break;
  1073.     case 0x35:                /* get_vector */
  1074.         tprintf("%04X:%04X\r\n", _es, _bx);
  1075.         break;
  1076.     case 0x39:                /* Mkdir */
  1077.     case 0x3a:                /* Rmdir */
  1078.     case 0x3b:                /* Chdir */
  1079.         okerrorproc(_flags, _ax);
  1080.         break;
  1081.     case 0x3c:                /* Creat */
  1082.     case 0x3d:                /* Open */
  1083.         nerrorproc(_flags, _ax);
  1084.         break;
  1085.     case 0x3e:                /* Close */
  1086.         okerrorproc(_flags, _ax);
  1087.         break;
  1088.     case 0x3f:                /* Read */
  1089.     case 0x40:                /* Write */
  1090.         if (_flags & 1)
  1091.             errprint(_ax);
  1092.         else
  1093.             tprintf("%u", _ax);
  1094.         if (stringprint)
  1095.             outbuff(_ds, _dx, _ax);
  1096.         tputs("\r\n");
  1097.         break;
  1098.     case 0x41:                /* Unlink */
  1099.         okerrorproc(_flags, _ax);
  1100.         break;
  1101.     case 0x42:                /* Lseek */
  1102.         if (_flags & 1)
  1103.             errprintln(_ax);
  1104.         else
  1105.             tprintf("%ld\r\n", makelong(_dx, _ax));
  1106.         break;
  1107.     case 0x43:                /* Chmod / getmod */
  1108.         if (_flags & 1)
  1109.             errprint(_ax);
  1110.         else {
  1111.             if ((_ax & 0xff) == 0)
  1112.                 tprintf("%u%s", _cx, strmode(_cx));
  1113.             else
  1114.                 tputs("ok");
  1115.         }
  1116.         tputs("\r\n");
  1117.         break;
  1118.     case 0x44:                /* ioctl */
  1119.         switch (funl) {
  1120.         case 0x00:            /* get device info */
  1121.             if (_flags & 1)
  1122.                 errprintln(_ax);
  1123.             else {
  1124.                 if (stringprint)
  1125.                     devinfo(_dx);
  1126.                 else
  1127.                     tprintf("%04X\r\n", _dx);
  1128.             }
  1129.             break;
  1130.         case 0x02:            /* read from chdev control */
  1131.             if (_flags & 1)
  1132.                 errprint(_ax);
  1133.             else
  1134.                 tprintf("%u", _ax);
  1135.             if (stringprint)
  1136.                 outbuff(_ds, _dx, _ax);
  1137.             tputs("\r\n");
  1138.             break;
  1139.         case 0x07:            /* get output status */
  1140.             if (_flags & 1)
  1141.                 errprint(_ax);
  1142.             else
  1143.                 tputs((_ax & 0xff) ? "NOT_READY" : "READY");
  1144.             tputs("\r\n");
  1145.             break;
  1146.         case 0x08:            /* check if removable */
  1147.             if (_flags & 1)
  1148.                 errprint(_ax);
  1149.             else
  1150.                 tputs(_ax ? "FIXED" : "REMOVABLE");
  1151.             tputs("\r\n");
  1152.             break;
  1153.         case 0x09:            /* check if remote */
  1154.             if (_flags & 1)
  1155.                 errprint(_ax);
  1156.             else {
  1157.                 tputs((_dx & 0x8000) ? "SUBST " : "NO_SUBST ");
  1158.                 tputs((_dx & 0x1000) ? "REMOTE " : "LOCAL ");
  1159.                 tputs((_dx & 0x0200) ? "NOIO" : "IO");
  1160.             }
  1161.             tputs("\r\n");
  1162.             break;
  1163.         case 0x0a:            /* check if remote */
  1164.             if (_flags & 1)
  1165.                 errprint(_ax);
  1166.             else
  1167.                 tputs((_dx & 0x8000) ? "REMOTE" : "LOCAL");
  1168.             tputs("\r\n");
  1169.             break;
  1170.         case 0x0e:            /* get logical map */
  1171.             if (_flags & 1)
  1172.                 errprint(_ax);
  1173.             else
  1174.                 tprintf("%d", _ax & 0xff);
  1175.             tputs("\r\n");
  1176.             break;
  1177.         case 0x0f:            /* set logical map */
  1178.             okerrorproc(_flags, _ax);
  1179.             break;
  1180.         }
  1181.         break;
  1182.     case 0x45:                /* Dup */
  1183.         nerrorproc(_flags, _ax);
  1184.         break;
  1185.     case 0x46:                /* Dup2 */
  1186.         okerrorproc(_flags, _ax);
  1187.         break;
  1188.     case 0x47:                /* Getcwd */
  1189.         if (_flags & 1)
  1190.             errprintln(_ax);
  1191.         else {
  1192.             if (stringprint)
  1193.                 tprintf("ok\t\"%Fs\"\r\n", makefptr(_ds, _si));
  1194.             else
  1195.                 tputs("ok\r\n");
  1196.         }
  1197.         break;
  1198.     case 0x48:                /* Alloc */
  1199.         if (_flags & 1) {
  1200.             errprint(_ax);
  1201.             tprintf("\t(free = %#x0 bytes)\r\n", _bx);
  1202.         } else
  1203.             tprintf("%04X:0000\r\n", _ax);
  1204.         break;
  1205.     case 0x49:                /* Free */
  1206.         okerrorproc(_flags, _ax);
  1207.         break;
  1208.     case 0x4a:                /* Realloc */
  1209.         if (_flags & 1) {
  1210.             errprint(_ax);
  1211.             tprintf("\t(free = %#x0 bytes)\r\n", _bx);
  1212.         } else
  1213.             tputs("ok\r\n");
  1214.         break;
  1215.     case 0x4b:                /* Exec */
  1216.         okerrorproc(_flags, _ax);
  1217.         break;
  1218.     case 0x4c:                /* Exit */
  1219.         /* NOTREACHED */
  1220.         break;
  1221.     case 0x4d:                /* Get return code */
  1222.         tprintf("get_code() = %d %d\r\n", _ax >> 8, _ax & 0xff);
  1223.         break;
  1224.     case 0x4e:                /* Findfirst */
  1225.         if (_flags & 1)
  1226.             errprintln(_ax);
  1227.         else {
  1228.             if (stringprint)
  1229.                 outdta();
  1230.             else
  1231.                 tputs("ok\r\n");
  1232.         }
  1233.         break;
  1234.     case 0x4f:                /* Findnext */
  1235.         if (_flags & 1)
  1236.             errprintln(_ax);
  1237.         else {
  1238.             if (stringprint)
  1239.                 outdta();
  1240.             else
  1241.                 tputs("ok\r\n");
  1242.         }
  1243.         break;
  1244.     case 0x50:                /* set_psp */
  1245.         tracedpsp = _bx;
  1246.         break;
  1247.     case 0x52:                /* sysvars */
  1248.         tprintf("%04X:%04X\r\n", _es, _bx);
  1249.         break;
  1250.     case 0x51:                /* get_psp */
  1251.     case 0x62:                /* get_psp */
  1252.         tprintf("get_psp() = %04X\r\n", _bx);
  1253.         break;
  1254.     case 0x55:                /* Create child PSP */
  1255.         if (_flags & 1)
  1256.             errprintln(_ax);
  1257.         else {
  1258.             tputs("ok\r\n");
  1259.             tracedpsp = _dx;
  1260.         }
  1261.         break;
  1262.     case 0x57:                /* get/set date time */
  1263.         switch (funl = (_ax & 0xff)) {
  1264.         case 0:                /* get time */
  1265.             if (_flags & 1)
  1266.                 errprint(_ax);
  1267.             else
  1268.                 print_dtim(_dx, _cx);
  1269.             tputs("\r\n");
  1270.             break;
  1271.         case 1:                /* set time */
  1272.             okerrorproc(_flags, _ax);
  1273.             break;
  1274.         }
  1275.         break;
  1276.     case 0x58:                /* memory allocation */
  1277.         switch (funl) {
  1278.         case 0:                /* get strategy */
  1279.             if (_flags & 1)
  1280.                 errprint(_ax);
  1281.             else
  1282.                 print_memory_strategy(_ax);
  1283.             tputs("\r\n");
  1284.             break;
  1285.         case 1:                /* set strategy */
  1286.             okerrorproc(_flags, _ax);
  1287.             break;
  1288.         case 2:                /* get umb state */
  1289.             nerrorproc(_flags, _ax & 0xff);
  1290.             break;
  1291.         case 3:                /* set umb state */
  1292.             okerrorproc(_flags, _ax);
  1293.             break;
  1294.         }
  1295.         break;
  1296.     case 0x5a:                /* Tmpfile */
  1297.         nerrorproc(_flags, _ax);
  1298.         break;
  1299.     case 0x5b:                /* Creat new */
  1300.         nerrorproc(_flags, _ax);
  1301.         break;
  1302.     case 0x6c:                /* Open 4 */
  1303.         if (_flags & 1)
  1304.             errprint(_ax);
  1305.         else {
  1306.             tprintf("%u ", _ax);
  1307.             if (stringprint)
  1308.                 switch (_cx) {
  1309.                 case 0: tputs("(OPEN)"); break;
  1310.                 case 1: tputs("(CREAT)"); break;
  1311.                 case 2: tputs("(TRUNC)"); break;
  1312.                 }
  1313.         }
  1314.         tputs("\r\n");
  1315.     }
  1316.     setpsp(tracedpsp);
  1317.     trace = 1;
  1318. }
  1319.  
  1320. /*
  1321.  * Restore the prevuious handler.
  1322.  * Called by signal handlers.
  1323.  */
  1324. void
  1325. restore_handler(int sig)
  1326. {
  1327.     /* Restore old handler */
  1328.     _dos_setvect(DOS_INT, old_dos_handler);
  1329. }
  1330.  
  1331. int getopt(int, char **, char *);
  1332.  
  1333. /*
  1334.  * Main program starts here.
  1335.  */
  1336. int
  1337. main(int argc, char *argv[])
  1338. {
  1339.     int status = 0;
  1340.     extern int optind;
  1341.     extern char *optarg;
  1342.     int errflag = 0;
  1343.     char *usagestring = "usage: %s [-o fname] [-l len] [-help] [-abcfinrstvwxy] [-p psp] [command options ...]\n";
  1344.     int c;
  1345.     static char revstring[] = "$Revision: 1.28 $", revision[30];
  1346.     char *p;
  1347.  
  1348.     strcpy(revision, strchr(revstring, ':') + 2);
  1349.     *strchr(revision, '$') = '\0';
  1350.     strlwr(argv[0]);
  1351.     if (p = strrchr(argv[0], '\\'))
  1352.         argv[0] = p + 1;
  1353.     if (p = strrchr(argv[0], '/'))
  1354.         argv[0] = p + 1;
  1355.     if (p = strrchr(argv[0], '.'))
  1356.         *p = '\0';
  1357.     if (!*argv[0])
  1358.         argv[0] = "trace";
  1359.     while ((c = getopt(argc, argv, "abfo:h:sxl:nitrevcp:wy")) != EOF)
  1360.         switch (c) {
  1361.         case 'i':            /* Print PSP */
  1362.             pspprint = 1;
  1363.             break;
  1364.         case 'p':            /* Trace with given PSP */
  1365.             if (optarg) {
  1366.                 tsrpsp = atoi(optarg);
  1367.                 tracetsr = 1;
  1368.             } else {
  1369.                 fprintf(stderr, "%s: -p needs a PSP parameter\n", argv[0]);
  1370.                 errflag = 1;
  1371.             }
  1372.             break;
  1373.         case 'e':            /* Trace children */
  1374.             tracechildren = 1;
  1375.             break;
  1376.         case 'v':            /* Verbose */
  1377.             branchprint = pspprint = worderror = numprint = timeprint = tracechildren = regdump = stringprint = hexprint = otherprint = nameprint = 1;
  1378.             break;
  1379.         case 'f':            /* Print function number */
  1380.             numprint = 1;
  1381.             break;
  1382.         case 'b':            /* Print interrupt branch address */
  1383.             branchprint = 1;
  1384.             break;
  1385.         case 't':            /* Print time of each call */
  1386.             timeprint = 1;
  1387.             break;
  1388.         case 'r':            /* Dump registers */
  1389.             regdump = 1;
  1390.             break;
  1391.         case 'o':            /* Output file */
  1392.             if (optarg)
  1393.                 fname = optarg ;
  1394.             else {
  1395.                 fprintf(stderr, "%s: -o needs a file parameter\n", argv[0]);
  1396.                 errflag = 1;
  1397.             }
  1398.             break ;
  1399.         case 'w':            /* Print errors as words */
  1400.             worderror = 1;
  1401.             break;
  1402.         case 'c':            /* Produce summary count */
  1403.             count = 1;
  1404.             break;
  1405.         case 's':            /* Print strings in I/O */
  1406.             stringprint = 1;
  1407.             break;
  1408.         case 'y':            /* Close file after every write */
  1409.             append = 1;
  1410.             break;
  1411.         case 'x':            /* Print binary data in I/O */
  1412.             hexprint = 1;
  1413.             break;
  1414.         case 'a':            /* Print all DOS functions */
  1415.             otherprint = 1;
  1416.             break;
  1417.         case 'n':            /* Print names of other DOS functions */
  1418.             nameprint = 1;
  1419.             break;
  1420.         case 'l':            /* Specify length */
  1421.             if (optarg) {
  1422.                 datalen = atoi(optarg);
  1423.                 if (datalen >= MAXBUFF) {
  1424.                     fprintf(stderr, "%s: Data length %u is greater than maximum length %u.  %u used.\n", argv[0], datalen, MAXBUFF - 1, MAXBUFF - 1);
  1425.                     datalen = MAXBUFF - 1;
  1426.                 }
  1427.             } else {
  1428.                 fprintf(stderr, "%s: -l needs a length parameter\n", argv[0]);
  1429.                 errflag = 1;
  1430.             }
  1431.             break;
  1432.         case 'h':            /* Help */
  1433.             fprintf(stdout, "Trace Version %s (C) Copyright 1991-1994 D. Spinellis.  All rights reserved.\n", revision);
  1434.             fprintf(stdout, usagestring, argv[0]);
  1435.             fputs("-a\tTrace all DOS functions\n", stdout);
  1436.             fputs("-b\tPrint interrupt branch address\n", stdout);
  1437.             fputs("-c\tProduce a count summary only\n", stdout);
  1438.             fputs("-e\tTrace across exec calls\n", stdout);
  1439.             fputs("-f\tPrefix calls with function number\n", stdout);
  1440.             fputs("-h\tPrint this list\n", stdout);
  1441.             fputs("-i\tPrefix calls with process id (psp address)\n", stdout);
  1442.             fputs("-l L\tSpecify I/O printed data length\n", stdout);
  1443.             fputs("-n\tPrint other functions by name\n", stdout);
  1444.             fputs("-o F\tSpecify output file name\n", stdout);
  1445.             fputs("-p P\tTrace resident process with PSP P\n", stdout);
  1446.             fputs("-r\tDump registers on other functions\n", stdout);
  1447.             fputs("-s\tPrint I/O strings\n", stdout);
  1448.             fputs("-t\tPrefix calls with time\n", stdout);
  1449.             fputs("-v\tVerbose (-abefinrstwx)\n", stdout);
  1450.             fputs("-w\tPrint errors as words\n", stdout);
  1451.             fputs("-x\tPrint I/O binary data (needs -s)\n", stdout);
  1452.             fputs("-y\tClose file after everY write\n", stdout);
  1453.             return 0;
  1454.         case '?':            /* Error */
  1455.             errflag = 1;
  1456.             break ;
  1457.         }
  1458.     if (errflag) {
  1459.         fprintf(stderr, usagestring, argv[0]);
  1460.         return 2;
  1461.     }
  1462.     if ((fd = open(fname, O_CREAT | O_TRUNC | O_TEXT | O_WRONLY, 0666)) == -1) {
  1463.         perror(fname);
  1464.         return 1;
  1465.     }
  1466.     someprefix = pspprint | timeprint | numprint | branchprint;
  1467.     mypsp = getpsp();
  1468.     critsectflag = getcritsectflag();
  1469.     if (_osmajor == 2)
  1470.         criterrflag = critsectflag + 1;
  1471.     else
  1472.         criterrflag = critsectflag - 1;
  1473.     /* Save old handler and install new one */
  1474.     old_dos_handler = _dos_getvect(DOS_INT);
  1475.     (void)signal(SIGABRT, restore_handler);
  1476.     (void)signal(SIGINT, restore_handler);
  1477.     (void)signal(SIGTERM, restore_handler);
  1478.     _dos_setvect(DOS_INT, dos_handler);
  1479.     if (tracetsr) {
  1480.         printf("Tracing process with psp %d (0x%04x)\n", tsrpsp, tsrpsp);
  1481.         puts("Press any key to exit.");
  1482.         execed = 1;
  1483.         (void)_bios_keybrd(_KEYBRD_READ);
  1484.     } else if (optind != argc) {
  1485.         status=spawnvp(P_WAIT, argv[optind], argv + optind);
  1486.     } else {
  1487.         puts("Tracing system activity.\nPress any key to exit.");
  1488.         execed = 1;
  1489.         (void)_bios_keybrd(_KEYBRD_READ);
  1490.     }
  1491.     execed = 0;
  1492.     restore_handler(SIGTERM);
  1493.     if (count)
  1494.         for (c = 0; c < 256; c++)
  1495.             if (funcs[c].count)
  1496.                 tprintf("%02X %20s %10u\r\n", c, funcs[c].name ? funcs[c].name : "???", funcs[c].count);
  1497.  
  1498.     close(fd);
  1499.     if (status == -1) {
  1500.         perror(argv[optind]);
  1501.         return 1;
  1502.     } else
  1503.         return 0;
  1504. }
  1505.