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