xref: /f-stack/freebsd/mips/mips/db_interface.c (revision 22ce4aff)
1 /*	$OpenBSD: db_machdep.c,v 1.2 1998/09/15 10:50:13 pefo Exp $ */
2 
3 /*-
4  * SPDX-License-Identifier: BSD-4-Clause
5  *
6  * Copyright (c) 1998 Per Fogelstrom, Opsycon AB
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  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed under OpenBSD by
19  *	Per Fogelstrom, Opsycon AB, Sweden.
20  * 4. The name of the author may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
24  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
27  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  *	JNPR: db_interface.c,v 1.6.2.1 2007/08/29 12:24:49 girish
36  */
37 
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40 
41 #include <sys/types.h>
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/cons.h>
45 #include <sys/lock.h>
46 #include <vm/vm.h>
47 #include <vm/vm_object.h>
48 #include <vm/vm_page.h>
49 #include <vm/pmap.h>
50 #include <vm/vm_map.h>
51 #include <sys/user.h>
52 #include <sys/proc.h>
53 #include <sys/reboot.h>
54 
55 #include <machine/cache.h>
56 #include <machine/db_machdep.h>
57 #include <machine/mips_opcode.h>
58 #include <machine/vmparam.h>
59 #include <machine/md_var.h>
60 #include <machine/setjmp.h>
61 
62 #include <ddb/ddb.h>
63 #include <ddb/db_sym.h>
64 #include <ddb/db_access.h>
65 #include <ddb/db_output.h>
66 #include <ddb/db_variables.h>
67 #include <sys/kdb.h>
68 
69 static db_varfcn_t db_frame;
70 
71 #define	DB_OFFSET(x)	(db_expr_t *)offsetof(struct trapframe, x)
72 struct db_variable db_regs[] = {
73 	{ "at",  DB_OFFSET(ast),	db_frame },
74 	{ "v0",  DB_OFFSET(v0),		db_frame },
75 	{ "v1",  DB_OFFSET(v1),		db_frame },
76 	{ "a0",  DB_OFFSET(a0),		db_frame },
77 	{ "a1",  DB_OFFSET(a1),		db_frame },
78 	{ "a2",  DB_OFFSET(a2),		db_frame },
79 	{ "a3",  DB_OFFSET(a3),		db_frame },
80 #if defined(__mips_n32) || defined(__mips_n64)
81 	{ "a4",  DB_OFFSET(a4),		db_frame },
82 	{ "a5",  DB_OFFSET(a5),		db_frame },
83 	{ "a6",  DB_OFFSET(a6),		db_frame },
84 	{ "a7",  DB_OFFSET(a7),		db_frame },
85 	{ "t0",  DB_OFFSET(t0),		db_frame },
86 	{ "t1",  DB_OFFSET(t1),		db_frame },
87 	{ "t2",  DB_OFFSET(t2),		db_frame },
88 	{ "t3",  DB_OFFSET(t3),		db_frame },
89 #else
90 	{ "t0",  DB_OFFSET(t0),		db_frame },
91 	{ "t1",  DB_OFFSET(t1),		db_frame },
92 	{ "t2",  DB_OFFSET(t2),		db_frame },
93 	{ "t3",  DB_OFFSET(t3),		db_frame },
94 	{ "t4",  DB_OFFSET(t4),		db_frame },
95 	{ "t5",  DB_OFFSET(t5),		db_frame },
96 	{ "t6",  DB_OFFSET(t6),		db_frame },
97 	{ "t7",  DB_OFFSET(t7),		db_frame },
98 #endif
99 	{ "s0",  DB_OFFSET(s0),		db_frame },
100 	{ "s1",  DB_OFFSET(s1),		db_frame },
101 	{ "s2",  DB_OFFSET(s2),		db_frame },
102 	{ "s3",  DB_OFFSET(s3),		db_frame },
103 	{ "s4",  DB_OFFSET(s4),		db_frame },
104 	{ "s5",  DB_OFFSET(s5),		db_frame },
105 	{ "s6",  DB_OFFSET(s6),		db_frame },
106 	{ "s7",  DB_OFFSET(s7),		db_frame },
107 	{ "t8",  DB_OFFSET(t8),		db_frame },
108 	{ "t9",  DB_OFFSET(t9),		db_frame },
109 	{ "k0",  DB_OFFSET(k0),		db_frame },
110 	{ "k1",  DB_OFFSET(k1),		db_frame },
111 	{ "gp",  DB_OFFSET(gp),		db_frame },
112 	{ "sp",  DB_OFFSET(sp),		db_frame },
113 	{ "s8",  DB_OFFSET(s8),		db_frame },
114 	{ "ra",  DB_OFFSET(ra),		db_frame },
115 	{ "sr",  DB_OFFSET(sr),		db_frame },
116 	{ "lo",  DB_OFFSET(mullo),	db_frame },
117 	{ "hi",  DB_OFFSET(mulhi),	db_frame },
118 	{ "bad", DB_OFFSET(badvaddr),	db_frame },
119 	{ "cs",  DB_OFFSET(cause),	db_frame },
120 	{ "pc",  DB_OFFSET(pc),		db_frame },
121 };
122 struct db_variable *db_eregs = db_regs + nitems(db_regs);
123 
124 int (*do_db_log_stack_trace_cmd)(char *);
125 
126 static int
db_frame(struct db_variable * vp,db_expr_t * valuep,int op)127 db_frame(struct db_variable *vp, db_expr_t *valuep, int op)
128 {
129 	register_t *reg;
130 
131 	if (kdb_frame == NULL)
132 		return (0);
133 
134 	reg = (register_t *)((uintptr_t)kdb_frame + (size_t)(intptr_t)vp->valuep);
135 	if (op == DB_VAR_GET)
136 		*valuep = *reg;
137 	else
138 		*reg = *valuep;
139 	return (1);
140 }
141 
142 int
db_read_bytes(vm_offset_t addr,size_t size,char * data)143 db_read_bytes(vm_offset_t addr, size_t size, char *data)
144 {
145 	jmp_buf jb;
146 	void *prev_jb;
147 	int ret;
148 
149 	prev_jb = kdb_jmpbuf(jb);
150 	ret = setjmp(jb);
151 	if (ret == 0) {
152 		/*
153 		 * 'addr' could be a memory-mapped I/O address.  Try to
154 		 * do atomic load/store in unit of size requested.
155 		 * size == 8 is only atomic on 64bit or n32 kernel.
156 		 */
157 		if ((size == 2 || size == 4 || size == 8) &&
158 		    ((addr & (size -1)) == 0) &&
159 		    (((vm_offset_t)data & (size -1)) == 0)) {
160 			switch (size) {
161 			case 2:
162 				*(uint16_t *)data = *(uint16_t *)addr;
163 				break;
164 			case 4:
165 				*(uint32_t *)data = *(uint32_t *)addr;
166 				break;
167 			case 8:
168 				*(uint64_t *)data = *(uint64_t *)addr;
169 				break;
170 			}
171 		} else {
172 			char *src;
173 
174 			src = (char *)addr;
175 			while (size-- > 0)
176 				*data++ = *src++;
177 		}
178 	}
179 
180 	(void)kdb_jmpbuf(prev_jb);
181 	return (ret);
182 }
183 
184 int
db_write_bytes(vm_offset_t addr,size_t size,char * data)185 db_write_bytes(vm_offset_t addr, size_t size, char *data)
186 {
187 	int ret;
188 	jmp_buf jb;
189 	void *prev_jb;
190 
191 	prev_jb = kdb_jmpbuf(jb);
192 	ret = setjmp(jb);
193 
194 	if (ret == 0) {
195 		/*
196 		 * 'addr' could be a memory-mapped I/O address.  Try to
197 		 * do atomic load/store in unit of size requested.
198 		 * size == 8 is only atomic on 64bit or n32 kernel.
199 		 */
200 		if ((size == 2 || size == 4 || size == 8) &&
201 		    ((addr & (size -1)) == 0) &&
202 		    (((vm_offset_t)data & (size -1)) == 0)) {
203 			switch (size) {
204 			case 2:
205 				*(uint16_t *)addr = *(uint16_t *)data;
206 				break;
207 			case 4:
208 				*(uint32_t *)addr = *(uint32_t *)data;
209 				break;
210 			case 8:
211 				*(uint64_t *)addr = *(uint64_t *)data;
212 				break;
213 			}
214 		} else {
215 			char *dst;
216 			size_t len = size;
217 
218 			dst = (char *)addr;
219 			while (len-- > 0)
220 				*dst++ = *data++;
221 		}
222 
223 		mips_icache_sync_range((db_addr_t) addr, size);
224 		mips_dcache_wbinv_range((db_addr_t) addr, size);
225 	}
226 	(void)kdb_jmpbuf(prev_jb);
227 	return (ret);
228 }
229 
230 /*
231  *	To do a single step ddb needs to know the next address
232  *	that we will get to. It means that we need to find out
233  *	both the address for a branch taken and for not taken, NOT! :-)
234  *	MipsEmulateBranch will do the job to find out _exactly_ which
235  *	address we will end up at so the 'dual bp' method is not
236  *	requiered.
237  */
238 db_addr_t
next_instr_address(db_addr_t pc,boolean_t bd)239 next_instr_address(db_addr_t pc, boolean_t bd)
240 {
241 	db_addr_t next;
242 
243 	next = (db_addr_t)MipsEmulateBranch(kdb_frame, pc, 0, 0);
244 	return (next);
245 }
246 
247 /*
248  *	Decode instruction and figure out type.
249  */
250 int
db_inst_type(int ins)251 db_inst_type(int ins)
252 {
253 	InstFmt inst;
254 	int	ityp = 0;
255 
256 	inst.word = ins;
257 	switch ((int)inst.JType.op) {
258 	case OP_SPECIAL:
259 		switch ((int)inst.RType.func) {
260 		case OP_JR:
261 			ityp = IT_BRANCH;
262 			break;
263 		case OP_JALR:
264 		case OP_SYSCALL:
265 			ityp = IT_CALL;
266 			break;
267 		}
268 		break;
269 
270 	case OP_BCOND:
271 		switch ((int)inst.IType.rt) {
272 		case OP_BLTZ:
273 		case OP_BLTZL:
274 		case OP_BGEZ:
275 		case OP_BGEZL:
276 			ityp = IT_BRANCH;
277 			break;
278 
279 		case OP_BLTZAL:
280 		case OP_BLTZALL:
281 		case OP_BGEZAL:
282 		case OP_BGEZALL:
283 			ityp = IT_CALL;
284 			break;
285 		}
286 		break;
287 
288 	case OP_JAL:
289 		ityp = IT_CALL;
290 		break;
291 
292 	case OP_J:
293 	case OP_BEQ:
294 	case OP_BEQL:
295 	case OP_BNE:
296 	case OP_BNEL:
297 	case OP_BLEZ:
298 	case OP_BLEZL:
299 	case OP_BGTZ:
300 	case OP_BGTZL:
301 		ityp = IT_BRANCH;
302 		break;
303 
304 	case OP_COP1:
305 		switch (inst.RType.rs) {
306 		case OP_BCx:
307 		case OP_BCy:
308 			ityp = IT_BRANCH;
309 			break;
310 		}
311 		break;
312 
313 	case OP_LB:
314 	case OP_LH:
315 	case OP_LW:
316 	case OP_LD:
317 	case OP_LBU:
318 	case OP_LHU:
319 	case OP_LWU:
320 	case OP_LWC1:
321 		ityp = IT_LOAD;
322 		break;
323 
324 	case OP_SB:
325 	case OP_SH:
326 	case OP_SW:
327 	case OP_SD:
328 	case OP_SWC1:
329 		ityp = IT_STORE;
330 		break;
331 	}
332 	return (ityp);
333 }
334 
335 /*
336  * Return the next pc if the given branch is taken.
337  * MachEmulateBranch() runs analysis for branch delay slot.
338  */
339 db_addr_t
branch_taken(int inst,db_addr_t pc)340 branch_taken(int inst, db_addr_t pc)
341 {
342 	db_addr_t ra;
343 	register_t fpucsr;
344 
345 	/* TBD: when is fsr set */
346 	fpucsr = (curthread) ? curthread->td_pcb->pcb_regs.fsr : 0;
347 	ra = (db_addr_t)MipsEmulateBranch(kdb_frame, pc, fpucsr, 0);
348 	return (ra);
349 }
350