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