2 * Copyright (c) 2017 Edward Tomasz Napierala <trasz@FreeBSD.org>
5 * This software was developed by SRI International and the University of
6 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7 * ("CTSRD"), as part of the DARPA CRASH research programme.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
36 #include <sys/ptrace.h>
37 #include <sys/syscallsubr.h>
39 #include <machine/pcb.h>
40 #include <machine/reg.h>
42 #include <amd64/linux/linux.h>
43 #include <amd64/linux/linux_proto.h>
44 #include <compat/linux/linux_signal.h>
46 #define LINUX_PTRACE_TRACEME 0
47 #define LINUX_PTRACE_PEEKTEXT 1
48 #define LINUX_PTRACE_PEEKDATA 2
49 #define LINUX_PTRACE_PEEKUSER 3
50 #define LINUX_PTRACE_POKETEXT 4
51 #define LINUX_PTRACE_POKEDATA 5
52 #define LINUX_PTRACE_POKEUSER 6
53 #define LINUX_PTRACE_CONT 7
54 #define LINUX_PTRACE_KILL 8
55 #define LINUX_PTRACE_SINGLESTEP 9
56 #define LINUX_PTRACE_GETREGS 12
57 #define LINUX_PTRACE_SETREGS 13
58 #define LINUX_PTRACE_GETFPREGS 14
59 #define LINUX_PTRACE_SETFPREGS 15
60 #define LINUX_PTRACE_ATTACH 16
61 #define LINUX_PTRACE_DETACH 17
62 #define LINUX_PTRACE_SYSCALL 24
63 #define LINUX_PTRACE_SETOPTIONS 0x4200
64 #define LINUX_PTRACE_GETREGSET 0x4204
65 #define LINUX_PTRACE_SEIZE 0x4206
67 #define LINUX_PTRACE_O_TRACESYSGOOD 1
68 #define LINUX_PTRACE_O_TRACEFORK 2
69 #define LINUX_PTRACE_O_TRACEVFORK 4
70 #define LINUX_PTRACE_O_TRACECLONE 8
71 #define LINUX_PTRACE_O_TRACEEXEC 16
72 #define LINUX_PTRACE_O_TRACEVFORKDONE 32
73 #define LINUX_PTRACE_O_TRACEEXIT 64
74 #define LINUX_PTRACE_O_TRACESECCOMP 128
75 #define LINUX_PTRACE_O_EXITKILL 1048576
76 #define LINUX_PTRACE_O_SUSPEND_SECCOMP 2097152
78 #define LINUX_NT_PRSTATUS 1
80 #define LINUX_PTRACE_O_MASK (LINUX_PTRACE_O_TRACESYSGOOD | \
81 LINUX_PTRACE_O_TRACEFORK | LINUX_PTRACE_O_TRACEVFORK | \
82 LINUX_PTRACE_O_TRACECLONE | LINUX_PTRACE_O_TRACEEXEC | \
83 LINUX_PTRACE_O_TRACEVFORKDONE | LINUX_PTRACE_O_TRACEEXIT | \
84 LINUX_PTRACE_O_TRACESECCOMP | LINUX_PTRACE_O_EXITKILL | \
85 LINUX_PTRACE_O_SUSPEND_SECCOMP)
88 map_signum(int lsig, int *bsigp)
97 if (lsig < 0 || lsig > LINUX_SIGRTMAX)
100 bsig = linux_to_bsd_signal(lsig);
108 struct linux_pt_reg {
133 * Translate amd64 ptrace registers between Linux and FreeBSD formats.
134 * The translation is pretty straighforward, for all registers but
135 * orig_rax on Linux side and r_trapno and r_err in FreeBSD.
138 map_regs_to_linux(struct reg *b_reg, struct linux_pt_reg *l_reg)
141 l_reg->r15 = b_reg->r_r15;
142 l_reg->r14 = b_reg->r_r14;
143 l_reg->r13 = b_reg->r_r13;
144 l_reg->r12 = b_reg->r_r12;
145 l_reg->rbp = b_reg->r_rbp;
146 l_reg->rbx = b_reg->r_rbx;
147 l_reg->r11 = b_reg->r_r11;
148 l_reg->r10 = b_reg->r_r10;
149 l_reg->r9 = b_reg->r_r9;
150 l_reg->r8 = b_reg->r_r8;
151 l_reg->rax = b_reg->r_rax;
152 l_reg->rcx = b_reg->r_rcx;
153 l_reg->rdx = b_reg->r_rdx;
154 l_reg->rsi = b_reg->r_rsi;
155 l_reg->rdi = b_reg->r_rdi;
156 l_reg->orig_rax = b_reg->r_rax;
157 l_reg->rip = b_reg->r_rip;
158 l_reg->cs = b_reg->r_cs;
159 l_reg->eflags = b_reg->r_rflags;
160 l_reg->rsp = b_reg->r_rsp;
161 l_reg->ss = b_reg->r_ss;
165 map_regs_from_linux(struct reg *b_reg, struct linux_pt_reg *l_reg)
167 b_reg->r_r15 = l_reg->r15;
168 b_reg->r_r14 = l_reg->r14;
169 b_reg->r_r13 = l_reg->r13;
170 b_reg->r_r12 = l_reg->r12;
171 b_reg->r_r11 = l_reg->r11;
172 b_reg->r_r10 = l_reg->r10;
173 b_reg->r_r9 = l_reg->r9;
174 b_reg->r_r8 = l_reg->r8;
175 b_reg->r_rdi = l_reg->rdi;
176 b_reg->r_rsi = l_reg->rsi;
177 b_reg->r_rbp = l_reg->rbp;
178 b_reg->r_rbx = l_reg->rbx;
179 b_reg->r_rdx = l_reg->rdx;
180 b_reg->r_rcx = l_reg->rcx;
181 b_reg->r_rax = l_reg->rax;
184 * XXX: Are zeroes the right thing to put here?
193 b_reg->r_rip = l_reg->rip;
194 b_reg->r_cs = l_reg->cs;
195 b_reg->r_rflags = l_reg->eflags;
196 b_reg->r_rsp = l_reg->rsp;
197 b_reg->r_ss = l_reg->ss;
201 linux_ptrace_peek(struct thread *td, pid_t pid, void *addr, void *data)
205 error = kern_ptrace(td, PT_READ_I, pid, addr, 0);
207 error = copyout(td->td_retval, data, sizeof(l_int));
208 td->td_retval[0] = error;
214 linux_ptrace_setoptions(struct thread *td, pid_t pid, l_ulong data)
220 if (data & ~LINUX_PTRACE_O_MASK) {
221 printf("%s: unknown ptrace option %lx set; "
222 "returning EINVAL\n",
223 __func__, data & ~LINUX_PTRACE_O_MASK);
228 * PTRACE_O_EXITKILL is ignored, we do that by default.
231 if (data & LINUX_PTRACE_O_TRACESYSGOOD) {
232 printf("%s: PTRACE_O_TRACESYSGOOD not implemented; "
233 "returning EINVAL\n", __func__);
237 if (data & LINUX_PTRACE_O_TRACEFORK)
240 if (data & LINUX_PTRACE_O_TRACEVFORK)
241 mask |= PTRACE_VFORK;
243 if (data & LINUX_PTRACE_O_TRACECLONE)
244 mask |= PTRACE_VFORK;
246 if (data & LINUX_PTRACE_O_TRACEEXEC)
249 if (data & LINUX_PTRACE_O_TRACEVFORKDONE)
250 mask |= PTRACE_VFORK; /* XXX: Close enough? */
252 if (data & LINUX_PTRACE_O_TRACEEXIT) {
253 printf("%s: PTRACE_O_TRACEEXIT not implemented; "
254 "returning EINVAL\n", __func__);
258 return (kern_ptrace(td, PT_SET_EVENT_MASK, pid, &mask, sizeof(mask)));
262 linux_ptrace_getregs(struct thread *td, pid_t pid, void *data)
264 struct ptrace_lwpinfo lwpinfo;
266 struct linux_pt_reg l_reg;
269 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
273 map_regs_to_linux(&b_reg, &l_reg);
276 * The strace(1) utility depends on RAX being set to -ENOSYS
279 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
281 printf("%s: PT_LWPINFO failed with error %d\n", __func__, error);
284 if (lwpinfo.pl_flags & PL_FLAG_SCE)
285 l_reg.rax = -38; // XXX: Don't hardcode?
287 error = copyout(&l_reg, (void *)data, sizeof(l_reg));
292 linux_ptrace_setregs(struct thread *td, pid_t pid, void *data)
295 struct linux_pt_reg l_reg;
298 error = copyin(data, &l_reg, sizeof(l_reg));
301 map_regs_from_linux(&b_reg, &l_reg);
302 error = kern_ptrace(td, PT_SETREGS, pid, &b_reg, 0);
307 linux_ptrace_getregset(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
311 case LINUX_NT_PRSTATUS:
312 printf("%s: NT_PRSTATUS not implemented; returning EINVAL\n",
316 printf("%s: PTRACE_GETREGSET request %ld not implemented; "
317 "returning EINVAL\n", __func__, addr);
323 linux_ptrace_seize(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
326 printf("%s: PTRACE_SEIZE not implemented; returning EINVAL\n", __func__);
331 linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
337 pid = (pid_t)uap->pid;
338 addr = (void *)uap->addr;
341 case LINUX_PTRACE_TRACEME:
342 error = kern_ptrace(td, PT_TRACE_ME, 0, 0, 0);
344 case LINUX_PTRACE_PEEKTEXT:
345 case LINUX_PTRACE_PEEKDATA:
346 error = linux_ptrace_peek(td, pid, addr, (void *)uap->data);
350 * Linux expects this syscall to read 64 bits, not 32.
352 error = linux_ptrace_peek(td, pid,
353 (void *)(uap->addr + 4), (void *)(uap->data + 4));
355 case LINUX_PTRACE_POKETEXT:
356 error = kern_ptrace(td, PT_WRITE_I, pid, addr, uap->data);
358 case LINUX_PTRACE_POKEDATA:
359 error = kern_ptrace(td, PT_WRITE_D, pid, addr, uap->data);
361 case LINUX_PTRACE_CONT:
362 error = map_signum(uap->data, &sig);
365 error = kern_ptrace(td, PT_CONTINUE, pid, (void *)1, sig);
367 case LINUX_PTRACE_KILL:
368 error = kern_ptrace(td, PT_KILL, pid, addr, uap->data);
370 case LINUX_PTRACE_SINGLESTEP:
371 error = map_signum(uap->data, &sig);
374 error = kern_ptrace(td, PT_STEP, pid, (void *)1, sig);
376 case LINUX_PTRACE_GETREGS:
377 error = linux_ptrace_getregs(td, pid, (void *)uap->data);
379 case LINUX_PTRACE_SETREGS:
380 error = linux_ptrace_setregs(td, pid, (void *)uap->data);
382 case LINUX_PTRACE_ATTACH:
383 error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data);
385 case LINUX_PTRACE_DETACH:
386 error = map_signum(uap->data, &sig);
389 error = kern_ptrace(td, PT_DETACH, pid, (void *)1, sig);
391 case LINUX_PTRACE_SYSCALL:
392 error = map_signum(uap->data, &sig);
395 error = kern_ptrace(td, PT_SYSCALL, pid, (void *)1, sig);
397 case LINUX_PTRACE_SETOPTIONS:
398 error = linux_ptrace_setoptions(td, pid, uap->data);
400 case LINUX_PTRACE_GETREGSET:
401 error = linux_ptrace_getregset(td, pid, uap->addr, uap->data);
403 case LINUX_PTRACE_SEIZE:
404 error = linux_ptrace_seize(td, pid, uap->addr, uap->data);
407 printf("%s: ptrace(%ld, ...) not implemented; returning EINVAL\n",