root/kernel/ptrace.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_task
  2. get_stack_long
  3. put_stack_long
  4. get_long
  5. put_long
  6. read_long
  7. write_long
  8. sys_ptrace

   1 /* ptrace.c */
   2 /* By Ross Biro 1/23/92 */
   3 /* edited by Linus Torvalds */
   4 
   5 #include <linux/head.h>
   6 #include <linux/kernel.h>
   7 #include <linux/sched.h>
   8 #include <linux/mm.h>
   9 #include <errno.h>
  10 #include <asm/segment.h>
  11 #include <asm/system.h>
  12 #include <sys/ptrace.h>
  13 
  14 /*
  15  * does not yet catch signals sent when the child dies.
  16  * in exit.c or in signal.c.
  17  */
  18 
  19 /* determines which flags the user has access to. */
  20 /* 1 = access 0 = no access */
  21 #define FLAG_MASK 0x00000dd9
  22 
  23 /* set's the trap flag. */
  24 #define TRAP_FLAG 0x100
  25 
  26 /*
  27  * this is the number to subtract from the top of the stack. To find
  28  * the local frame.
  29  */
  30 #define MAGICNUMBER 68
  31 
  32 void do_no_page(unsigned long, unsigned long, struct task_struct *);
  33 void write_verify(unsigned long);
  34 
  35 /* change a pid into a task struct. */
  36 static inline int get_task(int pid)
     /* [previous][next][first][last][top][bottom][index][help] */
  37 {
  38         int i;
  39 
  40         for (i = 0; i < NR_TASKS; i++) {
  41                 if (task[i] != NULL && (task[i]->pid == pid))
  42                         return i;
  43         }
  44         return -1;
  45 }
  46 
  47 /*
  48  * this routine will get a word off of the processes priviledged stack. 
  49  * the offset is how far from the base addr as stored in the TSS.  
  50  * this routine assumes that all the priviledged stacks are in our
  51  * data space.
  52  */   
  53 static inline int get_stack_long(struct task_struct *task, int offset)
     /* [previous][next][first][last][top][bottom][index][help] */
  54 {
  55         unsigned char *stack;
  56 
  57         stack = (unsigned char *)task->tss.esp0;
  58         stack += offset;
  59         return (*((int *)stack));
  60 }
  61 
  62 /*
  63  * this routine will put a word on the processes priviledged stack. 
  64  * the offset is how far from the base addr as stored in the TSS.  
  65  * this routine assumes that all the priviledged stacks are in our
  66  * data space.
  67  */
  68 static inline int put_stack_long(struct task_struct *task, int offset,
     /* [previous][next][first][last][top][bottom][index][help] */
  69         unsigned long data)
  70 {
  71         unsigned char * stack;
  72 
  73         stack = (unsigned char *) task->tss.esp0;
  74         stack += offset;
  75         *(unsigned long *) stack = data;
  76         return 0;
  77 }
  78 
  79 /*
  80  * This routine gets a long from any process space by following the page
  81  * tables. NOTE! You should check that the long isn't on a page boundary,
  82  * and that it is in the task area before calling this: this routine does
  83  * no checking.
  84  *
  85  * NOTE2! This uses "tsk->tss.cr3" even though we know it's currently always
  86  * zero. This routine shouldn't have to change when we make a better mm.
  87  */
  88 static unsigned long get_long(struct task_struct * tsk,
     /* [previous][next][first][last][top][bottom][index][help] */
  89         unsigned long addr)
  90 {
  91         unsigned long page;
  92 
  93         addr += tsk->start_code;
  94 repeat:
  95         page = tsk->tss.cr3 + ((addr >> 20) & 0xffc);
  96         page = *(unsigned long *) page;
  97         if (page & PAGE_PRESENT) {
  98                 page &= 0xfffff000;
  99                 page += (addr >> 10) & 0xffc;
 100                 page = *((unsigned long *) page);
 101         }
 102         if (!(page & PAGE_PRESENT)) {
 103                 do_no_page(0,addr,tsk);
 104                 goto repeat;
 105         }
 106         page &= 0xfffff000;
 107         page += addr & 0xfff;
 108         return *(unsigned long *) page;
 109 }
 110 
 111 /*
 112  * This routine puts a long into any process space by following the page
 113  * tables. NOTE! You should check that the long isn't on a page boundary,
 114  * and that it is in the task area before calling this: this routine does
 115  * no checking.
 116  */
 117 static void put_long(struct task_struct * tsk, unsigned long addr,
     /* [previous][next][first][last][top][bottom][index][help] */
 118         unsigned long data)
 119 {
 120         unsigned long page;
 121 
 122         addr += tsk->start_code;
 123 repeat:
 124         page = tsk->tss.cr3 + ((addr >> 20) & 0xffc);
 125         page = *(unsigned long *) page;
 126         if (page & PAGE_PRESENT) {
 127                 page &= 0xfffff000;
 128                 page += (addr >> 10) & 0xffc;
 129                 page = *((unsigned long *) page);
 130         }
 131         if (!(page & PAGE_PRESENT)) {
 132                 do_no_page(0,addr,tsk);
 133                 goto repeat;
 134         }
 135         if (!(page & PAGE_RW)) {
 136                 write_verify(addr);
 137                 goto repeat;
 138         }
 139         page &= 0xfffff000;
 140         page += addr & 0xfff;
 141         *(unsigned long *) page = data;
 142 }
 143 
 144 /*
 145  * This routine checks the page boundaries, and that the offset is
 146  * within the task area. It then calls get_long() to read a long.
 147  */
 148 static int read_long(struct task_struct * tsk, unsigned long addr,
     /* [previous][next][first][last][top][bottom][index][help] */
 149         unsigned long * result)
 150 {
 151         unsigned long low,high;
 152 
 153         if (addr > TASK_SIZE-4)
 154                 return -EIO;
 155         if ((addr & 0xfff) > PAGE_SIZE-4) {
 156                 low = get_long(tsk,addr & 0xfffffffc);
 157                 high = get_long(tsk,(addr+4) & 0xfffffffc);
 158                 switch (addr & 3) {
 159                         case 1:
 160                                 low >>= 8;
 161                                 low |= high << 24;
 162                                 break;
 163                         case 2:
 164                                 low >>= 16;
 165                                 low |= high << 16;
 166                                 break;
 167                         case 3:
 168                                 low >>= 24;
 169                                 low |= high << 8;
 170                                 break;
 171                 }
 172                 *result = low;
 173         } else
 174                 *result = get_long(tsk,addr);
 175         return 0;
 176 }
 177 
 178 /*
 179  * This routine checks the page boundaries, and that the offset is
 180  * within the task area. It then calls put_long() to write a long.
 181  */
 182 static int write_long(struct task_struct * tsk, unsigned long addr,
     /* [previous][next][first][last][top][bottom][index][help] */
 183         unsigned long data)
 184 {
 185         unsigned long low,high;
 186 
 187         if (addr > TASK_SIZE-4)
 188                 return -EIO;
 189         if ((addr & 0xfff) > PAGE_SIZE-4) {
 190                 low = get_long(tsk,addr & 0xfffffffc);
 191                 high = get_long(tsk,(addr+4) & 0xfffffffc);
 192                 switch (addr & 3) {
 193                         case 0: /* shouldn't happen, but safety first */
 194                                 low = data;
 195                                 break;
 196                         case 1:
 197                                 low &= 0x000000ff;
 198                                 low |= data << 8;
 199                                 high &= 0xffffff00;
 200                                 high |= data >> 24;
 201                                 break;
 202                         case 2:
 203                                 low &= 0x0000ffff;
 204                                 low |= data << 16;
 205                                 high &= 0xffff0000;
 206                                 high |= data >> 16;
 207                                 break;
 208                         case 3:
 209                                 low &= 0x00ffffff;
 210                                 low |= data << 24;
 211                                 high &= 0xff000000;
 212                                 high |= data >> 8;
 213                                 break;
 214                 }
 215                 put_long(tsk,addr & 0xfffffffc,low);
 216                 put_long(tsk,(addr+4) & 0xfffffffc,high);
 217         } else
 218                 put_long(tsk,addr,data);
 219         return 0;
 220 }
 221 
 222 int sys_ptrace(long request, long pid, long addr, long data)
     /* [previous][next][first][last][top][bottom][index][help] */
 223 {
 224         struct task_struct *child;
 225         int childno;
 226 
 227         if (request == 0) {
 228                 /* set the ptrace bit in the proccess flags. */
 229                 current->flags |= PF_PTRACED;
 230                 return 0;
 231         }
 232 
 233         childno = get_task(pid);
 234 
 235         if (childno < 0)
 236                 return -ESRCH;
 237         else
 238                 child = task[childno];
 239 
 240         if (child->p_pptr != current || !(child->flags & PF_PTRACED) ||
 241             child->state != TASK_STOPPED)
 242                 return -ESRCH;
 243 
 244         switch (request) {
 245         /* when I and D space are seperate, these will need to be fixed. */
 246                 case 1: /* read word at location addr. */ 
 247                 case 2: {
 248                         int tmp,res;
 249 
 250                         res = read_long(task[childno], addr, &tmp);
 251                         if (res < 0)
 252                                 return res;
 253                         verify_area((void *) data, 4);
 254                         put_fs_long(tmp,(unsigned long *) data);
 255                         return 0;
 256                 }
 257 
 258         /* read the word at location addr in the USER area. */
 259                 case 3: {
 260                         int tmp;
 261                         addr = addr >> 2; /* temporary hack. */
 262                         if (addr < 0 || addr >= 17)
 263                                 return -EIO;
 264                         verify_area((void *) data, 4);
 265                         tmp = get_stack_long(child, 4*addr - MAGICNUMBER);
 266                         put_fs_long(tmp,(unsigned long *) data);
 267                         return 0;
 268                 }
 269 
 270       /* when I and D space are seperate, this will have to be fixed. */
 271                 case 4: /* write the word at location addr. */
 272                 case 5:
 273                         return write_long(task[childno],addr,data);
 274 
 275                 case 6: /* write the word at location addr in the USER area */
 276                         addr = addr >> 2; /* temproary hack. */
 277                         if (addr < 0 || addr >= 17)
 278                                 return -EIO;
 279                         if (addr == ORIG_EAX)
 280                                 return -EIO;
 281                         if (addr == EFL) {   /* flags. */
 282                                 data &= FLAG_MASK;
 283                                 data |= get_stack_long(child, EFL*4-MAGICNUMBER)  & ~FLAG_MASK;
 284                         }
 285                         if (put_stack_long(child, 4*addr-MAGICNUMBER, data))
 286                                 return -EIO;
 287                         return 0;
 288 
 289                 case 7: { /* restart after signal. */
 290                         long tmp;
 291 
 292                         child->signal=0;
 293                         if (data > 0 && data <= NSIG)
 294                                 child->signal = 1<<(data-1);
 295                         child->state = 0;
 296         /* make sure the single step bit is not set. */
 297                         tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
 298                         put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
 299                         return 0;
 300                 }
 301 
 302 /*
 303  * make the child exit.  Best I can do is send it a sigkill. 
 304  * perhaps it should be put in the status that it want's to 
 305  * exit.
 306  */
 307                 case 8: {
 308                         long tmp;
 309 
 310                         child->state = 0;
 311                         child->signal = 1 << (SIGKILL-1);
 312         /* make sure the single step bit is not set. */
 313                         tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
 314                         put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
 315                         return 0;
 316                 }
 317 
 318                 case 9: {  /* set the trap flag. */
 319                         long tmp;
 320 
 321                         tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) | TRAP_FLAG;
 322                         put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
 323                         child->state = 0;
 324                         child->signal = 0;
 325                         if (data > 0 && data <NSIG)
 326                                 child->signal= 1<<(data-1);
 327         /* give it a chance to run. */
 328                         return 0;
 329                 }
 330 
 331                 default:
 332                         return -EIO;
 333         }
 334 }

/* [previous][next][first][last][top][bottom][index][help] */