xref: /openbsd-src/sys/arch/hppa/hppa/db_interface.c (revision 949c1c4ec8cc03255798b09f6078e1d0aed70a6a)
1 /*	$OpenBSD: db_interface.c,v 1.51 2024/11/07 16:02:29 miod Exp $	*/
2 
3 /*
4  * Copyright (c) 1999-2003 Michael Shalayeff
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  * THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #undef DDB_DEBUG
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/stacktrace.h>
34 
35 #include <machine/db_machdep.h>
36 #include <machine/frame.h>
37 #include <machine/cpufunc.h>
38 
39 #include <ddb/db_access.h>
40 #include <ddb/db_command.h>
41 #include <ddb/db_output.h>
42 #include <ddb/db_run.h>
43 #include <ddb/db_sym.h>
44 #include <ddb/db_var.h>
45 #include <ddb/db_variables.h>
46 #include <ddb/db_extern.h>
47 #include <ddb/db_interface.h>
48 
49 #include <dev/cons.h>
50 
51 void kdbprinttrap(int, int);
52 
53 extern char *trap_type[];
54 extern int trap_types;
55 
56 db_regs_t	ddb_regs;
57 struct db_variable db_regs[] = {
58 	{ "flags", (long *)&ddb_regs.tf_flags,  FCN_NULL },
59 	{ "r1",    (long *)&ddb_regs.tf_r1,  FCN_NULL },
60 	{ "rp",    (long *)&ddb_regs.tf_rp,  FCN_NULL },
61 	{ "r3",    (long *)&ddb_regs.tf_r3,  FCN_NULL },
62 	{ "r4",    (long *)&ddb_regs.tf_r4,  FCN_NULL },
63 	{ "r5",    (long *)&ddb_regs.tf_r5,  FCN_NULL },
64 	{ "r6",    (long *)&ddb_regs.tf_r6,  FCN_NULL },
65 	{ "r7",    (long *)&ddb_regs.tf_r7,  FCN_NULL },
66 	{ "r8",    (long *)&ddb_regs.tf_r8,  FCN_NULL },
67 	{ "r9",    (long *)&ddb_regs.tf_r9,  FCN_NULL },
68 	{ "r10",   (long *)&ddb_regs.tf_r10, FCN_NULL },
69 	{ "r11",   (long *)&ddb_regs.tf_r11, FCN_NULL },
70 	{ "r12",   (long *)&ddb_regs.tf_r12, FCN_NULL },
71 	{ "r13",   (long *)&ddb_regs.tf_r13, FCN_NULL },
72 	{ "r14",   (long *)&ddb_regs.tf_r14, FCN_NULL },
73 	{ "r15",   (long *)&ddb_regs.tf_r15, FCN_NULL },
74 	{ "r16",   (long *)&ddb_regs.tf_r16, FCN_NULL },
75 	{ "r17",   (long *)&ddb_regs.tf_r17, FCN_NULL },
76 	{ "r18",   (long *)&ddb_regs.tf_r18, FCN_NULL },
77 	{ "r19",   (long *)&ddb_regs.tf_t4,  FCN_NULL },
78 	{ "r20",   (long *)&ddb_regs.tf_t3,  FCN_NULL },
79 	{ "r21",   (long *)&ddb_regs.tf_t2,  FCN_NULL },
80 	{ "r22",   (long *)&ddb_regs.tf_t1,  FCN_NULL },
81 	{ "r23",   (long *)&ddb_regs.tf_arg3,  FCN_NULL },
82 	{ "r24",   (long *)&ddb_regs.tf_arg2,  FCN_NULL },
83 	{ "r25",   (long *)&ddb_regs.tf_arg1,  FCN_NULL },
84 	{ "r26",   (long *)&ddb_regs.tf_arg0,  FCN_NULL },
85 	{ "r27",   (long *)&ddb_regs.tf_dp,    FCN_NULL },
86 	{ "r28",   (long *)&ddb_regs.tf_ret0,  FCN_NULL },
87 	{ "r29",   (long *)&ddb_regs.tf_ret1,  FCN_NULL },
88 	{ "r30",   (long *)&ddb_regs.tf_sp,    FCN_NULL },
89 	{ "r31",   (long *)&ddb_regs.tf_r31,   FCN_NULL },
90 	{ "sar",   (long *)&ddb_regs.tf_sar,   FCN_NULL },
91 
92 	{ "rctr",  (long *)&ddb_regs.tf_rctr,  FCN_NULL },
93 	{ "ccr",   (long *)&ddb_regs.tf_ccr,   FCN_NULL },
94 	{ "eirr",  (long *)&ddb_regs.tf_eirr,  FCN_NULL },
95 	{ "eiem",  (long *)&ddb_regs.tf_eiem,  FCN_NULL },
96 	{ "iir",   (long *)&ddb_regs.tf_iir,   FCN_NULL },
97 	{ "isr",   (long *)&ddb_regs.tf_isr,   FCN_NULL },
98 	{ "ior",   (long *)&ddb_regs.tf_ior,   FCN_NULL },
99 	{ "ipsw",  (long *)&ddb_regs.tf_ipsw,  FCN_NULL },
100 	{ "iisqh", (long *)&ddb_regs.tf_iisq_head,  FCN_NULL },
101 	{ "iioqh", (long *)&ddb_regs.tf_iioq_head,  FCN_NULL },
102 	{ "iisqt", (long *)&ddb_regs.tf_iisq_tail,  FCN_NULL },
103 	{ "iioqt", (long *)&ddb_regs.tf_iioq_tail,  FCN_NULL },
104 
105 	{ "sr0",   (long *)&ddb_regs.tf_sr0,   FCN_NULL },
106 	{ "sr1",   (long *)&ddb_regs.tf_sr1,   FCN_NULL },
107 	{ "sr2",   (long *)&ddb_regs.tf_sr2,   FCN_NULL },
108 	{ "sr3",   (long *)&ddb_regs.tf_sr3,   FCN_NULL },
109 	{ "sr4",   (long *)&ddb_regs.tf_sr4,   FCN_NULL },
110 	{ "sr5",   (long *)&ddb_regs.tf_sr5,   FCN_NULL },
111 	{ "sr6",   (long *)&ddb_regs.tf_sr6,   FCN_NULL },
112 	{ "sr7",   (long *)&ddb_regs.tf_sr7,   FCN_NULL },
113 
114 	{ "pidr1", (long *)&ddb_regs.tf_pidr1, FCN_NULL },
115 	{ "pidr2", (long *)&ddb_regs.tf_pidr2, FCN_NULL },
116 #ifdef pbably_not_worth_it
117 	{ "pidr3", (long *)&ddb_regs.tf_pidr3, FCN_NULL },
118 	{ "pidr4", (long *)&ddb_regs.tf_pidr4, FCN_NULL },
119 #endif
120 
121 	{ "vtop",  (long *)&ddb_regs.tf_vtop,  FCN_NULL },
122 	{ "cr28",  (long *)&ddb_regs.tf_cr28,  FCN_NULL },
123 	{ "cr30",  (long *)&ddb_regs.tf_cr30,  FCN_NULL },
124 };
125 struct db_variable *db_eregs = db_regs + nitems(db_regs);
126 
127 void
128 db_enter(void)
129 {
130 	extern int kernelmapped;	/* from locore.S */
131 	if (kernelmapped)
132 		__asm volatile ("break %0, %1"
133 		    :: "i" (HPPA_BREAK_KERNEL), "i" (HPPA_BREAK_KGDB));
134 }
135 
136 void
137 db_read_bytes(vaddr_t addr, size_t size, void *datap)
138 {
139 	char *data = datap;
140 	register char *src = (char *)addr;
141 
142 	while (size--)
143 		*data++ = *src++;
144 }
145 
146 void
147 db_write_bytes(vaddr_t addr, size_t size, void *datap)
148 {
149 	char *data = datap;
150 	register char *dst = (char *)addr;
151 
152 	while (size--)
153 		*dst++ = *data++;
154 
155 	/* unfortunately ddb does not provide any hooks for these */
156 	ficache(HPPA_SID_KERNEL, (vaddr_t)data, size);
157 	fdcache(HPPA_SID_KERNEL, (vaddr_t)data, size);
158 }
159 
160 
161 /*
162  * Print trap reason.
163  */
164 void
165 kdbprinttrap(int type, int code)
166 {
167 	type &= ~T_USER;	/* just in case */
168 	db_printf("kernel: ");
169 	if (type >= trap_types || type < 0)
170 		db_printf("type 0x%x", type);
171 	else
172 		db_printf("%s", trap_type[type]);
173 	db_printf(" trap, code=0x%x\n", code);
174 }
175 
176 /*
177  *  db_ktrap - field a BPT trap
178  */
179 int
180 db_ktrap(int type, int code, db_regs_t *regs)
181 {
182 	extern label_t *db_recover;
183 	int s;
184 
185 	switch (type) {
186 	case T_IBREAK:
187 	case T_DBREAK:
188 	case -1:
189 		break;
190 	default:
191 		if (!db_panic)
192 			return (0);
193 
194 		kdbprinttrap(type, code);
195 		if (db_recover != 0) {
196 			db_error("Caught exception in DDB; continuing...\n");
197 			/* NOT REACHED */
198 		}
199 	}
200 
201 	/* XXX Should switch to kdb`s own stack here. */
202 
203 	s = splhigh();
204 	ddb_regs = *regs;
205 	db_active++;
206 	cnpollc(1);
207 	db_trap(type, code);
208 	cnpollc(0);
209 	db_active--;
210 	splx(s);
211 
212 	*regs = ddb_regs;
213 
214 	return (1);
215 }
216 
217 /*
218  *  Validate an address for use as a breakpoint.
219  *  Any address is allowed for now.
220  */
221 int
222 db_valid_breakpoint(vaddr_t addr)
223 {
224 	return (1);
225 }
226 
227 void
228 db_stack_trace_print(db_expr_t addr, int have_addr, db_expr_t count,
229     char *modif, int (*pr)(const char *, ...))
230 {
231 	register_t *fp, pc, rp, *argp;
232 	Elf_Sym *sym;
233 	db_expr_t off;
234 	const char *name;
235 	int nargs;
236 
237 	if (count < 0)
238 		count = 65536;
239 
240 	if (!have_addr) {
241 		fp = (register_t *)ddb_regs.tf_r3;
242 		pc = ddb_regs.tf_iioq_head;
243 		rp = ddb_regs.tf_rp;
244 	} else {
245 		fp = (register_t *)addr;
246 		pc = 0;
247 		rp = ((register_t *)fp)[-5];
248 	}
249 
250 #ifdef DDB_DEBUG
251 	(*pr) (">> %p, 0x%x, 0x%x\t", fp, pc, rp);
252 #endif
253 	while (fp && count--) {
254 
255 		if (USERMODE(pc))
256 			return;
257 
258 		sym = db_search_symbol(pc, DB_STGY_ANY, &off);
259 		db_symbol_values (sym, &name, NULL);
260 
261 		if (name == NULL)
262 			(*pr)("%lx(", pc);
263 		else
264 			(*pr)("%s(", name);
265 
266 		/* args */
267 		nargs = 4;
268 		/*
269 		 * XXX first four args are passed on registers, and may not
270 		 * be stored on stack, dunno how to recover their values yet
271 		 */
272 		for (argp = &fp[-9]; nargs--; argp--) {
273 			(*pr)("%x%s", db_get_value((int)argp, 4, 0),
274 				  nargs? ",":"");
275 		}
276 		(*pr)(") at ");
277 		db_printsym(pc, DB_STGY_PROC, pr);
278 		(*pr)("\n");
279 
280 		/* TODO: print locals */
281 
282 		/* next frame */
283 		pc = rp;
284 		rp = fp[-5];
285 
286 		/* if a terminal frame and not a start of a page
287 		 * then skip the trapframe and the terminal frame */
288 		if (!fp[0]) {
289 			struct trapframe *tf;
290 
291 			tf = (struct trapframe *)((char *)fp - sizeof(*tf));
292 
293 			if (tf->tf_flags & TFF_SYS)
294 				(*pr)("-- syscall #%d(%x, %x, %x, %x, ...)\n",
295 				    tf->tf_t1, tf->tf_arg0, tf->tf_arg1,
296 				    tf->tf_arg2, tf->tf_arg3);
297 			else
298 				(*pr)("-- trap #%d%s\n", tf->tf_flags & 0x3f,
299 				    (tf->tf_flags & T_USER)? " from user" : "");
300 
301 			if (!(tf->tf_flags & TFF_LAST)) {
302 				fp = (register_t *)tf->tf_r3;
303 				pc = tf->tf_iioq_head;
304 				rp = tf->tf_rp;
305 			} else
306 				fp = 0;
307 		} else
308 			fp = (register_t *)fp[0];
309 #ifdef DDB_DEBUG
310 		(*pr) (">> %x, %x, %x\t", fp, pc, rp);
311 #endif
312 	}
313 
314 	if (count && pc) {
315 		db_printsym(pc, DB_STGY_XTRN, pr);
316 		(*pr)(":\n");
317 	}
318 }
319 
320 void
321 stacktrace_save_at(struct stacktrace *st, unsigned int skip)
322 {
323 	register_t *fp, pc, rp;
324 	int	i;
325 
326 	fp = (register_t *)__builtin_frame_address(0);
327 	pc = 0;
328 	rp = fp[-5];
329 
330 	st->st_count = 0;
331 	for (i = 0; i < STACKTRACE_MAX; i++) {
332 		if (skip == 0)
333 			st->st_pc[st->st_count++] = rp;
334 		else
335 			skip--;
336 
337 		/* next frame */
338 		pc = rp;
339 		if (!fp[0] || USERMODE(pc))
340 			break;
341 
342 		rp = fp[-5];
343 		fp = (register_t *)fp[0];
344 	}
345 }
346 
347 void
348 stacktrace_save_utrace(struct stacktrace *st)
349 {
350 	st->st_count = 0;
351 }
352