1 /* $OpenBSD: process_machdep.c,v 1.13 2016/10/19 08:23:37 guenther Exp $ */
2 /* $NetBSD: process_machdep.c,v 1.7 1996/07/11 20:14:21 cgd Exp $ */
3
4 /*-
5 * Copyright (c) 1998 Doug Rabson
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29 /*
30 * Copyright (c) 1994 Christopher G. Demetriou
31 * All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 * must display the following acknowledgement:
43 * This product includes software developed by Christopher G. Demetriou.
44 * 4. The name of the author may not be used to endorse or promote products
45 * derived from this software without specific prior written permission
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
48 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
49 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
50 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
51 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
52 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
53 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
54 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
55 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
56 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57 */
58
59 /*
60 * This file may seem a bit stylized, but that so that it's easier to port.
61 * Functions to be implemented here are:
62 *
63 * process_read_regs(proc, regs)
64 * Get the current user-visible register set from the process
65 * and copy it into the regs structure (<machine/reg.h>).
66 * The process is stopped at the time read_regs is called.
67 *
68 * process_write_regs(proc, regs)
69 * Update the current register set from the passed in regs
70 * structure. Take care to avoid clobbering special CPU
71 * registers or privileged bits in the PSL.
72 * The process is stopped at the time write_regs is called.
73 *
74 * process_sstep(proc)
75 * Arrange for the process to trap after executing a single instruction.
76 *
77 * process_set_pc(proc)
78 * Set the process's program counter.
79 */
80
81 #include <sys/param.h>
82 #include <sys/systm.h>
83 #include <sys/kernel.h>
84 #include <sys/proc.h>
85 #include <sys/user.h>
86 #include <sys/vnode.h>
87 #include <sys/ptrace.h>
88 #include <machine/reg.h>
89 #include <machine/frame.h>
90
91 #include <alpha/alpha/db_instruction.h>
92
93 #define process_frame(p) ((p)->p_md.md_tf)
94 #define process_pcb(p) (&(p)->p_addr->u_pcb)
95 #define process_fpframe(p) (&(process_pcb(p)->pcb_fp))
96
97 int
process_read_regs(p,regs)98 process_read_regs(p, regs)
99 struct proc *p;
100 struct reg *regs;
101 {
102
103 frametoreg(process_frame(p), regs);
104 regs->r_regs[R_ZERO] = process_frame(p)->tf_regs[FRAME_PC];
105 regs->r_regs[R_SP] = process_pcb(p)->pcb_hw.apcb_usp;
106 return (0);
107 }
108
109 int
process_read_fpregs(p,regs)110 process_read_fpregs(p, regs)
111 struct proc *p;
112 struct fpreg *regs;
113 {
114
115 if (p->p_addr->u_pcb.pcb_fpcpu != NULL)
116 fpusave_proc(p, 1);
117
118 bcopy(process_fpframe(p), regs, sizeof(struct fpreg));
119 return (0);
120 }
121
122 #ifdef PTRACE
123
124 int
process_write_regs(p,regs)125 process_write_regs(p, regs)
126 struct proc *p;
127 struct reg *regs;
128 {
129
130 regtoframe(regs, process_frame(p));
131 process_frame(p)->tf_regs[FRAME_PC] = regs->r_regs[R_ZERO];
132 process_pcb(p)->pcb_hw.apcb_usp = regs->r_regs[R_SP];
133 return (0);
134 }
135
136 int
process_set_pc(p,addr)137 process_set_pc(p, addr)
138 struct proc *p;
139 caddr_t addr;
140 {
141 struct trapframe *frame = process_frame(p);
142
143 frame->tf_regs[FRAME_PC] = (u_int64_t)addr;
144 return (0);
145 }
146
147 int
process_write_fpregs(p,regs)148 process_write_fpregs(p, regs)
149 struct proc *p;
150 struct fpreg *regs;
151 {
152
153 if (p->p_addr->u_pcb.pcb_fpcpu != NULL)
154 fpusave_proc(p, 0);
155
156 bcopy(regs, process_fpframe(p), sizeof(struct fpreg));
157 return (0);
158 }
159
160 /*
161 * Single stepping infrastructure.
162 */
163 int ptrace_set_bpt(struct proc *p, struct mdbpt *bpt);
164 int ptrace_clear_bpt(struct proc *p, struct mdbpt *bpt);
165 int ptrace_read_int(struct proc *, vaddr_t, u_int32_t *);
166 int ptrace_write_int(struct proc *, vaddr_t, u_int32_t);
167 u_int64_t ptrace_read_register(struct proc *p, int regno);
168
169 int
ptrace_read_int(struct proc * p,vaddr_t addr,u_int32_t * v)170 ptrace_read_int(struct proc *p, vaddr_t addr, u_int32_t *v)
171 {
172 struct iovec iov;
173 struct uio uio;
174
175 iov.iov_base = (caddr_t) v;
176 iov.iov_len = sizeof(u_int32_t);
177 uio.uio_iov = &iov;
178 uio.uio_iovcnt = 1;
179 uio.uio_offset = (off_t)addr;
180 uio.uio_resid = sizeof(u_int32_t);
181 uio.uio_segflg = UIO_SYSSPACE;
182 uio.uio_rw = UIO_READ;
183 uio.uio_procp = curproc;
184 return process_domem(curproc, p->p_p, &uio, PT_READ_I);
185 }
186
187 int
ptrace_write_int(struct proc * p,vaddr_t addr,u_int32_t v)188 ptrace_write_int(struct proc *p, vaddr_t addr, u_int32_t v)
189 {
190 struct iovec iov;
191 struct uio uio;
192
193 iov.iov_base = (caddr_t) &v;
194 iov.iov_len = sizeof(u_int32_t);
195 uio.uio_iov = &iov;
196 uio.uio_iovcnt = 1;
197 uio.uio_offset = (off_t)addr;
198 uio.uio_resid = sizeof(u_int32_t);
199 uio.uio_segflg = UIO_SYSSPACE;
200 uio.uio_rw = UIO_WRITE;
201 uio.uio_procp = curproc;
202 return process_domem(curproc, p->p_p, &uio, PT_WRITE_I);
203 }
204
205 u_int64_t
ptrace_read_register(struct proc * p,int regno)206 ptrace_read_register(struct proc *p, int regno)
207 {
208 static int reg_to_frame[32] = {
209 FRAME_V0,
210 FRAME_T0,
211 FRAME_T1,
212 FRAME_T2,
213 FRAME_T3,
214 FRAME_T4,
215 FRAME_T5,
216 FRAME_T6,
217 FRAME_T7,
218
219 FRAME_S0,
220 FRAME_S1,
221 FRAME_S2,
222 FRAME_S3,
223 FRAME_S4,
224 FRAME_S5,
225 FRAME_S6,
226
227 FRAME_A0,
228 FRAME_A1,
229 FRAME_A2,
230 FRAME_A3,
231 FRAME_A4,
232 FRAME_A5,
233
234 FRAME_T8,
235 FRAME_T9,
236 FRAME_T10,
237 FRAME_T11,
238 FRAME_RA,
239 FRAME_T12,
240 FRAME_AT,
241 FRAME_GP,
242 FRAME_SP,
243 -1, /* zero */
244 };
245
246 if (regno == R_ZERO)
247 return 0;
248
249 return p->p_md.md_tf->tf_regs[reg_to_frame[regno]];
250 }
251
252 int
ptrace_clear_bpt(struct proc * p,struct mdbpt * bpt)253 ptrace_clear_bpt(struct proc *p, struct mdbpt *bpt)
254 {
255 return ptrace_write_int(p, bpt->addr, bpt->contents);
256 }
257
258 int
ptrace_set_bpt(struct proc * p,struct mdbpt * bpt)259 ptrace_set_bpt(struct proc *p, struct mdbpt *bpt)
260 {
261 int error;
262 u_int32_t bpins = 0x00000080;
263 error = ptrace_read_int(p, bpt->addr, &bpt->contents);
264 if (error)
265 return error;
266 return ptrace_write_int(p, bpt->addr, bpins);
267 }
268
269 int
process_sstep(struct proc * p,int sstep)270 process_sstep(struct proc *p, int sstep)
271 {
272 int error;
273 vaddr_t pc = p->p_md.md_tf->tf_regs[FRAME_PC];
274 alpha_instruction ins;
275 vaddr_t addr[2];
276 int count = 0;
277
278 if (sstep == 0) {
279 /* clearing the breakpoint */
280 if (p->p_md.md_flags & MDP_STEP2) {
281 ptrace_clear_bpt(p, &p->p_md.md_sstep[1]);
282 ptrace_clear_bpt(p, &p->p_md.md_sstep[0]);
283 p->p_md.md_flags &= ~MDP_STEP2;
284 } else if (p->p_md.md_flags & MDP_STEP1) {
285 ptrace_clear_bpt(p, &p->p_md.md_sstep[0]);
286 p->p_md.md_flags &= ~MDP_STEP1;
287 }
288 return (0);
289 }
290 #ifdef DIAGNOSTIC
291 if (p->p_md.md_flags & (MDP_STEP1|MDP_STEP2))
292 panic("process_sstep: step breakpoints not removed");
293 #endif
294 error = ptrace_read_int(p, pc, &ins.bits);
295 if (error)
296 return (error);
297
298 switch (ins.branch_format.opcode) {
299 case op_j:
300 /* Jump: target is register value */
301 addr[0] = ptrace_read_register(p, ins.jump_format.rb) & ~3;
302 count = 1;
303 break;
304
305 case op_br:
306 case op_fbeq:
307 case op_fblt:
308 case op_fble:
309 case op_bsr:
310 case op_fbne:
311 case op_fbge:
312 case op_fbgt:
313 case op_blbc:
314 case op_beq:
315 case op_blt:
316 case op_ble:
317 case op_blbs:
318 case op_bne:
319 case op_bge:
320 case op_bgt:
321 /* Branch: target is pc+4+4*displacement */
322 addr[0] = pc + 4;
323 addr[1] = pc + 4 + 4 * ins.branch_format.displacement;
324 count = 2;
325 break;
326
327 default:
328 addr[0] = pc + 4;
329 count = 1;
330 }
331
332 if (p->p_addr->u_pcb.pcb_fpcpu != NULL)
333 fpusave_proc(p, 0);
334 p->p_md.md_sstep[0].addr = addr[0];
335 error = ptrace_set_bpt(p, &p->p_md.md_sstep[0]);
336 if (error)
337 return (error);
338 if (count == 2) {
339 p->p_md.md_sstep[1].addr = addr[1];
340 error = ptrace_set_bpt(p, &p->p_md.md_sstep[1]);
341 if (error) {
342 ptrace_clear_bpt(p, &p->p_md.md_sstep[0]);
343 return (error);
344 }
345 p->p_md.md_flags |= MDP_STEP2;
346 } else
347 p->p_md.md_flags |= MDP_STEP1;
348
349 return (0);
350 }
351
352 #endif /* PTRACE */
353