11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public
31da177e4SLinus Torvalds * License. See the file "COPYING" in the main directory of this archive
41da177e4SLinus Torvalds * for more details.
51da177e4SLinus Torvalds *
61da177e4SLinus Torvalds * Copyright (C) 1992 Ross Biro
71da177e4SLinus Torvalds * Copyright (C) Linus Torvalds
81da177e4SLinus Torvalds * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle
91da177e4SLinus Torvalds * Copyright (C) 1996 David S. Miller
101da177e4SLinus Torvalds * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
111da177e4SLinus Torvalds * Copyright (C) 1999 MIPS Technologies, Inc.
121da177e4SLinus Torvalds * Copyright (C) 2000 Ulf Carlsson
131da177e4SLinus Torvalds *
141da177e4SLinus Torvalds * At this time Linux/MIPS64 only supports syscall tracing, even for 32-bit
151da177e4SLinus Torvalds * binaries.
161da177e4SLinus Torvalds */
171da177e4SLinus Torvalds #include <linux/compiler.h>
185d9a76cdSThomas Bogendoerfer #include <linux/compat.h>
191da177e4SLinus Torvalds #include <linux/kernel.h>
201da177e4SLinus Torvalds #include <linux/sched.h>
2168db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
221da177e4SLinus Torvalds #include <linux/mm.h>
231da177e4SLinus Torvalds #include <linux/errno.h>
241da177e4SLinus Torvalds #include <linux/ptrace.h>
251da177e4SLinus Torvalds #include <linux/smp.h>
261da177e4SLinus Torvalds #include <linux/security.h>
271da177e4SLinus Torvalds
281da177e4SLinus Torvalds #include <asm/cpu.h>
29e50c0a8fSRalf Baechle #include <asm/dsp.h>
301da177e4SLinus Torvalds #include <asm/fpu.h>
311da177e4SLinus Torvalds #include <asm/mipsregs.h>
32101b3531SRalf Baechle #include <asm/mipsmtregs.h>
331da177e4SLinus Torvalds #include <asm/page.h>
3460be939cSAlex Smith #include <asm/reg.h>
35de8cd0dcSJames Hogan #include <asm/syscall.h>
367c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
371da177e4SLinus Torvalds #include <asm/bootinfo.h>
381da177e4SLinus Torvalds
391da177e4SLinus Torvalds /*
401da177e4SLinus Torvalds * Tracing a 32-bit process with a 64-bit strace and vice versa will not
411da177e4SLinus Torvalds * work. I don't know how to fix this.
421da177e4SLinus Torvalds */
compat_arch_ptrace(struct task_struct * child,compat_long_t request,compat_ulong_t caddr,compat_ulong_t cdata)435d9a76cdSThomas Bogendoerfer long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
445d9a76cdSThomas Bogendoerfer compat_ulong_t caddr, compat_ulong_t cdata)
451da177e4SLinus Torvalds {
465d9a76cdSThomas Bogendoerfer int addr = caddr;
475d9a76cdSThomas Bogendoerfer int data = cdata;
481da177e4SLinus Torvalds int ret;
491da177e4SLinus Torvalds
501da177e4SLinus Torvalds switch (request) {
511da177e4SLinus Torvalds
52ea3d710fSDaniel Jacobowitz /*
53ea3d710fSDaniel Jacobowitz * Read 4 bytes of the other process' storage
54ea3d710fSDaniel Jacobowitz * data is a pointer specifying where the user wants the
55ea3d710fSDaniel Jacobowitz * 4 bytes copied into
56ea3d710fSDaniel Jacobowitz * addr is a pointer in the user's storage that contains an 8 byte
57ea3d710fSDaniel Jacobowitz * address in the other process of the 4 bytes that is to be read
58ea3d710fSDaniel Jacobowitz * (this is run in a 32-bit process looking at a 64-bit process)
59ea3d710fSDaniel Jacobowitz * when I and D space are separate, these will need to be fixed.
60ea3d710fSDaniel Jacobowitz */
61ea3d710fSDaniel Jacobowitz case PTRACE_PEEKTEXT_3264:
62ea3d710fSDaniel Jacobowitz case PTRACE_PEEKDATA_3264: {
63ea3d710fSDaniel Jacobowitz u32 tmp;
64ea3d710fSDaniel Jacobowitz int copied;
65ea3d710fSDaniel Jacobowitz u32 __user * addrOthers;
66ea3d710fSDaniel Jacobowitz
67ea3d710fSDaniel Jacobowitz ret = -EIO;
68ea3d710fSDaniel Jacobowitz
69ea3d710fSDaniel Jacobowitz /* Get the addr in the other process that we want to read */
70ea3d710fSDaniel Jacobowitz if (get_user(addrOthers, (u32 __user * __user *) (unsigned long) addr) != 0)
71ea3d710fSDaniel Jacobowitz break;
72ea3d710fSDaniel Jacobowitz
7384d77d3fSEric W. Biederman copied = ptrace_access_vm(child, (u64)addrOthers, &tmp,
74f307ab6dSLorenzo Stoakes sizeof(tmp), FOLL_FORCE);
75ea3d710fSDaniel Jacobowitz if (copied != sizeof(tmp))
76ea3d710fSDaniel Jacobowitz break;
77ea3d710fSDaniel Jacobowitz ret = put_user(tmp, (u32 __user *) (unsigned long) data);
78ea3d710fSDaniel Jacobowitz break;
79ea3d710fSDaniel Jacobowitz }
80ea3d710fSDaniel Jacobowitz
811da177e4SLinus Torvalds /* Read the word at location addr in the USER area. */
821da177e4SLinus Torvalds case PTRACE_PEEKUSR: {
831da177e4SLinus Torvalds struct pt_regs *regs;
841da177e4SLinus Torvalds unsigned int tmp;
851da177e4SLinus Torvalds
8640bc9c67SAl Viro regs = task_pt_regs(child);
871da177e4SLinus Torvalds ret = 0; /* Default return value. */
881da177e4SLinus Torvalds
891da177e4SLinus Torvalds switch (addr) {
901da177e4SLinus Torvalds case 0 ... 31:
911da177e4SLinus Torvalds tmp = regs->regs[addr];
921da177e4SLinus Torvalds break;
93*6c79759eSPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT
94*6c79759eSPaul Burton case FPR_BASE ... FPR_BASE + 31: {
95*6c79759eSPaul Burton union fpureg *fregs;
96*6c79759eSPaul Burton
97597ce172SPaul Burton if (!tsk_used_math(child)) {
98597ce172SPaul Burton /* FP not yet used */
99597ce172SPaul Burton tmp = -1;
100597ce172SPaul Burton break;
101597ce172SPaul Burton }
102597ce172SPaul Burton fregs = get_fpu_regs(child);
1039a3a92ccSMaciej W. Rozycki if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) {
1041da177e4SLinus Torvalds /*
1051da177e4SLinus Torvalds * The odd registers are actually the high
1061da177e4SLinus Torvalds * order bits of the values stored in the even
107d1157b10SMaciej W. Rozycki * registers.
1081da177e4SLinus Torvalds */
109bbd426f5SPaul Burton tmp = get_fpr32(&fregs[(addr & ~1) - FPR_BASE],
110bbd426f5SPaul Burton addr & 1);
111597ce172SPaul Burton break;
1121da177e4SLinus Torvalds }
113c7e81462SMaciej W. Rozycki tmp = get_fpr64(&fregs[addr - FPR_BASE], 0);
1141da177e4SLinus Torvalds break;
115*6c79759eSPaul Burton }
116*6c79759eSPaul Burton case FPC_CSR:
117*6c79759eSPaul Burton tmp = child->thread.fpu.fcr31;
118*6c79759eSPaul Burton break;
119*6c79759eSPaul Burton case FPC_EIR:
120*6c79759eSPaul Burton /* implementation / version register */
121*6c79759eSPaul Burton tmp = boot_cpu_data.fpu_id;
122*6c79759eSPaul Burton break;
123*6c79759eSPaul Burton #endif /* CONFIG_MIPS_FP_SUPPORT */
1241da177e4SLinus Torvalds case PC:
1251da177e4SLinus Torvalds tmp = regs->cp0_epc;
1261da177e4SLinus Torvalds break;
1271da177e4SLinus Torvalds case CAUSE:
1281da177e4SLinus Torvalds tmp = regs->cp0_cause;
1291da177e4SLinus Torvalds break;
1301da177e4SLinus Torvalds case BADVADDR:
1311da177e4SLinus Torvalds tmp = regs->cp0_badvaddr;
1321da177e4SLinus Torvalds break;
1331da177e4SLinus Torvalds case MMHI:
1341da177e4SLinus Torvalds tmp = regs->hi;
1351da177e4SLinus Torvalds break;
1361da177e4SLinus Torvalds case MMLO:
1371da177e4SLinus Torvalds tmp = regs->lo;
1381da177e4SLinus Torvalds break;
1393055acb0SAtsushi Nemoto case DSP_BASE ... DSP_BASE + 5: {
1403055acb0SAtsushi Nemoto dspreg_t *dregs;
1413055acb0SAtsushi Nemoto
142e50c0a8fSRalf Baechle if (!cpu_has_dsp) {
143e50c0a8fSRalf Baechle tmp = 0;
144e50c0a8fSRalf Baechle ret = -EIO;
1455d9a76cdSThomas Bogendoerfer goto out;
146e50c0a8fSRalf Baechle }
1473055acb0SAtsushi Nemoto dregs = __get_dsp_regs(child);
148f5958b4cSMaciej W. Rozycki tmp = dregs[addr - DSP_BASE];
149e50c0a8fSRalf Baechle break;
1503055acb0SAtsushi Nemoto }
151e50c0a8fSRalf Baechle case DSP_CONTROL:
152e50c0a8fSRalf Baechle if (!cpu_has_dsp) {
153e50c0a8fSRalf Baechle tmp = 0;
154e50c0a8fSRalf Baechle ret = -EIO;
1555d9a76cdSThomas Bogendoerfer goto out;
156e50c0a8fSRalf Baechle }
157e50c0a8fSRalf Baechle tmp = child->thread.dsp.dspcontrol;
158e50c0a8fSRalf Baechle break;
1591da177e4SLinus Torvalds default:
1601da177e4SLinus Torvalds tmp = 0;
1611da177e4SLinus Torvalds ret = -EIO;
1625d9a76cdSThomas Bogendoerfer goto out;
1631da177e4SLinus Torvalds }
1643055acb0SAtsushi Nemoto ret = put_user(tmp, (unsigned __user *) (unsigned long) data);
1651da177e4SLinus Torvalds break;
1661da177e4SLinus Torvalds }
1671da177e4SLinus Torvalds
168ea3d710fSDaniel Jacobowitz /*
169ea3d710fSDaniel Jacobowitz * Write 4 bytes into the other process' storage
170ea3d710fSDaniel Jacobowitz * data is the 4 bytes that the user wants written
171ea3d710fSDaniel Jacobowitz * addr is a pointer in the user's storage that contains an
172ea3d710fSDaniel Jacobowitz * 8 byte address in the other process where the 4 bytes
173ea3d710fSDaniel Jacobowitz * that is to be written
174ea3d710fSDaniel Jacobowitz * (this is run in a 32-bit process looking at a 64-bit process)
175ea3d710fSDaniel Jacobowitz * when I and D space are separate, these will need to be fixed.
176ea3d710fSDaniel Jacobowitz */
177ea3d710fSDaniel Jacobowitz case PTRACE_POKETEXT_3264:
178ea3d710fSDaniel Jacobowitz case PTRACE_POKEDATA_3264: {
179ea3d710fSDaniel Jacobowitz u32 __user * addrOthers;
180ea3d710fSDaniel Jacobowitz
181ea3d710fSDaniel Jacobowitz /* Get the addr in the other process that we want to write into */
182ea3d710fSDaniel Jacobowitz ret = -EIO;
183ea3d710fSDaniel Jacobowitz if (get_user(addrOthers, (u32 __user * __user *) (unsigned long) addr) != 0)
184ea3d710fSDaniel Jacobowitz break;
185ea3d710fSDaniel Jacobowitz ret = 0;
18684d77d3fSEric W. Biederman if (ptrace_access_vm(child, (u64)addrOthers, &data,
187f307ab6dSLorenzo Stoakes sizeof(data),
188f307ab6dSLorenzo Stoakes FOLL_FORCE | FOLL_WRITE) == sizeof(data))
189ea3d710fSDaniel Jacobowitz break;
190ea3d710fSDaniel Jacobowitz ret = -EIO;
191ea3d710fSDaniel Jacobowitz break;
192ea3d710fSDaniel Jacobowitz }
193ea3d710fSDaniel Jacobowitz
1941da177e4SLinus Torvalds case PTRACE_POKEUSR: {
1951da177e4SLinus Torvalds struct pt_regs *regs;
1961da177e4SLinus Torvalds ret = 0;
19740bc9c67SAl Viro regs = task_pt_regs(child);
1981da177e4SLinus Torvalds
1991da177e4SLinus Torvalds switch (addr) {
2001da177e4SLinus Torvalds case 0 ... 31:
2011da177e4SLinus Torvalds regs->regs[addr] = data;
202de8cd0dcSJames Hogan /* System call number may have been changed */
203de8cd0dcSJames Hogan if (addr == 2)
204de8cd0dcSJames Hogan mips_syscall_update_nr(child, regs);
205de8cd0dcSJames Hogan else if (addr == 4 &&
206de8cd0dcSJames Hogan mips_syscall_is_indirect(child, regs))
207de8cd0dcSJames Hogan mips_syscall_update_nr(child, regs);
2081da177e4SLinus Torvalds break;
209*6c79759eSPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT
2101da177e4SLinus Torvalds case FPR_BASE ... FPR_BASE + 31: {
211bbd426f5SPaul Burton union fpureg *fregs = get_fpu_regs(child);
2121da177e4SLinus Torvalds
2131da177e4SLinus Torvalds if (!tsk_used_math(child)) {
2141da177e4SLinus Torvalds /* FP not yet used */
215eae89076SAtsushi Nemoto memset(&child->thread.fpu, ~0,
216eae89076SAtsushi Nemoto sizeof(child->thread.fpu));
217eae89076SAtsushi Nemoto child->thread.fpu.fcr31 = 0;
2181da177e4SLinus Torvalds }
2199a3a92ccSMaciej W. Rozycki if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) {
2201da177e4SLinus Torvalds /*
221597ce172SPaul Burton * The odd registers are actually the high
222597ce172SPaul Burton * order bits of the values stored in the even
223d1157b10SMaciej W. Rozycki * registers.
2241da177e4SLinus Torvalds */
225bbd426f5SPaul Burton set_fpr32(&fregs[(addr & ~1) - FPR_BASE],
226bbd426f5SPaul Burton addr & 1, data);
2271da177e4SLinus Torvalds break;
2281da177e4SLinus Torvalds }
229bbd426f5SPaul Burton set_fpr64(&fregs[addr - FPR_BASE], 0, data);
230597ce172SPaul Burton break;
231597ce172SPaul Burton }
232*6c79759eSPaul Burton case FPC_CSR:
233*6c79759eSPaul Burton child->thread.fpu.fcr31 = data;
234*6c79759eSPaul Burton break;
235*6c79759eSPaul Burton #endif /* CONFIG_MIPS_FP_SUPPORT */
2361da177e4SLinus Torvalds case PC:
2371da177e4SLinus Torvalds regs->cp0_epc = data;
2381da177e4SLinus Torvalds break;
2391da177e4SLinus Torvalds case MMHI:
2401da177e4SLinus Torvalds regs->hi = data;
2411da177e4SLinus Torvalds break;
2421da177e4SLinus Torvalds case MMLO:
2431da177e4SLinus Torvalds regs->lo = data;
2441da177e4SLinus Torvalds break;
2453055acb0SAtsushi Nemoto case DSP_BASE ... DSP_BASE + 5: {
2463055acb0SAtsushi Nemoto dspreg_t *dregs;
2473055acb0SAtsushi Nemoto
248e50c0a8fSRalf Baechle if (!cpu_has_dsp) {
249e50c0a8fSRalf Baechle ret = -EIO;
250e50c0a8fSRalf Baechle break;
251e50c0a8fSRalf Baechle }
252e50c0a8fSRalf Baechle
2533055acb0SAtsushi Nemoto dregs = __get_dsp_regs(child);
254e50c0a8fSRalf Baechle dregs[addr - DSP_BASE] = data;
255e50c0a8fSRalf Baechle break;
2563055acb0SAtsushi Nemoto }
257e50c0a8fSRalf Baechle case DSP_CONTROL:
258e50c0a8fSRalf Baechle if (!cpu_has_dsp) {
259e50c0a8fSRalf Baechle ret = -EIO;
260e50c0a8fSRalf Baechle break;
261e50c0a8fSRalf Baechle }
262e50c0a8fSRalf Baechle child->thread.dsp.dspcontrol = data;
263e50c0a8fSRalf Baechle break;
2641da177e4SLinus Torvalds default:
2651da177e4SLinus Torvalds /* The rest are not allowed. */
2661da177e4SLinus Torvalds ret = -EIO;
2671da177e4SLinus Torvalds break;
2681da177e4SLinus Torvalds }
2691da177e4SLinus Torvalds break;
2701da177e4SLinus Torvalds }
2711da177e4SLinus Torvalds
272ea3d710fSDaniel Jacobowitz case PTRACE_GETREGS:
273a79ebea6SAlex Smith ret = ptrace_getregs(child,
274a79ebea6SAlex Smith (struct user_pt_regs __user *) (__u64) data);
275ea3d710fSDaniel Jacobowitz break;
276ea3d710fSDaniel Jacobowitz
277ea3d710fSDaniel Jacobowitz case PTRACE_SETREGS:
278a79ebea6SAlex Smith ret = ptrace_setregs(child,
279a79ebea6SAlex Smith (struct user_pt_regs __user *) (__u64) data);
280ea3d710fSDaniel Jacobowitz break;
281ea3d710fSDaniel Jacobowitz
282*6c79759eSPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT
283ea3d710fSDaniel Jacobowitz case PTRACE_GETFPREGS:
284ea3d710fSDaniel Jacobowitz ret = ptrace_getfpregs(child, (__u32 __user *) (__u64) data);
285ea3d710fSDaniel Jacobowitz break;
286ea3d710fSDaniel Jacobowitz
287ea3d710fSDaniel Jacobowitz case PTRACE_SETFPREGS:
288ea3d710fSDaniel Jacobowitz ret = ptrace_setfpregs(child, (__u32 __user *) (__u64) data);
289ea3d710fSDaniel Jacobowitz break;
290*6c79759eSPaul Burton #endif
2913c37026dSRalf Baechle case PTRACE_GET_THREAD_AREA:
292dc8f6029SAl Viro ret = put_user(task_thread_info(child)->tp_value,
2933c37026dSRalf Baechle (unsigned int __user *) (unsigned long) data);
2943c37026dSRalf Baechle break;
2953c37026dSRalf Baechle
296ea3d710fSDaniel Jacobowitz case PTRACE_GET_THREAD_AREA_3264:
297dc8f6029SAl Viro ret = put_user(task_thread_info(child)->tp_value,
298ea3d710fSDaniel Jacobowitz (unsigned long __user *) (unsigned long) data);
299ea3d710fSDaniel Jacobowitz break;
300ea3d710fSDaniel Jacobowitz
3010926bf95SDavid Daney case PTRACE_GET_WATCH_REGS:
3020926bf95SDavid Daney ret = ptrace_get_watch_regs(child,
3030926bf95SDavid Daney (struct pt_watch_regs __user *) (unsigned long) addr);
3040926bf95SDavid Daney break;
3050926bf95SDavid Daney
3060926bf95SDavid Daney case PTRACE_SET_WATCH_REGS:
3070926bf95SDavid Daney ret = ptrace_set_watch_regs(child,
3080926bf95SDavid Daney (struct pt_watch_regs __user *) (unsigned long) addr);
3090926bf95SDavid Daney break;
3100926bf95SDavid Daney
3111da177e4SLinus Torvalds default:
312797c3f32SAnirban Sinha ret = compat_ptrace_request(child, request, addr, data);
3131da177e4SLinus Torvalds break;
3141da177e4SLinus Torvalds }
3151da177e4SLinus Torvalds out:
3161da177e4SLinus Torvalds return ret;
3171da177e4SLinus Torvalds }
318