1 1.71 riastrad /* $NetBSD: db_sym.c,v 1.71 2022/08/30 22:38:01 riastradh Exp $ */ 2 1.7 cgd 3 1.31 simonb /* 4 1.1 cgd * Mach Operating System 5 1.1 cgd * Copyright (c) 1991,1990 Carnegie Mellon University 6 1.1 cgd * All Rights Reserved. 7 1.31 simonb * 8 1.1 cgd * Permission to use, copy, modify and distribute this software and its 9 1.1 cgd * documentation is hereby granted, provided that both the copyright 10 1.1 cgd * notice and this permission notice appear in all copies of the 11 1.1 cgd * software, derivative works or modified versions, and any portions 12 1.1 cgd * thereof, and that both notices appear in supporting documentation. 13 1.31 simonb * 14 1.17 pk * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 15 1.1 cgd * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 16 1.1 cgd * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 17 1.31 simonb * 18 1.1 cgd * Carnegie Mellon requests users of this software to return to 19 1.31 simonb * 20 1.1 cgd * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU 21 1.1 cgd * School of Computer Science 22 1.1 cgd * Carnegie Mellon University 23 1.1 cgd * Pittsburgh PA 15213-3890 24 1.31 simonb * 25 1.1 cgd * any improvements or extensions that they make and grant Carnegie the 26 1.1 cgd * rights to redistribute these changes. 27 1.1 cgd */ 28 1.28 lukem 29 1.28 lukem #include <sys/cdefs.h> 30 1.71 riastrad __KERNEL_RCSID(0, "$NetBSD: db_sym.c,v 1.71 2022/08/30 22:38:01 riastradh Exp $"); 31 1.5 mycroft 32 1.59 ad #ifdef _KERNEL_OPT 33 1.32 itohy #include "opt_ddbparam.h" 34 1.59 ad #endif 35 1.26 simonb 36 1.6 mycroft #include <sys/param.h> 37 1.6 mycroft #include <sys/proc.h> 38 1.15 thorpej #include <sys/systm.h> 39 1.35 ragge #include <sys/ksyms.h> 40 1.71 riastrad #include <sys/pserialize.h> 41 1.6 mycroft 42 1.59 ad #include <ddb/ddb.h> 43 1.1 cgd 44 1.35 ragge static void db_symsplit(char *, char **, char **); 45 1.31 simonb 46 1.15 thorpej 47 1.60 mrg #ifndef _KERNEL 48 1.35 ragge #define TBLNAME "netbsd" 49 1.15 thorpej 50 1.61 mrg #define use_ksyms 0 51 1.61 mrg 52 1.15 thorpej const db_symformat_t *db_symformat; 53 1.35 ragge static db_forall_func_t db_sift; 54 1.59 ad extern db_symformat_t db_symformat_elf; 55 1.35 ragge #endif 56 1.15 thorpej 57 1.15 thorpej 58 1.15 thorpej /* 59 1.15 thorpej * Initialize the kernel debugger by initializing the master symbol 60 1.15 thorpej * table. Note that if initializing the master symbol table fails, 61 1.15 thorpej * no other symbol tables can be loaded. 62 1.15 thorpej */ 63 1.15 thorpej void 64 1.31 simonb ddb_init(int symsize, void *vss, void *vse) 65 1.15 thorpej { 66 1.59 ad #ifdef _KERNEL 67 1.58 martin ksyms_addsyms_elf(symsize, vss, vse); /* Will complain if necessary */ 68 1.59 ad #else /* _KERNEL */ 69 1.59 ad db_symformat = &db_symformat_elf; 70 1.61 mrg if ((*db_symformat->sym_init)(symsize, vss, vse, TBLNAME) != true) 71 1.61 mrg printf("sym_init failed"); 72 1.59 ad #endif /* _KERNEL */ 73 1.1 cgd } 74 1.1 cgd 75 1.55 thorpej bool 76 1.51 christos db_eqname(const char *src, const char *dst, int c) 77 1.1 cgd { 78 1.31 simonb 79 1.1 cgd if (!strcmp(src, dst)) 80 1.56 thorpej return (true); 81 1.1 cgd if (src[0] == c) 82 1.31 simonb return (!strcmp(src+1,dst)); 83 1.56 thorpej return (false); 84 1.1 cgd } 85 1.1 cgd 86 1.55 thorpej bool 87 1.51 christos db_value_of_name(const char *name, db_expr_t *valuep) 88 1.1 cgd { 89 1.51 christos char symbol[128]; 90 1.35 ragge char *mod, *sym; 91 1.59 ad #ifdef _KERNEL 92 1.43 scw unsigned long uval; 93 1.43 scw long val; 94 1.59 ad #endif 95 1.1 cgd 96 1.60 mrg #ifndef _KERNEL 97 1.60 mrg if (!use_ksyms) { 98 1.60 mrg db_sym_t ssym; 99 1.1 cgd 100 1.35 ragge /* 101 1.35 ragge * Cannot load symtabs in a.out kernels, so the ':' 102 1.35 ragge * style of selecting modules is irrelevant. 103 1.35 ragge */ 104 1.35 ragge ssym = (*db_symformat->sym_lookup)(NULL, name); 105 1.35 ragge if (ssym == DB_SYM_NULL) 106 1.56 thorpej return (false); 107 1.35 ragge db_symbol_values(ssym, &name, valuep); 108 1.56 thorpej return (true); 109 1.1 cgd } 110 1.35 ragge #endif 111 1.60 mrg 112 1.51 christos (void)strlcpy(symbol, name, sizeof(symbol)); 113 1.51 christos db_symsplit(symbol, &mod, &sym); 114 1.59 ad #ifdef _KERNEL 115 1.65 maxv if (ksyms_getval_unlocked(mod, sym, NULL, &uval, KSYMS_EXTERN) == 0) { 116 1.43 scw val = (long) uval; 117 1.41 scw *valuep = (db_expr_t)val; 118 1.56 thorpej return true; 119 1.41 scw } 120 1.65 maxv if (ksyms_getval_unlocked(mod, sym, NULL, &uval, KSYMS_ANY) == 0) { 121 1.43 scw val = (long) uval; 122 1.41 scw *valuep = (db_expr_t)val; 123 1.56 thorpej return true; 124 1.41 scw } 125 1.59 ad #endif 126 1.56 thorpej return false; 127 1.1 cgd } 128 1.1 cgd 129 1.60 mrg #ifndef _KERNEL 130 1.20 jhawk /* Private structure for passing args to db_sift() from db_sifting(). */ 131 1.20 jhawk struct db_sift_args { 132 1.20 jhawk char *symstr; 133 1.20 jhawk int mode; 134 1.20 jhawk }; 135 1.20 jhawk 136 1.20 jhawk /* 137 1.20 jhawk * Does the work of db_sifting(), called once for each 138 1.35 ragge * symbol via db_forall(), prints out symbols matching 139 1.20 jhawk * criteria. 140 1.20 jhawk */ 141 1.20 jhawk static void 142 1.54 christos db_sift(db_symtab_t *stab, db_sym_t sym, char *name, 143 1.54 christos char *suffix, int prefix, void *arg) 144 1.20 jhawk { 145 1.20 jhawk char c, sc; 146 1.20 jhawk char *find, *p; 147 1.20 jhawk size_t len; 148 1.20 jhawk struct db_sift_args *dsa; 149 1.20 jhawk 150 1.20 jhawk dsa = (struct db_sift_args*)arg; 151 1.20 jhawk 152 1.20 jhawk find = dsa->symstr; /* String we're looking for. */ 153 1.20 jhawk p = name; /* String we're searching within. */ 154 1.31 simonb 155 1.20 jhawk /* Matching algorithm cribbed from strstr(), which is not 156 1.20 jhawk in the kernel. */ 157 1.20 jhawk if ((c = *find++) != 0) { 158 1.20 jhawk len = strlen(find); 159 1.20 jhawk do { 160 1.20 jhawk do { 161 1.20 jhawk if ((sc = *p++) == 0) 162 1.20 jhawk return; 163 1.20 jhawk } while (sc != c); 164 1.20 jhawk } while (strncmp(p, find, len) != 0); 165 1.20 jhawk } 166 1.20 jhawk if (dsa->mode=='F') /* ala ls -F */ 167 1.20 jhawk db_printf("%s%s ", name, suffix); 168 1.20 jhawk else 169 1.20 jhawk db_printf("%s ", name); 170 1.20 jhawk } 171 1.35 ragge #endif 172 1.20 jhawk 173 1.20 jhawk /* 174 1.20 jhawk * "Sift" for a partial symbol. 175 1.20 jhawk * Named for the Sun OpenPROM command ("sifting"). 176 1.20 jhawk * If the symbol has a qualifier (e.g., ux:vm_map), 177 1.20 jhawk * then only the specified symbol table will be searched; 178 1.20 jhawk * otherwise, all symbol tables will be searched.. 179 1.20 jhawk * 180 1.20 jhawk * "mode" is how-to-display, set from modifiers. 181 1.20 jhawk */ 182 1.20 jhawk void 183 1.31 simonb db_sifting(char *symstr, int mode) 184 1.20 jhawk { 185 1.59 ad #ifdef _KERNEL 186 1.35 ragge char *mod, *sym; 187 1.59 ad #endif 188 1.35 ragge 189 1.60 mrg #ifndef _KERNEL 190 1.20 jhawk struct db_sift_args dsa; 191 1.20 jhawk 192 1.60 mrg if (!use_ksyms) { 193 1.35 ragge dsa.symstr = symstr; 194 1.35 ragge dsa.mode = mode; 195 1.35 ragge (*db_symformat->sym_forall)(NULL, db_sift, &dsa); 196 1.35 ragge db_printf("\n"); 197 1.35 ragge return; 198 1.20 jhawk } 199 1.35 ragge #endif 200 1.20 jhawk 201 1.59 ad #ifdef _KERNEL 202 1.35 ragge db_symsplit(symstr, &mod, &sym); 203 1.35 ragge if (ksyms_sift(mod, sym, mode) == ENODEV) 204 1.35 ragge db_error("invalid symbol table name"); 205 1.59 ad #endif 206 1.1 cgd } 207 1.1 cgd 208 1.1 cgd /* 209 1.1 cgd * Find the closest symbol to val, and return its name 210 1.1 cgd * and the difference between val and the symbol found. 211 1.1 cgd */ 212 1.1 cgd db_sym_t 213 1.31 simonb db_search_symbol(db_addr_t val, db_strategy_t strategy, db_expr_t *offp) 214 1.1 cgd { 215 1.35 ragge unsigned int diff; 216 1.59 ad db_sym_t ret = DB_SYM_NULL; 217 1.59 ad #ifdef _KERNEL 218 1.41 scw unsigned long naddr; 219 1.39 jdolecek const char *mod; 220 1.51 christos const char *sym; 221 1.59 ad #endif 222 1.35 ragge 223 1.60 mrg #ifndef _KERNEL 224 1.60 mrg if (!use_ksyms) { 225 1.60 mrg db_expr_t newdiff; 226 1.60 mrg db_sym_t ssym; 227 1.35 ragge 228 1.67 mrg diff = ~0u; 229 1.67 mrg newdiff = ~0; 230 1.35 ragge ssym = (*db_symformat->sym_search) 231 1.35 ragge (NULL, val, strategy, &newdiff); 232 1.33 thorpej if ((unsigned int) newdiff < diff) { 233 1.31 simonb diff = newdiff; 234 1.35 ragge ret = ssym; 235 1.31 simonb } 236 1.35 ragge *offp = diff; 237 1.35 ragge return ret; 238 1.35 ragge } 239 1.35 ragge #endif 240 1.35 ragge 241 1.59 ad #ifdef _KERNEL 242 1.41 scw if (ksyms_getname(&mod, &sym, (vaddr_t)val, strategy) == 0) { 243 1.65 maxv (void)ksyms_getval_unlocked(mod, sym, NULL, &naddr, KSYMS_ANY); 244 1.41 scw diff = val - (db_addr_t)naddr; 245 1.41 scw ret = (db_sym_t)naddr; 246 1.44 christos } else 247 1.59 ad #endif 248 1.44 christos diff = 0; 249 1.1 cgd *offp = diff; 250 1.1 cgd return ret; 251 1.1 cgd } 252 1.1 cgd 253 1.1 cgd /* 254 1.1 cgd * Return name and value of a symbol 255 1.1 cgd */ 256 1.1 cgd void 257 1.51 christos db_symbol_values(db_sym_t sym, const char **namep, db_expr_t *valuep) 258 1.1 cgd { 259 1.59 ad #ifdef _KERNEL 260 1.39 jdolecek const char *mod; 261 1.59 ad #endif 262 1.1 cgd 263 1.1 cgd if (sym == DB_SYM_NULL) { 264 1.1 cgd *namep = 0; 265 1.1 cgd return; 266 1.1 cgd } 267 1.1 cgd 268 1.60 mrg #ifndef _KERNEL 269 1.60 mrg if (!use_ksyms) { 270 1.35 ragge db_expr_t value; 271 1.60 mrg 272 1.35 ragge (*db_symformat->sym_value)(NULL, sym, namep, &value); 273 1.35 ragge if (valuep) 274 1.35 ragge *valuep = value; 275 1.35 ragge return; 276 1.35 ragge } 277 1.35 ragge #endif 278 1.1 cgd 279 1.59 ad #ifdef _KERNEL 280 1.41 scw if (ksyms_getname(&mod, namep, (vaddr_t)sym, 281 1.41 scw KSYMS_ANY|KSYMS_EXACT) == 0) { 282 1.35 ragge if (valuep) 283 1.35 ragge *valuep = sym; 284 1.35 ragge } else 285 1.59 ad #endif 286 1.35 ragge *namep = NULL; 287 1.1 cgd } 288 1.1 cgd 289 1.1 cgd 290 1.1 cgd /* 291 1.1 cgd * Print a the closest symbol to value 292 1.1 cgd * 293 1.1 cgd * After matching the symbol according to the given strategy 294 1.1 cgd * we print it in the name+offset format, provided the symbol's 295 1.1 cgd * value is close enough (eg smaller than db_maxoff). 296 1.1 cgd * We also attempt to print [filename:linenum] when applicable 297 1.1 cgd * (eg for procedure names). 298 1.1 cgd * 299 1.1 cgd * If we could not find a reasonable name+offset representation, 300 1.1 cgd * then we just print the value in hex. Small values might get 301 1.1 cgd * bogus symbol associations, e.g. 3 might get some absolute 302 1.1 cgd * value like _INCLUDE_VERSION or something, therefore we do 303 1.1 cgd * not accept symbols whose value is zero (and use plain hex). 304 1.1 cgd */ 305 1.47 chs unsigned int db_maxoff = 0x100000; 306 1.1 cgd 307 1.30 jhawk void 308 1.40 itojun db_symstr(char *buf, size_t buflen, db_expr_t off, db_strategy_t strategy) 309 1.30 jhawk { 310 1.51 christos const char *name; 311 1.59 ad #ifdef _KERNEL 312 1.39 jdolecek const char *mod; 313 1.42 ragge unsigned long val; 314 1.59 ad #endif 315 1.38 ragge 316 1.60 mrg #ifndef _KERNEL 317 1.60 mrg if (!use_ksyms) { 318 1.38 ragge db_expr_t d; 319 1.38 ragge char *filename; 320 1.38 ragge db_expr_t value; 321 1.38 ragge int linenum; 322 1.38 ragge db_sym_t cursym; 323 1.38 ragge 324 1.62 christos cursym = db_search_symbol(off, strategy, &d); 325 1.62 christos db_symbol_values(cursym, &name, &value); 326 1.63 christos if (name != NULL && ((unsigned int)d < db_maxoff) && 327 1.62 christos value != 0) { 328 1.62 christos strlcpy(buf, name, buflen); 329 1.62 christos if (d) { 330 1.62 christos strlcat(buf, "+", buflen); 331 1.63 christos db_format_radix(buf + strlen(buf), 24, d, true); 332 1.62 christos } 333 1.62 christos if (strategy == DB_STGY_PROC) { 334 1.62 christos if ((*db_symformat->sym_line_at_pc) 335 1.63 christos (NULL, cursym, &filename, &linenum, off)) { 336 1.63 christos size_t len = strlen(buf); 337 1.63 christos snprintf(buf + len, buflen - len, 338 1.63 christos " [%s:%d]", filename, linenum); 339 1.63 christos } 340 1.38 ragge } 341 1.62 christos return; 342 1.38 ragge } 343 1.40 itojun strlcpy(buf, db_num_to_str(off), buflen); 344 1.38 ragge return; 345 1.38 ragge } 346 1.38 ragge #endif 347 1.59 ad #ifdef _KERNEL 348 1.71 riastrad const int s = pserialize_read_enter(); 349 1.41 scw if (ksyms_getname(&mod, &name, (vaddr_t)off, 350 1.41 scw strategy|KSYMS_CLOSEST) == 0) { 351 1.65 maxv (void)ksyms_getval_unlocked(mod, name, NULL, &val, KSYMS_ANY); 352 1.68 chs if (strategy & KSYMS_PROC && val == off) { 353 1.68 chs if (ksyms_getname(&mod, &name, (vaddr_t)off - 1, 354 1.68 chs strategy|KSYMS_CLOSEST) != 0) 355 1.71 riastrad goto hex_fallback; 356 1.68 chs (void)ksyms_getval_unlocked(mod, name, NULL, &val, KSYMS_ANY); 357 1.68 chs } 358 1.38 ragge if (((off - val) < db_maxoff) && val) { 359 1.46 itojun snprintf(buf, buflen, "%s:%s", mod, name); 360 1.38 ragge if (off - val) { 361 1.40 itojun strlcat(buf, "+", buflen); 362 1.38 ragge db_format_radix(buf+strlen(buf), 363 1.56 thorpej 24, off - val, true); 364 1.30 jhawk } 365 1.38 ragge #ifdef notyet 366 1.38 ragge if (strategy & KSYMS_PROC) { 367 1.46 itojun if (ksyms_fmaddr(off, &filename, &linenum) == 0) 368 1.46 itojun snprintf(buf + strlen(buf), 369 1.46 itojun buflen - strlen(buf), 370 1.30 jhawk " [%s:%d]", filename, linenum); 371 1.30 jhawk } 372 1.38 ragge #endif 373 1.71 riastrad goto out; 374 1.30 jhawk } 375 1.30 jhawk } 376 1.71 riastrad hex_fallback: 377 1.70 riastrad db_num_to_strbuf(off, buf, buflen); 378 1.71 riastrad out: pserialize_read_exit(s); 379 1.59 ad #endif 380 1.30 jhawk } 381 1.9 gwr 382 1.1 cgd void 383 1.31 simonb db_printsym(db_expr_t off, db_strategy_t strategy, 384 1.31 simonb void (*pr)(const char *, ...)) 385 1.1 cgd { 386 1.51 christos const char *name; 387 1.59 ad #ifdef _KERNEL 388 1.39 jdolecek const char *mod; 389 1.43 scw unsigned long uval; 390 1.43 scw long val; 391 1.59 ad #endif 392 1.35 ragge #ifdef notyet 393 1.35 ragge char *filename; 394 1.35 ragge int linenum; 395 1.35 ragge #endif 396 1.1 cgd 397 1.60 mrg #ifndef _KERNEL 398 1.60 mrg if (!use_ksyms) { 399 1.35 ragge db_expr_t d; 400 1.35 ragge char *filename; 401 1.35 ragge db_expr_t value; 402 1.35 ragge int linenum; 403 1.35 ragge db_sym_t cursym; 404 1.60 mrg 405 1.62 christos cursym = db_search_symbol(off, strategy, &d); 406 1.62 christos db_symbol_values(cursym, &name, &value); 407 1.63 christos if (name != NULL && ((unsigned int)d < db_maxoff) && 408 1.62 christos value != 0) { 409 1.62 christos (*pr)("%s", name); 410 1.62 christos if (d) { 411 1.62 christos char tbuf[24]; 412 1.62 christos 413 1.62 christos db_format_radix(tbuf, 24, d, true); 414 1.62 christos (*pr)("+%s", tbuf); 415 1.35 ragge } 416 1.62 christos if (strategy == DB_STGY_PROC) { 417 1.62 christos if ((*db_symformat->sym_line_at_pc) 418 1.63 christos (NULL, cursym, &filename, &linenum, off)) 419 1.63 christos (*pr)(" [%s:%d]", filename, linenum); 420 1.62 christos } 421 1.62 christos return; 422 1.35 ragge } 423 1.64 christos (*pr)("%s", db_num_to_str(off)); 424 1.35 ragge return; 425 1.35 ragge } 426 1.35 ragge #endif 427 1.59 ad #ifdef _KERNEL 428 1.41 scw if (ksyms_getname(&mod, &name, (vaddr_t)off, 429 1.41 scw strategy|KSYMS_CLOSEST) == 0) { 430 1.65 maxv (void)ksyms_getval_unlocked(mod, name, NULL, &uval, KSYMS_ANY); 431 1.68 chs if (strategy & KSYMS_PROC && uval == off) { 432 1.68 chs if (ksyms_getname(&mod, &name, (vaddr_t)off - 1, 433 1.68 chs strategy|KSYMS_CLOSEST) != 0) 434 1.68 chs goto out; 435 1.68 chs (void)ksyms_getval_unlocked(mod, name, NULL, &uval, KSYMS_ANY); 436 1.68 chs } 437 1.43 scw val = (long) uval; 438 1.35 ragge if (((off - val) < db_maxoff) && val) { 439 1.35 ragge (*pr)("%s:%s", mod, name); 440 1.35 ragge if (off - val) { 441 1.23 tv char tbuf[24]; 442 1.23 tv 443 1.56 thorpej db_format_radix(tbuf, 24, off - val, true); 444 1.24 tv (*pr)("+%s", tbuf); 445 1.23 tv } 446 1.35 ragge #ifdef notyet 447 1.35 ragge if (strategy & KSYMS_PROC) { 448 1.35 ragge if (ksyms_fmaddr(off, &filename, &linenum) == 0) 449 1.21 jhawk (*pr)(" [%s:%d]", filename, linenum); 450 1.9 gwr } 451 1.35 ragge #endif 452 1.9 gwr return; 453 1.9 gwr } 454 1.1 cgd } 455 1.69 kre out:; 456 1.59 ad #endif 457 1.64 christos (*pr)("%s", db_num_to_str(off)); 458 1.9 gwr return; 459 1.1 cgd } 460 1.1 cgd 461 1.35 ragge /* 462 1.35 ragge * Splits a string in the form "mod:sym" to two strings. 463 1.35 ragge */ 464 1.31 simonb static void 465 1.35 ragge db_symsplit(char *str, char **mod, char **sym) 466 1.15 thorpej { 467 1.35 ragge char *cp; 468 1.15 thorpej 469 1.35 ragge if ((cp = strchr(str, ':')) != NULL) { 470 1.35 ragge *cp++ = '\0'; 471 1.35 ragge *mod = str; 472 1.35 ragge *sym = cp; 473 1.35 ragge } else { 474 1.35 ragge *mod = NULL; 475 1.35 ragge *sym = str; 476 1.35 ragge } 477 1.1 cgd } 478 1.36 ragge 479 1.55 thorpej bool 480 1.36 ragge db_sym_numargs(db_sym_t cursym, int *nargp, char **argnamep) 481 1.36 ragge { 482 1.60 mrg #ifndef _KERNEL 483 1.60 mrg if (!use_ksyms) 484 1.36 ragge return ((*db_symformat->sym_numargs)(NULL, cursym, nargp, 485 1.36 ragge argnamep)); 486 1.36 ragge #endif 487 1.56 thorpej return (false); 488 1.49 perry } 489 1.36 ragge 490