linux/arch/arm/kernel/ptrace.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/kernel/ptrace.c
   3 *
   4 *  By Ross Biro 1/23/92
   5 * edited by Linus Torvalds
   6 * ARM modifications Copyright (C) 2000 Russell King
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 */
  12#include <linux/config.h>
  13#include <linux/kernel.h>
  14#include <linux/sched.h>
  15#include <linux/mm.h>
  16#include <linux/smp.h>
  17#include <linux/smp_lock.h>
  18#include <linux/ptrace.h>
  19#include <linux/user.h>
  20#include <linux/security.h>
  21#include <linux/init.h>
  22#include <linux/signal.h>
  23
  24#include <asm/uaccess.h>
  25#include <asm/pgtable.h>
  26#include <asm/system.h>
  27#include <asm/traps.h>
  28
  29#include "ptrace.h"
  30
  31#define REG_PC  15
  32#define REG_PSR 16
  33/*
  34 * does not yet catch signals sent when the child dies.
  35 * in exit.c or in signal.c.
  36 */
  37
  38#if 0
  39/*
  40 * Breakpoint SWI instruction: SWI &9F0001
  41 */
  42#define BREAKINST_ARM   0xef9f0001
  43#define BREAKINST_THUMB 0xdf00          /* fill this in later */
  44#else
  45/*
  46 * New breakpoints - use an undefined instruction.  The ARM architecture
  47 * reference manual guarantees that the following instruction space
  48 * will produce an undefined instruction exception on all CPUs:
  49 *
  50 *  ARM:   xxxx 0111 1111 xxxx xxxx xxxx 1111 xxxx
  51 *  Thumb: 1101 1110 xxxx xxxx
  52 */
  53#define BREAKINST_ARM   0xe7f001f0
  54#define BREAKINST_THUMB 0xde01
  55#endif
  56
  57/*
  58 * Get the address of the live pt_regs for the specified task.
  59 * These are saved onto the top kernel stack when the process
  60 * is not running.
  61 *
  62 * Note: if a user thread is execve'd from kernel space, the
  63 * kernel stack will not be empty on entry to the kernel, so
  64 * ptracing these tasks will fail.
  65 */
  66static inline struct pt_regs *
  67get_user_regs(struct task_struct *task)
  68{
  69        return (struct pt_regs *)
  70                ((unsigned long)task->thread_info + THREAD_SIZE -
  71                                 8 - sizeof(struct pt_regs));
  72}
  73
  74/*
  75 * this routine will get a word off of the processes privileged stack.
  76 * the offset is how far from the base addr as stored in the THREAD.
  77 * this routine assumes that all the privileged stacks are in our
  78 * data space.
  79 */
  80static inline long get_user_reg(struct task_struct *task, int offset)
  81{
  82        return get_user_regs(task)->uregs[offset];
  83}
  84
  85/*
  86 * this routine will put a word on the processes privileged stack.
  87 * the offset is how far from the base addr as stored in the THREAD.
  88 * this routine assumes that all the privileged stacks are in our
  89 * data space.
  90 */
  91static inline int
  92put_user_reg(struct task_struct *task, int offset, long data)
  93{
  94        struct pt_regs newregs, *regs = get_user_regs(task);
  95        int ret = -EINVAL;
  96
  97        newregs = *regs;
  98        newregs.uregs[offset] = data;
  99
 100        if (valid_user_regs(&newregs)) {
 101                regs->uregs[offset] = data;
 102                ret = 0;
 103        }
 104
 105        return ret;
 106}
 107
 108static inline int
 109read_u32(struct task_struct *task, unsigned long addr, u32 *res)
 110{
 111        int ret;
 112
 113        ret = access_process_vm(task, addr, res, sizeof(*res), 0);
 114
 115        return ret == sizeof(*res) ? 0 : -EIO;
 116}
 117
 118static inline int
 119read_instr(struct task_struct *task, unsigned long addr, u32 *res)
 120{
 121        int ret;
 122
 123        if (addr & 1) {
 124                u16 val;
 125                ret = access_process_vm(task, addr & ~1, &val, sizeof(val), 0);
 126                ret = ret == sizeof(val) ? 0 : -EIO;
 127                *res = val;
 128        } else {
 129                u32 val;
 130                ret = access_process_vm(task, addr & ~3, &val, sizeof(val), 0);
 131                ret = ret == sizeof(val) ? 0 : -EIO;
 132                *res = val;
 133        }
 134        return ret;
 135}
 136
 137/*
 138 * Get value of register `rn' (in the instruction)
 139 */
 140static unsigned long
 141ptrace_getrn(struct task_struct *child, unsigned long insn)
 142{
 143        unsigned int reg = (insn >> 16) & 15;
 144        unsigned long val;
 145
 146        val = get_user_reg(child, reg);
 147        if (reg == 15)
 148                val = pc_pointer(val + 8);
 149
 150        return val;
 151}
 152
 153/*
 154 * Get value of operand 2 (in an ALU instruction)
 155 */
 156static unsigned long
 157ptrace_getaluop2(struct task_struct *child, unsigned long insn)
 158{
 159        unsigned long val;
 160        int shift;
 161        int type;
 162
 163        if (insn & 1 << 25) {
 164                val = insn & 255;
 165                shift = (insn >> 8) & 15;
 166                type = 3;
 167        } else {
 168                val = get_user_reg (child, insn & 15);
 169
 170                if (insn & (1 << 4))
 171                        shift = (int)get_user_reg (child, (insn >> 8) & 15);
 172                else
 173                        shift = (insn >> 7) & 31;
 174
 175                type = (insn >> 5) & 3;
 176        }
 177
 178        switch (type) {
 179        case 0: val <<= shift;  break;
 180        case 1: val >>= shift;  break;
 181        case 2:
 182                val = (((signed long)val) >> shift);
 183                break;
 184        case 3:
 185                val = (val >> shift) | (val << (32 - shift));
 186                break;
 187        }
 188        return val;
 189}
 190
 191/*
 192 * Get value of operand 2 (in a LDR instruction)
 193 */
 194static unsigned long
 195ptrace_getldrop2(struct task_struct *child, unsigned long insn)
 196{
 197        unsigned long val;
 198        int shift;
 199        int type;
 200
 201        val = get_user_reg(child, insn & 15);
 202        shift = (insn >> 7) & 31;
 203        type = (insn >> 5) & 3;
 204
 205        switch (type) {
 206        case 0: val <<= shift;  break;
 207        case 1: val >>= shift;  break;
 208        case 2:
 209                val = (((signed long)val) >> shift);
 210                break;
 211        case 3:
 212                val = (val >> shift) | (val << (32 - shift));
 213                break;
 214        }
 215        return val;
 216}
 217
 218#define OP_MASK 0x01e00000
 219#define OP_AND  0x00000000
 220#define OP_EOR  0x00200000
 221#define OP_SUB  0x00400000
 222#define OP_RSB  0x00600000
 223#define OP_ADD  0x00800000
 224#define OP_ADC  0x00a00000
 225#define OP_SBC  0x00c00000
 226#define OP_RSC  0x00e00000
 227#define OP_ORR  0x01800000
 228#define OP_MOV  0x01a00000
 229#define OP_BIC  0x01c00000
 230#define OP_MVN  0x01e00000
 231
 232static unsigned long
 233get_branch_address(struct task_struct *child, unsigned long pc, unsigned long insn)
 234{
 235        u32 alt = 0;
 236
 237        switch (insn & 0x0e000000) {
 238        case 0x00000000:
 239        case 0x02000000: {
 240                /*
 241                 * data processing
 242                 */
 243                long aluop1, aluop2, ccbit;
 244
 245                if ((insn & 0xf000) != 0xf000)
 246                        break;
 247
 248                aluop1 = ptrace_getrn(child, insn);
 249                aluop2 = ptrace_getaluop2(child, insn);
 250                ccbit  = get_user_reg(child, REG_PSR) & PSR_C_BIT ? 1 : 0;
 251
 252                switch (insn & OP_MASK) {
 253                case OP_AND: alt = aluop1 & aluop2;             break;
 254                case OP_EOR: alt = aluop1 ^ aluop2;             break;
 255                case OP_SUB: alt = aluop1 - aluop2;             break;
 256                case OP_RSB: alt = aluop2 - aluop1;             break;
 257                case OP_ADD: alt = aluop1 + aluop2;             break;
 258                case OP_ADC: alt = aluop1 + aluop2 + ccbit;     break;
 259                case OP_SBC: alt = aluop1 - aluop2 + ccbit;     break;
 260                case OP_RSC: alt = aluop2 - aluop1 + ccbit;     break;
 261                case OP_ORR: alt = aluop1 | aluop2;             break;
 262                case OP_MOV: alt = aluop2;                      break;
 263                case OP_BIC: alt = aluop1 & ~aluop2;            break;
 264                case OP_MVN: alt = ~aluop2;                     break;
 265                }
 266                break;
 267        }
 268
 269        case 0x04000000:
 270        case 0x06000000:
 271                /*
 272                 * ldr
 273                 */
 274                if ((insn & 0x0010f000) == 0x0010f000) {
 275                        unsigned long base;
 276
 277                        base = ptrace_getrn(child, insn);
 278                        if (insn & 1 << 24) {
 279                                long aluop2;
 280
 281                                if (insn & 0x02000000)
 282                                        aluop2 = ptrace_getldrop2(child, insn);
 283                                else
 284                                        aluop2 = insn & 0xfff;
 285
 286                                if (insn & 1 << 23)
 287                                        base += aluop2;
 288                                else
 289                                        base -= aluop2;
 290                        }
 291                        if (read_u32(child, base, &alt) == 0)
 292                                alt = pc_pointer(alt);
 293                }
 294                break;
 295
 296        case 0x08000000:
 297                /*
 298                 * ldm
 299                 */
 300                if ((insn & 0x00108000) == 0x00108000) {
 301                        unsigned long base;
 302                        unsigned int nr_regs;
 303
 304                        if (insn & (1 << 23)) {
 305                                nr_regs = hweight16(insn & 65535) << 2;
 306
 307                                if (!(insn & (1 << 24)))
 308                                        nr_regs -= 4;
 309                        } else {
 310                                if (insn & (1 << 24))
 311                                        nr_regs = -4;
 312                                else
 313                                        nr_regs = 0;
 314                        }
 315
 316                        base = ptrace_getrn(child, insn);
 317
 318                        if (read_u32(child, base + nr_regs, &alt) == 0)
 319                                alt = pc_pointer(alt);
 320                        break;
 321                }
 322                break;
 323
 324        case 0x0a000000: {
 325                /*
 326                 * bl or b
 327                 */
 328                signed long displ;
 329                /* It's a branch/branch link: instead of trying to
 330                 * figure out whether the branch will be taken or not,
 331                 * we'll put a breakpoint at both locations.  This is
 332                 * simpler, more reliable, and probably not a whole lot
 333                 * slower than the alternative approach of emulating the
 334                 * branch.
 335                 */
 336                displ = (insn & 0x00ffffff) << 8;
 337                displ = (displ >> 6) + 8;
 338                if (displ != 0 && displ != 4)
 339                        alt = pc + displ;
 340            }
 341            break;
 342        }
 343
 344        return alt;
 345}
 346
 347static int
 348swap_insn(struct task_struct *task, unsigned long addr,
 349          void *old_insn, void *new_insn, int size)
 350{
 351        int ret;
 352
 353        ret = access_process_vm(task, addr, old_insn, size, 0);
 354        if (ret == size)
 355                ret = access_process_vm(task, addr, new_insn, size, 1);
 356        return ret;
 357}
 358
 359static void
 360add_breakpoint(struct task_struct *task, struct debug_info *dbg, unsigned long addr)
 361{
 362        int nr = dbg->nsaved;
 363
 364        if (nr < 2) {
 365                u32 new_insn = BREAKINST_ARM;
 366                int res;
 367
 368                res = swap_insn(task, addr, &dbg->bp[nr].insn, &new_insn, 4);
 369
 370                if (res == 4) {
 371                        dbg->bp[nr].address = addr;
 372                        dbg->nsaved += 1;
 373                }
 374        } else
 375                printk(KERN_ERR "ptrace: too many breakpoints\n");
 376}
 377
 378/*
 379 * Clear one breakpoint in the user program.  We copy what the hardware
 380 * does and use bit 0 of the address to indicate whether this is a Thumb
 381 * breakpoint or an ARM breakpoint.
 382 */
 383static void clear_breakpoint(struct task_struct *task, struct debug_entry *bp)
 384{
 385        unsigned long addr = bp->address;
 386        union debug_insn old_insn;
 387        int ret;
 388
 389        if (addr & 1) {
 390                ret = swap_insn(task, addr & ~1, &old_insn.thumb,
 391                                &bp->insn.thumb, 2);
 392
 393                if (ret != 2 || old_insn.thumb != BREAKINST_THUMB)
 394                        printk(KERN_ERR "%s:%d: corrupted Thumb breakpoint at "
 395                                "0x%08lx (0x%04x)\n", task->comm, task->pid,
 396                                addr, old_insn.thumb);
 397        } else {
 398                ret = swap_insn(task, addr & ~3, &old_insn.arm,
 399                                &bp->insn.arm, 4);
 400
 401                if (ret != 4 || old_insn.arm != BREAKINST_ARM)
 402                        printk(KERN_ERR "%s:%d: corrupted ARM breakpoint at "
 403                                "0x%08lx (0x%08x)\n", task->comm, task->pid,
 404                                addr, old_insn.arm);
 405        }
 406}
 407
 408void ptrace_set_bpt(struct task_struct *child)
 409{
 410        struct pt_regs *regs;
 411        unsigned long pc;
 412        u32 insn;
 413        int res;
 414
 415        regs = get_user_regs(child);
 416        pc = instruction_pointer(regs);
 417
 418        if (thumb_mode(regs)) {
 419                printk(KERN_WARNING "ptrace: can't handle thumb mode\n");
 420                return;
 421        }
 422
 423        res = read_instr(child, pc, &insn);
 424        if (!res) {
 425                struct debug_info *dbg = &child->thread.debug;
 426                unsigned long alt;
 427
 428                dbg->nsaved = 0;
 429
 430                alt = get_branch_address(child, pc, insn);
 431                if (alt)
 432                        add_breakpoint(child, dbg, alt);
 433
 434                /*
 435                 * Note that we ignore the result of setting the above
 436                 * breakpoint since it may fail.  When it does, this is
 437                 * not so much an error, but a forewarning that we may
 438                 * be receiving a prefetch abort shortly.
 439                 *
 440                 * If we don't set this breakpoint here, then we can
 441                 * lose control of the thread during single stepping.
 442                 */
 443                if (!alt || predicate(insn) != PREDICATE_ALWAYS)
 444                        add_breakpoint(child, dbg, pc + 4);
 445        }
 446}
 447
 448/*
 449 * Ensure no single-step breakpoint is pending.  Returns non-zero
 450 * value if child was being single-stepped.
 451 */
 452void ptrace_cancel_bpt(struct task_struct *child)
 453{
 454        int i, nsaved = child->thread.debug.nsaved;
 455
 456        child->thread.debug.nsaved = 0;
 457
 458        if (nsaved > 2) {
 459                printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
 460                nsaved = 2;
 461        }
 462
 463        for (i = 0; i < nsaved; i++)
 464                clear_breakpoint(child, &child->thread.debug.bp[i]);
 465}
 466
 467/*
 468 * Called by kernel/ptrace.c when detaching..
 469 *
 470 * Make sure the single step bit is not set.
 471 */
 472void ptrace_disable(struct task_struct *child)
 473{
 474        child->ptrace &= ~PT_SINGLESTEP;
 475        ptrace_cancel_bpt(child);
 476}
 477
 478/*
 479 * Handle hitting a breakpoint.
 480 */
 481void ptrace_break(struct task_struct *tsk, struct pt_regs *regs)
 482{
 483        siginfo_t info;
 484
 485        ptrace_cancel_bpt(tsk);
 486
 487        info.si_signo = SIGTRAP;
 488        info.si_errno = 0;
 489        info.si_code  = TRAP_BRKPT;
 490        info.si_addr  = (void __user *)instruction_pointer(regs);
 491
 492        force_sig_info(SIGTRAP, &info, tsk);
 493}
 494
 495static int break_trap(struct pt_regs *regs, unsigned int instr)
 496{
 497        ptrace_break(current, regs);
 498        return 0;
 499}
 500
 501static struct undef_hook arm_break_hook = {
 502        .instr_mask     = 0x0fffffff,
 503        .instr_val      = 0x07f001f0,
 504        .cpsr_mask      = PSR_T_BIT,
 505        .cpsr_val       = 0,
 506        .fn             = break_trap,
 507};
 508
 509static struct undef_hook thumb_break_hook = {
 510        .instr_mask     = 0xffff,
 511        .instr_val      = 0xde01,
 512        .cpsr_mask      = PSR_T_BIT,
 513        .cpsr_val       = PSR_T_BIT,
 514        .fn             = break_trap,
 515};
 516
 517static int __init ptrace_break_init(void)
 518{
 519        register_undef_hook(&arm_break_hook);
 520        register_undef_hook(&thumb_break_hook);
 521        return 0;
 522}
 523
 524core_initcall(ptrace_break_init);
 525
 526/*
 527 * Read the word at offset "off" into the "struct user".  We
 528 * actually access the pt_regs stored on the kernel stack.
 529 */
 530static int ptrace_read_user(struct task_struct *tsk, unsigned long off,
 531                            unsigned long __user *ret)
 532{
 533        unsigned long tmp;
 534
 535        if (off & 3 || off >= sizeof(struct user))
 536                return -EIO;
 537
 538        tmp = 0;
 539        if (off < sizeof(struct pt_regs))
 540                tmp = get_user_reg(tsk, off >> 2);
 541
 542        return put_user(tmp, ret);
 543}
 544
 545/*
 546 * Write the word at offset "off" into "struct user".  We
 547 * actually access the pt_regs stored on the kernel stack.
 548 */
 549static int ptrace_write_user(struct task_struct *tsk, unsigned long off,
 550                             unsigned long val)
 551{
 552        if (off & 3 || off >= sizeof(struct user))
 553                return -EIO;
 554
 555        if (off >= sizeof(struct pt_regs))
 556                return 0;
 557
 558        return put_user_reg(tsk, off >> 2, val);
 559}
 560
 561/*
 562 * Get all user integer registers.
 563 */
 564static int ptrace_getregs(struct task_struct *tsk, void __user *uregs)
 565{
 566        struct pt_regs *regs = get_user_regs(tsk);
 567
 568        return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0;
 569}
 570
 571/*
 572 * Set all user integer registers.
 573 */
 574static int ptrace_setregs(struct task_struct *tsk, void __user *uregs)
 575{
 576        struct pt_regs newregs;
 577        int ret;
 578
 579        ret = -EFAULT;
 580        if (copy_from_user(&newregs, uregs, sizeof(struct pt_regs)) == 0) {
 581                struct pt_regs *regs = get_user_regs(tsk);
 582
 583                ret = -EINVAL;
 584                if (valid_user_regs(&newregs)) {
 585                        *regs = newregs;
 586                        ret = 0;
 587                }
 588        }
 589
 590        return ret;
 591}
 592
 593/*
 594 * Get the child FPU state.
 595 */
 596static int ptrace_getfpregs(struct task_struct *tsk, void __user *ufp)
 597{
 598        return copy_to_user(ufp, &tsk->thread_info->fpstate,
 599                            sizeof(struct user_fp)) ? -EFAULT : 0;
 600}
 601
 602/*
 603 * Set the child FPU state.
 604 */
 605static int ptrace_setfpregs(struct task_struct *tsk, void __user *ufp)
 606{
 607        struct thread_info *thread = tsk->thread_info;
 608        thread->used_cp[1] = thread->used_cp[2] = 1;
 609        return copy_from_user(&thread->fpstate, ufp,
 610                              sizeof(struct user_fp)) ? -EFAULT : 0;
 611}
 612
 613#ifdef CONFIG_IWMMXT
 614
 615/*
 616 * Get the child iWMMXt state.
 617 */
 618static int ptrace_getwmmxregs(struct task_struct *tsk, void __user *ufp)
 619{
 620        struct thread_info *thread = tsk->thread_info;
 621        void *ptr = &thread->fpstate;
 622
 623        if (!test_ti_thread_flag(thread, TIF_USING_IWMMXT))
 624                return -ENODATA;
 625        iwmmxt_task_disable(thread);  /* force it to ram */
 626        /* The iWMMXt state is stored doubleword-aligned.  */
 627        if (((long) ptr) & 4)
 628                ptr += 4;
 629        return copy_to_user(ufp, ptr, 0x98) ? -EFAULT : 0;
 630}
 631
 632/*
 633 * Set the child iWMMXt state.
 634 */
 635static int ptrace_setwmmxregs(struct task_struct *tsk, void __user *ufp)
 636{
 637        struct thread_info *thread = tsk->thread_info;
 638        void *ptr = &thread->fpstate;
 639
 640        if (!test_ti_thread_flag(thread, TIF_USING_IWMMXT))
 641                return -EACCES;
 642        iwmmxt_task_release(thread);  /* force a reload */
 643        /* The iWMMXt state is stored doubleword-aligned.  */
 644        if (((long) ptr) & 4)
 645                ptr += 4;
 646        return copy_from_user(ptr, ufp, 0x98) ? -EFAULT : 0;
 647}
 648
 649#endif
 650
 651static int do_ptrace(int request, struct task_struct *child, long addr, long data)
 652{
 653        unsigned long tmp;
 654        int ret;
 655
 656        switch (request) {
 657                /*
 658                 * read word at location "addr" in the child process.
 659                 */
 660                case PTRACE_PEEKTEXT:
 661                case PTRACE_PEEKDATA:
 662                        ret = access_process_vm(child, addr, &tmp,
 663                                                sizeof(unsigned long), 0);
 664                        if (ret == sizeof(unsigned long))
 665                                ret = put_user(tmp, (unsigned long __user *) data);
 666                        else
 667                                ret = -EIO;
 668                        break;
 669
 670                case PTRACE_PEEKUSR:
 671                        ret = ptrace_read_user(child, addr, (unsigned long __user *)data);
 672                        break;
 673
 674                /*
 675                 * write the word at location addr.
 676                 */
 677                case PTRACE_POKETEXT:
 678                case PTRACE_POKEDATA:
 679                        ret = access_process_vm(child, addr, &data,
 680                                                sizeof(unsigned long), 1);
 681                        if (ret == sizeof(unsigned long))
 682                                ret = 0;
 683                        else
 684                                ret = -EIO;
 685                        break;
 686
 687                case PTRACE_POKEUSR:
 688                        ret = ptrace_write_user(child, addr, data);
 689                        break;
 690
 691                /*
 692                 * continue/restart and stop at next (return from) syscall
 693                 */
 694                case PTRACE_SYSCALL:
 695                case PTRACE_CONT:
 696                        ret = -EIO;
 697                        if (!valid_signal(data))
 698                                break;
 699                        if (request == PTRACE_SYSCALL)
 700                                set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 701                        else
 702                                clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 703                        child->exit_code = data;
 704                        /* make sure single-step breakpoint is gone. */
 705                        child->ptrace &= ~PT_SINGLESTEP;
 706                        ptrace_cancel_bpt(child);
 707                        wake_up_process(child);
 708                        ret = 0;
 709                        break;
 710
 711                /*
 712                 * make the child exit.  Best I can do is send it a sigkill.
 713                 * perhaps it should be put in the status that it wants to
 714                 * exit.
 715                 */
 716                case PTRACE_KILL:
 717                        /* make sure single-step breakpoint is gone. */
 718                        child->ptrace &= ~PT_SINGLESTEP;
 719                        ptrace_cancel_bpt(child);
 720                        if (child->exit_state != EXIT_ZOMBIE) {
 721                                child->exit_code = SIGKILL;
 722                                wake_up_process(child);
 723                        }
 724                        ret = 0;
 725                        break;
 726
 727                /*
 728                 * execute single instruction.
 729                 */
 730                case PTRACE_SINGLESTEP:
 731                        ret = -EIO;
 732                        if (!valid_signal(data))
 733                                break;
 734                        child->ptrace |= PT_SINGLESTEP;
 735                        clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 736                        child->exit_code = data;
 737                        /* give it a chance to run. */
 738                        wake_up_process(child);
 739                        ret = 0;
 740                        break;
 741
 742                case PTRACE_DETACH:
 743                        ret = ptrace_detach(child, data);
 744                        break;
 745
 746                case PTRACE_GETREGS:
 747                        ret = ptrace_getregs(child, (void __user *)data);
 748                        break;
 749
 750                case PTRACE_SETREGS:
 751                        ret = ptrace_setregs(child, (void __user *)data);
 752                        break;
 753
 754                case PTRACE_GETFPREGS:
 755                        ret = ptrace_getfpregs(child, (void __user *)data);
 756                        break;
 757                
 758                case PTRACE_SETFPREGS:
 759                        ret = ptrace_setfpregs(child, (void __user *)data);
 760                        break;
 761
 762#ifdef CONFIG_IWMMXT
 763                case PTRACE_GETWMMXREGS:
 764                        ret = ptrace_getwmmxregs(child, (void __user *)data);
 765                        break;
 766
 767                case PTRACE_SETWMMXREGS:
 768                        ret = ptrace_setwmmxregs(child, (void __user *)data);
 769                        break;
 770#endif
 771
 772                case PTRACE_GET_THREAD_AREA:
 773                        ret = put_user(child->thread_info->tp_value,
 774                                       (unsigned long __user *) data);
 775                        break;
 776
 777                default:
 778                        ret = ptrace_request(child, request, addr, data);
 779                        break;
 780        }
 781
 782        return ret;
 783}
 784
 785asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 786{
 787        struct task_struct *child;
 788        int ret;
 789
 790        lock_kernel();
 791        ret = -EPERM;
 792        if (request == PTRACE_TRACEME) {
 793                /* are we already being traced? */
 794                if (current->ptrace & PT_PTRACED)
 795                        goto out;
 796                ret = security_ptrace(current->parent, current);
 797                if (ret)
 798                        goto out;
 799                /* set the ptrace bit in the process flags. */
 800                current->ptrace |= PT_PTRACED;
 801                ret = 0;
 802                goto out;
 803        }
 804        ret = -ESRCH;
 805        read_lock(&tasklist_lock);
 806        child = find_task_by_pid(pid);
 807        if (child)
 808                get_task_struct(child);
 809        read_unlock(&tasklist_lock);
 810        if (!child)
 811                goto out;
 812
 813        ret = -EPERM;
 814        if (pid == 1)           /* you may not mess with init */
 815                goto out_tsk;
 816
 817        if (request == PTRACE_ATTACH) {
 818                ret = ptrace_attach(child);
 819                goto out_tsk;
 820        }
 821        ret = ptrace_check_attach(child, request == PTRACE_KILL);
 822        if (ret == 0)
 823                ret = do_ptrace(request, child, addr, data);
 824
 825out_tsk:
 826        put_task_struct(child);
 827out:
 828        unlock_kernel();
 829        return ret;
 830}
 831
 832asmlinkage void syscall_trace(int why, struct pt_regs *regs)
 833{
 834        unsigned long ip;
 835
 836        if (!test_thread_flag(TIF_SYSCALL_TRACE))
 837                return;
 838        if (!(current->ptrace & PT_PTRACED))
 839                return;
 840
 841        /*
 842         * Save IP.  IP is used to denote syscall entry/exit:
 843         *  IP = 0 -> entry, = 1 -> exit
 844         */
 845        ip = regs->ARM_ip;
 846        regs->ARM_ip = why;
 847
 848        /* the 0x80 provides a way for the tracing parent to distinguish
 849           between a syscall stop and SIGTRAP delivery */
 850        ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
 851                                 ? 0x80 : 0));
 852        /*
 853         * this isn't the same as continuing with a signal, but it will do
 854         * for normal use.  strace only continues with a signal if the
 855         * stopping signal is not SIGTRAP.  -brl
 856         */
 857        if (current->exit_code) {
 858                send_sig(current->exit_code, current, 1);
 859                current->exit_code = 0;
 860        }
 861        regs->ARM_ip = ip;
 862}
 863
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.