]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - 6/sys/sparc64/sparc64/db_trace.c
Clone Kip's Xen on stable/6 tree so that I can work on improving FreeBSD/amd64
[FreeBSD/FreeBSD.git] / 6 / sys / sparc64 / sparc64 / db_trace.c
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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kdb.h>
33 #include <sys/linker_set.h>
34 #include <sys/proc.h>
35 #include <sys/stack.h>
36 #include <sys/sysent.h>
37
38 #include <vm/vm.h>
39 #include <vm/vm_page.h>
40 #include <vm/vm_map.h>
41
42 #include <machine/cpu.h>
43 #include <machine/pcb.h>
44 #include <machine/trap.h>
45 #include <machine/vmparam.h>
46
47 #include <ddb/ddb.h>
48 #include <ddb/db_access.h>
49 #include <ddb/db_sym.h>
50 #include <ddb/db_variables.h>
51 #include <ddb/db_watch.h>
52
53 extern char tl_trap_begin[];
54 extern char tl_trap_end[];
55 extern char tl_text_begin[];
56 extern char tl_text_end[];
57
58 #define INKERNEL(va) \
59         ((va) >= VM_MIN_KERNEL_ADDRESS && (va) <= VM_MAX_KERNEL_ADDRESS)
60
61 static db_varfcn_t db_frame;
62
63 #define DB_OFFSET(x)    (db_expr_t *)offsetof(struct trapframe, x)
64 struct  db_variable db_regs[] = {
65         { "g0",         DB_OFFSET(tf_global[0]),        db_frame },
66         { "g1",         DB_OFFSET(tf_global[1]),        db_frame },
67         { "g2",         DB_OFFSET(tf_global[2]),        db_frame },
68         { "g3",         DB_OFFSET(tf_global[3]),        db_frame },
69         { "g4",         DB_OFFSET(tf_global[4]),        db_frame },
70         { "g5",         DB_OFFSET(tf_global[5]),        db_frame },
71         { "g6",         DB_OFFSET(tf_global[6]),        db_frame },
72         { "g7",         DB_OFFSET(tf_global[7]),        db_frame },
73         { "i0",         DB_OFFSET(tf_out[0]),           db_frame },
74         { "i1",         DB_OFFSET(tf_out[1]),           db_frame },
75         { "i2",         DB_OFFSET(tf_out[2]),           db_frame },
76         { "i3",         DB_OFFSET(tf_out[3]),           db_frame },
77         { "i4",         DB_OFFSET(tf_out[4]),           db_frame },
78         { "i5",         DB_OFFSET(tf_out[5]),           db_frame },
79         { "i6",         DB_OFFSET(tf_out[6]),           db_frame },
80         { "i7",         DB_OFFSET(tf_out[7]),           db_frame },
81         { "tnpc",       DB_OFFSET(tf_tnpc),             db_frame },
82         { "tpc",        DB_OFFSET(tf_tpc),              db_frame },
83         { "tstate",     DB_OFFSET(tf_tstate),           db_frame },
84 };
85 struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
86
87 static int
88 db_frame(struct db_variable *vp, db_expr_t *valuep, int op)
89 {
90         uint64_t *reg;
91
92         if (kdb_frame == NULL)
93                 return (0);
94         reg = (uint64_t*)((uintptr_t)kdb_frame + (uintptr_t)vp->valuep);
95         if (op == DB_VAR_GET)
96                 *valuep = *reg;
97         else
98                 *reg = *valuep;
99         return (1);
100 }
101
102 /*
103  * User stack trace (debugging aid).
104  */
105 static void
106 db_utrace(struct thread *td, struct trapframe *tf, int count, int *quitp)
107 {
108         struct pcb *pcb;
109         db_addr_t sp, rsp, o7, pc;
110         int i, found;
111
112         pcb = td->td_pcb;
113         sp = db_get_value((db_addr_t)&tf->tf_sp, sizeof(tf->tf_sp), FALSE);
114         o7 = db_get_value((db_addr_t)&tf->tf_out[7], sizeof(tf->tf_out[7]),
115             FALSE);
116         pc = db_get_value((db_addr_t)&tf->tf_tpc, sizeof(tf->tf_tpc), FALSE);
117         db_printf("user trace: trap %%o7=%#lx\n", o7);
118         while (count-- && sp != 0 && !*quitp) {
119                 db_printf("pc %#lx, sp %#lx\n", pc, sp);
120                 /* First, check whether the frame is in the pcb. */
121                 found = 0;
122                 for (i = 0; i < pcb->pcb_nsaved; i++) {
123                         if (pcb->pcb_rwsp[i] == sp) {
124                                 found = 1;
125                                 sp = pcb->pcb_rw[i].rw_in[6];
126                                 pc = pcb->pcb_rw[i].rw_in[7];
127                                 break;
128                         }
129                 }
130                 if (!found) {
131                         rsp = sp + SPOFF;
132                         sp = 0;
133                         if (copyin((void *)(rsp + offsetof(struct frame, fr_fp)),
134                             &sp, sizeof(sp)) != 0 ||
135                             copyin((void *)(rsp + offsetof(struct frame, fr_pc)),
136                             &pc, sizeof(pc)) != 0)
137                                 break;
138                 }
139         }
140         db_printf("done\n");
141 }
142
143 static int
144 db_print_trap(struct thread *td, struct trapframe *tf, int count, int *quitp)
145 {
146         struct proc *p;
147         const char *symname;
148         c_db_sym_t sym;
149         db_expr_t diff;
150         db_addr_t func;
151         db_addr_t tpc;
152         u_long type;
153         u_long sfar;
154         u_long sfsr;
155         u_long tar;
156         u_long level;
157         u_long pil;
158         u_long code;
159         u_long o7;
160         int user;
161
162         p = td->td_proc;
163         type = db_get_value((db_addr_t)&tf->tf_type,
164             sizeof(tf->tf_type), FALSE);
165         db_printf("-- %s", trap_msg[type & ~T_KERNEL]);
166         switch (type & ~T_KERNEL) {
167         case T_DATA_PROTECTION:
168                 tar = (u_long)db_get_value((db_addr_t)&tf->tf_tar,
169                     sizeof(tf->tf_tar), FALSE);
170                 db_printf(" tar=%#lx", tar);
171                 /* fall through */
172         case T_DATA_EXCEPTION:
173         case T_INSTRUCTION_EXCEPTION:
174         case T_MEM_ADDRESS_NOT_ALIGNED:
175                 sfar = (u_long)db_get_value((db_addr_t)&tf->tf_sfar,
176                     sizeof(tf->tf_sfar), FALSE);
177                 sfsr = (u_long)db_get_value((db_addr_t)&tf->tf_sfsr,
178                     sizeof(tf->tf_sfsr), FALSE);
179                 db_printf(" sfar=%#lx sfsr=%#lx", sfar, sfsr);
180                 break;
181         case T_DATA_MISS:
182         case T_INSTRUCTION_MISS:
183                 tar = (u_long)db_get_value((db_addr_t)&tf->tf_tar,
184                     sizeof(tf->tf_tar), FALSE);
185                 db_printf(" tar=%#lx", tar);
186                 break;
187         case T_SYSCALL:
188                 code = db_get_value((db_addr_t)&tf->tf_global[1],
189                     sizeof(tf->tf_global[1]), FALSE);
190                 db_printf(" (%ld", code);
191                 if (code >= 0 && code < p->p_sysent->sv_size) {
192                         func = (db_addr_t)p->p_sysent->sv_table[code].sy_call;
193                         sym = db_search_symbol(func, DB_STGY_ANY, &diff);
194                         if (sym != DB_SYM_NULL && diff == 0) {
195                                 db_symbol_values(sym, &symname, NULL);
196                                 db_printf(", %s, %s", p->p_sysent->sv_name,
197                                     symname);
198                         }
199                         db_printf(")");
200                 }
201                 break;
202         case T_INTERRUPT:
203                 level = (u_long)db_get_value((db_addr_t)&tf->tf_level,
204                     sizeof(tf->tf_level), FALSE);
205                 pil = (u_long)db_get_value((db_addr_t)&tf->tf_pil,
206                     sizeof(tf->tf_pil), FALSE);
207                 db_printf(" level=%#lx pil=%#lx", level, pil);
208                 break;
209         default:
210                 break;
211         }
212         o7 = (u_long)db_get_value((db_addr_t)&tf->tf_out[7],
213             sizeof(tf->tf_out[7]), FALSE);
214         db_printf(" %%o7=%#lx --\n", o7);
215         user = (type & T_KERNEL) == 0;
216         if (user) {
217                 tpc = db_get_value((db_addr_t)&tf->tf_tpc,
218                     sizeof(tf->tf_tpc), FALSE);
219                 db_printf("userland() at ");
220                 db_printsym(tpc, DB_STGY_PROC);
221                 db_printf("\n");
222                 db_utrace(td, tf, count, quitp);
223         }
224         return (user);
225 }
226
227 static int
228 db_backtrace(struct thread *td, struct frame *fp, int count)
229 {
230         struct trapframe *tf;
231         const char *name;
232         c_db_sym_t sym;
233         db_expr_t offset;
234         db_expr_t value;
235         db_addr_t npc;
236         db_addr_t pc;
237         int trap;
238         int user;
239         int quit;
240
241         if (count == -1)
242                 count = 1024;
243
244         trap = 0;
245         user = 0;
246         npc = 0;
247         quit = 0;
248         db_setup_paging(db_simple_pager, &quit, db_lines_per_page);
249         while (count-- && !user && !quit) {
250                 pc = (db_addr_t)db_get_value((db_addr_t)&fp->fr_pc,
251                     sizeof(fp->fr_pc), FALSE);
252                 if (trap) {
253                         pc = npc;
254                         trap = 0;
255                 }
256                 if (!INKERNEL((vm_offset_t)pc))
257                         break;
258                 sym = db_search_symbol(pc, DB_STGY_ANY, &offset);
259                 if (sym == C_DB_SYM_NULL) {
260                         value = 0;
261                         name = NULL;
262                 } else
263                         db_symbol_values(sym, &name, &value);
264                 if (name == NULL)
265                         name = "(null)";
266                 fp = (struct frame *)(db_get_value((db_addr_t)&fp->fr_fp,
267                    sizeof(fp->fr_fp), FALSE) + SPOFF);
268                 if ((value > (u_long)tl_trap_begin &&
269                     value < (u_long)tl_trap_end) ||
270                     (value > (u_long)tl_text_begin &&
271                     value < (u_long)tl_text_end)) {
272                         tf = (struct trapframe *)(fp + 1);
273                         npc = db_get_value((db_addr_t)&tf->tf_tpc,
274                             sizeof(tf->tf_tpc), FALSE);
275                         user = db_print_trap(td, tf, count, &quit);
276                         trap = 1;
277                 } else {
278                         db_printf("%s() at ", name);
279                         db_printsym(pc, DB_STGY_PROC);
280                         db_printf("\n");
281                 }
282         }
283         return (0);
284 }
285
286 void
287 db_trace_self(void)
288 {
289         db_expr_t addr;
290
291         addr = (db_expr_t)__builtin_frame_address(1);
292         db_backtrace(curthread, (struct frame *)(addr + SPOFF), -1);
293 }
294
295 int
296 db_trace_thread(struct thread *td, int count)
297 {
298         struct pcb *ctx;
299
300         ctx = kdb_thr_ctx(td);
301         return (db_backtrace(td, (struct frame*)(ctx->pcb_sp + SPOFF), count));
302 }
303
304 void
305 stack_save(struct stack *st)
306 {
307         struct frame *fp;
308         db_expr_t addr;
309         vm_offset_t callpc;
310
311         stack_zero(st);
312         addr = (db_expr_t)__builtin_frame_address(1);
313         fp = (struct frame *)(addr + SPOFF);
314         while (1) {
315                 callpc = fp->fr_pc;
316                 if (!INKERNEL(callpc))
317                         break;
318                 /* Don't bother traversing trap frames. */
319                 if ((callpc > (u_long)tl_trap_begin &&
320                     callpc < (u_long)tl_trap_end) ||
321                     (callpc > (u_long)tl_text_begin &&
322                     callpc < (u_long)tl_text_end))
323                         break;
324                 if (stack_put(st, callpc) == -1)
325                         break;
326                 fp = (struct frame *)(fp->fr_fp + SPOFF);
327         }
328 }