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 / ptrace.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  13KB  |  474 lines

  1. /*-
  2.  * Copyright (c) 1995 Leonard Norrgard.  All rights reserved.
  3.  * Copyright (c) 1994 Christopher G. Demetriou.  All rights reserved.
  4.  * Copyright (c) 1982, 1986, 1989, 1993
  5.  *    The Regents of the University of California.  All rights reserved.
  6.  * (c) UNIX System Laboratories, Inc.
  7.  * All or some portions of this file are derived from material licensed
  8.  * to the University of California by American Telephone and Telegraph
  9.  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
  10.  * the permission of UNIX System Laboratories, Inc.
  11.  *
  12.  * Redistribution and use in source and binary forms, with or without
  13.  * modification, are permitted provided that the following conditions
  14.  * are met:
  15.  * 1. Redistributions of source code must retain the above copyright
  16.  *    notice, this list of conditions and the following disclaimer.
  17.  * 2. Redistributions in binary form must reproduce the above copyright
  18.  *    notice, this list of conditions and the following disclaimer in the
  19.  *    documentation and/or other materials provided with the distribution.
  20.  * 3. All advertising materials mentioning features or use of this software
  21.  *    must display the following acknowledgement:
  22.  *    This product includes software developed by the University of
  23.  *    California, Berkeley and its contributors.
  24.  * 4. Neither the name of the University nor the names of its contributors
  25.  *    may be used to endorse or promote products derived from this software
  26.  *    without specific prior written permission.
  27.  *
  28.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  29.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  30.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  31.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  32.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  33.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  34.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  37.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  38.  * SUCH DAMAGE.
  39.  *
  40.  *    from: @(#)sys_process.c    8.1 (Berkeley) 6/10/93
  41.  */
  42.  
  43. /*
  44.  * References:
  45.  *    (1) Bach's "The Design of the UNIX Operating System",
  46.  *    (2) sys/miscfs/procfs from UCB's 4.4BSD-Lite distribution,
  47.  *    (3) the "4.4BSD Programmer's Reference Manual" published
  48.  *        by USENIX and O'Reilly & Associates.
  49.  * The 4.4BSD PRM does a reasonably good job of documenting what the various
  50.  * ptrace() requests should actually do, and its text is quoted several times
  51.  * in this file.
  52.  */
  53.  
  54. #define _KERNEL
  55. #include "ixemul.h"
  56. #include "kprintf.h"
  57.  
  58. #include <signal.h>
  59. #include <string.h>
  60. #include <sys/ptrace.h>
  61. #include <sys/types.h>
  62. #include <sys/wait.h>
  63. #include <exec/execbase.h>
  64.  
  65. int process_read_regs (struct user *p, struct reg *regs)
  66. {
  67.   if (p->u_regs == NULL)
  68.     {
  69.       bzero(regs, sizeof(struct reg));
  70.       errno = EIO;
  71.       return -1;
  72.     }
  73.   bcopy (p->u_regs, regs, sizeof (struct reg));
  74.   return 0;
  75. }
  76.  
  77. int process_write_regs (struct user *p, struct reg *regs)
  78. {
  79.   if (p->u_regs == NULL)
  80.     {
  81.       errno = EIO;
  82.       return -1;
  83.     }
  84.   bcopy (regs, p->u_regs, sizeof (struct reg));
  85.   return 0;
  86. }
  87.  
  88. int process_read_fpregs (struct user *p, struct fpreg *fpregs)
  89. {
  90.   if (p->u_fpregs == NULL)
  91.     {
  92.       bzero(fpregs, sizeof(struct fpreg));
  93.       errno = EIO;
  94.       return -1;
  95.     }
  96.   bcopy (p->u_fpregs, fpregs, sizeof (struct fpreg));
  97.   return 0;
  98. }
  99.  
  100. int process_write_fpregs (struct user *p, struct fpreg *fpregs)
  101. {
  102.   if (p->u_fpregs == NULL)
  103.     {
  104.       errno = EIO;
  105.       return -1;
  106.     }
  107.   bcopy (fpregs, p->u_fpregs, sizeof (struct fpreg));
  108.   return 0;
  109. }
  110.  
  111. int process_sstep (struct user *t, int sstep)
  112. {
  113.   if (sstep)
  114.     if (t->u_regs == NULL)
  115.       {
  116.         errno = EIO;
  117.         return -1;
  118.       }
  119.     else
  120.       t->u_regs->r_sr |= 0x8000;
  121.   else if (t->u_regs)
  122.     t->u_regs->r_sr &= ~0x8000;
  123.   return 0;
  124. }
  125.  
  126. int process_set_pc (struct user *t, caddr_t addr)
  127. {
  128.   if (t->u_regs)
  129.     {
  130.       t->u_regs->r_pc = addr;
  131.       return 0;
  132.     }
  133.   errno = EIO;
  134.   return -1;
  135. }
  136.  
  137. int ptrace (int request, pid_t pid, caddr_t addr, int data)
  138. {
  139.   struct Task *task, *me = FindTask(0);
  140.   struct user *t, *p;
  141.   int step;
  142.   int error;
  143.  
  144.   /* Find the user area of this process.  */
  145.   p = me->tc_TrapData;
  146.  
  147.   if (request == PT_GETIXINFO)
  148.     {
  149.       struct small_ixnet_base {
  150.     struct Library     ixnet_lib;
  151.     unsigned char      ix_myflags;
  152.     unsigned char      ix_pad;
  153.     BPTR           ix_seg_list;
  154.       };
  155.  
  156.       static struct ixinfo info;
  157.       extern void sig_trampoline();
  158.       extern void sig_launch();
  159.       extern void install_vector();  /* trap.s */
  160.       extern void restore_vector();  /* trap.s */
  161.         
  162.       info.version = 0;
  163.       info.ixemul_seglist = ix.ix_seg_list;
  164.       info.ixnet_seglist = (u.u_ixnetbase ? ((struct small_ixnet_base *)(u.u_ixnetbase))->ix_seg_list : NULL);
  165.       info.sigtramp_start = (long)sig_trampoline;
  166.       info.sigtramp_end = (long)sig_launch;
  167.       if (betterthan68010())
  168.         {
  169.           info.install_vector = install_vector;
  170.           info.restore_vector = restore_vector;
  171.         }
  172.       else
  173.         {
  174.           info.install_vector = NULL;
  175.           info.restore_vector = NULL;
  176.         }
  177.       return (int)&info;
  178.     }
  179.   else if (request == PT_TRACE_ME)
  180.     task = me;
  181.   else if ((request == PT_ATTACH))
  182.     { 
  183.       /* have to check if the task really exists */
  184.       if (pid == 0 || (task = pfind(pid)) == NULL)
  185.         {
  186.           errno = ESRCH;
  187.           return -1;
  188.         }
  189.     }
  190.   else
  191.     task = (struct Task *) pid;
  192.  
  193. /* Temporarily until I'm convinced it all works. It makes it also easier
  194.    to debug gdb. */
  195. #if 0
  196.   {
  197.     char *req;
  198.  
  199.     switch (request)
  200.       {
  201.       case PT_TRACE_ME:   req = "PT_TRACE_ME";  break;
  202.       case PT_READ_I:     req = "PT_READ_I";    break;
  203.       case PT_READ_D:     req = "PT_READ_D";    break;
  204.       case PT_READ_U:     req = "PT_READ_U";    break;
  205.       case PT_WRITE_I:    req = "PT_WRITE_I";   break;
  206.       case PT_WRITE_D:    req = "PT_WRITE_D";   break;
  207.       case PT_WRITE_U:    req = "PT_WRITE_U";   break;
  208.       case PT_CONTINUE:   req = "PT_CONTINUE";  break;
  209.       case PT_KILL:       req = "PT_KILL";      break;
  210.       case PT_STEP:       req = "PT_STEP";      break;
  211.       case PT_GETSEGS:    req = "PT_GETSEGS";   break;
  212.       case PT_GETIXINFO:  req = "PT_GETIXINFO"; break;
  213.       case PT_GETREGS:    req = "PT_GETREGS";   break;
  214.       case PT_SETREGS:    req = "PT_SETREGS";   break;
  215.       case PT_GETEXENAME: req = "PT_GETEXENAME";break;
  216.       case PT_GETA4:      req = "PT_GETA4";     break;
  217.       case PT_GETFPREGS:  req = "PT_GETFPREGS"; break;
  218.       case PT_SETFPREGS:  req = "PT_SETFPREGS"; break;
  219.       case PT_ATTACH:     req = "PT_ATTACH";    break;
  220.       case PT_DETACH:     req = "PT_DETACH";    break;
  221.       default:       req = "*Unknown request*"; break;
  222.       }
  223.     switch (request)
  224.       {
  225.       case PT_READ_I:   break;
  226.       case PT_READ_D:   break;
  227.       case PT_READ_U:   break;
  228.       case PT_WRITE_I:  break;
  229.       case PT_WRITE_D:  break;
  230.       case PT_WRITE_U:  break;
  231.       default:break;
  232.  
  233.       case PT_KILL:
  234.       case PT_CONTINUE:
  235.       case PT_STEP:
  236.     KPrintF("ptrace (%s, pid=%lx, addr=%lx , data=%lx);\n",
  237.     req, pid, addr, data);
  238.       }
  239.   }
  240. #endif
  241.  
  242.   /* sanity check */
  243.   if (task == NULL || (t = (struct user *) task->tc_TrapData) == NULL)
  244.     {
  245.       errno = ESRCH;
  246.       return -1;
  247.     }
  248.  
  249.   /* Check that the arguments are valid.  */
  250.   switch (request)
  251.     {
  252.     case PT_TRACE_ME:
  253.       /* Saying that you're being traced is always OK.  */
  254.       break;
  255.  
  256.     case PT_ATTACH:
  257.       /* You can't attach to a process if:
  258.      (1) it's the process that's doing the attaching or  */
  259.       if (t == FindTask (0)->tc_TrapData)
  260.         {
  261.           errno = EPERM;
  262.           return -1;
  263.         }
  264.  
  265.       /* (2) it's already being traced.  */
  266.       if (t->p_flag & STRC)
  267.         {
  268.           errno = EPERM;
  269.           return -1;
  270.         }
  271.       break;
  272.  
  273.     case PT_READ_I:
  274.     case PT_READ_D:
  275.     case PT_WRITE_I:
  276.     case PT_WRITE_D:
  277.     case PT_CONTINUE:
  278.     case PT_KILL:
  279.     case PT_DETACH:
  280.     case PT_GETFPREGS:
  281.     case PT_SETFPREGS:
  282.  
  283.       /* You can't do what you want to the process if:  */
  284.  
  285.       /* (1) It's not being traced at all,  */
  286.       if (!(t->p_flag & STRC))
  287.         {
  288.           errno = EPERM;
  289.           return -1;
  290.         }
  291.  
  292.       /* (2) it's not being traced by _you_, or  */
  293.       if (t->p_pptr->pr_Task.tc_TrapData != p)
  294.         {
  295.           errno = EPERM;
  296.           return -1;
  297.         }
  298.  
  299.       /* (3) it's not currently stopped.  */
  300.       if (t->p_stat != SSTOP
  301.       || !(t->p_flag & SWTED))
  302.         {
  303.           errno = EPERM;
  304.           return -1;
  305.         }
  306.       break;
  307.  
  308.     case PT_STEP:
  309.     case PT_GETREGS:
  310.     case PT_SETREGS:
  311.     case PT_GETSEGS:    /* you can always do this */
  312.     case PT_GETEXENAME:    /* you can always do this */
  313.     case PT_GETA4:    /* you can always do this */
  314.       break;
  315.  
  316.     default:
  317.       /* It was not a valid request. */
  318.       errno = EIO;
  319.       return -1;
  320.     }
  321.  
  322.   /* Now actually do the job.  */
  323.   step = 0;
  324.  
  325.   switch (request)
  326.     {
  327.     case PT_TRACE_ME:
  328.       /* Child declares it's being traced, just set the trace flag.  */
  329.       t->p_flag |= STRC;
  330.       break;
  331.  
  332.     case PT_READ_I:
  333.     case PT_READ_D:
  334.       /* Check whether this is valid memory */
  335.       if (((int)addr & 1) || addr == 0 || ((TypeOfMem(addr)) == 0))
  336.         {
  337.           errno = EIO;
  338.           return -1;
  339.         }
  340.       return *((int *)addr);
  341.  
  342.     case PT_WRITE_I:
  343.     case PT_WRITE_D:
  344.       /* Check whether this is valid memory */
  345.       if (((int)addr & 1) || addr == 0 || ((TypeOfMem(addr)) == 0))
  346.         {
  347.           errno = EIO;
  348.           return -1;
  349.         }
  350.       *((int *)addr) = data;
  351.       CacheClearE(addr, 4, CACRF_ClearI | CACRF_ClearD);
  352.       return 0;
  353.  
  354.     case PT_GETSEGS:
  355.       return (t->u_segs ? (int)t->u_segs->segment : 0);
  356.  
  357.     case PT_GETEXENAME:
  358.       return (t->u_segs ? (int)t->u_segs->name : 0);
  359.  
  360.     case PT_GETA4:
  361.       return t->u_a4;
  362.  
  363.       /* case PT_READ_U: fixme */
  364.       /* case PT_WRITE_U: fixme */
  365.  
  366.     case PT_STEP:
  367.       /* From the 4.4BSD PRM:
  368.      "Execution continues as in request PT_CONTINUE; however
  369.      as soon as possible after execution of at least one
  370.      instruction, execution stops again. [ ... ]"  */
  371.       step = 1;
  372.       /* fallthrough */
  373.  
  374.     case PT_CONTINUE:
  375.       /* From the 4.4BSD PRM:
  376.      "The data argument is taken as a signal number and the
  377.      child's execution continues at location addr as if it
  378.      incurred that signal.  Normally the signal number will
  379.      be either 0 to indicate that the signal that caused the
  380.      stop should be ignored, or that value fetched out of
  381.      the process's image indicating which signal caused
  382.      the stop.  If addr is (int *)1 then execution continues
  383.      from where it stopped." */
  384.       /* step = 0 done above. */
  385.  
  386.       /* Check that data is a valid signal number or zero.  */
  387.       if (data < 0 || data >= NSIG)
  388.         {
  389.           errno = EIO;
  390.           return -1;
  391.         }
  392.  
  393.       /* Arrange for a single-step, if that's requested and possible.  */
  394.       if ((error = process_sstep (t, step)))
  395.     return error;
  396.  
  397.       /* If the address parameter is not (int *)1, set the pc.  */
  398.       if ((int *)addr != (int *)1)
  399.     if ((error = process_set_pc (t, addr)))
  400.       return error;
  401.  
  402.       /* Finally, deliver the requested signal (or none).  */
  403.     sendsig:
  404.       t->p_xstat = data;
  405.       setrun (task);
  406.       return 0;
  407.  
  408.     case PT_KILL:
  409.       /* not being traced any more */
  410.       t->p_flag &= ~STRC;
  411.       /* Just send the process a KILL signal.  */
  412.       data = SIGKILL;
  413.       goto sendsig;
  414.  
  415.     case PT_GETREGS:
  416.       return process_read_regs (t, (struct reg *)addr);
  417.       
  418.     case PT_SETREGS:
  419.       return process_write_regs (t, (struct reg *)addr);
  420.       
  421.     case PT_GETFPREGS:
  422.       return process_read_fpregs (t, (struct fpreg *)addr);
  423.       
  424.     case PT_SETFPREGS:
  425.       return process_write_fpregs (t, (struct fpreg *)addr);
  426.  
  427.     case PT_ATTACH:      
  428.     /*
  429.      * Go ahead and set the trace flag.
  430.      * Save the old parent (it's reset in
  431.      *   _DETACH, and also in vfork.c:wait4()
  432.      * Reparent the process so that the tracing
  433.      *   proc gets to see all the action.
  434.      * Stop the target.
  435.      */
  436.     t->p_flag |= STRC;
  437.     t->p_xstat = 0;         /* XXX ? */
  438.     if (t->p_pptr != (struct Process *)me) {
  439.       t->p_opptr = t->p_pptr;
  440.       proc_reparent((struct Process *)task, (struct Process *)me);
  441.     }
  442.     _psignal(task, SIGSTOP);
  443.     return (0);
  444.  
  445.     case PT_DETACH:      
  446.     /* not being traced any more */
  447.     t->p_flag &= ~STRC;
  448.  
  449.     /* give process back to original parent */
  450.     if (t->p_opptr != t->p_pptr)
  451.         {
  452.       if (t->p_opptr && pfind((pid_t)t->p_opptr))
  453.         proc_reparent((struct Process *)task, t->p_opptr);
  454.     }
  455.  
  456.     t->p_opptr = NULL;
  457.     t->p_flag &= ~SWTED;
  458.  
  459.     /* and deliver any signal requested by tracer. */
  460.     if (t->p_stat == SSTOP)
  461.       goto sendsig;
  462.     else if (data)
  463.       _psignal(task, data);
  464.  
  465.     return (0);
  466.  
  467.     default:
  468.       /* Unknown request.  */
  469.       errno = EIO;
  470.       return -1;
  471.     }
  472.   return 0;    /* correct return value? */
  473. }
  474.