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 */
58struct 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 * 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
77static 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 */
95static void
96decode_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							\
107do {									\
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
162static int
163sym_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
173static void
174decode_syscall(int number, struct proc *p, void (*pr)(const char *, ...))
175{
176
177	(*pr)(" (%d)", number);
178}
179
180void
181db_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