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 104 if (symtab->private == NULL) { 105 if (!linker_ddb_search_symbol((caddr_t)off, &lsym, &diff)) { 106 *diffp = (db_expr_t)diff; 107 return ((c_db_sym_t)lsym); 108 } 109 return (NULL); 110 } 111 112 diff = ~0UL; 113 match = NULL; 114 for (sym = (Elf_Sym*)symtab->start; (char*)sym < symtab->end; sym++) { 115 if (sym->st_name == 0 || sym->st_shndx == SHN_UNDEF) 116 continue; 117 if (off < sym->st_value) 118 continue; 119 if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT && 120 ELF_ST_TYPE(sym->st_info) != STT_FUNC && 121 ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) 122 continue; 123 if ((off - sym->st_value) > diff) 124 continue; 125 if ((off - sym->st_value) < diff) { 126 diff = off - sym->st_value; 127 match = sym; 128 } else { 129 if (match == NULL) 130 match = sym; 131 else if (ELF_ST_BIND(match->st_info) == STB_LOCAL && 132 ELF_ST_BIND(sym->st_info) != STB_LOCAL) 133 match = sym; 134 } 135 if (diff == 0) { 136 if (strat == DB_STGY_PROC && 137 ELF_ST_TYPE(sym->st_info) == STT_FUNC && 138 ELF_ST_BIND(sym->st_info) != STB_LOCAL) 139 break; 140 if (strat == DB_STGY_ANY && 141 ELF_ST_BIND(sym->st_info) != STB_LOCAL) 142 break; 143 } 144 } 145 146 *diffp = (match == NULL) ? off : diff; 147 return ((c_db_sym_t)match); 148 } 149 150 bool 151 X_db_sym_numargs(db_symtab_t *symtab, c_db_sym_t sym, int *nargp, 152 char **argp) 153 { 154 return (false); 155 } 156 157 void 158 X_db_symbol_values(db_symtab_t *symtab, c_db_sym_t sym, const char **namep, 159 db_expr_t *valp) 160 { 161 linker_symval_t lval; 162 163 if (symtab->private == NULL) { 164 linker_ddb_symbol_values((c_linker_sym_t)sym, &lval); 165 if (namep != NULL) 166 *namep = (const char*)lval.name; 167 if (valp != NULL) 168 *valp = (db_expr_t)lval.value; 169 } else { 170 if (namep != NULL) 171 *namep = (const char *)symtab->private + 172 ((const Elf_Sym *)sym)->st_name; 173 if (valp != NULL) 174 *valp = (db_expr_t)((const Elf_Sym *)sym)->st_value; 175 } 176 } 177 178 int 179 db_fetch_ksymtab(vm_offset_t ksym_start, vm_offset_t ksym_end) 180 { 181 Elf_Size strsz; 182 183 if (ksym_end > ksym_start && ksym_start != 0) { 184 ksymtab = ksym_start; 185 ksymtab_size = *(Elf_Size*)ksymtab; 186 ksymtab += sizeof(Elf_Size); 187 kstrtab = ksymtab + ksymtab_size; 188 strsz = *(Elf_Size*)kstrtab; 189 kstrtab += sizeof(Elf_Size); 190 if (kstrtab + strsz > ksym_end) { 191 /* Sizes doesn't match, unset everything. */ 192 ksymtab = ksymtab_size = kstrtab = 0; 193 } 194 } 195 196 if (ksymtab == 0 || ksymtab_size == 0 || kstrtab == 0) 197 return (-1); 198 199 return (0); 200 } 201 202 static int 203 db_init(void) 204 { 205 206 db_command_init(); 207 208 if (ksymtab != 0 && kstrtab != 0 && ksymtab_size != 0) { 209 db_add_symbol_table((char *)ksymtab, 210 (char *)(ksymtab + ksymtab_size), "elf", (char *)kstrtab); 211 } 212 db_add_symbol_table(NULL, NULL, "kld", NULL); 213 return (1); /* We're the default debugger. */ 214 } 215 216 static int 217 db_trap(int type, int code) 218 { 219 jmp_buf jb; 220 void *prev_jb; 221 bool bkpt, watchpt; 222 const char *why; 223 224 /* 225 * Don't handle the trap if the console is unavailable (i.e. it 226 * is in graphics mode). 227 */ 228 if (cnunavailable()) 229 return (0); 230 231 if (db_stop_at_pc(type, code, &bkpt, &watchpt)) { 232 if (db_inst_count) { 233 db_printf("After %d instructions (%d loads, %d stores),\n", 234 db_inst_count, db_load_count, db_store_count); 235 } 236 prev_jb = kdb_jmpbuf(jb); 237 if (setjmp(jb) == 0) { 238 db_dot = PC_REGS(); 239 db_print_thread(); 240 if (bkpt) 241 db_printf("Breakpoint at\t"); 242 else if (watchpt) 243 db_printf("Watchpoint at\t"); 244 else 245 db_printf("Stopped at\t"); 246 db_print_loc_and_inst(db_dot); 247 } 248 why = kdb_why; 249 db_script_kdbenter(why != KDB_WHY_UNSET ? why : "unknown"); 250 db_command_loop(); 251 (void)kdb_jmpbuf(prev_jb); 252 } 253 254 db_restart_at_pc(watchpt); 255 256 return (1); 257 } 258 259 static void 260 db_trace_self_wrapper(void) 261 { 262 jmp_buf jb; 263 void *prev_jb; 264 265 prev_jb = kdb_jmpbuf(jb); 266 if (setjmp(jb) == 0) 267 db_trace_self(); 268 (void)kdb_jmpbuf(prev_jb); 269 } 270 271 static void 272 db_trace_thread_wrapper(struct thread *td) 273 { 274 jmp_buf jb; 275 void *prev_jb; 276 277 prev_jb = kdb_jmpbuf(jb); 278 if (setjmp(jb) == 0) 279 db_trace_thread(td, -1); 280 (void)kdb_jmpbuf(prev_jb); 281 } 282