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 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/cons.h> 33 #include <sys/linker.h> 34 #include <sys/kdb.h> 35 #include <sys/kernel.h> 36 #include <sys/pcpu.h> 37 #include <sys/proc.h> 38 #include <sys/reboot.h> 39 #include <sys/sysctl.h> 40 41 #include <machine/kdb.h> 42 #include <machine/pcb.h> 43 #include <machine/setjmp.h> 44 45 #include <ddb/ddb.h> 46 #include <ddb/db_command.h> 47 #include <ddb/db_sym.h> 48 49 struct db_private { 50 char* strtab; 51 vm_offset_t relbase; 52 }; 53 typedef struct db_private *db_private_t; 54 55 #define DB_PRIVATE(x) ((db_private_t)(x->private)) 56 57 SYSCTL_NODE(_debug, OID_AUTO, ddb, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 58 "DDB settings"); 59 60 static dbbe_init_f db_init; 61 static dbbe_trap_f db_trap; 62 static dbbe_trace_f db_trace_self_wrapper; 63 static dbbe_trace_thread_f db_trace_thread_wrapper; 64 65 KDB_BACKEND(ddb, db_init, db_trace_self_wrapper, db_trace_thread_wrapper, 66 db_trap); 67 68 /* 69 * Symbols can be loaded by specifying the exact addresses of 70 * the symtab and strtab in memory. This is used when loaded from 71 * boot loaders different than the native one (like Xen). 72 */ 73 vm_offset_t ksymtab, kstrtab, ksymtab_size, ksymtab_relbase; 74 static struct db_private ksymtab_private; 75 76 bool 77 X_db_line_at_pc(db_symtab_t *symtab, c_db_sym_t sym, char **file, int *line, 78 db_expr_t off) 79 { 80 return (false); 81 } 82 83 c_db_sym_t 84 X_db_lookup(db_symtab_t *symtab, const char *symbol) 85 { 86 c_linker_sym_t lsym; 87 Elf_Sym *sym; 88 89 if (symtab->private == NULL) { 90 return ((c_db_sym_t)((!linker_ddb_lookup(symbol, &lsym)) 91 ? lsym : NULL)); 92 } else { 93 sym = (Elf_Sym *)symtab->start; 94 while ((char *)sym < symtab->end) { 95 if (sym->st_name != 0 && 96 !strcmp(DB_PRIVATE(symtab)->strtab + 97 sym->st_name, symbol)) 98 return ((c_db_sym_t)sym); 99 sym++; 100 } 101 } 102 return (NULL); 103 } 104 105 c_db_sym_t 106 X_db_search_symbol(db_symtab_t *symtab, db_addr_t off, db_strategy_t strat, 107 db_expr_t *diffp) 108 { 109 c_linker_sym_t lsym; 110 Elf_Sym *sym, *match; 111 unsigned long diff; 112 db_addr_t stoffs = off; 113 114 if (symtab->private == NULL) { 115 if (!linker_ddb_search_symbol((caddr_t)off, &lsym, &diff)) { 116 *diffp = (db_expr_t)diff; 117 return ((c_db_sym_t)lsym); 118 } 119 return (NULL); 120 } 121 else 122 stoffs -= DB_PRIVATE(symtab)->relbase; 123 124 diff = ~0UL; 125 match = NULL; 126 for (sym = (Elf_Sym*)symtab->start; (char*)sym < symtab->end; sym++) { 127 if (sym->st_name == 0 || sym->st_shndx == SHN_UNDEF) 128 continue; 129 if (stoffs < sym->st_value) 130 continue; 131 if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT && 132 ELF_ST_TYPE(sym->st_info) != STT_FUNC && 133 ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) 134 continue; 135 if ((stoffs - sym->st_value) > diff) 136 continue; 137 if ((stoffs - sym->st_value) < diff) { 138 diff = stoffs - sym->st_value; 139 match = sym; 140 } else { 141 if (match == NULL) 142 match = sym; 143 else if (ELF_ST_BIND(match->st_info) == STB_LOCAL && 144 ELF_ST_BIND(sym->st_info) != STB_LOCAL) 145 match = sym; 146 } 147 if (diff == 0) { 148 if (strat == DB_STGY_PROC && 149 ELF_ST_TYPE(sym->st_info) == STT_FUNC && 150 ELF_ST_BIND(sym->st_info) != STB_LOCAL) 151 break; 152 if (strat == DB_STGY_ANY && 153 ELF_ST_BIND(sym->st_info) != STB_LOCAL) 154 break; 155 } 156 } 157 158 *diffp = (match == NULL) ? off : diff; 159 return ((c_db_sym_t)match); 160 } 161 162 bool 163 X_db_sym_numargs(db_symtab_t *symtab, c_db_sym_t sym, int *nargp, 164 char **argp) 165 { 166 return (false); 167 } 168 169 void 170 X_db_symbol_values(db_symtab_t *symtab, c_db_sym_t sym, const char **namep, 171 db_expr_t *valp) 172 { 173 linker_symval_t lval; 174 175 if (symtab->private == NULL) { 176 linker_ddb_symbol_values((c_linker_sym_t)sym, &lval); 177 if (namep != NULL) 178 *namep = (const char*)lval.name; 179 if (valp != NULL) 180 *valp = (db_expr_t)lval.value; 181 } else { 182 if (namep != NULL) 183 *namep = (const char *)DB_PRIVATE(symtab)->strtab + 184 ((const Elf_Sym *)sym)->st_name; 185 if (valp != NULL) 186 *valp = (db_expr_t)((const Elf_Sym *)sym)->st_value + 187 DB_PRIVATE(symtab)->relbase; 188 } 189 } 190 191 int 192 db_fetch_ksymtab(vm_offset_t ksym_start, vm_offset_t ksym_end, 193 vm_offset_t relbase) 194 { 195 Elf_Size strsz; 196 197 if (ksym_end > ksym_start && ksym_start != 0) { 198 ksymtab = ksym_start; 199 ksymtab_size = *(Elf_Size*)ksymtab; 200 ksymtab += sizeof(Elf_Size); 201 kstrtab = ksymtab + ksymtab_size; 202 strsz = *(Elf_Size*)kstrtab; 203 kstrtab += sizeof(Elf_Size); 204 ksymtab_relbase = relbase; 205 if (kstrtab + strsz > ksym_end) { 206 /* Sizes doesn't match, unset everything. */ 207 ksymtab = ksymtab_size = kstrtab = ksymtab_relbase 208 = 0; 209 } 210 } 211 212 if (ksymtab == 0 || ksymtab_size == 0 || kstrtab == 0) 213 return (-1); 214 215 return (0); 216 } 217 218 static int 219 db_init(void) 220 { 221 222 db_command_init(); 223 224 if (ksymtab != 0 && kstrtab != 0 && ksymtab_size != 0) { 225 ksymtab_private.strtab = (char *)kstrtab; 226 ksymtab_private.relbase = ksymtab_relbase; 227 db_add_symbol_table((char *)ksymtab, 228 (char *)(ksymtab + ksymtab_size), "elf", (char *)&ksymtab_private); 229 } 230 db_add_symbol_table(NULL, NULL, "kld", NULL); 231 return (1); /* We're the default debugger. */ 232 } 233 234 static int 235 db_trap(int type, int code) 236 { 237 jmp_buf jb; 238 void *prev_jb; 239 bool bkpt, watchpt; 240 const char *why; 241 242 /* 243 * Don't handle the trap if the console is unavailable (i.e. it 244 * is in graphics mode). 245 */ 246 if (cnunavailable()) 247 return (0); 248 249 if (db_stop_at_pc(type, code, &bkpt, &watchpt)) { 250 if (db_inst_count) { 251 db_printf("After %d instructions (%d loads, %d stores),\n", 252 db_inst_count, db_load_count, db_store_count); 253 } 254 prev_jb = kdb_jmpbuf(jb); 255 if (setjmp(jb) == 0) { 256 db_dot = PC_REGS(); 257 db_print_thread(); 258 if (bkpt) 259 db_printf("Breakpoint at\t"); 260 else if (watchpt) 261 db_printf("Watchpoint at\t"); 262 else 263 db_printf("Stopped at\t"); 264 db_print_loc_and_inst(db_dot); 265 } 266 why = kdb_why; 267 db_script_kdbenter(why != KDB_WHY_UNSET ? why : "unknown"); 268 db_command_loop(); 269 (void)kdb_jmpbuf(prev_jb); 270 } 271 272 db_restart_at_pc(watchpt); 273 274 return (1); 275 } 276 277 static void 278 db_trace_self_wrapper(void) 279 { 280 jmp_buf jb; 281 void *prev_jb; 282 283 prev_jb = kdb_jmpbuf(jb); 284 if (setjmp(jb) == 0) 285 db_trace_self(); 286 (void)kdb_jmpbuf(prev_jb); 287 } 288 289 static void 290 db_trace_thread_wrapper(struct thread *td) 291 { 292 jmp_buf jb; 293 void *prev_jb; 294 295 prev_jb = kdb_jmpbuf(jb); 296 if (setjmp(jb) == 0) 297 db_trace_thread(td, -1); 298 (void)kdb_jmpbuf(prev_jb); 299 } 300