1 /* $NetBSD: linux_ptrace.c,v 1.23 2008/12/17 20:51:33 cegger Exp $ */
4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: linux_ptrace.c,v 1.23 2008/12/17 20:51:33 cegger Exp $");
35 #include <sys/param.h>
36 #include <sys/malloc.h>
37 #include <sys/mount.h>
39 #include <sys/ptrace.h>
40 #include <sys/systm.h>
41 #include <sys/syscall.h>
42 #include <sys/syscallargs.h>
43 #include <uvm/uvm_extern.h>
45 #include <machine/reg.h>
47 #include <compat/linux/common/linux_types.h>
48 #include <compat/linux/common/linux_ptrace.h>
49 #include <compat/linux/common/linux_signal.h>
51 #include <compat/linux/common/linux_util.h>
52 #include <compat/linux/common/linux_machdep.h>
53 #include <compat/linux/common/linux_emuldata.h>
54 #include <compat/linux/common/linux_exec.h> /* for emul_linux */
56 #include <compat/linux/linux_syscallargs.h>
58 #include <lib/libkern/libkern.h> /* for offsetof() */
68 long xds
, xes
; /* unsigned short ds, __ds, es, __es; */
69 long __fs
, __gs
; /* unsigned short fs, __fs, gs, __gs; */
72 long xcs
; /* unsigned short cs, __cs; */
75 long xss
; /* unsigned short ss, __ss; */
78 /* structure used for storing floating point context */
90 /* user struct for linux process - this is used for Linux ptrace emulation */
91 /* most of it is junk only used by gdb */
93 struct linux_reg regs
; /* registers */
94 int u_fpvalid
; /* true if math co-processor being used. */
95 struct linux_fpctx i387
; /* Math Co-processor registers. */
96 /* The rest of this junk is to help gdb figure out what goes where */
97 #define lusr_startgdb u_tsize
98 unsigned long int u_tsize
; /* Text segment size (pages). */
99 unsigned long int u_dsize
; /* Data segment size (pages). */
100 unsigned long int u_ssize
; /* Stack segment size (pages). */
101 unsigned long start_code
; /* Starting virtual address of text. */
102 unsigned long start_stack
; /* Starting virtual address of stack
103 area. This is actually the bottom of
104 the stack, the top of the stack is
105 always found in the esp register. */
106 long int __signal
; /* Signal that caused the core dump. */
107 int __reserved
; /* unused */
108 void *u_ar0
; /* Used by gdb to help find the values
109 for the registers. */
110 struct linux_fpctx
*u_fpstate
; /* Math Co-processor pointer. */
111 unsigned long __magic
; /* To uniquely identify a core file */
112 char u_comm
[32]; /* User command that was responsible */
114 #define u_debugreg_end u_debugreg[7]
117 #define LUSR_OFF(member) offsetof(struct linux_user, member)
118 #define ISSET(t, f) ((t) & (f))
120 int linux_ptrace_disabled
= 1; /* bitrotted */
123 linux_sys_ptrace_arch(struct lwp
*l
, const struct linux_sys_ptrace_args
*uap
, register_t
*retval
)
126 syscallarg(int) request;
128 syscallarg(int) addr;
129 syscallarg(int) data;
131 struct proc
*p
= l
->l_proc
;
133 struct proc
*t
; /* target process */
135 struct reg
*regs
= NULL
;
136 struct fpreg
*fpregs
= NULL
;
137 struct linux_reg
*linux_regs
= NULL
;
138 struct linux_fpctx
*linux_fpregs
= NULL
;
141 if (linux_ptrace_disabled
)
144 request
= SCARG(uap
, request
);
146 if ((request
!= LINUX_PTRACE_PEEKUSR
) &&
147 (request
!= LINUX_PTRACE_POKEUSR
) &&
148 (request
!= LINUX_PTRACE_GETREGS
) &&
149 (request
!= LINUX_PTRACE_SETREGS
) &&
150 (request
!= LINUX_PTRACE_GETFPREGS
) &&
151 (request
!= LINUX_PTRACE_SETFPREGS
))
156 /* Find the process we're supposed to be operating on. */
157 if ((t
= pfind(SCARG(uap
, pid
))) == NULL
)
161 * You can't do what you want to the process if:
162 * (1) It's not being traced at all,
164 if (!ISSET(t
->p_slflag
, PSL_TRACED
))
168 * (2) it's being traced by procfs (which has
169 * different signal delivery semantics),
171 if (ISSET(t
->p_slflag
, PSL_FSTRACE
))
175 * (3) it's not being traced by _you_, or
181 * (4) it's not currently stopped.
183 if (t
->p_stat
!= SSTOP
|| !t
->p_waited
/* XXXSMP */)
187 * The entire ptrace interface needs work to be useful to
188 * a process with multiple LWPs. For the moment, we'll
189 * just kluge this and fail on others.
195 lt
= LIST_FIRST(&t
->p_lwps
);
200 case LINUX_PTRACE_GETREGS
:
201 regs
= malloc(sizeof(struct reg
), M_TEMP
, M_WAITOK
);
202 linux_regs
= malloc(sizeof(struct linux_reg
), M_TEMP
, M_WAITOK
);
204 error
= process_read_regs(lt
, regs
);
208 linux_regs
->ebx
= regs
->r_ebx
;
209 linux_regs
->ecx
= regs
->r_ecx
;
210 linux_regs
->edx
= regs
->r_edx
;
211 linux_regs
->esi
= regs
->r_esi
;
212 linux_regs
->edi
= regs
->r_edi
;
213 linux_regs
->ebp
= regs
->r_ebp
;
214 linux_regs
->eax
= regs
->r_eax
;
215 linux_regs
->xds
= regs
->r_ds
;
216 linux_regs
->xes
= regs
->r_es
;
217 linux_regs
->orig_eax
= regs
->r_eax
; /* XXX is this correct? */
218 linux_regs
->eip
= regs
->r_cs
+ regs
->r_eip
;
219 linux_regs
->xcs
= regs
->r_cs
;
220 linux_regs
->eflags
= regs
->r_eflags
;
221 linux_regs
->esp
= regs
->r_esp
;
222 linux_regs
->xss
= regs
->r_ss
;
224 error
= copyout(linux_regs
, (void *)SCARG(uap
, data
),
225 sizeof(struct linux_reg
));
228 case LINUX_PTRACE_SETREGS
:
229 regs
= malloc(sizeof(struct reg
), M_TEMP
, M_WAITOK
);
230 linux_regs
= malloc(sizeof(struct linux_reg
),
233 error
= copyin((void *)SCARG(uap
, data
), linux_regs
,
234 sizeof(struct linux_reg
));
238 regs
->r_ebx
= linux_regs
->ebx
;
239 regs
->r_ecx
= linux_regs
->ecx
;
240 regs
->r_edx
= linux_regs
->edx
;
241 regs
->r_esi
= linux_regs
->esi
;
242 regs
->r_edi
= linux_regs
->edi
;
243 regs
->r_ebp
= linux_regs
->ebp
;
244 regs
->r_eax
= linux_regs
->eax
;
245 regs
->r_ds
= linux_regs
->xds
;
246 regs
->r_es
= linux_regs
->xes
;
247 regs
->r_eip
= linux_regs
->eip
- linux_regs
->xcs
;
248 regs
->r_cs
= linux_regs
->xcs
;
249 regs
->r_eflags
= linux_regs
->eflags
;
250 regs
->r_esp
= linux_regs
->esp
;
251 regs
->r_ss
= linux_regs
->xss
;
253 error
= process_write_regs(lt
, regs
);
256 case LINUX_PTRACE_GETFPREGS
:
257 fpregs
= malloc(sizeof(struct fpreg
),
259 linux_fpregs
= malloc(sizeof(struct linux_fpctx
),
262 error
= process_read_fpregs(lt
, fpregs
);
266 /* zero the contents if NetBSD fpreg structure is smaller */
267 if (sizeof(struct fpreg
) < sizeof(struct linux_fpctx
))
268 memset(linux_fpregs
, '\0', sizeof(struct linux_fpctx
));
270 memcpy(linux_fpregs
, fpregs
,
271 min(sizeof(struct linux_fpctx
), sizeof(struct fpreg
)));
272 error
= copyout(linux_fpregs
, (void *)SCARG(uap
, data
),
273 sizeof(struct linux_fpctx
));
276 case LINUX_PTRACE_SETFPREGS
:
277 fpregs
= malloc(sizeof(struct fpreg
), M_TEMP
, M_WAITOK
);
278 linux_fpregs
= malloc(sizeof(struct linux_fpctx
),
280 error
= copyin((void *)SCARG(uap
, data
), linux_fpregs
,
281 sizeof(struct linux_fpctx
));
285 memset(fpregs
, '\0', sizeof(struct fpreg
));
286 memcpy(fpregs
, linux_fpregs
,
287 min(sizeof(struct linux_fpctx
), sizeof(struct fpreg
)));
289 error
= process_write_regs(lt
, regs
);
292 case LINUX_PTRACE_PEEKUSR
:
293 addr
= SCARG(uap
, addr
);
296 if (addr
< LUSR_OFF(lusr_startgdb
)) {
297 /* XXX should provide appropriate register */
299 } else if (addr
== LUSR_OFF(u_tsize
))
300 *retval
= p
->p_vmspace
->vm_tsize
;
301 else if (addr
== LUSR_OFF(u_dsize
))
302 *retval
= p
->p_vmspace
->vm_dsize
;
303 else if (addr
== LUSR_OFF(u_ssize
))
304 *retval
= p
->p_vmspace
->vm_ssize
;
305 else if (addr
== LUSR_OFF(start_code
))
306 *retval
= (register_t
) p
->p_vmspace
->vm_taddr
;
307 else if (addr
== LUSR_OFF(start_stack
))
308 *retval
= (register_t
) p
->p_vmspace
->vm_minsaddr
;
309 else if (addr
== LUSR_OFF(u_ar0
))
310 *retval
= LUSR_OFF(regs
);
311 else if (addr
>= LUSR_OFF(u_debugreg
)
312 && addr
<= LUSR_OFF(u_debugreg_end
)) {
313 int off
= (addr
- LUSR_OFF(u_debugreg
)) / sizeof(int);
315 /* only do this for Linux processes */
316 if (t
->p_emul
!= &emul_linux
)
319 *retval
= ((struct linux_emuldata
*)
320 t
->p_emuldata
)->debugreg
[off
];
322 } else if (addr
== LUSR_OFF(__signal
)) {
324 } else if (addr
== LUSR_OFF(__signal
)) {
326 } else if (addr
== LUSR_OFF(u_fpstate
)) {
328 } else if (addr
== LUSR_OFF(__magic
)) {
330 } else if (addr
== LUSR_OFF(u_comm
)) {
334 printf("linux_ptrace: unsupported address: %d\n", addr
);
341 case LINUX_PTRACE_POKEUSR
:
342 /* we only support setting debugregs for now */
343 addr
= SCARG(uap
, addr
);
344 if (addr
>= LUSR_OFF(u_debugreg
)
345 && addr
<= LUSR_OFF(u_debugreg_end
)) {
346 int off
= (addr
- LUSR_OFF(u_debugreg
)) / sizeof(int);
347 int data
= SCARG(uap
, data
);
349 /* only do this for Linux processes */
350 if (t
->p_emul
!= &emul_linux
)
353 ((struct linux_emuldata
*)t
->p_emuldata
)->debugreg
[off
] = data
;
369 free(fpregs
, M_TEMP
);
371 free(linux_regs
, M_TEMP
);
373 free(linux_fpregs
, M_TEMP
);