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