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