db_trace.c revision 85246
1/*-
2 * Copyright (c) 2001 Jake Burkholder.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/sparc64/sparc64/db_trace.c 85246 2001-10-20 17:10:34Z jake $
27 */
28
29#include <sys/param.h>
30#include <sys/systm.h>
31#include <sys/linker_set.h>
32#include <sys/proc.h>
33#include <sys/user.h>
34
35#include <vm/vm.h>
36#include <vm/vm_page.h>
37#include <vm/vm_map.h>
38
39#include <machine/cpu.h>
40#include <machine/trap.h>
41#include <machine/vmparam.h>
42
43#include <ddb/ddb.h>
44#include <ddb/db_access.h>
45#include <ddb/db_sym.h>
46#include <ddb/db_variables.h>
47#include <ddb/db_watch.h>
48
49static db_varfcn_t db_show_in0;
50static db_varfcn_t db_show_in1;
51static db_varfcn_t db_show_in2;
52static db_varfcn_t db_show_in3;
53static db_varfcn_t db_show_in4;
54static db_varfcn_t db_show_in5;
55static db_varfcn_t db_show_in6;
56static db_varfcn_t db_show_in7;
57static db_varfcn_t db_show_local0;
58static db_varfcn_t db_show_local1;
59static db_varfcn_t db_show_local2;
60static db_varfcn_t db_show_local3;
61static db_varfcn_t db_show_local4;
62static db_varfcn_t db_show_local5;
63static db_varfcn_t db_show_local6;
64static db_varfcn_t db_show_local7;
65
66static int db_print_trap(struct trapframe *);
67
68extern char _start[];
69extern char _end[];
70
71#define	INKERNEL(va) \
72	((va) >= (u_long)_start && (va) <= (u_long)_end)
73
74struct	db_variable db_regs[] = {
75	{ "g0",	&ddb_regs.tf_global[0], FCN_NULL },
76	{ "g1",	&ddb_regs.tf_global[1], FCN_NULL },
77	{ "g2",	&ddb_regs.tf_global[2], FCN_NULL },
78	{ "g3",	&ddb_regs.tf_global[3], FCN_NULL },
79	{ "g4",	&ddb_regs.tf_global[4], FCN_NULL },
80	{ "g5",	&ddb_regs.tf_global[5], FCN_NULL },
81	{ "g6",	&ddb_regs.tf_global[6], FCN_NULL },
82	{ "g7",	&ddb_regs.tf_global[7], FCN_NULL },
83	{ "i0", NULL, db_show_in0 },
84	{ "i1", NULL, db_show_in1 },
85	{ "i2", NULL, db_show_in2 },
86	{ "i3", NULL, db_show_in3 },
87	{ "i4", NULL, db_show_in4 },
88	{ "i5", NULL, db_show_in5 },
89	{ "i6", NULL, db_show_in6 },
90	{ "i7", NULL, db_show_in7 },
91	{ "l0", NULL, db_show_local0 },
92	{ "l1", NULL, db_show_local1 },
93	{ "l2", NULL, db_show_local2 },
94	{ "l3", NULL, db_show_local3 },
95	{ "l4", NULL, db_show_local4 },
96	{ "l5", NULL, db_show_local5 },
97	{ "l6", NULL, db_show_local6 },
98	{ "l7", NULL, db_show_local7 },
99	{ "tstate", &ddb_regs.tf_tstate, FCN_NULL },
100	{ "tpc", &ddb_regs.tf_tpc, FCN_NULL },
101	{ "tnpc", &ddb_regs.tf_tnpc, FCN_NULL }
102};
103struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
104
105void
106db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
107		   char *modif)
108{
109	struct trapframe *tf;
110	struct kdbframe *kfp;
111	struct frame *fp;
112	const char *name;
113	c_db_sym_t sym;
114	db_expr_t offset;
115	db_expr_t value;
116	db_addr_t nfp;
117	db_addr_t npc;
118	db_addr_t pc;
119	int trap;
120	int user;
121
122	trap = 0;
123	user = 0;
124	npc = 0;
125	if (count == -1)
126		count = 1024;
127	if (!have_addr) {
128		kfp = (struct kdbframe *)DDB_REGS->tf_arg;
129		fp = (struct frame *)(kfp->kf_cfp + SPOFF);
130	} else
131		fp = (struct frame *)(addr + SPOFF);
132	while (count-- && !user) {
133		pc = (db_addr_t)db_get_value((db_addr_t)&fp->f_pc,
134		    sizeof(db_addr_t), FALSE);
135		if (trap) {
136			pc = npc;
137			trap = 0;
138		}
139		if (!INKERNEL((vm_offset_t)pc))
140			break;
141		sym = db_search_symbol(pc, DB_STGY_ANY, &offset);
142		if (sym == C_DB_SYM_NULL) {
143			value = 0;
144			name = NULL;
145		} else
146			db_symbol_values(sym, &name, &value);
147		if (name == NULL)
148			name = "(null)";
149		if (bcmp(name, "tl0_", 4) == 0 ||
150		    bcmp(name, "tl1_", 4) == 0) {
151			nfp = db_get_value((db_addr_t)&fp->f_fp,
152			    sizeof(u_long), FALSE) + SPOFF;
153			tf = (struct trapframe *)(nfp + sizeof(*fp));
154			npc = db_get_value((db_addr_t)&tf->tf_tpc,
155			    sizeof(u_long), FALSE);
156			user = db_print_trap(tf);
157			trap = 1;
158		} else {
159			db_printf("%s() at ", name);
160			db_printsym(pc, DB_STGY_PROC);
161			db_printf("\n");
162		}
163		fp = (struct frame *)(db_get_value((db_addr_t)&fp->f_fp,
164		   sizeof(u_long), FALSE) + SPOFF);
165	}
166}
167
168static int
169db_print_trap(struct trapframe *tf)
170{
171	struct mmuframe *mf;
172	u_long type;
173	u_long va;
174
175	type = db_get_value((db_addr_t)&tf->tf_type, sizeof(u_long), FALSE);
176	db_printf("-- %s trap (%s) -- ", type & T_KERNEL ? "kernel" : "user",
177	    trap_msg[type & ~T_KERNEL]);
178	if ((type & T_KERNEL) == 0)
179		db_printf("tpc=0x%lx, tnpc=0x%lx ", tf->tf_tpc, tf->tf_tnpc);
180	switch (type & ~T_KERNEL) {
181	case T_ALIGN:
182		mf = (struct mmuframe *)db_get_value((db_addr_t)&tf->tf_arg,
183		    sizeof(void *), FALSE);
184		va = (u_long)db_get_value((db_addr_t)&mf->mf_sfar,
185		    sizeof(u_long), FALSE);
186		db_printf("va=%#lx", va);
187		break;
188	default:
189		break;
190	}
191	db_printf("\n");
192	return ((type & T_KERNEL) == 0);
193}
194
195DB_COMMAND(down, db_frame_down)
196{
197	struct kdbframe *kfp;
198	struct frame *fp;
199	u_long cfp;
200	u_long ofp;
201
202	kfp = (struct kdbframe *)DDB_REGS->tf_arg;
203	fp = (struct frame *)(kfp->kf_fp + SPOFF);
204	cfp = kfp->kf_cfp;
205	for (;;) {
206		if (!INKERNEL((u_long)fp)) {
207			db_printf("already at bottom\n");
208			break;
209		}
210		ofp = db_get_value((db_addr_t)&fp->f_fp, sizeof(u_long),
211		    FALSE);
212		if (ofp == cfp) {
213			kfp->kf_cfp = (u_long)fp - SPOFF;
214			break;
215		}
216		fp = (struct frame *)(ofp + SPOFF);
217	}
218}
219
220DB_COMMAND(up, db_frame_up)
221{
222	struct kdbframe *kfp;
223	struct frame *cfp;
224
225	kfp = (struct kdbframe *)DDB_REGS->tf_arg;
226	cfp = (struct frame *)(kfp->kf_cfp + SPOFF);
227	if (!INKERNEL((u_long)cfp)) {
228		db_printf("already at top\n");
229		return;
230	}
231	kfp->kf_cfp = db_get_value((db_addr_t)&cfp->f_fp, sizeof(u_long),
232	    FALSE);
233}
234
235#define	DB_SHOW_REG(name, num)						\
236static int								\
237db_show_ ## name ## num(struct db_variable *dp, db_expr_t *vp, int op)	\
238{									\
239	struct kdbframe *kfp;						\
240	struct frame *fp;						\
241									\
242	kfp = (struct kdbframe *)DDB_REGS->tf_arg;			\
243	fp = (struct frame *)(kfp->kf_cfp + SPOFF);			\
244	if (op == DB_VAR_GET)						\
245		*vp = db_get_value((db_addr_t)&fp->f_ ## name ## [num],	\
246		    sizeof(u_long), FALSE);				\
247	else								\
248		db_put_value((db_addr_t)&fp->f_ ## name ## [num],	\
249		    sizeof(u_long), *vp);				\
250	return (0);							\
251}
252
253DB_SHOW_REG(in, 0)
254DB_SHOW_REG(in, 1)
255DB_SHOW_REG(in, 2)
256DB_SHOW_REG(in, 3)
257DB_SHOW_REG(in, 4)
258DB_SHOW_REG(in, 5)
259DB_SHOW_REG(in, 6)
260DB_SHOW_REG(in, 7)
261DB_SHOW_REG(local, 0)
262DB_SHOW_REG(local, 1)
263DB_SHOW_REG(local, 2)
264DB_SHOW_REG(local, 3)
265DB_SHOW_REG(local, 4)
266DB_SHOW_REG(local, 5)
267DB_SHOW_REG(local, 6)
268DB_SHOW_REG(local, 7)
269