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