root/arch/alpha/kernel/ptrace.c

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

DEFINITIONS

This source file includes following definitions.
  1. offset_of_register
  2. get_task
  3. get_stack_long
  4. put_stack_long
  5. get_long
  6. put_long
  7. find_extend_vma
  8. read_long
  9. write_long
  10. read_int
  11. write_int
  12. set_success
  13. set_failure
  14. set_bpt
  15. ptrace_cancel_bpt
  16. sys_ptrace
  17. syscall_trace

   1 /* ptrace.c */
   2 /* By Ross Biro 1/23/92 */
   3 /* edited by Linus Torvalds */
   4 /* mangled further by Bob Manson (manson@santafe.edu) */
   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 #undef DEBUG
  20 
  21 #ifdef DEBUG
  22 
  23   enum {
  24       DBG_MEM = (1<<0),
  25       DBG_BPT = (1<<1)
  26   };
  27 
  28   int debug_mask = DBG_BPT;
  29 
  30 # define DBG(fac,args)  {if ((fac) & debug_mask) printk args;}
  31 
  32 #else
  33 # define DBG(fac,args)
  34 #endif
  35 
  36 #define BREAKINST       0x00000080      /* call_pal bpt */
  37 
  38 /* This was determined via brute force. */
  39 #define MAGICNUM 496
  40 
  41 /*
  42  * does not yet catch signals sent when the child dies.
  43  * in exit.c or in signal.c.
  44  */
  45 
  46 /* A mapping between register number and its offset on the kernel stack.
  47  * You also need to add MAGICNUM to get past the kernel stack frame
  48  * to the actual saved user info.
  49  * The first portion is the switch_stack, then comes the pt_regs.
  50  * 320 is the size of the switch_stack area.
  51  */
  52 
  53 enum {
  54         REG_R0 =  0,
  55         REG_F0 = 32,
  56         REG_PC = 64
  57 };
  58 
  59 static int map_reg_to_offset[] = {
  60    320+0,320+8,320+16,320+24,320+32,320+40,320+48,320+56,320+64, /* 0-8 */
  61    0,8,16,24,32,40,48, /* 9-15 */
  62    320+184,320+192,320+200, /* 16-18 */
  63    320+72,320+80,320+88,320+96,320+104,320+112,320+120, /* 19-25 */
  64    320+128,320+136,320+144,320+176,320+160,-1, /* 26-31*/
  65 
  66    /* fp registers below */
  67    64,72,80,88,96,104,112,120,128,136,144,152,160,168,176,184,192,
  68    200,208,216,224,232,240,248,256,264,272,280,288,296,304,312,
  69 
  70    /* 64 = pc */
  71    320+168
  72 };
  73 
  74 static int offset_of_register(int reg_num)
     /* [previous][next][first][last][top][bottom][index][help] */
  75 {
  76         if (reg_num < 0 || reg_num > 64) {
  77                 return -1;
  78         }
  79         return map_reg_to_offset[reg_num];
  80 }
  81 
  82 /* change a pid into a task struct. */
  83 static inline struct task_struct * get_task(int pid)
     /* [previous][next][first][last][top][bottom][index][help] */
  84 {
  85         int i;
  86 
  87         for (i = 1; i < NR_TASKS; i++) {
  88                 if (task[i] != NULL && (task[i]->pid == pid))
  89                         return task[i];
  90         }
  91         return NULL;
  92 }
  93 
  94 /*
  95  * this routine will get a word off of the processes privileged stack. 
  96  * the offset is how far from the base addr as stored in the TSS.  
  97  * this routine assumes that all the privileged stacks are in our
  98  * data space.
  99  * MAGICNUM is the amount to skip to get to the actual user regs. It
 100  * was determined by brute force & asking BufElves.
 101  */   
 102 static inline long get_stack_long(struct task_struct *task, unsigned long offset)
     /* [previous][next][first][last][top][bottom][index][help] */
 103 {
 104         unsigned char *stack;
 105 
 106         stack = (unsigned char *)task->tss.ksp;
 107         stack += offset+MAGICNUM;
 108         return (*((long *)stack));
 109 }
 110 
 111 /*
 112  * this routine will put a word on the processes privileged stack. 
 113  * the offset is how far from the base addr as stored in the TSS.  
 114  * this routine assumes that all the privileged stacks are in our
 115  * data space.
 116  */
 117 static inline int put_stack_long(struct task_struct *task, unsigned long offset,
     /* [previous][next][first][last][top][bottom][index][help] */
 118         unsigned long data)
 119 {
 120         unsigned char * stack;
 121 
 122         stack = (unsigned char *) task->tss.ksp;
 123         stack += offset+MAGICNUM;
 124         *(unsigned long *) stack = data;
 125         return 0;
 126 }
 127 
 128 /*
 129  * This routine gets a long from 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 static unsigned long get_long(struct vm_area_struct * vma, unsigned long addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 135 {
 136         pgd_t * pgdir;
 137         pmd_t * pgmiddle;
 138         pte_t * pgtable;
 139         unsigned long page;
 140 
 141         DBG(DBG_MEM, ("Getting long at 0x%lx\n", addr));
 142 repeat:
 143         pgdir = pgd_offset(vma->vm_task, addr);
 144         if (pgd_none(*pgdir)) {
 145                 do_no_page(vma, addr, 0);
 146                 goto repeat;
 147         }
 148         if (pgd_bad(*pgdir)) {
 149                 printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
 150                 pgd_clear(pgdir);
 151                 return 0;
 152         }
 153         pgmiddle = pmd_offset(pgdir, addr);
 154         if (pmd_none(*pgmiddle)) {
 155                 do_no_page(vma, addr, 0);
 156                 goto repeat;
 157         }
 158         if (pmd_bad(*pgmiddle)) {
 159                 printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
 160                 pmd_clear(pgmiddle);
 161                 return 0;
 162         }
 163         pgtable = pte_offset(pgmiddle, addr);
 164         if (!pte_present(*pgtable)) {
 165                 do_no_page(vma, addr, 0);
 166                 goto repeat;
 167         }
 168         page = pte_page(*pgtable);
 169 /* this is a hack for non-kernel-mapped video buffers and similar */
 170         if (page >= high_memory)
 171                 return 0;
 172         page += addr & ~PAGE_MASK;
 173         return *(unsigned long *) page;
 174 }
 175 
 176 /*
 177  * This routine puts a long into any process space by following the page
 178  * tables. NOTE! You should check that the long isn't on a page boundary,
 179  * and that it is in the task area before calling this: this routine does
 180  * no checking.
 181  *
 182  * Now keeps R/W state of page so that a text page stays readonly
 183  * even if a debugger scribbles breakpoints into it.  -M.U-
 184  */
 185 static void put_long(struct vm_area_struct * vma, unsigned long addr,
     /* [previous][next][first][last][top][bottom][index][help] */
 186                      unsigned long data)
 187 {
 188         pgd_t *pgdir;
 189         pmd_t *pgmiddle;
 190         pte_t *pgtable;
 191         unsigned long page;
 192 
 193 repeat:
 194         pgdir = pgd_offset(vma->vm_task, addr);
 195         if (!pgd_present(*pgdir)) {
 196                 do_no_page(vma, addr, 1);
 197                 goto repeat;
 198         }
 199         if (pgd_bad(*pgdir)) {
 200                 printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
 201                 pgd_clear(pgdir);
 202                 return;
 203         }
 204         pgmiddle = pmd_offset(pgdir, addr);
 205         if (pmd_none(*pgmiddle)) {
 206                 do_no_page(vma, addr, 1);
 207                 goto repeat;
 208         }
 209         if (pmd_bad(*pgmiddle)) {
 210                 printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
 211                 pmd_clear(pgmiddle);
 212                 return;
 213         }
 214         pgtable = pte_offset(pgmiddle, addr);
 215         if (!pte_present(*pgtable)) {
 216                 do_no_page(vma, addr, 1);
 217                 goto repeat;
 218         }
 219         page = pte_page(*pgtable);
 220         if (!pte_write(*pgtable)) {
 221                 do_wp_page(vma, addr, 1);
 222                 goto repeat;
 223         }
 224 /* this is a hack for non-kernel-mapped video buffers and similar */
 225         if (page < high_memory) {
 226                 page += addr & ~PAGE_MASK;
 227                 *(unsigned long *) page = data;
 228         }
 229 /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
 230 /* this should also re-instate whatever read-only mode there was before */
 231         *pgtable = pte_mkdirty(mk_pte(page, vma->vm_page_prot));
 232         invalidate();
 233 }
 234 
 235 static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 236 {
 237         struct vm_area_struct * vma;
 238 
 239         addr &= PAGE_MASK;
 240         vma = find_vma(tsk,addr);
 241         if (!vma)
 242                 return NULL;
 243         if (vma->vm_start <= addr)
 244                 return vma;
 245         if (!(vma->vm_flags & VM_GROWSDOWN))
 246                 return NULL;
 247         if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
 248                 return NULL;
 249         vma->vm_offset -= vma->vm_start - addr;
 250         vma->vm_start = addr;
 251         return vma;
 252 }
 253 
 254 /*
 255  * This routine checks the page boundaries, and that the offset is
 256  * within the task area. It then calls get_long() to read a long.
 257  */
 258 static int read_long(struct task_struct * tsk, unsigned long addr,
     /* [previous][next][first][last][top][bottom][index][help] */
 259                      unsigned long * result)
 260 {
 261         struct vm_area_struct * vma = find_extend_vma(tsk, addr);
 262 
 263         DBG(DBG_MEM, ("in read_long\n"));
 264         if (!vma) {
 265                 printk("Unable to find vma for addr 0x%lx\n",addr);
 266                 return -EIO;
 267         }
 268         if ((addr & ~PAGE_MASK) > (PAGE_SIZE-sizeof(long))) {
 269                 unsigned long low,high;
 270                 struct vm_area_struct * vma_high = vma;
 271 
 272                 if (addr + sizeof(long) >= vma->vm_end) {
 273                         vma_high = vma->vm_next;
 274                         if (!vma_high || vma_high->vm_start != vma->vm_end)
 275                                 return -EIO;
 276                 }
 277                 low = get_long(vma, addr & ~(sizeof(long)-1));
 278                 high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
 279                 switch (addr & (sizeof(long)-1)) {
 280                         case 1:
 281                                 low >>= 8;
 282                                 low |= high << 56;
 283                                 break;
 284                         case 2:
 285                                 low >>= 16;
 286                                 low |= high << 48;
 287                                 break;
 288                         case 3:
 289                                 low >>= 24;
 290                                 low |= high << 40;
 291                                 break;
 292                         case 4:
 293                                 low >>= 32;
 294                                 low |= high << 32;
 295                                 break;
 296                         case 5:
 297                                 low >>= 40;
 298                                 low |= high << 24;
 299                                 break;
 300                         case 6:
 301                                 low >>= 48;
 302                                 low |= high << 16;
 303                                 break;
 304                         case 7:
 305                                 low >>= 56;
 306                                 low |= high << 8;
 307                                 break;
 308                 }
 309                 *result = low;
 310         } else {
 311                 long l =get_long(vma, addr);
 312 
 313                 DBG(DBG_MEM, ("value is 0x%lx\n",l));
 314                 *result = l;
 315         }
 316         return 0;
 317 }
 318 
 319 /*
 320  * This routine checks the page boundaries, and that the offset is
 321  * within the task area. It then calls put_long() to write a long.
 322  */
 323 static int write_long(struct task_struct * tsk, unsigned long addr,
     /* [previous][next][first][last][top][bottom][index][help] */
 324         unsigned long data)
 325 {
 326         struct vm_area_struct * vma = find_extend_vma(tsk, addr);
 327 
 328         if (!vma)
 329                 return -EIO;
 330         if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
 331                 unsigned long low,high;
 332                 struct vm_area_struct * vma_high = vma;
 333 
 334                 if (addr + sizeof(long) >= vma->vm_end) {
 335                         vma_high = vma->vm_next;
 336                         if (!vma_high || vma_high->vm_start != vma->vm_end)
 337                                 return -EIO;
 338                 }
 339                 low = get_long(vma, addr & ~(sizeof(long)-1));
 340                 high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
 341                 switch (addr & (sizeof(long)-1)) {
 342                         case 0: /* shouldn't happen, but safety first */
 343                                 low = data;
 344                                 break;
 345                         case 1:
 346                                 low &= 0x00000000000000ffL;
 347                                 low |= data << 8;
 348                                 high &= ~0x000000000000ffL;
 349                                 high |= data >> 56;
 350                                 break;
 351                         case 2:
 352                                 low &= 0x000000000000ffffL;
 353                                 low |= data << 16;
 354                                 high &= ~0x0000000000ffffL;
 355                                 high |= data >> 48;
 356                                 break;
 357                         case 3:
 358                                 low &= 0x0000000000ffffffL;
 359                                 low |= data << 24;
 360                                 high &= ~0x00000000ffffffL;
 361                                 high |= data >> 40;
 362                                 break;
 363                         case 4:
 364                                 low &= 0x00000000ffffffffL;
 365                                 low |= data << 32;
 366                                 high &= ~0x000000ffffffffL;
 367                                 high |= data >> 32;
 368                                 break;
 369 
 370                         case 5:
 371                                 low &= 0x000000ffffffffffL;
 372                                 low |= data << 40;
 373                                 high &= ~0x0000ffffffffffL;
 374                                 high |= data >> 24;
 375                                 break;
 376                         case 6:
 377                                 low &= 0x0000ffffffffffffL;
 378                                 low |= data << 48;
 379                                 high &= ~0x00ffffffffffffL;
 380                                 high |= data >> 16;
 381                                 break;
 382                         case 7:
 383                                 low &= 0x00ffffffffffffffL;
 384                                 low |= data << 56;
 385                                 high &= ~0xffffffffffffffL;
 386                                 high |= data >> 8;
 387                                 break;
 388                 }
 389                 put_long(vma, addr & ~(sizeof(long)-1),low);
 390                 put_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high);
 391         } else
 392                 put_long(vma, addr, data);
 393         return 0;
 394 }
 395 
 396 /*
 397  * Read a 32bit int from address space TSK.
 398  */
 399 static int read_int(struct task_struct * tsk, unsigned long addr, unsigned int *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 400 {
 401         unsigned long l, align;
 402         int res;
 403 
 404         align = addr & 0x7;
 405         addr &= ~0x7;
 406 
 407         res = read_long(tsk, addr, &l);
 408         if (res < 0)
 409           return res;
 410 
 411         if (align == 0) {
 412                 *data = l;
 413         } else {
 414                 *data = l >> 32;
 415         }
 416         return 0;
 417 }
 418 
 419 /*
 420  * Write a 32bit word to address space TSK.
 421  *
 422  * For simplicity, do a read-modify-write of the 64bit word that
 423  * contains the 32bit word that we are about to write.
 424  */
 425 static int write_int(struct task_struct * tsk, unsigned long addr, unsigned int data)
     /* [previous][next][first][last][top][bottom][index][help] */
 426 {
 427         unsigned long l, align;
 428         int res;
 429 
 430         align = addr & 0x7;
 431         addr &= ~0x7;
 432 
 433         res = read_long(tsk, addr, &l);
 434         if (res < 0)
 435           return res;
 436 
 437         if (align == 0) {
 438                 l = (l & 0xffffffff00000000UL) | ((unsigned long) data <<  0);
 439         } else {
 440                 l = (l & 0x00000000ffffffffUL) | ((unsigned long) data << 32);
 441         }
 442         return write_long(tsk, addr, l);
 443 }
 444 
 445 /*
 446  * Uh, this does ugly stuff. It stores the specified value in the a3
 447  * register. entry.S will swap a3 and the returned value from
 448  * sys_ptrace() before returning to the user.
 449  */
 450 
 451 static inline void set_success(struct pt_regs *regs,long resval)
     /* [previous][next][first][last][top][bottom][index][help] */
 452 {
 453         regs->r19 = resval;
 454 }
 455 
 456 /*
 457  * This doesn't do diddly, actually--if the value returned from 
 458  * sys_ptrace() is != 0, it sets things up properly.
 459  */
 460 
 461 static inline void set_failure(struct pt_regs *regs, long errcode)
     /* [previous][next][first][last][top][bottom][index][help] */
 462 {
 463         regs->r19 = 0;
 464 }
 465 
 466 /*
 467  * Set breakpoint.
 468  */
 469 static int set_bpt(struct task_struct *child)
     /* [previous][next][first][last][top][bottom][index][help] */
 470 {
 471         int displ, i, res, reg_b, off, nsaved = 0;
 472         u32 insn, op_code;
 473         unsigned long pc;
 474 
 475         pc  = get_stack_long(child, map_reg_to_offset[REG_PC]);
 476         res = read_int(child, pc, &insn);
 477         if (res < 0)
 478           return res;
 479 
 480         op_code = insn >> 26;
 481         if (op_code >= 0x30) {
 482                 /*
 483                  * It's a branch: instead of trying to figure out
 484                  * whether the branch will be taken or not, we'll put
 485                  * a breakpoint at either location.  This is simpler,
 486                  * more reliable, and probably not a whole lot slower
 487                  * than the alternative approach of emulating the
 488                  * branch (emulation can be tricky for fp branches).
 489                  */
 490                 displ = ((s32)(insn << 11)) >> 9;
 491                 child->debugreg[nsaved++] = pc + 4;
 492                 if (displ)                      /* guard against unoptimized code */
 493                   child->debugreg[nsaved++] = pc + 4 + displ;
 494                 DBG(DBG_BPT, ("execing branch\n"));
 495         } else if (op_code == 0x1a) {
 496                 reg_b = (insn >> 16) & 0x1f;
 497                 off = offset_of_register(reg_b);
 498                 if (off >= 0) {
 499                         child->debugreg[nsaved++] = get_stack_long(child, off);
 500                 } else {
 501                         /* $31 (aka zero) doesn't have a stack-slot */
 502                         if (reg_b == 31) {
 503                                 child->debugreg[nsaved++] = 0;
 504                         } else {
 505                                 return -EIO;
 506                         }
 507                 }
 508                 DBG(DBG_BPT, ("execing jump\n"));
 509         } else {
 510                 child->debugreg[nsaved++] = pc + 4;
 511                 DBG(DBG_BPT, ("execing normal insn\n"));
 512         }
 513 
 514         /* install breakpoints: */
 515         for (i = 0; i < nsaved; ++i) {
 516                 res = read_int(child, child->debugreg[i], &insn);
 517                 if (res < 0)
 518                   return res;
 519                 child->debugreg[i + 2] = insn;
 520                 DBG(DBG_BPT, ("    -> next_pc=%lx\n", child->debugreg[i]));
 521                 res = write_int(child, child->debugreg[i], BREAKINST);
 522                 if (res < 0)
 523                   return res;
 524         }
 525         child->debugreg[4] = nsaved;
 526         return 0;
 527 }
 528 
 529 int ptrace_cancel_bpt(struct task_struct *child)
     /* [previous][next][first][last][top][bottom][index][help] */
 530 {
 531         int i, nsaved = child->debugreg[4];
 532 
 533         child->debugreg[4] = 0;
 534 
 535         if (nsaved > 2) {
 536             printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
 537             nsaved = 2;
 538         }
 539 
 540         for (i = 0; i < nsaved; ++i) {
 541                 write_int(child, child->debugreg[i], child->debugreg[i + 2]);
 542         }
 543         return nsaved;
 544 }
 545 
 546 asmlinkage long sys_ptrace(long request, long pid, long addr, long data, int a4, int a5,
     /* [previous][next][first][last][top][bottom][index][help] */
 547                            struct pt_regs regs)
 548 {
 549         struct task_struct *child;
 550         struct user * dummy;
 551         int res;
 552 
 553         dummy = NULL;
 554 
 555         DBG(DBG_MEM, ("request=%ld pid=%ld addr=0x%lx data=0x%lx\n",request,pid,addr,data));
 556         set_success(&regs,0);
 557         if (request == PTRACE_TRACEME) {
 558                 /* are we already being traced? */
 559                 if (current->flags & PF_PTRACED) {
 560                         set_failure(&regs,-EPERM);
 561                         return -EPERM;
 562                 }
 563                 /* set the ptrace bit in the process flags. */
 564                 current->flags |= PF_PTRACED;
 565                 return 0;
 566         }
 567         if (pid == 1) {         /* you may not mess with init */
 568                 set_failure(&regs,-EPERM);
 569                 return -EPERM;
 570         }
 571         if (!(child = get_task(pid))) {
 572                 set_failure(&regs,-ESRCH);
 573                 return -ESRCH;
 574         }
 575         if (request == PTRACE_ATTACH) {
 576                 if (child == current) {
 577                         set_failure(&regs,-EPERM);
 578                         return -EPERM;
 579                 }
 580                 if ((!child->dumpable ||
 581                      (current->uid != child->euid) ||
 582                      (current->uid != child->uid) ||
 583                      (current->gid != child->egid) ||
 584                      (current->gid != child->gid)) && !suser()) {
 585                         set_failure(&regs,-EPERM);
 586                         return -EPERM;
 587                 }
 588                 /* the same process cannot be attached many times */
 589                 if (child->flags & PF_PTRACED) {
 590                         set_failure(&regs,-EPERM);
 591                         return -EPERM;
 592                 }
 593                 child->flags |= PF_PTRACED;
 594                 if (child->p_pptr != current) {
 595                         REMOVE_LINKS(child);
 596                         child->p_pptr = current;
 597                         SET_LINKS(child);
 598                 }
 599                 send_sig(SIGSTOP, child, 1);
 600                 return 0;
 601         }
 602         if (!(child->flags & PF_PTRACED)) {
 603                 DBG(DBG_MEM, ("child not traced\n"));
 604                 set_failure(&regs,-ESRCH);
 605                 return -ESRCH;
 606         }
 607         if (child->state != TASK_STOPPED) {
 608                 DBG(DBG_MEM, ("child process not stopped\n"));
 609                 if (request != PTRACE_KILL) {
 610                         set_failure(&regs,-ESRCH);
 611                         return -ESRCH;
 612                 }
 613         }
 614         if (child->p_pptr != current) {
 615                 DBG(DBG_MEM, ("child not parent of this process\n"));
 616                 set_failure(&regs,-ESRCH);
 617                 return -ESRCH;
 618         }
 619 
 620         switch (request) {
 621         /* when I and D space are separate, these will need to be fixed. */
 622                 case PTRACE_PEEKTEXT: /* read word at location addr. */ 
 623                 case PTRACE_PEEKDATA: {
 624                         unsigned long tmp;
 625                         int res;
 626 
 627                         DBG(DBG_MEM, ("doing request at addr 0x%lx\n",addr));
 628                         res = read_long(child, addr, &tmp);
 629                         if (res < 0) {
 630                                 set_failure(&regs,res);
 631                                 return res;
 632                         } else {
 633                                 set_success(&regs,tmp);
 634                                 return 0;
 635                         }
 636                 }
 637 
 638         /* read the word at location addr in the USER area. */
 639                 case PTRACE_PEEKUSR: {
 640                         /* We only allow access to registers. */
 641                         unsigned long tmp;
 642 
 643                         tmp = 0;  /* Default return condition */
 644                         if (addr == 30) {
 645                                 /* stack pointer */
 646                                 tmp=child->tss.usp;
 647                         } else {
 648 #ifdef DEBUG
 649                                 int reg = addr;
 650 #endif
 651                                 addr = offset_of_register(addr);
 652                                 if (addr < 0) {
 653                                         set_failure(&regs, -EIO);
 654                                         return -EIO;
 655                                 }
 656                                 tmp = get_stack_long(child, addr);
 657                                 DBG(DBG_MEM, ("%d = reg 0x%lx=tmp\n",reg,tmp));
 658                         }
 659                         set_success(&regs,tmp);
 660                         return 0;
 661                 }
 662 
 663       /* when I and D space are separate, this will have to be fixed. */
 664                 case PTRACE_POKETEXT: /* write the word at location addr. */
 665                 case PTRACE_POKEDATA: {
 666                         long res = write_long(child,addr,data);
 667                         if (res) {
 668                                 set_failure(&regs,res);
 669                         }
 670                         return res;
 671                 }
 672 
 673                 case PTRACE_POKEUSR: /* write the specified register */
 674                   {
 675                           long res;
 676                           addr = offset_of_register(addr);
 677                           if(addr < 0) {
 678                                   set_failure(&regs,-EIO);
 679                                   return -EIO;
 680                           }
 681                           res = put_stack_long(child, addr, data);
 682                           if (res) {
 683                                   set_failure(&regs,res);
 684                           }
 685                           return res;
 686                   }
 687 
 688                 case PTRACE_SYSCALL: /* continue and stop at next 
 689                                         (return from) syscall */
 690                 case PTRACE_CONT: { /* restart after signal. */
 691                         if ((unsigned long) data > NSIG) {
 692                                 set_failure(&regs,-EIO);
 693                                 return -EIO;
 694                         }
 695                         if (request == PTRACE_SYSCALL)
 696                                 child->flags |= PF_TRACESYS;
 697                         else
 698                                 child->flags &= ~PF_TRACESYS;
 699                         child->exit_code = data;
 700                         wake_up_process(child);
 701         /* make sure single-step breakpoint is gone. */
 702                         ptrace_cancel_bpt(child);
 703                         set_success(&regs,data);
 704                         return 0;
 705                 }
 706 
 707 /*
 708  * make the child exit.  Best I can do is send it a sigkill. 
 709  * perhaps it should be put in the status that it wants to 
 710  * exit.
 711  */
 712                 case PTRACE_KILL: {
 713                         wake_up_process(child);
 714                         child->exit_code = SIGKILL;
 715         /* make sure single-step breakpoint is gone. */
 716                         ptrace_cancel_bpt(child);
 717                         return 0;
 718                 }
 719 
 720                 case PTRACE_SINGLESTEP: {  /* execute signle instruction. */
 721                         if ((unsigned long) data > NSIG) {
 722                                 set_failure(&regs,-EIO);
 723                                 return -EIO;
 724                         }
 725                         res = set_bpt(child);
 726                         if (res < 0) {
 727                                 return res;
 728                         }
 729                         child->flags &= ~PF_TRACESYS;
 730                         wake_up_process(child);
 731                         child->exit_code = data;
 732         /* give it a chance to run. */
 733                         return 0;
 734                 }
 735 
 736                 case PTRACE_DETACH: { /* detach a process that was attached. */
 737                         if ((unsigned long) data > NSIG) {
 738                                 set_failure(&regs,-EIO);
 739                                 return -EIO;
 740                         }
 741                         child->flags &= ~(PF_PTRACED|PF_TRACESYS);
 742                         wake_up_process(child);
 743                         child->exit_code = data;
 744                         REMOVE_LINKS(child);
 745                         child->p_pptr = child->p_opptr;
 746                         SET_LINKS(child);
 747         /* make sure single-step breakpoint is gone. */
 748                         ptrace_cancel_bpt(child);
 749                         return 0;
 750                 }
 751 
 752                 default:
 753                   set_failure(&regs,-EIO);
 754                   return -EIO;
 755           }
 756 }
 757 
 758 asmlinkage void syscall_trace(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 759 {
 760         if ((current->flags & (PF_PTRACED|PF_TRACESYS))
 761                         != (PF_PTRACED|PF_TRACESYS))
 762                 return;
 763         current->exit_code = SIGTRAP;
 764         current->state = TASK_STOPPED;
 765         notify_parent(current);
 766         schedule();
 767         /*
 768          * this isn't the same as continuing with a signal, but it will do
 769          * for normal use.  strace only continues with a signal if the
 770          * stopping signal is not SIGTRAP.  -brl
 771          */
 772         if (current->exit_code)
 773                 current->signal |= (1 << (current->exit_code - 1));
 774         current->exit_code = 0;
 775 }

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