Пример #1
0
int
kt_lookup_by_addr(mdb_tgt_t *t, uintptr_t addr, uint_t flags,
    char *buf, size_t nbytes, GElf_Sym *symp, mdb_syminfo_t *sip)
{
	kt_data_t *kt = t->t_data;
	kt_module_t kmods[3], *kmods_begin = &kmods[0], *kmods_end;
	const char *name;

	kt_module_t *km = &kmods[0];	/* Point km at first fake module */
	kt_module_t *sym_km = NULL;	/* Module associated with best sym */
	GElf_Sym sym;			/* Best symbol found so far if !exact */
	uint_t symid;			/* ID of best symbol found so far */

	/*
	 * To simplify the implementation, we create fake modules on the stack
	 * that are "prepended" to k_modlist and whose symtab is set to
	 * each of three special symbol tables, in order of precedence.
	 */
	km->km_symtab = mdb.m_prsym;

	if (kt->k_symtab != NULL) {
		km->km_list.ml_next = (mdb_list_t *)(km + 1);
		km = mdb_list_next(km);
		km->km_symtab = kt->k_symtab;
	}

	if (kt->k_dynsym != NULL) {
		km->km_list.ml_next = (mdb_list_t *)(km + 1);
		km = mdb_list_next(km);
		km->km_symtab = kt->k_dynsym;
	}

	km->km_list.ml_next = mdb_list_next(&kt->k_modlist);
	kmods_end = km;

	/*
	 * Now iterate over the list of fake and real modules.  If the module
	 * has no symbol table and the address is in the text section,
	 * instantiate the module's symbol table.  In exact mode, we can
	 * jump to 'found' immediately if we match.  Otherwise we continue
	 * looking and improve our choice if we find a closer symbol.
	 */
	for (km = &kmods[0]; km != NULL; km = mdb_list_next(km)) {
		if (km->km_symtab == NULL && addr >= km->km_text_va &&
		    addr < km->km_text_va + km->km_text_size)
			kt_load_module(kt, t, km);

		if (mdb_gelf_symtab_lookup_by_addr(km->km_symtab, addr,
		    flags, buf, nbytes, symp, &sip->sym_id) != 0 ||
		    symp->st_value == 0)
			continue;

		if (flags & MDB_TGT_SYM_EXACT) {
			sym_km = km;
			goto found;
		}

		if (sym_km == NULL || mdb_gelf_sym_closer(symp, &sym, addr)) {
			sym_km = km;
			sym = *symp;
			symid = sip->sym_id;
		}
	}

	if (sym_km == NULL)
		return (set_errno(EMDB_NOSYMADDR));

	*symp = sym; /* Copy our best symbol into the caller's symbol */
	sip->sym_id = symid;
found:
	/*
	 * Once we've found something, copy the final name into the caller's
	 * buffer and prefix it with the load object name if appropriate.
	 */
	name = mdb_gelf_sym_name(sym_km->km_symtab, symp);

	if (sym_km < kmods_begin || sym_km > kmods_end) {
		(void) mdb_snprintf(buf, nbytes, "%s`%s",
		    sym_km->km_name, name);
	} else if (nbytes > 0) {
		(void) strncpy(buf, name, nbytes);
		buf[nbytes - 1] = '\0';
	}

	if (sym_km->km_symtab == mdb.m_prsym)
		sip->sym_table = MDB_TGT_PRVSYM;
	else
		sip->sym_table = MDB_TGT_SYMTAB;

	return (0);
}
Пример #2
0
static int
kp_lookup_by_addr(mdb_tgt_t *t, uintptr_t addr, uint_t flags,
    char *buf, size_t nbytes, GElf_Sym *symp, mdb_syminfo_t *sip)
{
	kp_data_t *kp = t->t_data;
	kp_map_t *kpm = kp_addr_to_kpmap(kp, addr);

	kp_file_t *sym_kpf = NULL;
	GElf_Sym sym;
	uint_t symid;

	const char *name;
	kp_file_t *kpf;
	int n;

	/*
	 * Check the user's private symbol table first; if a match is
	 * found there, we're done or we have a first guess.
	 */
	if (mdb_gelf_symtab_lookup_by_addr(mdb.m_prsym,
	    addr, flags, buf, nbytes, symp, &sip->sym_id) == 0) {
		sym_kpf = &kp->kp_prfile;
		if (flags & MDB_TGT_SYM_EXACT)
			goto found;
		sym = *symp;
		symid = sip->sym_id;
	}

	/*
	 * If no mapping contains the address and EXACT mode is set, we're done.
	 * Otherwise we need to search all the symbol tables in fuzzy mode.
	 * If we find a mapping, then we only need to search that symtab.
	 */
	if (kpm == NULL || kpm->kpm_file == NULL) {
		if (flags & MDB_TGT_SYM_EXACT)
			return (set_errno(EMDB_NOSYMADDR));
		kpf = kp->kp_file_head;
		n = kp->kp_num_files;
	} else {
		kpf = kpm->kpm_file;
		n = 1;
	}

	/*
	 * Iterate through our list of load objects, scanning each one which
	 * has a symbol table.  In fuzzy mode, we continue looking and
	 * improve our choice if we find a closer symbol.
	 */
	for (; n > 0; n--, kpf = kpf->kpf_next) {
		if (kpf->kpf_dynsym == NULL)
			continue; /* No symbols for this file */

		if (mdb_gelf_symtab_lookup_by_addr(kpf->kpf_dynsym,
		    addr - kpf->kpf_dyn_base, flags, buf, nbytes,
		    symp, &sip->sym_id) != 0)
			continue; /* No symbol for this address */

		symp->st_value += kpf->kpf_dyn_base;

		if (flags & MDB_TGT_SYM_EXACT) {
			sym_kpf = kpf;
			goto found;
		}

		if (sym_kpf == NULL || mdb_gelf_sym_closer(symp, &sym, addr)) {
			sym_kpf = kpf;
			sym = *symp;
			symid = sip->sym_id;
		}
	}

	if (sym_kpf == NULL)
		return (set_errno(EMDB_NOSYMADDR));

	*symp = sym;	/* Copy our best symbol into the caller's symbol */
	sip->sym_id = symid;
found:
	/*
	 * Once we've found something, copy the final name into the caller's
	 * buffer and prefix it with the load object name if appropriate.
	 */
	name = mdb_gelf_sym_name(sym_kpf->kpf_dynsym, symp);

	if (sym_kpf != kp->kp_map_exec->kpm_file && sym_kpf != &kp->kp_prfile) {
		(void) mdb_snprintf(buf, nbytes, "%s`%s",
		    sym_kpf->kpf_basename, name);
	} else if (nbytes > 0) {
		(void) strncpy(buf, name, nbytes);
		buf[nbytes - 1] = '\0';
	}

	if (sym_kpf == &kp->kp_prfile)
		sip->sym_table = MDB_TGT_PRVSYM;
	else
		sip->sym_table = MDB_TGT_DYNSYM;

	return (0);
}