xref: /netbsd/sys/arch/alpha/alpha/db_trace.c (revision bf9ec67e)
1 /* $NetBSD: db_trace.c,v 1.9 2000/12/13 03:16:36 mycroft 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  * 3. All advertising materials mentioning features or use of this software
23  *    must display the following acknowledgement:
24  *	This product includes software developed by the NetBSD
25  *	Foundation, Inc. and its contributors.
26  * 4. Neither the name of The NetBSD Foundation nor the names of its
27  *    contributors may be used to endorse or promote products derived
28  *    from this software without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
31  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
32  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
33  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
34  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
35  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
36  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
37  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
40  * POSSIBILITY OF SUCH DAMAGE.
41  */
42 
43 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
44 
45 __KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.9 2000/12/13 03:16:36 mycroft Exp $");
46 
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/proc.h>
50 #include <sys/user.h>
51 
52 #include <machine/alpha.h>
53 #include <machine/db_machdep.h>
54 
55 #include <alpha/alpha/db_instruction.h>
56 
57 #include <ddb/db_sym.h>
58 #include <ddb/db_access.h>
59 #include <ddb/db_variables.h>
60 #include <ddb/db_output.h>
61 #include <ddb/db_interface.h>
62 
63 /*
64  * Information about the `standard' Alpha function prologue.
65  */
66 struct prologue_info {
67 	int	pi_reg_offset[32]; /* offset of registers in stack frame */
68 	u_int32_t pi_regmask;	   /* which registers are in frame */
69 	int	pi_frame_size;	   /* frame size */
70 };
71 
72 /*
73  * We use several symbols to take special action:
74  *
75  *	Trap vectors, which use a different (fixed-size) stack frame:
76  *
77  *		XentArith
78  *		XentIF
79  *		XentInt
80  *		XentMM
81  *		XentSys
82  *		XentUna
83  */
84 
85 static struct special_symbol {
86 	vaddr_t ss_val;
87 	const char *ss_note;
88 } special_symbols[] = {
89 	{ (vaddr_t)&XentArith,		"arithmetic trap" },
90 	{ (vaddr_t)&XentIF,		"instruction fault" },
91 	{ (vaddr_t)&XentInt,		"interrupt" },
92 	{ (vaddr_t)&XentMM,		"memory management fault" },
93 	{ (vaddr_t)&XentSys,		"syscall" },
94 	{ (vaddr_t)&XentUna,		"unaligned access fault" },
95 	{ (vaddr_t)&XentRestart,	"console restart" },
96 	{ NULL }
97 };
98 
99 /*
100  * Decode the function prologue for the function we're in, and note
101  * which registers are stored where, and how large the stack frame is.
102  */
103 static void
104 decode_prologue(db_addr_t callpc, db_addr_t func,
105     struct prologue_info *pi, void (*pr)(const char *, ...))
106 {
107 	long signed_immediate;
108 	alpha_instruction ins;
109 	db_expr_t pc;
110 
111 	pi->pi_regmask = 0;
112 	pi->pi_frame_size = 0;
113 
114 #define	CHECK_FRAMESIZE							\
115 do {									\
116 	if (pi->pi_frame_size != 0) {					\
117 		(*pr)("frame size botch: adjust register offsets?\n"); \
118 	}								\
119 } while (0)
120 
121 	for (pc = func; pc < callpc; pc += sizeof(alpha_instruction)) {
122 		ins.bits = *(unsigned int *)pc;
123 
124 		if (ins.mem_format.opcode == op_lda &&
125 		    ins.mem_format.ra == 30 &&
126 		    ins.mem_format.rb == 30) {
127 			/*
128 			 * GCC 2.7-style stack adjust:
129 			 *
130 			 *	lda	sp, -64(sp)
131 			 */
132 			signed_immediate = (long)ins.mem_format.displacement;
133 #if 1
134 			if (signed_immediate > 0)
135 				(*pr)("prologue botch: displacement %ld\n",
136 				    signed_immediate);
137 #endif
138 			CHECK_FRAMESIZE;
139 			pi->pi_frame_size += -signed_immediate;
140 		} else if (ins.operate_lit_format.opcode == op_arit &&
141 			   ins.operate_lit_format.function == op_subq &&
142 			   ins.operate_lit_format.ra == 30 &&
143 			   ins.operate_lit_format.rc == 30) {
144 			/*
145 			 * EGCS-style stack adjust:
146 			 *
147 			 *	subq	sp, 64, sp
148 			 */
149 			CHECK_FRAMESIZE;
150 			pi->pi_frame_size += ins.operate_lit_format.literal;
151 		} else if (ins.mem_format.opcode == op_stq &&
152 			   ins.mem_format.rb == 30 &&
153 			   ins.mem_format.ra != 31) {
154 			/* Store of (non-zero) register onto the stack. */
155 			signed_immediate = (long)ins.mem_format.displacement;
156 			pi->pi_regmask |= 1 << ins.mem_format.ra;
157 			pi->pi_reg_offset[ins.mem_format.ra] = signed_immediate;
158 		}
159 	}
160 }
161 
162 static int
163 sym_is_trapsymbol(vaddr_t v)
164 {
165 	int i;
166 
167 	for (i = 0; special_symbols[i].ss_val != NULL; ++i)
168 		if (v == special_symbols[i].ss_val)
169 			return 1;
170 	return 0;
171 }
172 
173 static void
174 decode_syscall(int number, struct proc *p, void (*pr)(const char *, ...))
175 {
176 
177 	(*pr)(" (%d)", number);
178 }
179 
180 void
181 db_stack_trace_print(db_expr_t addr, boolean_t have_addr, db_expr_t count,
182     char *modif, void (*pr)(const char *, ...))
183 {
184 	db_addr_t callpc, frame, symval;
185 	struct prologue_info pi;
186 	db_expr_t diff;
187 	db_sym_t sym;
188 	int i;
189 	u_long tfps;
190 	char *symname;
191 	struct pcb *pcbp;
192 	char c, *cp = modif;
193 	struct trapframe *tf;
194 	boolean_t ra_from_tf;
195 	boolean_t ra_from_pcb;
196 	u_long last_ipl = ~0L;
197 	struct proc *p = NULL;
198 	boolean_t trace_thread = FALSE;
199 	boolean_t have_trapframe = FALSE;
200 
201 	while ((c = *cp++) != 0)
202 		trace_thread |= c == 't';
203 
204 	if (!have_addr) {
205 		p = curproc;
206 		addr = DDB_REGS->tf_regs[FRAME_SP] - FRAME_SIZE * 8;
207 		tf = (struct trapframe *)addr;
208 		have_trapframe = 1;
209 	} else {
210 		if (trace_thread) {
211 			(*pr)("trace: pid %d ", (int)addr);
212 			p = pfind(addr);
213 			if (p == NULL) {
214 				(*pr)("not found\n");
215 				return;
216 			}
217 			if ((p->p_flag & P_INMEM) == 0) {
218 				(*pr)("swapped out\n");
219 				return;
220 			}
221 			pcbp = &p->p_addr->u_pcb;
222 			addr = (db_expr_t)pcbp->pcb_hw.apcb_ksp;
223 			callpc = pcbp->pcb_context[7];
224 			(*pr)("at 0x%lx\n", addr);
225 		} else {
226 			(*pr)("alpha trace requires known PC =eject=\n");
227 			return;
228 		}
229 		frame = addr;
230 	}
231 
232 	while (count--) {
233 		if (have_trapframe) {
234 			frame = (db_addr_t)tf + FRAME_SIZE * 8;
235 			callpc = tf->tf_regs[FRAME_PC];
236 			ra_from_tf = TRUE;
237 			have_trapframe = 0;
238 		}
239 		sym = db_search_symbol(callpc, DB_STGY_ANY, &diff);
240 		if (sym == DB_SYM_NULL)
241 			break;
242 
243 		db_symbol_values(sym, &symname, (db_expr_t *)&symval);
244 
245 		if (callpc < symval) {
246 			(*pr)("symbol botch: callpc 0x%lx < "
247 			    "func 0x%lx (%s)\n", callpc, symval, symname);
248 			return;
249 		}
250 
251 		/*
252 		 * XXX Printing out arguments is Hard.  We'd have to
253 		 * keep lots of state as we traverse the frame, figuring
254 		 * out where the arguments to the function are stored
255 		 * on the stack.
256 		 *
257 		 * Even worse, they may be stored to the stack _after_
258 		 * being modified in place; arguments are passed in
259 		 * registers.
260 		 *
261 		 * So, in order for this to work reliably, we pretty much
262 		 * have to have a kernel built with `cc -g':
263 		 *
264 		 *	- The debugging symbols would tell us where the
265 		 *	  arguments are, how many there are, if there were
266 		 *	  any passed on the stack, etc.
267 		 *
268 		 *	- Presumably, the compiler would be careful to
269 		 *	  store the argument registers on the stack before
270 		 *	  modifying the registers, so that a debugger could
271 		 *	  know what those values were upon procedure entry.
272 		 *
273 		 * Because of this, we don't bother.  We've got most of the
274 		 * benefit of back tracking without the arguments, and we
275 		 * could get the arguments if we use a remote source-level
276 		 * debugger (for serious debugging).
277 		 */
278 		(*pr)("%s() at ", symname);
279 		db_printsym(callpc, DB_STGY_PROC, pr);
280 		(*pr)("\n");
281 
282 		/*
283 		 * If we are in a trap vector, frame points to a
284 		 * trapframe.
285 		 */
286 		if (sym_is_trapsymbol(symval)) {
287 			tf = (struct trapframe *)frame;
288 
289 			for (i = 0; special_symbols[i].ss_val != NULL; ++i)
290 				if (symval == special_symbols[i].ss_val)
291 					(*pr)("--- %s",
292 					    special_symbols[i].ss_note);
293 
294 			tfps = tf->tf_regs[FRAME_PS];
295 			if (symval == (vaddr_t)&XentSys)
296 				decode_syscall(tf->tf_regs[FRAME_V0], p, pr);
297 			if ((tfps & ALPHA_PSL_IPL_MASK) != last_ipl) {
298 				last_ipl = tfps & ALPHA_PSL_IPL_MASK;
299 				if (symval != (vaddr_t)&XentSys)
300 					(*pr)(" (from ipl %ld)", last_ipl);
301 			}
302 			(*pr)(" ---\n");
303 			if (tfps & ALPHA_PSL_USERMODE) {
304 				(*pr)("--- user mode ---\n");
305 				break;	/* Terminate search.  */
306 			}
307 			have_trapframe = 1;
308 			continue;
309 		}
310 
311 		/*
312 		 * This is a bit trickier; we must decode the function
313 		 * prologue to find the saved RA.
314 		 *
315 		 * XXX How does this interact w/ alloca()?!
316 		 */
317 		decode_prologue(callpc, symval, &pi, pr);
318 		if ((pi.pi_regmask & (1 << 26)) == 0) {
319 			/*
320 			 * No saved RA found.  We might have RA from
321 			 * the trap frame, however (e.g trap occurred
322 			 * in a leaf call).  If not, we've found the
323 			 * root of the call graph.
324 			 */
325 			if (ra_from_tf)
326 				callpc = tf->tf_regs[FRAME_RA];
327 			else {
328 				(*pr)("--- root of call graph ---\n");
329 				break;
330 			}
331 		} else
332 			callpc = *(u_long *)(frame + pi.pi_reg_offset[26]);
333 		ra_from_tf = ra_from_pcb = FALSE;
334 #if 0
335 		/*
336 		 * The call was actually made at RA - 4; the PC is
337 		 * updated before being stored in RA.
338 		 */
339 		callpc -= 4;
340 #endif
341 		frame += pi.pi_frame_size;
342 	}
343 }
344