root/arch/alpha/kernel/ptrace.c

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

DEFINITIONS

This source file includes following definitions.
  1. get_task
  2. get_reg
  3. put_reg
  4. get_long
  5. put_long
  6. find_extend_vma
  7. read_long
  8. write_long
  9. read_int
  10. write_int
  11. ptrace_set_bpt
  12. ptrace_cancel_bpt
  13. sys_ptrace
  14. 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 /* more mutilation by David Mosberger (davidm@azstarnet.com) */
   6 
   7 #include <linux/head.h>
   8 #include <linux/kernel.h>
   9 #include <linux/sched.h>
  10 #include <linux/mm.h>
  11 #include <linux/errno.h>
  12 #include <linux/ptrace.h>
  13 #include <linux/user.h>
  14 #include <linux/debugreg.h>
  15 
  16 #include <asm/segment.h>
  17 #include <asm/pgtable.h>
  18 #include <asm/system.h>
  19 
  20 #undef DEBUG
  21 
  22 #ifdef DEBUG
  23 
  24   enum {
  25       DBG_MEM           = (1<<0),
  26       DBG_BPT           = (1<<1),
  27       DBG_MEM_ALL       = (1<<2)
  28   };
  29 
  30   int debug_mask = DBG_BPT;
  31 
  32 # define DBG(fac,args)  {if ((fac) & debug_mask) printk args;}
  33 
  34 #else
  35 # define DBG(fac,args)
  36 #endif
  37 
  38 #define BREAKINST       0x00000080      /* call_pal bpt */
  39 
  40 /*
  41  * does not yet catch signals sent when the child dies.
  42  * in exit.c or in signal.c.
  43  */
  44 
  45 /*
  46  * Processes always block with the following stack-layout:
  47  *
  48  *  +================================+ --------------------------
  49  *  | PALcode saved frame (ps, pc,   | ^                      ^
  50  *  | gp, a0, a1, a2)                | |                      |
  51  *  +================================+ | struct pt_regs       |
  52  *  |                                | |                      |
  53  *  | frame generated by SAVE_ALL    | |                      |
  54  *  |                                | v                      | P
  55  *  +================================+                        | A
  56  *  |                                | ^                      | G
  57  *  | frame saved by do_switch_stack | | struct switch_stack  | E
  58  *  |                                | v                      | _
  59  *  +================================+                        | S
  60  *  |                                |                        | I
  61  *  |                                |                        | Z
  62  *  /                                /                        | E
  63  *  /                                /                        |
  64  *  |                                |                        |
  65  *  |                                |                        |
  66  *  |                                |                        v
  67  *  +================================+ <-------------------------
  68  *                                      task->kernel_stack_page
  69  */
  70 #define PT_REG(reg)     (PAGE_SIZE - sizeof(struct pt_regs)     \
  71                          + (long)&((struct pt_regs *)0)->reg)
  72 #define SW_REG(reg)     (PAGE_SIZE - sizeof(struct pt_regs)     \
  73                          - sizeof(struct switch_stack)          \
  74                          + (long)&((struct switch_stack *)0)->reg)
  75 /* 
  76  * The following table maps a register index into the stack offset at
  77  * which the register is saved.  Register indices are 0-31 for integer
  78  * regs, 32-63 for fp regs, and 64 for the pc.  Notice that sp and
  79  * zero have no stack-slot and need to be treated specially (see
  80  * get_reg/put_reg below).
  81  */
  82 enum {
  83         REG_R0 = 0, REG_F0 = 32, REG_PC = 64
  84 };
  85 
  86 static unsigned short regoff[] = {
  87         PT_REG(    r0), PT_REG(    r1), PT_REG(    r2), PT_REG(   r3),
  88         PT_REG(    r4), PT_REG(    r5), PT_REG(    r6), PT_REG(   r7),
  89         PT_REG(    r8), SW_REG(    r9), SW_REG(   r10), SW_REG(  r11),
  90         SW_REG(   r12), SW_REG(   r13), SW_REG(   r14), SW_REG(  r15),
  91         PT_REG(   r16), PT_REG(   r17), PT_REG(   r18), PT_REG(  r19),
  92         PT_REG(   r20), PT_REG(   r21), PT_REG(   r22), PT_REG(  r23),
  93         PT_REG(   r24), PT_REG(   r25), PT_REG(   r26), PT_REG(  r27),
  94         PT_REG(   r28), PT_REG(    gp),            -1,             -1,
  95         SW_REG(fp[ 0]), SW_REG(fp[ 1]), SW_REG(fp[ 2]), SW_REG(fp[ 3]),
  96         SW_REG(fp[ 4]), SW_REG(fp[ 5]), SW_REG(fp[ 6]), SW_REG(fp[ 7]),
  97         SW_REG(fp[ 8]), SW_REG(fp[ 9]), SW_REG(fp[10]), SW_REG(fp[11]),
  98         SW_REG(fp[12]), SW_REG(fp[13]), SW_REG(fp[14]), SW_REG(fp[15]),
  99         SW_REG(fp[16]), SW_REG(fp[17]), SW_REG(fp[18]), SW_REG(fp[19]),
 100         SW_REG(fp[20]), SW_REG(fp[21]), SW_REG(fp[22]), SW_REG(fp[23]),
 101         SW_REG(fp[24]), SW_REG(fp[25]), SW_REG(fp[26]), SW_REG(fp[27]),
 102         SW_REG(fp[28]), SW_REG(fp[29]), SW_REG(fp[30]), SW_REG(fp[31]),
 103         PT_REG(    pc)
 104 };
 105 
 106 static long zero;
 107 
 108 
 109 /* change a pid into a task struct. */
 110 static inline struct task_struct * get_task(int pid)
     /* [previous][next][first][last][top][bottom][index][help] */
 111 {
 112         int i;
 113 
 114         for (i = 1; i < NR_TASKS; i++) {
 115                 if (task[i] != NULL && (task[i]->pid == pid))
 116                         return task[i];
 117         }
 118         return NULL;
 119 }
 120 
 121 /*
 122  * Get contents of register REGNO in task TASK.
 123  */
 124 static inline long get_reg(struct task_struct * task, long regno)
     /* [previous][next][first][last][top][bottom][index][help] */
 125 {
 126         long *addr;
 127 
 128         if (regno == 30) {
 129                 addr = &task->tss.usp;
 130         } else if (regno == 31) {
 131                 zero = 0;
 132                 addr = &zero;
 133         } else {
 134                 addr = (long *) (task->kernel_stack_page + regoff[regno]);
 135         }
 136         return *addr;
 137 }
 138 
 139 /*
 140  * Write contents of register REGNO in task TASK.
 141  */
 142 static inline int put_reg(struct task_struct *task, long regno, long data)
     /* [previous][next][first][last][top][bottom][index][help] */
 143 {
 144         long *addr, zero;
 145 
 146         if (regno == 30) {
 147                 addr = &task->tss.usp;
 148         } else if (regno == 31) {
 149                 addr = &zero;
 150         } else {
 151                 addr = (long *) (task->kernel_stack_page + regoff[regno]);
 152         }
 153         *addr = data;
 154         return 0;
 155 }
 156 
 157 /*
 158  * This routine gets a long from any process space by following the page
 159  * tables. NOTE! You should check that the long isn't on a page boundary,
 160  * and that it is in the task area before calling this: this routine does
 161  * no checking.
 162  */
 163 static unsigned long get_long(struct vm_area_struct * vma, unsigned long addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 164 {
 165         pgd_t * pgdir;
 166         pmd_t * pgmiddle;
 167         pte_t * pgtable;
 168         unsigned long page;
 169 
 170         DBG(DBG_MEM_ALL, ("getting long at 0x%lx\n", addr));
 171 repeat:
 172         pgdir = pgd_offset(vma->vm_task, addr);
 173         if (pgd_none(*pgdir)) {
 174                 do_no_page(vma, addr, 0);
 175                 goto repeat;
 176         }
 177         if (pgd_bad(*pgdir)) {
 178                 printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
 179                 pgd_clear(pgdir);
 180                 return 0;
 181         }
 182         pgmiddle = pmd_offset(pgdir, addr);
 183         if (pmd_none(*pgmiddle)) {
 184                 do_no_page(vma, addr, 0);
 185                 goto repeat;
 186         }
 187         if (pmd_bad(*pgmiddle)) {
 188                 printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
 189                 pmd_clear(pgmiddle);
 190                 return 0;
 191         }
 192         pgtable = pte_offset(pgmiddle, addr);
 193         if (!pte_present(*pgtable)) {
 194                 do_no_page(vma, addr, 0);
 195                 goto repeat;
 196         }
 197         page = pte_page(*pgtable);
 198 /* this is a hack for non-kernel-mapped video buffers and similar */
 199         if (page >= high_memory)
 200                 return 0;
 201         page += addr & ~PAGE_MASK;
 202         return *(unsigned long *) page;
 203 }
 204 
 205 /*
 206  * This routine puts a long into any process space by following the page
 207  * tables. NOTE! You should check that the long isn't on a page boundary,
 208  * and that it is in the task area before calling this: this routine does
 209  * no checking.
 210  *
 211  * Now keeps R/W state of page so that a text page stays readonly
 212  * even if a debugger scribbles breakpoints into it.  -M.U-
 213  */
 214 static void put_long(struct vm_area_struct * vma, unsigned long addr,
     /* [previous][next][first][last][top][bottom][index][help] */
 215                      unsigned long data)
 216 {
 217         pgd_t *pgdir;
 218         pmd_t *pgmiddle;
 219         pte_t *pgtable;
 220         unsigned long page;
 221 
 222 repeat:
 223         pgdir = pgd_offset(vma->vm_task, addr);
 224         if (!pgd_present(*pgdir)) {
 225                 do_no_page(vma, addr, 1);
 226                 goto repeat;
 227         }
 228         if (pgd_bad(*pgdir)) {
 229                 printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
 230                 pgd_clear(pgdir);
 231                 return;
 232         }
 233         pgmiddle = pmd_offset(pgdir, addr);
 234         if (pmd_none(*pgmiddle)) {
 235                 do_no_page(vma, addr, 1);
 236                 goto repeat;
 237         }
 238         if (pmd_bad(*pgmiddle)) {
 239                 printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
 240                 pmd_clear(pgmiddle);
 241                 return;
 242         }
 243         pgtable = pte_offset(pgmiddle, addr);
 244         if (!pte_present(*pgtable)) {
 245                 do_no_page(vma, addr, 1);
 246                 goto repeat;
 247         }
 248         page = pte_page(*pgtable);
 249         if (!pte_write(*pgtable)) {
 250                 do_wp_page(vma, addr, 1);
 251                 goto repeat;
 252         }
 253 /* this is a hack for non-kernel-mapped video buffers and similar */
 254         if (page < high_memory)
 255                 *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
 256 /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
 257 /* this should also re-instate whatever read-only mode there was before */
 258         set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
 259         invalidate();
 260 }
 261 
 262 static struct vm_area_struct * find_extend_vma(struct task_struct * tsk,
     /* [previous][next][first][last][top][bottom][index][help] */
 263                                                unsigned long addr)
 264 {
 265         struct vm_area_struct * vma;
 266 
 267         addr &= PAGE_MASK;
 268         vma = find_vma(tsk,addr);
 269         if (!vma)
 270                 return NULL;
 271         if (vma->vm_start <= addr)
 272                 return vma;
 273         if (!(vma->vm_flags & VM_GROWSDOWN))
 274                 return NULL;
 275         if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
 276                 return NULL;
 277         vma->vm_offset -= vma->vm_start - addr;
 278         vma->vm_start = addr;
 279         return vma;
 280 }
 281 
 282 /*
 283  * This routine checks the page boundaries, and that the offset is
 284  * within the task area. It then calls get_long() to read a long.
 285  */
 286 static int read_long(struct task_struct * tsk, unsigned long addr,
     /* [previous][next][first][last][top][bottom][index][help] */
 287                      unsigned long * result)
 288 {
 289         struct vm_area_struct * vma = find_extend_vma(tsk, addr);
 290 
 291         DBG(DBG_MEM_ALL, ("in read_long\n"));
 292         if (!vma) {
 293                 printk("Unable to find vma for addr 0x%lx\n",addr);
 294                 return -EIO;
 295         }
 296         if ((addr & ~PAGE_MASK) > (PAGE_SIZE - sizeof(long))) {
 297                 struct vm_area_struct * vma_high = vma;
 298                 unsigned long low, align;
 299 
 300                 if (addr + sizeof(long) >= vma->vm_end) {
 301                         vma_high = vma->vm_next;
 302                         if (!vma_high || vma_high->vm_start != vma->vm_end)
 303                                 return -EIO;
 304                 }
 305                 align = addr & (sizeof(long) - 1);
 306                 addr -= align;
 307                 low = get_long(vma, addr);
 308                 if (align) {
 309                     unsigned long high;
 310 
 311                     high = get_long(vma_high, addr + sizeof(long));
 312                     low >>= align * 8;
 313                     low  |= high << (64 - align * 8);
 314                 }
 315                 *result = low;
 316         } else {
 317                 long l = get_long(vma, addr);
 318 
 319                 DBG(DBG_MEM_ALL, ("value is 0x%lx\n", l));
 320                 *result = l;
 321         }
 322         return 0;
 323 }
 324 
 325 /*
 326  * This routine checks the page boundaries, and that the offset is
 327  * within the task area. It then calls put_long() to write a long.
 328  */
 329 static int write_long(struct task_struct * tsk, unsigned long addr,
     /* [previous][next][first][last][top][bottom][index][help] */
 330         unsigned long data)
 331 {
 332         struct vm_area_struct * vma = find_extend_vma(tsk, addr);
 333 
 334         if (!vma)
 335                 return -EIO;
 336         if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
 337                 unsigned long low, high, align;
 338                 struct vm_area_struct * vma_high = vma;
 339 
 340                 if (addr + sizeof(long) >= vma->vm_end) {
 341                         vma_high = vma->vm_next;
 342                         if (!vma_high || vma_high->vm_start != vma->vm_end)
 343                                 return -EIO;
 344                 }
 345                 align = addr & (sizeof(long) - 1);
 346                 addr -= align;
 347                 low  = get_long(vma, addr);
 348                 high = get_long(vma_high, addr + sizeof(long));
 349                 low  &= ~0UL >> (64 - align * 8);
 350                 high &= ~0UL << (align * 8);
 351                 low  |= data << (align * 8);
 352                 high |= data >> (64 - align * 8);
 353                 put_long(vma, addr, low);
 354                 put_long(vma_high, addr + sizeof(long), high);
 355         } else
 356                 put_long(vma, addr, data);
 357         return 0;
 358 }
 359 
 360 /*
 361  * Read a 32bit int from address space TSK.
 362  */
 363 static int read_int(struct task_struct * tsk, unsigned long addr,
     /* [previous][next][first][last][top][bottom][index][help] */
 364                     unsigned int *data)
 365 {
 366         unsigned long l, align;
 367         int res;
 368 
 369         align = addr & 0x7;
 370         addr &= ~0x7;
 371 
 372         res = read_long(tsk, addr, &l);
 373         if (res < 0)
 374           return res;
 375 
 376         if (align == 0) {
 377                 *data = l;
 378         } else {
 379                 *data = l >> 32;
 380         }
 381         return 0;
 382 }
 383 
 384 /*
 385  * Write a 32bit word to address space TSK.
 386  *
 387  * For simplicity, do a read-modify-write of the 64bit word that
 388  * contains the 32bit word that we are about to write.
 389  */
 390 static int write_int(struct task_struct * tsk, unsigned long addr,
     /* [previous][next][first][last][top][bottom][index][help] */
 391                      unsigned int data)
 392 {
 393         unsigned long l, align;
 394         int res;
 395 
 396         align = addr & 0x7;
 397         addr &= ~0x7;
 398 
 399         res = read_long(tsk, addr, &l);
 400         if (res < 0)
 401           return res;
 402 
 403         if (align == 0) {
 404                 l = (l & 0xffffffff00000000UL) | ((unsigned long) data <<  0);
 405         } else {
 406                 l = (l & 0x00000000ffffffffUL) | ((unsigned long) data << 32);
 407         }
 408         return write_long(tsk, addr, l);
 409 }
 410 
 411 /*
 412  * Set breakpoint.
 413  */
 414 int ptrace_set_bpt(struct task_struct * child)
     /* [previous][next][first][last][top][bottom][index][help] */
 415 {
 416         int displ, i, res, reg_b, nsaved = 0;
 417         u32 insn, op_code;
 418         unsigned long pc;
 419 
 420         pc  = get_reg(child, REG_PC);
 421         res = read_int(child, pc, &insn);
 422         if (res < 0)
 423           return res;
 424 
 425         op_code = insn >> 26;
 426         if (op_code >= 0x30) {
 427                 /*
 428                  * It's a branch: instead of trying to figure out
 429                  * whether the branch will be taken or not, we'll put
 430                  * a breakpoint at either location.  This is simpler,
 431                  * more reliable, and probably not a whole lot slower
 432                  * than the alternative approach of emulating the
 433                  * branch (emulation can be tricky for fp branches).
 434                  */
 435                 displ = ((s32)(insn << 11)) >> 9;
 436                 child->debugreg[nsaved++] = pc + 4;
 437                 if (displ)              /* guard against unoptimized code */
 438                   child->debugreg[nsaved++] = pc + 4 + displ;
 439                 DBG(DBG_BPT, ("execing branch\n"));
 440         } else if (op_code == 0x1a) {
 441                 reg_b = (insn >> 16) & 0x1f;
 442                 child->debugreg[nsaved++] = get_reg(child, reg_b);
 443                 DBG(DBG_BPT, ("execing jump\n"));
 444         } else {
 445                 child->debugreg[nsaved++] = pc + 4;
 446                 DBG(DBG_BPT, ("execing normal insn\n"));
 447         }
 448 
 449         /* install breakpoints: */
 450         for (i = 0; i < nsaved; ++i) {
 451                 res = read_int(child, child->debugreg[i], &insn);
 452                 if (res < 0)
 453                   return res;
 454                 child->debugreg[i + 2] = insn;
 455                 DBG(DBG_BPT, ("    -> next_pc=%lx\n", child->debugreg[i]));
 456                 res = write_int(child, child->debugreg[i], BREAKINST);
 457                 if (res < 0)
 458                   return res;
 459         }
 460         child->debugreg[4] = nsaved;
 461         return 0;
 462 }
 463 
 464 /*
 465  * Ensure no single-step breakpoint is pending.  Returns non-zero
 466  * value if child was being single-stepped.
 467  */
 468 int ptrace_cancel_bpt(struct task_struct * child)
     /* [previous][next][first][last][top][bottom][index][help] */
 469 {
 470         int i, nsaved = child->debugreg[4];
 471 
 472         child->debugreg[4] = 0;
 473 
 474         if (nsaved > 2) {
 475             printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
 476             nsaved = 2;
 477         }
 478 
 479         for (i = 0; i < nsaved; ++i) {
 480                 write_int(child, child->debugreg[i], child->debugreg[i + 2]);
 481         }
 482         return (nsaved != 0);
 483 }
 484 
 485 asmlinkage long sys_ptrace(long request, long pid, long addr, long data,
     /* [previous][next][first][last][top][bottom][index][help] */
 486                            int a4, int a5, struct pt_regs regs)
 487 {
 488         struct task_struct *child;
 489         struct user * dummy;
 490 
 491         dummy = NULL;
 492 
 493         DBG(DBG_MEM, ("request=%ld pid=%ld addr=0x%lx data=0x%lx\n",
 494                       request, pid, addr, data));
 495         if (request == PTRACE_TRACEME) {
 496                 /* are we already being traced? */
 497                 if (current->flags & PF_PTRACED)
 498                         return -EPERM;
 499                 /* set the ptrace bit in the process flags. */
 500                 current->flags |= PF_PTRACED;
 501                 return 0;
 502         }
 503         if (pid == 1)           /* you may not mess with init */
 504                 return -EPERM;
 505         if (!(child = get_task(pid)))
 506                 return -ESRCH;
 507         if (request == PTRACE_ATTACH) {
 508                 if (child == current)
 509                         return -EPERM;
 510                 if ((!child->dumpable ||
 511                      (current->uid != child->euid) ||
 512                      (current->uid != child->uid) ||
 513                      (current->gid != child->egid) ||
 514                      (current->gid != child->gid)) && !suser())
 515                         return -EPERM;
 516                 /* the same process cannot be attached many times */
 517                 if (child->flags & PF_PTRACED)
 518                         return -EPERM;
 519                 child->flags |= PF_PTRACED;
 520                 if (child->p_pptr != current) {
 521                         REMOVE_LINKS(child);
 522                         child->p_pptr = current;
 523                         SET_LINKS(child);
 524                 }
 525                 send_sig(SIGSTOP, child, 1);
 526                 return 0;
 527         }
 528         if (!(child->flags & PF_PTRACED)) {
 529                 DBG(DBG_MEM, ("child not traced\n"));
 530                 return -ESRCH;
 531         }
 532         if (child->state != TASK_STOPPED) {
 533                 DBG(DBG_MEM, ("child process not stopped\n"));
 534                 if (request != PTRACE_KILL)
 535                         return -ESRCH;
 536         }
 537         if (child->p_pptr != current) {
 538                 DBG(DBG_MEM, ("child not parent of this process\n"));
 539                 return -ESRCH;
 540         }
 541 
 542         switch (request) {
 543         /* when I and D space are separate, these will need to be fixed. */
 544                 case PTRACE_PEEKTEXT: /* read word at location addr. */
 545                 case PTRACE_PEEKDATA: {
 546                         unsigned long tmp;
 547                         int res;
 548 
 549                         res = read_long(child, addr, &tmp);
 550                         DBG(DBG_MEM, ("peek %#lx->%#lx\n", addr, tmp));
 551                         if (res < 0)
 552                                 return res;
 553                         regs.r0 = tmp;  /* special return */
 554                         return -255;
 555                 }
 556 
 557         /* read register number ADDR. */
 558                 case PTRACE_PEEKUSR:
 559                         regs.r0 = get_reg(child, addr);
 560                         DBG(DBG_MEM, ("peek $%ld=%#lx\n", addr, regs.r0));
 561                         return -255;            /* special return */
 562 
 563         /* when I and D space are separate, this will have to be fixed. */
 564                 case PTRACE_POKETEXT: /* write the word at location addr. */
 565                 case PTRACE_POKEDATA:
 566                         DBG(DBG_MEM, ("poke %#lx<-%#lx\n", addr, data));
 567                         return write_long(child, addr, data);
 568 
 569                 case PTRACE_POKEUSR: /* write the specified register */
 570                         DBG(DBG_MEM, ("poke $%ld<-%#lx\n", addr, data));
 571                         return put_reg(child, addr, data);
 572 
 573                 case PTRACE_SYSCALL: /* continue and stop at next
 574                                         (return from) syscall */
 575                 case PTRACE_CONT: { /* restart after signal. */
 576                         if ((unsigned long) data > NSIG)
 577                                 return -EIO;
 578                         if (request == PTRACE_SYSCALL)
 579                                 child->flags |= PF_TRACESYS;
 580                         else
 581                                 child->flags &= ~PF_TRACESYS;
 582                         child->exit_code = data;
 583                         wake_up_process(child);
 584         /* make sure single-step breakpoint is gone. */
 585                         ptrace_cancel_bpt(child);
 586                         return data;
 587                 }
 588 
 589 /*
 590  * make the child exit.  Best I can do is send it a sigkill.
 591  * perhaps it should be put in the status that it wants to
 592  * exit.
 593  */
 594                 case PTRACE_KILL: {
 595                         if (child->state != TASK_ZOMBIE) {
 596                                 wake_up_process(child);
 597                                 child->exit_code = SIGKILL;
 598                         }
 599         /* make sure single-step breakpoint is gone. */
 600                         ptrace_cancel_bpt(child);
 601                         return 0;
 602                 }
 603 
 604                 case PTRACE_SINGLESTEP: {  /* execute single instruction. */
 605                         if ((unsigned long) data > NSIG)
 606                                 return -EIO;
 607                         child->debugreg[4] = -1;        /* mark single-stepping */
 608                         child->flags &= ~PF_TRACESYS;
 609                         wake_up_process(child);
 610                         child->exit_code = data;
 611         /* give it a chance to run. */
 612                         return 0;
 613                 }
 614 
 615                 case PTRACE_DETACH: { /* detach a process that was attached. */
 616                         if ((unsigned long) data > NSIG)
 617                                 return -EIO;
 618                         child->flags &= ~(PF_PTRACED|PF_TRACESYS);
 619                         wake_up_process(child);
 620                         child->exit_code = data;
 621                         REMOVE_LINKS(child);
 622                         child->p_pptr = child->p_opptr;
 623                         SET_LINKS(child);
 624         /* make sure single-step breakpoint is gone. */
 625                         ptrace_cancel_bpt(child);
 626                         return 0;
 627                 }
 628 
 629                 default:
 630                   return -EIO;
 631           }
 632 }
 633 
 634 asmlinkage void syscall_trace(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 635 {
 636         if ((current->flags & (PF_PTRACED|PF_TRACESYS))
 637                         != (PF_PTRACED|PF_TRACESYS))
 638                 return;
 639         current->exit_code = SIGTRAP;
 640         current->state = TASK_STOPPED;
 641         notify_parent(current);
 642         schedule();
 643         /*
 644          * this isn't the same as continuing with a signal, but it will do
 645          * for normal use.  strace only continues with a signal if the
 646          * stopping signal is not SIGTRAP.  -brl
 647          */
 648         if (current->exit_code)
 649                 current->signal |= (1 << (current->exit_code - 1));
 650         current->exit_code = 0;
 651 }

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