Index: head/sys/ddb/db_examine.c =================================================================== --- head/sys/ddb/db_examine.c (revision 285773) +++ head/sys/ddb/db_examine.c (revision 285774) @@ -1,319 +1,323 @@ /*- * Mach Operating System * Copyright (c) 1991,1990 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /* * Author: David B. Golub, Carnegie Mellon University * Date: 7/90 */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include static char db_examine_format[TOK_STRING_SIZE] = "x"; static void db_examine(db_addr_t, char *, int); static void db_search(db_addr_t, int, db_expr_t, db_expr_t, u_int); /* * Examine (print) data. */ /*ARGSUSED*/ void db_examine_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) { if (modif[0] != '\0') db_strcpy(db_examine_format, modif); if (count == -1) count = 1; db_examine((db_addr_t) addr, db_examine_format, count); } static void db_examine(db_addr_t addr, char *fmt, int count) { int c; db_expr_t value; int size; int width; char * fp; while (--count >= 0 && !db_pager_quit) { fp = fmt; size = 4; while ((c = *fp++) != 0) { switch (c) { case 'b': size = 1; break; case 'h': size = 2; break; case 'l': size = 4; break; case 'g': size = 8; break; case 'a': /* address */ size = sizeof(void *); /* always forces a new line */ if (db_print_position() != 0) db_printf("\n"); db_prev = addr; db_printsym(addr, DB_STGY_ANY); db_printf(":\t"); break; default: if (db_print_position() == 0) { /* Print the address. */ db_printsym(addr, DB_STGY_ANY); db_printf(":\t"); db_prev = addr; } width = size * 4; switch (c) { case 'r': /* signed, current radix */ value = db_get_value(addr, size, true); addr += size; db_printf("%+-*lr", width, (long)value); 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_printf("%-*ly", width, (long)value); 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, (long)value); break; case 'c': /* character */ value = db_get_value(addr, 1, false); addr += 1; if (value >= ' ' && value <= '~') db_printf("%c", (int)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", (int)value); else db_printf("\\%03o", (int)value); } break; case 'S': /* symbol */ value = db_get_value(addr, sizeof(void *), false); addr += sizeof(void *); db_printsym(value, DB_STGY_ANY); 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(1); break; } } } db_next = addr; } /* * Print value. */ static char db_print_format = 'x'; /*ARGSUSED*/ void db_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count, 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); break; case 'r': db_printf("%+11lr", (long)addr); break; case 'x': db_printf("%8lx", (unsigned long)addr); break; case 'z': db_printf("%8ly", (long)addr); break; case 'd': db_printf("%11ld", (long)addr); break; case 'u': db_printf("%11lu", (unsigned long)addr); break; case 'o': db_printf("%16lo", (unsigned long)addr); break; case 'c': value = addr & 0xFF; if (value >= ' ' && value <= '~') db_printf("%c", (int)value); else db_printf("\\%03o", (int)value); break; } db_printf("\n"); } void db_print_loc_and_inst(db_addr_t loc) { + db_expr_t off; + db_printsym(loc, DB_STGY_PROC); - db_printf(":\t"); - (void) db_disasm(loc, true); + if (db_search_symbol(loc, DB_STGY_PROC, &off) != C_DB_SYM_NULL) { + db_printf(":\t"); + (void)db_disasm(loc, true); + } } /* * Search for a value in memory. * Syntax: search [/bhl] addr value [mask] [,count] */ void db_search_cmd(db_expr_t dummy1, bool dummy2, db_expr_t dummy3, char *dummy4) { int t; db_addr_t addr; int size; db_expr_t value; db_expr_t mask; db_expr_t count; t = db_read_token(); if (t == tSLASH) { t = db_read_token(); if (t != tIDENT) { bad_modifier: db_printf("Bad modifier\n"); db_flush_lex(); return; } if (!strcmp(db_tok_string, "b")) size = 1; else if (!strcmp(db_tok_string, "h")) size = 2; else if (!strcmp(db_tok_string, "l")) size = 4; else goto bad_modifier; } else { db_unread_token(t); size = 4; } if (!db_expression((db_expr_t *)&addr)) { db_printf("Address missing\n"); db_flush_lex(); return; } if (!db_expression(&value)) { db_printf("Value missing\n"); db_flush_lex(); return; } if (!db_expression(&mask)) mask = 0xffffffffUL; t = db_read_token(); if (t == tCOMMA) { if (!db_expression(&count)) { db_printf("Count missing\n"); db_flush_lex(); return; } } else { db_unread_token(t); count = -1; /* effectively forever */ } db_skip_to_eol(); db_search(addr, size, value, mask, count); } static void db_search(db_addr_t addr, int size, db_expr_t value, db_expr_t mask, unsigned int count) { while (count-- != 0) { db_prev = addr; if ((db_get_value(addr, size, false) & mask) == value) break; addr += size; } db_next = addr; } Index: head/sys/ddb/db_main.c =================================================================== --- head/sys/ddb/db_main.c (revision 285773) +++ head/sys/ddb/db_main.c (revision 285774) @@ -1,282 +1,282 @@ /*- * Mach Operating System * Copyright (c) 1991,1990 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SYSCTL_NODE(_debug, OID_AUTO, ddb, CTLFLAG_RW, 0, "DDB settings"); static dbbe_init_f db_init; static dbbe_trap_f db_trap; static dbbe_trace_f db_trace_self_wrapper; static dbbe_trace_thread_f db_trace_thread_wrapper; KDB_BACKEND(ddb, db_init, db_trace_self_wrapper, db_trace_thread_wrapper, db_trap); /* * Symbols can be loaded by specifying the exact addresses of * the symtab and strtab in memory. This is used when loaded from * boot loaders different than the native one (like Xen). */ vm_offset_t ksymtab, kstrtab, ksymtab_size; bool X_db_line_at_pc(db_symtab_t *symtab, c_db_sym_t sym, char **file, int *line, db_expr_t off) { return (false); } c_db_sym_t X_db_lookup(db_symtab_t *symtab, const char *symbol) { c_linker_sym_t lsym; Elf_Sym *sym; if (symtab->private == NULL) { return ((c_db_sym_t)((!linker_ddb_lookup(symbol, &lsym)) ? lsym : NULL)); } else { sym = (Elf_Sym *)symtab->start; while ((char *)sym < symtab->end) { if (sym->st_name != 0 && !strcmp(symtab->private + sym->st_name, symbol)) return ((c_db_sym_t)sym); sym++; } } return (NULL); } c_db_sym_t X_db_search_symbol(db_symtab_t *symtab, db_addr_t off, db_strategy_t strat, db_expr_t *diffp) { c_linker_sym_t lsym; Elf_Sym *sym, *match; unsigned long diff; if (symtab->private == NULL) { if (!linker_ddb_search_symbol((caddr_t)off, &lsym, &diff)) { *diffp = (db_expr_t)diff; return ((c_db_sym_t)lsym); } return (NULL); } diff = ~0UL; match = NULL; for (sym = (Elf_Sym*)symtab->start; (char*)sym < symtab->end; sym++) { - if (sym->st_name == 0) + if (sym->st_name == 0 || sym->st_shndx == SHN_UNDEF) continue; if (off < sym->st_value) continue; if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT && ELF_ST_TYPE(sym->st_info) != STT_FUNC && ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) continue; if ((off - sym->st_value) > diff) continue; if ((off - sym->st_value) < diff) { diff = off - sym->st_value; match = sym; } else { if (match == NULL) match = sym; else if (ELF_ST_BIND(match->st_info) == STB_LOCAL && ELF_ST_BIND(sym->st_info) != STB_LOCAL) match = sym; } if (diff == 0) { if (strat == DB_STGY_PROC && ELF_ST_TYPE(sym->st_info) == STT_FUNC && ELF_ST_BIND(sym->st_info) != STB_LOCAL) break; if (strat == DB_STGY_ANY && ELF_ST_BIND(sym->st_info) != STB_LOCAL) break; } } *diffp = (match == NULL) ? off : diff; return ((c_db_sym_t)match); } bool X_db_sym_numargs(db_symtab_t *symtab, c_db_sym_t sym, int *nargp, char **argp) { return (false); } void X_db_symbol_values(db_symtab_t *symtab, c_db_sym_t sym, const char **namep, db_expr_t *valp) { linker_symval_t lval; if (symtab->private == NULL) { linker_ddb_symbol_values((c_linker_sym_t)sym, &lval); if (namep != NULL) *namep = (const char*)lval.name; if (valp != NULL) *valp = (db_expr_t)lval.value; } else { if (namep != NULL) *namep = (const char *)symtab->private + ((const Elf_Sym *)sym)->st_name; if (valp != NULL) *valp = (db_expr_t)((const Elf_Sym *)sym)->st_value; } } int db_fetch_ksymtab(vm_offset_t ksym_start, vm_offset_t ksym_end) { Elf_Size strsz; if (ksym_end > ksym_start && ksym_start != 0) { ksymtab = ksym_start; ksymtab_size = *(Elf_Size*)ksymtab; ksymtab += sizeof(Elf_Size); kstrtab = ksymtab + ksymtab_size; strsz = *(Elf_Size*)kstrtab; kstrtab += sizeof(Elf_Size); if (kstrtab + strsz > ksym_end) { /* Sizes doesn't match, unset everything. */ ksymtab = ksymtab_size = kstrtab = 0; } } if (ksymtab == 0 || ksymtab_size == 0 || kstrtab == 0) return (-1); return (0); } static int db_init(void) { db_command_init(); if (ksymtab != 0 && kstrtab != 0 && ksymtab_size != 0) { db_add_symbol_table((char *)ksymtab, (char *)(ksymtab + ksymtab_size), "elf", (char *)kstrtab); } db_add_symbol_table(NULL, NULL, "kld", NULL); return (1); /* We're the default debugger. */ } static int db_trap(int type, int code) { jmp_buf jb; void *prev_jb; bool bkpt, watchpt; const char *why; /* * Don't handle the trap if the console is unavailable (i.e. it * is in graphics mode). */ if (cnunavailable()) return (0); bkpt = IS_BREAKPOINT_TRAP(type, code); watchpt = IS_WATCHPOINT_TRAP(type, code); if (db_stop_at_pc(&bkpt)) { if (db_inst_count) { db_printf("After %d instructions (%d loads, %d stores),\n", db_inst_count, db_load_count, db_store_count); } prev_jb = kdb_jmpbuf(jb); if (setjmp(jb) == 0) { db_dot = PC_REGS(); db_print_thread(); if (bkpt) db_printf("Breakpoint at\t"); else if (watchpt) db_printf("Watchpoint at\t"); else db_printf("Stopped at\t"); db_print_loc_and_inst(db_dot); } why = kdb_why; db_script_kdbenter(why != KDB_WHY_UNSET ? why : "unknown"); db_command_loop(); (void)kdb_jmpbuf(prev_jb); } db_restart_at_pc(watchpt); return (1); } static void db_trace_self_wrapper(void) { jmp_buf jb; void *prev_jb; prev_jb = kdb_jmpbuf(jb); if (setjmp(jb) == 0) db_trace_self(); (void)kdb_jmpbuf(prev_jb); } static void db_trace_thread_wrapper(struct thread *td) { jmp_buf jb; void *prev_jb; prev_jb = kdb_jmpbuf(jb); if (setjmp(jb) == 0) db_trace_thread(td, -1); (void)kdb_jmpbuf(prev_jb); }