Home | History | Annotate | Line # | Download | only in sh3
      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