1dd3cb568SWarner Losh /*- 2796df753SPedro F. Giffuni * SPDX-License-Identifier: MIT-CMU 3796df753SPedro F. Giffuni * 437224cd3SMarcel Moolenaar * Mach Operating System 537224cd3SMarcel Moolenaar * Copyright (c) 1991,1990 Carnegie Mellon University 637224cd3SMarcel Moolenaar * All Rights Reserved. 737224cd3SMarcel Moolenaar * 837224cd3SMarcel Moolenaar * Permission to use, copy, modify and distribute this software and its 937224cd3SMarcel Moolenaar * documentation is hereby granted, provided that both the copyright 1037224cd3SMarcel Moolenaar * notice and this permission notice appear in all copies of the 1137224cd3SMarcel Moolenaar * software, derivative works or modified versions, and any portions 1237224cd3SMarcel Moolenaar * thereof, and that both notices appear in supporting documentation. 1337224cd3SMarcel Moolenaar * 1437224cd3SMarcel Moolenaar * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 1537224cd3SMarcel Moolenaar * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 1637224cd3SMarcel Moolenaar * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 1737224cd3SMarcel Moolenaar * 1837224cd3SMarcel Moolenaar * Carnegie Mellon requests users of this software to return to 1937224cd3SMarcel Moolenaar * 2037224cd3SMarcel Moolenaar * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 2137224cd3SMarcel Moolenaar * School of Computer Science 2237224cd3SMarcel Moolenaar * Carnegie Mellon University 2337224cd3SMarcel Moolenaar * Pittsburgh PA 15213-3890 2437224cd3SMarcel Moolenaar * 2537224cd3SMarcel Moolenaar * any improvements or extensions that they make and grant Carnegie the 2637224cd3SMarcel Moolenaar * rights to redistribute these changes. 2737224cd3SMarcel Moolenaar */ 2837224cd3SMarcel Moolenaar 2937224cd3SMarcel Moolenaar #include <sys/cdefs.h> 3037224cd3SMarcel Moolenaar __FBSDID("$FreeBSD$"); 3137224cd3SMarcel Moolenaar 3237224cd3SMarcel Moolenaar #include <sys/param.h> 3337224cd3SMarcel Moolenaar #include <sys/systm.h> 3437224cd3SMarcel Moolenaar #include <sys/cons.h> 3537224cd3SMarcel Moolenaar #include <sys/linker.h> 3637224cd3SMarcel Moolenaar #include <sys/kdb.h> 3737224cd3SMarcel Moolenaar #include <sys/kernel.h> 3837224cd3SMarcel Moolenaar #include <sys/pcpu.h> 3937224cd3SMarcel Moolenaar #include <sys/proc.h> 4037224cd3SMarcel Moolenaar #include <sys/reboot.h> 41086fec57SRobert Watson #include <sys/sysctl.h> 4237224cd3SMarcel Moolenaar 4337224cd3SMarcel Moolenaar #include <machine/kdb.h> 4437224cd3SMarcel Moolenaar #include <machine/pcb.h> 4537224cd3SMarcel Moolenaar #include <machine/setjmp.h> 4637224cd3SMarcel Moolenaar 4737224cd3SMarcel Moolenaar #include <ddb/ddb.h> 4837224cd3SMarcel Moolenaar #include <ddb/db_command.h> 4937224cd3SMarcel Moolenaar #include <ddb/db_sym.h> 5037224cd3SMarcel Moolenaar 51*40b664f6SBrandon Bergren struct db_private { 52*40b664f6SBrandon Bergren char* strtab; 53*40b664f6SBrandon Bergren vm_offset_t relbase; 54*40b664f6SBrandon Bergren }; 55*40b664f6SBrandon Bergren typedef struct db_private *db_private_t; 56*40b664f6SBrandon Bergren 57*40b664f6SBrandon Bergren #define DB_PRIVATE(x) ((db_private_t)(x->private)) 58*40b664f6SBrandon Bergren 597029da5cSPawel Biernacki SYSCTL_NODE(_debug, OID_AUTO, ddb, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 607029da5cSPawel Biernacki "DDB settings"); 61086fec57SRobert Watson 6237224cd3SMarcel Moolenaar static dbbe_init_f db_init; 6337224cd3SMarcel Moolenaar static dbbe_trap_f db_trap; 64a0396f27SKonstantin Belousov static dbbe_trace_f db_trace_self_wrapper; 6528926c57SJohn Baldwin static dbbe_trace_thread_f db_trace_thread_wrapper; 6637224cd3SMarcel Moolenaar 6728926c57SJohn Baldwin KDB_BACKEND(ddb, db_init, db_trace_self_wrapper, db_trace_thread_wrapper, 6828926c57SJohn Baldwin db_trap); 6937224cd3SMarcel Moolenaar 70c98a2727SRoger Pau Monné /* 71c98a2727SRoger Pau Monné * Symbols can be loaded by specifying the exact addresses of 72c98a2727SRoger Pau Monné * the symtab and strtab in memory. This is used when loaded from 73c98a2727SRoger Pau Monné * boot loaders different than the native one (like Xen). 74c98a2727SRoger Pau Monné */ 75*40b664f6SBrandon Bergren vm_offset_t ksymtab, kstrtab, ksymtab_size, ksymtab_relbase; 76*40b664f6SBrandon Bergren static struct db_private ksymtab_private; 7737224cd3SMarcel Moolenaar 78cd508278SPedro F. Giffuni bool 7937224cd3SMarcel Moolenaar X_db_line_at_pc(db_symtab_t *symtab, c_db_sym_t sym, char **file, int *line, 8037224cd3SMarcel Moolenaar db_expr_t off) 8137224cd3SMarcel Moolenaar { 822b490bc7SPedro F. Giffuni return (false); 8337224cd3SMarcel Moolenaar } 8437224cd3SMarcel Moolenaar 8537224cd3SMarcel Moolenaar c_db_sym_t 8637224cd3SMarcel Moolenaar X_db_lookup(db_symtab_t *symtab, const char *symbol) 8737224cd3SMarcel Moolenaar { 8837224cd3SMarcel Moolenaar c_linker_sym_t lsym; 8937224cd3SMarcel Moolenaar Elf_Sym *sym; 9037224cd3SMarcel Moolenaar 9137224cd3SMarcel Moolenaar if (symtab->private == NULL) { 9237224cd3SMarcel Moolenaar return ((c_db_sym_t)((!linker_ddb_lookup(symbol, &lsym)) 9337224cd3SMarcel Moolenaar ? lsym : NULL)); 9437224cd3SMarcel Moolenaar } else { 9537224cd3SMarcel Moolenaar sym = (Elf_Sym *)symtab->start; 9637224cd3SMarcel Moolenaar while ((char *)sym < symtab->end) { 9737224cd3SMarcel Moolenaar if (sym->st_name != 0 && 98*40b664f6SBrandon Bergren !strcmp(DB_PRIVATE(symtab)->strtab + 99*40b664f6SBrandon Bergren sym->st_name, symbol)) 10037224cd3SMarcel Moolenaar return ((c_db_sym_t)sym); 10137224cd3SMarcel Moolenaar sym++; 10237224cd3SMarcel Moolenaar } 10337224cd3SMarcel Moolenaar } 10437224cd3SMarcel Moolenaar return (NULL); 10537224cd3SMarcel Moolenaar } 10637224cd3SMarcel Moolenaar 10737224cd3SMarcel Moolenaar c_db_sym_t 10837224cd3SMarcel Moolenaar X_db_search_symbol(db_symtab_t *symtab, db_addr_t off, db_strategy_t strat, 10937224cd3SMarcel Moolenaar db_expr_t *diffp) 11037224cd3SMarcel Moolenaar { 11137224cd3SMarcel Moolenaar c_linker_sym_t lsym; 11237224cd3SMarcel Moolenaar Elf_Sym *sym, *match; 11337224cd3SMarcel Moolenaar unsigned long diff; 114*40b664f6SBrandon Bergren db_addr_t stoffs = off; 11537224cd3SMarcel Moolenaar 11637224cd3SMarcel Moolenaar if (symtab->private == NULL) { 11737224cd3SMarcel Moolenaar if (!linker_ddb_search_symbol((caddr_t)off, &lsym, &diff)) { 11837224cd3SMarcel Moolenaar *diffp = (db_expr_t)diff; 11937224cd3SMarcel Moolenaar return ((c_db_sym_t)lsym); 12037224cd3SMarcel Moolenaar } 12137224cd3SMarcel Moolenaar return (NULL); 12237224cd3SMarcel Moolenaar } 123*40b664f6SBrandon Bergren else 124*40b664f6SBrandon Bergren stoffs -= DB_PRIVATE(symtab)->relbase; 12537224cd3SMarcel Moolenaar 12637224cd3SMarcel Moolenaar diff = ~0UL; 12737224cd3SMarcel Moolenaar match = NULL; 12837224cd3SMarcel Moolenaar for (sym = (Elf_Sym*)symtab->start; (char*)sym < symtab->end; sym++) { 129e31a60b4SMark Johnston if (sym->st_name == 0 || sym->st_shndx == SHN_UNDEF) 13037224cd3SMarcel Moolenaar continue; 131b4a0a598SJustin Hibbits if (stoffs < sym->st_value) 13237224cd3SMarcel Moolenaar continue; 13337224cd3SMarcel Moolenaar if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT && 13437224cd3SMarcel Moolenaar ELF_ST_TYPE(sym->st_info) != STT_FUNC && 13537224cd3SMarcel Moolenaar ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) 13637224cd3SMarcel Moolenaar continue; 137b4a0a598SJustin Hibbits if ((stoffs - sym->st_value) > diff) 13837224cd3SMarcel Moolenaar continue; 139b4a0a598SJustin Hibbits if ((stoffs - sym->st_value) < diff) { 140b4a0a598SJustin Hibbits diff = stoffs - sym->st_value; 14137224cd3SMarcel Moolenaar match = sym; 14237224cd3SMarcel Moolenaar } else { 14337224cd3SMarcel Moolenaar if (match == NULL) 14437224cd3SMarcel Moolenaar match = sym; 14537224cd3SMarcel Moolenaar else if (ELF_ST_BIND(match->st_info) == STB_LOCAL && 14637224cd3SMarcel Moolenaar ELF_ST_BIND(sym->st_info) != STB_LOCAL) 14737224cd3SMarcel Moolenaar match = sym; 14837224cd3SMarcel Moolenaar } 14937224cd3SMarcel Moolenaar if (diff == 0) { 15037224cd3SMarcel Moolenaar if (strat == DB_STGY_PROC && 15137224cd3SMarcel Moolenaar ELF_ST_TYPE(sym->st_info) == STT_FUNC && 15237224cd3SMarcel Moolenaar ELF_ST_BIND(sym->st_info) != STB_LOCAL) 15337224cd3SMarcel Moolenaar break; 15437224cd3SMarcel Moolenaar if (strat == DB_STGY_ANY && 15537224cd3SMarcel Moolenaar ELF_ST_BIND(sym->st_info) != STB_LOCAL) 15637224cd3SMarcel Moolenaar break; 15737224cd3SMarcel Moolenaar } 15837224cd3SMarcel Moolenaar } 15937224cd3SMarcel Moolenaar 16037224cd3SMarcel Moolenaar *diffp = (match == NULL) ? off : diff; 16137224cd3SMarcel Moolenaar return ((c_db_sym_t)match); 16237224cd3SMarcel Moolenaar } 16337224cd3SMarcel Moolenaar 164cd508278SPedro F. Giffuni bool 16537224cd3SMarcel Moolenaar X_db_sym_numargs(db_symtab_t *symtab, c_db_sym_t sym, int *nargp, 16637224cd3SMarcel Moolenaar char **argp) 16737224cd3SMarcel Moolenaar { 1682b490bc7SPedro F. Giffuni return (false); 16937224cd3SMarcel Moolenaar } 17037224cd3SMarcel Moolenaar 17137224cd3SMarcel Moolenaar void 17237224cd3SMarcel Moolenaar X_db_symbol_values(db_symtab_t *symtab, c_db_sym_t sym, const char **namep, 17337224cd3SMarcel Moolenaar db_expr_t *valp) 17437224cd3SMarcel Moolenaar { 17537224cd3SMarcel Moolenaar linker_symval_t lval; 17637224cd3SMarcel Moolenaar 17737224cd3SMarcel Moolenaar if (symtab->private == NULL) { 17837224cd3SMarcel Moolenaar linker_ddb_symbol_values((c_linker_sym_t)sym, &lval); 17937224cd3SMarcel Moolenaar if (namep != NULL) 18037224cd3SMarcel Moolenaar *namep = (const char*)lval.name; 18137224cd3SMarcel Moolenaar if (valp != NULL) 18237224cd3SMarcel Moolenaar *valp = (db_expr_t)lval.value; 18337224cd3SMarcel Moolenaar } else { 18437224cd3SMarcel Moolenaar if (namep != NULL) 185*40b664f6SBrandon Bergren *namep = (const char *)DB_PRIVATE(symtab)->strtab + 18637224cd3SMarcel Moolenaar ((const Elf_Sym *)sym)->st_name; 18737224cd3SMarcel Moolenaar if (valp != NULL) 188*40b664f6SBrandon Bergren *valp = (db_expr_t)((const Elf_Sym *)sym)->st_value + 189*40b664f6SBrandon Bergren DB_PRIVATE(symtab)->relbase; 19037224cd3SMarcel Moolenaar } 19137224cd3SMarcel Moolenaar } 19237224cd3SMarcel Moolenaar 193c98a2727SRoger Pau Monné int 194*40b664f6SBrandon Bergren db_fetch_ksymtab(vm_offset_t ksym_start, vm_offset_t ksym_end, 195*40b664f6SBrandon Bergren vm_offset_t relbase) 196c98a2727SRoger Pau Monné { 197c98a2727SRoger Pau Monné Elf_Size strsz; 198c98a2727SRoger Pau Monné 199c98a2727SRoger Pau Monné if (ksym_end > ksym_start && ksym_start != 0) { 200c98a2727SRoger Pau Monné ksymtab = ksym_start; 201c98a2727SRoger Pau Monné ksymtab_size = *(Elf_Size*)ksymtab; 202c98a2727SRoger Pau Monné ksymtab += sizeof(Elf_Size); 203c98a2727SRoger Pau Monné kstrtab = ksymtab + ksymtab_size; 204c98a2727SRoger Pau Monné strsz = *(Elf_Size*)kstrtab; 205c98a2727SRoger Pau Monné kstrtab += sizeof(Elf_Size); 206*40b664f6SBrandon Bergren ksymtab_relbase = relbase; 207c98a2727SRoger Pau Monné if (kstrtab + strsz > ksym_end) { 208c98a2727SRoger Pau Monné /* Sizes doesn't match, unset everything. */ 209*40b664f6SBrandon Bergren ksymtab = ksymtab_size = kstrtab = ksymtab_relbase 210*40b664f6SBrandon Bergren = 0; 211c98a2727SRoger Pau Monné } 212c98a2727SRoger Pau Monné } 213c98a2727SRoger Pau Monné 214c98a2727SRoger Pau Monné if (ksymtab == 0 || ksymtab_size == 0 || kstrtab == 0) 215c98a2727SRoger Pau Monné return (-1); 216c98a2727SRoger Pau Monné 217c98a2727SRoger Pau Monné return (0); 218c98a2727SRoger Pau Monné } 219c98a2727SRoger Pau Monné 22037224cd3SMarcel Moolenaar static int 22137224cd3SMarcel Moolenaar db_init(void) 22237224cd3SMarcel Moolenaar { 22337224cd3SMarcel Moolenaar 22493d4804bSJohn Baldwin db_command_init(); 225c98a2727SRoger Pau Monné 226c98a2727SRoger Pau Monné if (ksymtab != 0 && kstrtab != 0 && ksymtab_size != 0) { 227*40b664f6SBrandon Bergren ksymtab_private.strtab = (char *)kstrtab; 228*40b664f6SBrandon Bergren ksymtab_private.relbase = ksymtab_relbase; 229c98a2727SRoger Pau Monné db_add_symbol_table((char *)ksymtab, 230*40b664f6SBrandon Bergren (char *)(ksymtab + ksymtab_size), "elf", (char *)&ksymtab_private); 23137224cd3SMarcel Moolenaar } 23237224cd3SMarcel Moolenaar db_add_symbol_table(NULL, NULL, "kld", NULL); 23337224cd3SMarcel Moolenaar return (1); /* We're the default debugger. */ 23437224cd3SMarcel Moolenaar } 23537224cd3SMarcel Moolenaar 23637224cd3SMarcel Moolenaar static int 23737224cd3SMarcel Moolenaar db_trap(int type, int code) 23837224cd3SMarcel Moolenaar { 23937224cd3SMarcel Moolenaar jmp_buf jb; 24037224cd3SMarcel Moolenaar void *prev_jb; 241cd508278SPedro F. Giffuni bool bkpt, watchpt; 242c9b0cc3bSRobert Watson const char *why; 24337224cd3SMarcel Moolenaar 24437224cd3SMarcel Moolenaar /* 24537224cd3SMarcel Moolenaar * Don't handle the trap if the console is unavailable (i.e. it 24637224cd3SMarcel Moolenaar * is in graphics mode). 24737224cd3SMarcel Moolenaar */ 24837224cd3SMarcel Moolenaar if (cnunavailable()) 24937224cd3SMarcel Moolenaar return (0); 25037224cd3SMarcel Moolenaar 2515c48342fSBruce Evans if (db_stop_at_pc(type, code, &bkpt, &watchpt)) { 25237224cd3SMarcel Moolenaar if (db_inst_count) { 25337224cd3SMarcel Moolenaar db_printf("After %d instructions (%d loads, %d stores),\n", 25437224cd3SMarcel Moolenaar db_inst_count, db_load_count, db_store_count); 25537224cd3SMarcel Moolenaar } 25637224cd3SMarcel Moolenaar prev_jb = kdb_jmpbuf(jb); 25737224cd3SMarcel Moolenaar if (setjmp(jb) == 0) { 25837224cd3SMarcel Moolenaar db_dot = PC_REGS(); 25937224cd3SMarcel Moolenaar db_print_thread(); 26037224cd3SMarcel Moolenaar if (bkpt) 26137224cd3SMarcel Moolenaar db_printf("Breakpoint at\t"); 26237224cd3SMarcel Moolenaar else if (watchpt) 26337224cd3SMarcel Moolenaar db_printf("Watchpoint at\t"); 26437224cd3SMarcel Moolenaar else 26537224cd3SMarcel Moolenaar db_printf("Stopped at\t"); 26637224cd3SMarcel Moolenaar db_print_loc_and_inst(db_dot); 26737224cd3SMarcel Moolenaar } 268c9b0cc3bSRobert Watson why = kdb_why; 269c9b0cc3bSRobert Watson db_script_kdbenter(why != KDB_WHY_UNSET ? why : "unknown"); 27037224cd3SMarcel Moolenaar db_command_loop(); 27137224cd3SMarcel Moolenaar (void)kdb_jmpbuf(prev_jb); 27237224cd3SMarcel Moolenaar } 27337224cd3SMarcel Moolenaar 27437224cd3SMarcel Moolenaar db_restart_at_pc(watchpt); 27537224cd3SMarcel Moolenaar 27637224cd3SMarcel Moolenaar return (1); 27737224cd3SMarcel Moolenaar } 278a0396f27SKonstantin Belousov 279a0396f27SKonstantin Belousov static void 280a0396f27SKonstantin Belousov db_trace_self_wrapper(void) 281a0396f27SKonstantin Belousov { 282a0396f27SKonstantin Belousov jmp_buf jb; 283a0396f27SKonstantin Belousov void *prev_jb; 284a0396f27SKonstantin Belousov 285a0396f27SKonstantin Belousov prev_jb = kdb_jmpbuf(jb); 286a0396f27SKonstantin Belousov if (setjmp(jb) == 0) 287a0396f27SKonstantin Belousov db_trace_self(); 288a0396f27SKonstantin Belousov (void)kdb_jmpbuf(prev_jb); 289a0396f27SKonstantin Belousov } 29028926c57SJohn Baldwin 29128926c57SJohn Baldwin static void 29228926c57SJohn Baldwin db_trace_thread_wrapper(struct thread *td) 29328926c57SJohn Baldwin { 29428926c57SJohn Baldwin jmp_buf jb; 29528926c57SJohn Baldwin void *prev_jb; 29628926c57SJohn Baldwin 29728926c57SJohn Baldwin prev_jb = kdb_jmpbuf(jb); 29828926c57SJohn Baldwin if (setjmp(jb) == 0) 29928926c57SJohn Baldwin db_trace_thread(td, -1); 30028926c57SJohn Baldwin (void)kdb_jmpbuf(prev_jb); 30128926c57SJohn Baldwin } 302