Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * This file is subject to the terms and conditions of the GNU General Public
0003  * License.  See the file "COPYING" in the main directory of this archive
0004  * for more details.
0005  *
0006  * Copyright (C) 1992 Ross Biro
0007  * Copyright (C) Linus Torvalds
0008  * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle
0009  * Copyright (C) 1996 David S. Miller
0010  * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
0011  * Copyright (C) 1999 MIPS Technologies, Inc.
0012  * Copyright (C) 2000 Ulf Carlsson
0013  *
0014  * At this time Linux/MIPS64 only supports syscall tracing, even for 32-bit
0015  * binaries.
0016  */
0017 #include <linux/compiler.h>
0018 #include <linux/compat.h>
0019 #include <linux/kernel.h>
0020 #include <linux/sched.h>
0021 #include <linux/sched/task_stack.h>
0022 #include <linux/mm.h>
0023 #include <linux/errno.h>
0024 #include <linux/ptrace.h>
0025 #include <linux/smp.h>
0026 #include <linux/security.h>
0027 
0028 #include <asm/cpu.h>
0029 #include <asm/dsp.h>
0030 #include <asm/fpu.h>
0031 #include <asm/mipsregs.h>
0032 #include <asm/mipsmtregs.h>
0033 #include <asm/page.h>
0034 #include <asm/reg.h>
0035 #include <asm/syscall.h>
0036 #include <linux/uaccess.h>
0037 #include <asm/bootinfo.h>
0038 
0039 /*
0040  * Tracing a 32-bit process with a 64-bit strace and vice versa will not
0041  * work.  I don't know how to fix this.
0042  */
0043 long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
0044             compat_ulong_t caddr, compat_ulong_t cdata)
0045 {
0046     int addr = caddr;
0047     int data = cdata;
0048     int ret;
0049 
0050     switch (request) {
0051 
0052     /*
0053      * Read 4 bytes of the other process' storage
0054      *  data is a pointer specifying where the user wants the
0055      *  4 bytes copied into
0056      *  addr is a pointer in the user's storage that contains an 8 byte
0057      *  address in the other process of the 4 bytes that is to be read
0058      * (this is run in a 32-bit process looking at a 64-bit process)
0059      * when I and D space are separate, these will need to be fixed.
0060      */
0061     case PTRACE_PEEKTEXT_3264:
0062     case PTRACE_PEEKDATA_3264: {
0063         u32 tmp;
0064         int copied;
0065         u32 __user * addrOthers;
0066 
0067         ret = -EIO;
0068 
0069         /* Get the addr in the other process that we want to read */
0070         if (get_user(addrOthers, (u32 __user * __user *) (unsigned long) addr) != 0)
0071             break;
0072 
0073         copied = ptrace_access_vm(child, (u64)addrOthers, &tmp,
0074                 sizeof(tmp), FOLL_FORCE);
0075         if (copied != sizeof(tmp))
0076             break;
0077         ret = put_user(tmp, (u32 __user *) (unsigned long) data);
0078         break;
0079     }
0080 
0081     /* Read the word at location addr in the USER area. */
0082     case PTRACE_PEEKUSR: {
0083         struct pt_regs *regs;
0084         unsigned int tmp;
0085 
0086         regs = task_pt_regs(child);
0087         ret = 0;  /* Default return value. */
0088 
0089         switch (addr) {
0090         case 0 ... 31:
0091             tmp = regs->regs[addr];
0092             break;
0093 #ifdef CONFIG_MIPS_FP_SUPPORT
0094         case FPR_BASE ... FPR_BASE + 31: {
0095             union fpureg *fregs;
0096 
0097             if (!tsk_used_math(child)) {
0098                 /* FP not yet used */
0099                 tmp = -1;
0100                 break;
0101             }
0102             fregs = get_fpu_regs(child);
0103             if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) {
0104                 /*
0105                  * The odd registers are actually the high
0106                  * order bits of the values stored in the even
0107                  * registers.
0108                  */
0109                 tmp = get_fpr32(&fregs[(addr & ~1) - FPR_BASE],
0110                         addr & 1);
0111                 break;
0112             }
0113             tmp = get_fpr64(&fregs[addr - FPR_BASE], 0);
0114             break;
0115         }
0116         case FPC_CSR:
0117             tmp = child->thread.fpu.fcr31;
0118             break;
0119         case FPC_EIR:
0120             /* implementation / version register */
0121             tmp = boot_cpu_data.fpu_id;
0122             break;
0123 #endif /* CONFIG_MIPS_FP_SUPPORT */
0124         case PC:
0125             tmp = regs->cp0_epc;
0126             break;
0127         case CAUSE:
0128             tmp = regs->cp0_cause;
0129             break;
0130         case BADVADDR:
0131             tmp = regs->cp0_badvaddr;
0132             break;
0133         case MMHI:
0134             tmp = regs->hi;
0135             break;
0136         case MMLO:
0137             tmp = regs->lo;
0138             break;
0139         case DSP_BASE ... DSP_BASE + 5: {
0140             dspreg_t *dregs;
0141 
0142             if (!cpu_has_dsp) {
0143                 tmp = 0;
0144                 ret = -EIO;
0145                 goto out;
0146             }
0147             dregs = __get_dsp_regs(child);
0148             tmp = dregs[addr - DSP_BASE];
0149             break;
0150         }
0151         case DSP_CONTROL:
0152             if (!cpu_has_dsp) {
0153                 tmp = 0;
0154                 ret = -EIO;
0155                 goto out;
0156             }
0157             tmp = child->thread.dsp.dspcontrol;
0158             break;
0159         default:
0160             tmp = 0;
0161             ret = -EIO;
0162             goto out;
0163         }
0164         ret = put_user(tmp, (unsigned __user *) (unsigned long) data);
0165         break;
0166     }
0167 
0168     /*
0169      * Write 4 bytes into the other process' storage
0170      *  data is the 4 bytes that the user wants written
0171      *  addr is a pointer in the user's storage that contains an
0172      *  8 byte address in the other process where the 4 bytes
0173      *  that is to be written
0174      * (this is run in a 32-bit process looking at a 64-bit process)
0175      * when I and D space are separate, these will need to be fixed.
0176      */
0177     case PTRACE_POKETEXT_3264:
0178     case PTRACE_POKEDATA_3264: {
0179         u32 __user * addrOthers;
0180 
0181         /* Get the addr in the other process that we want to write into */
0182         ret = -EIO;
0183         if (get_user(addrOthers, (u32 __user * __user *) (unsigned long) addr) != 0)
0184             break;
0185         ret = 0;
0186         if (ptrace_access_vm(child, (u64)addrOthers, &data,
0187                     sizeof(data),
0188                     FOLL_FORCE | FOLL_WRITE) == sizeof(data))
0189             break;
0190         ret = -EIO;
0191         break;
0192     }
0193 
0194     case PTRACE_POKEUSR: {
0195         struct pt_regs *regs;
0196         ret = 0;
0197         regs = task_pt_regs(child);
0198 
0199         switch (addr) {
0200         case 0 ... 31:
0201             regs->regs[addr] = data;
0202             /* System call number may have been changed */
0203             if (addr == 2)
0204                 mips_syscall_update_nr(child, regs);
0205             else if (addr == 4 &&
0206                  mips_syscall_is_indirect(child, regs))
0207                 mips_syscall_update_nr(child, regs);
0208             break;
0209 #ifdef CONFIG_MIPS_FP_SUPPORT
0210         case FPR_BASE ... FPR_BASE + 31: {
0211             union fpureg *fregs = get_fpu_regs(child);
0212 
0213             if (!tsk_used_math(child)) {
0214                 /* FP not yet used  */
0215                 memset(&child->thread.fpu, ~0,
0216                        sizeof(child->thread.fpu));
0217                 child->thread.fpu.fcr31 = 0;
0218             }
0219             if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) {
0220                 /*
0221                  * The odd registers are actually the high
0222                  * order bits of the values stored in the even
0223                  * registers.
0224                  */
0225                 set_fpr32(&fregs[(addr & ~1) - FPR_BASE],
0226                       addr & 1, data);
0227                 break;
0228             }
0229             set_fpr64(&fregs[addr - FPR_BASE], 0, data);
0230             break;
0231         }
0232         case FPC_CSR:
0233             child->thread.fpu.fcr31 = data;
0234             break;
0235 #endif /* CONFIG_MIPS_FP_SUPPORT */
0236         case PC:
0237             regs->cp0_epc = data;
0238             break;
0239         case MMHI:
0240             regs->hi = data;
0241             break;
0242         case MMLO:
0243             regs->lo = data;
0244             break;
0245         case DSP_BASE ... DSP_BASE + 5: {
0246             dspreg_t *dregs;
0247 
0248             if (!cpu_has_dsp) {
0249                 ret = -EIO;
0250                 break;
0251             }
0252 
0253             dregs = __get_dsp_regs(child);
0254             dregs[addr - DSP_BASE] = data;
0255             break;
0256         }
0257         case DSP_CONTROL:
0258             if (!cpu_has_dsp) {
0259                 ret = -EIO;
0260                 break;
0261             }
0262             child->thread.dsp.dspcontrol = data;
0263             break;
0264         default:
0265             /* The rest are not allowed. */
0266             ret = -EIO;
0267             break;
0268         }
0269         break;
0270         }
0271 
0272     case PTRACE_GETREGS:
0273         ret = ptrace_getregs(child,
0274                 (struct user_pt_regs __user *) (__u64) data);
0275         break;
0276 
0277     case PTRACE_SETREGS:
0278         ret = ptrace_setregs(child,
0279                 (struct user_pt_regs __user *) (__u64) data);
0280         break;
0281 
0282 #ifdef CONFIG_MIPS_FP_SUPPORT
0283     case PTRACE_GETFPREGS:
0284         ret = ptrace_getfpregs(child, (__u32 __user *) (__u64) data);
0285         break;
0286 
0287     case PTRACE_SETFPREGS:
0288         ret = ptrace_setfpregs(child, (__u32 __user *) (__u64) data);
0289         break;
0290 #endif
0291     case PTRACE_GET_THREAD_AREA:
0292         ret = put_user(task_thread_info(child)->tp_value,
0293                 (unsigned int __user *) (unsigned long) data);
0294         break;
0295 
0296     case PTRACE_GET_THREAD_AREA_3264:
0297         ret = put_user(task_thread_info(child)->tp_value,
0298                 (unsigned long __user *) (unsigned long) data);
0299         break;
0300 
0301     case PTRACE_GET_WATCH_REGS:
0302         ret = ptrace_get_watch_regs(child,
0303             (struct pt_watch_regs __user *) (unsigned long) addr);
0304         break;
0305 
0306     case PTRACE_SET_WATCH_REGS:
0307         ret = ptrace_set_watch_regs(child,
0308             (struct pt_watch_regs __user *) (unsigned long) addr);
0309         break;
0310 
0311     default:
0312         ret = compat_ptrace_request(child, request, addr, data);
0313         break;
0314     }
0315 out:
0316     return ret;
0317 }