home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / ixemul-45.0-src.tgz / tar.out / contrib / ixemul / utils / ixtrace.c < prev    next >
C/C++ Source or Header  |  1996-10-01  |  13KB  |  583 lines

  1. /*
  2.  *  This file is part of ixemul.library for the Amiga.
  3.  *  Copyright (C) 1991, 1992  Markus M. Wild
  4.  *  Changed to avoid buffer overflows by J. Hoehle and
  5.  *  restricted output length for: str(n)cat, strlen
  6.  *
  7.  *  This library is free software; you can redistribute it and/or
  8.  *  modify it under the terms of the GNU Library General Public
  9.  *  License as published by the Free Software Foundation; either
  10.  *  version 2 of the License, or (at your option) any later version.
  11.  *
  12.  *  This library is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  *  Library General Public License for more details.
  16.  *
  17.  *  You should have received a copy of the GNU Library General Public
  18.  *  License along with this library; if not, write to the Free
  19.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  */
  21.  
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <proto/alib.h>
  25. #include <unistd.h>
  26. #include <string.h>
  27. #include <sys/tracecntl.h>
  28. #include <signal.h>
  29. #include <fcntl.h>
  30. #include <sys/ioctl.h>
  31. #include <sys/ioctl_compat.h>
  32. #include <sys/termios.h>
  33. #include <exec/types.h>
  34. #include <libraries/dos.h>
  35. #include <proto/exec.h>
  36. #include "ixtrace.h"
  37.  
  38. #define OUT_WIDTH  80    /* big enough (>30) to hold first information */
  39.  
  40. static void print_call (FILE *output, struct trace_packet *tp);
  41.  
  42. int print_all = 0;
  43. int skip_sigsetmask = 0;
  44. int skip_calls = 0;
  45. FILE *output;
  46. char VERSION[] = "$VER: ixtrace 1.41 (23-Sep-96)";
  47.  
  48. void
  49. dummy_handler ()
  50. {
  51. }
  52.  
  53. int
  54. main (int argc, char *argv[])
  55. {
  56.   char *logfile = "-";
  57.   struct trace_packet tp;
  58.   struct trace_packet *tpz;
  59.   int *tpz_;
  60.   struct MsgPort *mp;
  61.   int c, in = 0;
  62.  
  63.   memset ((char *) &tp, '\000', sizeof (tp));
  64.   signal (SIGMSG, dummy_handler);
  65.  
  66.   while ((c = getopt (argc, argv, "ailwvmzo:c:p:s:n:")) != EOF)
  67.     switch (c)
  68.       {
  69.       case 'a':
  70.     print_all = 1;
  71.     break;
  72.  
  73.       case 'i':
  74.     in = 1;
  75.     break;
  76.  
  77.       case 'l':                    /* list system calls */
  78.     {
  79.         int i;
  80.  
  81.         for(i=1;i<=MAXCALLS;i=i+2)
  82.         {
  83.         fprintf(stdout,"(%3d) %-25s\t(%3d) %-25s\n",i,call_table[i].name,
  84.                                                   i+1,call_table[i+1].name);
  85.         }
  86.     return 0;
  87.     }
  88.     break;
  89.  
  90.       case 'c':                    /* system call by name */
  91.     {
  92.         int i;
  93.         int notfound=1;    /* Just to make sure that we know if call is found */
  94.         char *callname;
  95.  
  96.         callname=optarg;
  97.  
  98.         for(i=1;i<=MAXCALLS;i++)
  99.         {
  100.             if (!strcmp(callname, call_table[i].name))
  101.                 {    tp.tp_syscall = i;
  102.                     notfound=0;
  103.                     break;
  104.                 }        
  105.         }
  106.         if (notfound)
  107.         {
  108.              fprintf(stderr,"system call [%s] is unknown to ixtrace\n",callname);
  109.              return 1;
  110.         }
  111.     }
  112.     break;
  113.  
  114.       case 'm':
  115.     skip_sigsetmask = 1;
  116.     break;
  117.  
  118.       case 'o':
  119.     logfile = optarg;
  120.     break;
  121.  
  122.       case 'p':
  123.     tp.tp_pid = atoi (optarg);
  124.     break;
  125.     
  126.       case 'n':
  127.     skip_calls = atoi (optarg);
  128.     if (skip_calls < 0)
  129.     {
  130.       fprintf(stderr, "invalid argument for option -n\n");
  131.       exit(1);
  132.     }
  133.     break;
  134.     
  135.       case 's':
  136.     if (!isdigit(optarg[0]))
  137.     {
  138.       fprintf(stderr, "The -s option requires a number\n",MAXCALLS);
  139.       exit(1);
  140.     }
  141.         tp.tp_syscall = atoi (optarg);
  142.     if (tp.tp_syscall > MAXCALLS)
  143.     {
  144.       fprintf(stderr, "System call number is out of range 1-%d\n",MAXCALLS);
  145.       exit(1);
  146.     }
  147.         break;
  148.  
  149.       case 'w':                    /* Wipe out the calls you don't want */
  150.     {
  151.         int i;
  152.         char calls[80]="";
  153.         int notfound=1;
  154.  
  155.         fprintf(stdout,"When done enter \"x\" by itself, followed by a [RETURN]\n");
  156.     do {
  157.         fprintf(stdout,"trace > ");
  158.         gets(calls);
  159.         if (!strcmp("x",calls)) break;
  160.             for(i=1;i<=MAXCALLS;i++)
  161.             {
  162.                 if (!strcmp(calls, call_table[i].name))
  163.                     {    call_table[i].interesting=0;
  164.                         notfound=0;
  165.                         break;
  166.                     }        
  167.             }
  168.             if (notfound) fprintf(stderr,"[%s] is unknown to ixtrace, try again\n"
  169.                                         , calls);
  170.         notfound=1;
  171.         } while(strcmp("x",calls)); /* A lil' over-kill */
  172.  
  173.     }
  174.     break;
  175.       case 'z':                    /* you name the calls --in testing-- */
  176.     {
  177.         int i;
  178.         char calls[80]="";
  179.         int notfound=1;
  180.  
  181.         /* Right now this is only the beginning, clear all systems calls.
  182.            In other words, make them all non-interesting.                    */
  183.         for(i=1;i<=MAXCALLS;i++)
  184.         {
  185.           call_table[i].interesting=0;
  186.         }
  187.         fprintf(stdout,"When done enter \"x\" by itself, followed by a [RETURN]\n");
  188.     do {
  189.         fprintf(stdout,"trace > ");
  190.         gets(calls);
  191.         if (!strcmp("x",calls)) break;
  192.             for(i=1;i<=MAXCALLS;i++)
  193.             {
  194.                 if (!strcmp(calls, call_table[i].name))
  195.                     {    call_table[i].interesting=1;
  196.                         notfound=0;
  197.                         break;
  198.                     }        
  199.             }
  200.             if (notfound) fprintf(stderr,"[%s] is unknown to ixtrace, try again\n"
  201.                                         , calls);
  202.         notfound=1;
  203.         } while(strcmp("x",calls)); /* A lil' over-kill */
  204.  
  205.     }
  206.     break;
  207.       case 'v':
  208.     {
  209.       fprintf(stdout, "%s\n",VERSION+6); /* get rid of the first 7 chars */
  210.       return 0;
  211.     }
  212.         break;
  213.  
  214.       default:
  215.     fprintf (stderr, "%s [-a] [-m] [-l] [-v] [-z] [-c syscall-name] [-n N] [-o logfile] [-p pid] [-s syscall-number]\n", argv[0]);
  216.     fprintf (stderr, "  -a  trace all calls (else __-calls are skipped)\n");
  217.     fprintf (stderr, "  -m  skip sigsetmask() calls (they're heavily used inside the library)\n");
  218.     fprintf (stderr, "  -i  trace entry to functions. Default is exit.\n");
  219.     fprintf (stderr, "  -l  list system calls (syscall #) [syscall name]\n");
  220.     fprintf (stderr, "  -v  version\n");
  221.     fprintf (stderr, "  -w  wipe out syscalls by name\n");
  222.     fprintf (stderr, "  -z  only trace the syscalls you want to trace\n");
  223.     fprintf (stderr, "  -c  only trace this syscall (by name)\n");
  224.     fprintf (stderr, "  -n  skip the first N traces\n");
  225.     fprintf (stderr, "  -o  log output to logfile (default is stdout)\n");
  226.     fprintf (stderr, "  -p  only trace process pid (default is to trace all processes)\n");
  227.     fprintf (stderr, "  -s  only trace this syscall (default is to trace all calls)\n");
  228.  
  229.         return 1;
  230.       }
  231.  
  232.   if (logfile[0] == '-' && !logfile[1])
  233.     output = stdout;
  234.   else
  235.     output = fopen (logfile, "w");
  236.  
  237.   if (!output)
  238.     {
  239.       perror ("fopen");
  240.       return 1;
  241.     }
  242.  
  243.   if ((mp = CreatePort (0, 0)))
  244.     {
  245.       tp.tp_tracer_port = mp;
  246.       if (tracecntl (TRACE_INSTALL_HANDLER, &tp) == 0)
  247.     {
  248.       while (1)
  249.         {
  250.           struct Message *msg;
  251.           long sigs;
  252.  
  253.           sigs = Wait ((1 << mp->mp_SigBit) | SIGBREAKF_CTRL_C);
  254.           while ((msg = GetMsg (mp)))
  255.         {
  256.               if (msg != (struct Message *) &tp)
  257.             {
  258.               fprintf (stderr, "Got alien message! Don't do that ever again ;-)\n");
  259.             } 
  260.               else
  261.             {
  262.               if (in)
  263.             tp.tp_action = TRACE_ACTION_JMP;
  264.               if (! tp.tp_is_entry || tp.tp_action == TRACE_ACTION_JMP)
  265.                 print_call (output, &tp);
  266.             }
  267.               Signal ((struct Task *) msg->mn_ReplyPort, SIGBREAKF_CTRL_E);
  268.             }
  269.           if (sigs & SIGBREAKF_CTRL_C)
  270.         break;
  271.         }
  272.       tracecntl (TRACE_REMOVE_HANDLER, &tp);
  273.     }
  274.       else
  275.     perror ("tracecntl");
  276.       
  277.       DeletePort (mp);
  278.     }
  279.   else
  280.     perror ("CreatePort");
  281. }
  282.  
  283.  
  284. /* should help make things less mystic... */
  285. #define TP_SCALL(tp) (tp->tp_argv[0])
  286. /* this is only valid if !tp->tp_is_entry */
  287. #define TP_RESULT(tp) (tp->tp_argv[1])
  288. #define TP_ERROR(tp) (* tp->tp_errno)
  289. /* tp_argv[2] is the return address */
  290. #define TP_FIRSTARG(tp) (tp->tp_argv[3])
  291.  
  292. void
  293. print_call (FILE *output, struct trace_packet *tp)
  294. {
  295.   char line[OUT_WIDTH+2];    /* for \n\0 */
  296.   char *argfield;
  297.   int space, len;
  298.   struct call *c;
  299.  
  300.   space = sizeof (line) - 1;
  301.   len = sprintf (line, "$%lx: %c", (unsigned long) tp->tp_message.mn_ReplyPort,
  302.                tp->tp_is_entry ? '>' : '<');
  303.   argfield = line + len;
  304.   space -= len;
  305.  
  306.   if (TP_SCALL (tp) > sizeof (call_table) / sizeof (struct call))
  307.     {
  308.       if (tp->tp_is_entry)
  309.         sprintf (argfield, "SYS_%d()\n", TP_SCALL (tp));
  310.       else
  311.         sprintf (argfield, "SYS_%d() = $%lx (%d)\n", 
  312.           TP_SCALL (tp), (unsigned long) TP_RESULT (tp), TP_ERROR (tp));
  313.     }
  314.   else
  315.     {
  316.       c = call_table + TP_SCALL (tp);
  317.  
  318.       if ((!print_all && !c->interesting) || 
  319.       (skip_sigsetmask && TP_SCALL (tp) == SYS_sigsetmask))
  320.     return;
  321.  
  322.       /* we can write space-1 real characters in the buffer, \n is not counted */
  323.       c->func (argfield, space-1, c, tp);
  324.     }
  325.  
  326.   if (skip_calls == 0)
  327.     fputs (line, output);
  328.   else
  329.     skip_calls--;
  330. }
  331.  
  332. /* the program contained a bug due to the fact that
  333.  * when snprintf or vsnprintf are called with a zero or negative size,
  334.  * they return -1 as an error marker but not any length.
  335.  */
  336.  
  337. static void
  338. vp (char *buf, int len, struct call *c, struct trace_packet *tp)
  339. {
  340.   int nl = snprintf (buf, len+1, "%s", c->name);
  341.  
  342.   len -= nl; if (len <= 0) goto finish;
  343.   buf += nl;
  344.   if (tp->tp_is_entry || !c->rfmt[0])
  345.     vsnprintf (buf, len+1, c->fmt, (_BSD_VA_LIST_) & TP_FIRSTARG (tp));
  346.   else
  347.     {
  348.       nl = vsnprintf (buf, len+1, c->fmt, (_BSD_VA_LIST_) & TP_FIRSTARG (tp));
  349.       len -= nl; if (len <= 0) goto finish;
  350.       buf += nl;
  351.       nl = snprintf (buf, len+1, "=");
  352.       len -= nl; if (len <= 0) goto finish;
  353.       buf += nl;
  354.       nl = vsnprintf (buf, len+1, c->rfmt, (_BSD_VA_LIST_) & TP_RESULT (tp));
  355.       len -= nl; if (len <= 0) goto finish;
  356.       buf += nl;
  357.       nl = snprintf (buf, len+1, " (%d)", TP_ERROR (tp));
  358.     }
  359.  
  360.   finish:
  361.   strcat (buf, "\n");
  362. }
  363.  
  364. const char *
  365. get_fcntl_cmd (int cmd)
  366. {
  367.   switch (cmd)
  368.     {
  369.     case F_DUPFD:
  370.     return "F_DUPFD";
  371.  
  372.     case F_GETFD:
  373.     return "F_GETFD";
  374.  
  375.     case F_SETFD:
  376.     return "F_SETFD";
  377.  
  378.     case F_GETFL:
  379.     return "F_GETFL";
  380.  
  381.     case F_SETFL:
  382.     return "F_SETFL";
  383.     
  384.     case F_GETOWN:
  385.     return "F_GETOWN";
  386.  
  387.     case F_SETOWN:
  388.     return "F_SETOWN";
  389.  
  390. #ifdef F_GETLK
  391.     case F_GETLK:
  392.     return "F_GETLK";
  393. #endif
  394.  
  395. #ifdef F_SETLK
  396.     case F_SETLK:
  397.     return "F_SETLK";
  398. #endif
  399.  
  400. #ifdef F_SETLKW
  401.     case F_SETLKW:
  402.     return "F_SETLKW";
  403. #endif
  404.  
  405.     default:
  406.     return "F_unknown";
  407.     }
  408. }
  409.  
  410. char *
  411. get_open_mode (int mode)
  412. {
  413.   static char buf[120];
  414.   
  415.   switch (mode & O_ACCMODE)
  416.     {
  417.     case O_RDONLY: 
  418.       strcpy (buf, "O_RDONLY");
  419.       break;
  420.       
  421.     case O_WRONLY:
  422.       strcpy (buf, "O_WRONLY");
  423.       break;
  424.       
  425.     case O_RDWR:
  426.       strcpy (buf, "O_RDWR");
  427.       break;
  428.       
  429.     default:
  430.       strcpy (buf, "O_illegal");
  431.       break;
  432.     }
  433.  
  434. #define ADD(flag) \
  435.   if (mode & flag) strcat (buf, "|" #flag);
  436.  
  437.   ADD (O_NONBLOCK);  
  438.   ADD (O_APPEND);
  439.   ADD (O_SHLOCK);
  440.   ADD (O_EXLOCK);
  441.   ADD (O_ASYNC);
  442.   ADD (O_FSYNC);
  443.   ADD (O_CREAT);
  444.   ADD (O_TRUNC);
  445.   ADD (O_EXCL);
  446. #undef ADD
  447.   
  448.   return buf;
  449. }
  450.  
  451. char *
  452. get_ioctl_cmd (int cmd)
  453. {
  454.   static char buf[12];
  455.  
  456.   /* only deal with those commands that are really implemented somehow in
  457.      ixemul.library. The others are dummies anyway, so they don't matter */
  458.  
  459.   switch (cmd)
  460.     {
  461.     case FIONREAD:
  462.       return "FIONREAD";
  463.  
  464.     case FIONBIO:
  465.       return "FIONBIO";
  466.  
  467.     case FIOASYNC:
  468.       /* not yet implemented, but important to know if some program tries
  469.          to use it ! */
  470.       return "FIOASYNC";
  471.  
  472.     case TIOCGETA:
  473.       return "TIOCGETA";
  474.  
  475.     case TIOCSETA:
  476.       return "TIOCSETA";
  477.  
  478.     case TIOCSETAW:
  479.       return "TIOCSETAW";
  480.  
  481.     case TIOCSETAF:
  482.       return "TIOCSETAF";
  483.  
  484.     case TIOCGETP:
  485.       return "TIOCGETP";
  486.  
  487.     case TIOCSETN:
  488.       return "TIOCSETN";
  489.  
  490.     case TIOCSETP:
  491.       return "TIOCSETP";
  492.  
  493.     case TIOCGWINSZ:
  494.       return "TIOCGWINSZ";
  495.  
  496.     case TIOCOUTQ:
  497.       return "TIOCOUTQ";
  498.  
  499.     case TIOCSWINSZ:
  500.       return "TIOCSWINSZ";
  501.       
  502.     default:
  503.       sprintf (buf, "$%lx", (unsigned long) cmd);
  504.       return buf;
  505.     }
  506. }
  507.  
  508.  
  509. static void
  510. vp_fcntl (char *buf, int len, struct call *c, struct trace_packet *tp)
  511. {
  512.   int *argv =  & TP_FIRSTARG (tp);
  513.   
  514.   if (tp->tp_is_entry)
  515.     if (argv[1] == F_GETFL || argv[1] == F_SETFL)
  516.       snprintf (buf, len+1, "fcntl(%d, %s, %s)",
  517.             argv[0], get_fcntl_cmd (argv[1]), get_open_mode (argv[2]));
  518.     else
  519.       snprintf (buf, len+1, "fcntl(%d, %s, %d)",
  520.             argv[0], get_fcntl_cmd (argv[1]), argv[2]);
  521.   else
  522.     if (argv[1] == F_GETFL || argv[1] == F_SETFL)
  523.       snprintf (buf, len+1, "fcntl(%d, %s, %s) = %d (%d)",
  524.             argv[0], get_fcntl_cmd (argv[1]), 
  525.         get_open_mode (argv[2]), TP_RESULT (tp), TP_ERROR (tp));
  526.     else
  527.       snprintf (buf, len+1, "fcntl(%d, %s, %d) = %d (%d)",
  528.             argv[0], get_fcntl_cmd (argv[1]), argv[2], 
  529.         TP_RESULT (tp), TP_ERROR (tp));
  530.  
  531.   strcat (buf, "\n");
  532. }
  533.  
  534.  
  535. static void
  536. vp_ioctl (char *buf, int len, struct call *c, struct trace_packet *tp)
  537. {
  538.   int *argv = & TP_FIRSTARG (tp);
  539.   
  540.   if (tp->tp_is_entry)
  541.     snprintf (buf, len+1, "ioctl(%d, %s, $%lx)",
  542.           argv[0], get_ioctl_cmd (argv[1]), argv[2]);
  543.   else
  544.     snprintf (buf, len+1, "ioctl(%d, %s, $%lx) = %d (%d)",
  545.           argv[0], get_ioctl_cmd (argv[1]), argv[2],
  546.           TP_RESULT (tp), TP_ERROR (tp));
  547.  
  548.   strcat (buf, "\n");
  549. }
  550.  
  551.  
  552. static void
  553. vp_open (char *buf, int len, struct call *c, struct trace_packet *tp)
  554. {
  555.   int *argv = & TP_FIRSTARG (tp);
  556.  
  557.   if (tp->tp_is_entry)
  558.     snprintf (buf, len+1, "open(\"%s\", %s)", argv[0], get_open_mode (argv[1]));
  559.   else
  560.     snprintf (buf, len+1, "open(\"%s\", %s) = %d (%d)", argv[0], 
  561.           get_open_mode (argv[1]), TP_RESULT (tp), TP_ERROR (tp));
  562.  
  563.   strcat (buf, "\n");
  564. }
  565.  
  566. static void
  567. vp_pipe (char *buf, int len, struct call *c, struct trace_packet *tp)
  568. {
  569.   int *argv = & TP_FIRSTARG (tp);
  570.  
  571.   if (tp->tp_is_entry)
  572.     snprintf (buf, len+1, "pipe($%lx)", argv[0]);
  573.   else
  574.     {
  575.       int *pv = (int *) argv[0];
  576.     
  577.       snprintf (buf, len+1, "pipe([%d, %d]) = %d (%d)", 
  578.         pv[0], pv[1], TP_RESULT (tp), TP_ERROR (tp));
  579.     }
  580.  
  581.   strcat (buf, "\n");
  582. }
  583.