Home | History | Annotate | Line # | Download | only in m68k
      1 /*	$NetBSD: db_trace.c,v 1.63 2023/09/26 14:33:55 tsutsui Exp $	*/
      2 
      3 /*
      4  * Mach Operating System
      5  * Copyright (c) 1992 Carnegie Mellon University
      6  * All Rights Reserved.
      7  *
      8  * Permission to use, copy, modify and distribute this software and its
      9  * documentation is hereby granted, provided that both the copyright
     10  * notice and this permission notice appear in all copies of the
     11  * software, derivative works or modified versions, and any portions
     12  * thereof, and that both notices appear in supporting documentation.
     13  *
     14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
     16  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     17  *
     18  * Carnegie Mellon requests users of this software to return to
     19  *
     20  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     21  *  School of Computer Science
     22  *  Carnegie Mellon University
     23  *  Pittsburgh PA 15213-3890
     24  *
     25  * any improvements or extensions that they make and grant Carnegie Mellon
     26  * the rights to redistribute these changes.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.63 2023/09/26 14:33:55 tsutsui Exp $");
     31 
     32 #include <sys/param.h>
     33 #include <sys/proc.h>
     34 #include <sys/systm.h>
     35 
     36 #include <machine/db_machdep.h>
     37 
     38 #include <ddb/db_interface.h>
     39 #include <ddb/db_output.h>
     40 #include <ddb/db_access.h>
     41 #include <ddb/db_sym.h>
     42 #include <ddb/db_variables.h>
     43 
     44 /*
     45  * Register list
     46  */
     47 static int db_var_short(const struct db_variable *, db_expr_t *, int);
     48 
     49 const struct db_variable db_regs[] = {
     50 	/* D0-D7 */
     51 	{ "d0",	(long *)&ddb_regs.tf_regs[0],	FCN_NULL, NULL },
     52 	{ "d1",	(long *)&ddb_regs.tf_regs[1],	FCN_NULL, NULL },
     53 	{ "d2",	(long *)&ddb_regs.tf_regs[2],	FCN_NULL, NULL },
     54 	{ "d3",	(long *)&ddb_regs.tf_regs[3],	FCN_NULL, NULL },
     55 	{ "d4",	(long *)&ddb_regs.tf_regs[4],	FCN_NULL, NULL },
     56 	{ "d5",	(long *)&ddb_regs.tf_regs[5],	FCN_NULL, NULL },
     57 	{ "d6",	(long *)&ddb_regs.tf_regs[6],	FCN_NULL, NULL },
     58 	{ "d7",	(long *)&ddb_regs.tf_regs[7],	FCN_NULL, NULL },
     59 	/* A0-A7 */
     60 	{ "a0",	(long *)&ddb_regs.tf_regs[8+0],	FCN_NULL, NULL },
     61 	{ "a1",	(long *)&ddb_regs.tf_regs[8+1],	FCN_NULL, NULL },
     62 	{ "a2",	(long *)&ddb_regs.tf_regs[8+2],	FCN_NULL, NULL },
     63 	{ "a3",	(long *)&ddb_regs.tf_regs[8+3],	FCN_NULL, NULL },
     64 	{ "a4",	(long *)&ddb_regs.tf_regs[8+4],	FCN_NULL, NULL },
     65 	{ "a5",	(long *)&ddb_regs.tf_regs[8+5],	FCN_NULL, NULL },
     66 	{ "a6",	(long *)&ddb_regs.tf_regs[8+6],	FCN_NULL, NULL },
     67 	{ "sp",	(long *)&ddb_regs.tf_regs[8+7],	FCN_NULL, NULL },
     68 	/* misc. */
     69 	{ "pc",	(long *)&ddb_regs.tf_pc,	FCN_NULL, NULL },
     70 	{ "sr",	(long *)&ddb_regs.tf_sr,	db_var_short, NULL }
     71 };
     72 const struct db_variable * const db_eregs =
     73     db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
     74 
     75 static int
     76 db_var_short(const struct db_variable *varp, db_expr_t *valp, int op)
     77 {
     78 
     79     if (op == DB_VAR_GET)
     80 	*valp = (db_expr_t)*((short*)varp->valuep);
     81     else
     82 	*((short*)varp->valuep) = (short) *valp;
     83     return 0;
     84 }
     85 
     86 #define	MAXINT	0x7fffffff
     87 
     88 #define	INKERNEL(va,pcb)	(((u_int)(va) > (u_int)(pcb)) && \
     89 				 ((u_int)(va) < ((u_int)(pcb) + USPACE)))
     90 
     91 #define	get(addr, space) \
     92 		(db_get_value((db_addr_t)(addr), sizeof(int), false))
     93 #define	get16(addr, space) \
     94 		(db_get_value((db_addr_t)(addr), sizeof(u_short), false))
     95 
     96 #define	NREGISTERS	16
     97 
     98 struct stackpos {
     99 	 int	k_pc;
    100 	 int	k_fp;
    101 	 int	k_nargs;
    102 	 int	k_entry;
    103 	 int	k_caller;
    104 	 int	k_flags;
    105 	 int	k_regloc[NREGISTERS];
    106 };
    107 
    108 static void	findentry(struct stackpos *, void (*)(const char *, ...));
    109 #ifdef _KERNEL
    110 static void	findregs(struct stackpos *, db_addr_t);
    111 static int	nextframe(struct stackpos *, struct pcb *, int,
    112 		    void (*)(const char *, ...));
    113 #endif
    114 static void	stacktop(db_regs_t *, struct stackpos *,
    115 		    void (*)(const char *, ...));
    116 
    117 
    118 #define FR_SAVFP	0
    119 #define FR_SAVPC	4
    120 
    121 static void
    122 stacktop(db_regs_t *regs, struct stackpos *sp, void (*pr)(const char *, ...))
    123 {
    124 	int i;
    125 
    126 	/* Note: leave out a6, a7 */
    127 	for (i = 0; i < (8+6); i++) {
    128 		sp->k_regloc[i] = (int) &regs->tf_regs[i];
    129 	}
    130 
    131 	sp->k_fp = get(&regs->tf_regs[8+6], 0);
    132 	/* skip sp (a7) */
    133 	sp->k_pc = get(&regs->tf_pc, 0);
    134 	sp->k_flags = 0;
    135 
    136 	findentry(sp, pr);
    137 }
    138 
    139 
    140 /*
    141  * The VAX has a very nice calling convention, and it is quite easy to
    142  * find saved registers, and the number of parameters. We are not nearly
    143  * so lucky. We must grub around in code for much of this information
    144  * (remember the PDP-11?), and the saved register list seems to be
    145  * especially hard to find.
    146  */
    147 
    148 #define HIWORD	0xffff0000
    149 #define LOWORD	0x0000ffff
    150 #define LINKLA6	0x480e0000	/* linkl a6,#x    */
    151 #define LINKWA6	0x4e560000	/* linkw a6,#x    */
    152 #define ADDLSP	0xdffc0000	/* addl #x,sp    */
    153 #define ADDWSP	0xdefc0000	/* addw #x,sp    */
    154 #define LEASP	0x4fef0000	/* lea	sp@(x),sp*/
    155 #define TSTBSP	0x4a2f0000	/* tstb sp@(x)   */
    156 #define INSMSK	0xfff80000
    157 #define MOVLSP	0x2e800000	/* movl dx,sp@   */
    158 #define MOVLD0	0x20000000	/* movl d0,dx	 */
    159 #define MOVLA0	0x20400000	/* movl d0,ax	 */
    160 #define MVLMSK	0xf1ff0000
    161 #define MOVEML	0x48d70000	/* moveml #x,sp@ */
    162 #define JSR	0x4eb80000	/* jsr x.[WL]    */
    163 #define JSRPC	0x4eba0000	/* jsr PC@( )    */
    164 #define LONGBIT 0x00010000
    165 #define BSR	0x61000000	/* bsr x	 */
    166 #define BSRL	0x61ff0000	/* bsrl x	 */
    167 #define BYTE3	0x0000ff00
    168 #define LOBYTE	0x000000ff
    169 #define ADQMSK	0xf1ff0000
    170 #define ADDQSP	0x508f0000	/* addql #x,sp   */
    171 #define ADDQWSP	0x504f0000	/* addqw #x,sp   */
    172 
    173 #if 0
    174 static struct nlist *	trampsym = 0;
    175 static struct nlist *	funcsym = 0;
    176 #endif
    177 
    178 #ifdef _KERNEL
    179 static int
    180 nextframe(struct stackpos *sp, struct pcb *pcb, int kerneltrace,
    181     void (*pr)(const char *, ...))
    182 {
    183 	int		i;
    184 	db_addr_t	addr;
    185 	db_addr_t	calladdr;
    186 	db_addr_t	oldfp = sp->k_fp;
    187 
    188 	/*
    189 	 * Find our entry point. Then find out
    190 	 * which registers we saved, and map them.
    191 	 * Our entry point is the address our caller called.
    192 	 */
    193 
    194 	calladdr = sp->k_caller;
    195 	addr     = sp->k_entry;
    196 	if (addr == MAXINT) {
    197 
    198 		/*
    199 		 * we don't know what registers are involved here,
    200 		 * invalidate them all.
    201 		 */
    202 		for (i = 0; i < NREGISTERS; i++)
    203 			sp->k_regloc[i] = -1;
    204 	} else
    205 		findregs(sp, addr);
    206 
    207 	/* find caller's pc and fp */
    208 	sp->k_pc = calladdr;
    209 	sp->k_fp = get(sp->k_fp + FR_SAVFP, DSP);
    210 
    211 	/*
    212 	 * Now that we have assumed the identity of our caller, find
    213 	 * how many longwords of argument WE were called with.
    214 	 */
    215 	sp->k_flags = 0;
    216 
    217 	/*
    218 	 * Don't dig around in user stack to find no. of args and
    219 	 * entry point if just tracing the kernel
    220 	 */
    221 	if (kerneltrace && !INKERNEL(sp->k_fp, pcb)) {
    222 		sp->k_nargs = 0;
    223 		sp->k_entry = MAXINT;
    224 	} else
    225 		findentry(sp, pr);
    226 
    227 	if (sp->k_fp == 0 || oldfp == (db_addr_t)sp->k_fp)
    228 		return 0;
    229 	return sp->k_fp;
    230 }
    231 #endif
    232 
    233 static void
    234 findentry(struct stackpos *sp, void (*pr)(const char *, ...))
    235 {
    236 	/*
    237 	 * Set the k_nargs and k_entry fields in the stackpos structure.  This
    238 	 * is called from stacktop() and from nextframe().  Our caller will do
    239 	 * an addq or addl or addw to sp just after we return to pop off our
    240 	 * arguments.  Find that instruction and extract the value.
    241 	 */
    242 	int		instruc;
    243 	int		val;
    244 	db_addr_t	addr, nextword;
    245 
    246 	addr = get(sp->k_fp + FR_SAVPC, DSP);
    247 	if (addr == 0) {
    248 		/* oops -- we touched something we ought not to have */
    249 		/* cannot trace caller of "start" */
    250 		sp->k_entry = MAXINT;
    251 		sp->k_nargs = 0;
    252 		return;
    253 	}
    254 	instruc  = get(addr - 6, ISP);
    255 	nextword = get(addr - 4, ISP);
    256 
    257 	if ((instruc & HIWORD) == (JSR | LONGBIT)) {
    258 		/* longword offset here */
    259 		sp->k_caller = addr - 6;
    260 		sp->k_entry  = nextword;
    261 	} else if ((instruc & HIWORD) == BSRL) {
    262 		/* longword self-relative offset */
    263 		sp->k_caller = addr - 6;
    264 		sp->k_entry  = nextword + (addr - 4);
    265 	} else {
    266 		instruc = nextword;
    267 		if ((instruc & HIWORD) == JSR) {
    268 			/* short word offset */
    269 			sp->k_caller = addr - 4;
    270 			sp->k_entry  = instruc & LOWORD;
    271 		} else if ((instruc & HIWORD) == BSR) {
    272 			/* short word, self-relative offset */
    273 			sp->k_caller = addr - 4;
    274 			sp->k_entry  = (addr - 2) + (short)(instruc & LOWORD);
    275 		} else if ((instruc & HIWORD) == JSRPC) {
    276 			/* PC-relative, short word offset */
    277 			sp->k_caller = addr - 4;
    278 			sp->k_entry  = (addr - 2) + (instruc & LOWORD);
    279 		} else {
    280 			if ((instruc & BYTE3) == (BSR >> 16)) {
    281 				/* byte, self-relative offset */
    282 				sp->k_caller = addr - 2;
    283 				sp->k_entry  = addr + (char)(instruc & LOBYTE);
    284 			} else {
    285 				/* was a call through a proc parameter */
    286 				sp->k_caller = addr - 2;
    287 				sp->k_entry  = MAXINT;
    288 			}
    289 		}
    290 	}
    291 	instruc = get(addr, ISP);
    292 	/* on bad days, the compiler dumps a register move here */
    293 	if ((instruc & MVLMSK) == MOVLA0 ||
    294 	    (instruc & MVLMSK) == MOVLD0)
    295 		instruc = get(addr += 2, ISP);
    296 	if ((instruc & ADQMSK) == ADDQSP ||
    297 	    (instruc & ADQMSK) == ADDQWSP) {
    298 		val = 0;
    299 		do {
    300 			int n;
    301 			n = (instruc >> (16+9)) & 07;
    302 			if (n == 0)
    303 				n = 8;
    304 			val += n;
    305 			instruc = get(addr += 2, ISP);
    306 		} while ((instruc & ADQMSK) == ADDQSP ||
    307 			 (instruc & ADQMSK) == ADDQWSP);
    308 	} else if ((instruc & HIWORD) == ADDLSP)
    309 		val = get(addr + 2, ISP);
    310 	else if ((instruc & HIWORD) == ADDWSP ||
    311 		 (instruc & HIWORD) == LEASP)
    312 		val = instruc & LOWORD;
    313 	else
    314 		val = 20;
    315 	sp->k_nargs = val / 4;
    316 }
    317 
    318 #ifdef _KERNEL
    319 /*
    320  * Look at the procedure prolog of the current called procedure.
    321  * Figure out which registers we saved, and where they are
    322  */
    323 static void
    324 findregs(struct stackpos *sp, db_addr_t addr)
    325 {
    326 	long instruc, val, i;
    327 	int  regp;
    328 
    329 	regp = 0;
    330 	instruc = get(addr, ISP);
    331 	if ((instruc & HIWORD) == LINKLA6) {
    332 		instruc = get(addr + 2, ISP);
    333 		addr += 6;
    334 		regp = sp->k_fp + instruc;
    335 	} else if ((instruc & HIWORD) == LINKWA6) {
    336 		addr += 4;
    337 		if ((instruc &= LOWORD) == 0) {
    338 			/* look for addl */
    339 			instruc = get(addr, ISP);
    340 			if ((instruc & HIWORD) == ADDLSP) {
    341 				instruc = get(addr + 2, ISP);
    342 				addr += 6;
    343 			}
    344 			/* else frame is really size 0 */
    345 		} else {
    346 			/* link offset was non-zero -- sign extend it */
    347 			instruc <<= 16;
    348 			instruc >>= 16;
    349 		}
    350 		/* we now have the negative frame size */
    351 		regp = sp->k_fp + instruc;
    352 	}
    353 
    354 	/* find which registers were saved */
    355 	/* (expecting probe instruction next) */
    356 	instruc = get(addr, ISP);
    357 	if ((instruc & HIWORD) == TSTBSP)
    358 		addr += 4;
    359 
    360 	/* now we expect either a moveml or a movl */
    361 	instruc = get(addr, ISP);
    362 	if ((instruc & INSMSK) == MOVLSP) {
    363 		/* only saving one register */
    364 		i = (instruc >> 16) & 07;
    365 		sp->k_regloc[i] = regp;
    366 	} else if ((instruc & HIWORD) == MOVEML) {
    367 		/* saving multiple registers or unoptimized code */
    368 		val = instruc & LOWORD;
    369 		i = 0;
    370 		while (val) {
    371 			if (val & 1) {
    372 				sp->k_regloc[i] = regp;
    373 				regp += sizeof(int);
    374 			}
    375 			val >>= 1;
    376 			i++;
    377 		}
    378 	}
    379 	/* else no registers saved */
    380 }
    381 #endif
    382 
    383 /*
    384  *	Frame tracing.
    385  */
    386 void
    387 db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count,
    388     const char *modif, void (*pr)(const char *, ...))
    389 {
    390 	int i, nargs;
    391 	long val;
    392 	db_addr_t	regp;
    393 	const char *	name;
    394 	struct stackpos pos;
    395 	struct pcb	*pcb;
    396 	struct lwp	*l;
    397 #ifdef _KERNEL
    398 	bool		kernel_only = true;
    399 #endif
    400 	bool		trace_thread = false;
    401 	bool		lwpaddr = false;
    402 	int		fault_pc = 0;
    403 
    404 	{
    405 		const char *cp = modif;
    406 		char c;
    407 
    408 		while ((c = *cp++) != 0) {
    409 			if (c == 'a') {
    410 				lwpaddr = true;
    411 				trace_thread = true;
    412 			} else if (c == 't')
    413 				trace_thread = true;
    414 #ifdef _KERNEL
    415 			else if (c == 'u')
    416 				kernel_only = false;
    417 #endif
    418 		}
    419 	}
    420 
    421 #ifdef _KERNEL
    422 	l = curlwp;
    423 #endif
    424 	if (!have_addr)
    425 		stacktop(&ddb_regs, &pos, pr);
    426 	else {
    427 		if (trace_thread) {
    428 			struct proc *p;
    429 
    430 			if (lwpaddr) {
    431 				l = (struct lwp *)addr;
    432 				p = l->l_proc;
    433 				(*pr)("trace: pid %d ", p->p_pid);
    434 			} else {
    435 				(*pr)("trace: pid %d ", (int)addr);
    436 #ifdef _KERNEL
    437 				p = proc_find_raw(addr);
    438 				if (p == NULL) {
    439 					(*pr)("not found\n");
    440 					return;
    441 				}
    442 				l = LIST_FIRST(&p->p_lwps);
    443 				KASSERT(l != NULL);
    444 #else
    445 				(*pr)("no proc_find_raw() in crash\n");
    446                                 return;
    447 #endif
    448 			}
    449 			(*pr)("lid %d ", l->l_lid);
    450 			pcb = lwp_getpcb(l);
    451 			pos.k_fp = pcb->pcb_regs[PCB_REGS_FP];
    452 			/*
    453 			 * Note: The following only works because cpu_switch()
    454 			 * doesn't push anything on the stack before it saves
    455 			 * the process' context in the pcb.
    456 			 */
    457 			pos.k_pc = get(pcb->pcb_regs[PCB_REGS_SP], DSP);
    458 			(*pr)("at %p\n", (void *)pos.k_fp);
    459 		} else {
    460 			pos.k_fp = addr;
    461 			pos.k_pc = MAXINT;
    462 		}
    463 
    464 		pos.k_flags = 0;
    465 		pos.k_nargs = 0;
    466 		pos.k_entry = MAXINT;
    467 
    468 		for (i = 0; i < NREGISTERS; i++)
    469 			pos.k_regloc[i] = 0;
    470 
    471 		findentry(&pos, pr);
    472 	}
    473 
    474 	while (count) {
    475 		count--;
    476 
    477 		/* HACK */
    478 		if (pos.k_pc == MAXINT) {
    479 			name = "?";
    480 			pos.k_pc = 0;
    481 			val = MAXINT;
    482 		} else {
    483 			db_find_sym_and_offset(pos.k_pc, &name, &val);
    484 			if (name == 0) {
    485 				name = "?";
    486 				val = MAXINT;
    487 			}
    488 		}
    489 
    490 		/*
    491 		 * Since faultstkadj doesn't set up a valid stack frame,
    492 		 * we would assume it was the source of the fault. To
    493 		 * get around this we peek just past the fourth argument of
    494 		 * "trap()" (the stack frame at the time of the fault)
    495 		 * to determine the _real_ value of PC when things went
    496 		 * wrong.
    497 		 *
    498 		 * NOTE: If the argument list for 'trap()' ever changes,
    499 		 * we lose.
    500 		 */
    501 		if (strcmp(___STRING(_C_LABEL(trap)), name) == 0) {
    502 			int tfp;
    503 
    504 			/* Point to frame structure just past 'trap()'s 4th argument */
    505 			tfp = pos.k_fp + FR_SAVFP + 4 + (5 * 4);
    506 
    507 			/* Determine if fault was from kernel or user mode */
    508 			regp = tfp + offsetof(struct frame, f_sr);
    509 			if (!USERMODE(get16(regp, DSP))) {
    510 
    511 				/*
    512 				 * Definitely a kernel mode fault,
    513 				 * so get the PC at the time of the fault.
    514 				 */
    515 				regp = tfp + offsetof(struct frame, f_pc);
    516 				fault_pc = get(regp, DSP);
    517 			}
    518 		} else if (fault_pc) {
    519 			if (strcmp("faultstkadj", name) == 0) {
    520 				db_find_sym_and_offset(fault_pc, &name, &val);
    521 				if (name == 0) {
    522 					name = "?";
    523 					val = MAXINT;
    524 				}
    525 			}
    526 			fault_pc = 0;
    527 		}
    528 
    529 		(*pr)("%s", name);
    530 		if (pos.k_entry != MAXINT && name) {
    531 			const char *entry_name;
    532 			long	e_val;
    533 
    534 			db_find_sym_and_offset(pos.k_entry, &entry_name,
    535 			    &e_val);
    536 			if (entry_name != 0 && entry_name != name &&
    537 			    e_val != val) {
    538 				(*pr)("(?)\n%s", entry_name);
    539 			}
    540 		}
    541 		(*pr)("(");
    542 		regp = pos.k_fp + FR_SAVFP + 4;
    543 		if ((nargs = pos.k_nargs)) {
    544 			while (nargs--) {
    545 				(*pr)("%lx", get(regp += 4, DSP));
    546 				if (nargs)
    547 					(*pr)(",");
    548 			}
    549 		}
    550 		if (val == MAXINT)
    551 			(*pr)(") at %x\n", pos.k_pc);
    552 		else
    553 			(*pr)(") + %lx\n", val);
    554 
    555 #ifdef _KERNEL
    556 		/*
    557 		 * Stop tracing if frame ptr no longer points into kernel
    558 		 * stack.
    559 		 */
    560 		pcb = lwp_getpcb(l);
    561 		if (kernel_only && !INKERNEL(pos.k_fp, pcb))
    562 			break;
    563 		if (nextframe(&pos, pcb, kernel_only, pr) == 0)
    564 			break;
    565 #endif
    566 	}
    567 }
    568