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