1 /*- 2 * SPDX-License-Identifier: MIT-CMU 3 * 4 * Mach Operating System 5 * Copyright (c) 1991,1990 Carnegie Mellon University 6 * All Rights Reserved. 7 * 8 * Permission to use, copy, modify and distribute this software and its 9 * documentation is hereby granted, provided that both the copyright 10 * notice and this permission notice appear in all copies of the 11 * software, derivative works or modified versions, and any portions 12 * thereof, and that both notices appear in supporting documentation. 13 * 14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 17 * 18 * Carnegie Mellon requests users of this software to return to 19 * 20 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 21 * School of Computer Science 22 * Carnegie Mellon University 23 * Pittsburgh PA 15213-3890 24 * 25 * any improvements or extensions that they make and grant Carnegie the 26 * rights to redistribute these changes. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/cons.h> 35 #include <sys/linker.h> 36 #include <sys/kdb.h> 37 #include <sys/kernel.h> 38 #include <sys/pcpu.h> 39 #include <sys/proc.h> 40 #include <sys/reboot.h> 41 #include <sys/sysctl.h> 42 43 #include <machine/kdb.h> 44 #include <machine/pcb.h> 45 #include <machine/setjmp.h> 46 47 #include <ddb/ddb.h> 48 #include <ddb/db_command.h> 49 #include <ddb/db_sym.h> 50 51 struct db_private { 52 char* strtab; 53 vm_offset_t relbase; 54 }; 55 typedef struct db_private *db_private_t; 56 57 #define DB_PRIVATE(x) ((db_private_t)(x->private)) 58 59 SYSCTL_NODE(_debug, OID_AUTO, ddb, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 60 "DDB settings"); 61 62 static dbbe_init_f db_init; 63 static dbbe_trap_f db_trap; 64 static dbbe_trace_f db_trace_self_wrapper; 65 static dbbe_trace_thread_f db_trace_thread_wrapper; 66 67 KDB_BACKEND(ddb, db_init, db_trace_self_wrapper, db_trace_thread_wrapper, 68 db_trap); 69 70 /* 71 * Symbols can be loaded by specifying the exact addresses of 72 * the symtab and strtab in memory. This is used when loaded from 73 * boot loaders different than the native one (like Xen). 74 */ 75 vm_offset_t ksymtab, kstrtab, ksymtab_size, ksymtab_relbase; 76 static struct db_private ksymtab_private; 77 78 bool 79 X_db_line_at_pc(db_symtab_t *symtab, c_db_sym_t sym, char **file, int *line, 80 db_expr_t off) 81 { 82 return (false); 83 } 84 85 c_db_sym_t 86 X_db_lookup(db_symtab_t *symtab, const char *symbol) 87 { 88 c_linker_sym_t lsym; 89 Elf_Sym *sym; 90 91 if (symtab->private == NULL) { 92 return ((c_db_sym_t)((!linker_ddb_lookup(symbol, &lsym)) 93 ? lsym : NULL)); 94 } else { 95 sym = (Elf_Sym *)symtab->start; 96 while ((char *)sym < symtab->end) { 97 if (sym->st_name != 0 && 98 !strcmp(DB_PRIVATE(symtab)->strtab + 99 sym->st_name, symbol)) 100 return ((c_db_sym_t)sym); 101 sym++; 102 } 103 } 104 return (NULL); 105 } 106 107 c_db_sym_t 108 X_db_search_symbol(db_symtab_t *symtab, db_addr_t off, db_strategy_t strat, 109 db_expr_t *diffp) 110 { 111 c_linker_sym_t lsym; 112 Elf_Sym *sym, *match; 113 unsigned long diff; 114 db_addr_t stoffs = off; 115 116 if (symtab->private == NULL) { 117 if (!linker_ddb_search_symbol((caddr_t)off, &lsym, &diff)) { 118 *diffp = (db_expr_t)diff; 119 return ((c_db_sym_t)lsym); 120 } 121 return (NULL); 122 } 123 else 124 stoffs -= DB_PRIVATE(symtab)->relbase; 125 126 diff = ~0UL; 127 match = NULL; 128 for (sym = (Elf_Sym*)symtab->start; (char*)sym < symtab->end; sym++) { 129 if (sym->st_name == 0 || sym->st_shndx == SHN_UNDEF) 130 continue; 131 if (stoffs < sym->st_value) 132 continue; 133 if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT && 134 ELF_ST_TYPE(sym->st_info) != STT_FUNC && 135 ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) 136 continue; 137 if ((stoffs - sym->st_value) > diff) 138 continue; 139 if ((stoffs - sym->st_value) < diff) { 140 diff = stoffs - sym->st_value; 141 match = sym; 142 } else { 143 if (match == NULL) 144 match = sym; 145 else if (ELF_ST_BIND(match->st_info) == STB_LOCAL && 146 ELF_ST_BIND(sym->st_info) != STB_LOCAL) 147 match = sym; 148 } 149 if (diff == 0) { 150 if (strat == DB_STGY_PROC && 151 ELF_ST_TYPE(sym->st_info) == STT_FUNC && 152 ELF_ST_BIND(sym->st_info) != STB_LOCAL) 153 break; 154 if (strat == DB_STGY_ANY && 155 ELF_ST_BIND(sym->st_info) != STB_LOCAL) 156 break; 157 } 158 } 159 160 *diffp = (match == NULL) ? off : diff; 161 return ((c_db_sym_t)match); 162 } 163 164 bool 165 X_db_sym_numargs(db_symtab_t *symtab, c_db_sym_t sym, int *nargp, 166 char **argp) 167 { 168 return (false); 169 } 170 171 void 172 X_db_symbol_values(db_symtab_t *symtab, c_db_sym_t sym, const char **namep, 173 db_expr_t *valp) 174 { 175 linker_symval_t lval; 176 177 if (symtab->private == NULL) { 178 linker_ddb_symbol_values((c_linker_sym_t)sym, &lval); 179 if (namep != NULL) 180 *namep = (const char*)lval.name; 181 if (valp != NULL) 182 *valp = (db_expr_t)lval.value; 183 } else { 184 if (namep != NULL) 185 *namep = (const char *)DB_PRIVATE(symtab)->strtab + 186 ((const Elf_Sym *)sym)->st_name; 187 if (valp != NULL) 188 *valp = (db_expr_t)((const Elf_Sym *)sym)->st_value + 189 DB_PRIVATE(symtab)->relbase; 190 } 191 } 192 193 int 194 db_fetch_ksymtab(vm_offset_t ksym_start, vm_offset_t ksym_end, 195 vm_offset_t relbase) 196 { 197 Elf_Size strsz; 198 199 if (ksym_end > ksym_start && ksym_start != 0) { 200 ksymtab = ksym_start; 201 ksymtab_size = *(Elf_Size*)ksymtab; 202 ksymtab += sizeof(Elf_Size); 203 kstrtab = ksymtab + ksymtab_size; 204 strsz = *(Elf_Size*)kstrtab; 205 kstrtab += sizeof(Elf_Size); 206 ksymtab_relbase = relbase; 207 if (kstrtab + strsz > ksym_end) { 208 /* Sizes doesn't match, unset everything. */ 209 ksymtab = ksymtab_size = kstrtab = ksymtab_relbase 210 = 0; 211 } 212 } 213 214 if (ksymtab == 0 || ksymtab_size == 0 || kstrtab == 0) 215 return (-1); 216 217 return (0); 218 } 219 220 static int 221 db_init(void) 222 { 223 224 db_command_init(); 225 226 if (ksymtab != 0 && kstrtab != 0 && ksymtab_size != 0) { 227 ksymtab_private.strtab = (char *)kstrtab; 228 ksymtab_private.relbase = ksymtab_relbase; 229 db_add_symbol_table((char *)ksymtab, 230 (char *)(ksymtab + ksymtab_size), "elf", (char *)&ksymtab_private); 231 } 232 db_add_symbol_table(NULL, NULL, "kld", NULL); 233 return (1); /* We're the default debugger. */ 234 } 235 236 static int 237 db_trap(int type, int code) 238 { 239 jmp_buf jb; 240 void *prev_jb; 241 bool bkpt, watchpt; 242 const char *why; 243 244 /* 245 * Don't handle the trap if the console is unavailable (i.e. it 246 * is in graphics mode). 247 */ 248 if (cnunavailable()) 249 return (0); 250 251 if (db_stop_at_pc(type, code, &bkpt, &watchpt)) { 252 if (db_inst_count) { 253 db_printf("After %d instructions (%d loads, %d stores),\n", 254 db_inst_count, db_load_count, db_store_count); 255 } 256 prev_jb = kdb_jmpbuf(jb); 257 if (setjmp(jb) == 0) { 258 db_dot = PC_REGS(); 259 db_print_thread(); 260 if (bkpt) 261 db_printf("Breakpoint at\t"); 262 else if (watchpt) 263 db_printf("Watchpoint at\t"); 264 else 265 db_printf("Stopped at\t"); 266 db_print_loc_and_inst(db_dot); 267 } 268 why = kdb_why; 269 db_script_kdbenter(why != KDB_WHY_UNSET ? why : "unknown"); 270 db_command_loop(); 271 (void)kdb_jmpbuf(prev_jb); 272 } 273 274 db_restart_at_pc(watchpt); 275 276 return (1); 277 } 278 279 static void 280 db_trace_self_wrapper(void) 281 { 282 jmp_buf jb; 283 void *prev_jb; 284 285 prev_jb = kdb_jmpbuf(jb); 286 if (setjmp(jb) == 0) 287 db_trace_self(); 288 (void)kdb_jmpbuf(prev_jb); 289 } 290 291 static void 292 db_trace_thread_wrapper(struct thread *td) 293 { 294 jmp_buf jb; 295 void *prev_jb; 296 297 prev_jb = kdb_jmpbuf(jb); 298 if (setjmp(jb) == 0) 299 db_trace_thread(td, -1); 300 (void)kdb_jmpbuf(prev_jb); 301 } 302