2 * Copyright (c) 2001 Alexander Kabaev
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
28 * $FreeBSD: src/sys/i386/linux/linux_ptrace.c,v 1.7.4.3 2003/01/03 17:13:23 kan Exp $
29 * $DragonFly: src/sys/emulation/linux/i386/linux_ptrace.c,v 1.15 2007/02/19 01:14:23 corecode Exp $
34 #include <sys/param.h>
37 #include <sys/ptrace.h>
38 #include <sys/systm.h>
42 #include <vm/vm_map.h>
46 #include <machine/md_var.h>
47 #include <machine/pcb.h>
50 #include "linux_proto.h"
53 * Linux ptrace requests numbers. Mostly identical to FreeBSD,
54 * except for MD ones and PT_ATTACH/PT_DETACH.
56 #define PTRACE_TRACEME 0
57 #define PTRACE_PEEKTEXT 1
58 #define PTRACE_PEEKDATA 2
59 #define PTRACE_PEEKUSR 3
60 #define PTRACE_POKETEXT 4
61 #define PTRACE_POKEDATA 5
62 #define PTRACE_POKEUSR 6
65 #define PTRACE_SINGLESTEP 9
67 #define PTRACE_ATTACH 16
68 #define PTRACE_DETACH 17
70 #define PTRACE_SYSCALL 24
72 #define PTRACE_GETREGS 12
73 #define PTRACE_SETREGS 13
74 #define PTRACE_GETFPREGS 14
75 #define PTRACE_SETFPREGS 15
76 #define PTRACE_GETFPXREGS 18
77 #define PTRACE_SETFPXREGS 19
79 #define PTRACE_SETOPTIONS 21
82 * Linux keeps debug registers at the following
83 * offset in the user struct
85 #define LINUX_DBREG_OFFSET 252
86 #define LINUX_DBREG_SIZE (8*sizeof(l_int))
89 map_signum(int signum
)
92 if (signum
> 0 && signum
<= LINUX_SIGTBLSZ
)
93 signum
= linux_to_bsd_signal
[_SIG_IDX(signum
)];
94 return ((signum
== SIGSTOP
)? 0 : signum
);
118 * Translate i386 ptrace registers between Linux and FreeBSD formats.
119 * The translation is pretty straighforward, for all registers, but
120 * orig_eax on Linux side and r_trapno and r_err in FreeBSD
123 map_regs_to_linux(struct reg
*bsd_r
, struct linux_pt_reg
*linux_r
)
125 linux_r
->ebx
= bsd_r
->r_ebx
;
126 linux_r
->ecx
= bsd_r
->r_ecx
;
127 linux_r
->edx
= bsd_r
->r_edx
;
128 linux_r
->esi
= bsd_r
->r_esi
;
129 linux_r
->edi
= bsd_r
->r_edi
;
130 linux_r
->ebp
= bsd_r
->r_ebp
;
131 linux_r
->eax
= bsd_r
->r_eax
;
132 linux_r
->xds
= bsd_r
->r_ds
;
133 linux_r
->xes
= bsd_r
->r_es
;
134 linux_r
->xfs
= bsd_r
->r_fs
;
135 linux_r
->xgs
= bsd_r
->r_gs
;
136 linux_r
->orig_eax
= bsd_r
->r_eax
;
137 linux_r
->eip
= bsd_r
->r_eip
;
138 linux_r
->xcs
= bsd_r
->r_cs
;
139 linux_r
->eflags
= bsd_r
->r_eflags
;
140 linux_r
->esp
= bsd_r
->r_esp
;
141 linux_r
->xss
= bsd_r
->r_ss
;
145 map_regs_from_linux(struct reg
*bsd_r
, struct linux_pt_reg
*linux_r
)
147 bsd_r
->r_ebx
= linux_r
->ebx
;
148 bsd_r
->r_ecx
= linux_r
->ecx
;
149 bsd_r
->r_edx
= linux_r
->edx
;
150 bsd_r
->r_esi
= linux_r
->esi
;
151 bsd_r
->r_edi
= linux_r
->edi
;
152 bsd_r
->r_ebp
= linux_r
->ebp
;
153 bsd_r
->r_eax
= linux_r
->eax
;
154 bsd_r
->r_ds
= linux_r
->xds
;
155 bsd_r
->r_es
= linux_r
->xes
;
156 bsd_r
->r_fs
= linux_r
->xfs
;
157 bsd_r
->r_gs
= linux_r
->xgs
;
158 bsd_r
->r_eip
= linux_r
->eip
;
159 bsd_r
->r_cs
= linux_r
->xcs
;
160 bsd_r
->r_eflags
= linux_r
->eflags
;
161 bsd_r
->r_esp
= linux_r
->esp
;
162 bsd_r
->r_ss
= linux_r
->xss
;
165 struct linux_pt_fpreg
{
173 l_long st_space
[2*10];
177 map_fpregs_to_linux(struct fpreg
*bsd_r
, struct linux_pt_fpreg
*linux_r
)
179 linux_r
->cwd
= bsd_r
->fpr_env
[0];
180 linux_r
->swd
= bsd_r
->fpr_env
[1];
181 linux_r
->twd
= bsd_r
->fpr_env
[2];
182 linux_r
->fip
= bsd_r
->fpr_env
[3];
183 linux_r
->fcs
= bsd_r
->fpr_env
[4];
184 linux_r
->foo
= bsd_r
->fpr_env
[5];
185 linux_r
->fos
= bsd_r
->fpr_env
[6];
186 bcopy(bsd_r
->fpr_acc
, linux_r
->st_space
, sizeof(linux_r
->st_space
));
190 map_fpregs_from_linux(struct fpreg
*bsd_r
, struct linux_pt_fpreg
*linux_r
)
192 bsd_r
->fpr_env
[0] = linux_r
->cwd
;
193 bsd_r
->fpr_env
[1] = linux_r
->swd
;
194 bsd_r
->fpr_env
[2] = linux_r
->twd
;
195 bsd_r
->fpr_env
[3] = linux_r
->fip
;
196 bsd_r
->fpr_env
[4] = linux_r
->fcs
;
197 bsd_r
->fpr_env
[5] = linux_r
->foo
;
198 bsd_r
->fpr_env
[6] = linux_r
->fos
;
199 bcopy(bsd_r
->fpr_acc
, linux_r
->st_space
, sizeof(bsd_r
->fpr_acc
));
202 struct linux_pt_fpxreg
{
214 l_long xmm_space
[32];
218 #ifndef CPU_DISABLE_SSE
220 linux_proc_read_fpxregs(struct lwp
*lp
, struct linux_pt_fpxreg
*fpxregs
)
228 bcopy(&lp
->lwp_thread
->td_pcb
->pcb_save
.sv_xmm
,
229 fpxregs
, sizeof(*fpxregs
));
234 linux_proc_write_fpxregs(struct lwp
*lp
, struct linux_pt_fpxreg
*fpxregs
)
242 bcopy(fpxregs
, &lp
->lwp_thread
->td_pcb
->pcb_save
.sv_xmm
,
252 sys_linux_ptrace(struct linux_ptrace_args
*uap
)
254 struct thread
*td
= curthread
;
255 struct proc
*curp
= td
->td_proc
;
257 struct linux_pt_reg reg
;
258 struct linux_pt_fpreg fpreg
;
259 struct linux_pt_fpxreg fpxreg
;
263 struct fpreg bsd_fpreg
;
264 struct dbreg bsd_dbreg
;
269 struct proc
*p
= NULL
; /* held process */
273 /* by default, just copy data intact */
275 pid
= (pid_t
)uap
->pid
;
276 addr
= (void *)uap
->addr
;
280 case PTRACE_POKETEXT
:
281 case PTRACE_POKEDATA
:
283 error
= kern_ptrace(curp
, req
, pid
, addr
, uap
->data
,
284 &uap
->sysmsg_iresult
);
286 case PTRACE_PEEKTEXT
:
287 case PTRACE_PEEKDATA
: {
288 /* need to preserve return value, use dummy */
290 error
= kern_ptrace(curp
, req
, pid
, addr
, 0, &rval
);
292 error
= copyout(&rval
, (caddr_t
)uap
->data
, sizeof(l_int
));
297 error
= kern_ptrace(curp
, PT_DETACH
, pid
, (void *)1,
298 map_signum(uap
->data
),
299 &uap
->sysmsg_iresult
);
301 case PTRACE_SINGLESTEP
:
303 error
= kern_ptrace(curp
, req
, pid
, (void *)1,
304 map_signum(uap
->data
),
305 &uap
->sysmsg_iresult
);
308 error
= kern_ptrace(curp
, PT_ATTACH
, pid
, addr
, uap
->data
,
309 &uap
->sysmsg_iresult
);
312 /* Linux is using data where FreeBSD is using addr */
313 error
= kern_ptrace(curp
, PT_GETREGS
, pid
, &u
.bsd_reg
, 0,
314 &uap
->sysmsg_iresult
);
316 map_regs_to_linux(&u
.bsd_reg
, &r
.reg
);
317 error
= copyout(&r
.reg
, (void *)uap
->data
,
322 /* Linux is using data where FreeBSD is using addr */
323 error
= copyin((caddr_t
)uap
->data
, &r
.reg
, sizeof(r
.reg
));
325 map_regs_from_linux(&u
.bsd_reg
, &r
.reg
);
326 error
= kern_ptrace(curp
, PT_SETREGS
, pid
, &u
.bsd_reg
,
327 0, &uap
->sysmsg_iresult
);
330 case PTRACE_GETFPREGS
:
331 /* Linux is using data where FreeBSD is using addr */
332 error
= kern_ptrace(curp
, PT_GETFPREGS
, pid
, &u
.bsd_fpreg
,
333 0, &uap
->sysmsg_iresult
);
335 map_fpregs_to_linux(&u
.bsd_fpreg
, &r
.fpreg
);
336 error
= copyout(&r
.fpreg
, (caddr_t
)uap
->data
,
340 case PTRACE_SETFPREGS
:
341 /* Linux is using data where FreeBSD is using addr */
342 error
= copyin((caddr_t
)uap
->data
, &r
.fpreg
, sizeof(r
.fpreg
));
344 map_fpregs_from_linux(&u
.bsd_fpreg
, &r
.fpreg
);
345 error
= kern_ptrace(curp
, PT_SETFPREGS
, pid
,
347 0, &uap
->sysmsg_iresult
);
350 case PTRACE_SETFPXREGS
:
351 #ifndef CPU_DISABLE_SSE
352 error
= copyin((caddr_t
)uap
->data
, &r
.fpxreg
,
358 case PTRACE_GETFPXREGS
: {
359 #ifndef CPU_DISABLE_SSE
363 if (sizeof(struct linux_pt_fpxreg
) != sizeof(struct savexmm
)) {
366 kprintf("linux: savexmm != linux_pt_fpxreg\n");
373 if ((p
= pfind(uap
->pid
)) == NULL
) {
378 if (!PRISON_CHECK(curp
->p_ucred
, p
->p_ucred
)) {
383 /* System processes can't be debugged. */
384 if ((p
->p_flags
& P_SYSTEM
) != 0) {
389 /* not being traced... */
390 if ((p
->p_flags
& P_TRACED
) == 0) {
395 /* not being traced by YOU */
396 if (p
->p_pptr
!= curp
) {
401 /* not currently stopped */
402 if ((p
->p_flags
& (P_TRACED
|P_WAITED
)) == 0) {
408 lp
= FIRST_LWP_IN_PROC(p
);
410 if (req
== PTRACE_GETFPXREGS
) {
412 error
= linux_proc_read_fpxregs(lp
, &r
.fpxreg
);
415 error
= copyout(&r
.fpxreg
, (caddr_t
)uap
->data
,
418 /* clear dangerous bits exactly as Linux does*/
419 r
.fpxreg
.mxcsr
&= 0xffbf;
421 error
= linux_proc_write_fpxregs(lp
, &r
.fpxreg
);
433 case PTRACE_POKEUSR
: {
436 /* check addr for alignment */
437 if (uap
->addr
< 0 || uap
->addr
& (sizeof(l_int
) - 1))
440 * Allow linux programs to access register values in
441 * user struct. We simulate this through PT_GET/SETREGS
444 if (uap
->addr
< sizeof(struct linux_pt_reg
)) {
445 error
= kern_ptrace(curp
, PT_GETREGS
, pid
, &u
.bsd_reg
,
446 0, &uap
->sysmsg_iresult
);
450 map_regs_to_linux(&u
.bsd_reg
, &r
.reg
);
451 if (req
== PTRACE_PEEKUSR
) {
452 error
= copyout((char *)&r
.reg
+ uap
->addr
,
453 (caddr_t
)uap
->data
, sizeof(l_int
));
457 *(l_int
*)((char *)&r
.reg
+ uap
->addr
) =
460 map_regs_from_linux(&u
.bsd_reg
, &r
.reg
);
461 error
= kern_ptrace(curp
, PT_SETREGS
, pid
, &u
.bsd_reg
,
462 0, &uap
->sysmsg_iresult
);
466 * Simulate debug registers access
468 if (uap
->addr
>= LINUX_DBREG_OFFSET
&&
469 uap
->addr
<= LINUX_DBREG_OFFSET
+ LINUX_DBREG_SIZE
) {
470 error
= kern_ptrace(curp
, PT_GETDBREGS
, pid
,
472 0, &uap
->sysmsg_iresult
);
476 uap
->addr
-= LINUX_DBREG_OFFSET
;
477 if (req
== PTRACE_PEEKUSR
) {
478 error
= copyout((char *)&u
.bsd_dbreg
+
479 uap
->addr
, (caddr_t
)uap
->data
,
484 *(l_int
*)((char *)&u
.bsd_dbreg
+ uap
->addr
) =
486 error
= kern_ptrace(curp
, PT_SETDBREGS
, pid
,
488 0, &uap
->sysmsg_iresult
);
496 kprintf("linux: ptrace(%u, ...) not implemented\n",
497 (unsigned int)uap
->req
);
503 * Release held proces (if any) before returning.