linux_ptrace.c revision 1.1 1 /* $NetBSD: linux_ptrace.c,v 1.1 2001/01/19 01:36:51 manu Exp $ */
2
3 /*-
4 * Copyright (c) 1999, 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matthias Scheler and Emmanuel Dreyfus.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Function linux_sys_ptrace_arch() is taken from NetBSD/i386
41 * with some stuff deleted to get it compiling. It is not expected to
42 * work, and it should be checked with care or re-writen.
43 */
44
45 #include <sys/types.h>
46 #include <sys/param.h>
47 #include <sys/malloc.h>
48 #include <sys/mount.h>
49 #include <sys/proc.h>
50 #include <sys/ptrace.h>
51 #include <sys/systm.h>
52 #include <sys/syscallargs.h>
53 #include <uvm/uvm_extern.h>
54
55 #include <machine/reg.h>
56
57 #include <compat/linux/common/linux_types.h>
58 #include <compat/linux/common/linux_ptrace.h>
59 #include <compat/linux/common/linux_signal.h>
60
61 #include <compat/linux/common/linux_util.h>
62 #include <compat/linux/common/linux_machdep.h>
63 #include <compat/linux/common/linux_emuldata.h>
64 #include <compat/linux/common/linux_exec.h> /* for emul_linux */
65
66 #include <compat/linux/linux_syscallargs.h>
67
68 #include <lib/libkern/libkern.h> /* for offsetof() */
69
70 /*
71 * From Linux's include/asm-ppc/ptrace.h.
72 * structure used for storing reg context: defined in linux_machdep.h
73 * structure used for storing floating point context:
74 * Linux just uses a double fpr[32], no struct
75 */
76
77 /*
78 * user struct for linux process - this is used for Linux ptrace emulation
79 * most of it is junk only used by gdb
80 *
81 * From Linux's include/asm-ppc/user.h
82 *
83 * XXX u_ar0 was a struct reg in Linux/powerpc
84 * Can't find out what a struct regs is for Linux/powerpc,
85 * so we use a struct pt_regs instead. don't know if this is right.
86 */
87
88 struct linux_user {
89 struct linux_pt_regs regs;
90 size_t u_tsize;
91 size_t u_dsize;
92 size_t u_ssize;
93 unsigned long start_code;
94 unsigned long start_data;
95 unsigned long start_stack;
96 long int signal;
97 struct linux_pt_regs *u_ar0; /* help gdb find registers */
98 unsigned long magic;
99 char u_comm[32];
100 };
101
102 #define lusr_startgdb regs
103 #define LUSR_OFF(member) offsetof(struct linux_user, member)
104 #define ISSET(t, f) ((t) & (f))
105
106 int
107 linux_sys_ptrace_arch(p, v, retval) /* XXX Check me! (From NetBSD/i386) */
108 struct proc *p;
109 void *v;
110 register_t *retval;
111 {
112 struct linux_sys_ptrace_args /* {
113 syscallarg(int) request;
114 syscallarg(int) pid;
115 syscallarg(int) addr;
116 syscallarg(int) data;
117 } */ *uap = v;
118 int request, error;
119 struct proc *t; /* target process */
120 struct reg *regs = NULL;
121 struct fpreg *fpregs = NULL;
122 struct linux_pt_regs *linux_regs = NULL;
123 double *linux_fpreg=NULL; /* it's an array, not a struct */
124 int addr;
125 int i;
126
127 request = SCARG(uap, request);
128
129 if ((request != LINUX_PTRACE_PEEKUSR) &&
130 (request != LINUX_PTRACE_POKEUSR) &&
131 (request != LINUX_PTRACE_GETREGS) &&
132 (request != LINUX_PTRACE_SETREGS) &&
133 (request != LINUX_PTRACE_GETFPREGS) &&
134 (request != LINUX_PTRACE_SETFPREGS))
135 return EIO;
136
137 /* Find the process we're supposed to be operating on. */
138 if ((t = pfind(SCARG(uap, pid))) == NULL)
139 return ESRCH;
140
141 /*
142 * You can't do what you want to the process if:
143 * (1) It's not being traced at all,
144 */
145 if (!ISSET(t->p_flag, P_TRACED))
146 return EPERM;
147
148 /*
149 * (2) it's being traced by procfs (which has
150 * different signal delivery semantics),
151 */
152 if (ISSET(t->p_flag, P_FSTRACE))
153 return EBUSY;
154
155 /*
156 * (3) it's not being traced by _you_, or
157 */
158 if (t->p_pptr != p)
159 return EBUSY;
160
161 /*
162 * (4) it's not currently stopped.
163 */
164 if (t->p_stat != SSTOP || !ISSET(t->p_flag, P_WAITED))
165 return EBUSY;
166
167 *retval = 0;
168
169 switch (request) {
170 case LINUX_PTRACE_GETREGS:
171 MALLOC(regs, struct reg*, sizeof(struct reg), M_TEMP, M_WAITOK);
172 MALLOC(linux_regs, struct linux_pt_regs*, sizeof(struct linux_pt_regs),
173 M_TEMP, M_WAITOK);
174
175 error = process_read_regs(t, regs);
176 if (error != 0)
177 goto out;
178
179 for (i=0; i<=31; i++)
180 linux_regs->lgpr[i] = regs->fixreg[i];
181 linux_regs->lnip = regs->pc;
182 linux_regs->lmsr = 0;
183 linux_regs->lorig_gpr3 = regs->fixreg[3]; /* XXX Is that right? */
184 linux_regs->lctr = regs->ctr;
185 linux_regs->llink = regs->lr;
186 linux_regs->lxer = regs->xer;
187 linux_regs->lccr = regs->cr;
188 linux_regs->lmq = 0;
189 linux_regs->ltrap = 0;
190 linux_regs->ldar = 0;
191 linux_regs->ldsisr = 0;
192 linux_regs->lresult = 0;
193
194 error = copyout(linux_regs, (caddr_t)SCARG(uap, data),
195 sizeof(struct linux_pt_regs));
196 goto out;
197
198 case LINUX_PTRACE_SETREGS:
199 MALLOC(regs, struct reg*, sizeof(struct reg), M_TEMP, M_WAITOK);
200 MALLOC(linux_regs, struct linux_pt_regs*, sizeof(struct linux_pt_regs),
201 M_TEMP, M_WAITOK);
202
203 error = copyin((caddr_t)SCARG(uap, data), linux_regs,
204 sizeof(struct linux_pt_regs));
205 if (error != 0)
206 goto out;
207
208 for (i=0; i<=31; i++)
209 regs->fixreg[i] = linux_regs->lgpr[i];
210 regs->lr = linux_regs->llink;
211 regs->cr = linux_regs->lccr;
212 regs->xer = linux_regs->lxer;
213 regs->ctr = linux_regs->lctr;
214 regs->pc = 0; /* XXX obviously this won't work ;o) */
215
216 error = process_write_regs(t, regs);
217 goto out;
218
219 case LINUX_PTRACE_GETFPREGS:
220 MALLOC(fpregs, struct fpreg *, sizeof(struct fpreg),
221 M_TEMP, M_WAITOK);
222 MALLOC(linux_fpreg, double *,
223 32*sizeof(double), M_TEMP, M_WAITOK);
224
225 error = process_read_fpregs(t, fpregs);
226 if (error != 0)
227 goto out;
228
229 /* zero the contents if NetBSD fpreg structure is smaller */
230 if (sizeof(struct fpreg) < (32*sizeof(double)))
231 memset(linux_fpreg, '\0', (32*sizeof(double)));
232
233 memcpy(linux_fpreg, fpregs,
234 min(32*sizeof(double), sizeof(struct fpreg)));
235 error = copyout(linux_fpreg, (caddr_t)SCARG(uap, data),
236 32*sizeof(double));
237 goto out;
238
239 case LINUX_PTRACE_SETFPREGS:
240 MALLOC(fpregs, struct fpreg *, sizeof(struct fpreg),
241 M_TEMP, M_WAITOK);
242 MALLOC(linux_fpreg, double *,
243 32*sizeof(double), M_TEMP, M_WAITOK);
244 error = copyin((caddr_t)SCARG(uap, data), linux_fpreg,
245 32*sizeof(double));
246 if (error != 0)
247 goto out;
248
249 memset(fpregs, '\0', sizeof(struct fpreg));
250 memcpy(fpregs, linux_fpreg,
251 min(32*sizeof(double), sizeof(struct fpreg)));
252
253 error = process_write_regs(t, regs);
254 goto out;
255
256 case LINUX_PTRACE_PEEKUSR:
257 addr = SCARG(uap, addr);
258
259 PHOLD(t); /* need full process info */
260 error = 0;
261 if (addr < LUSR_OFF(lusr_startgdb)) {
262 error = 1;
263 } else if (addr == LUSR_OFF(u_tsize))
264 *retval = p->p_vmspace->vm_tsize;
265 else if (addr == LUSR_OFF(u_dsize))
266 *retval = p->p_vmspace->vm_dsize;
267 else if (addr == LUSR_OFF(u_ssize))
268 *retval = p->p_vmspace->vm_ssize;
269 else if (addr == LUSR_OFF(start_code))
270 *retval = (register_t) p->p_vmspace->vm_taddr;
271 else if (addr == LUSR_OFF(start_stack))
272 *retval = (register_t) p->p_vmspace->vm_minsaddr;
273 else if (addr == LUSR_OFF(u_ar0))
274 *retval = LUSR_OFF(regs);
275 else if (addr == LUSR_OFF(signal)) {
276 error = 1;
277 } else if (addr == LUSR_OFF(signal)) {
278 error = 1;
279 } else if (addr == LUSR_OFF(magic)) {
280 error = 1;
281 } else if (addr == LUSR_OFF(u_comm)) {
282 error = 1;
283 } else {
284 #ifdef DEBUG_LINUX
285 printf("linux_ptrace: unsupported address: %d\n", addr);
286 #endif
287 error = 1;
288 }
289
290 PRELE(t);
291
292 if (!error)
293 return 0;
294
295 case LINUX_PTRACE_POKEUSR:
296 /* XXX We don't do much yet... */
297 addr = SCARG(uap, addr);
298 break;
299 default:
300 /* never reached */
301 break;
302 }
303
304 return EIO;
305
306 out:
307 if (regs)
308 FREE(regs, M_TEMP);
309 if (fpregs)
310 FREE(fpregs, M_TEMP);
311 if (linux_regs)
312 FREE(linux_regs, M_TEMP);
313 if (linux_fpreg)
314 FREE(linux_fpreg, M_TEMP);
315 return (error);
316 }
317