xref: /openbsd-src/sys/arch/alpha/alpha/process_machdep.c (revision f764f17bd112585cf34d54c83d00513f98c9e150)
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