1139747Simp/*- 24Srgrimes * Mach Operating System 34Srgrimes * Copyright (c) 1991,1990 Carnegie Mellon University 44Srgrimes * All Rights Reserved. 58876Srgrimes * 64Srgrimes * Permission to use, copy, modify and distribute this software and its 74Srgrimes * documentation is hereby granted, provided that both the copyright 84Srgrimes * notice and this permission notice appear in all copies of the 94Srgrimes * software, derivative works or modified versions, and any portions 104Srgrimes * thereof, and that both notices appear in supporting documentation. 118876Srgrimes * 128876Srgrimes * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 134Srgrimes * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 144Srgrimes * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 158876Srgrimes * 164Srgrimes * Carnegie Mellon requests users of this software to return to 178876Srgrimes * 184Srgrimes * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 194Srgrimes * School of Computer Science 204Srgrimes * Carnegie Mellon University 214Srgrimes * Pittsburgh PA 15213-3890 228876Srgrimes * 234Srgrimes * any improvements or extensions that they make and grant Carnegie the 244Srgrimes * rights to redistribute these changes. 254Srgrimes */ 264Srgrimes/* 274Srgrimes * Author: David B. Golub, Carnegie Mellon University 284Srgrimes * Date: 7/90 294Srgrimes */ 30116176Sobrien 31116176Sobrien#include <sys/cdefs.h> 32116176Sobrien__FBSDID("$FreeBSD: stable/10/sys/ddb/db_sym.c 328000 2018-01-15 12:15:04Z avg $"); 33116176Sobrien 342056Swollman#include <sys/param.h> 35196019Srwatson#include <sys/pcpu.h> 36195699Srwatson#include <sys/smp.h> 372056Swollman#include <sys/systm.h> 3812734Sbde 39195699Srwatson#include <net/vnet.h> 40195699Srwatson 412056Swollman#include <ddb/ddb.h> 424Srgrimes#include <ddb/db_sym.h> 43195699Srwatson#include <ddb/db_variables.h> 444Srgrimes 45126204Sphk#include <opt_ddb.h> 46126204Sphk 474Srgrimes/* 484Srgrimes * Multiple symbol tables 494Srgrimes */ 50923Sdg#ifndef MAXNOSYMTABS 514Srgrimes#define MAXNOSYMTABS 3 /* mach, ux, emulator */ 52923Sdg#endif 534Srgrimes 5412515Sphkstatic db_symtab_t db_symtabs[MAXNOSYMTABS] = {{0,},}; 5512515Sphkstatic int db_nsymtab = 0; 564Srgrimes 5727122Sbdestatic db_symtab_t *db_last_symtab; /* where last symbol was found */ 584Srgrimes 5992756Salfredstatic c_db_sym_t db_lookup( const char *symstr); 6092756Salfredstatic char *db_qualify(c_db_sym_t sym, char *symtabname); 6192756Salfredstatic boolean_t db_symbol_is_ambiguous(c_db_sym_t sym); 6292756Salfredstatic boolean_t db_line_at_pc(c_db_sym_t, char **, int *, db_expr_t); 634Srgrimes 64195699Srwatsonstatic int db_cpu = -1; 65195699Srwatson 66195699Srwatson#ifdef VIMAGE 67195699Srwatsonstatic void *db_vnet = NULL; 68195699Srwatson#endif 69195699Srwatson 704Srgrimes/* 71195699Srwatson * Validate the CPU number used to interpret per-CPU variables so we can 72195699Srwatson * avoid later confusion if an invalid CPU is requested. 73195699Srwatson */ 74195699Srwatsonint 75195699Srwatsondb_var_db_cpu(struct db_variable *vp, db_expr_t *valuep, int op) 76195699Srwatson{ 77195699Srwatson 78195699Srwatson switch (op) { 79195699Srwatson case DB_VAR_GET: 80195699Srwatson *valuep = db_cpu; 81195699Srwatson return (1); 82195699Srwatson 83195699Srwatson case DB_VAR_SET: 84328000Savg if (*(int *)valuep < -1 || *(int *)valuep > mp_maxid) { 85328000Savg db_printf("Invalid value: %d\n", *(int*)valuep); 86195699Srwatson return (0); 87195699Srwatson } 88195699Srwatson db_cpu = *(int *)valuep; 89195699Srwatson return (1); 90195699Srwatson 91195699Srwatson default: 92195699Srwatson db_printf("db_var_db_cpu: unknown operation\n"); 93195699Srwatson return (0); 94195699Srwatson } 95195699Srwatson} 96195699Srwatson 97195699Srwatson/* 98195699Srwatson * Read-only variable reporting the current CPU, which is what we use when 99195699Srwatson * db_cpu is set to -1. 100195699Srwatson */ 101195699Srwatsonint 102195699Srwatsondb_var_curcpu(struct db_variable *vp, db_expr_t *valuep, int op) 103195699Srwatson{ 104195699Srwatson 105195699Srwatson switch (op) { 106195699Srwatson case DB_VAR_GET: 107195699Srwatson *valuep = curcpu; 108195699Srwatson return (1); 109195699Srwatson 110195699Srwatson case DB_VAR_SET: 111195699Srwatson db_printf("Read-only variable.\n"); 112195699Srwatson return (0); 113195699Srwatson 114195699Srwatson default: 115195699Srwatson db_printf("db_var_curcpu: unknown operation\n"); 116195699Srwatson return (0); 117195699Srwatson } 118195699Srwatson} 119195699Srwatson 120195699Srwatson#ifdef VIMAGE 121195699Srwatson/* 122195699Srwatson * Validate the virtual network pointer used to interpret per-vnet global 123195699Srwatson * variable expansion. Right now we don't do much here, really we should 124195699Srwatson * walk the global vnet list to check it's an OK pointer. 125195699Srwatson */ 126195699Srwatsonint 127195699Srwatsondb_var_db_vnet(struct db_variable *vp, db_expr_t *valuep, int op) 128195699Srwatson{ 129195699Srwatson 130195699Srwatson switch (op) { 131195699Srwatson case DB_VAR_GET: 132195699Srwatson *valuep = (db_expr_t)db_vnet; 133195699Srwatson return (1); 134195699Srwatson 135195699Srwatson case DB_VAR_SET: 136195699Srwatson db_vnet = *(void **)valuep; 137195699Srwatson return (1); 138195699Srwatson 139195699Srwatson default: 140195699Srwatson db_printf("db_var_db_vnet: unknown operation\n"); 141195699Srwatson return (0); 142195699Srwatson } 143195699Srwatson} 144195699Srwatson 145195699Srwatson/* 146195699Srwatson * Read-only variable reporting the current vnet, which is what we use when 147195699Srwatson * db_vnet is set to NULL. 148195699Srwatson */ 149195699Srwatsonint 150195699Srwatsondb_var_curvnet(struct db_variable *vp, db_expr_t *valuep, int op) 151195699Srwatson{ 152195699Srwatson 153195699Srwatson switch (op) { 154195699Srwatson case DB_VAR_GET: 155195699Srwatson *valuep = (db_expr_t)curvnet; 156195699Srwatson return (1); 157195699Srwatson 158195699Srwatson case DB_VAR_SET: 159195699Srwatson db_printf("Read-only variable.\n"); 160195699Srwatson return (0); 161195699Srwatson 162195699Srwatson default: 163195699Srwatson db_printf("db_var_curcpu: unknown operation\n"); 164195699Srwatson return (0); 165195699Srwatson } 166195699Srwatson} 167195699Srwatson#endif 168195699Srwatson 169195699Srwatson/* 1704Srgrimes * Add symbol table, with given name, to list of symbol tables. 1714Srgrimes */ 1724Srgrimesvoid 173273265Spfgdb_add_symbol_table(char *start, char *end, char *name, char *ref) 1744Srgrimes{ 1754Srgrimes if (db_nsymtab >= MAXNOSYMTABS) { 1764Srgrimes printf ("No slots left for %s symbol table", name); 1774Srgrimes panic ("db_sym.c: db_add_symbol_table"); 1784Srgrimes } 1794Srgrimes 1804Srgrimes db_symtabs[db_nsymtab].start = start; 1814Srgrimes db_symtabs[db_nsymtab].end = end; 1824Srgrimes db_symtabs[db_nsymtab].name = name; 1834Srgrimes db_symtabs[db_nsymtab].private = ref; 1844Srgrimes db_nsymtab++; 1854Srgrimes} 1864Srgrimes 1874Srgrimes/* 1884Srgrimes * db_qualify("vm_map", "ux") returns "unix:vm_map". 1894Srgrimes * 1904Srgrimes * Note: return value points to static data whose content is 1914Srgrimes * overwritten by each call... but in practice this seems okay. 1924Srgrimes */ 1934Srgrimesstatic char * 194273265Spfgdb_qualify(c_db_sym_t sym, char *symtabname) 1954Srgrimes{ 19643289Sdillon const char *symname; 1974Srgrimes static char tmp[256]; 1984Srgrimes 1994Srgrimes db_symbol_values(sym, &symname, 0); 20041514Sarchie snprintf(tmp, sizeof(tmp), "%s:%s", symtabname, symname); 2014Srgrimes return tmp; 2024Srgrimes} 2034Srgrimes 2044Srgrimes 2054Srgrimesboolean_t 206273265Spfgdb_eqname(const char *src, const char *dst, int c) 2074Srgrimes{ 2084Srgrimes if (!strcmp(src, dst)) 2094Srgrimes return (TRUE); 2104Srgrimes if (src[0] == c) 2114Srgrimes return (!strcmp(src+1,dst)); 2124Srgrimes return (FALSE); 2134Srgrimes} 2144Srgrimes 2154Srgrimesboolean_t 216273265Spfgdb_value_of_name(const char *name, db_expr_t *valuep) 2174Srgrimes{ 21843309Sdillon c_db_sym_t sym; 2194Srgrimes 2204Srgrimes sym = db_lookup(name); 22143309Sdillon if (sym == C_DB_SYM_NULL) 2224Srgrimes return (FALSE); 2234Srgrimes db_symbol_values(sym, &name, valuep); 2244Srgrimes return (TRUE); 2254Srgrimes} 2264Srgrimes 227195699Srwatsonboolean_t 228273265Spfgdb_value_of_name_pcpu(const char *name, db_expr_t *valuep) 229195699Srwatson{ 230195699Srwatson static char tmp[256]; 231195699Srwatson db_expr_t value; 232195699Srwatson c_db_sym_t sym; 233195699Srwatson int cpu; 2344Srgrimes 235195699Srwatson if (db_cpu != -1) 236195699Srwatson cpu = db_cpu; 237195699Srwatson else 238195699Srwatson cpu = curcpu; 239195699Srwatson snprintf(tmp, sizeof(tmp), "pcpu_entry_%s", name); 240195699Srwatson sym = db_lookup(tmp); 241195699Srwatson if (sym == C_DB_SYM_NULL) 242195699Srwatson return (FALSE); 243195699Srwatson db_symbol_values(sym, &name, &value); 244195699Srwatson if (value < DPCPU_START || value >= DPCPU_STOP) 245195699Srwatson return (FALSE); 246195699Srwatson *valuep = (db_expr_t)((uintptr_t)value + dpcpu_off[cpu]); 247195699Srwatson return (TRUE); 248195699Srwatson} 249195699Srwatson 250195699Srwatsonboolean_t 251273265Spfgdb_value_of_name_vnet(const char *name, db_expr_t *valuep) 252195699Srwatson{ 253195699Srwatson#ifdef VIMAGE 254195699Srwatson static char tmp[256]; 255195699Srwatson db_expr_t value; 256195699Srwatson c_db_sym_t sym; 257195699Srwatson struct vnet *vnet; 258195699Srwatson 259195699Srwatson if (db_vnet != NULL) 260195699Srwatson vnet = db_vnet; 261195699Srwatson else 262195699Srwatson vnet = curvnet; 263195699Srwatson snprintf(tmp, sizeof(tmp), "vnet_entry_%s", name); 264195699Srwatson sym = db_lookup(tmp); 265195699Srwatson if (sym == C_DB_SYM_NULL) 266195699Srwatson return (FALSE); 267195699Srwatson db_symbol_values(sym, &name, &value); 268195699Srwatson if (value < VNET_START || value >= VNET_STOP) 269195699Srwatson return (FALSE); 270195699Srwatson *valuep = (db_expr_t)((uintptr_t)value + vnet->vnet_data_base); 271195699Srwatson return (TRUE); 272195699Srwatson#else 273195699Srwatson return (FALSE); 274195699Srwatson#endif 275195699Srwatson} 276195699Srwatson 2774Srgrimes/* 2784Srgrimes * Lookup a symbol. 2794Srgrimes * If the symbol has a qualifier (e.g., ux:vm_map), 2804Srgrimes * then only the specified symbol table will be searched; 2814Srgrimes * otherwise, all symbol tables will be searched. 2824Srgrimes */ 28343309Sdillonstatic c_db_sym_t 284273265Spfgdb_lookup(const char *symstr) 2854Srgrimes{ 28643309Sdillon c_db_sym_t sp; 2874Srgrimes register int i; 2884Srgrimes int symtab_start = 0; 2894Srgrimes int symtab_end = db_nsymtab; 29043289Sdillon register const char *cp; 2914Srgrimes 2924Srgrimes /* 2934Srgrimes * Look for, remove, and remember any symbol table specifier. 2944Srgrimes */ 2954Srgrimes for (cp = symstr; *cp; cp++) { 2964Srgrimes if (*cp == ':') { 2974Srgrimes for (i = 0; i < db_nsymtab; i++) { 29843289Sdillon int n = strlen(db_symtabs[i].name); 29943289Sdillon 30043289Sdillon if ( 30143289Sdillon n == (cp - symstr) && 30243289Sdillon strncmp(symstr, db_symtabs[i].name, n) == 0 30343289Sdillon ) { 3044Srgrimes symtab_start = i; 3054Srgrimes symtab_end = i + 1; 3064Srgrimes break; 3074Srgrimes } 3084Srgrimes } 3094Srgrimes if (i == db_nsymtab) { 3104Srgrimes db_error("invalid symbol table name"); 3114Srgrimes } 3124Srgrimes symstr = cp+1; 3134Srgrimes } 3144Srgrimes } 3154Srgrimes 3164Srgrimes /* 3174Srgrimes * Look in the specified set of symbol tables. 3184Srgrimes * Return on first match. 3194Srgrimes */ 3204Srgrimes for (i = symtab_start; i < symtab_end; i++) { 3213140Sphk sp = X_db_lookup(&db_symtabs[i], symstr); 3223140Sphk if (sp) { 3234Srgrimes db_last_symtab = &db_symtabs[i]; 3244Srgrimes return sp; 3254Srgrimes } 3264Srgrimes } 3274Srgrimes return 0; 3284Srgrimes} 3294Srgrimes 3304Srgrimes/* 33127122Sbde * If TRUE, check across symbol tables for multiple occurrences 33227122Sbde * of a name. Might slow things down quite a bit. 33327122Sbde */ 33427122Sbdestatic volatile boolean_t db_qualify_ambiguous_names = FALSE; 33527122Sbde 33627122Sbde/* 3374Srgrimes * Does this symbol name appear in more than one symbol table? 3384Srgrimes * Used by db_symbol_values to decide whether to qualify a symbol. 3394Srgrimes */ 34012515Sphkstatic boolean_t 341273265Spfgdb_symbol_is_ambiguous(c_db_sym_t sym) 3424Srgrimes{ 34343289Sdillon const char *sym_name; 3444Srgrimes register int i; 3454Srgrimes register 3464Srgrimes boolean_t found_once = FALSE; 3474Srgrimes 3484Srgrimes if (!db_qualify_ambiguous_names) 3494Srgrimes return FALSE; 3504Srgrimes 3514Srgrimes db_symbol_values(sym, &sym_name, 0); 3524Srgrimes for (i = 0; i < db_nsymtab; i++) { 3534Srgrimes if (X_db_lookup(&db_symtabs[i], sym_name)) { 3544Srgrimes if (found_once) 3554Srgrimes return TRUE; 3564Srgrimes found_once = TRUE; 3574Srgrimes } 3584Srgrimes } 3594Srgrimes return FALSE; 3604Srgrimes} 3614Srgrimes 3624Srgrimes/* 3634Srgrimes * Find the closest symbol to val, and return its name 3644Srgrimes * and the difference between val and the symbol found. 3654Srgrimes */ 36643309Sdillonc_db_sym_t 367273265Spfgdb_search_symbol(db_addr_t val, db_strategy_t strategy, db_expr_t *offp) 3684Srgrimes{ 3694Srgrimes register 3704Srgrimes unsigned int diff; 37136735Sdfr size_t newdiff; 3724Srgrimes register int i; 37343309Sdillon c_db_sym_t ret = C_DB_SYM_NULL, sym; 3744Srgrimes 3754Srgrimes newdiff = diff = ~0; 3764Srgrimes for (i = 0; i < db_nsymtab; i++) { 3774Srgrimes sym = X_db_search_symbol(&db_symtabs[i], val, strategy, &newdiff); 3784Srgrimes if (newdiff < diff) { 3794Srgrimes db_last_symtab = &db_symtabs[i]; 3804Srgrimes diff = newdiff; 3814Srgrimes ret = sym; 3824Srgrimes } 3834Srgrimes } 3844Srgrimes *offp = diff; 3854Srgrimes return ret; 3864Srgrimes} 3874Srgrimes 3884Srgrimes/* 3894Srgrimes * Return name and value of a symbol 3904Srgrimes */ 3914Srgrimesvoid 392273265Spfgdb_symbol_values(c_db_sym_t sym, const char **namep, db_expr_t *valuep) 3934Srgrimes{ 3944Srgrimes db_expr_t value; 3954Srgrimes 3964Srgrimes if (sym == DB_SYM_NULL) { 3974Srgrimes *namep = 0; 3984Srgrimes return; 3994Srgrimes } 4004Srgrimes 40137218Sdfr X_db_symbol_values(db_last_symtab, sym, namep, &value); 4024Srgrimes 4034Srgrimes if (db_symbol_is_ambiguous(sym)) 4044Srgrimes *namep = db_qualify(sym, db_last_symtab->name); 4054Srgrimes if (valuep) 4064Srgrimes *valuep = value; 4074Srgrimes} 4084Srgrimes 4094Srgrimes 4104Srgrimes/* 4114Srgrimes * Print a the closest symbol to value 4124Srgrimes * 4134Srgrimes * After matching the symbol according to the given strategy 4144Srgrimes * we print it in the name+offset format, provided the symbol's 4154Srgrimes * value is close enough (eg smaller than db_maxoff). 4164Srgrimes * We also attempt to print [filename:linenum] when applicable 4174Srgrimes * (eg for procedure names). 4184Srgrimes * 4194Srgrimes * If we could not find a reasonable name+offset representation, 4204Srgrimes * then we just print the value in hex. Small values might get 4214Srgrimes * bogus symbol associations, e.g. 3 might get some absolute 4224Srgrimes * value like _INCLUDE_VERSION or something, therefore we do 42321767Sbde * not accept symbols whose value is "small" (and use plain hex). 4244Srgrimes */ 4254Srgrimes 42637504Sbdedb_expr_t db_maxoff = 0x10000; 4274Srgrimes 4284Srgrimesvoid 429273265Spfgdb_printsym(db_expr_t off, db_strategy_t strategy) 4304Srgrimes{ 4314Srgrimes db_expr_t d; 4324Srgrimes char *filename; 43343289Sdillon const char *name; 4344Srgrimes db_expr_t value; 4354Srgrimes int linenum; 43643309Sdillon c_db_sym_t cursym; 4374Srgrimes 4384Srgrimes cursym = db_search_symbol(off, strategy, &d); 4394Srgrimes db_symbol_values(cursym, &name, &value); 44021767Sbde if (name == 0) 44121767Sbde value = off; 44221767Sbde if (value >= DB_SMALL_VALUE_MIN && value <= DB_SMALL_VALUE_MAX) { 44337506Sbde db_printf("%+#lr", (long)off); 44421767Sbde return; 44521767Sbde } 44637504Sbde if (name == 0 || d >= (unsigned long)db_maxoff) { 44737506Sbde db_printf("%#lr", (unsigned long)off); 4484Srgrimes return; 4494Srgrimes } 450126204Sphk#ifdef DDB_NUMSYM 451126204Sphk db_printf("%#lr = %s", (unsigned long)off, name); 452126204Sphk#else 4534Srgrimes db_printf("%s", name); 454126204Sphk#endif 4554Srgrimes if (d) 45648407Speter db_printf("+%+#lr", (long)d); 4574Srgrimes if (strategy == DB_STGY_PROC) { 4584Srgrimes if (db_line_at_pc(cursym, &filename, &linenum, off)) 4594Srgrimes db_printf(" [%s:%d]", filename, linenum); 4604Srgrimes } 4614Srgrimes} 4624Srgrimes 46312515Sphkstatic boolean_t 464273265Spfgdb_line_at_pc(c_db_sym_t sym, char **filename, int *linenum, db_expr_t pc) 4654Srgrimes{ 4664Srgrimes return X_db_line_at_pc( db_last_symtab, sym, filename, linenum, pc); 4674Srgrimes} 468923Sdg 469923Sdgint 470273265Spfgdb_sym_numargs(c_db_sym_t sym, int *nargp, char **argnames) 471923Sdg{ 472923Sdg return X_db_sym_numargs(db_last_symtab, sym, nargp, argnames); 473923Sdg} 474