xref: /freebsd/sys/i386/linux/linux_ptrace_machdep.c (revision d0b2dbfa0ecf2bbc9709efc5e20baf8e4b44bbbf)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2001 Alexander Kabaev
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 #include "opt_cpu.h"
31 
32 #include <sys/param.h>
33 #include <sys/lock.h>
34 #include <sys/mutex.h>
35 #include <sys/proc.h>
36 #include <sys/ptrace.h>
37 #include <sys/syscallsubr.h>
38 #include <sys/systm.h>
39 
40 #include <machine/md_var.h>
41 #include <machine/pcb.h>
42 
43 #include <i386/linux/linux.h>
44 #include <i386/linux/linux_proto.h>
45 #include <compat/linux/linux_signal.h>
46 
47 /*
48  *   Linux ptrace requests numbers. Mostly identical to FreeBSD,
49  *   except for MD ones and PT_ATTACH/PT_DETACH.
50  */
51 #define	PTRACE_TRACEME		0
52 #define	PTRACE_PEEKTEXT		1
53 #define	PTRACE_PEEKDATA		2
54 #define	PTRACE_PEEKUSR		3
55 #define	PTRACE_POKETEXT		4
56 #define	PTRACE_POKEDATA		5
57 #define	PTRACE_POKEUSR		6
58 #define	PTRACE_CONT		7
59 #define	PTRACE_KILL		8
60 #define	PTRACE_SINGLESTEP	9
61 
62 #define PTRACE_ATTACH		16
63 #define PTRACE_DETACH		17
64 
65 #define	LINUX_PTRACE_SYSCALL	24
66 
67 #define PTRACE_GETREGS		12
68 #define PTRACE_SETREGS		13
69 #define PTRACE_GETFPREGS	14
70 #define PTRACE_SETFPREGS	15
71 #define PTRACE_GETFPXREGS	18
72 #define PTRACE_SETFPXREGS	19
73 
74 #define PTRACE_SETOPTIONS	21
75 
76 /*
77  * Linux keeps debug registers at the following
78  * offset in the user struct
79  */
80 #define LINUX_DBREG_OFFSET	252
81 #define LINUX_DBREG_SIZE	(8*sizeof(l_int))
82 
83 static __inline int
84 map_signum(int signum)
85 {
86 
87 	signum = linux_to_bsd_signal(signum);
88 	return ((signum == SIGSTOP)? 0 : signum);
89 }
90 
91 struct linux_pt_reg {
92 	l_long	ebx;
93 	l_long	ecx;
94 	l_long	edx;
95 	l_long	esi;
96 	l_long	edi;
97 	l_long	ebp;
98 	l_long	eax;
99 	l_int	xds;
100 	l_int	xes;
101 	l_int	xfs;
102 	l_int	xgs;
103 	l_long	orig_eax;
104 	l_long	eip;
105 	l_int	xcs;
106 	l_long	eflags;
107 	l_long	esp;
108 	l_int	xss;
109 };
110 
111 /*
112  *   Translate i386 ptrace registers between Linux and FreeBSD formats.
113  *   The translation is pretty straighforward, for all registers, but
114  *   orig_eax on Linux side and r_trapno and r_err in FreeBSD
115  */
116 static void
117 map_regs_to_linux(struct reg *bsd_r, struct linux_pt_reg *linux_r)
118 {
119 	linux_r->ebx = bsd_r->r_ebx;
120 	linux_r->ecx = bsd_r->r_ecx;
121 	linux_r->edx = bsd_r->r_edx;
122 	linux_r->esi = bsd_r->r_esi;
123 	linux_r->edi = bsd_r->r_edi;
124 	linux_r->ebp = bsd_r->r_ebp;
125 	linux_r->eax = bsd_r->r_eax;
126 	linux_r->xds = bsd_r->r_ds;
127 	linux_r->xes = bsd_r->r_es;
128 	linux_r->xfs = bsd_r->r_fs;
129 	linux_r->xgs = bsd_r->r_gs;
130 	linux_r->orig_eax = bsd_r->r_eax;
131 	linux_r->eip = bsd_r->r_eip;
132 	linux_r->xcs = bsd_r->r_cs;
133 	linux_r->eflags = bsd_r->r_eflags;
134 	linux_r->esp = bsd_r->r_esp;
135 	linux_r->xss = bsd_r->r_ss;
136 }
137 
138 static void
139 map_regs_from_linux(struct reg *bsd_r, struct linux_pt_reg *linux_r)
140 {
141 	bsd_r->r_ebx = linux_r->ebx;
142 	bsd_r->r_ecx = linux_r->ecx;
143 	bsd_r->r_edx = linux_r->edx;
144 	bsd_r->r_esi = linux_r->esi;
145 	bsd_r->r_edi = linux_r->edi;
146 	bsd_r->r_ebp = linux_r->ebp;
147 	bsd_r->r_eax = linux_r->eax;
148 	bsd_r->r_ds  = linux_r->xds;
149 	bsd_r->r_es  = linux_r->xes;
150 	bsd_r->r_fs  = linux_r->xfs;
151 	bsd_r->r_gs  = linux_r->xgs;
152 	bsd_r->r_eip = linux_r->eip;
153 	bsd_r->r_cs  = linux_r->xcs;
154 	bsd_r->r_eflags = linux_r->eflags;
155 	bsd_r->r_esp = linux_r->esp;
156 	bsd_r->r_ss = linux_r->xss;
157 }
158 
159 struct linux_pt_fpreg {
160 	l_long cwd;
161 	l_long swd;
162 	l_long twd;
163 	l_long fip;
164 	l_long fcs;
165 	l_long foo;
166 	l_long fos;
167 	l_long st_space[2*10];
168 };
169 
170 static void
171 map_fpregs_to_linux(struct fpreg *bsd_r, struct linux_pt_fpreg *linux_r)
172 {
173 	linux_r->cwd = bsd_r->fpr_env[0];
174 	linux_r->swd = bsd_r->fpr_env[1];
175 	linux_r->twd = bsd_r->fpr_env[2];
176 	linux_r->fip = bsd_r->fpr_env[3];
177 	linux_r->fcs = bsd_r->fpr_env[4];
178 	linux_r->foo = bsd_r->fpr_env[5];
179 	linux_r->fos = bsd_r->fpr_env[6];
180 	bcopy(bsd_r->fpr_acc, linux_r->st_space, sizeof(linux_r->st_space));
181 }
182 
183 static void
184 map_fpregs_from_linux(struct fpreg *bsd_r, struct linux_pt_fpreg *linux_r)
185 {
186 	bsd_r->fpr_env[0] = linux_r->cwd;
187 	bsd_r->fpr_env[1] = linux_r->swd;
188 	bsd_r->fpr_env[2] = linux_r->twd;
189 	bsd_r->fpr_env[3] = linux_r->fip;
190 	bsd_r->fpr_env[4] = linux_r->fcs;
191 	bsd_r->fpr_env[5] = linux_r->foo;
192 	bsd_r->fpr_env[6] = linux_r->fos;
193 	bcopy(bsd_r->fpr_acc, linux_r->st_space, sizeof(bsd_r->fpr_acc));
194 }
195 
196 struct linux_pt_fpxreg {
197 	l_ushort	cwd;
198 	l_ushort	swd;
199 	l_ushort	twd;
200 	l_ushort	fop;
201 	l_long		fip;
202 	l_long		fcs;
203 	l_long		foo;
204 	l_long		fos;
205 	l_long		mxcsr;
206 	l_long		reserved;
207 	l_long		st_space[32];
208 	l_long		xmm_space[32];
209 	l_long		padding[56];
210 };
211 
212 static int
213 linux_proc_read_fpxregs(struct thread *td, struct linux_pt_fpxreg *fpxregs)
214 {
215 
216 	PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
217 	if (cpu_fxsr == 0 || (td->td_proc->p_flag & P_INMEM) == 0)
218 		return (EIO);
219 	bcopy(&get_pcb_user_save_td(td)->sv_xmm, fpxregs, sizeof(*fpxregs));
220 	return (0);
221 }
222 
223 static int
224 linux_proc_write_fpxregs(struct thread *td, struct linux_pt_fpxreg *fpxregs)
225 {
226 
227 	PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
228 	if (cpu_fxsr == 0 || (td->td_proc->p_flag & P_INMEM) == 0)
229 		return (EIO);
230 	bcopy(fpxregs, &get_pcb_user_save_td(td)->sv_xmm, sizeof(*fpxregs));
231 	return (0);
232 }
233 
234 int
235 linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
236 {
237 	union {
238 		struct linux_pt_reg	reg;
239 		struct linux_pt_fpreg	fpreg;
240 		struct linux_pt_fpxreg	fpxreg;
241 	} r;
242 	union {
243 		struct reg		bsd_reg;
244 		struct fpreg		bsd_fpreg;
245 		struct dbreg		bsd_dbreg;
246 	} u;
247 	void *addr;
248 	pid_t pid;
249 	int error, req;
250 
251 	error = 0;
252 
253 	/* by default, just copy data intact */
254 	req  = uap->req;
255 	pid  = (pid_t)uap->pid;
256 	addr = (void *)uap->addr;
257 
258 	switch (req) {
259 	case PTRACE_TRACEME:
260 	case PTRACE_POKETEXT:
261 	case PTRACE_POKEDATA:
262 	case PTRACE_KILL:
263 		error = kern_ptrace(td, req, pid, addr, uap->data);
264 		break;
265 	case PTRACE_PEEKTEXT:
266 	case PTRACE_PEEKDATA: {
267 		/* need to preserve return value */
268 		int rval = td->td_retval[0];
269 		error = kern_ptrace(td, req, pid, addr, 0);
270 		if (error == 0)
271 			error = copyout(td->td_retval, (void *)uap->data,
272 			    sizeof(l_int));
273 		td->td_retval[0] = rval;
274 		break;
275 	}
276 	case PTRACE_DETACH:
277 		error = kern_ptrace(td, PT_DETACH, pid, (void *)1,
278 		     map_signum(uap->data));
279 		break;
280 	case PTRACE_SINGLESTEP:
281 	case PTRACE_CONT:
282 		error = kern_ptrace(td, req, pid, (void *)1,
283 		     map_signum(uap->data));
284 		break;
285 	case PTRACE_ATTACH:
286 		error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data);
287 		break;
288 	case PTRACE_GETREGS:
289 		/* Linux is using data where FreeBSD is using addr */
290 		error = kern_ptrace(td, PT_GETREGS, pid, &u.bsd_reg, 0);
291 		if (error == 0) {
292 			map_regs_to_linux(&u.bsd_reg, &r.reg);
293 			error = copyout(&r.reg, (void *)uap->data,
294 			    sizeof(r.reg));
295 		}
296 		break;
297 	case PTRACE_SETREGS:
298 		/* Linux is using data where FreeBSD is using addr */
299 		error = copyin((void *)uap->data, &r.reg, sizeof(r.reg));
300 		if (error == 0) {
301 			map_regs_from_linux(&u.bsd_reg, &r.reg);
302 			error = kern_ptrace(td, PT_SETREGS, pid, &u.bsd_reg, 0);
303 		}
304 		break;
305 	case PTRACE_GETFPREGS:
306 		/* Linux is using data where FreeBSD is using addr */
307 		error = kern_ptrace(td, PT_GETFPREGS, pid, &u.bsd_fpreg, 0);
308 		if (error == 0) {
309 			map_fpregs_to_linux(&u.bsd_fpreg, &r.fpreg);
310 			error = copyout(&r.fpreg, (void *)uap->data,
311 			    sizeof(r.fpreg));
312 		}
313 		break;
314 	case PTRACE_SETFPREGS:
315 		/* Linux is using data where FreeBSD is using addr */
316 		error = copyin((void *)uap->data, &r.fpreg, sizeof(r.fpreg));
317 		if (error == 0) {
318 			map_fpregs_from_linux(&u.bsd_fpreg, &r.fpreg);
319 			error = kern_ptrace(td, PT_SETFPREGS, pid,
320 			    &u.bsd_fpreg, 0);
321 		}
322 		break;
323 	case PTRACE_SETFPXREGS:
324 		error = copyin((void *)uap->data, &r.fpxreg, sizeof(r.fpxreg));
325 		if (error)
326 			break;
327 		/* FALL THROUGH */
328 	case PTRACE_GETFPXREGS: {
329 		struct proc *p;
330 		struct thread *td2;
331 
332 		if (sizeof(struct linux_pt_fpxreg) != sizeof(struct savexmm)) {
333 			static int once = 0;
334 			if (!once) {
335 				printf("linux: savexmm != linux_pt_fpxreg\n");
336 				once = 1;
337 			}
338 			error = EIO;
339 			break;
340 		}
341 
342 		if ((p = pfind(uap->pid)) == NULL) {
343 			error = ESRCH;
344 			break;
345 		}
346 
347 		/* Exiting processes can't be debugged. */
348 		if ((p->p_flag & P_WEXIT) != 0) {
349 			error = ESRCH;
350 			goto fail;
351 		}
352 
353 		if ((error = p_candebug(td, p)) != 0)
354 			goto fail;
355 
356 		/* System processes can't be debugged. */
357 		if ((p->p_flag & P_SYSTEM) != 0) {
358 			error = EINVAL;
359 			goto fail;
360 		}
361 
362 		/* not being traced... */
363 		if ((p->p_flag & P_TRACED) == 0) {
364 			error = EPERM;
365 			goto fail;
366 		}
367 
368 		/* not being traced by YOU */
369 		if (p->p_pptr != td->td_proc) {
370 			error = EBUSY;
371 			goto fail;
372 		}
373 
374 		/* not currently stopped */
375 		if (!P_SHOULDSTOP(p) || (p->p_flag & P_WAITED) == 0) {
376 			error = EBUSY;
377 			goto fail;
378 		}
379 
380 		if (req == PTRACE_GETFPXREGS) {
381 			_PHOLD(p);	/* may block */
382 			td2 = FIRST_THREAD_IN_PROC(p);
383 			error = linux_proc_read_fpxregs(td2, &r.fpxreg);
384 			_PRELE(p);
385 			PROC_UNLOCK(p);
386 			if (error == 0)
387 				error = copyout(&r.fpxreg, (void *)uap->data,
388 				    sizeof(r.fpxreg));
389 		} else {
390 			/* clear dangerous bits exactly as Linux does*/
391 			r.fpxreg.mxcsr &= 0xffbf;
392 			_PHOLD(p);	/* may block */
393 			td2 = FIRST_THREAD_IN_PROC(p);
394 			error = linux_proc_write_fpxregs(td2, &r.fpxreg);
395 			_PRELE(p);
396 			PROC_UNLOCK(p);
397 		}
398 		break;
399 
400 	fail:
401 		PROC_UNLOCK(p);
402 		break;
403 	}
404 	case PTRACE_PEEKUSR:
405 	case PTRACE_POKEUSR: {
406 		error = EIO;
407 
408 		/* check addr for alignment */
409 		if (uap->addr < 0 || uap->addr & (sizeof(l_int) - 1))
410 			break;
411 		/*
412 		 * Allow Linux programs to access register values in
413 		 * user struct. We simulate this through PT_GET/SETREGS
414 		 * as necessary.
415 		 */
416 		if (uap->addr < sizeof(struct linux_pt_reg)) {
417 			error = kern_ptrace(td, PT_GETREGS, pid, &u.bsd_reg, 0);
418 			if (error != 0)
419 				break;
420 
421 			map_regs_to_linux(&u.bsd_reg, &r.reg);
422 			if (req == PTRACE_PEEKUSR) {
423 				error = copyout((char *)&r.reg + uap->addr,
424 				    (void *)uap->data, sizeof(l_int));
425 				break;
426 			}
427 
428 			*(l_int *)((char *)&r.reg + uap->addr) =
429 			    (l_int)uap->data;
430 
431 			map_regs_from_linux(&u.bsd_reg, &r.reg);
432 			error = kern_ptrace(td, PT_SETREGS, pid, &u.bsd_reg, 0);
433 		}
434 
435 		/*
436 		 * Simulate debug registers access
437 		 */
438 		if (uap->addr >= LINUX_DBREG_OFFSET &&
439 		    uap->addr <= LINUX_DBREG_OFFSET + LINUX_DBREG_SIZE) {
440 			error = kern_ptrace(td, PT_GETDBREGS, pid, &u.bsd_dbreg,
441 			    0);
442 			if (error != 0)
443 				break;
444 
445 			uap->addr -= LINUX_DBREG_OFFSET;
446 			if (req == PTRACE_PEEKUSR) {
447 				error = copyout((char *)&u.bsd_dbreg +
448 				    uap->addr, (void *)uap->data,
449 				    sizeof(l_int));
450 				break;
451 			}
452 
453 			*(l_int *)((char *)&u.bsd_dbreg + uap->addr) =
454 			     uap->data;
455 			error = kern_ptrace(td, PT_SETDBREGS, pid,
456 			    &u.bsd_dbreg, 0);
457 		}
458 
459 		break;
460 	}
461 	case LINUX_PTRACE_SYSCALL:
462 		/* fall through */
463 	default:
464 		printf("linux: ptrace(%u, ...) not implemented\n",
465 		    (unsigned int)uap->req);
466 		error = EINVAL;
467 		break;
468 	}
469 
470 	return (error);
471 }
472