xref: /openbsd-src/sys/arch/powerpc/ddb/db_trace.c (revision 949c1c4ec8cc03255798b09f6078e1d0aed70a6a)
1*949c1c4eSmiod /*	$OpenBSD: db_trace.c,v 1.21 2024/11/07 16:02:29 miod Exp $	*/
284c41355Smiod /*	$NetBSD: db_trace.c,v 1.15 1996/02/22 23:23:41 gwr Exp $	*/
384c41355Smiod 
484c41355Smiod /*
584c41355Smiod  * Mach Operating System
684c41355Smiod  * Copyright (c) 1992 Carnegie Mellon University
784c41355Smiod  * All Rights Reserved.
884c41355Smiod  *
984c41355Smiod  * Permission to use, copy, modify and distribute this software and its
1084c41355Smiod  * documentation is hereby granted, provided that both the copyright
1184c41355Smiod  * notice and this permission notice appear in all copies of the
1284c41355Smiod  * software, derivative works or modified versions, and any portions
1384c41355Smiod  * thereof, and that both notices appear in supporting documentation.
1484c41355Smiod  *
1584c41355Smiod  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
1684c41355Smiod  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
1784c41355Smiod  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
1884c41355Smiod  *
1984c41355Smiod  * Carnegie Mellon requests users of this software to return to
2084c41355Smiod  *
2184c41355Smiod  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
2284c41355Smiod  *  School of Computer Science
2384c41355Smiod  *  Carnegie Mellon University
2484c41355Smiod  *  Pittsburgh PA 15213-3890
2584c41355Smiod  *
2684c41355Smiod  * any improvements or extensions that they make and grant Carnegie Mellon
2784c41355Smiod  * the rights to redistribute these changes.
2884c41355Smiod  */
2984c41355Smiod 
3084c41355Smiod #include <sys/param.h>
3184c41355Smiod #include <sys/systm.h>
3284c41355Smiod #include <sys/proc.h>
33390e38f1Smpi #include <sys/user.h>
342877cd17Smpi #include <sys/stacktrace.h>
35390e38f1Smpi 
36390e38f1Smpi #include <uvm/uvm_extern.h>
3784c41355Smiod 
3884c41355Smiod #include <machine/db_machdep.h>
3984c41355Smiod #include <machine/signal.h>
4084c41355Smiod #include <machine/pcb.h>
41390e38f1Smpi #include <machine/pmap.h>
4284c41355Smiod 
4384c41355Smiod #include <ddb/db_access.h>
4484c41355Smiod #include <ddb/db_sym.h>
4584c41355Smiod #include <ddb/db_variables.h>
4684c41355Smiod #include <ddb/db_interface.h>
4784c41355Smiod #include <ddb/db_output.h>
4884c41355Smiod 
498070687fSjason db_regs_t ddb_regs;
508070687fSjason 
5184c41355Smiod struct db_variable db_regs[] = {
52f12e1735Smpi 	{ "r0",  (long *)&ddb_regs.fixreg[0],	FCN_NULL },
53f12e1735Smpi 	{ "r1",  (long *)&ddb_regs.fixreg[1],	FCN_NULL },
54f12e1735Smpi 	{ "r2",  (long *)&ddb_regs.fixreg[2],	FCN_NULL },
55f12e1735Smpi 	{ "r3",  (long *)&ddb_regs.fixreg[3],	FCN_NULL },
56f12e1735Smpi 	{ "r4",  (long *)&ddb_regs.fixreg[4],	FCN_NULL },
57f12e1735Smpi 	{ "r5",  (long *)&ddb_regs.fixreg[5],	FCN_NULL },
58f12e1735Smpi 	{ "r6",  (long *)&ddb_regs.fixreg[6],	FCN_NULL },
59f12e1735Smpi 	{ "r7",  (long *)&ddb_regs.fixreg[7],	FCN_NULL },
60f12e1735Smpi 	{ "r8",  (long *)&ddb_regs.fixreg[8],	FCN_NULL },
61f12e1735Smpi 	{ "r9",  (long *)&ddb_regs.fixreg[9],	FCN_NULL },
62f12e1735Smpi 	{ "r10", (long *)&ddb_regs.fixreg[10],	FCN_NULL },
63f12e1735Smpi 	{ "r11", (long *)&ddb_regs.fixreg[11],	FCN_NULL },
64f12e1735Smpi 	{ "r12", (long *)&ddb_regs.fixreg[12],	FCN_NULL },
65f12e1735Smpi 	{ "r13", (long *)&ddb_regs.fixreg[13],	FCN_NULL },
662987d5a7Sgkoehler 	{ "r14", (long *)&ddb_regs.fixreg[14],	FCN_NULL },
672987d5a7Sgkoehler 	{ "r15", (long *)&ddb_regs.fixreg[15],	FCN_NULL },
682987d5a7Sgkoehler 	{ "r16", (long *)&ddb_regs.fixreg[16],	FCN_NULL },
69f12e1735Smpi 	{ "r17", (long *)&ddb_regs.fixreg[17],	FCN_NULL },
70f12e1735Smpi 	{ "r18", (long *)&ddb_regs.fixreg[18],	FCN_NULL },
71f12e1735Smpi 	{ "r19", (long *)&ddb_regs.fixreg[19],	FCN_NULL },
72f12e1735Smpi 	{ "r20", (long *)&ddb_regs.fixreg[20],	FCN_NULL },
73f12e1735Smpi 	{ "r21", (long *)&ddb_regs.fixreg[21],	FCN_NULL },
74f12e1735Smpi 	{ "r22", (long *)&ddb_regs.fixreg[22],	FCN_NULL },
75f12e1735Smpi 	{ "r23", (long *)&ddb_regs.fixreg[23],	FCN_NULL },
76f12e1735Smpi 	{ "r24", (long *)&ddb_regs.fixreg[24],	FCN_NULL },
77f12e1735Smpi 	{ "r25", (long *)&ddb_regs.fixreg[25],	FCN_NULL },
78f12e1735Smpi 	{ "r26", (long *)&ddb_regs.fixreg[26],	FCN_NULL },
79f12e1735Smpi 	{ "r27", (long *)&ddb_regs.fixreg[27],	FCN_NULL },
80f12e1735Smpi 	{ "r28", (long *)&ddb_regs.fixreg[28],	FCN_NULL },
81f12e1735Smpi 	{ "r29", (long *)&ddb_regs.fixreg[29],	FCN_NULL },
82f12e1735Smpi 	{ "r30", (long *)&ddb_regs.fixreg[30],	FCN_NULL },
83f12e1735Smpi 	{ "r31", (long *)&ddb_regs.fixreg[31],	FCN_NULL },
84f12e1735Smpi 	{ "lr",  (long *)&ddb_regs.lr,		FCN_NULL },
85f12e1735Smpi 	{ "cr",  (long *)&ddb_regs.cr,		FCN_NULL },
86f12e1735Smpi 	{ "xer", (long *)&ddb_regs.xer,		FCN_NULL },
87f12e1735Smpi 	{ "ctr", (long *)&ddb_regs.ctr,		FCN_NULL },
88f12e1735Smpi 	{ "iar", (long *)&ddb_regs.srr0,	FCN_NULL },
89f12e1735Smpi 	{ "msr", (long *)&ddb_regs.srr1,	FCN_NULL },
902987d5a7Sgkoehler 	{ "dar", (long *)&ddb_regs.dar,		FCN_NULL },
912987d5a7Sgkoehler 	{ "dsisr", (long *)&ddb_regs.dsisr,	FCN_NULL },
9284c41355Smiod };
93eaf55909Sdrahn 
9485882e82Sjasper struct db_variable *db_eregs = db_regs + nitems(db_regs);
9584c41355Smiod 
9684c41355Smiod /*
9784c41355Smiod  * this is probably hackery.
9884c41355Smiod  */
9984c41355Smiod void
10084c41355Smiod db_save_regs(struct trapframe *frame)
10184c41355Smiod {
102f12e1735Smpi 	bcopy(frame, &ddb_regs, sizeof (struct trapframe));
10384c41355Smiod }
10484c41355Smiod 
105390e38f1Smpi /* from locore.S */
10652de38dfSmpi extern vaddr_t trapexit;
107390e38f1Smpi #define	INTSTK		(8*1024)	/* 8K interrupt stack */
10884c41355Smiod 
109390e38f1Smpi #define	INKERNEL(va)	(((vaddr_t)(va)) >= VM_MIN_KERNEL_ADDRESS &&	\
110390e38f1Smpi 			((vaddr_t)(va)) < VM_MAX_KERNEL_ADDRESS)
11184c41355Smiod 
11295573559Sgkoehler #define	ININTSTK(va)	db_in_interrupt_stack((vaddr_t)(va))
11395573559Sgkoehler 
11495573559Sgkoehler int
11595573559Sgkoehler db_in_interrupt_stack(vaddr_t va)
11695573559Sgkoehler {
11795573559Sgkoehler 	struct cpu_info *ci;
11895573559Sgkoehler 	CPU_INFO_ITERATOR cii;
11995573559Sgkoehler 	vaddr_t stack;
12095573559Sgkoehler 
12195573559Sgkoehler 	CPU_INFO_FOREACH(cii, ci) {
12295573559Sgkoehler 		stack = (vaddr_t)ci->ci_intstk;
12395573559Sgkoehler 		if (va >= stack - INTSTK && va < stack)
12495573559Sgkoehler 			return 1;
12595573559Sgkoehler 	}
12695573559Sgkoehler 	return 0;
12795573559Sgkoehler }
128eaf55909Sdrahn 
12984c41355Smiod /*
13084c41355Smiod  *	Frame tracing.
13184c41355Smiod  */
13284c41355Smiod void
133eaf55909Sdrahn db_stack_trace_print(db_expr_t addr, int have_addr, db_expr_t count,
134eaf55909Sdrahn     char *modif, int (*pr)(const char *, ...))
13584c41355Smiod {
13652de38dfSmpi 	vaddr_t		 lr, sp, lastsp, *db_fp_args;
137390e38f1Smpi 	db_expr_t	 offset;
13862781896Smpi 	Elf_Sym		*sym;
139*949c1c4eSmiod 	const char	*name;
140390e38f1Smpi 	char		 c, *cp = modif;
14169993134Sjasper 	int		 i, narg, trace_proc = 0;
14284c41355Smiod 
143390e38f1Smpi 	while ((c = *cp++) != 0) {
1447c8c9e97Smpi 		if (c == 't')
145390e38f1Smpi 			trace_proc = 1;
14684c41355Smiod 	}
147390e38f1Smpi 
148390e38f1Smpi 	if (!have_addr) {
149f12e1735Smpi 		sp = ddb_regs.fixreg[1];
150f12e1735Smpi 		lr = ddb_regs.srr0;
151390e38f1Smpi 	} else {
152390e38f1Smpi 		if (trace_proc) {
15369e7eddbSmpi 			struct proc *p = tfind((pid_t)addr);
154390e38f1Smpi 			if (p == NULL) {
1554c5c9f90Sjasper 				(*pr) ("not found\n");
156390e38f1Smpi 				return;
15784c41355Smiod 			}
158390e38f1Smpi 			addr = p->p_addr->u_pcb.pcb_sp;
159390e38f1Smpi 		}
160390e38f1Smpi 		sp = addr;
16152de38dfSmpi 		db_read_bytes(sp + 4, sizeof(vaddr_t), (char *)&lr);
162390e38f1Smpi 	}
163390e38f1Smpi 
164390e38f1Smpi 	while (count && sp != 0) {
165390e38f1Smpi 		/*
166390e38f1Smpi 		 * lr contains the return address, so adjust its value
167390e38f1Smpi 		 * to display the offset of the calling address.
168390e38f1Smpi 		 */
169390e38f1Smpi 		sym = db_search_symbol(lr - 4, DB_STGY_ANY, &offset);
170390e38f1Smpi 		db_symbol_values(sym, &name, NULL);
171390e38f1Smpi 
172390e38f1Smpi 		if (name == NULL || strcmp(name, "end") == 0) {
173390e38f1Smpi 			(*pr)("at 0x%lx", lr - 4);
174390e38f1Smpi 		} else {
17569993134Sjasper 			narg = db_ctf_func_numargs(sym);
17669993134Sjasper 			if (narg < 0 || narg > 8)
17769993134Sjasper 				narg = 8;
17869993134Sjasper 
17969993134Sjasper 			(*pr)("%s(", name);
18069993134Sjasper 
18169993134Sjasper 			if (narg > 0) {
18252de38dfSmpi 				db_fp_args = (vaddr_t *)(sp + 8);
18369993134Sjasper 
18469993134Sjasper 				for (i = 0; i < narg; i++) {
18569993134Sjasper 					(*pr)("%lx", db_fp_args[i]);
18669993134Sjasper 					if (i != (narg-1))
18769993134Sjasper 						(*pr)(",");
18869993134Sjasper 				}
18969993134Sjasper 			}
19069993134Sjasper 
19169993134Sjasper 			(*pr)(") at ");
192390e38f1Smpi 			db_printsym(lr - 4, DB_STGY_PROC, pr);
193390e38f1Smpi 		}
194390e38f1Smpi 		(*pr)("\n");
195390e38f1Smpi 
196390e38f1Smpi 		lastsp = sp;
197390e38f1Smpi 
198390e38f1Smpi 		/*
199390e38f1Smpi 		 * Abuse the fact that the return address of the trap()
200390e38f1Smpi 		 * function is always 'trapexit'.
201390e38f1Smpi 		 */
20252de38dfSmpi 		if (lr == (vaddr_t)&trapexit) {
203390e38f1Smpi 			struct trapframe *tf = (struct trapframe *)(sp + 8);
204390e38f1Smpi 			uint32_t code = tf->fixreg[0];
205390e38f1Smpi 			uint32_t type = tf->exc;
206390e38f1Smpi 
207390e38f1Smpi 			if (tf->srr1 & PSL_PR)
208390e38f1Smpi 				type |= EXC_USER;
209390e38f1Smpi 
210390e38f1Smpi 			if (type == (EXC_SC|EXC_USER))
211390e38f1Smpi 				(*pr)("--- syscall (number %d) ---\n", code);
212390e38f1Smpi 			else
213390e38f1Smpi 				(*pr)("--- trap (type 0x%x) ---\n", type);
214390e38f1Smpi 		}
215390e38f1Smpi 
21652de38dfSmpi 		db_read_bytes(sp, sizeof(vaddr_t), (char *)&sp);
217390e38f1Smpi 		if (sp == 0)
218390e38f1Smpi 			break;
219390e38f1Smpi 
22052de38dfSmpi 		db_read_bytes(sp + 4, sizeof(vaddr_t), (char *)&lr);
221390e38f1Smpi 
222390e38f1Smpi 		if (INKERNEL(sp)) {
223390e38f1Smpi 			if (sp <= lastsp) {
224390e38f1Smpi 				(*pr)("Bad frame pointer: 0x%lx\n", sp);
225390e38f1Smpi 				break;
226390e38f1Smpi 			}
227390e38f1Smpi 
228390e38f1Smpi 			if (ININTSTK(lastsp))
229390e38f1Smpi 				(*pr)("--- interrupt ---\n");
230390e38f1Smpi 
231390e38f1Smpi 		} else  {
232390e38f1Smpi 			if (!ININTSTK(sp)) {
233390e38f1Smpi 				(*pr)("End of kernel: 0x%lx\n", sp);
234390e38f1Smpi 				break;
235390e38f1Smpi 			}
236390e38f1Smpi 		}
237390e38f1Smpi 		--count;
238390e38f1Smpi 	}
239390e38f1Smpi 	(*pr)("end trace frame: 0x%lx, count: %d\n", sp, count);
24084c41355Smiod }
2412877cd17Smpi 
2422877cd17Smpi void
2432877cd17Smpi stacktrace_save_at(struct stacktrace *st, unsigned int skip)
2442877cd17Smpi {
2452877cd17Smpi 	vaddr_t		 lr, sp, lastsp;
2462877cd17Smpi 
2472877cd17Smpi 	sp = (vaddr_t)__builtin_frame_address(0);
2482877cd17Smpi 	if (!INKERNEL(sp) && !ININTSTK(sp))
2492877cd17Smpi 		return;
2502877cd17Smpi 
2512877cd17Smpi 	st->st_count = 0;
2522877cd17Smpi 	while (st->st_count < STACKTRACE_MAX) {
2532877cd17Smpi 		lr = *(vaddr_t *)(sp + 4) - 4;
2542877cd17Smpi 		if (lr & 3)
2552877cd17Smpi 			break;
2562877cd17Smpi 
2572877cd17Smpi 		if (skip == 0)
2582877cd17Smpi 			st->st_pc[st->st_count++] = lr;
2592877cd17Smpi 		else
2602877cd17Smpi 			skip--;
2612877cd17Smpi 
2622877cd17Smpi 		lastsp = sp;
2632877cd17Smpi 		sp = *(vaddr_t *)sp;
2642877cd17Smpi 
2652877cd17Smpi 		if ((sp == 0) || (sp & 3) || (sp <= lastsp))
2662877cd17Smpi 			break;
2672877cd17Smpi 		if (!INKERNEL(sp) && !ININTSTK(sp))
2682877cd17Smpi 			break;
2692877cd17Smpi 	}
2702877cd17Smpi }
271a28bb56fSclaudio 
272a28bb56fSclaudio void
273a28bb56fSclaudio stacktrace_save_utrace(struct stacktrace *st)
274a28bb56fSclaudio {
275a28bb56fSclaudio 	st->st_count = 0;
276a28bb56fSclaudio }
277