home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / arch / i386 / kernel / ptrace.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-25  |  14.1 KB  |  547 lines

  1. #define THREE_LEVEL
  2. /* ptrace.c */
  3. /* By Ross Biro 1/23/92 */
  4. /* edited by Linus Torvalds */
  5.  
  6. #include <linux/head.h>
  7. #include <linux/kernel.h>
  8. #include <linux/sched.h>
  9. #include <linux/mm.h>
  10. #include <linux/errno.h>
  11. #include <linux/ptrace.h>
  12. #include <linux/user.h>
  13. #include <linux/debugreg.h>
  14.  
  15. #include <asm/segment.h>
  16. #include <asm/pgtable.h>
  17. #include <asm/system.h>
  18.  
  19. /*
  20.  * does not yet catch signals sent when the child dies.
  21.  * in exit.c or in signal.c.
  22.  */
  23.  
  24. /* determines which flags the user has access to. */
  25. /* 1 = access 0 = no access */
  26. #define FLAG_MASK 0x00044dd5
  27.  
  28. /* set's the trap flag. */
  29. #define TRAP_FLAG 0x100
  30.  
  31. /*
  32.  * this is the number to subtract from the top of the stack. To find
  33.  * the local frame.
  34.  */
  35. #define MAGICNUMBER 68
  36.  
  37. /* change a pid into a task struct. */
  38. static inline struct task_struct * get_task(int pid)
  39. {
  40.     int i;
  41.  
  42.     for (i = 1; i < NR_TASKS; i++) {
  43.         if (task[i] != NULL && (task[i]->pid == pid))
  44.             return task[i];
  45.     }
  46.     return NULL;
  47. }
  48.  
  49. /*
  50.  * this routine will get a word off of the processes privileged stack. 
  51.  * the offset is how far from the base addr as stored in the TSS.  
  52.  * this routine assumes that all the privileged stacks are in our
  53.  * data space.
  54.  */   
  55. static inline int get_stack_long(struct task_struct *task, int offset)
  56. {
  57.     unsigned char *stack;
  58.  
  59.     stack = (unsigned char *)task->tss.esp0;
  60.     stack += offset;
  61.     return (*((int *)stack));
  62. }
  63.  
  64. /*
  65.  * this routine will put a word on the processes privileged stack. 
  66.  * the offset is how far from the base addr as stored in the TSS.  
  67.  * this routine assumes that all the privileged stacks are in our
  68.  * data space.
  69.  */
  70. static inline int put_stack_long(struct task_struct *task, int offset,
  71.     unsigned long data)
  72. {
  73.     unsigned char * stack;
  74.  
  75.     stack = (unsigned char *) task->tss.esp0;
  76.     stack += offset;
  77.     *(unsigned long *) stack = data;
  78.     return 0;
  79. }
  80.  
  81. /*
  82.  * This routine gets a long from any process space by following the page
  83.  * tables. NOTE! You should check that the long isn't on a page boundary,
  84.  * and that it is in the task area before calling this: this routine does
  85.  * no checking.
  86.  */
  87. static unsigned long get_long(struct vm_area_struct * vma, unsigned long addr)
  88. {
  89.     pgd_t * pgdir;
  90.     pmd_t * pgmiddle;
  91.     pte_t * pgtable;
  92.     unsigned long page;
  93.  
  94. repeat:
  95.     pgdir = pgd_offset(vma->vm_task, addr);
  96.     if (pgd_none(*pgdir)) {
  97.         do_no_page(vma, addr, 0);
  98.         goto repeat;
  99.     }
  100.     if (pgd_bad(*pgdir)) {
  101.         printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
  102.         pgd_clear(pgdir);
  103.         return 0;
  104.     }
  105.     pgmiddle = pmd_offset(pgdir, addr);
  106.     if (pmd_none(*pgmiddle)) {
  107.         do_no_page(vma, addr, 0);
  108.         goto repeat;
  109.     }
  110.     if (pmd_bad(*pgmiddle)) {
  111.         printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
  112.         pmd_clear(pgmiddle);
  113.         return 0;
  114.     }
  115.     pgtable = pte_offset(pgmiddle, addr);
  116.     if (!pte_present(*pgtable)) {
  117.         do_no_page(vma, addr, 0);
  118.         goto repeat;
  119.     }
  120.     page = pte_page(*pgtable);
  121. /* this is a hack for non-kernel-mapped video buffers and similar */
  122.     if (page >= high_memory)
  123.         return 0;
  124.     page += addr & ~PAGE_MASK;
  125.     return *(unsigned long *) page;
  126. }
  127.  
  128. /*
  129.  * This routine puts a long into any process space by following the page
  130.  * tables. NOTE! You should check that the long isn't on a page boundary,
  131.  * and that it is in the task area before calling this: this routine does
  132.  * no checking.
  133.  *
  134.  * Now keeps R/W state of page so that a text page stays readonly
  135.  * even if a debugger scribbles breakpoints into it.  -M.U-
  136.  */
  137. static void put_long(struct vm_area_struct * vma, unsigned long addr,
  138.     unsigned long data)
  139. {
  140.     pgd_t *pgdir;
  141.     pmd_t *pgmiddle;
  142.     pte_t *pgtable;
  143.     unsigned long page;
  144.  
  145. repeat:
  146.     pgdir = pgd_offset(vma->vm_task, addr);
  147.     if (!pgd_present(*pgdir)) {
  148.         do_no_page(vma, addr, 1);
  149.         goto repeat;
  150.     }
  151.     if (pgd_bad(*pgdir)) {
  152.         printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
  153.         pgd_clear(pgdir);
  154.         return;
  155.     }
  156.     pgmiddle = pmd_offset(pgdir, addr);
  157.     if (pmd_none(*pgmiddle)) {
  158.         do_no_page(vma, addr, 1);
  159.         goto repeat;
  160.     }
  161.     if (pmd_bad(*pgmiddle)) {
  162.         printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
  163.         pmd_clear(pgmiddle);
  164.         return;
  165.     }
  166.     pgtable = pte_offset(pgmiddle, addr);
  167.     if (!pte_present(*pgtable)) {
  168.         do_no_page(vma, addr, 1);
  169.         goto repeat;
  170.     }
  171.     page = pte_page(*pgtable);
  172.     if (!pte_write(*pgtable)) {
  173.         do_wp_page(vma, addr, 1);
  174.         goto repeat;
  175.     }
  176. /* this is a hack for non-kernel-mapped video buffers and similar */
  177.     if (page < high_memory) {
  178.         page += addr & ~PAGE_MASK;
  179.         *(unsigned long *) page = data;
  180.     }
  181. /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
  182. /* this should also re-instate whatever read-only mode there was before */
  183.     *pgtable = pte_mkdirty(mk_pte(page, vma->vm_page_prot));
  184.     invalidate();
  185. }
  186.  
  187. static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr)
  188. {
  189.     struct vm_area_struct * vma;
  190.  
  191.     addr &= PAGE_MASK;
  192.     vma = find_vma(tsk,addr);
  193.     if (!vma)
  194.         return NULL;
  195.     if (vma->vm_start <= addr)
  196.         return vma;
  197.     if (!(vma->vm_flags & VM_GROWSDOWN))
  198.         return NULL;
  199.     if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
  200.         return NULL;
  201.     vma->vm_offset -= vma->vm_start - addr;
  202.     vma->vm_start = addr;
  203.     return vma;
  204. }
  205.  
  206. /*
  207.  * This routine checks the page boundaries, and that the offset is
  208.  * within the task area. It then calls get_long() to read a long.
  209.  */
  210. static int read_long(struct task_struct * tsk, unsigned long addr,
  211.     unsigned long * result)
  212. {
  213.     struct vm_area_struct * vma = find_extend_vma(tsk, addr);
  214.  
  215.     if (!vma)
  216.         return -EIO;
  217.     if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
  218.         unsigned long low,high;
  219.         struct vm_area_struct * vma_high = vma;
  220.  
  221.         if (addr + sizeof(long) >= vma->vm_end) {
  222.             vma_high = vma->vm_next;
  223.             if (!vma_high || vma_high->vm_start != vma->vm_end)
  224.                 return -EIO;
  225.         }
  226.         low = get_long(vma, addr & ~(sizeof(long)-1));
  227.         high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
  228.         switch (addr & (sizeof(long)-1)) {
  229.             case 1:
  230.                 low >>= 8;
  231.                 low |= high << 24;
  232.                 break;
  233.             case 2:
  234.                 low >>= 16;
  235.                 low |= high << 16;
  236.                 break;
  237.             case 3:
  238.                 low >>= 24;
  239.                 low |= high << 8;
  240.                 break;
  241.         }
  242.         *result = low;
  243.     } else
  244.         *result = get_long(vma, addr);
  245.     return 0;
  246. }
  247.  
  248. /*
  249.  * This routine checks the page boundaries, and that the offset is
  250.  * within the task area. It then calls put_long() to write a long.
  251.  */
  252. static int write_long(struct task_struct * tsk, unsigned long addr,
  253.     unsigned long data)
  254. {
  255.     struct vm_area_struct * vma = find_extend_vma(tsk, addr);
  256.  
  257.     if (!vma)
  258.         return -EIO;
  259.     if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
  260.         unsigned long low,high;
  261.         struct vm_area_struct * vma_high = vma;
  262.  
  263.         if (addr + sizeof(long) >= vma->vm_end) {
  264.             vma_high = vma->vm_next;
  265.             if (!vma_high || vma_high->vm_start != vma->vm_end)
  266.                 return -EIO;
  267.         }
  268.         low = get_long(vma, addr & ~(sizeof(long)-1));
  269.         high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
  270.         switch (addr & (sizeof(long)-1)) {
  271.             case 0: /* shouldn't happen, but safety first */
  272.                 low = data;
  273.                 break;
  274.             case 1:
  275.                 low &= 0x000000ff;
  276.                 low |= data << 8;
  277.                 high &= ~0xff;
  278.                 high |= data >> 24;
  279.                 break;
  280.             case 2:
  281.                 low &= 0x0000ffff;
  282.                 low |= data << 16;
  283.                 high &= ~0xffff;
  284.                 high |= data >> 16;
  285.                 break;
  286.             case 3:
  287.                 low &= 0x00ffffff;
  288.                 low |= data << 24;
  289.                 high &= ~0xffffff;
  290.                 high |= data >> 8;
  291.                 break;
  292.         }
  293.         put_long(vma, addr & ~(sizeof(long)-1),low);
  294.         put_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high);
  295.     } else
  296.         put_long(vma, addr, data);
  297.     return 0;
  298. }
  299.  
  300. asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
  301. {
  302.     struct task_struct *child;
  303.     struct user * dummy;
  304.     int i;
  305.  
  306.     dummy = NULL;
  307.  
  308.     if (request == PTRACE_TRACEME) {
  309.         /* are we already being traced? */
  310.         if (current->flags & PF_PTRACED)
  311.             return -EPERM;
  312.         /* set the ptrace bit in the process flags. */
  313.         current->flags |= PF_PTRACED;
  314.         return 0;
  315.     }
  316.     if (pid == 1)        /* you may not mess with init */
  317.         return -EPERM;
  318.     if (!(child = get_task(pid)))
  319.         return -ESRCH;
  320.     if (request == PTRACE_ATTACH) {
  321.         if (child == current)
  322.             return -EPERM;
  323.         if ((!child->dumpable ||
  324.             (current->uid != child->euid) ||
  325.             (current->uid != child->uid) ||
  326.              (current->gid != child->egid) ||
  327.              (current->gid != child->gid)) && !suser())
  328.             return -EPERM;
  329.         /* the same process cannot be attached many times */
  330.         if (child->flags & PF_PTRACED)
  331.             return -EPERM;
  332.         child->flags |= PF_PTRACED;
  333.         if (child->p_pptr != current) {
  334.             REMOVE_LINKS(child);
  335.             child->p_pptr = current;
  336.             SET_LINKS(child);
  337.         }
  338.         send_sig(SIGSTOP, child, 1);
  339.         return 0;
  340.     }
  341.     if (!(child->flags & PF_PTRACED))
  342.         return -ESRCH;
  343.     if (child->state != TASK_STOPPED) {
  344.         if (request != PTRACE_KILL)
  345.             return -ESRCH;
  346.     }
  347.     if (child->p_pptr != current)
  348.         return -ESRCH;
  349.  
  350.     switch (request) {
  351.     /* when I and D space are separate, these will need to be fixed. */
  352.         case PTRACE_PEEKTEXT: /* read word at location addr. */ 
  353.         case PTRACE_PEEKDATA: {
  354.             unsigned long tmp;
  355.             int res;
  356.  
  357.             res = read_long(child, addr, &tmp);
  358.             if (res < 0)
  359.                 return res;
  360.             res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
  361.             if (!res)
  362.                 put_fs_long(tmp,(unsigned long *) data);
  363.             return res;
  364.         }
  365.  
  366.     /* read the word at location addr in the USER area. */
  367.         case PTRACE_PEEKUSR: {
  368.             unsigned long tmp;
  369.             int res;
  370.  
  371.             if ((addr & 3) || addr < 0 || 
  372.                 addr > sizeof(struct user) - 3)
  373.                 return -EIO;
  374.  
  375.             res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
  376.             if (res)
  377.                 return res;
  378.             tmp = 0;  /* Default return condition */
  379.             if(addr < 17*sizeof(long)) {
  380.               addr = addr >> 2; /* temporary hack. */
  381.  
  382.               tmp = get_stack_long(child, sizeof(long)*addr - MAGICNUMBER);
  383.               if (addr == DS || addr == ES ||
  384.                   addr == FS || addr == GS ||
  385.                   addr == CS || addr == SS)
  386.                 tmp &= 0xffff;
  387.             };
  388.             if(addr >= (long) &dummy->u_debugreg[0] &&
  389.                addr <= (long) &dummy->u_debugreg[7]){
  390.                 addr -= (long) &dummy->u_debugreg[0];
  391.                 addr = addr >> 2;
  392.                 tmp = child->debugreg[addr];
  393.             };
  394.             put_fs_long(tmp,(unsigned long *) data);
  395.             return 0;
  396.         }
  397.  
  398.       /* when I and D space are separate, this will have to be fixed. */
  399.         case PTRACE_POKETEXT: /* write the word at location addr. */
  400.         case PTRACE_POKEDATA:
  401.             return write_long(child,addr,data);
  402.  
  403.         case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
  404.             if ((addr & 3) || addr < 0 || 
  405.                 addr > sizeof(struct user) - 3)
  406.                 return -EIO;
  407.  
  408.             addr = addr >> 2; /* temporary hack. */
  409.  
  410.             if (addr == ORIG_EAX)
  411.                 return -EIO;
  412.             if (addr == DS || addr == ES ||
  413.                 addr == FS || addr == GS ||
  414.                 addr == CS || addr == SS) {
  415.                     data &= 0xffff;
  416.                     if (data && (data & 3) != 3)
  417.                     return -EIO;
  418.             }
  419.             if (addr == EFL) {   /* flags. */
  420.                 data &= FLAG_MASK;
  421.                 data |= get_stack_long(child, EFL*sizeof(long)-MAGICNUMBER)  & ~FLAG_MASK;
  422.             }
  423.           /* Do not allow the user to set the debug register for kernel
  424.              address space */
  425.           if(addr < 17){
  426.               if (put_stack_long(child, sizeof(long)*addr-MAGICNUMBER, data))
  427.                 return -EIO;
  428.             return 0;
  429.             };
  430.  
  431.           /* We need to be very careful here.  We implicitly
  432.              want to modify a portion of the task_struct, and we
  433.              have to be selective about what portions we allow someone
  434.              to modify. */
  435.  
  436.           addr = addr << 2;  /* Convert back again */
  437.           if(addr >= (long) &dummy->u_debugreg[0] &&
  438.              addr <= (long) &dummy->u_debugreg[7]){
  439.  
  440.               if(addr == (long) &dummy->u_debugreg[4]) return -EIO;
  441.               if(addr == (long) &dummy->u_debugreg[5]) return -EIO;
  442.               if(addr < (long) &dummy->u_debugreg[4] &&
  443.                  ((unsigned long) data) >= 0xbffffffd) return -EIO;
  444.               
  445.               if(addr == (long) &dummy->u_debugreg[7]) {
  446.                   data &= ~DR_CONTROL_RESERVED;
  447.                   for(i=0; i<4; i++)
  448.                       if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
  449.                           return -EIO;
  450.               };
  451.  
  452.               addr -= (long) &dummy->u_debugreg;
  453.               addr = addr >> 2;
  454.               child->debugreg[addr] = data;
  455.               return 0;
  456.           };
  457.           return -EIO;
  458.  
  459.         case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
  460.         case PTRACE_CONT: { /* restart after signal. */
  461.             long tmp;
  462.  
  463.             if ((unsigned long) data > NSIG)
  464.                 return -EIO;
  465.             if (request == PTRACE_SYSCALL)
  466.                 child->flags |= PF_TRACESYS;
  467.             else
  468.                 child->flags &= ~PF_TRACESYS;
  469.             child->exit_code = data;
  470.             child->state = TASK_RUNNING;
  471.     /* make sure the single step bit is not set. */
  472.             tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG;
  473.             put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
  474.             return 0;
  475.         }
  476.  
  477. /*
  478.  * make the child exit.  Best I can do is send it a sigkill. 
  479.  * perhaps it should be put in the status that it wants to 
  480.  * exit.
  481.  */
  482.         case PTRACE_KILL: {
  483.             long tmp;
  484.  
  485.             child->state = TASK_RUNNING;
  486.             child->exit_code = SIGKILL;
  487.     /* make sure the single step bit is not set. */
  488.             tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG;
  489.             put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
  490.             return 0;
  491.         }
  492.  
  493.         case PTRACE_SINGLESTEP: {  /* set the trap flag. */
  494.             long tmp;
  495.  
  496.             if ((unsigned long) data > NSIG)
  497.                 return -EIO;
  498.             child->flags &= ~PF_TRACESYS;
  499.             tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) | TRAP_FLAG;
  500.             put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
  501.             child->state = TASK_RUNNING;
  502.             child->exit_code = data;
  503.     /* give it a chance to run. */
  504.             return 0;
  505.         }
  506.  
  507.         case PTRACE_DETACH: { /* detach a process that was attached. */
  508.             long tmp;
  509.  
  510.             if ((unsigned long) data > NSIG)
  511.                 return -EIO;
  512.             child->flags &= ~(PF_PTRACED|PF_TRACESYS);
  513.             child->state = TASK_RUNNING;
  514.             child->exit_code = data;
  515.             REMOVE_LINKS(child);
  516.             child->p_pptr = child->p_opptr;
  517.             SET_LINKS(child);
  518.             /* make sure the single step bit is not set. */
  519.             tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG;
  520.             put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
  521.             return 0;
  522.         }
  523.  
  524.         default:
  525.             return -EIO;
  526.     }
  527. }
  528.  
  529. asmlinkage void syscall_trace(void)
  530. {
  531.     if ((current->flags & (PF_PTRACED|PF_TRACESYS))
  532.             != (PF_PTRACED|PF_TRACESYS))
  533.         return;
  534.     current->exit_code = SIGTRAP;
  535.     current->state = TASK_STOPPED;
  536.     notify_parent(current);
  537.     schedule();
  538.     /*
  539.      * this isn't the same as continuing with a signal, but it will do
  540.      * for normal use.  strace only continues with a signal if the
  541.      * stopping signal is not SIGTRAP.  -brl
  542.      */
  543.     if (current->exit_code)
  544.         current->signal |= (1 << (current->exit_code - 1));
  545.     current->exit_code = 0;
  546. }
  547.