home *** CD-ROM | disk | FTP | other *** search
/ Aminet 18 / aminetcdnumber181997.iso / Aminet / dev / gcc / ixemulsrc.lha / ixemul / utils / ixtrace.c < prev    next >
C/C++ Source or Header  |  1996-12-15  |  13KB  |  584 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.451 (06-Dec-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. /* tp_argv[3-6] are d0/d1/a0/a1 */
  291. #define TP_FIRSTARG(tp) (tp->tp_argv[7])
  292.  
  293. void
  294. print_call (FILE *output, struct trace_packet *tp)
  295. {
  296.   char line[OUT_WIDTH+2];    /* for \n\0 */
  297.   char *argfield;
  298.   int space, len;
  299.   struct call *c;
  300.  
  301.   space = sizeof (line) - 1;
  302.   len = sprintf (line, "$%lx: %c", (unsigned long) tp->tp_message.mn_ReplyPort,
  303.                tp->tp_is_entry ? '>' : '<');
  304.   argfield = line + len;
  305.   space -= len;
  306.  
  307.   if (TP_SCALL (tp) > sizeof (call_table) / sizeof (struct call))
  308.     {
  309.       if (tp->tp_is_entry)
  310.         sprintf (argfield, "SYS_%d()\n", TP_SCALL (tp));
  311.       else
  312.         sprintf (argfield, "SYS_%d() = $%lx (%d)\n", 
  313.           TP_SCALL (tp), (unsigned long) TP_RESULT (tp), TP_ERROR (tp));
  314.     }
  315.   else
  316.     {
  317.       c = call_table + TP_SCALL (tp);
  318.  
  319.       if ((!print_all && !c->interesting) || 
  320.       (skip_sigsetmask && TP_SCALL (tp) == SYS_sigsetmask))
  321.     return;
  322.  
  323.       /* we can write space-1 real characters in the buffer, \n is not counted */
  324.       c->func (argfield, space-1, c, tp);
  325.     }
  326.  
  327.   if (skip_calls == 0)
  328.     fputs (line, output);
  329.   else
  330.     skip_calls--;
  331. }
  332.  
  333. /* the program contained a bug due to the fact that
  334.  * when snprintf or vsnprintf are called with a zero or negative size,
  335.  * they return -1 as an error marker but not any length.
  336.  */
  337.  
  338. static void
  339. vp (char *buf, int len, struct call *c, struct trace_packet *tp)
  340. {
  341.   int nl = snprintf (buf, len+1, "%s", c->name);
  342.  
  343.   len -= nl; if (len <= 0) goto finish;
  344.   buf += nl;
  345.   if (tp->tp_is_entry || !c->rfmt[0])
  346.     vsnprintf (buf, len+1, c->fmt, (_BSD_VA_LIST_) & TP_FIRSTARG (tp));
  347.   else
  348.     {
  349.       nl = vsnprintf (buf, len+1, c->fmt, (_BSD_VA_LIST_) & TP_FIRSTARG (tp));
  350.       len -= nl; if (len <= 0) goto finish;
  351.       buf += nl;
  352.       nl = snprintf (buf, len+1, "=");
  353.       len -= nl; if (len <= 0) goto finish;
  354.       buf += nl;
  355.       nl = vsnprintf (buf, len+1, c->rfmt, (_BSD_VA_LIST_) & TP_RESULT (tp));
  356.       len -= nl; if (len <= 0) goto finish;
  357.       buf += nl;
  358.       nl = snprintf (buf, len+1, " (%d)", TP_ERROR (tp));
  359.     }
  360.  
  361.   finish:
  362.   strcat (buf, "\n");
  363. }
  364.  
  365. const char *
  366. get_fcntl_cmd (int cmd)
  367. {
  368.   switch (cmd)
  369.     {
  370.     case F_DUPFD:
  371.     return "F_DUPFD";
  372.  
  373.     case F_GETFD:
  374.     return "F_GETFD";
  375.  
  376.     case F_SETFD:
  377.     return "F_SETFD";
  378.  
  379.     case F_GETFL:
  380.     return "F_GETFL";
  381.  
  382.     case F_SETFL:
  383.     return "F_SETFL";
  384.     
  385.     case F_GETOWN:
  386.     return "F_GETOWN";
  387.  
  388.     case F_SETOWN:
  389.     return "F_SETOWN";
  390.  
  391. #ifdef F_GETLK
  392.     case F_GETLK:
  393.     return "F_GETLK";
  394. #endif
  395.  
  396. #ifdef F_SETLK
  397.     case F_SETLK:
  398.     return "F_SETLK";
  399. #endif
  400.  
  401. #ifdef F_SETLKW
  402.     case F_SETLKW:
  403.     return "F_SETLKW";
  404. #endif
  405.  
  406.     default:
  407.     return "F_unknown";
  408.     }
  409. }
  410.  
  411. char *
  412. get_open_mode (int mode)
  413. {
  414.   static char buf[120];
  415.   
  416.   switch (mode & O_ACCMODE)
  417.     {
  418.     case O_RDONLY: 
  419.       strcpy (buf, "O_RDONLY");
  420.       break;
  421.       
  422.     case O_WRONLY:
  423.       strcpy (buf, "O_WRONLY");
  424.       break;
  425.       
  426.     case O_RDWR:
  427.       strcpy (buf, "O_RDWR");
  428.       break;
  429.       
  430.     default:
  431.       strcpy (buf, "O_illegal");
  432.       break;
  433.     }
  434.  
  435. #define ADD(flag) \
  436.   if (mode & flag) strcat (buf, "|" #flag);
  437.  
  438.   ADD (O_NONBLOCK);  
  439.   ADD (O_APPEND);
  440.   ADD (O_SHLOCK);
  441.   ADD (O_EXLOCK);
  442.   ADD (O_ASYNC);
  443.   ADD (O_FSYNC);
  444.   ADD (O_CREAT);
  445.   ADD (O_TRUNC);
  446.   ADD (O_EXCL);
  447. #undef ADD
  448.   
  449.   return buf;
  450. }
  451.  
  452. char *
  453. get_ioctl_cmd (int cmd)
  454. {
  455.   static char buf[12];
  456.  
  457.   /* only deal with those commands that are really implemented somehow in
  458.      ixemul.library. The others are dummies anyway, so they don't matter */
  459.  
  460.   switch (cmd)
  461.     {
  462.     case FIONREAD:
  463.       return "FIONREAD";
  464.  
  465.     case FIONBIO:
  466.       return "FIONBIO";
  467.  
  468.     case FIOASYNC:
  469.       /* not yet implemented, but important to know if some program tries
  470.          to use it ! */
  471.       return "FIOASYNC";
  472.  
  473.     case TIOCGETA:
  474.       return "TIOCGETA";
  475.  
  476.     case TIOCSETA:
  477.       return "TIOCSETA";
  478.  
  479.     case TIOCSETAW:
  480.       return "TIOCSETAW";
  481.  
  482.     case TIOCSETAF:
  483.       return "TIOCSETAF";
  484.  
  485.     case TIOCGETP:
  486.       return "TIOCGETP";
  487.  
  488.     case TIOCSETN:
  489.       return "TIOCSETN";
  490.  
  491.     case TIOCSETP:
  492.       return "TIOCSETP";
  493.  
  494.     case TIOCGWINSZ:
  495.       return "TIOCGWINSZ";
  496.  
  497.     case TIOCOUTQ:
  498.       return "TIOCOUTQ";
  499.  
  500.     case TIOCSWINSZ:
  501.       return "TIOCSWINSZ";
  502.       
  503.     default:
  504.       sprintf (buf, "$%lx", (unsigned long) cmd);
  505.       return buf;
  506.     }
  507. }
  508.  
  509.  
  510. static void
  511. vp_fcntl (char *buf, int len, struct call *c, struct trace_packet *tp)
  512. {
  513.   int *argv =  & TP_FIRSTARG (tp);
  514.   
  515.   if (tp->tp_is_entry)
  516.     if (argv[1] == F_GETFL || argv[1] == F_SETFL)
  517.       snprintf (buf, len+1, "fcntl(%d, %s, %s)",
  518.             argv[0], get_fcntl_cmd (argv[1]), get_open_mode (argv[2]));
  519.     else
  520.       snprintf (buf, len+1, "fcntl(%d, %s, %d)",
  521.             argv[0], get_fcntl_cmd (argv[1]), argv[2]);
  522.   else
  523.     if (argv[1] == F_GETFL || argv[1] == F_SETFL)
  524.       snprintf (buf, len+1, "fcntl(%d, %s, %s) = %d (%d)",
  525.             argv[0], get_fcntl_cmd (argv[1]), 
  526.         get_open_mode (argv[2]), TP_RESULT (tp), TP_ERROR (tp));
  527.     else
  528.       snprintf (buf, len+1, "fcntl(%d, %s, %d) = %d (%d)",
  529.             argv[0], get_fcntl_cmd (argv[1]), argv[2], 
  530.         TP_RESULT (tp), TP_ERROR (tp));
  531.  
  532.   strcat (buf, "\n");
  533. }
  534.  
  535.  
  536. static void
  537. vp_ioctl (char *buf, int len, struct call *c, struct trace_packet *tp)
  538. {
  539.   int *argv = & TP_FIRSTARG (tp);
  540.   
  541.   if (tp->tp_is_entry)
  542.     snprintf (buf, len+1, "ioctl(%d, %s, $%lx)",
  543.           argv[0], get_ioctl_cmd (argv[1]), argv[2]);
  544.   else
  545.     snprintf (buf, len+1, "ioctl(%d, %s, $%lx) = %d (%d)",
  546.           argv[0], get_ioctl_cmd (argv[1]), argv[2],
  547.           TP_RESULT (tp), TP_ERROR (tp));
  548.  
  549.   strcat (buf, "\n");
  550. }
  551.  
  552.  
  553. static void
  554. vp_open (char *buf, int len, struct call *c, struct trace_packet *tp)
  555. {
  556.   int *argv = & TP_FIRSTARG (tp);
  557.  
  558.   if (tp->tp_is_entry)
  559.     snprintf (buf, len+1, "open(\"%s\", %s)", argv[0], get_open_mode (argv[1]));
  560.   else
  561.     snprintf (buf, len+1, "open(\"%s\", %s) = %d (%d)", argv[0], 
  562.           get_open_mode (argv[1]), TP_RESULT (tp), TP_ERROR (tp));
  563.  
  564.   strcat (buf, "\n");
  565. }
  566.  
  567. static void
  568. vp_pipe (char *buf, int len, struct call *c, struct trace_packet *tp)
  569. {
  570.   int *argv = & TP_FIRSTARG (tp);
  571.  
  572.   if (tp->tp_is_entry)
  573.     snprintf (buf, len+1, "pipe($%lx)", argv[0]);
  574.   else
  575.     {
  576.       int *pv = (int *) argv[0];
  577.     
  578.       snprintf (buf, len+1, "pipe([%d, %d]) = %d (%d)", 
  579.         pv[0], pv[1], TP_RESULT (tp), TP_ERROR (tp));
  580.     }
  581.  
  582.   strcat (buf, "\n");
  583. }
  584.