linux-old/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/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
  20#include <asm/uaccess.h>
  21#include <asm/pgtable.h>
  22#include <asm/system.h>
  23
  24#include "ptrace.h"
  25
  26#define REG_PC  15
  27#define REG_PSR 16
  28/*
  29 * does not yet catch signals sent when the child dies.
  30 * in exit.c or in signal.c.
  31 */
  32
  33/*
  34 * Breakpoint SWI instruction: SWI &9F0001
  35 */
  36#define BREAKINST       0xef9f0001
  37
  38/*
  39 * Get the address of the live pt_regs for the specified task.
  40 * These are saved onto the top kernel stack when the process
  41 * is not running.
  42 */
  43static inline struct pt_regs *
  44get_user_regs(struct task_struct *task)
  45{
  46        return (struct pt_regs *)
  47                ((unsigned long)task + 8192 - sizeof(struct pt_regs));
  48}
  49
  50/*
  51 * this routine will get a word off of the processes privileged stack.
  52 * the offset is how far from the base addr as stored in the THREAD.
  53 * this routine assumes that all the privileged stacks are in our
  54 * data space.
  55 */
  56static inline long get_stack_long(struct task_struct *task, int offset)
  57{
  58        return get_user_regs(task)->uregs[offset];
  59}
  60
  61/*
  62 * this routine will put a word on the processes privileged stack.
  63 * the offset is how far from the base addr as stored in the THREAD.
  64 * this routine assumes that all the privileged stacks are in our
  65 * data space.
  66 */
  67static inline int
  68put_stack_long(struct task_struct *task, int offset, long data)
  69{
  70        struct pt_regs newregs, *regs = get_user_regs(task);
  71        int ret = -EINVAL;
  72
  73        newregs = *regs;
  74        newregs.uregs[offset] = data;
  75        
  76        if (valid_user_regs(&newregs)) {
  77                regs->uregs[offset] = data;
  78                ret = 0;
  79        }
  80
  81        return ret;
  82}
  83
  84static inline int
  85read_tsk_long(struct task_struct *child, unsigned long addr, unsigned long *res)
  86{
  87        int copied;
  88
  89        copied = access_process_vm(child, addr, res, sizeof(*res), 0);
  90
  91        return copied != sizeof(*res) ? -EIO : 0;
  92}
  93
  94static inline int
  95write_tsk_long(struct task_struct *child, unsigned long addr, unsigned long val)
  96{
  97        int copied;
  98
  99        copied = access_process_vm(child, addr, &val, sizeof(val), 1);
 100
 101        return copied != sizeof(val) ? -EIO : 0;
 102}
 103
 104/*
 105 * Get value of register `rn' (in the instruction)
 106 */
 107static unsigned long
 108ptrace_getrn(struct task_struct *child, unsigned long insn)
 109{
 110        unsigned int reg = (insn >> 16) & 15;
 111        unsigned long val;
 112
 113        val = get_stack_long(child, reg);
 114        if (reg == 15)
 115                val = pc_pointer(val + 8);
 116
 117        return val;
 118}
 119
 120/*
 121 * Get value of operand 2 (in an ALU instruction)
 122 */
 123static unsigned long
 124ptrace_getaluop2(struct task_struct *child, unsigned long insn)
 125{
 126        unsigned long val;
 127        int shift;
 128        int type;
 129
 130        if (insn & 1 << 25) {
 131                val = insn & 255;
 132                shift = (insn >> 8) & 15;
 133                type = 3;
 134        } else {
 135                val = get_stack_long (child, insn & 15);
 136
 137                if (insn & (1 << 4))
 138                        shift = (int)get_stack_long (child, (insn >> 8) & 15);
 139                else
 140                        shift = (insn >> 7) & 31;
 141
 142                type = (insn >> 5) & 3;
 143        }
 144
 145        switch (type) {
 146        case 0: val <<= shift;  break;
 147        case 1: val >>= shift;  break;
 148        case 2:
 149                val = (((signed long)val) >> shift);
 150                break;
 151        case 3:
 152                val = (val >> shift) | (val << (32 - shift));
 153                break;
 154        }
 155        return val;
 156}
 157
 158/*
 159 * Get value of operand 2 (in a LDR instruction)
 160 */
 161static unsigned long
 162ptrace_getldrop2(struct task_struct *child, unsigned long insn)
 163{
 164        unsigned long val;
 165        int shift;
 166        int type;
 167
 168        val = get_stack_long(child, insn & 15);
 169        shift = (insn >> 7) & 31;
 170        type = (insn >> 5) & 3;
 171
 172        switch (type) {
 173        case 0: val <<= shift;  break;
 174        case 1: val >>= shift;  break;
 175        case 2:
 176                val = (((signed long)val) >> shift);
 177                break;
 178        case 3:
 179                val = (val >> shift) | (val << (32 - shift));
 180                break;
 181        }
 182        return val;
 183}
 184
 185static unsigned long
 186get_branch_address(struct task_struct *child, unsigned long pc, unsigned long insn)
 187{
 188        unsigned long alt = 0;
 189
 190        switch (insn & 0x0e000000) {
 191        case 0x00000000:
 192        case 0x02000000: {
 193                /*
 194                 * data processing
 195                 */
 196                long aluop1, aluop2, ccbit;
 197
 198                if ((insn & 0xf000) != 0xf000)
 199                        break;
 200
 201                aluop1 = ptrace_getrn(child, insn);
 202                aluop2 = ptrace_getaluop2(child, insn);
 203                ccbit  = get_stack_long(child, REG_PSR) & CC_C_BIT ? 1 : 0;
 204
 205                switch (insn & 0x01e00000) {
 206                case 0x00000000: alt = aluop1 & aluop2;         break;
 207                case 0x00200000: alt = aluop1 ^ aluop2;         break;
 208                case 0x00400000: alt = aluop1 - aluop2;         break;
 209                case 0x00600000: alt = aluop2 - aluop1;         break;
 210                case 0x00800000: alt = aluop1 + aluop2;         break;
 211                case 0x00a00000: alt = aluop1 + aluop2 + ccbit; break;
 212                case 0x00c00000: alt = aluop1 - aluop2 + ccbit; break;
 213                case 0x00e00000: alt = aluop2 - aluop1 + ccbit; break;
 214                case 0x01800000: alt = aluop1 | aluop2;         break;
 215                case 0x01a00000: alt = aluop2;                  break;
 216                case 0x01c00000: alt = aluop1 & ~aluop2;        break;
 217                case 0x01e00000: alt = ~aluop2;                 break;
 218                }
 219                break;
 220        }
 221
 222        case 0x04000000:
 223        case 0x06000000:
 224                /*
 225                 * ldr
 226                 */
 227                if ((insn & 0x0010f000) == 0x0010f000) {
 228                        unsigned long base;
 229
 230                        base = ptrace_getrn(child, insn);
 231                        if (insn & 1 << 24) {
 232                                long aluop2;
 233
 234                                if (insn & 0x02000000)
 235                                        aluop2 = ptrace_getldrop2(child, insn);
 236                                else
 237                                        aluop2 = insn & 0xfff;
 238
 239                                if (insn & 1 << 23)
 240                                        base += aluop2;
 241                                else
 242                                        base -= aluop2;
 243                        }
 244                        if (read_tsk_long(child, base, &alt) == 0)
 245                                alt = pc_pointer(alt);
 246                }
 247                break;
 248
 249        case 0x08000000:
 250                /*
 251                 * ldm
 252                 */
 253                if ((insn & 0x00108000) == 0x00108000) {
 254                        unsigned long base;
 255                        unsigned int nr_regs;
 256
 257                        if (insn & (1 << 23)) {
 258                                nr_regs = insn & 65535;
 259
 260                                nr_regs = (nr_regs & 0x5555) + ((nr_regs & 0xaaaa) >> 1);
 261                                nr_regs = (nr_regs & 0x3333) + ((nr_regs & 0xcccc) >> 2);
 262                                nr_regs = (nr_regs & 0x0707) + ((nr_regs & 0x7070) >> 4);
 263                                nr_regs = (nr_regs & 0x000f) + ((nr_regs & 0x0f00) >> 8);
 264                                nr_regs <<= 2;
 265
 266                                if (!(insn & (1 << 24)))
 267                                        nr_regs -= 4;
 268                        } else {
 269                                if (insn & (1 << 24))
 270                                        nr_regs = -4;
 271                                else
 272                                        nr_regs = 0;
 273                        }
 274
 275                        base = ptrace_getrn(child, insn);
 276
 277                        if (read_tsk_long(child, base + nr_regs, &alt) == 0)
 278                                alt = pc_pointer (alt);
 279                        break;
 280                }
 281                break;
 282
 283        case 0x0a000000: {
 284                /*
 285                 * bl or b
 286                 */
 287                signed long displ;
 288                /* It's a branch/branch link: instead of trying to
 289                 * figure out whether the branch will be taken or not,
 290                 * we'll put a breakpoint at both locations.  This is
 291                 * simpler, more reliable, and probably not a whole lot
 292                 * slower than the alternative approach of emulating the
 293                 * branch.
 294                 */
 295                displ = (insn & 0x00ffffff) << 8;
 296                displ = (displ >> 6) + 8;
 297                if (displ != 0 && displ != 4)
 298                        alt = pc + displ;
 299            }
 300            break;
 301        }
 302
 303        return alt;
 304}
 305
 306static int
 307add_breakpoint(struct task_struct *child, struct debug_info *dbg, unsigned long addr)
 308{
 309        int nr = dbg->nsaved;
 310        int res = -EINVAL;
 311
 312        if (nr < 2) {
 313                res = read_tsk_long(child, addr, &dbg->bp[nr].insn);
 314                if (res == 0)
 315                        res = write_tsk_long(child, addr, BREAKINST);
 316
 317                if (res == 0) {
 318                        dbg->bp[nr].address = addr;
 319                        dbg->nsaved += 1;
 320                }
 321        } else
 322                printk(KERN_ERR "ptrace: too many breakpoints\n");
 323
 324        return res;
 325}
 326
 327int ptrace_set_bpt(struct task_struct *child)
 328{
 329        struct pt_regs *regs;
 330        unsigned long pc, insn;
 331        int res;
 332
 333        regs = get_user_regs(child);
 334        pc = instruction_pointer(regs);
 335
 336        res = read_tsk_long(child, pc, &insn);
 337        if (!res) {
 338                struct debug_info *dbg = &child->thread.debug;
 339                unsigned long alt;
 340
 341                dbg->nsaved = 0;
 342
 343                alt = get_branch_address(child, pc, insn);
 344                if (alt)
 345                        res = add_breakpoint(child, dbg, alt);
 346
 347                /*
 348                 * Note that we ignore the result of setting the above
 349                 * breakpoint since it may fail.  When it does, this is
 350                 * not so much an error, but a forewarning that we may
 351                 * be receiving a prefetch abort shortly.
 352                 *
 353                 * If we don't set this breakpoint here, then we can
 354                 * loose control of the thread during single stepping.
 355                 */
 356                if (!alt || predicate(insn) != PREDICATE_ALWAYS)
 357                        res = add_breakpoint(child, dbg, pc + 4);
 358        }
 359
 360        return res;
 361}
 362
 363/*
 364 * Ensure no single-step breakpoint is pending.  Returns non-zero
 365 * value if child was being single-stepped.
 366 */
 367void __ptrace_cancel_bpt(struct task_struct *child)
 368{
 369        struct debug_info *dbg = &child->thread.debug;
 370        int i, nsaved = dbg->nsaved;
 371
 372        dbg->nsaved = 0;
 373
 374        if (nsaved > 2) {
 375                printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
 376                nsaved = 2;
 377        }
 378
 379        for (i = 0; i < nsaved; i++) {
 380                unsigned long tmp;
 381
 382                read_tsk_long(child, dbg->bp[i].address, &tmp);
 383                write_tsk_long(child, dbg->bp[i].address, dbg->bp[i].insn);
 384                if (tmp != BREAKINST)
 385                        printk(KERN_ERR "ptrace_cancel_bpt: weirdness\n");
 386        }
 387}
 388
 389/*
 390 * Called by kernel/ptrace.c when detaching..
 391 *
 392 * Make sure the single step bit is not set.
 393 */
 394void ptrace_disable(struct task_struct *child)
 395{
 396        __ptrace_cancel_bpt(child);
 397}
 398
 399static int do_ptrace(int request, struct task_struct *child, long addr, long data)
 400{
 401        unsigned long tmp;
 402        int ret;
 403
 404        switch (request) {
 405                /*
 406                 * read word at location "addr" in the child process.
 407                 */
 408                case PTRACE_PEEKTEXT:
 409                case PTRACE_PEEKDATA:
 410                        ret = read_tsk_long(child, addr, &tmp);
 411                        if (!ret)
 412                                ret = put_user(tmp, (unsigned long *) data);
 413                        break;
 414
 415                /*
 416                 * read the word at location "addr" in the user registers.
 417                 */
 418                case PTRACE_PEEKUSR:
 419                        ret = -EIO;
 420                        if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
 421                                break;
 422
 423                        tmp = 0;  /* Default return condition */
 424                        if (addr < sizeof(struct pt_regs))
 425                                tmp = get_stack_long(child, (int)addr >> 2);
 426                        ret = put_user(tmp, (unsigned long *)data);
 427                        break;
 428
 429                /*
 430                 * write the word at location addr.
 431                 */
 432                case PTRACE_POKETEXT:
 433                case PTRACE_POKEDATA:
 434                        ret = write_tsk_long(child, addr, data);
 435                        break;
 436
 437                /*
 438                 * write the word at location addr in the user registers.
 439                 */
 440                case PTRACE_POKEUSR:
 441                        ret = -EIO;
 442                        if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
 443                                break;
 444
 445                        if (addr < sizeof(struct pt_regs))
 446                                ret = put_stack_long(child, (int)addr >> 2, data);
 447                        break;
 448
 449                /*
 450                 * continue/restart and stop at next (return from) syscall
 451                 */
 452                case PTRACE_SYSCALL:
 453                case PTRACE_CONT:
 454                        ret = -EIO;
 455                        if ((unsigned long) data > _NSIG)
 456                                break;
 457                        if (request == PTRACE_SYSCALL)
 458                                child->ptrace |= PT_TRACESYS;
 459                        else
 460                                child->ptrace &= ~PT_TRACESYS;
 461                        child->exit_code = data;
 462                        /* make sure single-step breakpoint is gone. */
 463                        __ptrace_cancel_bpt(child);
 464                        wake_up_process(child);
 465                        ret = 0;
 466                        break;
 467
 468                /*
 469                 * make the child exit.  Best I can do is send it a sigkill.
 470                 * perhaps it should be put in the status that it wants to
 471                 * exit.
 472                 */
 473                case PTRACE_KILL:
 474                        /* already dead */
 475                        ret = 0;
 476                        if (child->state == TASK_ZOMBIE)
 477                                break;
 478                        child->exit_code = SIGKILL;
 479                        /* make sure single-step breakpoint is gone. */
 480                        __ptrace_cancel_bpt(child);
 481                        wake_up_process(child);
 482                        ret = 0;
 483                        break;
 484
 485                /*
 486                 * execute single instruction.
 487                 */
 488                case PTRACE_SINGLESTEP:
 489                        ret = -EIO;
 490                        if ((unsigned long) data > _NSIG)
 491                                break;
 492                        child->thread.debug.nsaved = -1;
 493                        child->ptrace &= ~PT_TRACESYS;
 494                        child->exit_code = data;
 495                        /* give it a chance to run. */
 496                        wake_up_process(child);
 497                        ret = 0;
 498                        break;
 499
 500                /*
 501                 * detach a process that was attached.
 502                 */
 503                case PTRACE_DETACH:
 504                        ret = ptrace_detach(child, data);
 505                        break;
 506
 507                /*
 508                 * Get all gp regs from the child.
 509                 */
 510                case PTRACE_GETREGS: {
 511                        struct pt_regs *regs = get_user_regs(child);
 512
 513                        ret = 0;
 514                        if (copy_to_user((void *)data, regs,
 515                                         sizeof(struct pt_regs)))
 516                                ret = -EFAULT;
 517
 518                        break;
 519                }
 520
 521                /*
 522                 * Set all gp regs in the child.
 523                 */
 524                case PTRACE_SETREGS: {
 525                        struct pt_regs newregs;
 526
 527                        ret = -EFAULT;
 528                        if (copy_from_user(&newregs, (void *)data,
 529                                           sizeof(struct pt_regs)) == 0) {
 530                                struct pt_regs *regs = get_user_regs(child);
 531
 532                                ret = -EINVAL;
 533                                if (valid_user_regs(&newregs)) {
 534                                        *regs = newregs;
 535                                        ret = 0;
 536                                }
 537                        }
 538                        break;
 539                }
 540
 541                /*
 542                 * Get the child FPU state.
 543                 */
 544                case PTRACE_GETFPREGS:
 545                        ret = -EIO;
 546                        if (!access_ok(VERIFY_WRITE, (void *)data, sizeof(struct user_fp)))
 547                                break;
 548
 549                        /* we should check child->used_math here */
 550                        ret = __copy_to_user((void *)data, &child->thread.fpstate,
 551                                             sizeof(struct user_fp)) ? -EFAULT : 0;
 552                        break;
 553                
 554                /*
 555                 * Set the child FPU state.
 556                 */
 557                case PTRACE_SETFPREGS:
 558                        ret = -EIO;
 559                        if (!access_ok(VERIFY_READ, (void *)data, sizeof(struct user_fp)))
 560                                break;
 561
 562                        child->used_math = 1;
 563                        ret = __copy_from_user(&child->thread.fpstate, (void *)data,
 564                                           sizeof(struct user_fp)) ? -EFAULT : 0;
 565                        break;
 566
 567                default:
 568                        ret = -EIO;
 569                        break;
 570        }
 571
 572        return ret;
 573}
 574
 575asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 576{
 577        struct task_struct *child;
 578        int ret;
 579
 580        lock_kernel();
 581        ret = -EPERM;
 582        if (request == PTRACE_TRACEME) {
 583                /* are we already being traced? */
 584                if (current->ptrace & PT_PTRACED)
 585                        goto out;
 586                /* set the ptrace bit in the process flags. */
 587                current->ptrace |= PT_PTRACED;
 588                ret = 0;
 589                goto out;
 590        }
 591        ret = -ESRCH;
 592        read_lock(&tasklist_lock);
 593        child = find_task_by_pid(pid);
 594        if (child)
 595                get_task_struct(child);
 596        read_unlock(&tasklist_lock);
 597        if (!child)
 598                goto out;
 599
 600        ret = -EPERM;
 601        if (pid == 1)           /* you may not mess with init */
 602                goto out_tsk;
 603
 604        if (request == PTRACE_ATTACH) {
 605                ret = ptrace_attach(child);
 606                goto out_tsk;
 607        }
 608        ret = -ESRCH;
 609        if (!(child->ptrace & PT_PTRACED))
 610                goto out_tsk;
 611        if (child->state != TASK_STOPPED && request != PTRACE_KILL)
 612                goto out_tsk;
 613        if (child->p_pptr != current)
 614                goto out_tsk;
 615
 616        ret = do_ptrace(request, child, addr, data);
 617
 618out_tsk:
 619        free_task_struct(child);
 620out:
 621        unlock_kernel();
 622        return ret;
 623}
 624
 625asmlinkage void syscall_trace(int why, struct pt_regs *regs)
 626{
 627        unsigned long ip;
 628
 629        if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
 630                        != (PT_PTRACED|PT_TRACESYS))
 631                return;
 632
 633        /*
 634         * Save IP.  IP is used to denote syscall entry/exit:
 635         *  IP = 0 -> entry, = 1 -> exit
 636         */
 637        ip = regs->ARM_ip;
 638        regs->ARM_ip = why;
 639
 640        /* the 0x80 provides a way for the tracing parent to distinguish
 641           between a syscall stop and SIGTRAP delivery */
 642        current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
 643                                        ? 0x80 : 0);
 644        current->state = TASK_STOPPED;
 645        notify_parent(current, SIGCHLD);
 646        schedule();
 647        /*
 648         * this isn't the same as continuing with a signal, but it will do
 649         * for normal use.  strace only continues with a signal if the
 650         * stopping signal is not SIGTRAP.  -brl
 651         */
 652        if (current->exit_code) {
 653                send_sig(current->exit_code, current, 1);
 654                current->exit_code = 0;
 655        }
 656        regs->ARM_ip = ip;
 657}
 658
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.