2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2017 Edward Tomasz Napierala <trasz@FreeBSD.org>
7 * This software was developed by SRI International and the University of
8 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
9 * ("CTSRD"), as part of the DARPA CRASH research programme.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
39 #include <sys/ptrace.h>
41 #include <sys/syscallsubr.h>
43 #include <machine/pcb.h>
44 #include <machine/reg.h>
46 #include <amd64/linux/linux.h>
47 #include <amd64/linux/linux_proto.h>
48 #include <compat/linux/linux_emul.h>
49 #include <compat/linux/linux_misc.h>
50 #include <compat/linux/linux_signal.h>
51 #include <compat/linux/linux_util.h>
53 #define LINUX_PTRACE_TRACEME 0
54 #define LINUX_PTRACE_PEEKTEXT 1
55 #define LINUX_PTRACE_PEEKDATA 2
56 #define LINUX_PTRACE_PEEKUSER 3
57 #define LINUX_PTRACE_POKETEXT 4
58 #define LINUX_PTRACE_POKEDATA 5
59 #define LINUX_PTRACE_POKEUSER 6
60 #define LINUX_PTRACE_CONT 7
61 #define LINUX_PTRACE_KILL 8
62 #define LINUX_PTRACE_SINGLESTEP 9
63 #define LINUX_PTRACE_GETREGS 12
64 #define LINUX_PTRACE_SETREGS 13
65 #define LINUX_PTRACE_GETFPREGS 14
66 #define LINUX_PTRACE_SETFPREGS 15
67 #define LINUX_PTRACE_ATTACH 16
68 #define LINUX_PTRACE_DETACH 17
69 #define LINUX_PTRACE_SYSCALL 24
70 #define LINUX_PTRACE_SETOPTIONS 0x4200
71 #define LINUX_PTRACE_GETREGSET 0x4204
72 #define LINUX_PTRACE_SEIZE 0x4206
74 #define LINUX_PTRACE_O_TRACESYSGOOD 1
75 #define LINUX_PTRACE_O_TRACEFORK 2
76 #define LINUX_PTRACE_O_TRACEVFORK 4
77 #define LINUX_PTRACE_O_TRACECLONE 8
78 #define LINUX_PTRACE_O_TRACEEXEC 16
79 #define LINUX_PTRACE_O_TRACEVFORKDONE 32
80 #define LINUX_PTRACE_O_TRACEEXIT 64
81 #define LINUX_PTRACE_O_TRACESECCOMP 128
82 #define LINUX_PTRACE_O_EXITKILL 1048576
83 #define LINUX_PTRACE_O_SUSPEND_SECCOMP 2097152
85 #define LINUX_NT_PRSTATUS 1
87 #define LINUX_PTRACE_O_MASK (LINUX_PTRACE_O_TRACESYSGOOD | \
88 LINUX_PTRACE_O_TRACEFORK | LINUX_PTRACE_O_TRACEVFORK | \
89 LINUX_PTRACE_O_TRACECLONE | LINUX_PTRACE_O_TRACEEXEC | \
90 LINUX_PTRACE_O_TRACEVFORKDONE | LINUX_PTRACE_O_TRACEEXIT | \
91 LINUX_PTRACE_O_TRACESECCOMP | LINUX_PTRACE_O_EXITKILL | \
92 LINUX_PTRACE_O_SUSPEND_SECCOMP)
95 map_signum(int lsig, int *bsigp)
104 if (lsig < 0 || lsig > LINUX_SIGRTMAX)
107 bsig = linux_to_bsd_signal(lsig);
116 linux_ptrace_status(struct thread *td, pid_t pid, int status)
118 struct ptrace_lwpinfo lwpinfo;
119 struct linux_pemuldata *pem;
120 register_t saved_retval;
123 saved_retval = td->td_retval[0];
124 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
125 td->td_retval[0] = saved_retval;
127 linux_msg(td, "PT_LWPINFO failed with error %d", error);
131 pem = pem_find(td->td_proc);
132 KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
134 LINUX_PEM_SLOCK(pem);
135 if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) &&
136 lwpinfo.pl_flags & PL_FLAG_SCE)
137 status |= (LINUX_SIGTRAP | 0x80) << 8;
138 if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) &&
139 lwpinfo.pl_flags & PL_FLAG_SCX)
140 status |= (LINUX_SIGTRAP | 0x80) << 8;
141 LINUX_PEM_SUNLOCK(pem);
146 struct linux_pt_reg {
170 struct linux_pt_regset {
201 * Translate amd64 ptrace registers between Linux and FreeBSD formats.
202 * The translation is pretty straighforward, for all registers but
203 * orig_rax on Linux side and r_trapno and r_err in FreeBSD.
206 map_regs_to_linux(struct reg *b_reg, struct linux_pt_reg *l_reg)
209 l_reg->r15 = b_reg->r_r15;
210 l_reg->r14 = b_reg->r_r14;
211 l_reg->r13 = b_reg->r_r13;
212 l_reg->r12 = b_reg->r_r12;
213 l_reg->rbp = b_reg->r_rbp;
214 l_reg->rbx = b_reg->r_rbx;
215 l_reg->r11 = b_reg->r_r11;
216 l_reg->r10 = b_reg->r_r10;
217 l_reg->r9 = b_reg->r_r9;
218 l_reg->r8 = b_reg->r_r8;
219 l_reg->rax = b_reg->r_rax;
220 l_reg->rcx = b_reg->r_rcx;
221 l_reg->rdx = b_reg->r_rdx;
222 l_reg->rsi = b_reg->r_rsi;
223 l_reg->rdi = b_reg->r_rdi;
224 l_reg->orig_rax = b_reg->r_rax;
225 l_reg->rip = b_reg->r_rip;
226 l_reg->cs = b_reg->r_cs;
227 l_reg->eflags = b_reg->r_rflags;
228 l_reg->rsp = b_reg->r_rsp;
229 l_reg->ss = b_reg->r_ss;
233 map_regs_to_linux_regset(struct reg *b_reg, unsigned long fs_base,
234 unsigned long gs_base, struct linux_pt_regset *l_regset)
237 l_regset->r15 = b_reg->r_r15;
238 l_regset->r14 = b_reg->r_r14;
239 l_regset->r13 = b_reg->r_r13;
240 l_regset->r12 = b_reg->r_r12;
241 l_regset->rbp = b_reg->r_rbp;
242 l_regset->rbx = b_reg->r_rbx;
243 l_regset->r11 = b_reg->r_r11;
244 l_regset->r10 = b_reg->r_r10;
245 l_regset->r9 = b_reg->r_r9;
246 l_regset->r8 = b_reg->r_r8;
247 l_regset->rax = b_reg->r_rax;
248 l_regset->rcx = b_reg->r_rcx;
249 l_regset->rdx = b_reg->r_rdx;
250 l_regset->rsi = b_reg->r_rsi;
251 l_regset->rdi = b_reg->r_rdi;
252 l_regset->orig_rax = b_reg->r_rax;
253 l_regset->rip = b_reg->r_rip;
254 l_regset->cs = b_reg->r_cs;
255 l_regset->eflags = b_reg->r_rflags;
256 l_regset->rsp = b_reg->r_rsp;
257 l_regset->ss = b_reg->r_ss;
258 l_regset->fs_base = fs_base;
259 l_regset->gs_base = gs_base;
260 l_regset->ds = b_reg->r_ds;
261 l_regset->es = b_reg->r_es;
262 l_regset->fs = b_reg->r_fs;
263 l_regset->gs = b_reg->r_gs;
267 map_regs_from_linux(struct reg *b_reg, struct linux_pt_reg *l_reg)
269 b_reg->r_r15 = l_reg->r15;
270 b_reg->r_r14 = l_reg->r14;
271 b_reg->r_r13 = l_reg->r13;
272 b_reg->r_r12 = l_reg->r12;
273 b_reg->r_r11 = l_reg->r11;
274 b_reg->r_r10 = l_reg->r10;
275 b_reg->r_r9 = l_reg->r9;
276 b_reg->r_r8 = l_reg->r8;
277 b_reg->r_rdi = l_reg->rdi;
278 b_reg->r_rsi = l_reg->rsi;
279 b_reg->r_rbp = l_reg->rbp;
280 b_reg->r_rbx = l_reg->rbx;
281 b_reg->r_rdx = l_reg->rdx;
282 b_reg->r_rcx = l_reg->rcx;
283 b_reg->r_rax = l_reg->rax;
286 * XXX: Are zeroes the right thing to put here?
295 b_reg->r_rip = l_reg->rip;
296 b_reg->r_cs = l_reg->cs;
297 b_reg->r_rflags = l_reg->eflags;
298 b_reg->r_rsp = l_reg->rsp;
299 b_reg->r_ss = l_reg->ss;
303 linux_ptrace_peek(struct thread *td, pid_t pid, void *addr, void *data)
307 error = kern_ptrace(td, PT_READ_I, pid, addr, 0);
309 error = copyout(td->td_retval, data, sizeof(l_int));
310 td->td_retval[0] = error;
316 linux_ptrace_setoptions(struct thread *td, pid_t pid, l_ulong data)
318 struct linux_pemuldata *pem;
323 if (data & ~LINUX_PTRACE_O_MASK) {
324 linux_msg(td, "unknown ptrace option %lx set; "
326 data & ~LINUX_PTRACE_O_MASK);
330 pem = pem_find(td->td_proc);
331 KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
334 * PTRACE_O_EXITKILL is ignored, we do that by default.
337 LINUX_PEM_XLOCK(pem);
338 if (data & LINUX_PTRACE_O_TRACESYSGOOD) {
339 pem->ptrace_flags |= LINUX_PTRACE_O_TRACESYSGOOD;
341 pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACESYSGOOD;
343 LINUX_PEM_XUNLOCK(pem);
345 if (data & LINUX_PTRACE_O_TRACEFORK)
348 if (data & LINUX_PTRACE_O_TRACEVFORK)
349 mask |= PTRACE_VFORK;
351 if (data & LINUX_PTRACE_O_TRACECLONE)
352 mask |= PTRACE_VFORK;
354 if (data & LINUX_PTRACE_O_TRACEEXEC)
357 if (data & LINUX_PTRACE_O_TRACEVFORKDONE)
358 mask |= PTRACE_VFORK; /* XXX: Close enough? */
360 if (data & LINUX_PTRACE_O_TRACEEXIT) {
361 linux_msg(td, "PTRACE_O_TRACEEXIT not implemented; "
366 return (kern_ptrace(td, PT_SET_EVENT_MASK, pid, &mask, sizeof(mask)));
370 linux_ptrace_getregs(struct thread *td, pid_t pid, void *data)
372 struct ptrace_lwpinfo lwpinfo;
374 struct linux_pt_reg l_reg;
377 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
381 map_regs_to_linux(&b_reg, &l_reg);
383 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
385 linux_msg(td, "PT_LWPINFO failed with error %d", error);
388 if (lwpinfo.pl_flags & PL_FLAG_SCE) {
390 * The strace(1) utility depends on RAX being set to -ENOSYS
391 * on syscall entry; otherwise it loops printing those:
393 * [ Process PID=928 runs in 64 bit mode. ]
394 * [ Process PID=928 runs in x32 mode. ]
396 l_reg.rax = -38; /* -ENOSYS */
399 * Undo the mangling done in exception.S:fast_syscall_common().
401 l_reg.r10 = l_reg.rcx;
404 error = copyout(&l_reg, (void *)data, sizeof(l_reg));
409 linux_ptrace_setregs(struct thread *td, pid_t pid, void *data)
412 struct linux_pt_reg l_reg;
415 error = copyin(data, &l_reg, sizeof(l_reg));
418 map_regs_from_linux(&b_reg, &l_reg);
419 error = kern_ptrace(td, PT_SETREGS, pid, &b_reg, 0);
424 linux_ptrace_getregset_prstatus(struct thread *td, pid_t pid, l_ulong data)
426 struct ptrace_lwpinfo lwpinfo;
428 struct linux_pt_regset l_regset;
431 unsigned long fsbase, gsbase;
435 error = copyin((const void *)data, &iov, sizeof(iov));
437 linux_msg(td, "copyin error %d", error);
441 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
447 update_pcb_bases(pcb);
448 fsbase = pcb->pcb_fsbase;
449 gsbase = pcb->pcb_gsbase;
451 map_regs_to_linux_regset(&b_reg, fsbase, gsbase, &l_regset);
453 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
455 linux_msg(td, "PT_LWPINFO failed with error %d", error);
458 if (lwpinfo.pl_flags & PL_FLAG_SCE) {
460 * The strace(1) utility depends on RAX being set to -ENOSYS
461 * on syscall entry; otherwise it loops printing those:
463 * [ Process PID=928 runs in 64 bit mode. ]
464 * [ Process PID=928 runs in x32 mode. ]
466 l_regset.rax = -38; /* -ENOSYS */
469 * Undo the mangling done in exception.S:fast_syscall_common().
471 l_regset.r10 = l_regset.rcx;
474 len = MIN(iov.iov_len, sizeof(l_regset));
475 error = copyout(&l_regset, (void *)iov.iov_base, len);
477 linux_msg(td, "copyout error %d", error);
482 error = copyout(&iov, (void *)data, sizeof(iov));
484 linux_msg(td, "iov copyout error %d", error);
492 linux_ptrace_getregset(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
496 case LINUX_NT_PRSTATUS:
497 return (linux_ptrace_getregset_prstatus(td, pid, data));
499 linux_msg(td, "PTRACE_GETREGSET request %ld not implemented; "
500 "returning EINVAL", addr);
506 linux_ptrace_seize(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
509 linux_msg(td, "PTRACE_SEIZE not implemented; returning EINVAL");
514 linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
520 pid = (pid_t)uap->pid;
521 addr = (void *)uap->addr;
524 case LINUX_PTRACE_TRACEME:
525 error = kern_ptrace(td, PT_TRACE_ME, 0, 0, 0);
527 case LINUX_PTRACE_PEEKTEXT:
528 case LINUX_PTRACE_PEEKDATA:
529 error = linux_ptrace_peek(td, pid, addr, (void *)uap->data);
533 * Linux expects this syscall to read 64 bits, not 32.
535 error = linux_ptrace_peek(td, pid,
536 (void *)(uap->addr + 4), (void *)(uap->data + 4));
538 case LINUX_PTRACE_POKETEXT:
539 error = kern_ptrace(td, PT_WRITE_I, pid, addr, uap->data);
541 case LINUX_PTRACE_POKEDATA:
542 error = kern_ptrace(td, PT_WRITE_D, pid, addr, uap->data);
544 case LINUX_PTRACE_CONT:
545 error = map_signum(uap->data, &sig);
548 error = kern_ptrace(td, PT_CONTINUE, pid, (void *)1, sig);
550 case LINUX_PTRACE_KILL:
551 error = kern_ptrace(td, PT_KILL, pid, addr, uap->data);
553 case LINUX_PTRACE_SINGLESTEP:
554 error = map_signum(uap->data, &sig);
557 error = kern_ptrace(td, PT_STEP, pid, (void *)1, sig);
559 case LINUX_PTRACE_GETREGS:
560 error = linux_ptrace_getregs(td, pid, (void *)uap->data);
562 case LINUX_PTRACE_SETREGS:
563 error = linux_ptrace_setregs(td, pid, (void *)uap->data);
565 case LINUX_PTRACE_ATTACH:
566 error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data);
568 case LINUX_PTRACE_DETACH:
569 error = map_signum(uap->data, &sig);
572 error = kern_ptrace(td, PT_DETACH, pid, (void *)1, sig);
574 case LINUX_PTRACE_SYSCALL:
575 error = map_signum(uap->data, &sig);
578 error = kern_ptrace(td, PT_SYSCALL, pid, (void *)1, sig);
580 case LINUX_PTRACE_SETOPTIONS:
581 error = linux_ptrace_setoptions(td, pid, uap->data);
583 case LINUX_PTRACE_GETREGSET:
584 error = linux_ptrace_getregset(td, pid, uap->addr, uap->data);
586 case LINUX_PTRACE_SEIZE:
587 error = linux_ptrace_seize(td, pid, uap->addr, uap->data);
590 linux_msg(td, "ptrace(%ld, ...) not implemented; "
591 "returning EINVAL", uap->req);