Home | History | Annotate | Line # | Download | only in mips
      1 /*	$NetBSD: mips_stacktrace.c,v 1.9 2021/04/06 13:11:22 simonb Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1988 University of Utah.
      5  * Copyright (c) 1992, 1993
      6  *	The Regents of the University of California.  All rights reserved.
      7  *
      8  * This code is derived from software contributed to Berkeley by
      9  * the Systems Programming Group of the University of Utah Computer
     10  * Science Department and Ralph Campbell.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  * 1. Redistributions of source code must retain the above copyright
     16  *    notice, this list of conditions and the following disclaimer.
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  * 3. Neither the name of the University nor the names of its contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  *
     36  * from: NetBSD: trap.c,v 1.255 2020/07/13 09:00:40 simonb Exp
     37  * from: Utah Hdr: trap.c 1.32 91/04/06
     38  *
     39  *	@(#)trap.c	8.5 (Berkeley) 1/11/94
     40  */
     41 
     42 #include <sys/cdefs.h>
     43 __KERNEL_RCSID(0, "$NetBSD: mips_stacktrace.c,v 1.9 2021/04/06 13:11:22 simonb Exp $");
     44 
     45 #ifdef _KERNEL_OPT
     46 #include "opt_ddb.h"
     47 #include "opt_kgdb.h"
     48 #endif
     49 
     50 #include <sys/param.h>
     51 #include <sys/systm.h>
     52 #include <sys/proc.h>
     53 
     54 #include <mips/locore.h>
     55 #include <mips/mips_opcode.h>
     56 #include <mips/regnum.h>
     57 #include <mips/stacktrace.h>
     58 
     59 #if defined(_KMEMUSER) && !defined(DDB)
     60 #define DDB 1
     61 #endif
     62 
     63 #ifdef DDB
     64 #include <machine/db_machdep.h>
     65 #include <ddb/db_sym.h>
     66 #include <ddb/db_user.h>
     67 #include <ddb/db_access.h>
     68 #endif
     69 
     70 #ifdef KGDB
     71 #include <sys/kgdb.h>
     72 #endif
     73 
     74 #ifndef DDB_TRACE
     75 
     76 #if defined(DEBUG) || defined(DDB) || defined(KGDB) || defined(geo)
     77 
     78 extern char start[], edata[], verylocore[];
     79 #ifdef MIPS1
     80 extern char mips1_kern_gen_exception[];
     81 extern char mips1_user_gen_exception[];
     82 extern char mips1_kern_intr[];
     83 extern char mips1_user_intr[];
     84 extern char mips1_systemcall[];
     85 #endif
     86 #ifdef MIPS3
     87 extern char mips3_kern_gen_exception[];
     88 extern char mips3_user_gen_exception[];
     89 extern char mips3_kern_intr[];
     90 extern char mips3_user_intr[];
     91 extern char mips3_systemcall[];
     92 #endif
     93 #ifdef MIPS32
     94 extern char mips32_kern_gen_exception[];
     95 extern char mips32_user_gen_exception[];
     96 extern char mips32_kern_intr[];
     97 extern char mips32_user_intr[];
     98 extern char mips32_systemcall[];
     99 #endif
    100 #ifdef MIPS32R2
    101 extern char mips32r2_kern_gen_exception[];
    102 extern char mips32r2_user_gen_exception[];
    103 extern char mips32r2_kern_intr[];
    104 extern char mips32r2_user_intr[];
    105 extern char mips32r2_systemcall[];
    106 #endif
    107 #ifdef MIPS64
    108 extern char mips64_kern_gen_exception[];
    109 extern char mips64_user_gen_exception[];
    110 extern char mips64_kern_intr[];
    111 extern char mips64_user_intr[];
    112 extern char mips64_systemcall[];
    113 #endif
    114 #ifdef MIPS64R2
    115 extern char mips64r2_kern_gen_exception[];
    116 extern char mips64r2_user_gen_exception[];
    117 extern char mips64r2_kern_intr[];
    118 extern char mips64r2_user_intr[];
    119 extern char mips64r2_systemcall[];
    120 #endif
    121 
    122 #define	MIPS_JR_RA	0x03e00008	/* instruction code for jr ra */
    123 #define	MIPS_JR_K0	0x03400008	/* instruction code for jr k0 */
    124 #define	MIPS_ERET	0x42000018	/* instruction code for eret */
    125 
    126 int main(void *);	/* XXX */
    127 
    128 /*
    129  * Functions ``special'' enough to print by name
    130  */
    131 #define Name(_fn)  { (void*)_fn, # _fn }
    132 static const struct { void *addr; const char *name;} names[] = {
    133 #ifdef _KERNEL
    134 	Name(stacktrace),
    135 	Name(stacktrace_subr),
    136 	Name(main),
    137 	Name(trap),
    138 
    139 #ifdef MIPS1	/*  r2000 family  (mips-I CPU) */
    140 	Name(mips1_kern_gen_exception),
    141 	Name(mips1_user_gen_exception),
    142 	Name(mips1_systemcall),
    143 	Name(mips1_kern_intr),
    144 	Name(mips1_user_intr),
    145 #endif	/* MIPS1 */
    146 
    147 #if defined(MIPS3)			/* r4000 family (mips-III CPU) */
    148 	Name(mips3_kern_gen_exception),
    149 	Name(mips3_user_gen_exception),
    150 	Name(mips3_systemcall),
    151 	Name(mips3_kern_intr),
    152 	Name(mips3_user_intr),
    153 #endif	/* MIPS3 */
    154 
    155 #if defined(MIPS32)			/* MIPS32 family (mips-III CPU) */
    156 	Name(mips32_kern_gen_exception),
    157 	Name(mips32_user_gen_exception),
    158 	Name(mips32_systemcall),
    159 	Name(mips32_kern_intr),
    160 	Name(mips32_user_intr),
    161 #endif	/* MIPS32 */
    162 
    163 #if defined(MIPS32R2)			/* MIPS32R2 family (mips-III CPU) */
    164 	Name(mips32r2_kern_gen_exception),
    165 	Name(mips32r2_user_gen_exception),
    166 	Name(mips32r2_systemcall),
    167 	Name(mips32r2_kern_intr),
    168 	Name(mips32r2_user_intr),
    169 #endif	/* MIPS32R2 */
    170 
    171 #if defined(MIPS64)			/* MIPS64 family (mips-III CPU) */
    172 	Name(mips64_kern_gen_exception),
    173 	Name(mips64_user_gen_exception),
    174 	Name(mips64_systemcall),
    175 	Name(mips64_kern_intr),
    176 	Name(mips64_user_intr),
    177 #endif	/* MIPS64 */
    178 
    179 #if defined(MIPS64R2)			/* MIPS64R2 family (mips-III CPU) */
    180 	Name(mips64r2_kern_gen_exception),
    181 	Name(mips64r2_user_gen_exception),
    182 	Name(mips64r2_systemcall),
    183 	Name(mips64r2_kern_intr),
    184 	Name(mips64r2_user_intr),
    185 #endif	/* MIPS64R2 */
    186 
    187 	Name(cpu_idle),
    188 	Name(cpu_switchto),
    189 #endif /* _KERNEL */
    190 	{0, 0}
    191 };
    192 
    193 
    194 bool
    195 kdbpeek(vaddr_t addr, unsigned *valp)
    196 {
    197 	if (addr & 3) {
    198 		printf("kdbpeek: unaligned address %#"PRIxVADDR"\n", addr);
    199 		/* We might have been called from DDB, so do not go there. */
    200 		return false;
    201 	} else if (addr == 0) {
    202 		printf("kdbpeek: NULL\n");
    203 		return false;
    204 	} else {
    205 #if _KERNEL
    206 		*valp = *(unsigned *)addr;
    207 #else
    208 		db_read_bytes((db_addr_t)addr, sizeof(unsigned), (char *)valp);
    209 #endif
    210 		return true;
    211 	}
    212 }
    213 
    214 mips_reg_t
    215 kdbrpeek(vaddr_t addr, size_t n)
    216 {
    217 	mips_reg_t rc = 0;
    218 
    219 	if (addr & (n - 1)) {
    220 		printf("kdbrpeek: unaligned address %#"PRIxVADDR"\n", addr);
    221 #if _KERNEL
    222 		/* We might have been called from DDB, so do not go there. */
    223 		stacktrace();
    224 #endif
    225 		rc = -1;
    226 	} else if (addr == 0) {
    227 		printf("kdbrpeek: NULL\n");
    228 		rc = 0xdeadfeed;
    229 	} else {
    230 		if (sizeof(mips_reg_t) == 8 && n == 8)
    231 #if _KERNEL
    232 			rc = *(int64_t *)addr;
    233  		else
    234 			rc = *(int32_t *)addr;
    235 #else
    236 			db_read_bytes((db_addr_t)addr, sizeof(int64_t), (char *)&rc);
    237 		else
    238 			db_read_bytes((db_addr_t)addr, sizeof(int32_t), (char *)&rc);
    239 #endif
    240 	}
    241 	return rc;
    242 }
    243 
    244 /*
    245  * Map a function address to a string name, if known; or a hex string.
    246  */
    247 static const char *
    248 fn_name(vaddr_t addr)
    249 {
    250 	static char buf[17];
    251 	int i = 0;
    252 #ifdef DDB
    253 	db_expr_t diff;
    254 	db_sym_t sym;
    255 	const char *symname;
    256 #endif
    257 
    258 #ifdef DDB
    259 	diff = 0;
    260 	symname = NULL;
    261 	sym = db_search_symbol(addr, DB_STGY_ANY, &diff);
    262 	db_symbol_values(sym, &symname, 0);
    263 	if (symname && diff == 0)
    264 		return (symname);
    265 #endif
    266 	for (i = 0; names[i].name; i++)
    267 		if (names[i].addr == (void*)addr)
    268 			return (names[i].name);
    269 	snprintf(buf, sizeof(buf), "%#"PRIxVADDR, addr);
    270 	return (buf);
    271 }
    272 
    273 /*
    274  * Do a stack backtrace.
    275  * (*printfn)()  prints the output to either the system log,
    276  * the console, or both.
    277  */
    278 void
    279 stacktrace_subr(mips_reg_t a0, mips_reg_t a1, mips_reg_t a2, mips_reg_t a3,
    280     vaddr_t pc, vaddr_t sp, vaddr_t fp, vaddr_t ra,
    281     void (*printfn)(const char*, ...))
    282 {
    283 	vaddr_t va, subr;
    284 	unsigned instr, mask;
    285 	InstFmt i;
    286 	int more, stksize;
    287 	unsigned int frames =  0;
    288 	int foundframesize = 0;
    289 	mips_reg_t regs[32] = {
    290 		[_R_ZERO] = 0,
    291 		[_R_A0] = a0, [_R_A1] = a1, [_R_A2] = a2, [_R_A3] = a3,
    292 		[_R_RA] = ra,
    293 	};
    294 
    295 /* Jump here when done with a frame, to start a new one */
    296 loop:
    297 	stksize = 0;
    298 	subr = 0;
    299 	mask = 1;
    300 	if (frames++ > 100) {
    301 		(*printfn)("\nstackframe count exceeded\n");
    302 		/* return breaks stackframe-size heuristics with gcc -O2 */
    303 		goto finish;	/*XXX*/
    304 	}
    305 
    306 	/* check for bad SP: could foul up next frame */
    307 	if ((sp & (sizeof(sp)-1)) || (intptr_t)sp >= 0) {
    308 		(*printfn)("SP 0x%x: not in kernel\n", sp);
    309 		ra = 0;
    310 		subr = 0;
    311 		goto done;
    312 	}
    313 
    314 	/* Check for bad PC */
    315 	if (pc & 3 || (intptr_t)pc >= 0 || (intptr_t)pc >= (intptr_t)edata) {
    316 		(*printfn)("PC 0x%x: not in kernel space\n", pc);
    317 		ra = 0;
    318 		goto done;
    319 	}
    320 
    321 #if defined(DDB) && defined(_KERNEL)
    322 	if (ksyms_available()) {
    323 		db_expr_t diff;
    324 		db_sym_t sym;
    325 
    326 		/*
    327 		 * Check the kernel symbol table to see the beginning of
    328 		 * the current subroutine.
    329 		 */
    330 		diff = 0;
    331 		sym = db_search_symbol(pc, DB_STGY_ANY, &diff);
    332 		if (sym != DB_SYM_NULL && diff == 0) {
    333 			/* check func(foo) __attribute__((__noreturn__)) case */
    334 			if (!kdbpeek(pc - 2 * sizeof(unsigned), &instr))
    335 				return;
    336 			i.word = instr;
    337 			if (i.JType.op == OP_JAL) {
    338 				sym = db_search_symbol(pc - sizeof(int),
    339 				    DB_STGY_ANY, &diff);
    340 				if (sym != DB_SYM_NULL && diff != 0)
    341 					diff += sizeof(int);
    342 			}
    343 		}
    344 		if (sym == DB_SYM_NULL) {
    345 			ra = 0;
    346 			goto done;
    347 		}
    348 		va = pc - diff;
    349 	} else {
    350 #endif /* DDB && _KERNEL */
    351 		/*
    352 		 * Find the beginning of the current subroutine by
    353 		 * scanning backwards from the current PC for the end
    354 		 * of the previous subroutine.
    355 		 *
    356 		 * XXX This won't work well because nowadays gcc is so
    357 		 *     aggressive as to reorder instruction blocks for
    358 		 *     branch-predict. (i.e. 'jr ra' wouldn't indicate
    359 		 *     the end of subroutine)
    360 		 */
    361 		va = pc;
    362 		do {
    363 			va -= sizeof(int);
    364 #ifdef _KERNEL /* XXX crash */
    365 			if (va <= (vaddr_t)verylocore)
    366 				goto finish;
    367 #endif
    368 			if (!kdbpeek(va, &instr))
    369 				return;
    370 			if (instr == MIPS_ERET)
    371 				goto mips3_eret;
    372 		} while (instr != MIPS_JR_RA && instr != MIPS_JR_K0);
    373 		/* skip back over branch & delay slot */
    374 		va += sizeof(int);
    375 mips3_eret:
    376 		va += sizeof(int);
    377 		/* skip over nulls which might separate .o files */
    378 		instr = 0;
    379 		while (instr == 0) {
    380 			if (!kdbpeek(va, &instr))
    381 				return;
    382 			va += sizeof(int);
    383 		}
    384 #if defined(DDB) && defined(_KERNEL)
    385 	}
    386 #endif /* DDB && _KERNEL */
    387 	subr = va;
    388 
    389 	/* scan forwards to find stack size and any saved registers */
    390 	stksize = 0;
    391 	more = 3;
    392 	mask &= 0x40ff0001;	/* if s0-s8 are valid, leave then as valid */
    393 	foundframesize = 0;
    394 	for (va = subr; more; va += sizeof(int),
    395 			      more = (more == 3) ? 3 : more - 1) {
    396 		/* stop if hit our current position */
    397 		if (va >= pc)
    398 			break;
    399 		if (!kdbpeek(va, &instr))
    400 			return;
    401 		i.word = instr;
    402 		switch (i.JType.op) {
    403 		case OP_SPECIAL:
    404 			switch (i.RType.func) {
    405 			case OP_JR:
    406 			case OP_JALR:
    407 				more = 2; /* stop after next instruction */
    408 				break;
    409 
    410 			case OP_ADD:
    411 			case OP_ADDU:
    412 			case OP_DADD:
    413 			case OP_DADDU:
    414 				if (!(mask & (1 << i.RType.rd))
    415 				    || !(mask & (1 << i.RType.rt)))
    416 					break;
    417 				if (i.RType.rd != _R_ZERO)
    418 					break;
    419 				mask |= (1 << i.RType.rs);
    420 				regs[i.RType.rs] = regs[i.RType.rt];
    421 				if (i.RType.func >= OP_DADD)
    422 					break;
    423 				regs[i.RType.rs] = (int32_t)regs[i.RType.rs];
    424 				break;
    425 
    426 			case OP_SYSCALL:
    427 			case OP_BREAK:
    428 				more = 1; /* stop now */
    429 				break;
    430 			}
    431 			break;
    432 
    433 		case OP_REGIMM:
    434 		case OP_J:
    435 		case OP_JAL:
    436 		case OP_BEQ:
    437 		case OP_BNE:
    438 		case OP_BLEZ:
    439 		case OP_BGTZ:
    440 			more = 2; /* stop after next instruction */
    441 			break;
    442 
    443 		case OP_COP0:
    444 		case OP_COP1:
    445 		case OP_COP2:
    446 		case OP_COP3:
    447 			switch (i.RType.rs) {
    448 			case OP_BCx:
    449 			case OP_BCy:
    450 				more = 2; /* stop after next instruction */
    451 			};
    452 			break;
    453 
    454 		case OP_SW:
    455 #if !defined(__mips_o32)
    456 		case OP_SD:
    457 #endif
    458 		{
    459 			size_t size = (i.JType.op == OP_SW) ? 4 : 8;
    460 
    461 			/* look for saved registers on the stack */
    462 			if (i.IType.rs != _R_SP)
    463 				break;
    464 			switch (i.IType.rt) {
    465 			case _R_A0: /* a0 */
    466 			case _R_A1: /* a1 */
    467 			case _R_A2: /* a2 */
    468 			case _R_A3: /* a3 */
    469 			case _R_S0: /* s0 */
    470 			case _R_S1: /* s1 */
    471 			case _R_S2: /* s2 */
    472 			case _R_S3: /* s3 */
    473 			case _R_S4: /* s4 */
    474 			case _R_S5: /* s5 */
    475 			case _R_S6: /* s6 */
    476 			case _R_S7: /* s7 */
    477 			case _R_S8: /* s8 */
    478 			case _R_RA: /* ra */
    479 				regs[i.IType.rt] =
    480 				    kdbrpeek(sp + (int16_t)i.IType.imm, size);
    481 				mask |= (1 << i.IType.rt);
    482 				break;
    483 			}
    484 			break;
    485 		}
    486 
    487 		case OP_ADDI:
    488 		case OP_ADDIU:
    489 #if !defined(__mips_o32)
    490 		case OP_DADDI:
    491 		case OP_DADDIU:
    492 #endif
    493 			/* look for stack pointer adjustment */
    494 			if (i.IType.rs != _R_SP || i.IType.rt != _R_SP)
    495 				break;
    496 			/* don't count pops for mcount */
    497 			if (!foundframesize) {
    498 				stksize = - ((short)i.IType.imm);
    499 				foundframesize = 1;
    500 			}
    501 			break;
    502 		}
    503 	}
    504 done:
    505 	if (mask & (1 << _R_RA))
    506 		ra = regs[_R_RA];
    507 	(*printfn)("%#"PRIxVADDR": %s+%#"PRIxVADDR" (%#"PRIxREGISTER","
    508 	    "%#"PRIxREGISTER",%#"PRIxREGISTER",%#"PRIxREGISTER") "
    509 	    "ra %#"PRIxVADDR" sz %d\n",
    510 	    sp, fn_name(subr), pc - subr,
    511 	    regs[_R_A0], regs[_R_A1], regs[_R_A2], regs[_R_A3],
    512 	    ra, stksize);
    513 
    514 	if (ra) {
    515 		if (pc == ra && stksize == 0)
    516 			(*printfn)("stacktrace: loop!\n");
    517 		else {
    518 			pc = ra;
    519 			sp += stksize;
    520 			ra = 0;
    521 			goto loop;
    522 		}
    523 	} else {
    524 finish:
    525 #ifdef _KERNEL
    526 		(*printfn)("User-level: pid %d.%d\n",
    527 		    curlwp->l_proc->p_pid, curlwp->l_lid);
    528 #else
    529 		(*printfn)("User-level: FIXME\n");
    530 #endif
    531 	}
    532 }
    533 
    534 #endif /* DEBUG || DDB || KGDB || geo */
    535 #endif /* DDB_TRACE */
    536