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