home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 3 / CDPDIII.bin / pd / programming / gnuc / library / rcs / tracecntl.c,v < prev    next >
Encoding:
Text File  |  1992-08-09  |  11.1 KB  |  456 lines

  1. head    1.5;
  2. access;
  3. symbols
  4.     version39-41:1.4;
  5. locks;
  6. comment    @ *  @;
  7.  
  8.  
  9. 1.5
  10. date    92.08.09.21.01.09;    author amiga;    state Exp;
  11. branches;
  12. next    1.4;
  13.  
  14. 1.4
  15. date    92.07.04.19.23.16;    author mwild;    state Exp;
  16. branches;
  17. next    1.3;
  18.  
  19. 1.3
  20. date    92.05.22.01.51.07;    author mwild;    state Exp;
  21. branches;
  22. next    1.2;
  23.  
  24. 1.2
  25. date    92.05.18.12.24.20;    author mwild;    state Exp;
  26. branches;
  27. next    1.1;
  28.  
  29. 1.1
  30. date    92.05.14.19.55.40;    author mwild;    state Exp;
  31. branches;
  32. next    ;
  33.  
  34.  
  35. desc
  36. @support for any tracing-clients (if configured with TRACE_LIBRARY)
  37. @
  38.  
  39.  
  40. 1.5
  41. log
  42. @import sysbase
  43. @
  44. text
  45. @/*
  46.  *  This file is part of ixemul.library for the Amiga.
  47.  *  Copyright (C) 1991, 1992  Markus M. Wild
  48.  *
  49.  *  This library is free software; you can redistribute it and/or
  50.  *  modify it under the terms of the GNU Library General Public
  51.  *  License as published by the Free Software Foundation; either
  52.  *  version 2 of the License, or (at your option) any later version.
  53.  *
  54.  *  This library is distributed in the hope that it will be useful,
  55.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  56.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  57.  *  Library General Public License for more details.
  58.  *
  59.  *  You should have received a copy of the GNU Library General Public
  60.  *  License along with this library; if not, write to the Free
  61.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  62.  *
  63.  *  $Id: tracecntl.c,v 1.4 1992/07/04 19:23:16 mwild Exp $
  64.  *
  65.  *  $Log: tracecntl.c,v $
  66.  *  Revision 1.4  1992/07/04  19:23:16  mwild
  67.  *  double the number of passed parameters. Probably still not enough for weird
  68.  *  cases, but I can't do much about that...
  69.  *
  70.  * Revision 1.3  1992/05/22  01:51:07  mwild
  71.  * all common double returning functions are _JMP or they won't work
  72.  *
  73.  * Revision 1.2  1992/05/18  12:24:20  mwild
  74.  * new way of getting at the result of a function. Do the call from
  75.  * inside the handler and tell the library call hook to not call the
  76.  * function again (TRACE_ACTION_RTS). Removed trace_exit() handler.
  77.  *
  78.  * Revision 1.1  1992/05/14  19:55:40  mwild
  79.  * Initial revision
  80.  *
  81.  */
  82.  
  83. #define KERNEL
  84. #include "ixemul.h"
  85.  
  86. #include <sys/tracecntl.h>
  87.  
  88. #ifdef DEBUG
  89. #define DP(a) kprintf a
  90. #else
  91. #define DP(a)
  92. #endif
  93.  
  94. #ifdef TRACE_LIBRARY
  95. struct ExecBase *SysBase;
  96.  
  97. static struct List packets = {
  98.   (struct Node *) &packets.lh_Tail, 0, (struct Node *) &packets.lh_Head,
  99. };
  100.  
  101. static struct SignalSemaphore psem;
  102. static sem_initialized = 0;
  103.  
  104. /* for each function traced, the trace_entry() function decides whether
  105.    the trace_exit() function is invoked or not.
  106.    If trace_entry() returns false, trace_exit() is not invoked.
  107.  
  108.    NOTE: having setjmp, vfork and the like invoke trace_exit will *NOT*
  109.          work and will cause crashes!!
  110.  
  111.    Since I consider placing break points just to get the return value
  112.    a bit overkill, I'll take a less optimal solution: I copy 8 args, this
  113.    will do for 99% of all cases, and some nasty printf() style call will
  114.    probably fail if tracing is enabled, so what ;-)) */
  115.  
  116. int
  117. trace_entry (int scall, int (*func)(...), void *ret_addr,
  118.          int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8,
  119.          int a9, int aa, int ab, int ac, int ad, int ae, int af)
  120. {
  121.   struct trace_packet *tp, *ntp;
  122.   struct Task *me = FindTask (0);
  123.   int te_action, handler_active;
  124.   int omask;
  125.  
  126.   /* for safety, don't do anything if running in Forbid() or Disable() */
  127.   if (SysBase->TDNestCnt >= 0 || SysBase->IDNestCnt >= 0)
  128.     return TRACE_ACTION_JMP;
  129.  
  130.   /* have to do this here, or the handler may get into a deadlock
  131.      situation when trying to obtain the semaphore */
  132.   if (u.u_trace_flags)
  133.     return TRACE_ACTION_JMP;
  134.  
  135.   /* get default action value */  
  136.   switch (scall)
  137.     {
  138.       case SYS_abort:
  139.       case SYS_exit:
  140.       case SYS_longjmp:
  141.       case SYS_setjmp:        /* can return twice ! */
  142.       case SYS_siglongjmp:
  143.       case SYS_sigreturn:
  144.       case SYS_sigsetjmp:    /* "" */
  145.       case SYS__exit:
  146.       case SYS__longjmp:
  147.       case SYS__setjmp:        /* "" */
  148.       case SYS_vfork:        /* "" */
  149.       case SYS_vfork_resume:    /* does longjmp-y thing... */
  150.       case SYS_execve:
  151.       case SYS_ix_geta4:    /* special, result is in A4, not D0 ;-)) */
  152.       case SYS_ix_check_cpu:    /* may not return (but isn't used currently ;-)) */
  153.       case SYS_ix_startup:    /* those two call longjmp thru _exit */
  154.       case SYS_ix_exec_entry:
  155.       case SYS_fork:
  156.       case SYS_floor:        /* have all functions returning more than */
  157.       case SYS_ceil:        /* 4 bytes be called JMP'y */
  158.       case SYS_atof:
  159.       case SYS_frexp:
  160.       case SYS_modf:      
  161.       case SYS_ldexp:
  162.       case SYS_atan ... SYS_fabs:    /* all the trigo stuff from *transbase.. */
  163.       case SYS_strtod:
  164.     te_action = TRACE_ACTION_JMP;
  165.     break;
  166.  
  167.       default:
  168.     te_action = TRACE_ACTION_JSR;
  169.     break;
  170.     }
  171.  
  172.   /* don't use syscall() here.. */
  173.   omask = sigsetmask (~0);
  174.   if (! sem_initialized)
  175.     {
  176.       sem_initialized = 1;
  177.       InitSemaphore (& psem);
  178.     }
  179.   ObtainSemaphore (& psem);
  180.   handler_active = 0;
  181.   for (tp  = (struct trace_packet *) packets.lh_Head;
  182.        ntp = (struct trace_packet *) tp->tp_message.mn_Node.ln_Succ;
  183.        tp  = ntp)
  184.     {
  185.       if ((!tp->tp_pid || tp->tp_pid == (pid_t) me) &&
  186.             (!tp->tp_syscall || tp->tp_syscall == scall))
  187.     {
  188.       Remove ((struct Node *) tp);
  189.  
  190.       tp->tp_is_entry = 1;
  191.       tp->tp_argv = &scall;
  192.       tp->tp_errno = u.u_errno;
  193.       /* provide the default for the handler to (possibly) override */
  194.       tp->tp_action = te_action;
  195.       /* wanted to use u.u_sync_mp here, but this leads to some
  196.          deadlock situations when the port is used for packets.. */
  197.       tp->tp_message.mn_ReplyPort = (struct MsgPort *) me;
  198.       SetSignal (0, SIGBREAKF_CTRL_E);
  199.           PutMsg (tp->tp_tracer_port, (struct Message *) tp);
  200.       Wait (SIGBREAKF_CTRL_E);
  201.       /* the last handler wins ;-)) */
  202.       te_action = tp->tp_action;
  203.       handler_active = 1;
  204.  
  205.       /* should be safe.. */
  206.       AddHead (&packets, (struct Node *) tp);
  207.     }
  208.     }
  209.   ReleaseSemaphore (& psem);
  210.   sigsetmask (omask);
  211.  
  212.   if (! handler_active)
  213.     te_action = TRACE_ACTION_JMP;
  214.  
  215.   switch (te_action)      
  216.     {
  217.     case TRACE_ACTION_ABORT:
  218.       abort();
  219.  
  220.     default:
  221.     case TRACE_ACTION_JMP:
  222.       return TRACE_ACTION_JMP;
  223.       
  224.     case TRACE_ACTION_JSR:
  225.       {
  226.         int result, error;
  227.  
  228.         /* we now know that there is at least one trace handler
  229.            interested in this result, so do the extra overhead of
  230.            calling with (excess) argument copying */
  231.     result = func (a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af);
  232.     error  = errno;
  233.  
  234.     /* replace the function address with the result */
  235.     *(int *)&func = result;
  236.     
  237.     /* and repeat the process of calling the trace handler(s) */
  238.     omask = sigsetmask (~0);
  239.         ObtainSemaphore (& psem);
  240.         for (tp  = (struct trace_packet *) packets.lh_Head;
  241.              ntp = (struct trace_packet *) tp->tp_message.mn_Node.ln_Succ;
  242.              tp  = ntp)
  243.           {
  244.             if ((!tp->tp_pid || tp->tp_pid == (pid_t) me) &&
  245.                   (!tp->tp_syscall || tp->tp_syscall == scall))
  246.           {
  247.             Remove ((struct Node *) tp);
  248.  
  249.         tp->tp_is_entry = 0;
  250.         tp->tp_argv = &scall;
  251.         errno = error;
  252.         tp->tp_errno = u.u_errno;
  253.         tp->tp_message.mn_ReplyPort = (struct MsgPort *) me;
  254.         SetSignal (0, SIGBREAKF_CTRL_E);
  255.         PutMsg (tp->tp_tracer_port, (struct Message *) tp);
  256.         Wait (SIGBREAKF_CTRL_E);
  257.  
  258.         error = errno;
  259.         /* should be safe.. */
  260.         AddHead (&packets, (struct Node *) tp);
  261.           }
  262.       }
  263.     ReleaseSemaphore (& psem);
  264.     sigsetmask (omask);
  265.     errno = error;
  266.       }
  267.       /* fall into */
  268.  
  269.     case TRACE_ACTION_RTS:
  270.       return TRACE_ACTION_RTS;
  271.     }
  272. }
  273.  
  274. #endif /* TRACE_LIBRARY */
  275.  
  276.  
  277. int
  278. tracecntl (enum trace_cmd cmd, struct trace_packet *tp)
  279. {
  280. #ifndef TRACE_LIBRARY
  281.   errno = ENOSYS;
  282.   return -1;
  283. #else
  284.   switch (cmd)
  285.     {
  286.     case TRACE_INSTALL_HANDLER:
  287.       ix_lock_base ();
  288.       tp->tp_message.mn_Node.ln_Type = NT_MESSAGE;
  289.       tp->tp_message.mn_Length = sizeof (struct trace_packet);
  290.       ObtainSemaphore (& psem);
  291.       AddTail (&packets, (struct Node *) tp);
  292.       ReleaseSemaphore (& psem);
  293.       ix_unlock_base ();
  294.       u.u_trace_flags = 1;
  295.       return errno = 0;
  296.  
  297.     case TRACE_REMOVE_HANDLER:
  298.       ix_lock_base ();
  299.       ObtainSemaphore (& psem);
  300.       Remove ((struct Node *) tp);
  301.       ReleaseSemaphore (& psem);
  302.       ix_unlock_base ();
  303.       u.u_trace_flags = 0;
  304.       return errno = 0;
  305.       
  306.     default:
  307.       errno = EINVAL;
  308.       return -1;
  309.     }
  310. #endif
  311. }
  312. @
  313.  
  314.  
  315. 1.4
  316. log
  317. @double the number of passed parameters. Probably still not enough for weird
  318. cases, but I can't do much about that...
  319. @
  320. text
  321. @d19 1
  322. a19 1
  323.  *  $Id: tracecntl.c,v 1.3 1992/05/22 01:51:07 mwild Exp $
  324. d22 4
  325. d51 1
  326. a77 1
  327.   struct ExecBase *SysBase = *(void **)4;
  328. @
  329.  
  330.  
  331. 1.3
  332. log
  333. @all common double returning functions are _JMP or they won't work
  334. @
  335. text
  336. @d19 1
  337. a19 1
  338.  *  $Id: tracecntl.c,v 1.2 1992/05/18 12:24:20 mwild Exp $
  339. d22 3
  340. d69 2
  341. a70 1
  342.          int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8)
  343. d183 1
  344. a183 1
  345.     result = func (a1, a2, a3, a4, a5, a6, a7, a8);
  346. @
  347.  
  348.  
  349. 1.2
  350. log
  351. @new way of getting at the result of a function. Do the call from
  352. inside the handler and tell the library call hook to not call the
  353. function again (TRACE_ACTION_RTS). Removed trace_exit() handler.
  354. @
  355. text
  356. @d19 1
  357. a19 1
  358.  *  $Id: tracecntl.c,v 1.1 1992/05/14 19:55:40 mwild Exp $
  359. d22 5
  360. d98 1
  361. d103 9
  362. @
  363.  
  364.  
  365. 1.1
  366. log
  367. @Initial revision
  368. @
  369. text
  370. @d19 1
  371. a19 1
  372.  *  $Id$
  373. d21 4
  374. a24 1
  375.  *  $Log$
  376. d52 6
  377. a57 1
  378.          work and will cause crashes!! */
  379. d60 2
  380. a61 1
  381. trace_entry (int scall, ...)
  382. a80 4
  383. #if 1
  384.       default:
  385. #endif
  386.  
  387. d95 2
  388. a98 1
  389. #if 0
  390. a102 1
  391. #endif
  392. d145 2
  393. a146 30
  394.   if (te_action == TRACE_ACTION_ABORT)
  395.     abort ();
  396. #if 0
  397.   else
  398.     /* there's no reason to invoke the exit handler if there's nobody
  399.        interested in this event */
  400.     return handler_active ? te_action : TRACE_ACTION_JMP;
  401. #else
  402.   return TRACE_ACTION_JMP;
  403. #endif
  404. }
  405.  
  406. /* we still have the original argument vector on the stack before the
  407.    result. Some handler might be interested in this (sprintf for example) */
  408. void
  409. trace_exit (int scall, int result, ...)
  410. {
  411.   struct trace_packet *tp, *ntp;
  412.   struct ExecBase *SysBase = *(void **)4;
  413.   struct Task *me = FindTask (0);
  414.   int omask;
  415.  
  416.   /* for safety, don't do anything if running in Forbid() or Disable() */
  417.   if (SysBase->TDNestCnt >= 0 || SysBase->IDNestCnt >= 0)
  418.     return TRACE_ACTION_JMP;
  419.  
  420.   /* have to do this here, or the handler may get into a deadlock
  421.      situation when trying to obtain the semaphore */
  422.   if (u.u_trace_flags)
  423.     return TRACE_ACTION_JMP;
  424. d148 1
  425. a148 5
  426.   omask = sigsetmask (~0);
  427.   ObtainSemaphore (& psem);
  428.   for (tp  = (struct trace_packet *) packets.lh_Head;
  429.        ntp = (struct trace_packet *) tp->tp_message.mn_Node.ln_Succ;
  430.        tp  = ntp)
  431. d150 2
  432. a151 5
  433.       /* don't trace the trace handler itself... */
  434.       if ((!tp->tp_pid || tp->tp_pid == (pid_t) me) &&
  435.             (!tp->tp_syscall || tp->tp_syscall == scall))
  436.     {
  437.       Remove ((struct Node *) tp);
  438. d153 48
  439. a200 8
  440.       tp->tp_is_entry = 0;
  441.       tp->tp_argv = &scall;
  442.       tp->tp_errno = u.u_errno;
  443.       tp->tp_action = 0;
  444.       tp->tp_message.mn_ReplyPort = (struct MsgPort *) me;
  445.       SetSignal (0, SIGBREAKF_CTRL_E);
  446.           PutMsg (tp->tp_tracer_port, (struct Message *) tp);
  447.       Wait (SIGBREAKF_CTRL_E);
  448. d202 2
  449. a203 2
  450.       AddHead (&packets, (struct Node *) tp);
  451.     }
  452. a204 2
  453.   ReleaseSemaphore (& psem);
  454.   sigsetmask (omask);
  455. @
  456.