1 /* $NetBSD: linux_ptrace.c,v 1.21 2008/12/17 20:51:33 cegger Exp $ */
4 * Copyright (c) 1999, 2001 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matthias Scheler and Emmanuel Dreyfus.
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.21 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/syscallargs.h>
42 #include <uvm/uvm_extern.h>
44 #include <machine/reg.h>
46 #include <compat/linux/common/linux_types.h>
47 #include <compat/linux/common/linux_ptrace.h>
48 #include <compat/linux/common/linux_signal.h>
50 #include <compat/linux/common/linux_util.h>
51 #include <compat/linux/common/linux_machdep.h>
52 #include <compat/linux/common/linux_emuldata.h>
53 #include <compat/linux/common/linux_exec.h> /* for emul_linux */
55 #include <compat/linux/linux_syscallargs.h>
57 #include <lib/libkern/libkern.h> /* for offsetof() */
60 * From Linux's include/asm-ppc/ptrace.h.
61 * structure used for storing reg context: defined in linux_machdep.h
62 * structure used for storing floating point context:
63 * Linux just uses a double fpr[32], no struct
67 * user struct for linux process - this is used for Linux ptrace emulation
68 * most of it is junk only used by gdb
70 * From Linux's include/asm-ppc/user.h
72 * XXX u_ar0 was a struct reg in Linux/powerpc
73 * Can't find out what a struct regs is for Linux/powerpc,
74 * so we use a struct pt_regs instead. don't know if this is right.
78 struct linux_pt_regs regs
;
79 #define lusr_startgdb regs
83 unsigned long start_code
;
84 unsigned long start_data
;
85 unsigned long start_stack
;
87 struct linux_pt_regs
*u_ar0
; /* help gdb find registers */
90 #define lu_comm_end u_comm[31]
93 #define LUSR_OFF(member) offsetof(struct linux_user, member)
94 #define LUSR_REG_OFF(member) offsetof(struct linux_pt_regs, member)
95 #define ISSET(t, f) ((t) & (f))
97 int linux_ptrace_disabled
= 1; /* bitrotted */
99 /* XXX Check me! (From NetBSD/i386) */
101 linux_sys_ptrace_arch(struct lwp
*l
, const struct linux_sys_ptrace_args
*uap
, register_t
*retval
)
104 syscallarg(int) request;
106 syscallarg(int) addr;
107 syscallarg(int) data;
110 struct proc
*p
= l
->l_proc
;
111 struct proc
*t
; /* target process */
113 struct reg
*regs
= NULL
;
114 struct fpreg
*fpregs
= NULL
;
115 struct linux_pt_regs
*linux_regs
= NULL
;
116 double *linux_fpreg
= NULL
; /* it's an array, not a struct */
120 if (linux_ptrace_disabled
)
123 switch (request
= SCARG(uap
, request
)) {
124 case LINUX_PTRACE_PEEKUSR
:
125 case LINUX_PTRACE_POKEUSR
:
126 case LINUX_PTRACE_GETREGS
:
127 case LINUX_PTRACE_SETREGS
:
128 case LINUX_PTRACE_GETFPREGS
:
129 case LINUX_PTRACE_SETFPREGS
:
135 /* Find the process we're supposed to be operating on. */
136 if ((t
= pfind(SCARG(uap
, pid
))) == NULL
)
140 * You can't do what you want to the process if:
141 * (1) It's not being traced at all,
143 if (!ISSET(t
->p_slflag
, PSL_TRACED
)) /* XXXSMP */
147 * (2) it's being traced by procfs (which has
148 * different signal delivery semantics),
150 if (ISSET(t
->p_slflag
, PSL_FSTRACE
))
154 * (3) it's not being traced by _you_, or
160 * (4) it's not currently stopped.
162 if (t
->p_stat
!= SSTOP
|| !t
->p_waited
)
165 lt
= LIST_FIRST(&t
->p_lwps
);
169 case LINUX_PTRACE_GETREGS
:
170 regs
= malloc(sizeof(struct reg
), M_TEMP
, M_WAITOK
);
171 linux_regs
= malloc(sizeof(*linux_regs
), M_TEMP
, M_WAITOK
);
173 error
= process_read_regs(lt
, regs
);
177 for (i
=0; i
<=31; i
++)
178 linux_regs
->lgpr
[i
] = regs
->fixreg
[i
];
179 linux_regs
->lnip
= regs
->pc
;
180 linux_regs
->lmsr
= 0;
181 /* XXX Is that right? */
182 linux_regs
->lorig_gpr3
= regs
->fixreg
[3];
183 linux_regs
->lctr
= regs
->ctr
;
184 linux_regs
->llink
= regs
->lr
;
185 linux_regs
->lxer
= regs
->xer
;
186 linux_regs
->lccr
= regs
->cr
;
188 linux_regs
->ltrap
= 0;
189 linux_regs
->ldar
= 0;
190 linux_regs
->ldsisr
= 0;
191 linux_regs
->lresult
= 0;
193 error
= copyout(linux_regs
, (void *)SCARG(uap
, data
),
194 sizeof(struct linux_pt_regs
));
197 case LINUX_PTRACE_SETREGS
:
198 regs
= malloc(sizeof(struct reg
), M_TEMP
, M_WAITOK
);
199 linux_regs
= malloc(sizeof(*linux_regs
), M_TEMP
, M_WAITOK
);
201 error
= copyin((void *)SCARG(uap
, data
), linux_regs
,
202 sizeof(struct linux_pt_regs
));
206 for (i
=0; i
<=31; i
++)
207 regs
->fixreg
[i
] = linux_regs
->lgpr
[i
];
208 regs
->lr
= linux_regs
->llink
;
209 regs
->cr
= linux_regs
->lccr
;
210 regs
->xer
= linux_regs
->lxer
;
211 regs
->ctr
= linux_regs
->lctr
;
212 regs
->pc
= linux_regs
->lnip
; /* XXX */
214 error
= process_write_regs(lt
, regs
);
217 case LINUX_PTRACE_GETFPREGS
:
218 fpregs
= malloc(sizeof(struct fpreg
), M_TEMP
, M_WAITOK
);
219 linux_fpreg
= malloc(32*sizeof(double), M_TEMP
, M_WAITOK
);
221 error
= process_read_fpregs(lt
, fpregs
);
225 /* zero the contents if NetBSD fpreg structure is smaller */
226 if (sizeof(struct fpreg
) < (32*sizeof(double)))
227 memset(linux_fpreg
, '\0', (32*sizeof(double)));
229 memcpy(linux_fpreg
, fpregs
,
230 min(32*sizeof(double), sizeof(struct fpreg
)));
231 error
= copyout(linux_fpreg
, (void *)SCARG(uap
, data
),
235 case LINUX_PTRACE_SETFPREGS
:
236 fpregs
= malloc(sizeof(struct fpreg
), M_TEMP
, M_WAITOK
);
237 linux_fpreg
= malloc(32*sizeof(double), M_TEMP
, M_WAITOK
);
238 error
= copyin((void *)SCARG(uap
, data
), linux_fpreg
,
243 memset(fpregs
, '\0', sizeof(struct fpreg
));
244 memcpy(fpregs
, linux_fpreg
,
245 min(32*sizeof(double), sizeof(struct fpreg
)));
247 error
= process_write_fpregs(lt
, fpregs
);
250 case LINUX_PTRACE_PEEKUSR
:
251 addr
= SCARG(uap
, addr
);
252 regs
= malloc(sizeof(struct reg
), M_TEMP
, M_WAITOK
);
253 error
= process_read_regs(lt
, regs
);
258 if ((addr
< LUSR_OFF(lusr_startgdb
)) ||
259 (addr
> LUSR_OFF(lu_comm_end
)))
261 else if (addr
== LUSR_OFF(u_tsize
))
262 *retval
= p
->p_vmspace
->vm_tsize
;
263 else if (addr
== LUSR_OFF(u_dsize
))
264 *retval
= p
->p_vmspace
->vm_dsize
;
265 else if (addr
== LUSR_OFF(u_ssize
))
266 *retval
= p
->p_vmspace
->vm_ssize
;
267 else if (addr
== LUSR_OFF(start_code
))
268 *retval
= (register_t
) p
->p_vmspace
->vm_taddr
;
269 else if (addr
== LUSR_OFF(start_stack
))
270 *retval
= (register_t
) p
->p_vmspace
->vm_minsaddr
;
271 else if ((addr
>= LUSR_REG_OFF(lpt_regs_fixreg_begin
)) &&
272 (addr
<= LUSR_REG_OFF(lpt_regs_fixreg_end
)))
273 *retval
= regs
->fixreg
[addr
/ sizeof (register_t
)];
274 else if (addr
== LUSR_REG_OFF(lnip
))
276 else if (addr
== LUSR_REG_OFF(lctr
))
278 else if (addr
== LUSR_REG_OFF(llink
))
280 else if (addr
== LUSR_REG_OFF(lxer
))
282 else if (addr
== LUSR_REG_OFF(lccr
))
284 else if (addr
== LUSR_OFF(signal
))
286 else if (addr
== LUSR_OFF(signal
))
288 else if (addr
== LUSR_OFF(magic
))
290 else if (addr
== LUSR_OFF(u_comm
))
294 printf("linux_ptrace: unsupported address: %d\n", addr
);
302 error
= copyout (retval
,
303 (void *)SCARG(uap
, data
), sizeof retval
);
304 *retval
= SCARG(uap
, data
);
310 case LINUX_PTRACE_POKEUSR
: /* XXX Not tested */
311 addr
= SCARG(uap
, addr
);
312 regs
= malloc(sizeof(struct reg
), M_TEMP
, M_WAITOK
);
313 error
= process_read_regs(lt
, regs
);
318 if ((addr
< LUSR_OFF(lusr_startgdb
)) ||
319 (addr
> LUSR_OFF(lu_comm_end
)))
321 else if (addr
== LUSR_OFF(u_tsize
))
323 else if (addr
== LUSR_OFF(u_dsize
))
325 else if (addr
== LUSR_OFF(u_ssize
))
327 else if (addr
== LUSR_OFF(start_code
))
329 else if (addr
== LUSR_OFF(start_stack
))
331 else if ((addr
>= LUSR_REG_OFF(lpt_regs_fixreg_begin
)) &&
332 (addr
<= LUSR_REG_OFF(lpt_regs_fixreg_end
)))
333 regs
->fixreg
[addr
/ sizeof (register_t
)] =
334 (register_t
)SCARG(uap
, data
);
335 else if (addr
== LUSR_REG_OFF(lnip
))
336 regs
->pc
= (register_t
)SCARG(uap
, data
);
337 else if (addr
== LUSR_REG_OFF(lctr
))
338 regs
->ctr
= (register_t
)SCARG(uap
, data
);
339 else if (addr
== LUSR_REG_OFF(llink
))
340 regs
->lr
= (register_t
)SCARG(uap
, data
);
341 else if (addr
== LUSR_REG_OFF(lxer
))
342 regs
->xer
= (register_t
)SCARG(uap
, data
);
343 else if (addr
== LUSR_REG_OFF(lccr
))
344 regs
->cr
= (register_t
)SCARG(uap
, data
);
345 else if (addr
== LUSR_OFF(signal
))
347 else if (addr
== LUSR_OFF(magic
))
349 else if (addr
== LUSR_OFF(u_comm
))
353 printf("linux_ptrace: unsupported address: %d\n", addr
);
358 error
= process_write_regs(lt
,regs
);
373 free(fpregs
, M_TEMP
);
375 free(linux_regs
, M_TEMP
);
377 free(linux_fpreg
, M_TEMP
);