void db_show_all_slocks(void) { unsigned int i, index; int mycpu = cpu_number(); usimple_lock_t l; if (uslock_stack_enabled == FALSE) return; #if 0 if (!mach_slocks_init) iprintf("WARNING: simple locks stack may not be accurate\n"); #endif assert(uslock_stack_index[mycpu] >= 0); assert(uslock_stack_index[mycpu] <= USLOCK_STACK_DEPTH); index = uslock_stack_index[mycpu]; for (i = 0; i < index; ++i) { l = uslock_stack[mycpu][i]; iprintf("%d: ", i); db_printsym((vm_offset_t)l, DB_STGY_ANY); printf(" <ETAP type 0x%x> ", l->debug.etap_type); if (l->debug.lock_pc != INVALID_PC) { printf(" locked by "); db_printsym((int)l->debug.lock_pc, DB_STGY_PROC); } printf("\n"); } }
void kobjserver_stats(void) { register unsigned int i, n = sizeof(mig_e)/sizeof(rpc_subsystem_t); register unsigned int howmany; register mach_msg_id_t j, pos, nentry, range; db_printf("Kobject server call counts:\n"); for (i = 0; i < n; i++) { db_printf(" "); db_printsym((vm_offset_t)mig_e[i], DB_STGY_ANY); db_printf(":\n"); range = mig_e[i]->end - mig_e[i]->start; if (!mig_e[i]->start || range < 0) continue; for (j = 0; j < range; j++) { nentry = j + mig_e[i]->start; for (pos = MIG_HASH(nentry) % MAX_MIG_ENTRIES, howmany = 1; mig_buckets[pos].num; pos = ++pos % MAX_MIG_ENTRIES, howmany++) { if (mig_buckets[pos].num == nentry) bucket_stats_print(&mig_buckets[pos]); } } } }
void db_print_loc_and_inst(db_addr_t loc) { db_printsym(loc, DB_STGY_PROC, db_printf); db_printf(":\t"); (void) db_disasm(loc, FALSE); }
void db_show_all_slocks(void) { int i; struct simple_locks_info *info; simple_lock_t l; for (i = 0; i < simple_locks_taken; i++) { info = &simple_locks_info[i]; db_printf("%d: ", i); db_printsym(info->l, DB_STGY_ANY); #if defined(__i386__) db_printf(" locked by "); db_printsym(info->ra, DB_STGY_PROC); #endif db_printf("\n"); } }
/*ARGSUSED*/ void db_write_cmd(db_expr_t address, boolean_t have_addr, db_expr_t count, char *modif) { db_addr_t addr; db_expr_t old_value; db_expr_t new_value; int size; boolean_t wrote_one = FALSE; char tmpfmt[28]; addr = (db_addr_t) address; switch (modif[0]) { case 'b': size = 1; break; case 'h': size = 2; break; case 'l': case '\0': size = 4; break; #ifdef __LP64__ case 'q': size = 8; break; #endif default: size = -1; db_error("Unknown size\n"); /*NOTREACHED*/ } while (db_expression(&new_value)) { old_value = db_get_value(addr, size, FALSE); db_printsym(addr, DB_STGY_ANY, db_printf); db_printf("\t\t%s\t", db_format(tmpfmt, sizeof tmpfmt, old_value, DB_FORMAT_N, 0, 8)); db_printf("=\t%s\n", db_format(tmpfmt, sizeof tmpfmt, new_value, DB_FORMAT_N, 0, 8)); db_put_value(addr, size, new_value); addr += size; wrote_one = TRUE; } if (!wrote_one) { db_error("Nothing written.\n"); /*NOTREACHED*/ } db_next = addr; db_prev = addr - size; db_skip_to_eol(); }
void bucket_stats_print(mig_hash_t *bucket) { if (bucket->callcount) { db_printf(" "); db_printsym((vm_offset_t)bucket->routine, DB_STGY_ANY); db_printf(" (%d):\t%d\n", bucket->num, bucket->callcount); } }
/*ARGSUSED*/ void db_write_cmd(db_expr_t address, bool have_addr, db_expr_t count, const char *modif) { db_addr_t addr; db_expr_t old_value; db_expr_t new_value; int size; bool wrote_one; bool show_old_val; addr = (db_addr_t) address; wrote_one = false; show_old_val = islower((unsigned char)modif[0]); switch (tolower((unsigned char)modif[0])) { case 'b': size = 1; break; case 'h': size = 2; break; case 'l': case '\0': size = 4; break; default: size = -1; db_error("Unknown size\n"); /*NOTREACHED*/ } while (db_expression(&new_value)) { db_printsym(addr, DB_STGY_ANY, db_printf); if (show_old_val) { old_value = db_get_value(addr, size, false); db_printf("\t\t%s = ", db_num_to_str(old_value)); db_printf("%s\n", db_num_to_str(new_value)); } else db_printf("\t\t= %s\n", db_num_to_str(new_value)); db_put_value(addr, size, new_value); addr += size; wrote_one = true; } if (!wrote_one) { db_error("Nothing written.\n"); /*NOTREACHED*/ } db_next = addr; db_prev = addr - size; db_skip_to_eol(); }
void db_print_mutex ( mutex_t * addr) { db_printf ("%08x %6d %7d", addr, *addr, addr->lck_mtx.lck_mtx_waiters); #if MACH_LDEBUG db_printf (" %08x ", addr->thread); db_printsym (addr->pc, DB_STGY_ANY); #endif /* MACH_LDEBUG */ db_printf ("\n"); }
void db_print_simple_lock ( simple_lock_t addr) { db_printf ("%08x %3d", addr, *hw_lock_addr(addr->interlock)); #if USLOCK_DEBUG db_printf (" %08x", addr->debug.lock_thread); db_printf (" %08x ", addr->debug.duration[1]); db_printsym ((int)addr->debug.lock_pc, DB_STGY_ANY); #endif /* USLOCK_DEBUG */ db_printf ("\n"); }
/*ARGSUSED*/ void db_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) { db_expr_t value; if (modif[0] != '\0') db_print_format = modif[0]; switch (db_print_format) { case 'a': db_printsym((db_addr_t)addr, DB_STGY_ANY, db_printf); break; case 'r': { char tbuf[24]; db_format_radix(tbuf, 24, addr, false); db_printf("%11s", tbuf); break; } case 'x': db_printf("%16" DDB_EXPR_FMT "x", addr); break; case 'z': { char tbuf[24]; db_format_hex(tbuf, 24, addr, false); db_printf("%8s", tbuf); break; } case 'd': db_printf("%11" DDB_EXPR_FMT "d", addr); break; case 'u': db_printf("%11" DDB_EXPR_FMT "u", addr); break; case 'o': db_printf("%15" DDB_EXPR_FMT "o", addr); break; case 'c': value = addr & 0xFF; if (value >= ' ' && value <= '~') db_printf("%c", (char)value); else db_printf("\\%03o", (int)value); break; } db_printf("\n"); }
/*ARGSUSED*/ void db_write_cmd(db_expr_t address, boolean_t have_addr, db_expr_t count, char *modif) { db_addr_t addr; db_expr_t old_value; db_expr_t new_value; int size; boolean_t wrote_one = FALSE; addr = (db_addr_t) address; switch (modif[0]) { case 'b': size = 1; break; case 'h': size = 2; break; case 'l': case '\0': size = 4; break; default: db_error("Unknown size\n"); return; } while (db_expression(&new_value)) { old_value = db_get_value(addr, size, FALSE); db_printsym(addr, DB_STGY_ANY); db_printf("\t\t%s = ", db_num_to_str(old_value)); db_printf("%s\n", db_num_to_str(new_value)); db_put_value(addr, size, new_value); addr += size; wrote_one = TRUE; } if (!wrote_one) db_error("Nothing written.\n"); db_next = addr; db_prev = addr - size; db_skip_to_eol(); }
/* * List breakpoints. */ void db_list_breakpoints(void) { db_breakpoint_t bkpt; if (db_breakpoint_list == NULL) { db_printf("No breakpoints set\n"); return; } db_printf(" Count Address\n"); for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) { db_printf(" %5d ", bkpt->init_count); db_printsym(bkpt->address, DB_STGY_PROC, db_printf); db_printf("\n"); } }
/*ARGSUSED*/ void db_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) { db_expr_t value; char tmpfmt[28]; if (modif[0] != '\0') db_print_format = modif[0]; switch (db_print_format) { case 'a': db_printsym((db_addr_t)addr, DB_STGY_ANY, db_printf); break; case 'r': db_printf("%s", db_format(tmpfmt, sizeof tmpfmt, addr, DB_FORMAT_R, 0, sizeof(db_expr_t) * 2 * 6 / 5)); break; case 'x': db_printf("%*lx", sizeof(db_expr_t) * 2, addr); break; case 'z': db_printf("%s", db_format(tmpfmt, sizeof tmpfmt, addr, DB_FORMAT_Z, 0, sizeof(db_expr_t) * 2)); break; case 'd': db_printf("%*ld", sizeof(db_expr_t) * 2 * 6 / 5, addr); break; case 'u': db_printf("%*lu", sizeof(db_expr_t) * 2 * 6 / 5, addr); break; case 'o': db_printf("%*lo", sizeof(db_expr_t) * 2 * 4 / 3, addr); break; case 'c': value = addr & 0xFF; if (value >= ' ' && value <= '~') db_printf("%c", value); else db_printf("\\%03o", value); break; } db_printf("\n"); }
void db_print_address(char *seg, int size, struct i_addr *addrp) { if (addrp->is_reg) { db_printf("%s", db_reg[size][addrp->disp]); return; } if (seg) db_printf("%s:", seg); db_printsym((db_addr_t)addrp->disp, DB_STGY_ANY, db_printf); if (addrp->base != 0 || addrp->index != 0) { db_printf("("); if (addrp->base) db_printf("%s", addrp->base); if (addrp->index) db_printf(",%s,%d", addrp->index, 1<<addrp->ss); db_printf(")"); } }
static void db_print_address(const char *seg, int size, int rex, struct i_addr *addrp) { if (addrp->is_reg) { db_printf("%s", db_reg[rex != 0 ? 1 : 0][(size == LONG && (rex & REX_W)) ? QUAD : size][addrp->disp]); return; } if (seg) { db_printf("%s:", seg); } if (addrp->disp != 0 || (addrp->base == NULL && addrp->index == NULL)) db_printsym((db_addr_t)addrp->disp, DB_STGY_ANY); if (addrp->base != NULL || addrp->index != NULL) { db_printf("("); if (addrp->base) db_printf("%s", addrp->base); if (addrp->index) db_printf(",%s,%d", addrp->index, 1<<addrp->ss); db_printf(")"); } }
static void db_examine(db_addr_t addr, char *fmt, int count) { int i, c; db_expr_t value; int size; int width; int bytes; char * fp; char tbuf[24]; while (--count >= 0) { fp = fmt; size = 4; width = 12; while ((c = *fp++) != 0) { if (db_print_position() == 0) { /* Always print the address. */ db_printsym(addr, DB_STGY_ANY, db_printf); db_printf(":\t"); db_prev = addr; } switch (c) { case 'b': /* byte */ size = 1; width = 4; break; case 'h': /* half-word */ size = 2; width = 8; break; case 'l': /* long-word */ size = 4; width = 12; break; case 'q': if (sizeof(db_expr_t) != sizeof(uint64_t)) { size = -1; db_error("q not supported\n"); /*NOTREACHED*/ } case 'L': /* implementation maximum */ size = sizeof value; width = 12 * (sizeof value / 4); break; case 'a': /* address */ db_printf("= 0x%lx\n", (long)addr); break; case 'r': /* signed, current radix */ value = db_get_value(addr, size, true); addr += size; db_format_radix(tbuf, 24, value, false); db_printf("%-*s", width, tbuf); break; case 'x': /* unsigned hex */ value = db_get_value(addr, size, false); addr += size; db_printf("%-*" DDB_EXPR_FMT "x", width, value); break; case 'm': /* hex dump */ /* * Print off in chunks of size. Try to print 16 * bytes at a time into 4 columns. This * loops modify's count extra times in order * to get the nicely formatted lines. */ bytes = 0; do { for (i = 0; i < size; i++) { value = db_get_value(addr+bytes, 1, false); db_printf( "%02" DDB_EXPR_FMT "x", value); bytes++; if (!(bytes % 4)) db_printf(" "); } } while ((bytes != 16) && count--); /* True up the columns before continuing */ for (i = 4; i >= (bytes / 4); i--) db_printf ("\t"); /* Print chars, use . for non-printable's. */ while (bytes--) { value = db_get_value(addr, 1, false); addr += 1; if (value >= ' ' && value <= '~') db_printf("%c", (char)value); else db_printf("."); } db_printf("\n"); break; case 'z': /* signed hex */ value = db_get_value(addr, size, true); addr += size; db_format_hex(tbuf, 24, value, false); db_printf("%-*s", width, tbuf); break; case 'd': /* signed decimal */ value = db_get_value(addr, size, true); addr += size; db_printf("%-*" DDB_EXPR_FMT "d", width, value); break; case 'u': /* unsigned decimal */ value = db_get_value(addr, size, false); addr += size; db_printf("%-*" DDB_EXPR_FMT "u", width, value); break; case 'o': /* unsigned octal */ value = db_get_value(addr, size, false); addr += size; db_printf("%-*" DDB_EXPR_FMT "o", width, value); break; case 'c': /* character */ value = db_get_value(addr, 1, false); addr += 1; if (value >= ' ' && value <= '~') db_printf("%c", (char)value); else db_printf("\\%03o", (int)value); break; case 's': /* null-terminated string */ for (;;) { value = db_get_value(addr, 1, false); addr += 1; if (value == 0) break; if (value >= ' ' && value <= '~') db_printf("%c", (char)value); else db_printf("\\%03o", (int)value); } break; case 'i': /* instruction */ addr = db_disasm(addr, false); break; case 'I': /* instruction, alternate form */ addr = db_disasm(addr, true); break; default: break; } if (db_print_position() != 0) db_end_line(); } } db_next = addr; }
/* * Frame tracing. */ static int db_backtrace(struct thread *td, db_addr_t fp, int count) { db_addr_t stackframe, lr, *args; boolean_t kernel_only = TRUE; boolean_t full = FALSE; #if 0 { register char *cp = modif; register char c; while ((c = *cp++) != 0) { if (c == 't') trace_thread = TRUE; if (c == 'u') kernel_only = FALSE; if (c == 'f') full = TRUE; } } #endif stackframe = fp; while (!db_pager_quit) { if (stackframe < PAGE_SIZE) break; /* * Locate the next frame by grabbing the backchain ptr * from frame[0] */ stackframe = *(db_addr_t *)stackframe; next_frame: #ifdef __powerpc64__ /* The saved arg values start at frame[6] */ args = (db_addr_t *)(stackframe + 48); #else /* The saved arg values start at frame[2] */ args = (db_addr_t *)(stackframe + 8); #endif if (stackframe < PAGE_SIZE) break; if (count-- == 0) break; /* * Extract link register from frame and subtract * 4 to convert into calling address (as opposed to * return address) */ #ifdef __powerpc64__ lr = *(db_addr_t *)(stackframe + 16) - 4; #else lr = *(db_addr_t *)(stackframe + 4) - 4; #endif if ((lr & 3) || (lr < 0x100)) { db_printf("saved LR(0x%zx) is invalid.", lr); break; } #ifdef __powerpc64__ db_printf("0x%016lx: ", stackframe); #else db_printf("0x%08x: ", stackframe); #endif /* * The trap code labels the return addresses from the * call to C code as 'trapexit' and 'asttrapexit. Use this * to determine if the callframe has to traverse a saved * trap context */ if ((lr + CALLOFFSET == (db_addr_t) &trapexit) || (lr + CALLOFFSET == (db_addr_t) &asttrapexit)) { const char *trapstr; struct trapframe *tf = (struct trapframe *)(args); db_printf("%s ", tf->srr1 & PSL_PR ? "user" : "kernel"); switch (tf->exc) { case EXC_DSI: /* XXX take advantage of the union. */ db_printf("DSI %s trap @ %#zx by ", (tf->cpu.aim.dsisr & DSISR_STORE) ? "write" : "read", tf->dar); goto print_trap; case EXC_ALI: /* XXX take advantage of the union. */ db_printf("ALI trap @ %#zx (xSR %#x) ", tf->dar, (uint32_t)tf->cpu.aim.dsisr); goto print_trap; #ifdef __powerpc64__ case EXC_DSE: db_printf("DSE trap @ %#zx by ", tf->dar); goto print_trap; case EXC_ISE: db_printf("ISE trap @ %#zx by ", tf->srr0); goto print_trap; #endif case EXC_ISI: trapstr = "ISI"; break; case EXC_PGM: trapstr = "PGM"; break; case EXC_SC: trapstr = "SC"; break; case EXC_EXI: trapstr = "EXI"; break; case EXC_MCHK: trapstr = "MCHK"; break; #if !defined(BOOKE) case EXC_VEC: trapstr = "VEC"; break; case EXC_FPA: trapstr = "FPA"; break; case EXC_BPT: trapstr = "BPT"; break; case EXC_TRC: trapstr = "TRC"; break; case EXC_RUNMODETRC: trapstr = "RUNMODETRC"; break; case EXC_SMI: trapstr = "SMI"; break; case EXC_RST: trapstr = "RST"; break; #endif case EXC_FPU: trapstr = "FPU"; break; case EXC_DECR: trapstr = "DECR"; break; case EXC_PERF: trapstr = "PERF"; break; case EXC_VSX: trapstr = "VSX"; break; default: trapstr = NULL; break; } if (trapstr != NULL) { db_printf("%s trap by ", trapstr); } else { db_printf("trap %#zx by ", tf->exc); } print_trap: lr = (db_addr_t) tf->srr0; db_printsym(lr, DB_STGY_ANY); db_printf(": srr1=%#zx\n", tf->srr1); db_printf("%-10s r1=%#zx cr=%#x xer=%#x ctr=%#zx", "", tf->fixreg[1], (uint32_t)tf->cr, (uint32_t)tf->xer, tf->ctr); #ifdef __powerpc64__ db_printf(" r2=%#zx", tf->fixreg[2]); #endif if (tf->exc == EXC_DSI) db_printf(" sr=%#x", (uint32_t)tf->cpu.aim.dsisr); db_printf("\n"); stackframe = (db_addr_t) tf->fixreg[1]; if (kernel_only && (tf->srr1 & PSL_PR)) break; goto next_frame; } db_printf("at "); db_printsym(lr, DB_STGY_PROC); if (full) /* Print all the args stored in that stackframe. */ db_printf("(%zx, %zx, %zx, %zx, %zx, %zx, %zx, %zx)", args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); db_printf("\n"); } return (0); }
void db_examine(db_addr_t addr, char *fmt, int count) { int c; db_expr_t value; int size; int width; char * fp; char tmpfmt[28]; while (--count >= 0) { fp = fmt; size = 4; width = 12; while ((c = *fp++) != 0) { if (db_print_position() == 0) { /* Always print the address. */ db_printsym(addr, DB_STGY_ANY, db_printf); db_printf(":\t"); db_prev = addr; } switch (c) { case 'b': /* byte */ size = 1; width = 4; break; case 'h': /* half-word */ size = 2; width = 8; break; case 'l': /* long-word */ size = 4; width = 12; break; #ifdef __LP64__ case 'q': /* quad-word */ size = 8; width = 20; break; #endif case 'a': /* address */ db_printf("= 0x%lx\n", (long)addr); break; case 'r': /* signed, current radix */ value = db_get_value(addr, size, TRUE); addr += size; db_format(tmpfmt, sizeof tmpfmt, (long)value, DB_FORMAT_R, 0, width); db_printf("%-*s", width, tmpfmt); break; case 'x': /* unsigned hex */ value = db_get_value(addr, size, FALSE); addr += size; db_printf("%-*lx", width, (long)value); break; case 'z': /* signed hex */ value = db_get_value(addr, size, TRUE); addr += size; db_format(tmpfmt, sizeof tmpfmt, (long)value, DB_FORMAT_Z, 0, width); db_printf("%-*s", width, tmpfmt); break; case 'd': /* signed decimal */ value = db_get_value(addr, size, TRUE); addr += size; db_printf("%-*ld", width, (long)value); break; case 'u': /* unsigned decimal */ value = db_get_value(addr, size, FALSE); addr += size; db_printf("%-*lu", width, (long)value); break; case 'o': /* unsigned octal */ value = db_get_value(addr, size, FALSE); addr += size; db_printf("%-*lo", width, value); break; case 'c': /* character */ value = db_get_value(addr, 1, FALSE); addr += 1; if (value >= ' ' && value <= '~') db_printf("%c", value); else db_printf("\\%03o", value); break; case 's': /* null-terminated string */ for (;;) { value = db_get_value(addr, 1, FALSE); addr += 1; if (value == 0) break; if (value >= ' ' && value <= '~') db_printf("%c", value); else db_printf("\\%03o", value); } break; case 'i': /* instruction */ addr = db_disasm(addr, FALSE); break; case 'I': /* instruction, alternate form */ addr = db_disasm(addr, TRUE); break; default: break; } if (db_print_position() != 0) db_end_line(width); } } db_next = addr; }
static void db_disasm_printaddr(vm_offset_t address) { db_printsym((db_addr_t)address, DB_STGY_ANY); }
void db_stack_trace_print(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *modif, int (*pr)(const char *, ...)) { struct x86_64_frame *frame, *lastframe; long *argp; db_addr_t callpc; int is_trap = 0; boolean_t kernel_only = TRUE; boolean_t trace_thread = FALSE; #if 0 if (!db_trace_symbols_found) db_find_trace_symbols(); #endif { char *cp = modif; char c; while ((c = *cp++) != 0) { if (c == 't') trace_thread = TRUE; if (c == 'u') kernel_only = FALSE; } } if (!have_addr) { frame = (struct x86_64_frame *)ddb_regs.tf_rbp; callpc = (db_addr_t)ddb_regs.tf_rip; } else { #if 0 if (trace_thread) { struct proc *p; struct user *u; struct lwp *l; (*pr)("trace: pid %d ", (int)addr); p = pfind(addr); if (p == NULL) { (*pr)("not found\n"); return; } l = proc_representative_lwp(p); if (!(l->l_flag&L_INMEM)) { (*pr)("swapped out\n"); return; } u = l->l_addr; frame = (struct x86_64_frame *) u->u_pcb.pcb_rbp; (*pr)("at %p\n", frame); } else #endif frame = (struct x86_64_frame *)addr; callpc = (db_addr_t) db_get_value((db_addr_t)&frame->f_retaddr, 8, FALSE); frame = (struct x86_64_frame *)frame->f_frame; } lastframe = 0; while (count && frame != 0) { int narg; char * name; db_expr_t offset; db_sym_t sym; #define MAXNARG 16 char *argnames[MAXNARG], **argnp = NULL; sym = db_search_symbol(callpc, DB_STGY_ANY, &offset); db_symbol_values(sym, &name, NULL); if (lastframe == 0 && sym == NULL) { /* Symbol not found, peek at code */ long instr = db_get_value(callpc, 8, FALSE); offset = 1; if ((instr & 0x00ffffff) == 0x00e58955 || /* enter: pushl %ebp, movl %esp, %ebp */ (instr & 0x0000ffff) == 0x0000e589 /* enter+1: movl %esp, %ebp */) { offset = 0; } } if (INKERNEL(frame) && name) { #ifdef __ELF__ if (!strcmp(name, "trap")) { is_trap = TRAP; } else if (!strcmp(name, "syscall")) { is_trap = SYSCALL; } else if (name[0] == 'X') { if (!strncmp(name, "Xintr", 5) || !strncmp(name, "Xresume", 7) || !strncmp(name, "Xstray", 6) || !strncmp(name, "Xhold", 5) || !strncmp(name, "Xrecurse", 8) || !strcmp(name, "Xdoreti") || !strncmp(name, "Xsoft", 5)) { is_trap = INTERRUPT; } else goto normal; } else goto normal; narg = 0; #else if (!strcmp(name, "_trap")) { is_trap = TRAP; } else if (!strcmp(name, "_syscall")) { is_trap = SYSCALL; } else if (name[0] == '_' && name[1] == 'X') { if (!strncmp(name, "_Xintr", 6) || !strncmp(name, "_Xresume", 8) || !strncmp(name, "_Xstray", 7) || !strncmp(name, "_Xhold", 6) || !strncmp(name, "_Xrecurse", 9) || !strcmp(name, "_Xdoreti") || !strncmp(name, "_Xsoft", 6)) { is_trap = INTERRUPT; } else goto normal; } else goto normal; narg = 0; #endif /* __ELF__ */ } else { normal: is_trap = NONE; narg = MAXNARG; if (db_sym_numargs(sym, &narg, argnames)) argnp = argnames; else narg = db_numargs(frame); } (*pr)("%s(", name); if (lastframe == 0 && offset == 0 && !have_addr) { /* * We have a breakpoint before the frame is set up * Use %esp instead */ argp = &((struct x86_64_frame *)(ddb_regs.tf_rsp-8))->f_arg0; } else { argp = &frame->f_arg0; } while (narg) { if (argnp) (*pr)("%s=", *argnp++); (*pr)("%lx", db_get_value((db_addr_t)argp, 8, FALSE)); argp++; if (--narg != 0) (*pr)(","); } (*pr)(") at "); db_printsym(callpc, DB_STGY_PROC, pr); (*pr)("\n"); if (lastframe == 0 && offset == 0 && !have_addr) { /* Frame really belongs to next callpc */ lastframe = (struct x86_64_frame *)(ddb_regs.tf_rsp-8); callpc = (db_addr_t) db_get_value((db_addr_t)&lastframe->f_retaddr, 8, FALSE); continue; } lastframe = frame; db_nextframe(&frame, &callpc, &frame->f_arg0, is_trap, pr); if (frame == 0) { /* end of chain */ break; } if (INKERNEL(frame)) { /* staying in kernel */ if (frame <= lastframe) { (*pr)("Bad frame pointer: %p\n", frame); break; } } else if (INKERNEL(lastframe)) { /* switch from user to kernel */ if (kernel_only) { (*pr)("end of kernel\n"); break; /* kernel stack only */ } } else { /* in user */ if (frame <= lastframe) { (*pr)("Bad user frame pointer: %p\n", frame); break; } } --count; } (*pr)("end trace frame: 0x%lx, count: %d\n", frame, count); if (count && is_trap != NONE) { db_printsym(callpc, DB_STGY_XTRN, pr); (*pr)(":\n"); } }
void db_stack_trace_print(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *modif, int (*pr)(const char *, ...)) { struct callframe *frame, *lastframe; long *argp, *arg0; db_addr_t callpc; int is_trap = 0; boolean_t kernel_only = TRUE; boolean_t trace_proc = FALSE; { char *cp = modif; char c; while ((c = *cp++) != 0) { if (c == 'p') trace_proc = TRUE; if (c == 'u') kernel_only = FALSE; } } if (!have_addr) { frame = (struct callframe *)ddb_regs.tf_rbp; callpc = (db_addr_t)ddb_regs.tf_rip; } else { if (trace_proc) { struct proc *p = pfind((pid_t)addr); if (p == NULL) { (*pr) ("db_trace.c: process not found\n"); return; } frame = (struct callframe *)p->p_addr->u_pcb.pcb_rbp; } else { frame = (struct callframe *)addr; } callpc = (db_addr_t) db_get_value((db_addr_t)&frame->f_retaddr, 8, FALSE); frame = (struct callframe *)frame->f_frame; } lastframe = 0; while (count && frame != 0) { int narg; char * name; db_expr_t offset; db_sym_t sym; sym = db_search_symbol(callpc, DB_STGY_ANY, &offset); db_symbol_values(sym, &name, NULL); if (lastframe == 0 && sym == NULL) { /* Symbol not found, peek at code */ long instr = db_get_value(callpc, 8, FALSE); offset = 1; if ((instr & 0x00ffffff) == 0x00e58955 || /* enter: pushl %ebp, movl %esp, %ebp */ (instr & 0x0000ffff) == 0x0000e589 /* enter+1: movl %esp, %ebp */) { offset = 0; } } if (INKERNEL(callpc) && name) { if (!strcmp(name, "trap")) { is_trap = TRAP; } else if (!strcmp(name, "ast")) { is_trap = AST; } else if (!strcmp(name, "syscall")) { is_trap = SYSCALL; } else if (name[0] == 'X') { if (!strncmp(name, "Xintr", 5) || !strncmp(name, "Xresume", 7) || !strncmp(name, "Xrecurse", 8) || !strcmp(name, "Xdoreti") || !strncmp(name, "Xsoft", 5)) { is_trap = INTERRUPT; } else goto normal; } else goto normal; narg = 0; } else { normal: is_trap = NONE; narg = db_numargs(frame); } (*pr)("%s(", name); if (lastframe == 0 && offset == 0 && !have_addr) { /* * We have a breakpoint before the frame is set up * Use %rsp instead */ arg0 = &((struct callframe *)(ddb_regs.tf_rsp-8))->f_arg0; } else { arg0 = &frame->f_arg0; } for (argp = arg0; narg > 0; ) { (*pr)("%lx", db_get_value((db_addr_t)argp, 8, FALSE)); argp++; if (--narg != 0) (*pr)(","); } (*pr)(") at "); db_printsym(callpc, DB_STGY_PROC, pr); (*pr)("\n"); if (lastframe == 0 && offset == 0 && !have_addr && !is_trap) { /* Frame really belongs to next callpc */ lastframe = (struct callframe *)(ddb_regs.tf_rsp-8); callpc = (db_addr_t) db_get_value((db_addr_t)&lastframe->f_retaddr, 8, FALSE); continue; } if (is_trap == INTERRUPT) { /* * Interrupt routines don't update %rbp, so it still * points to the frame that was interrupted. Pull * back to just above lastframe so we can find the * trapframe as with syscalls and traps. */ frame = (struct callframe *)&lastframe->f_retaddr; arg0 = &frame->f_arg0; } lastframe = frame; db_nextframe(&frame, &callpc, arg0, is_trap, pr); if (frame == 0) { /* end of chain */ break; } if (INKERNEL(frame)) { /* staying in kernel */ if (frame <= lastframe) { (*pr)("Bad frame pointer: %p\n", frame); break; } } else if (INKERNEL(lastframe)) { /* switch from user to kernel */ if (kernel_only) { (*pr)("end of kernel\n"); break; /* kernel stack only */ } } else { /* in user */ if (frame <= lastframe) { (*pr)("Bad user frame pointer: %p\n", frame); break; } } --count; } (*pr)("end trace frame: 0x%lx, count: %d\n", frame, count); if (count && is_trap != NONE) { db_printsym(callpc, DB_STGY_XTRN, pr); (*pr)(":\n"); } }
static void db_disasm_printaddr(db_expr_t address) { db_printsym((db_addr_t)address, DB_STGY_ANY, db_printf); }
void db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif, void (*pr)(const char *, ...)) { long *frame, *lastframe; long *retaddr, *arg0; long *argp; db_addr_t callpc; int is_trap; bool kernel_only = true; bool trace_thread = false; bool lwpaddr = false; #if 0 if (!db_trace_symbols_found) db_find_trace_symbols(); #endif { const char *cp = modif; char c; while ((c = *cp++) != 0) { if (c == 'a') { lwpaddr = true; trace_thread = true; } if (c == 't') trace_thread = true; if (c == 'u') kernel_only = false; } } if (!have_addr) { frame = (long *)ddb_regs.tf_rbp; callpc = (db_addr_t)ddb_regs.tf_rip; } else { if (trace_thread) { struct proc *p; struct user *u; struct lwp *l; if (lwpaddr) { l = (struct lwp *)addr; p = l->l_proc; (*pr)("trace: pid %d ", p->p_pid); } else { (*pr)("trace: pid %d ", (int)addr); p = p_find(addr, PFIND_LOCKED); if (p == NULL) { (*pr)("not found\n"); return; } l = LIST_FIRST(&p->p_lwps); KASSERT(l != NULL); } (*pr)("lid %d ", l->l_lid); if (!(l->l_flag & LW_INMEM)) { (*pr)("swapped out\n"); return; } u = l->l_addr; if (p == curproc && l == curlwp) { frame = (long *)ddb_regs.tf_rbp; callpc = (db_addr_t)ddb_regs.tf_rip; (*pr)("at %p\n", frame); } else { frame = (long *)u->u_pcb.pcb_rbp; callpc = (db_addr_t) db_get_value((long)(frame + 1), 8, false); (*pr)("at %p\n", frame); frame = (long *)*frame; /* XXXfvdl db_get_value? */ } } else { frame = (long *)addr; callpc = (db_addr_t) db_get_value((long)(frame + 1), 8, false); frame = (long *)*frame; /* XXXfvdl db_get_value? */ } } retaddr = frame + 1; arg0 = frame + 2; lastframe = 0; while (count && frame != 0) { int narg; const char * name; db_expr_t offset; db_sym_t sym; char *argnames[16], **argnp = NULL; db_addr_t lastcallpc; name = "?"; is_trap = NONE; offset = 0; sym = db_frame_info(frame, callpc, &name, &offset, &is_trap, &narg); if (lastframe == 0 && sym == (db_sym_t)0) { /* Symbol not found, peek at code */ u_long instr = db_get_value(callpc, 4, false); offset = 1; if (instr == 0xe5894855 || /* enter: pushq %rbp, movq %rsp, %rbp */ (instr & 0x00ffffff) == 0x0048e589 /* enter+1: movq %rsp, %rbp */) { offset = 0; } } if (is_trap == NONE) { if (db_sym_numargs(sym, &narg, argnames)) argnp = argnames; else narg = db_numargs(frame); } (*pr)("%s(", name); if (lastframe == 0 && offset == 0 && !have_addr) { /* * We have a breakpoint before the frame is set up * Use %rsp instead */ argp = &((struct x86_64_frame *)(ddb_regs.tf_rsp-8))->f_arg0; } else { argp = frame + 2; } while (narg) { if (argnp) (*pr)("%s=", *argnp++); (*pr)("%lx", db_get_value((long)argp, 8, false)); argp++; if (--narg != 0) (*pr)(","); } (*pr)(") at "); db_printsym(callpc, DB_STGY_PROC, pr); (*pr)("\n"); if (lastframe == 0 && offset == 0 && !have_addr) { /* Frame really belongs to next callpc */ struct x86_64_frame *fp = (void *)(ddb_regs.tf_rsp-8); lastframe = (long *)fp; callpc = (db_addr_t) db_get_value((db_addr_t)&fp->f_retaddr, 8, false); continue; } lastframe = frame; lastcallpc = callpc; if (!db_nextframe(&frame, &retaddr, &arg0, &callpc, frame + 2, is_trap, pr)) break; if (INKERNEL((long)frame)) { /* staying in kernel */ if (frame < lastframe || (frame == lastframe && callpc == lastcallpc)) { (*pr)("Bad frame pointer: %p\n", frame); break; } } else if (INKERNEL((long)lastframe)) { /* switch from user to kernel */ if (kernel_only) break; /* kernel stack only */ } else { /* in user */ if (frame <= lastframe) { (*pr)("Bad user frame pointer: %p\n", frame); break; } } --count; } if (count && is_trap != NONE) { db_printsym(callpc, DB_STGY_XTRN, pr); (*pr)(":\n"); } }
/* * Figure out the next frame up in the call stack. * For trap(), we print the address of the faulting instruction and * proceed with the calling frame. We return the ip that faulted. * If the trap was caused by jumping through a bogus pointer, then * the next line in the backtrace will list some random function as * being called. It should get the argument list correct, though. * It might be possible to dig out from the next frame up the name * of the function that faulted, but that could get hairy. */ int db_nextframe(long **nextframe, long **retaddr, long **arg0, db_addr_t *ip, long *argp, int is_trap, void (*pr)(const char *, ...)) { struct trapframe *tf; struct x86_64_frame *fp; struct intrframe *ifp; int traptype, trapno, err, i; switch (is_trap) { case NONE: *ip = (db_addr_t) db_get_value((long)*retaddr, 8, false); fp = (struct x86_64_frame *) db_get_value((long)*nextframe, 8, false); if (fp == NULL) return 0; *nextframe = (long *)&fp->f_frame; *retaddr = (long *)&fp->f_retaddr; *arg0 = (long *)&fp->f_arg0; break; case TRAP: case SYSCALL: case INTERRUPT: default: /* The only argument to trap() or syscall() is the trapframe. */ tf = (struct trapframe *)argp; switch (is_trap) { case TRAP: (*pr)("--- trap (number %"DDB_EXPR_FMT"u) ---\n", db_get_value((long)&tf->tf_trapno, 8, false)); break; case SYSCALL: (*pr)("--- syscall (number %"DDB_EXPR_FMT"u) ---\n", db_get_value((long)&tf->tf_rax, 8, false)); break; case INTERRUPT: (*pr)("--- interrupt ---\n"); break; } *ip = (db_addr_t)db_get_value((long)&tf->tf_rip, 8, false); fp = (struct x86_64_frame *) db_get_value((long)&tf->tf_rbp, 8, false); if (fp == NULL) return 0; *nextframe = (long *)&fp->f_frame; *retaddr = (long *)&fp->f_retaddr; *arg0 = (long *)&fp->f_arg0; break; } /* * A bit of a hack. Since %rbp may be used in the stub code, * walk the stack looking for a valid interrupt frame. Such * a frame can be recognized by always having * err 0 or IREENT_MAGIC and trapno T_ASTFLT. */ if (db_frame_info(*nextframe, (db_addr_t)*ip, NULL, NULL, &traptype, NULL) != (db_sym_t)0 && traptype == INTERRUPT) { for (i = 0; i < 4; i++) { ifp = (struct intrframe *)(argp + i); err = db_get_value((long)&ifp->if_tf.tf_err, sizeof(long), false); trapno = db_get_value((long)&ifp->if_tf.tf_trapno, sizeof(long), false); if ((err == 0 || err == IREENT_MAGIC) && trapno == T_ASTFLT) { *nextframe = (long *)ifp - 1; break; } } if (i == 4) { (*pr)("DDB lost frame for "); db_printsym(*ip, DB_STGY_ANY, pr); (*pr)(", trying %p\n",argp); *nextframe = argp; } } return 1; }
void db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif, void (*pr)(const char *, ...)) { register_t *fp, pc, rp; bool kernel_only = true; bool trace_thread = false; bool lwpaddr = false; db_sym_t sym; db_expr_t off; const char *name; const char *cp = modif; char c; if (count < 0) count = 65536; while ((c = *cp++) != 0) { if (c == 'a') { lwpaddr = true; trace_thread = true; } if (c == 't') trace_thread = true; if (c == 'u') kernel_only = false; } if (!have_addr) { fp = (register_t *)ddb_regs.tf_r3; pc = ddb_regs.tf_iioq_head; rp = ddb_regs.tf_rp; } else { if (trace_thread) { struct proc *p; struct user *u; struct lwp *l; if (lwpaddr) { l = (struct lwp *)addr; p = l->l_proc; (*pr)("trace: pid %d ", p->p_pid); } else { (*pr)("trace: pid %d ", (int)addr); p = p_find(addr, PFIND_LOCKED); if (p == NULL) { (*pr)("not found\n"); return; } l = LIST_FIRST(&p->p_lwps); KASSERT(l != NULL); } (*pr)("lid %d ", l->l_lid); if (!(l->l_flag & LW_INMEM)) { (*pr)("swapped out\n"); return; } u = l->l_addr; if (p == curproc && l == curlwp) { fp = (int *)ddb_regs.tf_r3; pc = ddb_regs.tf_iioq_head; rp = ddb_regs.tf_rp; } else { /* cpu_switchto fp, and return point */ fp = (int *)(u->u_pcb.pcb_ksp - (HPPA_FRAME_SIZE + 16*4)); pc = 0; rp = fp[-5]; } (*pr)("at %p\n", fp); } else { pc = 0; fp = (register_t *)addr; rp = fp[-5]; } } while (fp && count--) { #ifdef DDB_DEBUG pr(">> %08x %08x %08x\t", fp, pc, rp); #endif if (USERMODE(pc)) return; sym = db_search_symbol(pc, DB_STGY_ANY, &off); db_symbol_values (sym, &name, NULL); pr("%s() at ", name); db_printsym(pc, DB_STGY_PROC, pr); pr("\n"); /* XXX NH - unwind info here */ /* aue = ue_find(pc); */ /* * get rp? * fp -= ue_total_frame_size(aue) */ /* * if a terminal frame then report the trapframe * and continue after it (if not the last one). */ if (!fp[0]) { register_t *scargs; struct trapframe *tf; int scoff; /* Stack space for syscall args */ scoff = HPPA_FRAME_ROUND(HPPA_FRAME_SIZE + HPPA_FRAME_MAXARGS); scargs = (register_t *)((char *)fp - scoff); tf = (struct trapframe *)((char *)scargs - sizeof(*tf)); if (tf->tf_flags & TFF_SYS) pr("-- syscall #%d(%x, %x, %x, %x, ...)\n", tf->tf_t1, scargs[1], scargs[2], scargs[3], scargs[4]); else pr("-- trap #%d%s\n", tf->tf_flags & 0x3f, (tf->tf_flags & T_USER)? " from user" : ""); if (!(tf->tf_flags & TFF_LAST)) { fp = (register_t *)tf->tf_r3; pc = tf->tf_iioq_head; rp = tf->tf_rp; } else { pc = 0; fp = 0; } } else { /* next frame */ fp = (register_t *)fp[0]; pc = rp; rp = fp[-5]; } } if (count && pc) { db_printsym(pc, DB_STGY_XTRN, pr); pr(":\n"); } }
void db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif, void (*pr)(const char *, ...)) { struct frame *frame, *prevframe; db_addr_t pc; bool kernel_only = true; bool trace_thread = false; bool lwpaddr = false; const char *cp = modif; char c; if (ddb_cpuinfo == NULL) ddb_cpuinfo = curcpu(); while ((c = *cp++) != 0) { if (c == 'a') { lwpaddr = true; trace_thread = true; } if (c == 't') trace_thread = true; if (c == 'u') kernel_only = false; } if (!have_addr) { frame = (struct frame *)DDB_TF->tf_out[6]; pc = DDB_TF->tf_pc; } else { if (trace_thread) { struct proc *p; struct user *u; struct lwp *l; if (lwpaddr) { l = (struct lwp *)addr; p = l->l_proc; (*pr)("trace: pid %d ", p->p_pid); } else { (*pr)("trace: pid %d ", (int)addr); p = p_find(addr, PFIND_LOCKED); if (p == NULL) { (*pr)("not found\n"); return; } l = LIST_FIRST(&p->p_lwps); KASSERT(l != NULL); } (*pr)("lid %d ", l->l_lid); if ((l->l_flag & LW_INMEM) == 0) { (*pr)("swapped out\n"); return; } u = l->l_addr; frame = (struct frame *)u->u_pcb.pcb_sp; pc = u->u_pcb.pcb_pc; (*pr)("at %p\n", frame); } else { frame = (struct frame *)addr; pc = 0; } } while (count--) { int i; db_expr_t offset; const char *name; db_addr_t prevpc; #define FR(framep,field) (INKERNEL(framep) \ ? (u_int)(framep)->field \ : fuword(&(framep)->field)) /* Fetch return address and arguments frame */ prevpc = (db_addr_t)FR(frame, fr_pc); prevframe = (struct frame *)FR(frame, fr_fp); /* * Switch to frame that contains arguments */ if (prevframe == NULL || (!INKERNEL(prevframe) && kernel_only)) return; if ((ONINTSTACK(frame) && !ONINTSTACK(prevframe)) || (INKERNEL(frame) && !INKERNEL(prevframe))) { /* We're crossing a trap frame; pc = %l1 */ prevpc = (db_addr_t)FR(frame, fr_local[1]); } name = NULL; if (INKERNEL(pc)) db_find_sym_and_offset(pc, &name, &offset); if (name == NULL) (*pr)("0x%lx(", pc); else (*pr)("%s(", name); /* * Print %i0..%i5, hope these still reflect the * actual arguments somewhat... */ for (i = 0; i < 6; i++) (*pr)("0x%x%s", FR(frame, fr_arg[i]), (i < 5) ? ", " : ") at "); if (INKERNEL(prevpc)) db_printsym(prevpc, DB_STGY_PROC, pr); else (*pr)("0x%lx", prevpc); (*pr)("\n"); pc = prevpc; frame = prevframe; } }