2 * Mach Operating System
3 * Copyright (c) 1991,1990 Carnegie Mellon University
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
16 * Carnegie Mellon requests users of this software to return to
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
23 * any improvements or extensions that they make and grant Carnegie the
24 * rights to redistribute these changes.
31 #include <machine/db_machdep.h>
33 #include <ddb/db_access.h>
34 #include <ddb/db_sym.h>
35 #include <ddb/db_variables.h>
38 * Machine register set.
40 struct db_variable db_regs[] = {
41 "cs", (int *)&ddb_regs.tf_cs, FCN_NULL,
42 "ds", (int *)&ddb_regs.tf_ds, FCN_NULL,
43 "es", (int *)&ddb_regs.tf_es, FCN_NULL,
45 "fs", (int *)&ddb_regs.tf_fs, FCN_NULL,
46 "gs", (int *)&ddb_regs.tf_gs, FCN_NULL,
48 "ss", (int *)&ddb_regs.tf_ss, FCN_NULL,
49 "eax", (int *)&ddb_regs.tf_eax, FCN_NULL,
50 "ecx", (int *)&ddb_regs.tf_ecx, FCN_NULL,
51 "edx", (int *)&ddb_regs.tf_edx, FCN_NULL,
52 "ebx", (int *)&ddb_regs.tf_ebx, FCN_NULL,
53 "esp", (int *)&ddb_regs.tf_esp,FCN_NULL,
54 "ebp", (int *)&ddb_regs.tf_ebp, FCN_NULL,
55 "esi", (int *)&ddb_regs.tf_esi, FCN_NULL,
56 "edi", (int *)&ddb_regs.tf_edi, FCN_NULL,
57 "eip", (int *)&ddb_regs.tf_eip, FCN_NULL,
58 "efl", (int *)&ddb_regs.tf_eflags, FCN_NULL,
60 struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
65 #define INKERNEL(va) (((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
68 struct i386_frame *f_frame;
76 db_addr_t db_trap_symbol_value = 0;
77 db_addr_t db_kdintr_symbol_value = 0;
78 boolean_t db_trace_symbols_found = FALSE;
81 db_find_trace_symbols()
84 if (db_value_of_name("_trap", &value))
85 db_trap_symbol_value = (db_addr_t) value;
86 if (db_value_of_name("_kdintr", &value))
87 db_kdintr_symbol_value = (db_addr_t) value;
88 db_trace_symbols_found = TRUE;
92 * Figure out how many arguments were passed into the frame at "fp".
96 struct i386_frame *fp;
103 argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE);
104 if (argp < (int *)VM_MIN_KERNEL_ADDRESS || argp > (int *)etext)
107 inst = db_get_value((int)argp, 4, FALSE);
108 if ((inst & 0xff) == 0x59) /* popl %ecx */
110 else if ((inst & 0xffff) == 0xc483) /* addl %n, %esp */
111 args = ((inst >> 16) & 0xff) / 4;
119 * Figure out the next frame up in the call stack.
120 * For trap(), we print the address of the faulting instruction and
121 * proceed with the calling frame. We return the ip that faulted.
122 * If the trap was caused by jumping through a bogus pointer, then
123 * the next line in the backtrace will list some random function as
124 * being called. It should get the argument list correct, though.
125 * It might be possible to dig out from the next frame up the name
126 * of the function that faulted, but that could get hairy.
129 db_nextframe(fp, ip, argp, is_trap)
130 struct i386_frame **fp; /* in/out */
131 db_addr_t *ip; /* out */
133 int is_trap; /* in */
135 struct i386_saved_state *saved_regs;
139 db_get_value((int) &(*fp)->f_retaddr, 4, FALSE);
140 *fp = (struct i386_frame *)
141 db_get_value((int) &(*fp)->f_frame, 4, FALSE);
144 * We know that trap() has 1 argument and we know that
147 saved_regs = (struct i386_saved_state *)
148 db_get_value((int)argp, 4, FALSE);
149 db_printf("--- trap (number %d) ---\n",
150 saved_regs->tf_trapno & 0xffff);
151 db_printsym(saved_regs->tf_eip, DB_STGY_XTRN);
153 *fp = (struct i386_frame *)saved_regs->tf_ebp;
154 *ip = (db_addr_t)saved_regs->tf_eip;
160 db_stack_trace_cmd(addr, have_addr, count, modif)
166 struct i386_frame *frame, *lastframe;
170 boolean_t kernel_only = TRUE;
171 boolean_t trace_thread = FALSE;
173 if (!db_trace_symbols_found)
174 db_find_trace_symbols();
177 register char *cp = modif;
180 while ((c = *cp++) != 0) {
192 frame = (struct i386_frame *)ddb_regs.tf_ebp;
193 callpc = (db_addr_t)ddb_regs.tf_eip;
195 else if (trace_thread) {
196 printf ("db_trace.c: can't trace thread\n");
199 frame = (struct i386_frame *)addr;
200 callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE);
204 while (count-- && frame != 0) {
209 if (INKERNEL((int)frame) && callpc == db_trap_symbol_value) {
214 if (INKERNEL((int)frame) && callpc == db_kdintr_symbol_value) {
220 narg = db_numargs(frame);
223 db_find_sym_and_offset(callpc, &name, &offset);
224 db_printf("%s(", name);
226 argp = &frame->f_arg0;
228 db_printf("%x", db_get_value((int)argp, 4, FALSE));
234 db_printsym(callpc, DB_STGY_XTRN);
238 db_nextframe(&frame, &callpc, &frame->f_arg0, is_trap);
244 if (INKERNEL((int)frame)) {
245 /* staying in kernel */
246 if (frame <= lastframe) {
247 db_printf("Bad frame pointer: 0x%x\n", frame);
251 else if (INKERNEL((int)lastframe)) {
252 /* switch from user to kernel */
254 break; /* kernel stack only */
258 if (frame <= lastframe) {
259 db_printf("Bad frame pointer: 0x%x\n", frame);