xref: /netbsd/sys/arch/sh3/sh3/db_trace.c (revision b76426bb)
1 /*	$NetBSD: db_trace.c,v 1.26 2019/05/09 16:48:31 ryo Exp $	*/
2 
3 /*-
4  * Copyright (c) 2000 Tsubai Masanari.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.26 2019/05/09 16:48:31 ryo Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 
35 #include <machine/db_machdep.h>
36 
37 #include <ddb/db_access.h>
38 #include <ddb/db_interface.h>
39 #include <ddb/db_output.h>
40 #include <ddb/db_proc.h>
41 #include <ddb/db_sym.h>
42 #include <ddb/db_variables.h>
43 
44 volatile int db_trace_debug = 0; /* settabble from ddb */
45 #define DPRINTF(level, fmt, args...)					\
46 	do {								\
47 		if (__predict_false(db_trace_debug > (level))) {	\
48 			print(fmt, ## args);				\
49 		}							\
50 	} while (0 /* CONSTCOND*/)
51 
52 extern char start[], etext[];
53 static bool db_nextframe(db_addr_t, db_addr_t, db_addr_t *, db_addr_t *,
54     db_addr_t *, void (*)(const char *, ...) __printflike(1, 2));
55 
56 const struct db_variable db_regs[] = {
57 	{ "r0",   (long *)&ddb_regs.tf_r0,   FCN_NULL },
58 	{ "r1",   (long *)&ddb_regs.tf_r1,   FCN_NULL },
59 	{ "r2",   (long *)&ddb_regs.tf_r2,   FCN_NULL },
60 	{ "r3",   (long *)&ddb_regs.tf_r3,   FCN_NULL },
61 	{ "r4",   (long *)&ddb_regs.tf_r4,   FCN_NULL },
62 	{ "r5",   (long *)&ddb_regs.tf_r5,   FCN_NULL },
63 	{ "r6",   (long *)&ddb_regs.tf_r6,   FCN_NULL },
64 	{ "r7",   (long *)&ddb_regs.tf_r7,   FCN_NULL },
65 	{ "r8",   (long *)&ddb_regs.tf_r8,   FCN_NULL },
66 	{ "r9",   (long *)&ddb_regs.tf_r9,   FCN_NULL },
67 	{ "r10",  (long *)&ddb_regs.tf_r10,  FCN_NULL },
68 	{ "r11",  (long *)&ddb_regs.tf_r11,  FCN_NULL },
69 	{ "r12",  (long *)&ddb_regs.tf_r12,  FCN_NULL },
70 	{ "r13",  (long *)&ddb_regs.tf_r13,  FCN_NULL },
71 	{ "r14",  (long *)&ddb_regs.tf_r14,  FCN_NULL },
72 	{ "r15",  (long *)&ddb_regs.tf_r15,  FCN_NULL },
73 	{ "pr",   (long *)&ddb_regs.tf_pr,   FCN_NULL },
74 	{ "pc",   (long *)&ddb_regs.tf_spc,  FCN_NULL },
75 	{ "sr",   (long *)&ddb_regs.tf_ssr,  FCN_NULL },
76 	{ "mach", (long *)&ddb_regs.tf_mach, FCN_NULL },
77 	{ "macl", (long *)&ddb_regs.tf_macl, FCN_NULL },
78 };
79 
80 const struct db_variable * const db_eregs = db_regs + __arraycount(db_regs);
81 
82 static void
83 dump_trapframe(struct trapframe *tf,
84 	void (*print)(const char *, ...) __printflike(1, 2))
85 {
86 	print("   sr=%08x   gbr=%08x    pc=%08x     pr=%08x\n",
87 	    tf->tf_ssr, tf->tf_gbr, tf->tf_spc, tf->tf_pr);
88 	print("   r0=%08x    r1=%08x    r2=%08x     r3=%08x\n",
89 	    tf->tf_r0, tf->tf_r1, tf->tf_r2, tf->tf_r3);
90 	print("   r4=%08x    r6=%08x    r7=%08x     r8=%08x\n",
91 	    tf->tf_r4, tf->tf_r5, tf->tf_r6, tf->tf_r7);
92 	print("   r5=%08x    r9=%08x   r10=%08x    r11=%08x\n",
93 	    tf->tf_r8, tf->tf_r9, tf->tf_r10, tf->tf_r11);
94 	print("  r12=%08x   r13=%08x   r14=%08x sp=r15=%08x\n",
95 	    tf->tf_r12, tf->tf_r13, tf->tf_r14, tf->tf_r15);
96 }
97 
98 void
99 db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count,
100 	const char *modif, void (*print)(const char *, ...) __printflike(1, 2))
101 {
102 	struct trapframe *tf;
103 	db_addr_t func, pc, lastpc, pr, sp, fp;
104 	uint32_t vbr;
105 	bool lwpid = false;
106 	bool lwpaddr = false;
107 	const char *cp;
108 	char c;
109 
110 	__asm volatile("stc vbr, %0" : "=r"(vbr));
111 
112 	cp = modif;
113 	while ((c = *cp++) != 0) {
114 		if (c == 'a')
115 			lwpaddr = true;
116 		else if (c == 't')
117 			lwpid = true;
118 	}
119 
120 	if (lwpaddr && lwpid) {
121 		db_printf("only one of /a or /t can be specified\n");
122 		return;
123 	}
124 	if ((lwpaddr || lwpid) && !have_addr) {
125 		db_printf("%s required\n", lwpaddr ? "address" : "pid");
126 		return;
127 	}
128 
129 	if (!have_addr) {
130 		tf = &ddb_regs;
131 		fp = tf->tf_r14;
132 		sp = tf->tf_r15;
133 		pr = tf->tf_pr;
134 		pc = tf->tf_spc;
135 		if (pc == 0) {
136 			print("calling through null pointer?\n");
137 			pc = tf->tf_pr;
138 		}
139 		DPRINTF(1, "# trapframe: pc=%lx pr=%lx fp=%lx sp=%lx\n",
140 		    pc, pr, fp, sp);
141 
142 	} else if (lwpaddr || lwpid) {
143 		struct proc *p;
144 		struct lwp *l;
145 		struct pcb *pcb;
146 
147 		if (lwpaddr) {
148 			l = (struct lwp *)addr;
149 			p = l->l_proc;
150 			print("trace: lwp addr %p pid %d ",
151 			    (void *)addr, p->p_pid);
152 		} else {
153 			pid_t pid = (pid_t)addr;
154 			print("trace: pid %d ", pid);
155 			p = db_proc_find(pid);
156 			if (p == NULL) {
157 				print("not found\n");
158 				return;
159 			}
160 			l = LIST_FIRST(&p->p_lwps);
161 		}
162 		KASSERT(l != NULL);
163 		print("lid %d", l->l_lid);
164 		pcb = lwp_getpcb(l);
165 		tf = (struct trapframe *)pcb->pcb_sf.sf_r6_bank;
166 		fp = pcb->pcb_sf.sf_r14;
167 		sp = pcb->pcb_sf.sf_r15;
168 		pr = pcb->pcb_sf.sf_pr;
169 		pc = pcb->pcb_sf.sf_pr;
170 		print(", fp=%lx, sp=%lx\n", fp, sp);
171 		DPRINTF(1, "# lwp: pc=%lx pr=%lx fp=%lx sp=%lx\n",
172 		    pc, pr, fp, sp);
173 	} else {
174 		fp = 0;
175 		sp = addr;
176 		pr = 0;
177 		/*
178 		 * Assume that the frame address (__builtin_frame_address)
179 		 * passed as an argument is the same level
180 		 * as this __builtin_return_address().
181 		 */
182 		pc = (db_addr_t)__builtin_return_address(0);
183 	}
184 
185 	lastpc = 0;
186 	while (count > 0 && pc != 0 && sp != 0) {
187 		DPRINTF(2, "# trace: pc=%lx sp=%lx fp=%lx\n", pc, sp, fp);
188 
189 		/* Are we crossing a trap frame? */
190 		if ((pc & ~PAGE_MASK) == vbr) {
191 			struct trapframe trapframe;
192 			tf = &trapframe;
193 
194 			/* r14 in exception vectors points to trap frame */
195 			db_read_bytes((db_addr_t)fp, sizeof(*tf), (char *)tf);
196 			pc = tf->tf_spc;
197 			pr = tf->tf_pr;
198 			fp = tf->tf_r14;
199 			sp = tf->tf_r15;
200 
201 			print("<EXPEVT %03x; SSR=%08x> at ",
202 			    tf->tf_expevt, tf->tf_ssr);
203 			db_printsym(pc, DB_STGY_PROC, print);
204 			print("\n");
205 
206 			print("[trapframe 0x%lx]\n", fp);
207 			dump_trapframe(tf, print);
208 
209 			/* XXX: don't venture into the userland yet */
210 			if ((tf->tf_ssr & PSL_MD) == 0)
211 				break;
212 		} else {
213 			const char *name;
214 			db_expr_t offset;
215 			db_sym_t sym;
216 			bool found;
217 
218 			sym = db_search_symbol(pc, DB_STGY_ANY, &offset);
219 			if (sym == 0) {
220 				print("symbol not found\n");
221 				break;
222 			}
223 			db_symbol_values(sym, &name, NULL);
224 
225 			func = pc - offset;
226 
227 			DPRINTF(1,
228 			    "    (1) func=%lx+%lx, pc=%lx, sp=%lx, fp=%lx\n",
229 			    func, offset, pc, sp, fp);
230 
231 			found = db_nextframe(func, pc, &fp, &pr, &sp, print);
232 			if (!found && lastpc == pc)
233 				break;
234 			lastpc = pc;
235 
236 			DPRINTF(1, "    (2) newpc=%lx, newsp=%lx, newfp=%lx\n",
237 			    pr, sp, fp);
238 
239 			DPRINTF(1, "sp=%lx ", sp);
240 			print("%s() at ", name ? name : "");
241 			db_printsym(pr, DB_STGY_PROC, print);
242 			print("\n");
243 
244 			pc = pr;
245 			pr = 0;
246 		}
247 
248 		count--;
249 	}
250 }
251 
252 static bool
253 db_nextframe(
254 	db_addr_t func,		/* in: entry address of current function */
255 	db_addr_t curpc,	/* in: current pc in the function */
256 	db_addr_t *fp,		/* out: parent fp */
257 	db_addr_t *pr,		/* out: parent pr */
258 	db_addr_t *sp,		/* in: current sp, out: parent sp */
259 	void (*print)(const char *, ...) __printflike(1, 2))
260 {
261 	int *stack = (void *)*sp;
262 	int i, inst, inst2;
263 	int depth, prdepth, fpdepth;
264 	db_addr_t pc;
265 
266 	if (__predict_false(db_trace_debug >= 2)) {
267 		DPRINTF(2, "%s:%d: START: func=%lx=", __func__, __LINE__, func);
268 		db_printsym(func, DB_STGY_PROC, print);
269 		DPRINTF(2, " pc=%lx fp=%lx pr=%lx, sp=%lx\n",
270 		    curpc, *fp, *pr, *sp);
271 	}
272 
273 	pc = func;
274 	depth = 0;
275 	prdepth = fpdepth = -1;
276 
277 	if (pc < (db_addr_t)start || pc > (db_addr_t)etext)
278 		goto out;
279 
280 	for (i = 0; i < 30 && pc < curpc; i++) {
281 		inst = db_get_value(pc, 2, false);
282 		DPRINTF(2, "%s:%d: %lx insn=%04x depth=%d\n",
283 		    __func__, __LINE__, pc, inst, depth);
284 		pc += 2;
285 
286 		if (inst == 0x000b)	/* rts - asm routines w/out frame */
287 			break;
288 
289 		if (inst == 0x6ef3)	/* mov r15,r14 -- end of prologue */
290 			break;
291 
292 		if (inst == 0x4f22) {			/* sts.l pr,@-r15 */
293 			prdepth = depth;
294 			depth++;
295 			continue;
296 		}
297 		if (inst == 0x2fe6) {			/* mov.l r14,@-r15 */
298 			fpdepth = depth;
299 			depth++;
300 			continue;
301 		}
302 		if ((inst & 0xff0f) == 0x2f06) {	/* mov.l r?,@-r15 */
303 			depth++;
304 			continue;
305 		}
306 		if ((inst & 0xff00) == 0x7f00) {	/* add #n,r15 */
307 			int8_t n = inst & 0xff;
308 
309 			if (n >= 0) {
310 				/* XXX: in epilogue? ignore it */
311 				DPRINTF(2,
312 				    "%s:%d: %lx: add #%d,r15 (n > 0) ignored\n",
313 				    __func__, __LINE__, pc - 2, n);
314 				break;
315 			}
316 
317 			depth += -n / 4;
318 			continue;
319 		}
320 		if ((inst & 0xf000) == 0x9000) {
321 			inst2 = db_get_value(pc, 2, false);
322 			if (((inst2 & 0xff0f) == 0x3f08) &&
323 			    ((inst & 0x0f00) == ((inst2 & 0x00f0) << 4))) {
324 
325 				/* mov <disp>,r?; sub r?,r15 */
326 				unsigned int disp = (int)(inst & 0xff);
327 				vaddr_t addr;
328 				int val;
329 
330 				addr = pc + (4 - 2) + (disp << 1);
331 				db_read_bytes(addr, sizeof(val), (char *)&val);
332 				if ((val & 0x00008000) == 0)
333 					val &= 0x0000ffff;
334 				else
335 					val |= 0xffff0000;
336 				depth += (val / 4);
337 
338 				pc += 2;
339 				continue;
340 			}
341 		}
342 
343 		if (__predict_false(db_trace_debug > 1)) {
344 			print("    unknown insn at ");
345 			db_printsym(pc - 2, DB_STGY_PROC, print);
346 			print(":\t");
347 			db_disasm(pc - 2, 0);/* XXX: always uses db_printf */
348 		}
349 	}
350 
351  out:
352 	DPRINTF(2, "%s:%d: fpdepth=%d prdepth=%d depth=%d sp=%lx->%lx\n",
353 	    __func__, __LINE__, fpdepth, prdepth, depth, *sp, *sp - depth * 4);
354 
355 	/* dump stack */
356 	if (__predict_false(db_trace_debug > 2) &&
357 	    ((fpdepth != -1) || (prdepth != -1))) {
358 		print("%s:%d: func=%lx pc=%lx\n",
359 		    __func__, __LINE__, func, curpc);
360 
361 		for (int j = 0; j < prdepth + 32; j++) {
362 			uint32_t v;
363 
364 			db_read_bytes((db_addr_t)&stack[j],
365 			    sizeof(v), (char *)&v);
366 			print("  STACK[%2d]: %p: %08x  ",
367 			    j, &stack[j], v);
368 			db_printsym(v, DB_STGY_PROC, print);
369 			if (j == (depth - prdepth - 1))
370 				print("  # = pr");
371 			if (j == (depth - fpdepth - 1))
372 				print("  # = fp");
373 			print("\n");
374 		}
375 	}
376 
377 	/* fetch fp and pr if exists in stack */
378 	if (fpdepth != -1)
379 		db_read_bytes((db_addr_t)&stack[depth - fpdepth - 1],
380 		    sizeof(*fp), (char *)fp);
381 	if (prdepth != -1)
382 		db_read_bytes((db_addr_t)&stack[depth - prdepth - 1],
383 		    sizeof(*pr), (char *)pr);
384 
385 	/* adjust stack pointer, and update */
386 	stack += depth;
387 	*sp = (db_addr_t)stack;
388 
389 	if (__predict_false(db_trace_debug >= 2)) {
390 		DPRINTF(2, "%s:%d: RESULT: fp=%lx pr=%lx(",
391 		    __func__, __LINE__, *fp, *pr);
392 		db_printsym(*pr, DB_STGY_PROC, print);
393 		DPRINTF(2, ") sp=%lx\n", *sp);
394 	}
395 
396 	if ((prdepth == -1) && (fpdepth == -1) && (depth == 0))
397 		return false;
398 	return true;
399 }
400