linux/arch/mips/kernel/ptrace32.c
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * Copyright (C) 1992 Ross Biro
   7 * Copyright (C) Linus Torvalds
   8 * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle
   9 * Copyright (C) 1996 David S. Miller
  10 * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
  11 * Copyright (C) 1999 MIPS Technologies, Inc.
  12 * Copyright (C) 2000 Ulf Carlsson
  13 *
  14 * At this time Linux/MIPS64 only supports syscall tracing, even for 32-bit
  15 * binaries.
  16 */
  17#include <linux/compiler.h>
  18#include <linux/compat.h>
  19#include <linux/kernel.h>
  20#include <linux/sched.h>
  21#include <linux/mm.h>
  22#include <linux/errno.h>
  23#include <linux/ptrace.h>
  24#include <linux/smp.h>
  25#include <linux/user.h>
  26#include <linux/security.h>
  27
  28#include <asm/cpu.h>
  29#include <asm/dsp.h>
  30#include <asm/fpu.h>
  31#include <asm/mipsregs.h>
  32#include <asm/mipsmtregs.h>
  33#include <asm/pgtable.h>
  34#include <asm/page.h>
  35#include <asm/uaccess.h>
  36#include <asm/bootinfo.h>
  37
  38/*
  39 * Tracing a 32-bit process with a 64-bit strace and vice versa will not
  40 * work.  I don't know how to fix this.
  41 */
  42long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
  43                        compat_ulong_t caddr, compat_ulong_t cdata)
  44{
  45        int addr = caddr;
  46        int data = cdata;
  47        int ret;
  48
  49        switch (request) {
  50
  51        /*
  52         * Read 4 bytes of the other process' storage
  53         *  data is a pointer specifying where the user wants the
  54         *      4 bytes copied into
  55         *  addr is a pointer in the user's storage that contains an 8 byte
  56         *      address in the other process of the 4 bytes that is to be read
  57         * (this is run in a 32-bit process looking at a 64-bit process)
  58         * when I and D space are separate, these will need to be fixed.
  59         */
  60        case PTRACE_PEEKTEXT_3264:
  61        case PTRACE_PEEKDATA_3264: {
  62                u32 tmp;
  63                int copied;
  64                u32 __user * addrOthers;
  65
  66                ret = -EIO;
  67
  68                /* Get the addr in the other process that we want to read */
  69                if (get_user(addrOthers, (u32 __user * __user *) (unsigned long) addr) != 0)
  70                        break;
  71
  72                copied = access_process_vm(child, (u64)addrOthers, &tmp,
  73                                sizeof(tmp), 0);
  74                if (copied != sizeof(tmp))
  75                        break;
  76                ret = put_user(tmp, (u32 __user *) (unsigned long) data);
  77                break;
  78        }
  79
  80        /* Read the word at location addr in the USER area. */
  81        case PTRACE_PEEKUSR: {
  82                struct pt_regs *regs;
  83                unsigned int tmp;
  84
  85                regs = task_pt_regs(child);
  86                ret = 0;  /* Default return value. */
  87
  88                switch (addr) {
  89                case 0 ... 31:
  90                        tmp = regs->regs[addr];
  91                        break;
  92                case FPR_BASE ... FPR_BASE + 31:
  93                        if (tsk_used_math(child)) {
  94                                fpureg_t *fregs = get_fpu_regs(child);
  95
  96                                /*
  97                                 * The odd registers are actually the high
  98                                 * order bits of the values stored in the even
  99                                 * registers - unless we're using r2k_switch.S.
 100                                 */
 101                                if (addr & 1)
 102                                        tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32);
 103                                else
 104                                        tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff);
 105                        } else {
 106                                tmp = -1;       /* FP not yet used  */
 107                        }
 108                        break;
 109                case PC:
 110                        tmp = regs->cp0_epc;
 111                        break;
 112                case CAUSE:
 113                        tmp = regs->cp0_cause;
 114                        break;
 115                case BADVADDR:
 116                        tmp = regs->cp0_badvaddr;
 117                        break;
 118                case MMHI:
 119                        tmp = regs->hi;
 120                        break;
 121                case MMLO:
 122                        tmp = regs->lo;
 123                        break;
 124                case FPC_CSR:
 125                        tmp = child->thread.fpu.fcr31;
 126                        break;
 127                case FPC_EIR: { /* implementation / version register */
 128                        unsigned int flags;
 129#ifdef CONFIG_MIPS_MT_SMTC
 130                        unsigned int irqflags;
 131                        unsigned int mtflags;
 132#endif /* CONFIG_MIPS_MT_SMTC */
 133
 134                        preempt_disable();
 135                        if (!cpu_has_fpu) {
 136                                preempt_enable();
 137                                tmp = 0;
 138                                break;
 139                        }
 140
 141#ifdef CONFIG_MIPS_MT_SMTC
 142                        /* Read-modify-write of Status must be atomic */
 143                        local_irq_save(irqflags);
 144                        mtflags = dmt();
 145#endif /* CONFIG_MIPS_MT_SMTC */
 146
 147                        if (cpu_has_mipsmt) {
 148                                unsigned int vpflags = dvpe();
 149                                flags = read_c0_status();
 150                                __enable_fpu();
 151                                __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
 152                                write_c0_status(flags);
 153                                evpe(vpflags);
 154                        } else {
 155                                flags = read_c0_status();
 156                                __enable_fpu();
 157                                __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
 158                                write_c0_status(flags);
 159                        }
 160#ifdef CONFIG_MIPS_MT_SMTC
 161                        emt(mtflags);
 162                        local_irq_restore(irqflags);
 163#endif /* CONFIG_MIPS_MT_SMTC */
 164                        preempt_enable();
 165                        break;
 166                }
 167                case DSP_BASE ... DSP_BASE + 5: {
 168                        dspreg_t *dregs;
 169
 170                        if (!cpu_has_dsp) {
 171                                tmp = 0;
 172                                ret = -EIO;
 173                                goto out;
 174                        }
 175                        dregs = __get_dsp_regs(child);
 176                        tmp = (unsigned long) (dregs[addr - DSP_BASE]);
 177                        break;
 178                }
 179                case DSP_CONTROL:
 180                        if (!cpu_has_dsp) {
 181                                tmp = 0;
 182                                ret = -EIO;
 183                                goto out;
 184                        }
 185                        tmp = child->thread.dsp.dspcontrol;
 186                        break;
 187                default:
 188                        tmp = 0;
 189                        ret = -EIO;
 190                        goto out;
 191                }
 192                ret = put_user(tmp, (unsigned __user *) (unsigned long) data);
 193                break;
 194        }
 195
 196        /*
 197         * Write 4 bytes into the other process' storage
 198         *  data is the 4 bytes that the user wants written
 199         *  addr is a pointer in the user's storage that contains an
 200         *      8 byte address in the other process where the 4 bytes
 201         *      that is to be written
 202         * (this is run in a 32-bit process looking at a 64-bit process)
 203         * when I and D space are separate, these will need to be fixed.
 204         */
 205        case PTRACE_POKETEXT_3264:
 206        case PTRACE_POKEDATA_3264: {
 207                u32 __user * addrOthers;
 208
 209                /* Get the addr in the other process that we want to write into */
 210                ret = -EIO;
 211                if (get_user(addrOthers, (u32 __user * __user *) (unsigned long) addr) != 0)
 212                        break;
 213                ret = 0;
 214                if (access_process_vm(child, (u64)addrOthers, &data,
 215                                        sizeof(data), 1) == sizeof(data))
 216                        break;
 217                ret = -EIO;
 218                break;
 219        }
 220
 221        case PTRACE_POKEUSR: {
 222                struct pt_regs *regs;
 223                ret = 0;
 224                regs = task_pt_regs(child);
 225
 226                switch (addr) {
 227                case 0 ... 31:
 228                        regs->regs[addr] = data;
 229                        break;
 230                case FPR_BASE ... FPR_BASE + 31: {
 231                        fpureg_t *fregs = get_fpu_regs(child);
 232
 233                        if (!tsk_used_math(child)) {
 234                                /* FP not yet used  */
 235                                memset(&child->thread.fpu, ~0,
 236                                       sizeof(child->thread.fpu));
 237                                child->thread.fpu.fcr31 = 0;
 238                        }
 239                        /*
 240                         * The odd registers are actually the high order bits
 241                         * of the values stored in the even registers - unless
 242                         * we're using r2k_switch.S.
 243                         */
 244                        if (addr & 1) {
 245                                fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff;
 246                                fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long long) data) << 32;
 247                        } else {
 248                                fregs[addr - FPR_BASE] &= ~0xffffffffLL;
 249                                /* Must cast, lest sign extension fill upper
 250                                   bits!  */
 251                                fregs[addr - FPR_BASE] |= (unsigned int)data;
 252                        }
 253                        break;
 254                }
 255                case PC:
 256                        regs->cp0_epc = data;
 257                        break;
 258                case MMHI:
 259                        regs->hi = data;
 260                        break;
 261                case MMLO:
 262                        regs->lo = data;
 263                        break;
 264                case FPC_CSR:
 265                        child->thread.fpu.fcr31 = data;
 266                        break;
 267                case DSP_BASE ... DSP_BASE + 5: {
 268                        dspreg_t *dregs;
 269
 270                        if (!cpu_has_dsp) {
 271                                ret = -EIO;
 272                                break;
 273                        }
 274
 275                        dregs = __get_dsp_regs(child);
 276                        dregs[addr - DSP_BASE] = data;
 277                        break;
 278                }
 279                case DSP_CONTROL:
 280                        if (!cpu_has_dsp) {
 281                                ret = -EIO;
 282                                break;
 283                        }
 284                        child->thread.dsp.dspcontrol = data;
 285                        break;
 286                default:
 287                        /* The rest are not allowed. */
 288                        ret = -EIO;
 289                        break;
 290                }
 291                break;
 292                }
 293
 294        case PTRACE_GETREGS:
 295                ret = ptrace_getregs(child, (__s64 __user *) (__u64) data);
 296                break;
 297
 298        case PTRACE_SETREGS:
 299                ret = ptrace_setregs(child, (__s64 __user *) (__u64) data);
 300                break;
 301
 302        case PTRACE_GETFPREGS:
 303                ret = ptrace_getfpregs(child, (__u32 __user *) (__u64) data);
 304                break;
 305
 306        case PTRACE_SETFPREGS:
 307                ret = ptrace_setfpregs(child, (__u32 __user *) (__u64) data);
 308                break;
 309
 310        case PTRACE_GET_THREAD_AREA:
 311                ret = put_user(task_thread_info(child)->tp_value,
 312                                (unsigned int __user *) (unsigned long) data);
 313                break;
 314
 315        case PTRACE_GET_THREAD_AREA_3264:
 316                ret = put_user(task_thread_info(child)->tp_value,
 317                                (unsigned long __user *) (unsigned long) data);
 318                break;
 319
 320        case PTRACE_GET_WATCH_REGS:
 321                ret = ptrace_get_watch_regs(child,
 322                        (struct pt_watch_regs __user *) (unsigned long) addr);
 323                break;
 324
 325        case PTRACE_SET_WATCH_REGS:
 326                ret = ptrace_set_watch_regs(child,
 327                        (struct pt_watch_regs __user *) (unsigned long) addr);
 328                break;
 329
 330        default:
 331                ret = compat_ptrace_request(child, request, addr, data);
 332                break;
 333        }
 334out:
 335        return ret;
 336}
 337