diff options
author | 2025-03-08 22:04:20 +0800 | |
---|---|---|
committer | 2025-03-08 22:04:20 +0800 | |
commit | a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch) | |
tree | 84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/kernel/ptrace32.c | |
download | ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.tar.gz ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.zip |
Initial commit: OpenHarmony-v4.0-ReleaseOpenHarmony-v4.0-Release
Diffstat (limited to 'arch/mips/kernel/ptrace32.c')
-rw-r--r-- | arch/mips/kernel/ptrace32.c | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c new file mode 100644 index 000000000..afcf27a87 --- /dev/null +++ b/arch/mips/kernel/ptrace32.c | |||
@@ -0,0 +1,317 @@ | |||
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/page.h> | ||
34 | #include <asm/reg.h> | ||
35 | #include <asm/syscall.h> | ||
36 | #include <linux/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 | */ | ||
43 | long 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 = ptrace_access_vm(child, (u64)addrOthers, &tmp, | ||
74 | sizeof(tmp), FOLL_FORCE); | ||
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 | #ifdef CONFIG_MIPS_FP_SUPPORT | ||
94 | case FPR_BASE ... FPR_BASE + 31: { | ||
95 | union fpureg *fregs; | ||
96 | |||
97 | if (!tsk_used_math(child)) { | ||
98 | /* FP not yet used */ | ||
99 | tmp = -1; | ||
100 | break; | ||
101 | } | ||
102 | fregs = get_fpu_regs(child); | ||
103 | if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) { | ||
104 | /* | ||
105 | * The odd registers are actually the high | ||
106 | * order bits of the values stored in the even | ||
107 | * registers. | ||
108 | */ | ||
109 | tmp = get_fpr32(&fregs[(addr & ~1) - FPR_BASE], | ||
110 | addr & 1); | ||
111 | break; | ||
112 | } | ||
113 | tmp = get_fpr64(&fregs[addr - FPR_BASE], 0); | ||
114 | break; | ||
115 | } | ||
116 | case FPC_CSR: | ||
117 | tmp = child->thread.fpu.fcr31; | ||
118 | break; | ||
119 | case FPC_EIR: | ||
120 | /* implementation / version register */ | ||
121 | tmp = boot_cpu_data.fpu_id; | ||
122 | break; | ||
123 | #endif /* CONFIG_MIPS_FP_SUPPORT */ | ||
124 | case PC: | ||
125 | tmp = regs->cp0_epc; | ||
126 | break; | ||
127 | case CAUSE: | ||
128 | tmp = regs->cp0_cause; | ||
129 | break; | ||
130 | case BADVADDR: | ||
131 | tmp = regs->cp0_badvaddr; | ||
132 | break; | ||
133 | case MMHI: | ||
134 | tmp = regs->hi; | ||
135 | break; | ||
136 | case MMLO: | ||
137 | tmp = regs->lo; | ||
138 | break; | ||
139 | case DSP_BASE ... DSP_BASE + 5: { | ||
140 | dspreg_t *dregs; | ||
141 | |||
142 | if (!cpu_has_dsp) { | ||
143 | tmp = 0; | ||
144 | ret = -EIO; | ||
145 | goto out; | ||
146 | } | ||
147 | dregs = __get_dsp_regs(child); | ||
148 | tmp = dregs[addr - DSP_BASE]; | ||
149 | break; | ||
150 | } | ||
151 | case DSP_CONTROL: | ||
152 | if (!cpu_has_dsp) { | ||
153 | tmp = 0; | ||
154 | ret = -EIO; | ||
155 | goto out; | ||
156 | } | ||
157 | tmp = child->thread.dsp.dspcontrol; | ||
158 | break; | ||
159 | default: | ||
160 | tmp = 0; | ||
161 | ret = -EIO; | ||
162 | goto out; | ||
163 | } | ||
164 | ret = put_user(tmp, (unsigned __user *) (unsigned long) data); | ||
165 | break; | ||
166 | } | ||
167 | |||
168 | /* | ||
169 | * Write 4 bytes into the other process' storage | ||
170 | * data is the 4 bytes that the user wants written | ||
171 | * addr is a pointer in the user's storage that contains an | ||
172 | * 8 byte address in the other process where the 4 bytes | ||
173 | * that is to be written | ||
174 | * (this is run in a 32-bit process looking at a 64-bit process) | ||
175 | * when I and D space are separate, these will need to be fixed. | ||
176 | */ | ||
177 | case PTRACE_POKETEXT_3264: | ||
178 | case PTRACE_POKEDATA_3264: { | ||
179 | u32 __user * addrOthers; | ||
180 | |||
181 | /* Get the addr in the other process that we want to write into */ | ||
182 | ret = -EIO; | ||
183 | if (get_user(addrOthers, (u32 __user * __user *) (unsigned long) addr) != 0) | ||
184 | break; | ||
185 | ret = 0; | ||
186 | if (ptrace_access_vm(child, (u64)addrOthers, &data, | ||
187 | sizeof(data), | ||
188 | FOLL_FORCE | FOLL_WRITE) == sizeof(data)) | ||
189 | break; | ||
190 | ret = -EIO; | ||
191 | break; | ||
192 | } | ||
193 | |||
194 | case PTRACE_POKEUSR: { | ||
195 | struct pt_regs *regs; | ||
196 | ret = 0; | ||
197 | regs = task_pt_regs(child); | ||
198 | |||
199 | switch (addr) { | ||
200 | case 0 ... 31: | ||
201 | regs->regs[addr] = data; | ||
202 | /* System call number may have been changed */ | ||
203 | if (addr == 2) | ||
204 | mips_syscall_update_nr(child, regs); | ||
205 | else if (addr == 4 && | ||
206 | mips_syscall_is_indirect(child, regs)) | ||
207 | mips_syscall_update_nr(child, regs); | ||
208 | break; | ||
209 | #ifdef CONFIG_MIPS_FP_SUPPORT | ||
210 | case FPR_BASE ... FPR_BASE + 31: { | ||
211 | union fpureg *fregs = get_fpu_regs(child); | ||
212 | |||
213 | if (!tsk_used_math(child)) { | ||
214 | /* FP not yet used */ | ||
215 | memset(&child->thread.fpu, ~0, | ||
216 | sizeof(child->thread.fpu)); | ||
217 | child->thread.fpu.fcr31 = 0; | ||
218 | } | ||
219 | if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) { | ||
220 | /* | ||
221 | * The odd registers are actually the high | ||
222 | * order bits of the values stored in the even | ||
223 | * registers. | ||
224 | */ | ||
225 | set_fpr32(&fregs[(addr & ~1) - FPR_BASE], | ||
226 | addr & 1, data); | ||
227 | break; | ||
228 | } | ||
229 | set_fpr64(&fregs[addr - FPR_BASE], 0, data); | ||
230 | break; | ||
231 | } | ||
232 | case FPC_CSR: | ||
233 | child->thread.fpu.fcr31 = data; | ||
234 | break; | ||
235 | #endif /* CONFIG_MIPS_FP_SUPPORT */ | ||
236 | case PC: | ||
237 | regs->cp0_epc = data; | ||
238 | break; | ||
239 | case MMHI: | ||
240 | regs->hi = data; | ||
241 | break; | ||
242 | case MMLO: | ||
243 | regs->lo = data; | ||
244 | break; | ||
245 | case DSP_BASE ... DSP_BASE + 5: { | ||
246 | dspreg_t *dregs; | ||
247 | |||
248 | if (!cpu_has_dsp) { | ||
249 | ret = -EIO; | ||
250 | break; | ||
251 | } | ||
252 | |||
253 | dregs = __get_dsp_regs(child); | ||
254 | dregs[addr - DSP_BASE] = data; | ||
255 | break; | ||
256 | } | ||
257 | case DSP_CONTROL: | ||
258 | if (!cpu_has_dsp) { | ||
259 | ret = -EIO; | ||
260 | break; | ||
261 | } | ||
262 | child->thread.dsp.dspcontrol = data; | ||
263 | break; | ||
264 | default: | ||
265 | /* The rest are not allowed. */ | ||
266 | ret = -EIO; | ||
267 | break; | ||
268 | } | ||
269 | break; | ||
270 | } | ||
271 | |||
272 | case PTRACE_GETREGS: | ||
273 | ret = ptrace_getregs(child, | ||
274 | (struct user_pt_regs __user *) (__u64) data); | ||
275 | break; | ||
276 | |||
277 | case PTRACE_SETREGS: | ||
278 | ret = ptrace_setregs(child, | ||
279 | (struct user_pt_regs __user *) (__u64) data); | ||
280 | break; | ||
281 | |||
282 | #ifdef CONFIG_MIPS_FP_SUPPORT | ||
283 | case PTRACE_GETFPREGS: | ||
284 | ret = ptrace_getfpregs(child, (__u32 __user *) (__u64) data); | ||
285 | break; | ||
286 | |||
287 | case PTRACE_SETFPREGS: | ||
288 | ret = ptrace_setfpregs(child, (__u32 __user *) (__u64) data); | ||
289 | break; | ||
290 | #endif | ||
291 | case PTRACE_GET_THREAD_AREA: | ||
292 | ret = put_user(task_thread_info(child)->tp_value, | ||
293 | (unsigned int __user *) (unsigned long) data); | ||
294 | break; | ||
295 | |||
296 | case PTRACE_GET_THREAD_AREA_3264: | ||
297 | ret = put_user(task_thread_info(child)->tp_value, | ||
298 | (unsigned long __user *) (unsigned long) data); | ||
299 | break; | ||
300 | |||
301 | case PTRACE_GET_WATCH_REGS: | ||
302 | ret = ptrace_get_watch_regs(child, | ||
303 | (struct pt_watch_regs __user *) (unsigned long) addr); | ||
304 | break; | ||
305 | |||
306 | case PTRACE_SET_WATCH_REGS: | ||
307 | ret = ptrace_set_watch_regs(child, | ||
308 | (struct pt_watch_regs __user *) (unsigned long) addr); | ||
309 | break; | ||
310 | |||
311 | default: | ||
312 | ret = compat_ptrace_request(child, request, addr, data); | ||
313 | break; | ||
314 | } | ||
315 | out: | ||
316 | return ret; | ||
317 | } | ||