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