xref: /f-stack/freebsd/amd64/linux/linux_ptrace.c (revision 22ce4aff)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2017 Edward Tomasz Napierala <[email protected]>
5  *
6  * This software was developed by SRI International and the University of
7  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
8  * ("CTSRD"), as part of the DARPA CRASH research programme.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 
35 #include <sys/param.h>
36 #include <sys/lock.h>
37 #include <sys/proc.h>
38 #include <sys/ptrace.h>
39 #include <sys/sx.h>
40 #include <sys/syscallsubr.h>
41 
42 #include <machine/pcb.h>
43 #include <machine/reg.h>
44 
45 #include <amd64/linux/linux.h>
46 #include <amd64/linux/linux_proto.h>
47 #include <compat/linux/linux_emul.h>
48 #include <compat/linux/linux_misc.h>
49 #include <compat/linux/linux_signal.h>
50 #include <compat/linux/linux_util.h>
51 
52 #define	LINUX_PTRACE_TRACEME		0
53 #define	LINUX_PTRACE_PEEKTEXT		1
54 #define	LINUX_PTRACE_PEEKDATA		2
55 #define	LINUX_PTRACE_PEEKUSER		3
56 #define	LINUX_PTRACE_POKETEXT		4
57 #define	LINUX_PTRACE_POKEDATA		5
58 #define	LINUX_PTRACE_POKEUSER		6
59 #define	LINUX_PTRACE_CONT		7
60 #define	LINUX_PTRACE_KILL		8
61 #define	LINUX_PTRACE_SINGLESTEP		9
62 #define	LINUX_PTRACE_GETREGS		12
63 #define	LINUX_PTRACE_SETREGS		13
64 #define	LINUX_PTRACE_GETFPREGS		14
65 #define	LINUX_PTRACE_SETFPREGS		15
66 #define	LINUX_PTRACE_ATTACH		16
67 #define	LINUX_PTRACE_DETACH		17
68 #define	LINUX_PTRACE_SYSCALL		24
69 #define	LINUX_PTRACE_SETOPTIONS		0x4200
70 #define	LINUX_PTRACE_GETSIGINFO		0x4202
71 #define	LINUX_PTRACE_GETREGSET		0x4204
72 #define	LINUX_PTRACE_SEIZE		0x4206
73 #define	LINUX_PTRACE_GET_SYSCALL_INFO	0x420e
74 
75 #define	LINUX_PTRACE_EVENT_EXIT		6
76 
77 #define	LINUX_PTRACE_O_TRACESYSGOOD	1
78 #define	LINUX_PTRACE_O_TRACEFORK	2
79 #define	LINUX_PTRACE_O_TRACEVFORK	4
80 #define	LINUX_PTRACE_O_TRACECLONE	8
81 #define	LINUX_PTRACE_O_TRACEEXEC	16
82 #define	LINUX_PTRACE_O_TRACEVFORKDONE	32
83 #define	LINUX_PTRACE_O_TRACEEXIT	64
84 #define	LINUX_PTRACE_O_TRACESECCOMP	128
85 #define	LINUX_PTRACE_O_EXITKILL		1048576
86 #define	LINUX_PTRACE_O_SUSPEND_SECCOMP	2097152
87 
88 #define	LINUX_NT_PRSTATUS		1
89 
90 #define	LINUX_PTRACE_O_MASK	(LINUX_PTRACE_O_TRACESYSGOOD |	\
91     LINUX_PTRACE_O_TRACEFORK | LINUX_PTRACE_O_TRACEVFORK |	\
92     LINUX_PTRACE_O_TRACECLONE | LINUX_PTRACE_O_TRACEEXEC |	\
93     LINUX_PTRACE_O_TRACEVFORKDONE | LINUX_PTRACE_O_TRACEEXIT |	\
94     LINUX_PTRACE_O_TRACESECCOMP | LINUX_PTRACE_O_EXITKILL |	\
95     LINUX_PTRACE_O_SUSPEND_SECCOMP)
96 
97 static int
map_signum(int lsig,int * bsigp)98 map_signum(int lsig, int *bsigp)
99 {
100 	int bsig;
101 
102 	if (lsig == 0) {
103 		*bsigp = 0;
104 		return (0);
105 	}
106 
107 	if (lsig < 0 || lsig > LINUX_SIGRTMAX)
108 		return (EINVAL);
109 
110 	bsig = linux_to_bsd_signal(lsig);
111 	if (bsig == SIGSTOP)
112 		bsig = 0;
113 
114 	*bsigp = bsig;
115 	return (0);
116 }
117 
118 int
linux_ptrace_status(struct thread * td,pid_t pid,int status)119 linux_ptrace_status(struct thread *td, pid_t pid, int status)
120 {
121 	struct ptrace_lwpinfo lwpinfo;
122 	struct linux_pemuldata *pem;
123 	register_t saved_retval;
124 	int error;
125 
126 	saved_retval = td->td_retval[0];
127 	error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
128 	td->td_retval[0] = saved_retval;
129 	if (error != 0) {
130 		linux_msg(td, "PT_LWPINFO failed with error %d", error);
131 		return (status);
132 	}
133 
134 	pem = pem_find(td->td_proc);
135 	KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
136 
137 	LINUX_PEM_SLOCK(pem);
138 	if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) &&
139 	    lwpinfo.pl_flags & PL_FLAG_SCE)
140 		status |= (LINUX_SIGTRAP | 0x80) << 8;
141 	if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) &&
142 	    lwpinfo.pl_flags & PL_FLAG_SCX)
143 		status |= (LINUX_SIGTRAP | 0x80) << 8;
144 	if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACEEXIT) &&
145 	    lwpinfo.pl_flags & PL_FLAG_EXITED)
146 		status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXIT << 8) << 8;
147 	LINUX_PEM_SUNLOCK(pem);
148 
149 	return (status);
150 }
151 
152 struct linux_pt_reg {
153 	l_ulong	r15;
154 	l_ulong	r14;
155 	l_ulong	r13;
156 	l_ulong	r12;
157 	l_ulong	rbp;
158 	l_ulong	rbx;
159 	l_ulong	r11;
160 	l_ulong	r10;
161 	l_ulong	r9;
162 	l_ulong	r8;
163 	l_ulong	rax;
164 	l_ulong	rcx;
165 	l_ulong	rdx;
166 	l_ulong	rsi;
167 	l_ulong	rdi;
168 	l_ulong	orig_rax;
169 	l_ulong	rip;
170 	l_ulong	cs;
171 	l_ulong	eflags;
172 	l_ulong	rsp;
173 	l_ulong	ss;
174 };
175 
176 struct linux_pt_regset {
177 	l_ulong	r15;
178 	l_ulong	r14;
179 	l_ulong	r13;
180 	l_ulong	r12;
181 	l_ulong	rbp;
182 	l_ulong	rbx;
183 	l_ulong	r11;
184 	l_ulong	r10;
185 	l_ulong	r9;
186 	l_ulong	r8;
187 	l_ulong	rax;
188 	l_ulong	rcx;
189 	l_ulong	rdx;
190 	l_ulong	rsi;
191 	l_ulong	rdi;
192 	l_ulong	orig_rax;
193 	l_ulong	rip;
194 	l_ulong	cs;
195 	l_ulong	eflags;
196 	l_ulong	rsp;
197 	l_ulong	ss;
198 	l_ulong fs_base;
199 	l_ulong gs_base;
200 	l_ulong ds;
201 	l_ulong es;
202 	l_ulong fs;
203 	l_ulong gs;
204 };
205 
206 /*
207  * Translate amd64 ptrace registers between Linux and FreeBSD formats.
208  * The translation is pretty straighforward, for all registers but
209  * orig_rax on Linux side and r_trapno and r_err in FreeBSD.
210  */
211 static void
map_regs_to_linux(struct reg * b_reg,struct linux_pt_reg * l_reg)212 map_regs_to_linux(struct reg *b_reg, struct linux_pt_reg *l_reg)
213 {
214 
215 	l_reg->r15 = b_reg->r_r15;
216 	l_reg->r14 = b_reg->r_r14;
217 	l_reg->r13 = b_reg->r_r13;
218 	l_reg->r12 = b_reg->r_r12;
219 	l_reg->rbp = b_reg->r_rbp;
220 	l_reg->rbx = b_reg->r_rbx;
221 	l_reg->r11 = b_reg->r_r11;
222 	l_reg->r10 = b_reg->r_r10;
223 	l_reg->r9 = b_reg->r_r9;
224 	l_reg->r8 = b_reg->r_r8;
225 	l_reg->rax = b_reg->r_rax;
226 	l_reg->rcx = b_reg->r_rcx;
227 	l_reg->rdx = b_reg->r_rdx;
228 	l_reg->rsi = b_reg->r_rsi;
229 	l_reg->rdi = b_reg->r_rdi;
230 	l_reg->orig_rax = b_reg->r_rax;
231 	l_reg->rip = b_reg->r_rip;
232 	l_reg->cs = b_reg->r_cs;
233 	l_reg->eflags = b_reg->r_rflags;
234 	l_reg->rsp = b_reg->r_rsp;
235 	l_reg->ss = b_reg->r_ss;
236 }
237 
238 static void
map_regs_to_linux_regset(struct reg * b_reg,unsigned long fs_base,unsigned long gs_base,struct linux_pt_regset * l_regset)239 map_regs_to_linux_regset(struct reg *b_reg, unsigned long fs_base,
240     unsigned long gs_base, struct linux_pt_regset *l_regset)
241 {
242 
243 	l_regset->r15 = b_reg->r_r15;
244 	l_regset->r14 = b_reg->r_r14;
245 	l_regset->r13 = b_reg->r_r13;
246 	l_regset->r12 = b_reg->r_r12;
247 	l_regset->rbp = b_reg->r_rbp;
248 	l_regset->rbx = b_reg->r_rbx;
249 	l_regset->r11 = b_reg->r_r11;
250 	l_regset->r10 = b_reg->r_r10;
251 	l_regset->r9 = b_reg->r_r9;
252 	l_regset->r8 = b_reg->r_r8;
253 	l_regset->rax = b_reg->r_rax;
254 	l_regset->rcx = b_reg->r_rcx;
255 	l_regset->rdx = b_reg->r_rdx;
256 	l_regset->rsi = b_reg->r_rsi;
257 	l_regset->rdi = b_reg->r_rdi;
258 	l_regset->orig_rax = b_reg->r_rax;
259 	l_regset->rip = b_reg->r_rip;
260 	l_regset->cs = b_reg->r_cs;
261 	l_regset->eflags = b_reg->r_rflags;
262 	l_regset->rsp = b_reg->r_rsp;
263 	l_regset->ss = b_reg->r_ss;
264 	l_regset->fs_base = fs_base;
265 	l_regset->gs_base = gs_base;
266 	l_regset->ds = b_reg->r_ds;
267 	l_regset->es = b_reg->r_es;
268 	l_regset->fs = b_reg->r_fs;
269 	l_regset->gs = b_reg->r_gs;
270 }
271 
272 static void
map_regs_from_linux(struct reg * b_reg,struct linux_pt_reg * l_reg)273 map_regs_from_linux(struct reg *b_reg, struct linux_pt_reg *l_reg)
274 {
275 	b_reg->r_r15 = l_reg->r15;
276 	b_reg->r_r14 = l_reg->r14;
277 	b_reg->r_r13 = l_reg->r13;
278 	b_reg->r_r12 = l_reg->r12;
279 	b_reg->r_r11 = l_reg->r11;
280 	b_reg->r_r10 = l_reg->r10;
281 	b_reg->r_r9 = l_reg->r9;
282 	b_reg->r_r8 = l_reg->r8;
283 	b_reg->r_rdi = l_reg->rdi;
284 	b_reg->r_rsi = l_reg->rsi;
285 	b_reg->r_rbp = l_reg->rbp;
286 	b_reg->r_rbx = l_reg->rbx;
287 	b_reg->r_rdx = l_reg->rdx;
288 	b_reg->r_rcx = l_reg->rcx;
289 	b_reg->r_rax = l_reg->rax;
290 
291 	/*
292 	 * XXX: Are zeroes the right thing to put here?
293 	 */
294 	b_reg->r_trapno = 0;
295 	b_reg->r_fs = 0;
296 	b_reg->r_gs = 0;
297 	b_reg->r_err = 0;
298 	b_reg->r_es = 0;
299 	b_reg->r_ds = 0;
300 
301 	b_reg->r_rip = l_reg->rip;
302 	b_reg->r_cs = l_reg->cs;
303 	b_reg->r_rflags = l_reg->eflags;
304 	b_reg->r_rsp = l_reg->rsp;
305 	b_reg->r_ss = l_reg->ss;
306 }
307 
308 static int
linux_ptrace_peek(struct thread * td,pid_t pid,void * addr,void * data)309 linux_ptrace_peek(struct thread *td, pid_t pid, void *addr, void *data)
310 {
311 	int error;
312 
313 	error = kern_ptrace(td, PT_READ_I, pid, addr, 0);
314 	if (error == 0)
315 		error = copyout(td->td_retval, data, sizeof(l_int));
316 	td->td_retval[0] = error;
317 
318 	return (error);
319 }
320 
321 static int
linux_ptrace_peekuser(struct thread * td,pid_t pid,void * addr,void * data)322 linux_ptrace_peekuser(struct thread *td, pid_t pid, void *addr, void *data)
323 {
324 
325 	linux_msg(td, "PTRACE_PEEKUSER not implemented; returning EINVAL");
326 	return (EINVAL);
327 }
328 
329 static int
linux_ptrace_pokeuser(struct thread * td,pid_t pid,void * addr,void * data)330 linux_ptrace_pokeuser(struct thread *td, pid_t pid, void *addr, void *data)
331 {
332 
333 	linux_msg(td, "PTRACE_POKEUSER not implemented; returning EINVAL");
334 	return (EINVAL);
335 }
336 
337 static int
linux_ptrace_setoptions(struct thread * td,pid_t pid,l_ulong data)338 linux_ptrace_setoptions(struct thread *td, pid_t pid, l_ulong data)
339 {
340 	struct linux_pemuldata *pem;
341 	int mask;
342 
343 	mask = 0;
344 
345 	if (data & ~LINUX_PTRACE_O_MASK) {
346 		linux_msg(td, "unknown ptrace option %lx set; "
347 		    "returning EINVAL",
348 		    data & ~LINUX_PTRACE_O_MASK);
349 		return (EINVAL);
350 	}
351 
352 	pem = pem_find(td->td_proc);
353 	KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
354 
355 	/*
356 	 * PTRACE_O_EXITKILL is ignored, we do that by default.
357 	 */
358 
359 	LINUX_PEM_XLOCK(pem);
360 	if (data & LINUX_PTRACE_O_TRACESYSGOOD) {
361 		pem->ptrace_flags |= LINUX_PTRACE_O_TRACESYSGOOD;
362 	} else {
363 		pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACESYSGOOD;
364 	}
365 	LINUX_PEM_XUNLOCK(pem);
366 
367 	if (data & LINUX_PTRACE_O_TRACEFORK)
368 		mask |= PTRACE_FORK;
369 
370 	if (data & LINUX_PTRACE_O_TRACEVFORK)
371 		mask |= PTRACE_VFORK;
372 
373 	if (data & LINUX_PTRACE_O_TRACECLONE)
374 		mask |= PTRACE_VFORK;
375 
376 	if (data & LINUX_PTRACE_O_TRACEEXEC)
377 		mask |= PTRACE_EXEC;
378 
379 	if (data & LINUX_PTRACE_O_TRACEVFORKDONE)
380 		mask |= PTRACE_VFORK; /* XXX: Close enough? */
381 
382 	if (data & LINUX_PTRACE_O_TRACEEXIT) {
383 		pem->ptrace_flags |= LINUX_PTRACE_O_TRACEEXIT;
384 	} else {
385 		pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACEEXIT;
386 	}
387 
388 	return (kern_ptrace(td, PT_SET_EVENT_MASK, pid, &mask, sizeof(mask)));
389 }
390 
391 static int
linux_ptrace_getsiginfo(struct thread * td,pid_t pid,l_ulong data)392 linux_ptrace_getsiginfo(struct thread *td, pid_t pid, l_ulong data)
393 {
394 	struct ptrace_lwpinfo lwpinfo;
395 	l_siginfo_t l_siginfo;
396 	int error, sig;
397 
398 	error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
399 	if (error != 0) {
400 		linux_msg(td, "PT_LWPINFO failed with error %d", error);
401 		return (error);
402 	}
403 
404 	if ((lwpinfo.pl_flags & PL_FLAG_SI) == 0) {
405 		error = EINVAL;
406 		linux_msg(td, "no PL_FLAG_SI, returning %d", error);
407 		return (error);
408 	}
409 
410 	sig = bsd_to_linux_signal(lwpinfo.pl_siginfo.si_signo);
411 	siginfo_to_lsiginfo(&lwpinfo.pl_siginfo, &l_siginfo, sig);
412 	error = copyout(&l_siginfo, (void *)data, sizeof(l_siginfo));
413 	return (error);
414 }
415 
416 static int
linux_ptrace_getregs(struct thread * td,pid_t pid,void * data)417 linux_ptrace_getregs(struct thread *td, pid_t pid, void *data)
418 {
419 	struct ptrace_lwpinfo lwpinfo;
420 	struct reg b_reg;
421 	struct linux_pt_reg l_reg;
422 	int error;
423 
424 	error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
425 	if (error != 0)
426 		return (error);
427 
428 	map_regs_to_linux(&b_reg, &l_reg);
429 
430 	error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
431 	if (error != 0) {
432 		linux_msg(td, "PT_LWPINFO failed with error %d", error);
433 		return (error);
434 	}
435 	if (lwpinfo.pl_flags & PL_FLAG_SCE) {
436 		/*
437 		 * The strace(1) utility depends on RAX being set to -ENOSYS
438 		 * on syscall entry; otherwise it loops printing those:
439 		 *
440 		 * [ Process PID=928 runs in 64 bit mode. ]
441 		 * [ Process PID=928 runs in x32 mode. ]
442 		 */
443 		l_reg.rax = -38; /* -ENOSYS */
444 
445 		/*
446 		 * Undo the mangling done in exception.S:fast_syscall_common().
447 		 */
448 		l_reg.r10 = l_reg.rcx;
449 	}
450 
451 	error = copyout(&l_reg, (void *)data, sizeof(l_reg));
452 	return (error);
453 }
454 
455 static int
linux_ptrace_setregs(struct thread * td,pid_t pid,void * data)456 linux_ptrace_setregs(struct thread *td, pid_t pid, void *data)
457 {
458 	struct reg b_reg;
459 	struct linux_pt_reg l_reg;
460 	int error;
461 
462 	error = copyin(data, &l_reg, sizeof(l_reg));
463 	if (error != 0)
464 		return (error);
465 	map_regs_from_linux(&b_reg, &l_reg);
466 	error = kern_ptrace(td, PT_SETREGS, pid, &b_reg, 0);
467 	return (error);
468 }
469 
470 static int
linux_ptrace_getregset_prstatus(struct thread * td,pid_t pid,l_ulong data)471 linux_ptrace_getregset_prstatus(struct thread *td, pid_t pid, l_ulong data)
472 {
473 	struct ptrace_lwpinfo lwpinfo;
474 	struct reg b_reg;
475 	struct linux_pt_regset l_regset;
476 	struct iovec iov;
477 	struct pcb *pcb;
478 	unsigned long fsbase, gsbase;
479 	size_t len;
480 	int error;
481 
482 	error = copyin((const void *)data, &iov, sizeof(iov));
483 	if (error != 0) {
484 		linux_msg(td, "copyin error %d", error);
485 		return (error);
486 	}
487 
488 	error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
489 	if (error != 0)
490 		return (error);
491 
492 	pcb = td->td_pcb;
493 	if (td == curthread)
494 		update_pcb_bases(pcb);
495 	fsbase = pcb->pcb_fsbase;
496 	gsbase = pcb->pcb_gsbase;
497 
498 	map_regs_to_linux_regset(&b_reg, fsbase, gsbase, &l_regset);
499 
500 	error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
501 	if (error != 0) {
502 		linux_msg(td, "PT_LWPINFO failed with error %d", error);
503 		return (error);
504 	}
505 	if (lwpinfo.pl_flags & PL_FLAG_SCE) {
506 		/*
507 		 * The strace(1) utility depends on RAX being set to -ENOSYS
508 		 * on syscall entry; otherwise it loops printing those:
509 		 *
510 		 * [ Process PID=928 runs in 64 bit mode. ]
511 		 * [ Process PID=928 runs in x32 mode. ]
512 		 */
513 		l_regset.rax = -38; /* -ENOSYS */
514 
515 		/*
516 		 * Undo the mangling done in exception.S:fast_syscall_common().
517 		 */
518 		l_regset.r10 = l_regset.rcx;
519 	}
520 
521 	len = MIN(iov.iov_len, sizeof(l_regset));
522 	error = copyout(&l_regset, (void *)iov.iov_base, len);
523 	if (error != 0) {
524 		linux_msg(td, "copyout error %d", error);
525 		return (error);
526 	}
527 
528 	iov.iov_len -= len;
529 	error = copyout(&iov, (void *)data, sizeof(iov));
530 	if (error != 0) {
531 		linux_msg(td, "iov copyout error %d", error);
532 		return (error);
533 	}
534 
535 	return (error);
536 }
537 
538 static int
linux_ptrace_getregset(struct thread * td,pid_t pid,l_ulong addr,l_ulong data)539 linux_ptrace_getregset(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
540 {
541 
542 	switch (addr) {
543 	case LINUX_NT_PRSTATUS:
544 		return (linux_ptrace_getregset_prstatus(td, pid, data));
545 	default:
546 		linux_msg(td, "PTRACE_GETREGSET request %ld not implemented; "
547 		    "returning EINVAL", addr);
548 		return (EINVAL);
549 	}
550 }
551 
552 static int
linux_ptrace_seize(struct thread * td,pid_t pid,l_ulong addr,l_ulong data)553 linux_ptrace_seize(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
554 {
555 
556 	linux_msg(td, "PTRACE_SEIZE not implemented; returning EINVAL");
557 	return (EINVAL);
558 }
559 
560 static int
linux_ptrace_get_syscall_info(struct thread * td,pid_t pid,l_ulong addr,l_ulong data)561 linux_ptrace_get_syscall_info(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
562 {
563 
564 	linux_msg(td, "PTRACE_GET_SYSCALL_INFO not implemented; returning EINVAL");
565 	return (EINVAL);
566 }
567 
568 int
linux_ptrace(struct thread * td,struct linux_ptrace_args * uap)569 linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
570 {
571 	void *addr;
572 	pid_t pid;
573 	int error, sig;
574 
575 	pid  = (pid_t)uap->pid;
576 	addr = (void *)uap->addr;
577 
578 	switch (uap->req) {
579 	case LINUX_PTRACE_TRACEME:
580 		error = kern_ptrace(td, PT_TRACE_ME, 0, 0, 0);
581 		break;
582 	case LINUX_PTRACE_PEEKTEXT:
583 	case LINUX_PTRACE_PEEKDATA:
584 		error = linux_ptrace_peek(td, pid, addr, (void *)uap->data);
585 		if (error != 0)
586 			goto out;
587 		/*
588 		 * Linux expects this syscall to read 64 bits, not 32.
589 		 */
590 		error = linux_ptrace_peek(td, pid,
591 		    (void *)(uap->addr + 4), (void *)(uap->data + 4));
592 		break;
593 	case LINUX_PTRACE_PEEKUSER:
594 		error = linux_ptrace_peekuser(td, pid, addr, (void *)uap->data);
595 		break;
596 	case LINUX_PTRACE_POKETEXT:
597 	case LINUX_PTRACE_POKEDATA:
598 		error = kern_ptrace(td, PT_WRITE_D, pid, addr, uap->data);
599 		if (error != 0)
600 			goto out;
601 		/*
602 		 * Linux expects this syscall to write 64 bits, not 32.
603 		 */
604 		error = kern_ptrace(td, PT_WRITE_D, pid,
605 		    (void *)(uap->addr + 4), uap->data >> 32);
606 		break;
607 	case LINUX_PTRACE_POKEUSER:
608 		error = linux_ptrace_pokeuser(td, pid, addr, (void *)uap->data);
609 		break;
610 	case LINUX_PTRACE_CONT:
611 		error = map_signum(uap->data, &sig);
612 		if (error != 0)
613 			break;
614 		error = kern_ptrace(td, PT_CONTINUE, pid, (void *)1, sig);
615 		break;
616 	case LINUX_PTRACE_KILL:
617 		error = kern_ptrace(td, PT_KILL, pid, addr, uap->data);
618 		break;
619 	case LINUX_PTRACE_SINGLESTEP:
620 		error = map_signum(uap->data, &sig);
621 		if (error != 0)
622 			break;
623 		error = kern_ptrace(td, PT_STEP, pid, (void *)1, sig);
624 		break;
625 	case LINUX_PTRACE_GETREGS:
626 		error = linux_ptrace_getregs(td, pid, (void *)uap->data);
627 		break;
628 	case LINUX_PTRACE_SETREGS:
629 		error = linux_ptrace_setregs(td, pid, (void *)uap->data);
630 		break;
631 	case LINUX_PTRACE_ATTACH:
632 		error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data);
633 		break;
634 	case LINUX_PTRACE_DETACH:
635 		error = map_signum(uap->data, &sig);
636 		if (error != 0)
637 			break;
638 		error = kern_ptrace(td, PT_DETACH, pid, (void *)1, sig);
639 		break;
640 	case LINUX_PTRACE_SYSCALL:
641 		error = map_signum(uap->data, &sig);
642 		if (error != 0)
643 			break;
644 		error = kern_ptrace(td, PT_SYSCALL, pid, (void *)1, sig);
645 		break;
646 	case LINUX_PTRACE_SETOPTIONS:
647 		error = linux_ptrace_setoptions(td, pid, uap->data);
648 		break;
649 	case LINUX_PTRACE_GETSIGINFO:
650 		error = linux_ptrace_getsiginfo(td, pid, uap->data);
651 		break;
652 	case LINUX_PTRACE_GETREGSET:
653 		error = linux_ptrace_getregset(td, pid, uap->addr, uap->data);
654 		break;
655 	case LINUX_PTRACE_SEIZE:
656 		error = linux_ptrace_seize(td, pid, uap->addr, uap->data);
657 		break;
658 	case LINUX_PTRACE_GET_SYSCALL_INFO:
659 		error = linux_ptrace_get_syscall_info(td, pid, uap->addr, uap->data);
660 		break;
661 	default:
662 		linux_msg(td, "ptrace(%ld, ...) not implemented; "
663 		    "returning EINVAL", uap->req);
664 		error = EINVAL;
665 		break;
666 	}
667 
668 out:
669 	if (error == EBUSY)
670 		error = ESRCH;
671 
672 	return (error);
673 }
674