xref: /netbsd/sys/arch/alpha/alpha/db_trace.c (revision 6550d01e)
1 /* $NetBSD: db_trace.c,v 1.27 2010/07/01 02:38:26 rmind 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.27 2010/07/01 02:38:26 rmind 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 <alpha/alpha/db_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 	u_int32_t pi_regmask;	   /* which registers are in frame */
61 	int	pi_frame_size;	   /* frame size */
62 };
63 
64 /*
65  * We use several symbols to take special action:
66  *
67  *	Trap vectors, which use a different (fixed-size) stack frame:
68  *
69  *		XentArith
70  *		XentIF
71  *		XentInt
72  *		XentMM
73  *		XentSys
74  *		XentUna
75  */
76 
77 static struct special_symbol {
78 	vaddr_t ss_val;
79 	const char *ss_note;
80 } special_symbols[] = {
81 	{ (vaddr_t)&XentArith,		"arithmetic trap" },
82 	{ (vaddr_t)&XentIF,		"instruction fault" },
83 	{ (vaddr_t)&XentInt,		"interrupt" },
84 	{ (vaddr_t)&XentMM,		"memory management fault" },
85 	{ (vaddr_t)&XentSys,		"syscall" },
86 	{ (vaddr_t)&XentUna,		"unaligned access fault" },
87 	{ (vaddr_t)&XentRestart,	"console restart" },
88 	{ 0 }
89 };
90 
91 /*
92  * Decode the function prologue for the function we're in, and note
93  * which registers are stored where, and how large the stack frame is.
94  */
95 static void
96 decode_prologue(db_addr_t callpc, db_addr_t func,
97     struct prologue_info *pi, void (*pr)(const char *, ...))
98 {
99 	long signed_immediate;
100 	alpha_instruction ins;
101 	db_expr_t pc;
102 
103 	pi->pi_regmask = 0;
104 	pi->pi_frame_size = 0;
105 
106 #define	CHECK_FRAMESIZE							\
107 do {									\
108 	if (pi->pi_frame_size != 0) {					\
109 		(*pr)("frame size botch: adjust register offsets?\n"); \
110 	}								\
111 } while (0)
112 
113 	for (pc = func; pc < callpc; pc += sizeof(alpha_instruction)) {
114 		ins.bits = *(unsigned int *)pc;
115 
116 		if (ins.mem_format.opcode == op_lda &&
117 		    ins.mem_format.ra == 30 &&
118 		    ins.mem_format.rb == 30) {
119 			/*
120 			 * GCC 2.7-style stack adjust:
121 			 *
122 			 *	lda	sp, -64(sp)
123 			 */
124 			signed_immediate = (long)ins.mem_format.displacement;
125 			/*
126 			 * The assumption here is that a positive
127 			 * stack offset is the function epilogue,
128 			 * which may come before callpc when an
129 			 * agressive optimizer (like GCC 3.3 or later)
130 			 * has moved part of the function "out of
131 			 * line", past the epilogue. Therefore, ignore
132 			 * the positive offset so that
133 			 * pi->pi_frame_size has the correct value
134 			 * when we reach callpc.
135 			 */
136 			if (signed_immediate <= 0) {
137 				CHECK_FRAMESIZE;
138 				pi->pi_frame_size += -signed_immediate;
139 			}
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 != 0; ++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, bool have_addr, db_expr_t count,
182     const 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 	const char *symname;
191 	struct pcb *pcbp;
192 	const char *cp = modif;
193 	struct trapframe *tf;
194 	bool ra_from_tf;
195 	u_long last_ipl = ~0L;
196 	struct proc *p = NULL;
197 	struct lwp *l = NULL;
198 	char c;
199 	bool trace_thread = false;
200 	bool lwpaddr = false;
201 
202 	while ((c = *cp++) != 0) {
203 		trace_thread |= c == 't';
204 		trace_thread |= c == 'a';
205 		lwpaddr |= c == 'a';
206 	}
207 
208 	if (!have_addr) {
209 		p = curproc;
210 		addr = DDB_REGS->tf_regs[FRAME_SP] - FRAME_SIZE * 8;
211 		tf = (struct trapframe *)addr;
212 		callpc = tf->tf_regs[FRAME_PC];
213 		frame = (db_addr_t)tf + FRAME_SIZE * 8;
214 		ra_from_tf = true;
215 	} else {
216 		if (trace_thread) {
217 			if (lwpaddr) {
218 				l = (struct lwp *)addr;
219 				p = l->l_proc;
220 				(*pr)("trace: pid %d ", p->p_pid);
221 			} else {
222 				(*pr)("trace: pid %d ", (int)addr);
223 				p = proc_find_raw(addr);
224 				if (p == NULL) {
225 					(*pr)("not found\n");
226 					return;
227 				}
228 				l = LIST_FIRST(&p->p_lwps);
229 				KASSERT(l != NULL);
230 			}
231 			(*pr)("lid %d ", l->l_lid);
232 			pcbp = lwp_getpcb(l);
233 			addr = (db_expr_t)pcbp->pcb_hw.apcb_ksp;
234 			callpc = pcbp->pcb_context[7];
235 			(*pr)("at 0x%lx\n", addr);
236 		} else {
237 			(*pr)("alpha trace requires known PC =eject=\n");
238 			return;
239 		}
240 		frame = addr;
241 		tf = NULL;
242 		ra_from_tf = false;
243 	}
244 
245 	while (count--) {
246 		sym = db_search_symbol(callpc, DB_STGY_ANY, &diff);
247 		if (sym == DB_SYM_NULL)
248 			break;
249 
250 		db_symbol_values(sym, &symname, (db_expr_t *)&symval);
251 
252 		if (callpc < symval) {
253 			(*pr)("symbol botch: callpc 0x%lx < "
254 			    "func 0x%lx (%s)\n", callpc, symval, symname);
255 			return;
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 (sym_is_trapsymbol(symval)) {
294 			tf = (struct trapframe *)frame;
295 
296 			for (i = 0; special_symbols[i].ss_val != 0; ++i)
297 				if (symval == special_symbols[i].ss_val)
298 					(*pr)("--- %s",
299 					    special_symbols[i].ss_note);
300 
301 			tfps = tf->tf_regs[FRAME_PS];
302 			if (symval == (vaddr_t)&XentSys)
303 				decode_syscall(tf->tf_regs[FRAME_V0], p, pr);
304 			if ((tfps & ALPHA_PSL_IPL_MASK) != last_ipl) {
305 				last_ipl = tfps & ALPHA_PSL_IPL_MASK;
306 				if (symval != (vaddr_t)&XentSys)
307 					(*pr)(" (from ipl %ld)", last_ipl);
308 			}
309 			(*pr)(" ---\n");
310 			if (tfps & ALPHA_PSL_USERMODE) {
311 				(*pr)("--- user mode ---\n");
312 				break;	/* Terminate search.  */
313 			}
314 			callpc = tf->tf_regs[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 = tf->tf_regs[FRAME_RA];
336 			else {
337 				(*pr)("--- root of call graph ---\n");
338 				break;
339 			}
340 		} else
341 			callpc = *(u_long *)(frame + pi.pi_reg_offset[26]);
342 		frame += pi.pi_frame_size;
343 		ra_from_tf = false;
344 	}
345 }
346