home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / ixemul-45.0-src.tgz / tar.out / contrib / ixemul / library / tracecntl.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  8KB  |  276 lines

  1. /*
  2.  *  This file is part of ixemul.library for the Amiga.
  3.  *  Copyright (C) 1991, 1992  Markus M. Wild
  4.  *
  5.  *  This library is free software; you can redistribute it and/or
  6.  *  modify it under the terms of the GNU Library General Public
  7.  *  License as published by the Free Software Foundation; either
  8.  *  version 2 of the License, or (at your option) any later version.
  9.  *
  10.  *  This library is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.  *  Library General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU Library General Public
  16.  *  License along with this library; if not, write to the Free
  17.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  *  tracecntl.c,v 1.1.1.1 1994/04/04 04:29:49 amiga Exp
  20.  *
  21.  *  tracecntl.c,v
  22.  * Revision 1.1.1.1  1994/04/04  04:29:49  amiga
  23.  * Initial CVS check in.
  24.  *
  25.  *  Revision 1.6  1993/11/05  22:03:32  mwild
  26.  *  treat vfork2 same as vfork
  27.  *
  28.  *  Revision 1.5  1992/08/09  21:01:09  amiga
  29.  *  import sysbase
  30.  *
  31.  *  Revision 1.4  1992/07/04  19:23:16  mwild
  32.  *  double the number of passed parameters. Probably still not enough for weird
  33.  *  cases, but I can't do much about that...
  34.  *
  35.  * Revision 1.3  1992/05/22  01:51:07  mwild
  36.  * all common double returning functions are _JMP or they won't work
  37.  *
  38.  * Revision 1.2  1992/05/18  12:24:20  mwild
  39.  * new way of getting at the result of a function. Do the call from
  40.  * inside the handler and tell the library call hook to not call the
  41.  * function again (TRACE_ACTION_RTS). Removed trace_exit() handler.
  42.  *
  43.  * Revision 1.1  1992/05/14  19:55:40  mwild
  44.  * Initial revision
  45.  *
  46.  */
  47.  
  48. #define _KERNEL
  49. #include "ixemul.h"
  50. #include "kprintf.h"
  51.  
  52. #include <sys/tracecntl.h>
  53.  
  54. #ifdef TRACE_LIBRARY
  55.  
  56. static struct List packets = {
  57.   (struct Node *) &packets.lh_Tail, 0, (struct Node *) &packets.lh_Head,
  58. };
  59.  
  60. static struct SignalSemaphore psem;
  61. static sem_initialized = 0;
  62.  
  63. /* for each function traced, the trace_entry() function decides whether
  64.    the trace_exit() function is invoked or not.
  65.    If trace_entry() returns false, trace_exit() is not invoked.
  66.  
  67.    NOTE: having setjmp, vfork and the like invoke trace_exit will *NOT*
  68.          work and will cause crashes!!
  69.  
  70.    Since I consider placing break points just to get the return value
  71.    a bit overkill, I'll take a less optimal solution: I copy 8 args, this
  72.    will do for 99% of all cases, and some nasty printf() style call will
  73.    probably fail if tracing is enabled, so what ;-)) */
  74.  
  75. int
  76. trace_entry (int scall, int (*func)(int, ...), void *ret_addr,
  77.          int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8,
  78.          int a9, int aa, int ab, int ac, int ad, int ae, int af)
  79. {
  80.   struct trace_packet *tp, *ntp;
  81.   struct Task *me = FindTask (0);
  82.   int te_action, handler_active;
  83.   int omask;
  84.  
  85.   /* for safety, don't do anything if running in Forbid() or Disable() */
  86.   if (SysBase->TDNestCnt >= 0 || SysBase->IDNestCnt >= 0)
  87.     return TRACE_ACTION_JMP;
  88.  
  89.   /* have to do this here, or the handler may get into a deadlock
  90.      situation when trying to obtain the semaphore */
  91.   if (u.u_trace_flags)
  92.     return TRACE_ACTION_JMP;
  93.  
  94.   /* get default action value */  
  95.   switch (scall)
  96.     {
  97.       case SYS_abort:
  98.       case SYS_exit:
  99.       case SYS_longjmp:
  100.       case SYS_setjmp:        /* can return twice ! */
  101.       case SYS_siglongjmp:
  102.       case SYS_sigreturn:
  103.       case SYS_sigsetjmp:    /* "" */
  104.       case SYS__exit:
  105.       case SYS__longjmp:
  106.       case SYS__setjmp:        /* "" */
  107.       case SYS_vfork:        /* "" */
  108.       case SYS_vfork2:        /* "" */
  109.       case SYS_vfork_resume:    /* does longjmp-y thing... */
  110.       case SYS_execve:
  111.       case SYS_ix_geta4:    /* special, result is in A4, not D0 ;-)) */
  112.       case SYS_ix_check_cpu:    /* may not return (but isn't used currently ;-)) */
  113.       case SYS_ix_startup:    /* those two call longjmp thru _exit */
  114.       case SYS_ix_exec_entry:
  115.       case SYS_fork:
  116.       case SYS_floor:        /* have all functions returning more than */
  117.       case SYS_ceil:        /* 4 bytes be called JMP'y */
  118.       case SYS_atof:
  119.       case SYS_frexp:
  120.       case SYS_modf:      
  121.       case SYS_ldexp:
  122.       case SYS_atan ... SYS_fabs:    /* all the trigo stuff from *transbase.. */
  123.       case SYS_strtod:
  124.     te_action = TRACE_ACTION_JMP;
  125.     break;
  126.  
  127.       default:
  128.     te_action = TRACE_ACTION_JSR;
  129.     break;
  130.     }
  131.  
  132.   /* don't use syscall() here.. */
  133.   omask = sigsetmask (~0);
  134.   if (! sem_initialized)
  135.     {
  136.       sem_initialized = 1;
  137.       InitSemaphore (& psem);
  138.     }
  139.   ObtainSemaphore (& psem);
  140.   handler_active = 0;
  141.   for (tp  = (struct trace_packet *) packets.lh_Head;
  142.        (ntp = (struct trace_packet *) tp->tp_message.mn_Node.ln_Succ);
  143.        tp  = ntp)
  144.     {
  145.       if ((!tp->tp_pid || tp->tp_pid == (pid_t) me) &&
  146.             (!tp->tp_syscall || tp->tp_syscall == scall))
  147.     {
  148.       Remove ((struct Node *) tp);
  149.  
  150.       tp->tp_is_entry = 1;
  151.       tp->tp_argv = &scall;
  152.       tp->tp_errno = u.u_errno;
  153.       /* provide the default for the handler to (possibly) override */
  154.       tp->tp_action = te_action;
  155.       /* wanted to use u.u_sync_mp here, but this leads to some
  156.          deadlock situations when the port is used for packets.. */
  157.       tp->tp_message.mn_ReplyPort = (struct MsgPort *) me;
  158.       SetSignal (0, SIGBREAKF_CTRL_E);
  159.           PutMsg (tp->tp_tracer_port, (struct Message *) tp);
  160.       Wait (SIGBREAKF_CTRL_E);
  161.       /* the last handler wins ;-)) */
  162.       te_action = tp->tp_action;
  163.       handler_active = 1;
  164.  
  165.       /* should be safe.. */
  166.       AddHead (&packets, (struct Node *) tp);
  167.     }
  168.     }
  169.   ReleaseSemaphore (& psem);
  170.   sigsetmask (omask);
  171.  
  172.   if (! handler_active)
  173.     te_action = TRACE_ACTION_JMP;
  174.  
  175.   switch (te_action)      
  176.     {
  177.     case TRACE_ACTION_ABORT:
  178.       abort();
  179.  
  180.     default:
  181.     case TRACE_ACTION_JMP:
  182.       return TRACE_ACTION_JMP;
  183.       
  184.     case TRACE_ACTION_JSR:
  185.       {
  186.         int result, error;
  187.  
  188.         /* we now know that there is at least one trace handler
  189.            interested in this result, so do the extra overhead of
  190.            calling with (excess) argument copying */
  191.     result = func (a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af);
  192.     error  = errno;
  193.  
  194.     /* replace the function address with the result */
  195.     *(int *)&func = result;
  196.     
  197.     /* and repeat the process of calling the trace handler(s) */
  198.     omask = sigsetmask (~0);
  199.         ObtainSemaphore (& psem);
  200.         for (tp  = (struct trace_packet *) packets.lh_Head;
  201.              (ntp = (struct trace_packet *) tp->tp_message.mn_Node.ln_Succ);
  202.              tp  = ntp)
  203.           {
  204.             if ((!tp->tp_pid || tp->tp_pid == (pid_t) me) &&
  205.                   (!tp->tp_syscall || tp->tp_syscall == scall))
  206.           {
  207.             Remove ((struct Node *) tp);
  208.  
  209.         tp->tp_is_entry = 0;
  210.         tp->tp_argv = &scall;
  211.         errno = error;
  212.         KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
  213.         tp->tp_errno = u.u_errno;
  214.         tp->tp_message.mn_ReplyPort = (struct MsgPort *) me;
  215.         SetSignal (0, SIGBREAKF_CTRL_E);
  216.         PutMsg (tp->tp_tracer_port, (struct Message *) tp);
  217.         Wait (SIGBREAKF_CTRL_E);
  218.  
  219.         error = errno;
  220.         /* should be safe.. */
  221.         AddHead (&packets, (struct Node *) tp);
  222.           }
  223.       }
  224.     ReleaseSemaphore (& psem);
  225.     sigsetmask (omask);
  226.     errno = error;
  227.     KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
  228.       }
  229.       /* fall into */
  230.  
  231.     case TRACE_ACTION_RTS:
  232.       return TRACE_ACTION_RTS;
  233.     }
  234. }
  235.  
  236. #endif /* TRACE_LIBRARY */
  237.  
  238.  
  239. int
  240. tracecntl (enum trace_cmd cmd, struct trace_packet *tp)
  241. {
  242. #ifndef TRACE_LIBRARY
  243.   errno = ENOSYS;
  244.   KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
  245.   return -1;
  246. #else
  247.   switch (cmd)
  248.     {
  249.     case TRACE_INSTALL_HANDLER:
  250.       ix_lock_base ();
  251.       tp->tp_message.mn_Node.ln_Type = NT_MESSAGE;
  252.       tp->tp_message.mn_Length = sizeof (struct trace_packet);
  253.       ObtainSemaphore (& psem);
  254.       AddTail (&packets, (struct Node *) tp);
  255.       ReleaseSemaphore (& psem);
  256.       ix_unlock_base ();
  257.       u.u_trace_flags = 1;
  258.       return 0;
  259.  
  260.     case TRACE_REMOVE_HANDLER:
  261.       ix_lock_base ();
  262.       ObtainSemaphore (& psem);
  263.       Remove ((struct Node *) tp);
  264.       ReleaseSemaphore (& psem);
  265.       ix_unlock_base ();
  266.       u.u_trace_flags = 0;
  267.       return 0;
  268.       
  269.     default:
  270.       errno = EINVAL;
  271.       KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
  272.       return -1;
  273.     }
  274. #endif
  275. }
  276.