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: releng/5.2/sys/sparc64/sparc64/db_trace.c 119291 2003-08-22 07:39:05Z imp $
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/sysent.h>
34 #include <sys/user.h>
35
36 #include <vm/vm.h>
37 #include <vm/vm_page.h>
38 #include <vm/vm_map.h>
39
40 #include <machine/cpu.h>
41 #include <machine/trap.h>
42 #include <machine/vmparam.h>
43
44 #include <ddb/ddb.h>
45 #include <ddb/db_access.h>
46 #include <ddb/db_sym.h>
47 #include <ddb/db_variables.h>
48 #include <ddb/db_watch.h>
49
50 static int db_print_trap(struct thread *td, struct trapframe *);
51 static void db_utrace(struct thread *td, struct trapframe *tf);
52
53 #define INKERNEL(va) \
54 ((va) >= VM_MIN_KERNEL_ADDRESS && (va) <= VM_MAX_KERNEL_ADDRESS)
55
56 struct db_variable db_regs[] = {
57 { "g0", &ddb_regs.tf_global[0], FCN_NULL },
58 { "g1", &ddb_regs.tf_global[1], FCN_NULL },
59 { "g2", &ddb_regs.tf_global[2], FCN_NULL },
60 { "g3", &ddb_regs.tf_global[3], FCN_NULL },
61 { "g4", &ddb_regs.tf_global[4], FCN_NULL },
62 { "g5", &ddb_regs.tf_global[5], FCN_NULL },
63 { "g6", &ddb_regs.tf_global[6], FCN_NULL },
64 { "g7", &ddb_regs.tf_global[7], FCN_NULL },
65 { "i0", &ddb_regs.tf_out[0], FCN_NULL },
66 { "i1", &ddb_regs.tf_out[1], FCN_NULL },
67 { "i2", &ddb_regs.tf_out[2], FCN_NULL },
68 { "i3", &ddb_regs.tf_out[3], FCN_NULL },
69 { "i4", &ddb_regs.tf_out[4], FCN_NULL },
70 { "i5", &ddb_regs.tf_out[5], FCN_NULL },
71 { "i6", &ddb_regs.tf_out[6], FCN_NULL },
72 { "i7", &ddb_regs.tf_out[7], FCN_NULL },
73 { "tnpc", &ddb_regs.tf_tnpc, FCN_NULL },
74 { "tpc", &ddb_regs.tf_tpc, FCN_NULL },
75 { "tstate", &ddb_regs.tf_tstate, FCN_NULL },
76 };
77 struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
78
79 void
80 db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
81 char *modif)
82 {
83 struct trapframe *tf;
84 struct frame *fp;
85 struct proc *p;
86 struct thread *td;
87 const char *name;
88 c_db_sym_t sym;
89 db_expr_t offset;
90 db_expr_t value;
91 db_addr_t npc;
92 db_addr_t pc;
93 int trap;
94 int user;
95 pid_t pid;
96
97 trap = 0;
98 user = 0;
99 npc = 0;
100 if (count == -1)
101 count = 1024;
102 td = curthread;
103 p = td->td_proc;
104 /*
105 * Provide an /a modifier to pass the stack address instead of a PID
106 * as argument.
107 * Note that, if this address is not on the stack of curthread, the
108 * printed data may be wrong (at the moment, this applies only to the
109 * sysent list).
110 */
111 if (!have_addr)
112 addr = DDB_REGS->tf_out[6];
113 else if (strcmp(modif, "a") != 0) {
114 /*
115 * addr was parsed as hex, convert so it is interpreted as
116 * decimal (ugh).
117 */
118 pid = (addr % 16) + ((addr >> 4) % 16) * 10 +
119 ((addr >> 8) % 16) * 100 + ((addr >> 12) % 16) * 1000 +
120 ((addr >> 16) % 16) * 10000;
121 /*
122 * The pcb for curproc is not valid at this point,
123 * so fall back to the default case.
124 */
125 if (pid == curthread->td_proc->p_pid) {
126 td = curthread;
127 p = td->td_proc;
128 addr = DDB_REGS->tf_out[6];
129 } else {
130 /* sx_slock(&allproc_lock); */
131 LIST_FOREACH(p, &allproc, p_list) {
132 if (p->p_pid == pid)
133 break;
134 }
135 /* sx_sunlock(&allproc_lock); */
136 if (p == NULL) {
137 db_printf("pid %d not found\n", pid);
138 return;
139 }
140 if ((p->p_sflag & PS_INMEM) == 0) {
141 db_printf("pid %d swapped out\n", pid);
142 return;
143 }
144 td = FIRST_THREAD_IN_PROC(p); /* XXXKSE */
145 addr = td->td_pcb->pcb_sp;
146 }
147 }
148 fp = (struct frame *)(addr + SPOFF);
149
150 while (count-- && !user) {
151 pc = (db_addr_t)db_get_value((db_addr_t)&fp->fr_pc,
152 sizeof(fp->fr_pc), FALSE);
153 if (trap) {
154 pc = npc;
155 trap = 0;
156 }
157 if (!INKERNEL((vm_offset_t)pc))
158 break;
159 sym = db_search_symbol(pc, DB_STGY_ANY, &offset);
160 if (sym == C_DB_SYM_NULL) {
161 value = 0;
162 name = NULL;
163 } else
164 db_symbol_values(sym, &name, &value);
165 if (name == NULL)
166 name = "(null)";
167 fp = (struct frame *)(db_get_value((db_addr_t)&fp->fr_fp,
168 sizeof(fp->fr_fp), FALSE) + SPOFF);
169 if (bcmp(name, "tl0_", 4) == 0 ||
170 bcmp(name, "tl1_", 4) == 0) {
171 tf = (struct trapframe *)(fp + 1);
172 npc = db_get_value((db_addr_t)&tf->tf_tpc,
173 sizeof(tf->tf_tpc), FALSE);
174 user = db_print_trap(td, tf);
175 trap = 1;
176 } else {
177 db_printf("%s() at ", name);
178 db_printsym(pc, DB_STGY_PROC);
179 db_printf("\n");
180 }
181 }
182 }
183
184 static int
185 db_print_trap(struct thread *td, struct trapframe *tf)
186 {
187 struct proc *p;
188 const char *symname;
189 c_db_sym_t sym;
190 db_expr_t diff;
191 db_addr_t func;
192 db_addr_t tpc;
193 u_long type;
194 u_long sfar;
195 u_long sfsr;
196 u_long tar;
197 u_long level;
198 u_long pil;
199 u_long code;
200 u_long o7;
201 int user;
202
203 p = td->td_proc;
204 type = db_get_value((db_addr_t)&tf->tf_type,
205 sizeof(tf->tf_type), FALSE);
206 db_printf("-- %s", trap_msg[type & ~T_KERNEL]);
207 switch (type & ~T_KERNEL) {
208 case T_DATA_PROTECTION:
209 tar = (u_long)db_get_value((db_addr_t)&tf->tf_tar,
210 sizeof(tf->tf_tar), FALSE);
211 db_printf(" tar=%#lx", tar);
212 /* fall through */
213 case T_DATA_EXCEPTION:
214 case T_INSTRUCTION_EXCEPTION:
215 case T_MEM_ADDRESS_NOT_ALIGNED:
216 sfar = (u_long)db_get_value((db_addr_t)&tf->tf_sfar,
217 sizeof(tf->tf_sfar), FALSE);
218 sfsr = (u_long)db_get_value((db_addr_t)&tf->tf_sfsr,
219 sizeof(tf->tf_sfsr), FALSE);
220 db_printf(" sfar=%#lx sfsr=%#lx", sfar, sfsr);
221 break;
222 case T_DATA_MISS:
223 case T_INSTRUCTION_MISS:
224 tar = (u_long)db_get_value((db_addr_t)&tf->tf_tar,
225 sizeof(tf->tf_tar), FALSE);
226 db_printf(" tar=%#lx", tar);
227 break;
228 case T_SYSCALL:
229 code = db_get_value((db_addr_t)&tf->tf_global[1],
230 sizeof(tf->tf_global[1]), FALSE);
231 db_printf(" (%ld", code);
232 if (code >= 0 && code < p->p_sysent->sv_size) {
233 func = (db_addr_t)p->p_sysent->sv_table[code].sy_call;
234 sym = db_search_symbol(func, DB_STGY_ANY, &diff);
235 if (sym != DB_SYM_NULL && diff == 0) {
236 db_symbol_values(sym, &symname, NULL);
237 db_printf(", %s, %s", p->p_sysent->sv_name,
238 symname);
239 }
240 db_printf(")");
241 }
242 break;
243 case T_INTERRUPT:
244 level = (u_long)db_get_value((db_addr_t)&tf->tf_level,
245 sizeof(tf->tf_level), FALSE);
246 pil = (u_long)db_get_value((db_addr_t)&tf->tf_pil,
247 sizeof(tf->tf_pil), FALSE);
248 db_printf(" level=%#lx pil=%#lx", level, pil);
249 break;
250 default:
251 break;
252 }
253 o7 = (u_long)db_get_value((db_addr_t)&tf->tf_out[7],
254 sizeof(tf->tf_out[7]), FALSE);
255 db_printf(" %%o7=%#lx --\n", o7);
256 user = (type & T_KERNEL) == 0;
257 if (user) {
258 tpc = db_get_value((db_addr_t)&tf->tf_tpc,
259 sizeof(tf->tf_tpc), FALSE);
260 db_printf("userland() at ");
261 db_printsym(tpc, DB_STGY_PROC);
262 db_printf("\n");
263 db_utrace(td, tf);
264 }
265 return (user);
266 }
267
268 /*
269 * User stack trace (debugging aid).
270 */
271 static void
272 db_utrace(struct thread *td, struct trapframe *tf)
273 {
274 struct pcb *pcb;
275 db_addr_t sp, rsp, o7, pc;
276 int i, found;
277
278 pcb = td->td_pcb;
279 sp = db_get_value((db_addr_t)&tf->tf_sp, sizeof(tf->tf_sp), FALSE);
280 o7 = db_get_value((db_addr_t)&tf->tf_out[7], sizeof(tf->tf_out[7]),
281 FALSE);
282 pc = db_get_value((db_addr_t)&tf->tf_tpc, sizeof(tf->tf_tpc), FALSE);
283 db_printf("user trace: trap %%o7=%#lx\n", o7);
284 while (sp != 0) {
285 db_printf("pc %#lx, sp %#lx\n", pc, sp);
286 /* First, check whether the frame is in the pcb. */
287 found = 0;
288 for (i = 0; i < pcb->pcb_nsaved; i++) {
289 if (pcb->pcb_rwsp[i] == sp) {
290 found = 1;
291 sp = pcb->pcb_rw[i].rw_in[6];
292 pc = pcb->pcb_rw[i].rw_in[7];
293 break;
294 }
295 }
296 if (!found) {
297 rsp = sp + SPOFF;
298 sp = NULL;
299 if (copyin((void *)(rsp + offsetof(struct frame, fr_fp)),
300 &sp, sizeof(sp)) != 0 ||
301 copyin((void *)(rsp + offsetof(struct frame, fr_pc)),
302 &pc, sizeof(pc)) != 0)
303 break;
304 }
305 }
306 db_printf("done\n");
307 }
308
309 void
310 db_print_backtrace(void)
311 {
312 u_long *sp;
313
314 sp = __builtin_frame_address(1);
315 db_stack_trace_cmd((db_expr_t)sp, TRUE, -1, "a");
316 }
Cache object: 384eb369ed426824c3e98ee4fb6fdf8d
|