db_trace.c revision 620
155714Skris/* 255714Skris * Mach Operating System 355714Skris * Copyright (c) 1991,1990 Carnegie Mellon University 455714Skris * All Rights Reserved. 555714Skris * 655714Skris * Permission to use, copy, modify and distribute this software and its 755714Skris * documentation is hereby granted, provided that both the copyright 8296341Sdelphij * notice and this permission notice appear in all copies of the 955714Skris * software, derivative works or modified versions, and any portions 1055714Skris * thereof, and that both notices appear in supporting documentation. 1155714Skris * 1255714Skris * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 1355714Skris * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 1455714Skris * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 15296341Sdelphij * 1655714Skris * Carnegie Mellon requests users of this software to return to 1755714Skris * 1855714Skris * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 1955714Skris * School of Computer Science 2055714Skris * Carnegie Mellon University 2155714Skris * Pittsburgh PA 15213-3890 22296341Sdelphij * 2355714Skris * any improvements or extensions that they make and grant Carnegie the 2455714Skris * rights to redistribute these changes. 2555714Skris * 2655714Skris * $Id$ 2755714Skris */ 2855714Skris 2955714Skris#include "param.h" 3055714Skris#include "proc.h" 3155714Skris#include <machine/db_machdep.h> 3255714Skris 3355714Skris#include <ddb/db_access.h> 3455714Skris#include <ddb/db_sym.h> 3555714Skris#include <ddb/db_variables.h> 3655714Skris 37296341Sdelphij/* 3855714Skris * Machine register set. 3955714Skris */ 40296341Sdelphijstruct db_variable db_regs[] = { 4155714Skris "cs", (int *)&ddb_regs.tf_cs, FCN_NULL, 4255714Skris "ds", (int *)&ddb_regs.tf_ds, FCN_NULL, 4355714Skris "es", (int *)&ddb_regs.tf_es, FCN_NULL, 4455714Skris#if 0 4555714Skris "fs", (int *)&ddb_regs.tf_fs, FCN_NULL, 4655714Skris "gs", (int *)&ddb_regs.tf_gs, FCN_NULL, 4755714Skris#endif 4855714Skris "ss", (int *)&ddb_regs.tf_ss, FCN_NULL, 4955714Skris "eax", (int *)&ddb_regs.tf_eax, FCN_NULL, 5055714Skris "ecx", (int *)&ddb_regs.tf_ecx, FCN_NULL, 5155714Skris "edx", (int *)&ddb_regs.tf_edx, FCN_NULL, 52296341Sdelphij "ebx", (int *)&ddb_regs.tf_ebx, FCN_NULL, 5355714Skris "esp", (int *)&ddb_regs.tf_esp,FCN_NULL, 5455714Skris "ebp", (int *)&ddb_regs.tf_ebp, FCN_NULL, 5555714Skris "esi", (int *)&ddb_regs.tf_esi, FCN_NULL, 5655714Skris "edi", (int *)&ddb_regs.tf_edi, FCN_NULL, 5755714Skris "eip", (int *)&ddb_regs.tf_eip, FCN_NULL, 5855714Skris "efl", (int *)&ddb_regs.tf_eflags, FCN_NULL, 5955714Skris}; 6055714Skrisstruct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); 6155714Skris 6255714Skris/* 6355714Skris * Stack trace. 6455714Skris */ 6555714Skris#define INKERNEL(va) (((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS) 6655714Skris 6755714Skrisstruct i386_frame { 6855714Skris struct i386_frame *f_frame; 69296341Sdelphij int f_retaddr; 7055714Skris int f_arg0; 7159191Skris}; 7259191Skris 7355714Skris#define TRAP 1 74296341Sdelphij#define INTERRUPT 2 75296341Sdelphij 76296341Sdelphijdb_addr_t db_trap_symbol_value = 0; 77296341Sdelphijdb_addr_t db_kdintr_symbol_value = 0; 7855714Skrisboolean_t db_trace_symbols_found = FALSE; 79296341Sdelphij 8055714Skrisvoid 81296341Sdelphijdb_find_trace_symbols() 82296341Sdelphij{ 83296341Sdelphij db_expr_t value; 8455714Skris if (db_value_of_name("_trap", &value)) 85296341Sdelphij db_trap_symbol_value = (db_addr_t) value; 8655714Skris if (db_value_of_name("_kdintr", &value)) 87296341Sdelphij db_kdintr_symbol_value = (db_addr_t) value; 88296341Sdelphij db_trace_symbols_found = TRUE; 8955714Skris} 90296341Sdelphij 91296341Sdelphij/* 92109998Smarkm * Figure out how many arguments were passed into the frame at "fp". 93296341Sdelphij */ 94296341Sdelphijint 95296341Sdelphijdb_numargs(fp) 96296341Sdelphij struct i386_frame *fp; 9768651Skris{ 98296341Sdelphij int *argp; 99296341Sdelphij int inst; 100296341Sdelphij int args; 101296341Sdelphij extern char etext[]; 102296341Sdelphij 103296341Sdelphij argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE); 104296341Sdelphij if (argp < (int *)VM_MIN_KERNEL_ADDRESS || argp > (int *)etext) 105296341Sdelphij args = 5; 106296341Sdelphij else { 107296341Sdelphij inst = db_get_value((int)argp, 4, FALSE); 10855714Skris if ((inst & 0xff) == 0x59) /* popl %ecx */ 109296341Sdelphij args = 1; 110296341Sdelphij else if ((inst & 0xffff) == 0xc483) /* addl %n, %esp */ 111296341Sdelphij args = ((inst >> 16) & 0xff) / 4; 112296341Sdelphij else 113296341Sdelphij args = 5; 114296341Sdelphij } 115296341Sdelphij return (args); 116296341Sdelphij} 117296341Sdelphij 118296341Sdelphij/* 119296341Sdelphij * Figure out the next frame up in the call stack. 120296341Sdelphij * For trap(), we print the address of the faulting instruction and 121296341Sdelphij * 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. 127 */ 128void 129db_nextframe(fp, ip, argp, is_trap) 130 struct i386_frame **fp; /* in/out */ 131 db_addr_t *ip; /* out */ 132 int *argp; /* in */ 133 int is_trap; /* in */ 134{ 135 struct i386_saved_state *saved_regs; 136 137 if (is_trap == 0) { 138 *ip = (db_addr_t) 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); 142 } else { 143 /* 144 * We know that trap() has 1 argument and we know that 145 * it is an (int *). 146 */ 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); 152 db_printf(":\n"); 153 *fp = (struct i386_frame *)saved_regs->tf_ebp; 154 *ip = (db_addr_t)saved_regs->tf_eip; 155 } 156 157} 158 159void 160db_stack_trace_cmd(addr, have_addr, count, modif) 161 db_expr_t addr; 162 boolean_t have_addr; 163 db_expr_t count; 164 char *modif; 165{ 166 struct i386_frame *frame, *lastframe; 167 int *argp; 168 db_addr_t callpc; 169 int is_trap; 170 boolean_t kernel_only = TRUE; 171 boolean_t trace_thread = FALSE; 172 173 if (!db_trace_symbols_found) 174 db_find_trace_symbols(); 175 176 { 177 register char *cp = modif; 178 register char c; 179 180 while ((c = *cp++) != 0) { 181 if (c == 't') 182 trace_thread = TRUE; 183 if (c == 'u') 184 kernel_only = FALSE; 185 } 186 } 187 188 if (count == -1) 189 count = 65535; 190 191 if (!have_addr) { 192 frame = (struct i386_frame *)ddb_regs.tf_ebp; 193 callpc = (db_addr_t)ddb_regs.tf_eip; 194 } 195 else if (trace_thread) { 196 printf ("db_trace.c: can't trace thread\n"); 197 } 198 else { 199 frame = (struct i386_frame *)addr; 200 callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE); 201 } 202 203 lastframe = 0; 204 while (count-- && frame != 0) { 205 register int narg; 206 char * name; 207 db_expr_t offset; 208 209 if (INKERNEL((int)frame) && callpc == db_trap_symbol_value) { 210 narg = 1; 211 is_trap = TRAP; 212 } 213 else 214 if (INKERNEL((int)frame) && callpc == db_kdintr_symbol_value) { 215 is_trap = INTERRUPT; 216 narg = 0; 217 } 218 else { 219 is_trap = 0; 220 narg = db_numargs(frame); 221 } 222 223 db_find_sym_and_offset(callpc, &name, &offset); 224 db_printf("%s(", name); 225 226 argp = &frame->f_arg0; 227 while (narg) { 228 db_printf("%x", db_get_value((int)argp, 4, FALSE)); 229 argp++; 230 if (--narg != 0) 231 db_printf(","); 232 } 233 db_printf(") at "); 234 db_printsym(callpc, DB_STGY_XTRN); 235 db_printf("\n"); 236 237 lastframe = frame; 238 db_nextframe(&frame, &callpc, &frame->f_arg0, is_trap); 239 240 if (frame == 0) { 241 /* end of chain */ 242 break; 243 } 244 if (INKERNEL((int)frame)) { 245 /* staying in kernel */ 246 if (frame <= lastframe) { 247 db_printf("Bad frame pointer: 0x%x\n", frame); 248 break; 249 } 250 } 251 else if (INKERNEL((int)lastframe)) { 252 /* switch from user to kernel */ 253 if (kernel_only) 254 break; /* kernel stack only */ 255 } 256 else { 257 /* in user */ 258 if (frame <= lastframe) { 259 db_printf("Bad frame pointer: 0x%x\n", frame); 260 break; 261 } 262 } 263 } 264} 265