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