db_sym.c revision 196019
14910Swollman/*- 24910Swollman * Mach Operating System 34910Swollman * Copyright (c) 1991,1990 Carnegie Mellon University 44910Swollman * All Rights Reserved. 530300Sjoerg * 625944Sjoerg * Permission to use, copy, modify and distribute this software and its 74910Swollman * documentation is hereby granted, provided that both the copyright 825944Sjoerg * notice and this permission notice appear in all copies of the 925944Sjoerg * software, derivative works or modified versions, and any portions 1025944Sjoerg * thereof, and that both notices appear in supporting documentation. 114910Swollman * 124910Swollman * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 134910Swollman * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 144910Swollman * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 154910Swollman * 164910Swollman * Carnegie Mellon requests users of this software to return to 174910Swollman * 1830300Sjoerg * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 1916288Sgpalmer * School of Computer Science 2050477Speter * Carnegie Mellon University 214910Swollman * Pittsburgh PA 15213-3890 224910Swollman * 2340008Sjoerg * any improvements or extensions that they make and grant Carnegie the 2440008Sjoerg * rights to redistribute these changes. 2542065Sphk */ 2632350Seivind/* 2754263Sshin * Author: David B. Golub, Carnegie Mellon University 2831742Seivind * Date: 7/90 2940008Sjoerg */ 3031742Seivind 3140008Sjoerg#include <sys/cdefs.h> 3240008Sjoerg__FBSDID("$FreeBSD: head/sys/ddb/db_sym.c 196019 2009-08-01 19:26:27Z rwatson $"); 3340008Sjoerg 3454263Sshin#include <sys/param.h> 3540008Sjoerg#include <sys/pcpu.h> 3640008Sjoerg#include <sys/smp.h> 3740008Sjoerg#include <sys/systm.h> 3840008Sjoerg 394952Sbde#include <net/vnet.h> 404952Sbde 4170199Sjhay#include <ddb/ddb.h> 4224204Sbde#include <ddb/db_sym.h> 434910Swollman#include <ddb/db_variables.h> 4425706Sjoerg 4542104Sphk#include <opt_ddb.h> 4659604Sobrien 4742104Sphk/* 4829024Sbde * Multiple symbol tables 494910Swollman */ 5040008Sjoerg#ifndef MAXNOSYMTABS 5140008Sjoerg#define MAXNOSYMTABS 3 /* mach, ux, emulator */ 5240008Sjoerg#endif 5340008Sjoerg 5430300Sjoergstatic db_symtab_t db_symtabs[MAXNOSYMTABS] = {{0,},}; 5540008Sjoergstatic int db_nsymtab = 0; 564910Swollman 574910Swollmanstatic db_symtab_t *db_last_symtab; /* where last symbol was found */ 584910Swollman 594910Swollmanstatic c_db_sym_t db_lookup( const char *symstr); 6042104Sphkstatic char *db_qualify(c_db_sym_t sym, char *symtabname); 614910Swollmanstatic boolean_t db_symbol_is_ambiguous(c_db_sym_t sym); 6240008Sjoergstatic boolean_t db_line_at_pc(c_db_sym_t, char **, int *, db_expr_t); 6340008Sjoerg 6440008Sjoergstatic int db_cpu = -1; 6542104Sphk 6630300Sjoerg#ifdef VIMAGE 6730300Sjoergextern uintptr_t *__start_set_vnet; 684910Swollmanextern uintptr_t *__stop_set_vnet; 694910Swollman 704910Swollman#define VNET_START (uintptr_t)&__start_set_vnet 714910Swollman#define VNET_STOP (uintptr_t)&__stop_set_vnet 724910Swollman 734910Swollmanstatic void *db_vnet = NULL; 7440008Sjoerg#endif 7540008Sjoerg 7640008Sjoerg/* 7740008Sjoerg * Validate the CPU number used to interpret per-CPU variables so we can 7840008Sjoerg * avoid later confusion if an invalid CPU is requested. 7932350Seivind */ 8040008Sjoergint 814910Swollmandb_var_db_cpu(struct db_variable *vp, db_expr_t *valuep, int op) 824910Swollman{ 8311819Sjulian 8411819Sjulian switch (op) { 8511819Sjulian case DB_VAR_GET: 8611819Sjulian *valuep = db_cpu; 8711819Sjulian return (1); 884910Swollman 894910Swollman case DB_VAR_SET: 904910Swollman if (*(int *)valuep < -1 && *(int *)valuep > mp_maxid) { 914910Swollman db_printf("Invalid value: %d", *(int*)valuep); 924910Swollman return (0); 934910Swollman } 944910Swollman db_cpu = *(int *)valuep; 9542065Sphk return (1); 9642064Sphk 9742064Sphk default: 9842104Sphk db_printf("db_var_db_cpu: unknown operation\n"); 9940008Sjoerg return (0); 10042064Sphk } 10142064Sphk} 10242104Sphk 10340008Sjoerg/* 10442104Sphk * Read-only variable reporting the current CPU, which is what we use when 1054910Swollman * db_cpu is set to -1. 1064910Swollman */ 10725944Sjoergint 10825944Sjoergdb_var_curcpu(struct db_variable *vp, db_expr_t *valuep, int op) 10925944Sjoerg{ 11025955Sjoerg 11125944Sjoerg switch (op) { 11225944Sjoerg case DB_VAR_GET: 11325944Sjoerg *valuep = curcpu; 11425955Sjoerg return (1); 11525955Sjoerg 11625955Sjoerg case DB_VAR_SET: 11730300Sjoerg db_printf("Read-only variable.\n"); 11830300Sjoerg return (0); 11930300Sjoerg 12030300Sjoerg default: 12130300Sjoerg db_printf("db_var_curcpu: unknown operation\n"); 12230300Sjoerg return (0); 12330300Sjoerg } 12430300Sjoerg} 12530300Sjoerg 12625944Sjoerg#ifdef VIMAGE 12725944Sjoerg/* 12825955Sjoerg * Validate the virtual network pointer used to interpret per-vnet global 12925955Sjoerg * variable expansion. Right now we don't do much here, really we should 13045152Sphk * walk the global vnet list to check it's an OK pointer. 13125944Sjoerg */ 13230300Sjoergint 13330300Sjoergdb_var_db_vnet(struct db_variable *vp, db_expr_t *valuep, int op) 13430300Sjoerg{ 13530300Sjoerg 13630300Sjoerg switch (op) { 13730300Sjoerg case DB_VAR_GET: 13878064Sume *valuep = (db_expr_t)db_vnet; 13930300Sjoerg return (1); 14030300Sjoerg 14130300Sjoerg case DB_VAR_SET: 14230300Sjoerg db_vnet = *(void **)valuep; 14378064Sume return (1); 1444910Swollman 14525944Sjoerg default: 14625944Sjoerg db_printf("db_var_db_vnet: unknown operation\n"); 14725944Sjoerg return (0); 14825944Sjoerg } 14925944Sjoerg} 15025944Sjoerg 15125944Sjoerg/* 15225944Sjoerg * Read-only variable reporting the current vnet, which is what we use when 15325944Sjoerg * db_vnet is set to NULL. 15425944Sjoerg */ 15525944Sjoergint 1564910Swollmandb_var_curvnet(struct db_variable *vp, db_expr_t *valuep, int op) 15730300Sjoerg{ 15830300Sjoerg 15930300Sjoerg switch (op) { 16030300Sjoerg case DB_VAR_GET: 16130300Sjoerg *valuep = (db_expr_t)curvnet; 16230300Sjoerg return (1); 16330300Sjoerg 16430300Sjoerg case DB_VAR_SET: 1654910Swollman db_printf("Read-only variable.\n"); 16625944Sjoerg return (0); 16725944Sjoerg 16825944Sjoerg default: 1694910Swollman db_printf("db_var_curcpu: unknown operation\n"); 17078064Sume return (0); 17178064Sume } 17278064Sume} 17330300Sjoerg#endif 17430300Sjoerg 17530300Sjoerg/* 1764910Swollman * Add symbol table, with given name, to list of symbol tables. 17730300Sjoerg */ 17830300Sjoergvoid 17930300Sjoergdb_add_symbol_table(start, end, name, ref) 18030300Sjoerg char *start; 18130300Sjoerg char *end; 18230300Sjoerg char *name; 18330300Sjoerg char *ref; 18430300Sjoerg{ 18530300Sjoerg if (db_nsymtab >= MAXNOSYMTABS) { 18630300Sjoerg printf ("No slots left for %s symbol table", name); 18730300Sjoerg panic ("db_sym.c: db_add_symbol_table"); 18830300Sjoerg } 18930300Sjoerg 19030300Sjoerg db_symtabs[db_nsymtab].start = start; 19125944Sjoerg db_symtabs[db_nsymtab].end = end; 19225944Sjoerg db_symtabs[db_nsymtab].name = name; 19325944Sjoerg db_symtabs[db_nsymtab].private = ref; 19425944Sjoerg db_nsymtab++; 19525944Sjoerg} 19625944Sjoerg 19725944Sjoerg/* 19825944Sjoerg * db_qualify("vm_map", "ux") returns "unix:vm_map". 19925944Sjoerg * 20025944Sjoerg * Note: return value points to static data whose content is 20125944Sjoerg * overwritten by each call... but in practice this seems okay. 20225944Sjoerg */ 2034910Swollmanstatic char * 20411189Sjkhdb_qualify(sym, symtabname) 20511189Sjkh c_db_sym_t sym; 20611189Sjkh register char *symtabname; 2074910Swollman{ 2084910Swollman const char *symname; 2094910Swollman static char tmp[256]; 2104910Swollman 21111189Sjkh db_symbol_values(sym, &symname, 0); 21211189Sjkh snprintf(tmp, sizeof(tmp), "%s:%s", symtabname, symname); 21311189Sjkh return tmp; 2144910Swollman} 2154910Swollman 2164910Swollman 2174910Swollmanboolean_t 21811189Sjkhdb_eqname(src, dst, c) 21911189Sjkh const char *src; 22011189Sjkh const char *dst; 22111189Sjkh int c; 22211189Sjkh{ 22311189Sjkh if (!strcmp(src, dst)) 2244910Swollman return (TRUE); 2254910Swollman if (src[0] == c) 2264910Swollman return (!strcmp(src+1,dst)); 22725944Sjoerg return (FALSE); 22825944Sjoerg} 22925944Sjoerg 23025944Sjoergboolean_t 23125944Sjoergdb_value_of_name(name, valuep) 23225944Sjoerg const char *name; 23325944Sjoerg db_expr_t *valuep; 23425944Sjoerg{ 23525944Sjoerg c_db_sym_t sym; 23625944Sjoerg 23725944Sjoerg sym = db_lookup(name); 23825944Sjoerg if (sym == C_DB_SYM_NULL) 23925944Sjoerg return (FALSE); 24025944Sjoerg db_symbol_values(sym, &name, valuep); 24125944Sjoerg return (TRUE); 24225944Sjoerg} 24325944Sjoerg 24425944Sjoergboolean_t 24525944Sjoergdb_value_of_name_pcpu(name, valuep) 24625944Sjoerg const char *name; 24725944Sjoerg db_expr_t *valuep; 24825944Sjoerg{ 24925944Sjoerg static char tmp[256]; 25025944Sjoerg db_expr_t value; 25125944Sjoerg c_db_sym_t sym; 25225944Sjoerg int cpu; 25325944Sjoerg 25425944Sjoerg if (db_cpu != -1) 25525944Sjoerg cpu = db_cpu; 25625944Sjoerg else 25725944Sjoerg cpu = curcpu; 25825944Sjoerg snprintf(tmp, sizeof(tmp), "pcpu_entry_%s", name); 25912820Sphk sym = db_lookup(tmp); 26042065Sphk if (sym == C_DB_SYM_NULL) 26130300Sjoerg return (FALSE); 26240008Sjoerg db_symbol_values(sym, &name, &value); 2634910Swollman if (value < DPCPU_START || value >= DPCPU_STOP) 26442065Sphk return (FALSE); 26540008Sjoerg *valuep = (db_expr_t)((uintptr_t)value + dpcpu_off[cpu]); 26640008Sjoerg return (TRUE); 26740008Sjoerg} 26840008Sjoerg 26940008Sjoergboolean_t 27040008Sjoergdb_value_of_name_vnet(name, valuep) 27140008Sjoerg const char *name; 2724910Swollman db_expr_t *valuep; 2734910Swollman{ 2744910Swollman#ifdef VIMAGE 2754910Swollman static char tmp[256]; 2764910Swollman db_expr_t value; 27730300Sjoerg c_db_sym_t sym; 27830300Sjoerg struct vnet *vnet; 2794910Swollman 28011189Sjkh if (db_vnet != NULL) 2814910Swollman vnet = db_vnet; 2824910Swollman else 2834910Swollman vnet = curvnet; 2844910Swollman snprintf(tmp, sizeof(tmp), "vnet_entry_%s", name); 2854910Swollman sym = db_lookup(tmp); 28625944Sjoerg if (sym == C_DB_SYM_NULL) 28725944Sjoerg return (FALSE); 28825944Sjoerg db_symbol_values(sym, &name, &value); 28925944Sjoerg if (value < VNET_START || value >= VNET_STOP) 29011189Sjkh return (FALSE); 29130300Sjoerg *valuep = (db_expr_t)((uintptr_t)value + vnet->vnet_data_base); 29225944Sjoerg return (TRUE); 2934910Swollman#else 29425944Sjoerg return (FALSE); 29525944Sjoerg#endif 29625944Sjoerg} 29725944Sjoerg 29825944Sjoerg/* 29925944Sjoerg * Lookup a symbol. 30025944Sjoerg * If the symbol has a qualifier (e.g., ux:vm_map), 30142104Sphk * then only the specified symbol table will be searched; 30225944Sjoerg * otherwise, all symbol tables will be searched. 30325944Sjoerg */ 30430300Sjoergstatic c_db_sym_t 30542104Sphkdb_lookup(symstr) 30630300Sjoerg const char *symstr; 30725944Sjoerg{ 30825944Sjoerg c_db_sym_t sp; 30925944Sjoerg register int i; 31025944Sjoerg int symtab_start = 0; 31125944Sjoerg int symtab_end = db_nsymtab; 31225944Sjoerg register const char *cp; 31325944Sjoerg 31430300Sjoerg /* 31530300Sjoerg * Look for, remove, and remember any symbol table specifier. 31625944Sjoerg */ 31725944Sjoerg for (cp = symstr; *cp; cp++) { 31825944Sjoerg if (*cp == ':') { 31925944Sjoerg for (i = 0; i < db_nsymtab; i++) { 32025944Sjoerg int n = strlen(db_symtabs[i].name); 32125944Sjoerg 32225944Sjoerg if ( 32325944Sjoerg n == (cp - symstr) && 32425944Sjoerg strncmp(symstr, db_symtabs[i].name, n) == 0 32525944Sjoerg ) { 32625944Sjoerg symtab_start = i; 32725944Sjoerg symtab_end = i + 1; 32825944Sjoerg break; 32925944Sjoerg } 33030300Sjoerg } 33130300Sjoerg if (i == db_nsymtab) { 33225944Sjoerg db_error("invalid symbol table name"); 33325944Sjoerg } 33425944Sjoerg symstr = cp+1; 33525944Sjoerg } 33625944Sjoerg } 33725944Sjoerg 33825944Sjoerg /* 33925944Sjoerg * Look in the specified set of symbol tables. 34025944Sjoerg * Return on first match. 34125944Sjoerg */ 34225944Sjoerg for (i = symtab_start; i < symtab_end; i++) { 34325944Sjoerg sp = X_db_lookup(&db_symtabs[i], symstr); 34425944Sjoerg if (sp) { 34525944Sjoerg db_last_symtab = &db_symtabs[i]; 34625944Sjoerg return sp; 34725944Sjoerg } 34878064Sume } 34978064Sume return 0; 35078064Sume} 35178064Sume 35278064Sume/* 35378064Sume * If TRUE, check across symbol tables for multiple occurrences 35478064Sume * of a name. Might slow things down quite a bit. 35578064Sume */ 35678064Sumestatic volatile boolean_t db_qualify_ambiguous_names = FALSE; 35778064Sume 35878064Sume/* 35978064Sume * Does this symbol name appear in more than one symbol table? 36078064Sume * Used by db_symbol_values to decide whether to qualify a symbol. 36178064Sume */ 36278064Sumestatic boolean_t 36330300Sjoergdb_symbol_is_ambiguous(sym) 36430300Sjoerg c_db_sym_t sym; 36530300Sjoerg{ 36630300Sjoerg const char *sym_name; 36730300Sjoerg register int i; 36830300Sjoerg register 36930300Sjoerg boolean_t found_once = FALSE; 37030300Sjoerg 37130300Sjoerg if (!db_qualify_ambiguous_names) 37230300Sjoerg return FALSE; 37330300Sjoerg 37430300Sjoerg db_symbol_values(sym, &sym_name, 0); 37530300Sjoerg for (i = 0; i < db_nsymtab; i++) { 37630300Sjoerg if (X_db_lookup(&db_symtabs[i], sym_name)) { 37730300Sjoerg if (found_once) 37830300Sjoerg return TRUE; 37930300Sjoerg found_once = TRUE; 38030300Sjoerg } 38130300Sjoerg } 38230300Sjoerg return FALSE; 38325944Sjoerg} 38430300Sjoerg 38530300Sjoerg/* 38678064Sume * Find the closest symbol to val, and return its name 38778064Sume * and the difference between val and the symbol found. 38878064Sume */ 38925944Sjoergc_db_sym_t 39025944Sjoergdb_search_symbol( val, strategy, offp) 39125944Sjoerg register db_addr_t val; 39230300Sjoerg db_strategy_t strategy; 39338343Sbde db_expr_t *offp; 39430300Sjoerg{ 39530300Sjoerg register 39630300Sjoerg unsigned int diff; 39725944Sjoerg size_t newdiff; 39830300Sjoerg register int i; 39930300Sjoerg c_db_sym_t ret = C_DB_SYM_NULL, sym; 40030300Sjoerg 40125944Sjoerg newdiff = diff = ~0; 40225944Sjoerg for (i = 0; i < db_nsymtab; i++) { 40378064Sume sym = X_db_search_symbol(&db_symtabs[i], val, strategy, &newdiff); 40478064Sume if (newdiff < diff) { 40578064Sume db_last_symtab = &db_symtabs[i]; 40678064Sume diff = newdiff; 40778064Sume ret = sym; 40878064Sume } 40978064Sume } 41078064Sume *offp = diff; 41178064Sume return ret; 41225944Sjoerg} 41325944Sjoerg 41433181Seivind/* 41525944Sjoerg * Return name and value of a symbol 41625944Sjoerg */ 41725944Sjoergvoid 41825944Sjoergdb_symbol_values(sym, namep, valuep) 41925944Sjoerg c_db_sym_t sym; 42025944Sjoerg const char **namep; 42125944Sjoerg db_expr_t *valuep; 42233181Seivind{ 42325944Sjoerg db_expr_t value; 42425944Sjoerg 42525944Sjoerg if (sym == DB_SYM_NULL) { 42625944Sjoerg *namep = 0; 42725944Sjoerg return; 42825944Sjoerg } 42925944Sjoerg 43078064Sume X_db_symbol_values(db_last_symtab, sym, namep, &value); 43178064Sume 43278064Sume if (db_symbol_is_ambiguous(sym)) 43378064Sume *namep = db_qualify(sym, db_last_symtab->name); 43478064Sume if (valuep) 43578064Sume *valuep = value; 43678064Sume} 43778064Sume 43878064Sume 43978064Sume/* 44078064Sume * Print a the closest symbol to value 44178064Sume * 44278064Sume * After matching the symbol according to the given strategy 44378064Sume * we print it in the name+offset format, provided the symbol's 44433181Seivind * value is close enough (eg smaller than db_maxoff). 44530300Sjoerg * We also attempt to print [filename:linenum] when applicable 44630300Sjoerg * (eg for procedure names). 44730300Sjoerg * 44830300Sjoerg * If we could not find a reasonable name+offset representation, 44930300Sjoerg * then we just print the value in hex. Small values might get 45030300Sjoerg * bogus symbol associations, e.g. 3 might get some absolute 45130300Sjoerg * value like _INCLUDE_VERSION or something, therefore we do 45233181Seivind * not accept symbols whose value is "small" (and use plain hex). 45330300Sjoerg */ 45430300Sjoerg 45530300Sjoergdb_expr_t db_maxoff = 0x10000; 45630300Sjoerg 45730300Sjoergvoid 45830300Sjoergdb_printsym(off, strategy) 45930300Sjoerg db_expr_t off; 46033181Seivind db_strategy_t strategy; 46125944Sjoerg{ 46225944Sjoerg db_expr_t d; 46378064Sume char *filename; 46430300Sjoerg const char *name; 46530300Sjoerg db_expr_t value; 46625944Sjoerg int linenum; 46725944Sjoerg c_db_sym_t cursym; 46870199Sjhay 46970199Sjhay cursym = db_search_symbol(off, strategy, &d); 47070199Sjhay db_symbol_values(cursym, &name, &value); 47170199Sjhay if (name == 0) 47270199Sjhay value = off; 47370199Sjhay if (value >= DB_SMALL_VALUE_MIN && value <= DB_SMALL_VALUE_MAX) { 47470199Sjhay db_printf("%+#lr", (long)off); 47570199Sjhay return; 47670199Sjhay } 47770199Sjhay if (name == 0 || d >= (unsigned long)db_maxoff) { 47870199Sjhay db_printf("%#lr", (unsigned long)off); 47970199Sjhay return; 48070199Sjhay } 48170199Sjhay#ifdef DDB_NUMSYM 48270199Sjhay db_printf("%#lr = %s", (unsigned long)off, name); 48370199Sjhay#else 48470199Sjhay db_printf("%s", name); 48570199Sjhay#endif 48670199Sjhay if (d) 48770199Sjhay db_printf("+%+#lr", (long)d); 48870199Sjhay if (strategy == DB_STGY_PROC) { 48925944Sjoerg if (db_line_at_pc(cursym, &filename, &linenum, off)) 49070199Sjhay db_printf(" [%s:%d]", filename, linenum); 49125944Sjoerg } 4924910Swollman} 4934910Swollman 4944910Swollmanstatic boolean_t 4954910Swollmandb_line_at_pc( sym, filename, linenum, pc) 4964910Swollman c_db_sym_t sym; 49725706Sjoerg char **filename; 49825706Sjoerg int *linenum; 4994910Swollman db_expr_t pc; 5004910Swollman{ 5014910Swollman return X_db_line_at_pc( db_last_symtab, sym, filename, linenum, pc); 50225944Sjoerg} 50325944Sjoerg 5044910Swollmanint 5054910Swollmandb_sym_numargs(sym, nargp, argnames) 5064910Swollman c_db_sym_t sym; 5074910Swollman int *nargp; 5084910Swollman char **argnames; 5094910Swollman{ 5104910Swollman return X_db_sym_numargs(db_last_symtab, sym, nargp, argnames); 51125944Sjoerg} 51225706Sjoerg