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