Home | History | Annotate | Line # | Download | only in alpha
      1 /* $NetBSD: db_trace.c,v 1.39 2023/11/21 22:19:12 thorpej Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 1999 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
      9  * NASA Ames Research Center.
     10  *
     11  * This code is derived from software contributed to The NetBSD Foundation
     12  * by Ross Harvey.
     13  *
     14  * Redistribution and use in source and binary forms, with or without
     15  * modification, are permitted provided that the following conditions
     16  * are met:
     17  * 1. Redistributions of source code must retain the above copyright
     18  *    notice, this list of conditions and the following disclaimer.
     19  * 2. Redistributions in binary form must reproduce the above copyright
     20  *    notice, this list of conditions and the following disclaimer in the
     21  *    documentation and/or other materials provided with the distribution.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     24  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     25  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     26  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     27  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     33  * POSSIBILITY OF SUCH DAMAGE.
     34  */
     35 
     36 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
     37 
     38 __KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.39 2023/11/21 22:19:12 thorpej Exp $");
     39 
     40 #include <sys/param.h>
     41 #include <sys/systm.h>
     42 #include <sys/proc.h>
     43 
     44 #include <machine/alpha.h>
     45 #include <machine/db_machdep.h>
     46 
     47 #include <machine/alpha_instruction.h>
     48 
     49 #include <ddb/db_sym.h>
     50 #include <ddb/db_access.h>
     51 #include <ddb/db_variables.h>
     52 #include <ddb/db_output.h>
     53 #include <ddb/db_interface.h>
     54 
     55 /*
     56  * Information about the `standard' Alpha function prologue.
     57  */
     58 struct prologue_info {
     59 	int	pi_reg_offset[32]; /* offset of registers in stack frame */
     60 	uint32_t pi_regmask;	   /* which registers are in frame */
     61 	int	pi_frame_size;	   /* frame size */
     62 };
     63 
     64 /*
     65  * Decode the function prologue for the function we're in, and note
     66  * which registers are stored where, and how large the stack frame is.
     67  */
     68 static void
     69 decode_prologue(db_addr_t callpc, db_addr_t func,
     70     struct prologue_info *pi, void (*pr)(const char *, ...))
     71 {
     72 	long signed_immediate;
     73 	alpha_instruction ins;
     74 	db_addr_t pc;
     75 
     76 	pi->pi_regmask = 0;
     77 	pi->pi_frame_size = 0;
     78 
     79 #define	CHECK_FRAMESIZE							\
     80 do {									\
     81 	if (pi->pi_frame_size != 0) {					\
     82 		(*pr)("frame size botch: adjust register offsets?\n"); \
     83 	}								\
     84 } while (0)
     85 
     86 	for (pc = func; pc < callpc; pc += sizeof(alpha_instruction)) {
     87 		db_read_bytes(pc, sizeof(ins.bits), (char *)&ins.bits);
     88 
     89 		if (ins.mem_format.opcode == op_lda &&
     90 		    ins.mem_format.ra == 30 &&
     91 		    ins.mem_format.rb == 30) {
     92 			/*
     93 			 * GCC 2.7-style stack adjust:
     94 			 *
     95 			 *	lda	sp, -64(sp)
     96 			 */
     97 			signed_immediate = (long)ins.mem_format.displacement;
     98 			/*
     99 			 * The assumption here is that a positive
    100 			 * stack offset is the function epilogue,
    101 			 * which may come before callpc when an
    102 			 * aggressive optimizer (like GCC 3.3 or later)
    103 			 * has moved part of the function "out of
    104 			 * line", past the epilogue. Therefore, ignore
    105 			 * the positive offset so that
    106 			 * pi->pi_frame_size has the correct value
    107 			 * when we reach callpc.
    108 			 */
    109 			if (signed_immediate <= 0) {
    110 				CHECK_FRAMESIZE;
    111 				pi->pi_frame_size += -signed_immediate;
    112 			}
    113 		} else if (ins.operate_lit_format.opcode == op_arit &&
    114 			   ins.operate_lit_format.function == op_subq &&
    115 			   ins.operate_lit_format.ra == 30 &&
    116 			   ins.operate_lit_format.rc == 30) {
    117 			/*
    118 			 * EGCS-style stack adjust:
    119 			 *
    120 			 *	subq	sp, 64, sp
    121 			 */
    122 			CHECK_FRAMESIZE;
    123 			pi->pi_frame_size += ins.operate_lit_format.literal;
    124 		} else if (ins.mem_format.opcode == op_stq &&
    125 			   ins.mem_format.rb == 30 &&
    126 			   ins.mem_format.ra != 31) {
    127 			/* Store of (non-zero) register onto the stack. */
    128 			signed_immediate = (long)ins.mem_format.displacement;
    129 			pi->pi_regmask |= 1 << ins.mem_format.ra;
    130 			pi->pi_reg_offset[ins.mem_format.ra] = signed_immediate;
    131 		}
    132 	}
    133 }
    134 
    135 static void
    136 decode_syscall(int number, void (*pr)(const char *, ...))
    137 {
    138 	(*pr)(" (%d)", number);
    139 }
    140 
    141 void
    142 db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count,
    143     const char *modif, void (*pr)(const char *, ...))
    144 {
    145 
    146 	db_stack_trace_print_ra(/*ra*/0, /*have_ra*/false, addr, have_addr,
    147 	    count, modif, pr);
    148 }
    149 
    150 void
    151 db_stack_trace_print_ra(db_expr_t ra, bool have_ra,
    152     db_expr_t addr, bool have_addr,
    153     db_expr_t count,
    154     const char *modif, void (*pr)(const char *, ...))
    155 {
    156 	db_addr_t callpc, frame, symval;
    157 	struct prologue_info pi;
    158 	db_expr_t diff;
    159 	db_sym_t sym;
    160 	u_long tfps;
    161 	const char *symname;
    162 	struct pcb *pcbp;
    163 	const char *cp = modif;
    164 	struct trapframe *tf;
    165 	bool ra_from_tf;
    166 	u_long last_ipl = ~0L;
    167 	char c;
    168 	bool trace_thread = false;
    169 	bool lwpaddr = false;
    170 
    171 	while ((c = *cp++) != 0) {
    172 		trace_thread |= c == 't';
    173 		trace_thread |= c == 'a';
    174 		lwpaddr |= c == 'a';
    175 	}
    176 
    177 	if (!have_addr) {
    178 		addr = DDB_REGS->tf_regs[FRAME_SP] - FRAME_SIZE * 8;
    179 		tf = (struct trapframe *)addr;
    180 		callpc = db_alpha_tf_reg(tf, FRAME_PC);
    181 		frame = (db_addr_t)tf + FRAME_SIZE * 8;
    182 		ra_from_tf = true;
    183 	} else {
    184 #ifdef _KERNEL
    185 		struct proc *p = NULL;
    186 		struct lwp *l = NULL;
    187 #else
    188 		struct proc pstore, *p = &pstore;
    189 		struct lwp lstore, *l = &lstore;
    190 #endif /* _KERNEL */
    191 
    192 		if (trace_thread) {
    193 			if (lwpaddr) {
    194 #ifdef _KERNEL
    195 				l = (struct lwp *)addr;
    196 				p = l->l_proc;
    197 #else
    198 				db_read_bytes(addr, sizeof(*l), (char *)l);
    199 				db_read_bytes((db_addr_t)l->l_proc,
    200 				    sizeof(*p), (char *)p);
    201 #endif /* _KERNEL */
    202 				(*pr)("trace: pid %d ", p->p_pid);
    203 			} else {
    204 #ifdef _KERNEL
    205 				(*pr)("trace: pid %d ", (int)addr);
    206 				p = proc_find_raw(addr);
    207 				if (p == NULL) {
    208 					(*pr)("not found\n");
    209 					return;
    210 				}
    211 				l = LIST_FIRST(&p->p_lwps);
    212 				KASSERT(l != NULL);
    213 #else
    214 				(*pr)("no proc_find_raw() in crash\n");
    215 				return;
    216 #endif /* _KERNEL */
    217 			}
    218 			(*pr)("lid %d ", l->l_lid);
    219 			pcbp = lwp_getpcb(l);
    220 			addr = db_alpha_read_saved_reg(&pcbp->pcb_hw.apcb_ksp);
    221 			callpc = db_alpha_read_saved_reg(&pcbp->pcb_context[7]);
    222 			(*pr)("at 0x%lx\n", addr);
    223 		} else if (have_ra) {
    224 			callpc = ra;
    225 			(*pr)("at 0x%lx pc 0x%lx\n", addr, callpc);
    226 		} else {
    227 			(*pr)("alpha trace requires known PC =eject=\n");
    228 			return;
    229 		}
    230 		frame = addr;
    231 		tf = NULL;
    232 		ra_from_tf = false;
    233 	}
    234 
    235 	while (count--) {
    236 		sym = db_search_symbol(callpc, DB_STGY_ANY, &diff);
    237 		if (sym == DB_SYM_NULL)
    238 			break;
    239 
    240 		db_symbol_values(sym, &symname, (db_expr_t *)&symval);
    241 
    242 		if (callpc < symval) {
    243 			(*pr)("symbol botch: callpc 0x%lx < "
    244 			    "func 0x%lx (%s)\n", callpc, symval, symname);
    245 			return;
    246 		}
    247 
    248 		/*
    249 		 * If the previous RA pointed at the kernel thread
    250 		 * backstop, then we are at the root of the call
    251 		 * graph.
    252 		 */
    253 		if (db_alpha_sym_is_backstop(symval)) {
    254 			(*pr)("--- kernel thread backstop ---\n");
    255 			break;
    256 		}
    257 
    258 		/*
    259 		 * XXX Printing out arguments is Hard.  We'd have to
    260 		 * keep lots of state as we traverse the frame, figuring
    261 		 * out where the arguments to the function are stored
    262 		 * on the stack.
    263 		 *
    264 		 * Even worse, they may be stored to the stack _after_
    265 		 * being modified in place; arguments are passed in
    266 		 * registers.
    267 		 *
    268 		 * So, in order for this to work reliably, we pretty much
    269 		 * have to have a kernel built with `cc -g':
    270 		 *
    271 		 *	- The debugging symbols would tell us where the
    272 		 *	  arguments are, how many there are, if there were
    273 		 *	  any passed on the stack, etc.
    274 		 *
    275 		 *	- Presumably, the compiler would be careful to
    276 		 *	  store the argument registers on the stack before
    277 		 *	  modifying the registers, so that a debugger could
    278 		 *	  know what those values were upon procedure entry.
    279 		 *
    280 		 * Because of this, we don't bother.  We've got most of the
    281 		 * benefit of back tracking without the arguments, and we
    282 		 * could get the arguments if we use a remote source-level
    283 		 * debugger (for serious debugging).
    284 		 */
    285 		(*pr)("%s() at ", symname);
    286 		db_printsym(callpc, DB_STGY_PROC, pr);
    287 		(*pr)("\n");
    288 
    289 		/*
    290 		 * If we are in a trap vector, frame points to a
    291 		 * trapframe.
    292 		 */
    293 		if (db_alpha_sym_is_trap(symval)) {
    294 			tf = (struct trapframe *)frame;
    295 
    296 			(*pr)("--- %s", db_alpha_trapsym_description(symval));
    297 
    298 			tfps = db_alpha_tf_reg(tf, FRAME_PS);
    299 			if (db_alpha_sym_is_syscall(symval)) {
    300 				decode_syscall(db_alpha_tf_reg(tf, FRAME_V0),
    301 				    pr);
    302 			}
    303 			if ((tfps & ALPHA_PSL_IPL_MASK) != last_ipl) {
    304 				last_ipl = tfps & ALPHA_PSL_IPL_MASK;
    305 				if (! db_alpha_sym_is_syscall(symval)) {
    306 					(*pr)(" (from ipl %ld)", last_ipl);
    307 				}
    308 			}
    309 			(*pr)(" ---\n");
    310 			if (tfps & ALPHA_PSL_USERMODE) {
    311 				(*pr)("--- user mode ---\n");
    312 				break;	/* Terminate search.  */
    313 			}
    314 			callpc = db_alpha_tf_reg(tf, FRAME_PC);
    315 			frame = (db_addr_t)tf + FRAME_SIZE * 8;
    316 			ra_from_tf = true;
    317 			continue;
    318 		}
    319 
    320 		/*
    321 		 * This is a bit trickier; we must decode the function
    322 		 * prologue to find the saved RA.
    323 		 *
    324 		 * XXX How does this interact w/ alloca()?!
    325 		 */
    326 		decode_prologue(callpc, symval, &pi, pr);
    327 		if ((pi.pi_regmask & (1 << 26)) == 0) {
    328 			/*
    329 			 * No saved RA found.  We might have RA from
    330 			 * the trap frame, however (e.g trap occurred
    331 			 * in a leaf call).  If not, we've found the
    332 			 * root of the call graph.
    333 			 */
    334 			if (ra_from_tf) {
    335 				callpc = db_alpha_tf_reg(tf, FRAME_RA);
    336 			} else {
    337 				(*pr)("--- root of call graph ---\n");
    338 				break;
    339 			}
    340 		} else {
    341 			unsigned long reg;
    342 
    343 			db_read_bytes(frame + pi.pi_reg_offset[26],
    344 			    sizeof(reg), (char *)&reg);
    345 			callpc = reg;
    346 		}
    347 		frame += pi.pi_frame_size;
    348 		ra_from_tf = false;
    349 	}
    350 }
    351