Home | History | Annotate | Line # | Download | only in powerpc
      1 /*	$NetBSD: db_trace.c,v 1.63 2023/04/13 06:39:23 riastradh Exp $	*/
      2 /*	$OpenBSD: db_trace.c,v 1.3 1997/03/21 02:10:48 niklas Exp $	*/
      3 
      4 /*
      5  * Mach Operating System
      6  * Copyright (c) 1992 Carnegie Mellon University
      7  * All Rights Reserved.
      8  *
      9  * Permission to use, copy, modify and distribute this software and its
     10  * documentation is hereby granted, provided that both the copyright
     11  * notice and this permission notice appear in all copies of the
     12  * software, derivative works or modified versions, and any portions
     13  * thereof, and that both notices appear in supporting documentation.
     14  *
     15  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     16  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
     17  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     18  *
     19  * Carnegie Mellon requests users of this software to return to
     20  *
     21  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     22  *  School of Computer Science
     23  *  Carnegie Mellon University
     24  *  Pittsburgh PA 15213-3890
     25  *
     26  * any improvements or extensions that they make and grant Carnegie Mellon
     27  * the rights to redistribute these changes.
     28  */
     29 
     30 #include <sys/cdefs.h>
     31 __KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.63 2023/04/13 06:39:23 riastradh Exp $");
     32 
     33 #ifdef _KERNEL_OPT
     34 #include "opt_ppcarch.h"
     35 #endif
     36 
     37 #include <sys/param.h>
     38 #include <sys/proc.h>
     39 #include <sys/kernel.h>
     40 
     41 #include <uvm/uvm_extern.h>
     42 
     43 #include <machine/db_machdep.h>
     44 #include <machine/pmap.h>
     45 
     46 #include <powerpc/pcb.h>
     47 #include <powerpc/psl.h>
     48 #include <powerpc/spr.h>
     49 #if defined (PPC_OEA) || defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE)
     50 #include <powerpc/oea/spr.h>
     51 #elif defined(PPC_IBM4XX)
     52 #include <powerpc/ibm4xx/spr.h>
     53 #elif defined(PPC_BOOKE)
     54 #include <powerpc/booke/spr.h>
     55 #else
     56 #ifdef _KERNEL
     57 #error unknown powerpc variants
     58 #endif
     59 #endif
     60 
     61 #ifndef _KERNEL			/* crash(8) */
     62 #include <unistd.h>
     63 #define	PAGE_SIZE	((unsigned)sysconf(_SC_PAGESIZE))
     64 #endif
     65 
     66 #include <ddb/db_access.h>
     67 #include <ddb/db_interface.h>
     68 #include <ddb/db_proc.h>
     69 #include <ddb/db_sym.h>
     70 #include <ddb/db_variables.h>
     71 
     72 #define	R(P)								      \
     73 ({									      \
     74 	__typeof__(*(P)) __db_tmp;					      \
     75 	db_read_bytes((db_addr_t)(P), sizeof(*(P)), (char *)&__db_tmp);	      \
     76 	__db_tmp;							      \
     77 })
     78 
     79 const struct db_variable db_regs[] = {
     80 	{ "r0",  (long *)&ddb_regs.r[0],  FCN_NULL, NULL },
     81 	{ "r1",  (long *)&ddb_regs.r[1],  FCN_NULL, NULL },
     82 	{ "r2",  (long *)&ddb_regs.r[2],  FCN_NULL, NULL },
     83 	{ "r3",  (long *)&ddb_regs.r[3],  FCN_NULL, NULL },
     84 	{ "r4",  (long *)&ddb_regs.r[4],  FCN_NULL, NULL },
     85 	{ "r5",  (long *)&ddb_regs.r[5],  FCN_NULL, NULL },
     86 	{ "r6",  (long *)&ddb_regs.r[6],  FCN_NULL, NULL },
     87 	{ "r7",  (long *)&ddb_regs.r[7],  FCN_NULL, NULL },
     88 	{ "r8",  (long *)&ddb_regs.r[8],  FCN_NULL, NULL },
     89 	{ "r9",  (long *)&ddb_regs.r[9],  FCN_NULL, NULL },
     90 	{ "r10", (long *)&ddb_regs.r[10], FCN_NULL, NULL },
     91 	{ "r11", (long *)&ddb_regs.r[11], FCN_NULL, NULL },
     92 	{ "r12", (long *)&ddb_regs.r[12], FCN_NULL, NULL },
     93 	{ "r13", (long *)&ddb_regs.r[13], FCN_NULL, NULL },
     94 	{ "r14", (long *)&ddb_regs.r[14], FCN_NULL, NULL },
     95 	{ "r15", (long *)&ddb_regs.r[15], FCN_NULL, NULL },
     96 	{ "r16", (long *)&ddb_regs.r[16], FCN_NULL, NULL },
     97 	{ "r17", (long *)&ddb_regs.r[17], FCN_NULL, NULL },
     98 	{ "r18", (long *)&ddb_regs.r[18], FCN_NULL, NULL },
     99 	{ "r19", (long *)&ddb_regs.r[19], FCN_NULL, NULL },
    100 	{ "r20", (long *)&ddb_regs.r[20], FCN_NULL, NULL },
    101 	{ "r21", (long *)&ddb_regs.r[21], FCN_NULL, NULL },
    102 	{ "r22", (long *)&ddb_regs.r[22], FCN_NULL, NULL },
    103 	{ "r23", (long *)&ddb_regs.r[23], FCN_NULL, NULL },
    104 	{ "r24", (long *)&ddb_regs.r[24], FCN_NULL, NULL },
    105 	{ "r25", (long *)&ddb_regs.r[25], FCN_NULL, NULL },
    106 	{ "r26", (long *)&ddb_regs.r[26], FCN_NULL, NULL },
    107 	{ "r27", (long *)&ddb_regs.r[27], FCN_NULL, NULL },
    108 	{ "r28", (long *)&ddb_regs.r[28], FCN_NULL, NULL },
    109 	{ "r29", (long *)&ddb_regs.r[29], FCN_NULL, NULL },
    110 	{ "r30", (long *)&ddb_regs.r[30], FCN_NULL, NULL },
    111 	{ "r31", (long *)&ddb_regs.r[31], FCN_NULL, NULL },
    112 	{ "iar", (long *)&ddb_regs.iar,   FCN_NULL, NULL },
    113 	{ "msr", (long *)&ddb_regs.msr,   FCN_NULL, NULL },
    114 	{ "lr",  (long *)&ddb_regs.lr,    FCN_NULL, NULL },
    115 	{ "ctr", (long *)&ddb_regs.ctr,   FCN_NULL, NULL },
    116 	{ "cr",  (long *)&ddb_regs.cr,    FCN_NULL, NULL },
    117 	{ "xer", (long *)&ddb_regs.xer,   FCN_NULL, NULL },
    118 	{ "mq",  (long *)&ddb_regs.mq,    FCN_NULL, NULL },
    119 #ifdef PPC_IBM4XX		/* XXX crash(8) */
    120 	{ "dear", (long *)&ddb_regs.dear, FCN_NULL, NULL },
    121 	{ "esr", (long *)&ddb_regs.esr,   FCN_NULL, NULL },
    122 	{ "pid", (long *)&ddb_regs.pid,   FCN_NULL, NULL },
    123 #endif
    124 };
    125 const struct db_variable * const db_eregs = db_regs + sizeof (db_regs)/sizeof (db_regs[0]);
    126 
    127 /*
    128  *	Frame tracing.
    129  */
    130 void
    131 db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count,
    132 	const char *modif, void (*pr)(const char *, ...))
    133 {
    134 	db_addr_t frame, lr, *args;
    135 	db_expr_t diff;
    136 	db_sym_t sym;
    137 	const char *symname;
    138 	const char *cp = modif;
    139 	char c;
    140 	bool kernel_only = true;
    141 	bool trace_thread = false;
    142 	bool lwpaddr = false;
    143 #ifdef _KERNEL
    144 	extern int trapexit[], sctrapexit[];
    145 #ifdef PPC_BOOKE
    146 	extern int intrcall[];
    147 #endif
    148 #else
    149 	extern void *trapexit, *sctrapexit, *intrcall;
    150 #endif
    151 	bool full = false;
    152 	bool in_kernel = true;
    153 
    154 	while ((c = *cp++) != 0) {
    155 		if (c == 'a') {
    156 			lwpaddr = true;
    157 			trace_thread = true;
    158 		}
    159 		if (c == 't')
    160 			trace_thread = true;
    161 		if (c == 'u')
    162 			kernel_only = false;
    163 		if (c == 'f')
    164 			full = true;
    165 	}
    166 
    167 	if (have_addr) {
    168 		if (trace_thread) {
    169 			struct proc *p;
    170 			struct lwp *l;
    171 			struct pcb *pcb;
    172 
    173 			if (lwpaddr) {
    174 				l = (struct lwp *)addr;
    175 				p = R(&l->l_proc);
    176 				(*pr)("trace: pid %d ", R(&p->p_pid));
    177 			} else {
    178 				(*pr)("trace: pid %d ", (int)addr);
    179 				p = db_proc_find((pid_t)addr);
    180 				if (p == NULL) {
    181 					(*pr)("not found\n");
    182 					return;
    183 				}
    184 				l = R(&LIST_FIRST(&p->p_lwps));
    185 				if (l == NULL) {
    186 					(*pr)("trace: no LWP?\n");
    187 					return;
    188 				}
    189 			}
    190 			(*pr)("lid %d ", R(&l->l_lid));
    191 			pcb = R(&l->l_addr); /* lwp_getpcb */
    192 			frame = (db_addr_t)R(&pcb->pcb_sp);
    193 			(*pr)("at %p\n", frame);
    194 		} else
    195 			frame = (db_addr_t)addr;
    196 	} else {
    197 		frame = (db_addr_t)ddb_regs.r[1];
    198 	}
    199 	for (;;) {
    200 		if (frame < PAGE_SIZE)
    201 			break;
    202 		frame = R((db_addr_t *)frame);
    203 	    next_frame:
    204 		args = (db_addr_t *)(frame + 8);
    205 		if (frame < PAGE_SIZE)
    206 			break;
    207 	        if (count-- == 0)
    208 			break;
    209 
    210 		lr = R((db_addr_t *)(frame + 4)) - 4;
    211 		if ((lr & 3) || (lr < 0x100)) {
    212 			(*pr)("saved LR(0x%x) is invalid.", lr);
    213 			break;
    214 		}
    215 
    216 		(*pr)("0x%08lx: ", frame);
    217 		if (lr + 4 == (db_addr_t) trapexit ||
    218 #if !defined(_KERNEL) || defined(PPC_BOOKE) /* XXX crash(8) */
    219 		    lr + 4 == (db_addr_t) intrcall ||
    220 #endif
    221 		    lr + 4 == (db_addr_t) sctrapexit) {
    222 			const char *trapstr;
    223 			struct trapframe *tf =
    224 			    &((struct ktrapframe *)frame)->ktf_tf;
    225 			(*pr)("%s ",
    226 			    R(&tf->tf_srr1) & PSL_PR ? "user" : "kernel");
    227 			if (lr + 4 == (db_addr_t) sctrapexit) {
    228 				(*pr)("SC trap #%d by ", R(&tf->tf_fixreg[0]));
    229 				goto print_trap;
    230 			}
    231 			switch (R(&tf->tf_exc)) {
    232 			case EXC_DSI:
    233 #ifdef PPC_OEA			/* XXX crash(8) */
    234 				(*pr)("DSI %s trap @ %#x by ",
    235 				    (R(&tf->tf_dsisr) & DSISR_STORE
    236 					? "write"
    237 					: "read"),
    238 				    R(&tf->tf_dar));
    239 #endif
    240 #ifdef PPC_IBM4XX		/* XXX crash(8) */
    241 				trapstr = "DSI";
    242 dsi:
    243 				(*pr)("%s %s trap @ %#x by ", trapstr,
    244 				    (R(&tf->tf_esr) & ESR_DST
    245 					? "write"
    246 					: "read"),
    247 				    R(&tf->tf_dear));
    248 #endif
    249 				goto print_trap;
    250 			case EXC_ALI:
    251 #ifdef PPC_OEA			/* XXX crash(8) */
    252 				(*pr)("ALI trap @ %#x (DSISR %#x) ",
    253 				    R(&tf->tf_dar), R(&tf->tf_dsisr));
    254 				goto print_trap;
    255 #else
    256 				trapstr = "ALI"; break;
    257 #endif
    258 			case EXC_ISI: trapstr = "ISI"; break;
    259 			case EXC_PGM: trapstr = "PGM"; break;
    260 			case EXC_SC: trapstr = "SC"; break;
    261 			case EXC_EXI: trapstr = "EXI"; break;
    262 			case EXC_MCHK: trapstr = "MCHK"; break;
    263 			case EXC_VEC: trapstr = "VEC"; break;
    264 			case EXC_FPU: trapstr = "FPU"; break;
    265 			case EXC_FPA: trapstr = "FPA"; break;
    266 			case EXC_DECR: trapstr = "DECR"; break;
    267 			case EXC_BPT: trapstr = "BPT"; break;
    268 			case EXC_TRC: trapstr = "TRC"; break;
    269 			case EXC_RUNMODETRC: trapstr = "RUNMODETRC"; break;
    270 			case EXC_PERF: trapstr = "PERF"; break;
    271 			case EXC_SMI: trapstr = "SMI"; break;
    272 			case EXC_RST: trapstr = "RST"; break;
    273 			case EXC_DTMISS: trapstr = "DTMISS";
    274 #ifdef PPC_IBM4XX		/* XXX crash(8) */
    275 				goto dsi;
    276 #endif
    277 				break;
    278 			case EXC_ITMISS: trapstr = "ITMISS"; break;
    279 			case EXC_FIT: trapstr = "FIT"; break;
    280 			case EXC_PIT: trapstr = "PIT"; break;
    281 			case EXC_WDOG: trapstr = "WDOG"; break;
    282 			default: trapstr = NULL; break;
    283 			}
    284 			if (trapstr != NULL) {
    285 				(*pr)("%s trap by ", trapstr);
    286 			} else {
    287 				(*pr)("trap %#x by ", R(&tf->tf_exc));
    288 			}
    289 		   print_trap:
    290 			lr = (db_addr_t)R(&tf->tf_srr0);
    291 			diff = 0;
    292 			symname = NULL;
    293 			if (in_kernel && (R(&tf->tf_srr1) & PSL_PR) == 0) {
    294 				sym = db_search_symbol(lr, DB_STGY_ANY, &diff);
    295 				db_symbol_values(sym, &symname, 0);
    296 			}
    297 			if (symname == NULL || !strcmp(symname, "end")) {
    298 				(*pr)("%p: srr1=%#x\n", lr, R(&tf->tf_srr1));
    299 			} else {
    300 				(*pr)("%s+%#x: srr1=%#x\n", symname,
    301 				    diff, R(&tf->tf_srr1));
    302 			}
    303 			(*pr)("%-10s  r1=%#x cr=%#x xer=%#x ctr=%#x",
    304 			    "",
    305 			    R(&tf->tf_fixreg[1]),
    306 			    R(&tf->tf_cr),
    307 			    R(&tf->tf_xer),
    308 			    R(&tf->tf_ctr));
    309 #ifdef PPC_OEA			/* XXX crash(8) */
    310 			if (R(&tf->tf_exc) == EXC_DSI)
    311 				(*pr)(" dsisr=%#x", R(&tf->tf_dsisr));
    312 #ifdef PPC_OEA601		/* XXX crash(8) */
    313 			if ((mfpvr() >> 16) == MPC601) /* XXX crash(8) */
    314 				(*pr)(" mq=%#x", R(&tf->tf_mq));
    315 #endif /* PPC_OEA601 */
    316 #endif /* PPC_OEA */
    317 #ifdef PPC_IBM4XX		/* XXX crash(8) */
    318 			if (R(&tf->tf_exc) == EXC_DSI ||
    319 			    R(&tf->tf_exc) == EXC_DTMISS)
    320 				(*pr)(" dear=%#x", R(&tf->tf_dear));
    321 			(*pr)(" esr=%#x pid=%#x", R(&tf->tf_esr),
    322 			    R(&tf->tf_pid));
    323 #endif
    324 			(*pr)("\n");
    325 			frame = (db_addr_t)R(&tf->tf_fixreg[1]);
    326 			in_kernel = !(R(&tf->tf_srr1) & PSL_PR);
    327 			if (kernel_only && !in_kernel)
    328 				break;
    329 			goto next_frame;
    330 		}
    331 
    332 		diff = 0;
    333 		symname = NULL;
    334 		if (in_kernel) {
    335 			sym = db_search_symbol(lr, DB_STGY_ANY, &diff);
    336 			db_symbol_values(sym, &symname, 0);
    337 		}
    338 		if (symname == NULL || !strcmp(symname, "end"))
    339 			(*pr)("at %p", lr);
    340 		else
    341 			(*pr)("at %s+%#x", symname, diff);
    342 		if (full)
    343 			/* Print all the args stored in that stackframe. */
    344 			(*pr)("(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)",
    345 			    R(&args[0]), R(&args[1]), R(&args[2]), R(&args[3]),
    346 			    R(&args[4]), R(&args[5]), R(&args[6]), R(&args[7]));
    347 		(*pr)("\n");
    348 	}
    349 }
    350