db_trace.c revision 78903
1/* 2 * Mach Operating System 3 * Copyright (c) 1991,1990 Carnegie Mellon University 4 * All Rights Reserved. 5 * 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. 11 * 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. 15 * 16 * Carnegie Mellon requests users of this software to return to 17 * 18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 19 * School of Computer Science 20 * Carnegie Mellon University 21 * Pittsburgh PA 15213-3890 22 * 23 * any improvements or extensions that they make and grant Carnegie the 24 * rights to redistribute these changes. 25 * 26 * $FreeBSD: head/sys/i386/i386/db_trace.c 78903 2001-06-28 02:08:13Z bsd $ 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 <machine/cpu.h> 37 38#include <vm/vm.h> 39#include <vm/vm_param.h> 40#include <vm/pmap.h> 41#include <ddb/ddb.h> 42 43#include <ddb/db_access.h> 44#include <ddb/db_sym.h> 45#include <ddb/db_variables.h> 46 47db_varfcn_t db_dr0; 48db_varfcn_t db_dr1; 49db_varfcn_t db_dr2; 50db_varfcn_t db_dr3; 51db_varfcn_t db_dr4; 52db_varfcn_t db_dr5; 53db_varfcn_t db_dr6; 54db_varfcn_t db_dr7; 55 56/* 57 * Machine register set. 58 */ 59struct db_variable db_regs[] = { 60 { "cs", &ddb_regs.tf_cs, FCN_NULL }, 61 { "ds", &ddb_regs.tf_ds, FCN_NULL }, 62 { "es", &ddb_regs.tf_es, FCN_NULL }, 63 { "fs", &ddb_regs.tf_fs, FCN_NULL }, 64#if 0 65 { "gs", &ddb_regs.tf_gs, FCN_NULL }, 66#endif 67 { "ss", &ddb_regs.tf_ss, FCN_NULL }, 68 { "eax", &ddb_regs.tf_eax, FCN_NULL }, 69 { "ecx", &ddb_regs.tf_ecx, FCN_NULL }, 70 { "edx", &ddb_regs.tf_edx, FCN_NULL }, 71 { "ebx", &ddb_regs.tf_ebx, FCN_NULL }, 72 { "esp", &ddb_regs.tf_esp, FCN_NULL }, 73 { "ebp", &ddb_regs.tf_ebp, FCN_NULL }, 74 { "esi", &ddb_regs.tf_esi, FCN_NULL }, 75 { "edi", &ddb_regs.tf_edi, FCN_NULL }, 76 { "eip", &ddb_regs.tf_eip, FCN_NULL }, 77 { "efl", &ddb_regs.tf_eflags, FCN_NULL }, 78 { "dr0", NULL, db_dr0 }, 79 { "dr1", NULL, db_dr1 }, 80 { "dr2", NULL, db_dr2 }, 81 { "dr3", NULL, db_dr3 }, 82 { "dr4", NULL, db_dr4 }, 83 { "dr5", NULL, db_dr5 }, 84 { "dr6", NULL, db_dr6 }, 85 { "dr7", NULL, db_dr7 }, 86}; 87struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); 88 89/* 90 * Stack trace. 91 */ 92#define INKERNEL(va) (((vm_offset_t)(va)) >= USRSTACK) 93 94struct i386_frame { 95 struct i386_frame *f_frame; 96 int f_retaddr; 97 int f_arg0; 98}; 99 100#define NORMAL 0 101#define TRAP 1 102#define INTERRUPT 2 103#define SYSCALL 3 104 105static void db_nextframe __P((struct i386_frame **, db_addr_t *, struct proc *)); 106static int db_numargs __P((struct i386_frame *)); 107static void db_print_stack_entry __P((const char *, int, char **, int *, db_addr_t)); 108static void decode_syscall __P((int, struct proc *)); 109 110/* 111 * Figure out how many arguments were passed into the frame at "fp". 112 */ 113static int 114db_numargs(fp) 115 struct i386_frame *fp; 116{ 117 int *argp; 118 int inst; 119 int args; 120 121 argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE); 122 /* 123 * XXX etext is wrong for LKMs. We should attempt to interpret 124 * the instruction at the return address in all cases. This 125 * may require better fault handling. 126 */ 127 if (argp < (int *)btext || argp >= (int *)etext) { 128 args = 5; 129 } else { 130 inst = db_get_value((int)argp, 4, FALSE); 131 if ((inst & 0xff) == 0x59) /* popl %ecx */ 132 args = 1; 133 else if ((inst & 0xffff) == 0xc483) /* addl $Ibs, %esp */ 134 args = ((inst >> 16) & 0xff) / 4; 135 else 136 args = 5; 137 } 138 return (args); 139} 140 141static void 142db_print_stack_entry(name, narg, argnp, argp, callpc) 143 const char *name; 144 int narg; 145 char **argnp; 146 int *argp; 147 db_addr_t callpc; 148{ 149 db_printf("%s(", name); 150 while (narg) { 151 if (argnp) 152 db_printf("%s=", *argnp++); 153 db_printf("%r", db_get_value((int)argp, 4, FALSE)); 154 argp++; 155 if (--narg != 0) 156 db_printf(","); 157 } 158 db_printf(") at "); 159 db_printsym(callpc, DB_STGY_PROC); 160 db_printf("\n"); 161} 162 163static void 164decode_syscall(number, p) 165 int number; 166 struct proc *p; 167{ 168 c_db_sym_t sym; 169 db_expr_t diff; 170 sy_call_t *f; 171 const char *symname; 172 173 db_printf(" (%d", number); 174 if (p != NULL && 0 <= number && number < p->p_sysent->sv_size) { 175 f = p->p_sysent->sv_table[number].sy_call; 176 sym = db_search_symbol((db_addr_t)f, DB_STGY_ANY, &diff); 177 if (sym != DB_SYM_NULL && diff == 0) { 178 db_symbol_values(sym, &symname, NULL); 179 db_printf(", %s, %s", p->p_sysent->sv_name, symname); 180 } 181 } 182 db_printf(")"); 183} 184 185/* 186 * Figure out the next frame up in the call stack. 187 */ 188static void 189db_nextframe(fp, ip, p) 190 struct i386_frame **fp; /* in/out */ 191 db_addr_t *ip; /* out */ 192 struct proc *p; /* in */ 193{ 194 struct trapframe *tf; 195 int frame_type; 196 int eip, esp, ebp; 197 db_expr_t offset; 198 const char *sym, *name; 199 200 eip = db_get_value((int) &(*fp)->f_retaddr, 4, FALSE); 201 ebp = db_get_value((int) &(*fp)->f_frame, 4, FALSE); 202 203 /* 204 * Figure out frame type. 205 */ 206 207 frame_type = NORMAL; 208 209 sym = db_search_symbol(eip, DB_STGY_ANY, &offset); 210 db_symbol_values(sym, &name, NULL); 211 if (name != NULL) { 212 if (!strcmp(name, "calltrap")) { 213 frame_type = TRAP; 214 } else if (!strncmp(name, "Xresume", 7)) { 215 frame_type = INTERRUPT; 216 } else if (!strcmp(name, "syscall_with_err_pushed")) { 217 frame_type = SYSCALL; 218 } 219 } 220 221 /* 222 * Normal frames need no special processing. 223 */ 224 if (frame_type == NORMAL) { 225 *ip = (db_addr_t) eip; 226 *fp = (struct i386_frame *) ebp; 227 return; 228 } 229 230 db_print_stack_entry(name, 0, 0, 0, eip); 231 232 /* 233 * Point to base of trapframe which is just above the 234 * current frame. 235 */ 236 if (frame_type == INTERRUPT) 237 tf = (struct trapframe *)((int)*fp + 12); 238 else 239 tf = (struct trapframe *)((int)*fp + 8); 240 241 if (INKERNEL((int) tf)) { 242 esp = (ISPL(tf->tf_cs) == SEL_UPL) ? 243 tf->tf_esp : (int)&tf->tf_esp; 244 eip = tf->tf_eip; 245 ebp = tf->tf_ebp; 246 247 switch (frame_type) { 248 case TRAP: 249 db_printf("--- trap %#r", tf->tf_trapno); 250 break; 251 case SYSCALL: 252 db_printf("--- syscall"); 253 decode_syscall(tf->tf_eax, p); 254 break; 255 case INTERRUPT: 256 db_printf("--- interrupt"); 257 break; 258 default: 259 panic("The moon has moved again."); 260 } 261 db_printf(", eip = %#r, esp = %#r, ebp = %#r ---\n", eip, 262 esp, ebp); 263 } 264 265 *ip = (db_addr_t) eip; 266 *fp = (struct i386_frame *) ebp; 267} 268 269void 270db_stack_trace_cmd(addr, have_addr, count, modif) 271 db_expr_t addr; 272 boolean_t have_addr; 273 db_expr_t count; 274 char *modif; 275{ 276 struct i386_frame *frame; 277 int *argp; 278 db_addr_t callpc; 279 boolean_t first; 280 struct pcb *pcb; 281 struct proc *p; 282 pid_t pid; 283 284 if (count == -1) 285 count = 1024; 286 287 if (!have_addr) { 288 p = curproc; 289 frame = (struct i386_frame *)ddb_regs.tf_ebp; 290 if (frame == NULL) 291 frame = (struct i386_frame *)(ddb_regs.tf_esp - 4); 292 callpc = (db_addr_t)ddb_regs.tf_eip; 293 } else if (!INKERNEL(addr)) { 294 pid = (addr % 16) + ((addr >> 4) % 16) * 10 + 295 ((addr >> 8) % 16) * 100 + ((addr >> 12) % 16) * 1000 + 296 ((addr >> 16) % 16) * 10000; 297 /* 298 * The pcb for curproc is not valid at this point, 299 * so fall back to the default case. 300 */ 301 if (pid == curproc->p_pid) { 302 p = curproc; 303 frame = (struct i386_frame *)ddb_regs.tf_ebp; 304 if (frame == NULL) 305 frame = (struct i386_frame *) 306 (ddb_regs.tf_esp - 4); 307 callpc = (db_addr_t)ddb_regs.tf_eip; 308 } else { 309 310 /* sx_slock(&allproc_lock); */ 311 LIST_FOREACH(p, &allproc, p_list) { 312 if (p->p_pid == pid) 313 break; 314 } 315 /* sx_sunlock(&allproc_lock); */ 316 if (p == NULL) { 317 db_printf("pid %d not found\n", pid); 318 return; 319 } 320 if ((p->p_sflag & PS_INMEM) == 0) { 321 db_printf("pid %d swapped out\n", pid); 322 return; 323 } 324 pcb = &p->p_addr->u_pcb; 325 frame = (struct i386_frame *)pcb->pcb_ebp; 326 if (frame == NULL) 327 frame = (struct i386_frame *) 328 (pcb->pcb_esp - 4); 329 callpc = (db_addr_t)pcb->pcb_eip; 330 } 331 } else { 332 p = NULL; 333 frame = (struct i386_frame *)addr; 334 callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE); 335 } 336 337 first = TRUE; 338 while (count--) { 339 struct i386_frame *actframe; 340 int narg; 341 const char * name; 342 db_expr_t offset; 343 c_db_sym_t sym; 344#define MAXNARG 16 345 char *argnames[MAXNARG], **argnp = NULL; 346 347 sym = db_search_symbol(callpc, DB_STGY_ANY, &offset); 348 db_symbol_values(sym, &name, NULL); 349 350 /* 351 * Attempt to determine a (possibly fake) frame that gives 352 * the caller's pc. It may differ from `frame' if the 353 * current function never sets up a standard frame or hasn't 354 * set one up yet or has just discarded one. The last two 355 * cases can be guessed fairly reliably for code generated 356 * by gcc. The first case is too much trouble to handle in 357 * general because the amount of junk on the stack depends 358 * on the pc (the special handling of "calltrap", etc. in 359 * db_nextframe() works because the `next' pc is special). 360 */ 361 actframe = frame; 362 if (first) { 363 if (!have_addr) { 364 int instr; 365 366 instr = db_get_value(callpc, 4, FALSE); 367 if ((instr & 0x00ffffff) == 0x00e58955) { 368 /* pushl %ebp; movl %esp, %ebp */ 369 actframe = (struct i386_frame *) 370 (ddb_regs.tf_esp - 4); 371 } else if ((instr & 0x0000ffff) == 0x0000e589) { 372 /* movl %esp, %ebp */ 373 actframe = (struct i386_frame *) 374 ddb_regs.tf_esp; 375 if (ddb_regs.tf_ebp == 0) { 376 /* Fake caller's frame better. */ 377 frame = actframe; 378 } 379 } else if ((instr & 0x000000ff) == 0x000000c3) { 380 /* ret */ 381 actframe = (struct i386_frame *) 382 (ddb_regs.tf_esp - 4); 383 } else if (offset == 0) { 384 /* Probably a symbol in assembler code. */ 385 actframe = (struct i386_frame *) 386 (ddb_regs.tf_esp - 4); 387 } 388 } else if (!strcmp(name, "fork_trampoline")) { 389 /* 390 * Don't try to walk back on a stack for a 391 * process that hasn't actually been run yet. 392 */ 393 db_print_stack_entry(name, 0, 0, 0, callpc); 394 break; 395 } 396 first = FALSE; 397 } 398 399 argp = &actframe->f_arg0; 400 narg = MAXNARG; 401 if (sym != NULL && db_sym_numargs(sym, &narg, argnames)) { 402 argnp = argnames; 403 } else { 404 narg = db_numargs(frame); 405 } 406 407 db_print_stack_entry(name, narg, argnp, argp, callpc); 408 409 if (actframe != frame) { 410 /* `frame' belongs to caller. */ 411 callpc = (db_addr_t) 412 db_get_value((int)&actframe->f_retaddr, 4, FALSE); 413 continue; 414 } 415 416 db_nextframe(&frame, &callpc, p); 417 418 if (INKERNEL((int) callpc) && !INKERNEL((int) frame)) { 419 sym = db_search_symbol(callpc, DB_STGY_ANY, &offset); 420 db_symbol_values(sym, &name, NULL); 421 db_print_stack_entry(name, 0, 0, 0, callpc); 422 break; 423 } 424 if (!INKERNEL((int) frame)) { 425 break; 426 } 427 } 428} 429 430#define DB_DRX_FUNC(reg) \ 431int \ 432db_ ## reg (vp, valuep, op) \ 433 struct db_variable *vp; \ 434 db_expr_t * valuep; \ 435 int op; \ 436{ \ 437 if (op == DB_VAR_GET) \ 438 *valuep = r ## reg (); \ 439 else \ 440 load_ ## reg (*valuep); \ 441 \ 442 return(0); \ 443} 444 445DB_DRX_FUNC(dr0) 446DB_DRX_FUNC(dr1) 447DB_DRX_FUNC(dr2) 448DB_DRX_FUNC(dr3) 449DB_DRX_FUNC(dr4) 450DB_DRX_FUNC(dr5) 451DB_DRX_FUNC(dr6) 452DB_DRX_FUNC(dr7) 453