linux/arch/xtensa/kernel/ptrace.c
<<
>>
Prefs
   1// TODO some minor issues
   2/*
   3 * This file is subject to the terms and conditions of the GNU General Public
   4 * License.  See the file "COPYING" in the main directory of this archive
   5 * for more details.
   6 *
   7 * Copyright (C) 2001 - 2007  Tensilica Inc.
   8 *
   9 * Joe Taylor   <joe@tensilica.com, joetylr@yahoo.com>
  10 * Chris Zankel <chris@zankel.net>
  11 * Scott Foehner<sfoehner@yahoo.com>,
  12 * Kevin Chea
  13 * Marc Gauthier<marc@tensilica.com> <marc@alumni.uwaterloo.ca>
  14 */
  15
  16#include <linux/kernel.h>
  17#include <linux/sched.h>
  18#include <linux/mm.h>
  19#include <linux/errno.h>
  20#include <linux/ptrace.h>
  21#include <linux/smp.h>
  22#include <linux/security.h>
  23#include <linux/signal.h>
  24
  25#include <asm/pgtable.h>
  26#include <asm/page.h>
  27#include <asm/system.h>
  28#include <asm/uaccess.h>
  29#include <asm/ptrace.h>
  30#include <asm/elf.h>
  31#include <asm/coprocessor.h>
  32
  33/*
  34 * Called by kernel/ptrace.c when detaching to disable single stepping.
  35 */
  36
  37void ptrace_disable(struct task_struct *child)
  38{
  39        /* Nothing to do.. */
  40}
  41
  42int ptrace_getregs(struct task_struct *child, void __user *uregs)
  43{
  44        struct pt_regs *regs = task_pt_regs(child);
  45        xtensa_gregset_t __user *gregset = uregs;
  46        unsigned long wm = regs->wmask;
  47        unsigned long wb = regs->windowbase;
  48        int live, i;
  49
  50        if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t)))
  51                return -EIO;
  52
  53        __put_user(regs->pc, &gregset->pc);
  54        __put_user(regs->ps & ~(1 << PS_EXCM_BIT), &gregset->ps);
  55        __put_user(regs->lbeg, &gregset->lbeg);
  56        __put_user(regs->lend, &gregset->lend);
  57        __put_user(regs->lcount, &gregset->lcount);
  58        __put_user(regs->windowstart, &gregset->windowstart);
  59        __put_user(regs->windowbase, &gregset->windowbase);
  60
  61        live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16;
  62
  63        for (i = 0; i < live; i++)
  64                __put_user(regs->areg[i],gregset->a+((wb*4+i)%XCHAL_NUM_AREGS));
  65        for (i = XCHAL_NUM_AREGS - (wm >> 4) * 4; i < XCHAL_NUM_AREGS; i++)
  66                __put_user(regs->areg[i],gregset->a+((wb*4+i)%XCHAL_NUM_AREGS));
  67
  68        return 0;
  69}
  70
  71int ptrace_setregs(struct task_struct *child, void __user *uregs)
  72{
  73        struct pt_regs *regs = task_pt_regs(child);
  74        xtensa_gregset_t *gregset = uregs;
  75        const unsigned long ps_mask = PS_CALLINC_MASK | PS_OWB_MASK;
  76        unsigned long ps;
  77        unsigned long wb;
  78
  79        if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t)))
  80                return -EIO;
  81
  82        __get_user(regs->pc, &gregset->pc);
  83        __get_user(ps, &gregset->ps);
  84        __get_user(regs->lbeg, &gregset->lbeg);
  85        __get_user(regs->lend, &gregset->lend);
  86        __get_user(regs->lcount, &gregset->lcount);
  87        __get_user(regs->windowstart, &gregset->windowstart);
  88        __get_user(wb, &gregset->windowbase);
  89
  90        regs->ps = (regs->ps & ~ps_mask) | (ps & ps_mask) | (1 << PS_EXCM_BIT);
  91
  92        if (wb >= XCHAL_NUM_AREGS / 4)
  93                return -EFAULT;
  94
  95        regs->windowbase = wb;
  96
  97        if (wb != 0 &&  __copy_from_user(regs->areg + XCHAL_NUM_AREGS - wb * 4,
  98                                         gregset->a, wb * 16))
  99                return -EFAULT;
 100
 101        if (__copy_from_user(regs->areg, gregset->a + wb*4, (WSBITS-wb) * 16))
 102                return -EFAULT;
 103
 104        return 0;
 105}
 106
 107
 108int ptrace_getxregs(struct task_struct *child, void __user *uregs)
 109{
 110        struct pt_regs *regs = task_pt_regs(child);
 111        struct thread_info *ti = task_thread_info(child);
 112        elf_xtregs_t __user *xtregs = uregs;
 113        int ret = 0;
 114
 115        if (!access_ok(VERIFY_WRITE, uregs, sizeof(elf_xtregs_t)))
 116                return -EIO;
 117
 118#if XTENSA_HAVE_COPROCESSORS
 119        /* Flush all coprocessor registers to memory. */
 120        coprocessor_flush_all(ti);
 121        ret |= __copy_to_user(&xtregs->cp0, &ti->xtregs_cp,
 122                              sizeof(xtregs_coprocessor_t));
 123#endif
 124        ret |= __copy_to_user(&xtregs->opt, &regs->xtregs_opt,
 125                              sizeof(xtregs->opt));
 126        ret |= __copy_to_user(&xtregs->user,&ti->xtregs_user,
 127                              sizeof(xtregs->user));
 128
 129        return ret ? -EFAULT : 0;
 130}
 131
 132int ptrace_setxregs(struct task_struct *child, void __user *uregs)
 133{
 134        struct thread_info *ti = task_thread_info(child);
 135        struct pt_regs *regs = task_pt_regs(child);
 136        elf_xtregs_t *xtregs = uregs;
 137        int ret = 0;
 138
 139#if XTENSA_HAVE_COPROCESSORS
 140        /* Flush all coprocessors before we overwrite them. */
 141        coprocessor_flush_all(ti);
 142        coprocessor_release_all(ti);
 143
 144        ret |= __copy_from_user(&ti->xtregs_cp, &xtregs->cp0, 
 145                                sizeof(xtregs_coprocessor_t));
 146#endif
 147        ret |= __copy_from_user(&regs->xtregs_opt, &xtregs->opt,
 148                                sizeof(xtregs->opt));
 149        ret |= __copy_from_user(&ti->xtregs_user, &xtregs->user,
 150                                sizeof(xtregs->user));
 151
 152        return ret ? -EFAULT : 0;
 153}
 154
 155int ptrace_peekusr(struct task_struct *child, long regno, long __user *ret)
 156{
 157        struct pt_regs *regs;
 158        unsigned long tmp;
 159
 160        regs = task_pt_regs(child);
 161        tmp = 0;  /* Default return value. */
 162
 163        switch(regno) {
 164
 165                case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1:
 166                        tmp = regs->areg[regno - REG_AR_BASE];
 167                        break;
 168
 169                case REG_A_BASE ... REG_A_BASE + 15:
 170                        tmp = regs->areg[regno - REG_A_BASE];
 171                        break;
 172
 173                case REG_PC:
 174                        tmp = regs->pc;
 175                        break;
 176
 177                case REG_PS:
 178                        /* Note:  PS.EXCM is not set while user task is running;
 179                         * its being set in regs is for exception handling
 180                         * convenience.  */
 181                        tmp = (regs->ps & ~(1 << PS_EXCM_BIT));
 182                        break;
 183
 184                case REG_WB:
 185                        break;          /* tmp = 0 */
 186
 187                case REG_WS:
 188                {
 189                        unsigned long wb = regs->windowbase;
 190                        unsigned long ws = regs->windowstart;
 191                        tmp = ((ws>>wb) | (ws<<(WSBITS-wb))) & ((1<<WSBITS)-1);
 192                        break;
 193                }
 194                case REG_LBEG:
 195                        tmp = regs->lbeg;
 196                        break;
 197
 198                case REG_LEND:
 199                        tmp = regs->lend;
 200                        break;
 201
 202                case REG_LCOUNT:
 203                        tmp = regs->lcount;
 204                        break;
 205
 206                case REG_SAR:
 207                        tmp = regs->sar;
 208                        break;
 209
 210                case SYSCALL_NR:
 211                        tmp = regs->syscall;
 212                        break;
 213
 214                default:
 215                        return -EIO;
 216        }
 217        return put_user(tmp, ret);
 218}
 219
 220int ptrace_pokeusr(struct task_struct *child, long regno, long val)
 221{
 222        struct pt_regs *regs;
 223        regs = task_pt_regs(child);
 224
 225        switch (regno) {
 226                case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1:
 227                        regs->areg[regno - REG_AR_BASE] = val;
 228                        break;
 229
 230                case REG_A_BASE ... REG_A_BASE + 15:
 231                        regs->areg[regno - REG_A_BASE] = val;
 232                        break;
 233
 234                case REG_PC:
 235                        regs->pc = val;
 236                        break;
 237
 238                case SYSCALL_NR:
 239                        regs->syscall = val;
 240                        break;
 241
 242                default:
 243                        return -EIO;
 244        }
 245        return 0;
 246}
 247
 248long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 249{
 250        int ret = -EPERM;
 251
 252        switch (request) {
 253        case PTRACE_PEEKTEXT:   /* read word at location addr. */
 254        case PTRACE_PEEKDATA:
 255                ret = generic_ptrace_peekdata(child, addr, data);
 256                break;
 257
 258        case PTRACE_PEEKUSR:    /* read register specified by addr. */
 259                ret = ptrace_peekusr(child, addr, (void __user *) data);
 260                break;
 261
 262        case PTRACE_POKETEXT:   /* write the word at location addr. */
 263        case PTRACE_POKEDATA:
 264                ret = generic_ptrace_pokedata(child, addr, data);
 265                break;
 266
 267        case PTRACE_POKEUSR:    /* write register specified by addr. */
 268                ret = ptrace_pokeusr(child, addr, data);
 269                break;
 270
 271        /* continue and stop at next (return from) syscall */
 272
 273        case PTRACE_SYSCALL:
 274        case PTRACE_CONT: /* restart after signal. */
 275        {
 276                ret = -EIO;
 277                if (!valid_signal(data))
 278                        break;
 279                if (request == PTRACE_SYSCALL)
 280                        set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 281                else
 282                        clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 283                child->exit_code = data;
 284                /* Make sure the single step bit is not set. */
 285                child->ptrace &= ~PT_SINGLESTEP;
 286                wake_up_process(child);
 287                ret = 0;
 288                break;
 289        }
 290
 291        /*
 292         * make the child exit.  Best I can do is send it a sigkill.
 293         * perhaps it should be put in the status that it wants to
 294         * exit.
 295         */
 296        case PTRACE_KILL:
 297                ret = 0;
 298                if (child->exit_state == EXIT_ZOMBIE)   /* already dead */
 299                        break;
 300                child->exit_code = SIGKILL;
 301                child->ptrace &= ~PT_SINGLESTEP;
 302                wake_up_process(child);
 303                break;
 304
 305        case PTRACE_SINGLESTEP:
 306                ret = -EIO;
 307                if (!valid_signal(data))
 308                        break;
 309                clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 310                child->ptrace |= PT_SINGLESTEP;
 311                child->exit_code = data;
 312                wake_up_process(child);
 313                ret = 0;
 314                break;
 315
 316        case PTRACE_GETREGS:
 317                ret = ptrace_getregs(child, (void __user *) data);
 318                break;
 319
 320        case PTRACE_SETREGS:
 321                ret = ptrace_setregs(child, (void __user *) data);
 322                break;
 323
 324        case PTRACE_GETXTREGS:
 325                ret = ptrace_getxregs(child, (void __user *) data);
 326                break;
 327
 328        case PTRACE_SETXTREGS:
 329                ret = ptrace_setxregs(child, (void __user *) data);
 330                break;
 331
 332        default:
 333                ret = ptrace_request(child, request, addr, data);
 334                break;
 335        }
 336
 337        return ret;
 338}
 339
 340void do_syscall_trace(void)
 341{
 342        /*
 343         * The 0x80 provides a way for the tracing parent to distinguish
 344         * between a syscall stop and SIGTRAP delivery
 345         */
 346        ptrace_notify(SIGTRAP|((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
 347
 348        /*
 349         * this isn't the same as continuing with a signal, but it will do
 350         * for normal use.  strace only continues with a signal if the
 351         * stopping signal is not SIGTRAP.  -brl
 352         */
 353        if (current->exit_code) {
 354                send_sig(current->exit_code, current, 1);
 355                current->exit_code = 0;
 356        }
 357}
 358
 359void do_syscall_trace_enter(struct pt_regs *regs)
 360{
 361        if (test_thread_flag(TIF_SYSCALL_TRACE)
 362                        && (current->ptrace & PT_PTRACED))
 363                do_syscall_trace();
 364
 365#if 0
 366        if (unlikely(current->audit_context))
 367                audit_syscall_entry(current, AUDIT_ARCH_XTENSA..);
 368#endif
 369}
 370
 371void do_syscall_trace_leave(struct pt_regs *regs)
 372{
 373        if ((test_thread_flag(TIF_SYSCALL_TRACE))
 374                        && (current->ptrace & PT_PTRACED))
 375                do_syscall_trace();
 376}
 377
 378