Ejemplo n.º 1
0
/*
 * If two syms are of equal value this routine will
 * favor one over the other based off of it's symbol
 * type.
 */
static GElf_Sym
sym_swap(GElf_Sym * s1, GElf_Sym * s2)
{
	int	t1 = GELF_ST_TYPE(s1->st_info);
	int	t2 = GELF_ST_TYPE(s2->st_info);

	if ((t1 == STT_FUNC) || (t2 == STT_FUNC)) {
		if (t1 == STT_FUNC)
			return (*s1);
		return (*s2);
	}

	if ((t1 == STT_OBJECT) || (t2 == STT_OBJECT)) {
		if (t1 == STT_OBJECT)
			return (*s1);
		return (*s2);
	}

	if ((t1 == STT_OBJECT) || (t2 == STT_OBJECT)) {
		if (t1 == STT_OBJECT)
			return (*s1);
		return (*s2);
	}
	return (*s1);
}
Ejemplo n.º 2
0
static int
is_function(Elf *elf, GElf_Sym *sym)
{
	Elf_Scn		*scn;
	GElf_Shdr	shdr;

	/*
	 * With dynamic linking, it is possible that certain undefined
	 * symbols exist in the objects. The actual definition will be
	 * found elsewhere, so we'll just skip it for this object.
	 */
	if (sym->st_shndx == SHN_UNDEF)
		return (0);

	if (GELF_ST_TYPE(sym->st_info) == STT_FUNC) {
		if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL)
			return (1);

		if (GELF_ST_BIND(sym->st_info) == STB_WEAK)
			return (1);

		if (gflag && GELF_ST_BIND(sym->st_info) == STB_LOCAL)
			return (1);
	}

	/*
	 * It's not a function; determine if it's in an executable section.
	 */
	if (GELF_ST_TYPE(sym->st_info) != STT_NOTYPE)
		return (0);

	/*
	 * If it isn't global, and it isn't weak, and it isn't
	 * a 'local with the gflag set', then get out.
	 */
	if (GELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
			GELF_ST_BIND(sym->st_info) != STB_WEAK &&
			!(gflag && GELF_ST_BIND(sym->st_info) == STB_LOCAL))
		return (0);

	if (sym->st_shndx >= SHN_LORESERVE)
		return (0);

	scn = elf_getscn(elf, sym->st_shndx);
	(void) gelf_getshdr(scn, &shdr);

	if (!(shdr.sh_flags & SHF_EXECINSTR))
		return (0);

	return (1);
}
Ejemplo n.º 3
0
static arch_addr_t _find_solib_break(struct mt_elf *mte, Elf_Data *symtab, const char *strtab, size_t size)
{
	size_t i;
	unsigned int j;

	static const char * const solib_break_names[] =
	{
		"r_debug_state",
		"_r_debug_state",
		"_dl_debug_state",
		"rtld_db_dlactivity",
		"__dl_rtld_db_dlactivity",
		"_rtld_debug_state"
	};

	for (i = 0; i < size; ++i) {
		GElf_Sym sym;

		if (gelf_getsym(symtab, i, &sym) == NULL) {
			fprintf(stderr, "couldn't get symbol #%zd from %s: %s\n", i, mte->filename, elf_errmsg(-1));
			continue;
		}

		if (GELF_ST_TYPE(sym.st_info) != STT_FUNC || sym.st_value == 0 || sym.st_shndx == STN_UNDEF)
			continue;

		const char *name = strtab + sym.st_name;

		for(j = 0; j < ARRAY_SIZE(solib_break_names); j++) {
			if (!strcmp(name, solib_break_names[j]))
				return ARCH_ADDR_T(sym.st_value + mte->bias);
		}
	}
	return ARCH_ADDR_T(0);
}
Ejemplo n.º 4
0
Archivo: symbol.c Proyecto: 0mp/freebsd
int
ignore_symbol(GElf_Sym *sym, const char *name)
{
	uchar_t type = GELF_ST_TYPE(sym->st_info);

	/*
	 * As an optimization, we do not output function or data object
	 * records for undefined or anonymous symbols.
	 */
	if (sym->st_shndx == SHN_UNDEF || sym->st_name == 0)
		return (1);

	/*
	 * _START_ and _END_ are added to the symbol table by the
	 * linker, and will never have associated type information.
	 */
	if (strcmp(name, "_START_") == 0 || strcmp(name, "_END_") == 0)
		return (1);

	/*
	 * Do not output records for absolute-valued object symbols
	 * that have value zero.  The compiler insists on generating
	 * things like this for __fsr_init_value settings, etc.
	 */
	if (type == STT_OBJECT && sym->st_shndx == SHN_ABS &&
	    sym->st_value == 0)
		return (1);
	return (0);
}
Ejemplo n.º 5
0
/*ARGSUSED*/
static int
nm_print(void *data, const GElf_Sym *sym, const char *name,
    const mdb_syminfo_t *sip, const char *obj)
{
	nm_iter_info_t *niip = data;

	if (!((1 << GELF_ST_TYPE(sym->st_info)) & niip->nii_types))
		return (0);

	niip->nii_id = sip->sym_id;
	niip->nii_symp = sym;

	mdb_table_print(niip->nii_flags, "|",
	    MDB_TBL_PRNT, NM_FMT_INDEX, "%5u", sip->sym_id,
	    MDB_TBL_FUNC, NM_FMT_OBJECT, nm_print_obj, obj,
	    MDB_TBL_PRNT, NM_FMT_VALUE, niip->nii_pfmt, sym->st_value,
	    MDB_TBL_PRNT, NM_FMT_SIZE, niip->nii_pfmt, sym->st_size,
	    MDB_TBL_PRNT, NM_FMT_TYPE, "%-5s", nm_type2str(sym->st_info),
	    MDB_TBL_PRNT, NM_FMT_BIND, "%-5s", nm_bind2str(sym->st_info),
	    MDB_TBL_PRNT, NM_FMT_OTHER, niip->nii_ofmt, sym->st_other,
	    MDB_TBL_PRNT, NM_FMT_SHNDX, "%-8s", nm_sect2str(sym->st_shndx),
	    MDB_TBL_FUNC, NM_FMT_CTFID, nm_print_ctfid, niip,
	    MDB_TBL_FUNC, NM_FMT_CTYPE, nm_print_ctype, niip,
	    MDB_TBL_PRNT, NM_FMT_NAME, "%s", name,
	    MDB_TBL_DONE);

	mdb_printf("\n");

	return (0);
}
Ejemplo n.º 6
0
/*
 * Given the current symbol index (-1 to start at the beginning of the symbol
 * table) and the type of symbol to match, this function returns the index of
 * the next matching symbol (if any), and places the name of that symbol in
 * *namep.  If no symbol is found, -1 is returned.
 */
static int
next_sym(const ctf_data_t *cd, const int symidx, const uchar_t matchtype,
    char **namep)
{
	int i;

	for (i = symidx + 1; i < cd->cd_nsyms; i++) {
		GElf_Sym sym;
		char *name;
		int type;

		if (gelf_getsym(cd->cd_symdata, i, &sym) == 0)
			return (-1);

		name = (char *)cd->cd_strdata->d_buf + sym.st_name;
		type = GELF_ST_TYPE(sym.st_info);

		/*
		 * Skip various types of symbol table entries.
		 */
		if (type != matchtype || ignore_symbol(&sym, name))
			continue;

		/* Found one */
		*namep = name;
		return (i);
	}

	return (-1);
}
Ejemplo n.º 7
0
static int populate_this_symtab(struct mt_elf *mte, struct libref *libref, Elf_Data *symtab, const char *strtab, size_t size)
{
	size_t i;

	for (i = 0; i < size; ++i) {
		GElf_Sym sym;

		if (gelf_getsym(symtab, i, &sym) == NULL) {
			fprintf(stderr, "couldn't get symbol #%zd from %s: %s\n", i, mte->filename, elf_errmsg(-1));
			continue;
		}

		if (GELF_ST_TYPE(sym.st_info) != STT_FUNC || sym.st_value == 0 || sym.st_shndx == STN_UNDEF)
			continue;

		/* Find symbol name and snip version. */
		const char *orig_name = strtab + sym.st_name;
		const char *version = strchr(orig_name, '@');
		size_t len = version ? (size_t)(version - orig_name) : strlen(orig_name);
		char name[len + 1];

		memcpy(name, orig_name, len);
		name[len] = 0;

		/* If the symbol is not matched, skip it. */
		const struct function *func = flist_matches_symbol(name);
		if (!func)
			continue;

		arch_addr_t addr = ARCH_ADDR_T(sym.st_value + mte->bias);

		struct library_symbol *libsym = library_find_symbol(libref, addr);
		if (!libsym) {
			struct library_symbol *libsym = library_symbol_new(libref, addr, func);

			if (!libsym) {
				fprintf(stderr, "couldn't init symbol: %s%s\n", name, func->name);
				continue;
			}
		}
		else {
			/* handle symbol alias */
			if (libsym->func->level > func->level)
				libsym->func = func;
		}
		if (unlikely(options.verbose > 1))
			fprintf(stderr, "breakpoint for %s:%s at %#lx\n", libref->filename, func->demangled_name, addr);
	}

	return 0;
}
Ejemplo n.º 8
0
const mdb_modinfo_t *
_mdb_init(void)
{
	GElf_Sym	sym;

	if (mdb_lookup_by_name("gld_intr", &sym) != -1)
		if (GELF_ST_TYPE(sym.st_info) == STT_FUNC)
			gld_intr_addr = (uintptr_t)sym.st_value;

	if (mdb_readvar(&apic_pir_vect, "apic_pir_vect") == -1) {
		apic_pir_vect = -1;
	}

	return (&modinfo);
}
Ejemplo n.º 9
0
int
dtrace_symbol_type(dtrace_hdl_t *dtp, const GElf_Sym *symp,
    const dtrace_syminfo_t *sip, dtrace_typeinfo_t *tip)
{
	dt_module_t *dmp;

	tip->dtt_object = NULL;
	tip->dtt_ctfp = NULL;
	tip->dtt_type = CTF_ERR;
	tip->dtt_flags = 0;

	if ((dmp = dt_module_lookup_by_name(dtp, sip->dts_object)) == NULL)
		return (dt_set_errno(dtp, EDT_NOMOD));

	if (symp->st_shndx == SHN_UNDEF && dmp->dm_extern != NULL) {
		dt_ident_t *idp =
		    dt_idhash_lookup(dmp->dm_extern, sip->dts_name);

		if (idp == NULL)
			return (dt_set_errno(dtp, EDT_NOSYM));

		tip->dtt_ctfp = idp->di_ctfp;
		tip->dtt_type = idp->di_type;

	} else if (GELF_ST_TYPE(symp->st_info) != STT_FUNC) {
		if (dt_module_getctf(dtp, dmp) == NULL)
			return (-1); /* errno is set for us */

		tip->dtt_ctfp = dmp->dm_ctfp;
		tip->dtt_type = ctf_lookup_by_symbol(dmp->dm_ctfp, sip->dts_id);

		if (tip->dtt_type == CTF_ERR) {
			dtp->dt_ctferr = ctf_errno(tip->dtt_ctfp);
			return (dt_set_errno(dtp, EDT_CTF));
		}

	} else {
		tip->dtt_ctfp = DT_FPTR_CTFP(dtp);
		tip->dtt_type = DT_FPTR_TYPE(dtp);
	}

	tip->dtt_object = dmp->dm_name;
	return (0);
}
Ejemplo n.º 10
0
static void
nm_print_ctype(void *data)
{
	nm_iter_info_t *niip = data;
	char buf[256];
	ctf_id_t id;
	char *str = NULL;
	uint_t index = niip->nii_id;
	ctf_file_t *fp = niip->nii_fp;

	if (fp != NULL) {
		if (GELF_ST_TYPE(niip->nii_symp->st_info) == STT_FUNC)
			str = nm_func_signature(fp, index, buf, sizeof (buf));
		else if ((id = ctf_lookup_by_symbol(fp, index)) != CTF_ERR)
			str = ctf_type_name(fp, id, buf, sizeof (buf));
	}

	if (str == NULL)
		str = "<unknown type>";

	mdb_printf("%-50s", str);
}
Ejemplo n.º 11
0
/*ARGSUSED*/
static int
nm_asgn(void *data, const GElf_Sym *sym, const char *name,
    const mdb_syminfo_t *sip, const char *obj)
{
	const char *opts;

	switch (GELF_ST_TYPE(sym->st_info)) {
	case STT_FUNC:
		opts = "-f";
		break;
	case STT_OBJECT:
		opts = "-o";
		break;
	default:
		opts = "";
	}

	mdb_printf("%#llr::nmadd %s -s %#llr %s\n",
	    sym->st_value, opts, sym->st_size, name);

	return (0);
}
Ejemplo n.º 12
0
static const char *
gelf_type (GElf_Sym *sym)
{
  switch (GELF_ST_TYPE (sym->st_info))
    {
    case STT_NOTYPE:
      return "NOTYPE";
    case STT_OBJECT:
      return "OBJECT";
    case STT_FUNC:
      return "FUNC";
    case STT_SECTION:
      return "SECTION";
    case STT_FILE:
      return "FILE";
    case STT_COMMON:
      return "COMMON";
    case STT_TLS:
      return "TLS";
    default:
      return "UNKNOWN";
    }
}
Ejemplo n.º 13
0
static const char *
nm_type2str(uchar_t info)
{
	switch (GELF_ST_TYPE(info)) {
	case STT_NOTYPE:
		return ("NOTY");
	case STT_OBJECT:
		return ("OBJT");
	case STT_FUNC:
		return ("FUNC");
	case STT_SECTION:
		return ("SECT");
	case STT_FILE:
		return ("FILE");
	case STT_COMMON:
		return ("COMM");
	case STT_TLS:
		return ("TLS");
	case STT_SPARC_REGISTER:
		return ("REGI");
	default:
		return ("?");
	}
}
Ejemplo n.º 14
0
/*
 * Search for a symbol by name and return the corresponding symbol
 * information.  If we're compiled _LP64, we just call Plookup_by_name
 * and return because ps_sym_t is defined to be an Elf64_Sym, which
 * is the same as a GElf_Sym.  In the _ILP32 case, we have to convert
 * Plookup_by_name's result back to a ps_sym_t (which is an Elf32_Sym).
 */
ps_err_e
ps_pglobal_sym(struct ps_prochandle *P, const char *object_name,
	const char *sym_name, ps_sym_t *symp)
{
#if defined(_ILP32)
	GElf_Sym sym;

	if (Plookup_by_name(P, object_name, sym_name, &sym) == 0) {
		symp->st_name = (Elf32_Word)sym.st_name;
		symp->st_value = (Elf32_Addr)sym.st_value;
		symp->st_size = (Elf32_Word)sym.st_size;
		symp->st_info = ELF32_ST_INFO(
		    GELF_ST_BIND(sym.st_info), GELF_ST_TYPE(sym.st_info));
		symp->st_other = sym.st_other;
		symp->st_shndx = sym.st_shndx;
		return (PS_OK);
	}

#elif defined(_LP64)
	if (Plookup_by_name(P, object_name, sym_name, symp) == 0)
		return (PS_OK);
#endif
	return (PS_NOSYM);
}
Ejemplo n.º 15
0
static void
walk_symtab(Elf *elf, char *fname, ctf_file_t *fp,
    void (*callback)(ctf_file_t *, symtab_sym_t *))
{
	Elf_Scn *stab = NULL;
	Elf_Scn *text = NULL;
	Elf_Data *stabdata = NULL;
	Elf_Data *textdata = NULL;
	GElf_Ehdr ehdr;
	GElf_Shdr stabshdr;
	GElf_Shdr textshdr;
	int foundtext = 0, foundstab = 0;
	symtab_sym_t ss;

	if ((gelf_getehdr(elf, &ehdr)) == NULL)
		errx(1, "could not read ELF header from %s\n",
		    fname);

	while ((stab = elf_nextscn(elf, stab)) != NULL) {
		(void) gelf_getshdr(stab, &stabshdr);

		if (stabshdr.sh_type == SHT_SYMTAB) {
			foundstab = 1;
			break;
		}
	}

	while ((text = elf_nextscn(elf, text)) != NULL) {
		(void) gelf_getshdr(text, &textshdr);

		if (strcmp(".text", elf_strptr(elf,
		    ehdr.e_shstrndx, (size_t)textshdr.sh_name)) == 0) {
			foundtext = 1;
			break;
		}
	}

	if (!foundstab || !foundtext)
		return;

	stabdata = elf_getdata(stab, NULL);
	textdata = elf_rawdata(text,  NULL);
	for (unsigned symdx = 0;
	    symdx < (stabshdr.sh_size / stabshdr.sh_entsize);
	    symdx++) {
		(void) gelf_getsym(stabdata, symdx, &ss.ss_sym);

		if ((GELF_ST_TYPE(ss.ss_sym.st_info) != STT_FUNC) ||
		    (ss.ss_sym.st_shndx == SHN_UNDEF))
			continue;

		ss.ss_name = elf_strptr(elf, stabshdr.sh_link,
		    ss.ss_sym.st_name);
		ss.ss_data = ((uint8_t *)(textdata->d_buf)) +
		    (ss.ss_sym.st_value - textshdr.sh_addr);

		if (ctf_func_info(fp, symdx, &ss.ss_finfo) == CTF_ERR) {
			fprintf(stderr, "failed to get funcinfo for: %s\n",
			    ss.ss_name);
			continue;
		}

		(void) callback(fp, &ss);
	}
}
Ejemplo n.º 16
0
static inline uint8_t elf_sym__type(const GElf_Sym *sym)
{
	return GELF_ST_TYPE(sym->st_info);
}
Ejemplo n.º 17
0
static int
dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj)
{
	dt_pid_probe_t *pp = arg;
	dtrace_hdl_t *dtp = pp->dpp_dtp;
	dt_pcb_t *pcb = pp->dpp_pcb;
	dt_proc_t *dpr = pp->dpp_dpr;
	GElf_Sym sym;

	if (obj == NULL)
		return (0);

#if defined(sun)
	(void) Plmid(pp->dpp_pr, pmp->pr_vaddr, &pp->dpp_lmid);
#endif
	

	if ((pp->dpp_obj = strrchr(obj, '/')) == NULL)
		pp->dpp_obj = obj;
	else
		pp->dpp_obj++;
#if defined(sun)
	if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret1", &sym,
	    NULL) == 0)
		pp->dpp_stret[0] = sym.st_value;
	else
		pp->dpp_stret[0] = 0;

	if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret2", &sym,
	    NULL) == 0)
		pp->dpp_stret[1] = sym.st_value;
	else
		pp->dpp_stret[1] = 0;

	if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret4", &sym,
	    NULL) == 0)
		pp->dpp_stret[2] = sym.st_value;
	else
		pp->dpp_stret[2] = 0;

	if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret8", &sym,
	    NULL) == 0)
		pp->dpp_stret[3] = sym.st_value;
	else
		pp->dpp_stret[3] = 0;
#else
	pp->dpp_stret[0] = 0;
	pp->dpp_stret[1] = 0;
	pp->dpp_stret[2] = 0;
	pp->dpp_stret[3] = 0;
#endif

	dt_dprintf("%s stret %llx %llx %llx %llx\n", obj,
	    (u_longlong_t)pp->dpp_stret[0], (u_longlong_t)pp->dpp_stret[1],
	    (u_longlong_t)pp->dpp_stret[2], (u_longlong_t)pp->dpp_stret[3]);

	/*
	 * If pp->dpp_func contains any globbing meta-characters, we need
	 * to iterate over the symbol table and compare each function name
	 * against the pattern.
	 */
	if (!strisglob(pp->dpp_func)) {
		/*
		 * If we fail to lookup the symbol, try interpreting the
		 * function as the special "-" function that indicates that the
		 * probe name should be interpreted as a absolute virtual
		 * address. If that fails and we were matching a specific
		 * function in a specific module, report the error, otherwise
		 * just fail silently in the hopes that some other object will
		 * contain the desired symbol.
		 */
		if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj,
		    pp->dpp_func, &sym, NULL) != 0) {
			if (strcmp("-", pp->dpp_func) == 0) {
				sym.st_name = 0;
				sym.st_info =
				    GELF_ST_INFO(STB_LOCAL, STT_FUNC);
				sym.st_other = 0;
				sym.st_value = 0;
#if defined(sun)
				sym.st_size = Pstatus(pp->dpp_pr)->pr_dmodel ==
				    PR_MODEL_ILP32 ? -1U : -1ULL;
#else
				sym.st_size = ~((Elf64_Xword) 0);
#endif

			} else if (!strisglob(pp->dpp_mod)) {
				return (dt_pid_error(dtp, pcb, dpr, NULL,
				    D_PROC_FUNC,
				    "failed to lookup '%s' in module '%s'",
				    pp->dpp_func, pp->dpp_mod));
			} else {
				return (0);
			}
		}

		/*
		 * Only match defined functions of non-zero size.
		 */
		if (GELF_ST_TYPE(sym.st_info) != STT_FUNC ||
		    sym.st_shndx == SHN_UNDEF || sym.st_size == 0)
			return (0);

		/*
		 * We don't instrument PLTs -- they're dynamically rewritten,
		 * and, so, inherently dicey to instrument.
		 */
#ifdef DOODAD
		if (Ppltdest(pp->dpp_pr, sym.st_value) != NULL)
			return (0);
#endif

		(void) Plookup_by_addr(pp->dpp_pr, sym.st_value, pp->dpp_func,
		    DTRACE_FUNCNAMELEN, &sym);

		return (dt_pid_per_sym(pp, &sym, pp->dpp_func));
	} else {
		uint_t nmatches = pp->dpp_nmatches;

		if (Psymbol_iter_by_addr(pp->dpp_pr, obj, PR_SYMTAB,
		    BIND_ANY | TYPE_FUNC, dt_pid_sym_filt, pp) == 1)
			return (1);

		if (nmatches == pp->dpp_nmatches) {
			/*
			 * If we didn't match anything in the PR_SYMTAB, try
			 * the PR_DYNSYM.
			 */
			if (Psymbol_iter_by_addr(pp->dpp_pr, obj, PR_DYNSYM,
			    BIND_ANY | TYPE_FUNC, dt_pid_sym_filt, pp) == 1)
				return (1);
		}
	}

	return (0);
}
Ejemplo n.º 18
0
internal_function
__libdwfl_getsym (Dwfl_Module *mod, int ndx, GElf_Sym *sym, GElf_Addr *addr,
		  GElf_Word *shndxp, Elf **elfp, Dwarf_Addr *biasp,
		  bool *resolved, bool adjust_st_value)
{
  if (unlikely (mod == NULL))
    return NULL;

  if (unlikely (mod->symdata == NULL))
    {
      int result = INTUSE(dwfl_module_getsymtab) (mod);
      if (result < 0)
	return NULL;
    }

  /* All local symbols should come before all global symbols.  If we
     have an auxiliary table make sure all the main locals come first,
     then all aux locals, then all main globals and finally all aux globals.
     And skip the auxiliary table zero undefined entry.  */
  GElf_Word shndx;
  int tndx = ndx;
  int skip_aux_zero = (mod->syments > 0 && mod->aux_syments > 0) ? 1 : 0;
  Elf *elf;
  Elf_Data *symdata;
  Elf_Data *symxndxdata;
  Elf_Data *symstrdata;
  if (mod->aux_symdata == NULL
      || ndx < mod->first_global)
    {
      /* main symbol table (locals).  */
      tndx = ndx;
      elf = mod->symfile->elf;
      symdata = mod->symdata;
      symxndxdata = mod->symxndxdata;
      symstrdata = mod->symstrdata;
    }
  else if (ndx < mod->first_global + mod->aux_first_global - skip_aux_zero)
    {
      /* aux symbol table (locals).  */
      tndx = ndx - mod->first_global + skip_aux_zero;
      elf = mod->aux_sym.elf;
      symdata = mod->aux_symdata;
      symxndxdata = mod->aux_symxndxdata;
      symstrdata = mod->aux_symstrdata;
    }
  else if ((size_t) ndx < mod->syments + mod->aux_first_global - skip_aux_zero)
    {
      /* main symbol table (globals).  */
      tndx = ndx - mod->aux_first_global + skip_aux_zero;
      elf = mod->symfile->elf;
      symdata = mod->symdata;
      symxndxdata = mod->symxndxdata;
      symstrdata = mod->symstrdata;
    }
  else
    {
      /* aux symbol table (globals).  */
      tndx = ndx - mod->syments + skip_aux_zero;
      elf = mod->aux_sym.elf;
      symdata = mod->aux_symdata;
      symxndxdata = mod->aux_symxndxdata;
      symstrdata = mod->aux_symstrdata;
    }
  sym = gelf_getsymshndx (symdata, symxndxdata, tndx, sym, &shndx);

  if (unlikely (sym == NULL))
    {
      __libdwfl_seterrno (DWFL_E_LIBELF);
      return NULL;
    }

  if (sym->st_shndx != SHN_XINDEX)
    shndx = sym->st_shndx;

  /* Figure out whether this symbol points into an SHF_ALLOC section.  */
  bool alloc = true;
  if ((shndxp != NULL || mod->e_type != ET_REL)
      && (sym->st_shndx == SHN_XINDEX
	  || (sym->st_shndx < SHN_LORESERVE && sym->st_shndx != SHN_UNDEF)))
    {
      GElf_Shdr shdr_mem;
      GElf_Shdr *shdr = gelf_getshdr (elf_getscn (elf, shndx), &shdr_mem);
      alloc = unlikely (shdr == NULL) || (shdr->sh_flags & SHF_ALLOC);
    }

  /* In case of an value in an allocated section the main Elf Ebl
     might know where the real value is (e.g. for function
     descriptors).  */

  char *ident;
  GElf_Addr st_value = sym->st_value & ebl_func_addr_mask (mod->ebl);
  *resolved = false;
  if (! adjust_st_value && mod->e_type != ET_REL && alloc
      && (GELF_ST_TYPE (sym->st_info) == STT_FUNC
	  || (GELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
	      && (ident = elf_getident (elf, NULL)) != NULL
	      && ident[EI_OSABI] == ELFOSABI_LINUX)))
    {
      if (likely (__libdwfl_module_getebl (mod) == DWFL_E_NOERROR))
	{
	  if (elf != mod->main.elf)
	    {
	      st_value = dwfl_adjusted_st_value (mod, elf, st_value);
	      st_value = dwfl_deadjust_st_value (mod, mod->main.elf, st_value);
	    }

	  *resolved = ebl_resolve_sym_value (mod->ebl, &st_value);
	  if (! *resolved)
	    st_value = sym->st_value;
	}
    }

  if (shndxp != NULL)
    /* Yield -1 in case of a non-SHF_ALLOC section.  */
    *shndxp = alloc ? shndx : (GElf_Word) -1;

  switch (sym->st_shndx)
    {
    case SHN_ABS:		/* XXX sometimes should use bias?? */
    case SHN_UNDEF:
    case SHN_COMMON:
      break;

    default:
      if (mod->e_type == ET_REL)
	{
	  /* In an ET_REL file, the symbol table values are relative
	     to the section, not to the module's load base.  */
	  size_t symshstrndx = SHN_UNDEF;
	  Dwfl_Error result = __libdwfl_relocate_value (mod, elf,
							&symshstrndx,
							shndx, &st_value);
	  if (unlikely (result != DWFL_E_NOERROR))
	    {
	      __libdwfl_seterrno (result);
	      return NULL;
	    }
	}
      else if (alloc)
	/* Apply the bias to the symbol value.  */
	st_value = dwfl_adjusted_st_value (mod,
					   *resolved ? mod->main.elf : elf,
					   st_value);
      break;
    }

  if (adjust_st_value)
    sym->st_value = st_value;

  if (addr != NULL)
    *addr = st_value;

  if (unlikely (sym->st_name >= symstrdata->d_size))
    {
      __libdwfl_seterrno (DWFL_E_BADSTROFF);
      return NULL;
    }
  if (elfp)
    *elfp = elf;
  if (biasp)
    *biasp = dwfl_adjusted_st_value (mod, elf, 0);
  return (const char *) symstrdata->d_buf + sym->st_name;
}
Ejemplo n.º 19
0
void clone_elf(Elf *elf, Elf *newelf,
               const char *elf_name,
               const char *newelf_name,
               bool *sym_filter, int num_symbols,
               int shady
#ifdef SUPPORT_ANDROID_PRELINK_TAGS
               , int *prelinked,
               int *elf_little,
               long *prelink_addr
#endif
               , bool rebuild_shstrtab,
               bool strip_debug,
               bool dry_run)
{
	GElf_Ehdr ehdr_mem, *ehdr; /* store ELF header of original library */
	size_t shstrndx; /* section-strings-section index */
	size_t shnum; /* number of sections in the original file */
	/* string table for section headers in new file */
	struct Ebl_Strtab *shst = NULL;
    int dynamic_idx = -1; /* index in shdr_info[] of .dynamic section */
    int dynsym_idx = -1; /* index in shdr_info[] of dynamic symbol table
                            section */

    unsigned int cnt;	  /* general-purpose counter */
    /* This flag is true when at least one section is dropped or when the
       relative order of sections has changed, so that section indices in
       the resulting file will be different from those in the original. */
    bool sections_dropped_or_rearranged;
	Elf_Scn *scn; /* general-purpose section */
	size_t idx;	  /* general-purporse section index */

	shdr_info_t *shdr_info = NULL;
    unsigned int shdr_info_len = 0;
    GElf_Phdr *phdr_info = NULL;

	/* Get the information from the old file. */
	ehdr = gelf_getehdr (elf, &ehdr_mem);
	FAILIF_LIBELF(NULL == ehdr, gelf_getehdr);

	/* Create new program header for the elf file */
	FAILIF(gelf_newehdr (newelf, gelf_getclass (elf)) == 0 ||
		   (ehdr->e_type != ET_REL && gelf_newphdr (newelf,
													ehdr->e_phnum) == 0),
		   "Cannot create new file: %s", elf_errmsg (-1));

#ifdef SUPPORT_ANDROID_PRELINK_TAGS
    ASSERT(prelinked);
    ASSERT(prelink_addr);
    ASSERT(elf_little);
    *elf_little = (ehdr->e_ident[EI_DATA] == ELFDATA2LSB);
    *prelinked = check_prelinked(elf_name, *elf_little, prelink_addr);
#endif

    INFO("\n\nCALCULATING MODIFICATIONS\n\n");

	/* Copy out the old program header: notice that if the ELF file does not
	   have a program header, this loop won't execute.
	*/
	INFO("Copying ELF program header...\n");
    phdr_info = (GElf_Phdr *)CALLOC(ehdr->e_phnum, sizeof(GElf_Phdr));
	for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) {
		INFO("\tRetrieving entry %d\n", cnt);
		FAILIF_LIBELF(NULL == gelf_getphdr(elf, cnt, phdr_info + cnt),
                      gelf_getphdr);
        /* -- we update the header at the end
        FAILIF_LIBELF(gelf_update_phdr (newelf, cnt, phdr_info + cnt) == 0,
                      gelf_update_phdr);
        */
	}

    /* Get the section-header strings section.  This section contains the
	   strings used to name the other sections. */
	FAILIF_LIBELF(elf_getshstrndx(elf, &shstrndx) < 0, elf_getshstrndx);

	/* Get the number of sections. */
	FAILIF_LIBELF(elf_getshnum (elf, &shnum) < 0, elf_getshnum);
	INFO("Original ELF file has %zd sections.\n", shnum);

	/* Allocate the section-header-info buffer.  We allocate one more entry
       for the section-strings section because we regenerate that one and
       place it at the very end of the file.  Note that just because we create
       an extra entry in the shdr_info array, it does not mean that we create
       one more section the header.  We just mark the old section for removal
       and create one as the last section.
    */
	INFO("Allocating section-header info structure (%zd) bytes...\n",
		 shnum*sizeof (shdr_info_t));
    shdr_info_len = rebuild_shstrtab ? shnum + 1 : shnum;
	shdr_info = (shdr_info_t *)CALLOC(shdr_info_len, sizeof (shdr_info_t));

	/* Iterate over all the sections and initialize the internal section-info
	   array...
	*/
	INFO("Initializing section-header info structure...\n");
	/* Gather information about the sections in this file. */
	scn = NULL;
	cnt = 1;
	while ((scn = elf_nextscn (elf, scn)) != NULL) {
		ASSERT(elf_ndxscn(scn) == cnt);
		shdr_info[cnt].scn = scn;
		FAILIF_LIBELF(NULL == gelf_getshdr(scn, &shdr_info[cnt].shdr),
					  gelf_getshdr);

		/* Get the name of the section. */
		shdr_info[cnt].name = elf_strptr (elf, shstrndx,
										  shdr_info[cnt].shdr.sh_name);

		INFO("\tname: %s\n", shdr_info[cnt].name);
		FAILIF(shdr_info[cnt].name == NULL,
			   "Malformed file: section %d name is null\n",
			   cnt);

		/* Mark them as present but not yet investigated.  By "investigating"
		   sections, we mean that we check to see if by stripping other
		   sections, the sections under investigation will be compromised.  For
		   example, if we are removing a section of code, then we want to make
		   sure that the symbol table does not contain symbols that refer to
		   this code, so we investigate the symbol table.  If we do find such
		   symbols, we will not strip the code section.
		*/
		shdr_info[cnt].idx = 1;

		/* Remember the shdr.sh_link value.  We need to remember this value
		   for those sections that refer to other sections.  For example,
		   we need to remember it for relocation-entry sections, because if
		   we modify the symbol table that a relocation-entry section is
		   relative to, then we need to patch the relocation section.  By the
		   time we get to deciding whether we need to patch the relocation
		   section, we will have overwritten its header's sh_link field with
		   a new value.
		*/
		shdr_info[cnt].old_shdr = shdr_info[cnt].shdr;
        INFO("\t\toriginal sh_link: %08d\n", shdr_info[cnt].old_shdr.sh_link);
        INFO("\t\toriginal sh_addr: %lld\n", shdr_info[cnt].old_shdr.sh_addr);
        INFO("\t\toriginal sh_offset: %lld\n",
             shdr_info[cnt].old_shdr.sh_offset);
        INFO("\t\toriginal sh_size: %lld\n", shdr_info[cnt].old_shdr.sh_size);

        if (shdr_info[cnt].shdr.sh_type == SHT_DYNAMIC) {
            INFO("\t\tthis is the SHT_DYNAMIC section [%s] at index %d\n",
                 shdr_info[cnt].name,
                 cnt);
            dynamic_idx = cnt;
        }
        else if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM) {
            INFO("\t\tthis is the SHT_DYNSYM section [%s] at index %d\n",
                 shdr_info[cnt].name,
                 cnt);
            dynsym_idx = cnt;
        }

		FAILIF(shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX,
			   "Cannot handle sh_type SHT_SYMTAB_SHNDX!\n");
		FAILIF(shdr_info[cnt].shdr.sh_type == SHT_GROUP,
			   "Cannot handle sh_type SHT_GROUP!\n");
		FAILIF(shdr_info[cnt].shdr.sh_type == SHT_GNU_versym,
			   "Cannot handle sh_type SHT_GNU_versym!\n");

		/* Increment the counter. */
		++cnt;
	} /* while */

	/* Get the EBL handling. */
	Ebl *ebl = ebl_openbackend (elf);
	FAILIF_LIBELF(NULL == ebl, ebl_openbackend);
    FAILIF_LIBELF(0 != arm_init(elf, ehdr->e_machine, ebl, sizeof(Ebl)),
                  arm_init);

    if (strip_debug) {

      /* This will actually strip more than just sections.  It will strip
         anything not essential to running the image.
      */

      INFO("Finding debug sections to strip.\n");

      /* Now determine which sections can go away.  The general rule is that
         all sections which are not used at runtime are stripped out.  But
         there are a few exceptions:

         - special sections named ".comment" and ".note" are kept
         - OS or architecture specific sections are kept since we might not
		 know how to handle them
         - if a section is referred to from a section which is not removed
		 in the sh_link or sh_info element it cannot be removed either
      */
      for (cnt = 1; cnt < shnum; ++cnt) {
		/* Check whether the section can be removed.  */
		if (SECTION_STRIP_P (ebl, elf, ehdr, &shdr_info[cnt].shdr,
							 shdr_info[cnt].name,
							 1,	 /* remove .comment sections */
							 1	 /* remove all debug sections */) ||
            /* The macro above is broken--check for .comment explicitly */
            !strcmp(".comment", shdr_info[cnt].name)
#ifdef ARM_SPECIFIC_HACKS
            ||
            /* We ignore this section, that's why we can remove it. */
            !strcmp(".stack", shdr_info[cnt].name)
#endif
            )
        {
          /* For now assume this section will be removed.  */
          INFO("Section [%s] will be stripped from image.\n",
               shdr_info[cnt].name);
          shdr_info[cnt].idx = 0;
		}
#ifdef STRIP_STATIC_SYMBOLS
		else if (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB) {
          /* Mark the static symbol table for removal */
          INFO("Section [%s] (static symbol table) will be stripped from image.\n",
               shdr_info[cnt].name);
          shdr_info[cnt].idx = 0;
          if (shdr_info[shdr_info[cnt].shdr.sh_link].shdr.sh_type ==
              SHT_STRTAB)
          {
            /* Mark the symbol table's string table for removal. */
            INFO("Section [%s] (static symbol-string table) will be stripped from image.\n",
                 shdr_info[shdr_info[cnt].shdr.sh_link].name);
            shdr_info[shdr_info[cnt].shdr.sh_link].idx = 0;
          }
          else {
            ERROR("Expecting the sh_link field of a symbol table to point to"
                  " associated symbol-strings table!  This is not mandated by"
                  " the standard, but is a common practice and the only way "
                  " to know for sure which strings table corresponds to which"
                  " symbol table!\n");
          }
		}
#endif
      }

      /* Mark the SHT_NULL section as handled. */
      shdr_info[0].idx = 2;

      /* Handle exceptions: section groups and cross-references.  We might have
         to repeat this a few times since the resetting of the flag might
         propagate.
      */
      int exceptions_pass = 0;
      bool changes;
      do {
        changes = false;
		INFO("\nHandling exceptions, pass %d\n\n", exceptions_pass++);
		for (cnt = 1; cnt < shnum; ++cnt) {
          if (shdr_info[cnt].idx == 0) {
            /* If a relocation section is marked as being removed but the
               section it is relocating is not, then do not remove the
               relocation section.
            */
            if ((shdr_info[cnt].shdr.sh_type == SHT_REL
                 || shdr_info[cnt].shdr.sh_type == SHT_RELA)
                && shdr_info[shdr_info[cnt].shdr.sh_info].idx != 0) {
              PRINT("\tSection [%s] will not be removed because the "
                    "section it is relocating (%s) stays.\n",
                    shdr_info[cnt].name,
                    shdr_info[shdr_info[cnt].shdr.sh_info].name);
            }
          }
          if (shdr_info[cnt].idx == 1) {
            INFO("Processing section [%s]...\n", shdr_info[cnt].name);

            /* The content of symbol tables we don't remove must not
               reference any section which we do remove.  Otherwise
               we cannot remove the referred section.
            */
            if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM ||
                shdr_info[cnt].shdr.sh_type == SHT_SYMTAB)
            {
              Elf_Data *symdata;
              size_t elsize;

              INFO("\tSection [%s] is a symbol table that's not being"
                   " removed.\n\tChecking to make sure that no symbols"
                   " refer to sections that are being removed.\n",
                   shdr_info[cnt].name);

              /* Make sure the data is loaded.  */
              symdata = elf_getdata (shdr_info[cnt].scn, NULL);
              FAILIF_LIBELF(NULL == symdata, elf_getdata);

              /* Go through all symbols and make sure the section they
                 reference is not removed.  */
              elsize = gelf_fsize (elf, ELF_T_SYM, 1, ehdr->e_version);

              /* Check the length of the dynamic-symbol filter. */
              FAILIF(sym_filter != NULL &&
                     (size_t)num_symbols != symdata->d_size / elsize,
                     "Length of dynsym filter (%d) must equal the number"
                     " of dynamic symbols (%zd)!\n",
                     num_symbols,
                     symdata->d_size / elsize);

              size_t inner;
              for (inner = 0;
                   inner < symdata->d_size / elsize;
                   ++inner)
              {
                GElf_Sym sym_mem;
                GElf_Sym *sym;
                size_t scnidx;

                sym = gelf_getsymshndx (symdata, NULL,
                                        inner, &sym_mem, NULL);
                FAILIF_LIBELF(sym == NULL, gelf_getsymshndx);

                scnidx = sym->st_shndx;
                FAILIF(scnidx == SHN_XINDEX,
                       "Can't handle SHN_XINDEX!\n");
                if (scnidx == SHN_UNDEF ||
                    scnidx >= shnum ||
                    (scnidx >= SHN_LORESERVE &&
                     scnidx <= SHN_HIRESERVE) ||
                    GELF_ST_TYPE (sym->st_info) == STT_SECTION)
                {
                  continue;
                }

                /* If the symbol is going to be thrown and it is a
                   global or weak symbol that is defined (not imported),
                   then continue.  Since the symbol is going away, we
                   do not care  whether it refers to a section that is
                   also going away.
                */
                if (sym_filter && !sym_filter[inner])
                {
                  bool global_or_weak =
                      ELF32_ST_BIND(sym->st_info) == STB_GLOBAL ||
                      ELF32_ST_BIND(sym->st_info) == STB_WEAK;
                  if (!global_or_weak && sym->st_shndx != SHN_UNDEF)
                    continue;
                }

                /* -- far too much output
                   INFO("\t\t\tSymbol [%s] (%d)\n",
                   elf_strptr(elf,
                   shdr_info[cnt].shdr.sh_link,
                   sym->st_name),
                   shdr_info[cnt].shdr.sh_info);
                */

                if (shdr_info[scnidx].idx == 0)
                {
                  PRINT("\t\t\tSymbol [%s] refers to section [%s], "
                        "which is being removed.  Will keep that "
                        "section.\n",
                        elf_strptr(elf,
                                   shdr_info[cnt].shdr.sh_link,
                                   sym->st_name),
                        shdr_info[scnidx].name);
                  /* Mark this section as used.  */
                  shdr_info[scnidx].idx = 1;
                  changes |= scnidx < cnt;
                }
              } /* for each symbol */
            } /* section type is SHT_DYNSYM or SHT_SYMTAB */
            /* Cross referencing happens:
			   - for the cases the ELF specification says.  That are
			   + SHT_DYNAMIC in sh_link to string table
			   + SHT_HASH in sh_link to symbol table
			   + SHT_REL and SHT_RELA in sh_link to symbol table
			   + SHT_SYMTAB and SHT_DYNSYM in sh_link to string table
			   + SHT_GROUP in sh_link to symbol table
			   + SHT_SYMTAB_SHNDX in sh_link to symbol table
			   Other (OS or architecture-specific) sections might as
			   well use this field so we process it unconditionally.
			   - references inside section groups
			   - specially marked references in sh_info if the SHF_INFO_LINK
			   flag is set
            */

            if (shdr_info[shdr_info[cnt].shdr.sh_link].idx == 0) {
              shdr_info[shdr_info[cnt].shdr.sh_link].idx = 1;
              changes |= shdr_info[cnt].shdr.sh_link < cnt;
            }

            /* Handle references through sh_info.  */
            if (SH_INFO_LINK_P (&shdr_info[cnt].shdr) &&
                shdr_info[shdr_info[cnt].shdr.sh_info].idx == 0) {
              PRINT("\tSection [%s] links to section [%s], which was "
                    "marked for removal--it will not be removed.\n",
                    shdr_info[cnt].name,
                    shdr_info[shdr_info[cnt].shdr.sh_info].name);

              shdr_info[shdr_info[cnt].shdr.sh_info].idx = 1;
              changes |= shdr_info[cnt].shdr.sh_info < cnt;
            }

            /* Mark the section as investigated.  */
            shdr_info[cnt].idx = 2;
          } /* if (shdr_info[cnt].idx == 1) */
		} /* for (cnt = 1; cnt < shnum; ++cnt) */
      } while (changes);
    }
    else {
      INFO("Not stripping sections.\n");
      /* Mark the SHT_NULL section as handled. */
      shdr_info[0].idx = 2;
    }

	/* Mark the section header string table as unused, we will create
	   a new one as the very last section in the new ELF file.
	*/
	shdr_info[shstrndx].idx = rebuild_shstrtab ? 0 : 2;

	/* We need a string table for the section headers. */
	FAILIF_LIBELF((shst = ebl_strtabinit (1	/* null-terminated */)) == NULL,
				  ebl_strtabinit);

	/* Assign new section numbers. */
	INFO("Creating new sections...\n");
	//shdr_info[0].idx = 0;
	for (cnt = idx = 1; cnt < shnum; ++cnt) {
		if (shdr_info[cnt].idx > 0) {
			shdr_info[cnt].idx = idx++;

			/* Create a new section. */
			FAILIF_LIBELF((shdr_info[cnt].newscn =
						   elf_newscn(newelf)) == NULL, elf_newscn);
			ASSERT(elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx);

			/* Add this name to the section header string table. */
			shdr_info[cnt].se = ebl_strtabadd (shst, shdr_info[cnt].name, 0);

			INFO("\tsection [%s]  (old offset %lld, old size %lld) will have index %d "
				 "(was %zd).\n",
				 shdr_info[cnt].name,
				 shdr_info[cnt].old_shdr.sh_offset,
				 shdr_info[cnt].old_shdr.sh_size,
				 shdr_info[cnt].idx,
				 elf_ndxscn(shdr_info[cnt].scn));
		} else {
			INFO("\tIgnoring section [%s] (offset %lld, size %lld, index %zd), "
				 "it will be discarded.\n",
				 shdr_info[cnt].name,
				 shdr_info[cnt].shdr.sh_offset,
				 shdr_info[cnt].shdr.sh_size,
				 elf_ndxscn(shdr_info[cnt].scn));
		}
	} /* for */

    sections_dropped_or_rearranged = idx != cnt;

    Elf_Data *shstrtab_data = NULL;

#if 0
    /* Fail if sections are being dropped or rearranged (except for moving shstrtab) or the
       symbol filter is not empty, AND the file is an executable.
    */
    FAILIF(((idx != cnt && !(cnt - idx == 1 && rebuild_shstrtab)) || sym_filter != NULL) &&
           ehdr->e_type != ET_DYN,
           "You may not rearrange sections or strip symbols on an executable file!\n");
#endif

    INFO("\n\nADJUSTING ELF FILE\n\n");

    adjust_elf(elf, elf_name,
               newelf, newelf_name,
               ebl,
               ehdr, /* store ELF header of original library */
               sym_filter, num_symbols,
               shdr_info, shdr_info_len,
               phdr_info,
               idx, /* highest_scn_num */
               shnum,
               shstrndx,
               shst,
               sections_dropped_or_rearranged,
               dynamic_idx, /* index in shdr_info[] of .dynamic section */
               dynsym_idx, /* index in shdr_info[] of dynamic symbol table */
               shady,
               &shstrtab_data,
               ehdr->e_type == ET_DYN, /* adjust section ofsets only when the file is a shared library */
               rebuild_shstrtab);

    /* We have everything from the old file. */
	FAILIF_LIBELF(elf_cntl(elf, ELF_C_FDDONE) != 0, elf_cntl);

	/* The ELF library better follows our layout when this is not a
	   relocatable object file. */
	elf_flagelf (newelf,
				 ELF_C_SET,
				 (ehdr->e_type != ET_REL ? ELF_F_LAYOUT : 0));

	/* Finally write the file. */
    FAILIF_LIBELF(!dry_run && elf_update(newelf, ELF_C_WRITE) == -1, elf_update);

	if (shdr_info != NULL) {
		/* For some sections we might have created an table to map symbol
           table indices. */
       for (cnt = 1; cnt < shdr_info_len; ++cnt) {
            FREEIF(shdr_info[cnt].newsymidx);
            FREEIF(shdr_info[cnt].symse);
            if(shdr_info[cnt].dynsymst != NULL)
                ebl_strtabfree (shdr_info[cnt].dynsymst);
        }
		/* Free the memory. */
		FREE (shdr_info);
	}
    FREEIF(phdr_info);

    ebl_closebackend(ebl);

	/* Free other resources. */
	if (shst != NULL) ebl_strtabfree (shst);
    if (shstrtab_data != NULL)
        FREEIF(shstrtab_data->d_buf);
}
Ejemplo n.º 20
0
static void
print_symtab(Elf *elf, const char *file)
{
	Elf_Scn		*scn = NULL;
	GElf_Shdr	shdr;
	GElf_Ehdr	ehdr;
	size_t		shstrndx;


	if (gelf_getehdr(elf, &ehdr) == NULL) {
		(void) fprintf(stderr, "%s: elf_getehdr() failed: %s\n",
		    file, elf_errmsg(0));
		return;
	}

	if (elf_getshdrstrndx(elf, &shstrndx) == -1) {
		(void) fprintf(stderr, "%s: elf_getshdrstrndx() failed: %s\n",
		    file, elf_errmsg(0));
		return;
	}

	while ((scn = elf_nextscn(elf, scn)) != NULL) {
		uint_t		symcnt, ndx, nosymshndx;
		Elf_Data	*symdata, *shndxdata;

		if (gelf_getshdr(scn, &shdr) == NULL) {
			(void) fprintf(stderr,
			    "%s: elf_getshdr() failed: %s\n",
			    file, elf_errmsg(0));
			return;
		}
		if ((shdr.sh_type != SHT_SYMTAB) &&
		    (shdr.sh_type != SHT_DYNSYM) &&
		    (shdr.sh_type != SHT_SUNW_LDYNSYM))
			continue;

		/*
		 * Get the data associated with the Symbol
		 * section.
		 */
		if ((symdata = elf_getdata(scn, NULL)) == NULL) {
			(void) fprintf(stderr,
			    "%s: elf_getdata() failed: %s\n",
			    file, elf_errmsg(0));
			return;
		}

		/*
		 * Print symbol table title and header for symbol display
		 */
		(void) printf("\nSymTab: %s:%s\n", file,
		    elf_strptr(elf, shstrndx, shdr.sh_name));
		(void) printf("  index   value    size     type "
		    "bind  oth shndx name\n");

		/*
		 * We now iterate over the full symbol table printing
		 * the symbols as we go.
		 */
		shndxdata = 0;
		nosymshndx = 0;
		symcnt = shdr.sh_size / shdr.sh_entsize;
		for (ndx = 0; ndx < symcnt; ndx++) {
			GElf_Sym	sym;
			Elf32_Word	shndx;
			uint_t		type, bind, specshndx;
			char		bindbuf[INTSTRLEN];
			char		typebuf[INTSTRLEN];
			char		shndxbuf[INTSTRLEN];
			const char	*bindstr, *typestr, *shndxstr;

			/*
			 * Get a symbol entry
			 */
			if (gelf_getsymshndx(symdata, shndxdata, ndx,
			    &sym, &shndx) == NULL) {
				(void) fprintf(stderr,
				    "%s: gelf_getsymshndx() failed: %s\n",
				    file, elf_errmsg(0));
				return;
			}
			/*
			 * Check to see if this symbol's st_shndx is using
			 * the 'Extended SHNDX table' for a SYMTAB.
			 *
			 * If it is - and we haven't searched before, go
			 * find the associated SHT_SYMTAB_SHNDX section.
			 */
			if ((sym.st_shndx == SHN_XINDEX) &&
			    (shndxdata == 0) && (nosymshndx == 0)) {
				Elf_Scn		*_scn = NULL;
				GElf_Shdr	_shdr;
				GElf_Word	symscnndx;

				specshndx = 0;
				symscnndx = elf_ndxscn(scn);

				while ((_scn =
				    elf_nextscn(elf, _scn)) != NULL) {
					if (gelf_getshdr(_scn, &_shdr) == NULL)
						break;

					/*
					 * We've found the Symtab SHNDX table
					 * if it's of type SHT_SYMTAB_SHNDX
					 * and it's shdr.sh_link points to the
					 * section index for the current symbol
					 * table.
					 */
					if ((_shdr.sh_type ==
					    SHT_SYMTAB_SHNDX) &&
					    (_shdr.sh_link == symscnndx) &&
					    ((shndxdata = elf_getdata(_scn,
					    NULL)) != NULL))
						break;
				}
				/*
				 * Get a symbol entry
				 */
				if (shndxdata &&
				    (gelf_getsymshndx(symdata, shndxdata, ndx,
				    &sym, &shndx) == NULL)) {
					(void) fprintf(stderr,
					    "%s: gelf_getsymshndx() "
					    "failed: %s\n",
					    file, elf_errmsg(0));
					return;
				}
				/*
				 * No Symtab SHNDX table was found.  We could
				 * give a fatal error here - instead we'll
				 * just mark that fact and display as much of
				 * the symbol table as we can.  Any symbol
				 * displayed with a XINDX section index has
				 * a bogus value.
				 */
				if (shndxdata == 0)
					nosymshndx = 1;
			}

			/*
			 * Decode the type & binding information
			 */
			type = GELF_ST_TYPE(sym.st_info);
			bind = GELF_ST_BIND(sym.st_info);

			if (type < STT_NUM)
				typestr = symtype[type];
			else {
				(void) snprintf(typebuf, INTSTRLEN,
				    "%d", type);
				typestr = typebuf;
			}

			if (bind < STB_NUM)
				bindstr = symbind[bind];
			else {
				(void) snprintf(bindbuf, INTSTRLEN,
				    "%d", bind);
				bindstr = bindbuf;
			}


			specshndx = 0;
			if (sym.st_shndx <  SHN_LORESERVE)
				shndx = sym.st_shndx;
			else if ((sym.st_shndx != SHN_XINDEX) ||
			    (shndxdata == NULL)) {
				shndx = sym.st_shndx;
				specshndx = 1;
			}

			if (shndx == SHN_UNDEF) {
				shndxstr = (const char *)"UNDEF";

			} else if (specshndx) {
				if (shndx == SHN_ABS)
					shndxstr = (const char *)"ABS";
				else if (shndx == SHN_COMMON)
					shndxstr = (const char *)"COMM";
				else if (shndx == SHN_XINDEX)
					shndxstr = (const char *)"XIND";
				else {
					(void) snprintf(shndxbuf, INTSTRLEN,
					    "%ld", shndx);
					shndxstr = shndxbuf;
				}
			} else {
				(void) snprintf(shndxbuf, INTSTRLEN,
				    "%ld", shndx);
				shndxstr = shndxbuf;
			}

			/*
			 * Display the symbol entry.
			 */
			(void) printf("[%3d] 0x%08llx 0x%08llx %-4s "
			    "%-6s %2d %5s %s\n",
			    ndx, sym.st_value, sym.st_size,
			    typestr, bindstr, sym.st_other, shndxstr,
			    elf_strptr(elf, shdr.sh_link, sym.st_name));
		}
	}
}
Ejemplo n.º 21
0
/*
 * Add the list of symbols in the given section to the list associated
 * with the object.
 */
void
pmcstat_image_add_symbols(struct pmcstat_image *image, Elf *e,
    Elf_Scn *scn, GElf_Shdr *sh)
{
	int firsttime;
	size_t n, newsyms, nshsyms, nfuncsyms;
	struct pmcstat_symbol *symptr;
	char *fnname;
	GElf_Sym sym;
	Elf_Data *data;

	if ((data = elf_getdata(scn, NULL)) == NULL)
		return;

	/*
	 * Determine the number of functions named in this
	 * section.
	 */

	nshsyms = sh->sh_size / sh->sh_entsize;
	for (n = nfuncsyms = 0; n < nshsyms; n++) {
		if (gelf_getsym(data, (int) n, &sym) != &sym)
			return;
		if (GELF_ST_TYPE(sym.st_info) == STT_FUNC)
			nfuncsyms++;
	}

	if (nfuncsyms == 0)
		return;

	/*
	 * Allocate space for the new entries.
	 */
	firsttime = image->pi_symbols == NULL;
	symptr = reallocarray(image->pi_symbols,
	    image->pi_symcount + nfuncsyms, sizeof(*symptr));
	if (symptr == image->pi_symbols) /* realloc() failed. */
		return;
	image->pi_symbols = symptr;

	/*
	 * Append new symbols to the end of the current table.
	 */
	symptr += image->pi_symcount;

	for (n = newsyms = 0; n < nshsyms; n++) {
		if (gelf_getsym(data, (int) n, &sym) != &sym)
			return;
		if (GELF_ST_TYPE(sym.st_info) != STT_FUNC)
			continue;

		if (sym.st_shndx == STN_UNDEF)
			continue;

		if (!firsttime && pmcstat_symbol_search(image, sym.st_value))
			continue; /* We've seen this symbol already. */

		if ((fnname = elf_strptr(e, sh->sh_link, sym.st_name))
		    == NULL)
			continue;
#ifdef __arm__
		/* Remove spurious ARM function name. */
		if (fnname[0] == '$' &&
		    (fnname[1] == 'a' || fnname[1] == 't' ||
		    fnname[1] == 'd') &&
		    fnname[2] == '\0')
			continue;
#endif

		symptr->ps_name  = pmcstat_string_intern(fnname);
		symptr->ps_start = sym.st_value - image->pi_vaddr;
		symptr->ps_end   = symptr->ps_start + sym.st_size;

		symptr++;
		newsyms++;
	}

	image->pi_symcount += newsyms;
	if (image->pi_symcount == 0)
		return;

	assert(newsyms <= nfuncsyms);

	/*
	 * Return space to the system if there were duplicates.
	 */
	if (newsyms < nfuncsyms)
		image->pi_symbols = reallocarray(image->pi_symbols,
		    image->pi_symcount, sizeof(*symptr));

	/*
	 * Keep the list of symbols sorted.
	 */
	qsort(image->pi_symbols, image->pi_symcount, sizeof(*symptr),
	    pmcstat_symbol_compare);

	/*
	 * Deal with function symbols that have a size of 'zero' by
	 * making them extend to the next higher address.  These
	 * symbols are usually defined in assembly code.
	 */
	for (symptr = image->pi_symbols;
	     symptr < image->pi_symbols + (image->pi_symcount - 1);
	     symptr++)
		if (symptr->ps_start == symptr->ps_end)
			symptr->ps_end = (symptr+1)->ps_start;
}
Ejemplo n.º 22
0
/**
 * Try to find the symbol closest to an address within a given ELF
 * section.
 *
 * Only function symbols are taken into account. The symbol's address
 * must precede `addr`. A symbol with a closer address might exist
 * after `addr` but is irrelevant because it cannot encompass `addr`.
 *
 * On success, if found, the out parameters `sym` and `shdr` are
 * set. On failure or if none are found, they remain unchanged.
 *
 * @param scn		ELF section in which to look for the address
 * @param addr		Virtual memory address for which to find the
 *			nearest function symbol
 * @param sym		Out parameter, the nearest function symbol
 * @param shdr		Out parameter, the section header for scn
 * @returns		0 on success, -1 on failure
 */
static
int bin_info_get_nearest_symbol_from_section(Elf_Scn *scn, uint64_t addr,
		GElf_Sym **sym, GElf_Shdr **shdr)
{
	int i;
	size_t symbol_count;
	Elf_Data *data = NULL;
	GElf_Shdr *_shdr = NULL;
	GElf_Sym *nearest_sym = NULL;

	if (!scn || !sym || !shdr) {
		goto error;
	}

	_shdr = g_new0(GElf_Shdr, 1);
	if (!_shdr) {
		goto error;
	}

	_shdr = gelf_getshdr(scn, _shdr);
	if (!_shdr) {
		goto error;
	}

	if (_shdr->sh_type != SHT_SYMTAB) {
		/*
		 * We are only interested in symbol table (symtab)
		 * sections, skip this one.
		 */
		goto end;
	}

	data = elf_getdata(scn, NULL);
	if (!data) {
		goto error;
	}

	symbol_count = _shdr->sh_size / _shdr->sh_entsize;

	for (i = 0; i < symbol_count; ++i) {
		GElf_Sym *cur_sym = NULL;

		cur_sym = g_new0(GElf_Sym, 1);
		if (!cur_sym) {
			goto error;
		}
		cur_sym = gelf_getsym(data, i, cur_sym);
		if (!cur_sym) {
			goto error;
		}
		if (GELF_ST_TYPE(cur_sym->st_info) != STT_FUNC) {
			/* We're only interested in the functions. */
			g_free(cur_sym);
			continue;
		}

		if (cur_sym->st_value <= addr &&
				(!nearest_sym ||
				cur_sym->st_value > nearest_sym->st_value)) {
			g_free(nearest_sym);
			nearest_sym = cur_sym;
		} else {
			g_free(cur_sym);
		}
	}

end:
	if (nearest_sym) {
		*sym = nearest_sym;
		*shdr = _shdr;
	} else {
		g_free(_shdr);
	}

	return 0;

error:
	g_free(nearest_sym);
	g_free(_shdr);
	return -1;
}
Ejemplo n.º 23
0
int
_elf_nlist(int fd, struct nlist * list)
{
	Elf	   *elfdes;	/* ELF descriptor */
	GElf_Ehdr  ehdr;	/* ELF Ehdr */
	GElf_Shdr  s_buf;	/* buffer storing section header */
	Elf_Data   *symdata;	/* buffer points to symbol table */
	Elf_Scn    *secidx = 0;	/* index of the section header table */
	GElf_Sym   sym;		/* buffer storing one symbol information */
	unsigned   strtab;	/* index of symbol name in string table */
	long	   count;	/* number of symbols */
	long	   ii;		/* loop control */

	if (elf_version(EV_CURRENT) == EV_NONE) {
		(void) close(fd);
		return (-1);
	}
	elfdes = elf_begin(fd, ELF_C_READ, (Elf *)0);
	if (gelf_getehdr(elfdes, &ehdr) == 0)
		return (end_elf_job(fd, elfdes));

	while ((secidx = elf_nextscn(elfdes, secidx)) != 0) {
		if ((gelf_getshdr(secidx, &s_buf)) == 0)
			return (end_elf_job(fd, elfdes));
		if (s_buf.sh_type != SHT_SYMTAB) /* not symbol table */
			continue;
		symdata = elf_getdata(secidx, (Elf_Data *)0);
		if (symdata == 0)
			return (end_elf_job(fd, elfdes));
		if (symdata->d_size == 0)
			break;
		strtab = s_buf.sh_link;
		count = symdata->d_size / s_buf.sh_entsize;
		for (ii = 1; ii < count; ++ii) {
			struct nlist *p;
			register char *name;
			/* LINTED */
			(void) gelf_getsym(symdata, (int)ii, &sym);
			name = elf_strptr(elfdes, strtab, (size_t)sym.st_name);
			if (name == 0)
				continue;
			for (p = list; p->n_name && p->n_name[0]; ++p) {
				if (strcmp(p->n_name, name))
					continue;
				p->n_value = (long)sym.st_value;
				p->n_type = GELF_ST_TYPE(sym.st_info);
				p->n_scnum = sym.st_shndx;
				break;
			}
		}
		break;
		/*
		 * Currently there is only one symbol table section
		 * in an object file, but this restriction may be
		 * relaxed in the future.
		 */
	}
	(void) elf_end(elfdes);
	(void) close(fd);
	return (0);
}
Ejemplo n.º 24
0
/*
 * Translate symbol table data particularly for sorting.
 * Input is the symbol table data structure, number of symbols,
 * opened ELF file, and the string table link offset.
 */
static SYM *
readsyms(Elf_Data * data, GElf_Sxword num, Elf *elf,
	unsigned int link, unsigned int symscnndx)
{
	SYM		*s, *buf;
	GElf_Sym	sym;
	Elf32_Word	*symshndx = 0;
	unsigned int	nosymshndx = 0;
	int		i;

	if ((buf = calloc(num, sizeof (SYM))) == NULL) {
		(void) fprintf(stderr, gettext("%s: cannot allocate memory\n"),
		    prog_name);
		return (NULL);
	}

	s = buf;	/* save pointer to head of array */

	for (i = 1; i < num; i++, buf++) {
		(void) gelf_getsym(data, i, &sym);

		buf->indx = i;
		/* allow to work on machines where NULL-derefs dump core */
		if (sym.st_name == 0)
			buf->name = "";
		else if (C_flag) {
			const char *dn;
			char *name = (char *)elf_strptr(elf, link, sym.st_name);
			dn = conv_demangle_name(name);
			if (strcmp(dn, name) == 0) {	/* Not demangled */
				if (exotic(name)) {
					name = FormatName(name, d_buf);
				}
			} else {  /* name demangled */
				name = FormatName(name, dn);
			}
			buf->name = name;
		}
		else
			buf->name = (char *)elf_strptr(elf, link, sym.st_name);

		buf->value	= sym.st_value;
		buf->size	= sym.st_size;
		buf->type	= GELF_ST_TYPE(sym.st_info);
		buf->bind	= GELF_ST_BIND(sym.st_info);
		buf->other	= sym.st_other;
		if ((sym.st_shndx == SHN_XINDEX) &&
		    (symshndx == 0) && (nosymshndx == 0)) {
			Elf_Scn		*_scn;
			GElf_Shdr	_shdr;
			_scn = 0;
			while ((_scn = elf_nextscn(elf, _scn)) != 0) {
				if (gelf_getshdr(_scn, &_shdr) == 0)
					break;
				if ((_shdr.sh_type == SHT_SYMTAB_SHNDX) &&
				    (_shdr.sh_link == symscnndx)) {
					Elf_Data	*_data;
					if ((_data = elf_getdata(_scn,
					    0)) != 0) {
						symshndx =
						    (Elf32_Word *)_data->d_buf;
						break;
					}
				}
			}
			nosymshndx = 1;
		}
		if ((symshndx) && (sym.st_shndx == SHN_XINDEX)) {
			buf->shndx = symshndx[i];
		} else {
			buf->shndx	= sym.st_shndx;
			if (sym.st_shndx >= SHN_LORESERVE)
				buf->flags |= FLG_SYM_SPECSEC;
		}
	}	/* end for loop */
	return (s);
}
Ejemplo n.º 25
0
int
main (void)
{
  int result = 0;
  size_t cnt;
  AsmCtx_t *ctx;
  Elf *elf;
  int fd;

  elf_version (EV_CURRENT);

  ctx = asm_begin (fname, false, EM_386, ELFCLASS32, ELFDATA2LSB);
  if (ctx == NULL)
    {
      printf ("cannot create assembler context: %s\n", asm_errmsg (-1));
      return 1;
    }

  if (asm_newabssym (ctx, "tst8-out.s", 4, 0xfeedbeef, STT_FILE, STB_LOCAL)
      == NULL)
    {
      printf ("cannot create absolute symbol: %s\n", asm_errmsg (-1));
      asm_abort (ctx);
      return 1;
    }

  /* Create the output file.  */
  if (asm_end (ctx) != 0)
    {
      printf ("cannot create output file: %s\n", asm_errmsg (-1));
      asm_abort (ctx);
      return 1;
    }

  /* Check the file.  */
  fd = open (fname, O_RDONLY);
  if (fd == -1)
    {
      printf ("cannot open generated file: %m\n");
      result = 1;
      goto out;
    }

  elf = elf_begin (fd, ELF_C_READ, NULL);
  if (elf == NULL)
    {
      printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1));
      result = 1;
      goto out_close;
    }
  if (elf_kind (elf) != ELF_K_ELF)
    {
      puts ("not a valid ELF file");
      result = 1;
      goto out_close2;
    }

  for (cnt = 1; 1; ++cnt)
    {
      Elf_Scn *scn;
      GElf_Shdr shdr_mem;
      GElf_Shdr *shdr;

      scn = elf_getscn (elf, cnt);
      if (scn == NULL)
	{
	  printf ("cannot get section %Zd: %s\n", cnt, elf_errmsg (-1));
	  result = 1;
	  continue;
	}

      shdr = gelf_getshdr (scn, &shdr_mem);
      if (shdr == NULL)
	{
	  printf ("cannot get section header for section %Zd: %s\n",
		  cnt, elf_errmsg (-1));
	  result = 1;
	  continue;
	}
      /* We are looking for the symbol table.  */
      if (shdr->sh_type != SHT_SYMTAB)
	continue;

      for (cnt = 1; cnt< (shdr->sh_size
			  / gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT));
	   ++cnt)
	{
	  GElf_Sym sym_mem;
	  GElf_Sym *sym;

	  if (cnt > 1)
	    {
	      puts ("too many symbol");
	      result = 1;
	      break;
	    }

	  sym = gelf_getsym (elf_getdata (scn, NULL), cnt, &sym_mem);
	  if (sym == NULL)
	    {
	      printf ("cannot get symbol %zu: %s\n", cnt, elf_errmsg (-1));
	      result = 1;
	    }
	  else
	    {
	      if (sym->st_shndx != SHN_ABS)
		{
		  printf ("expected common symbol, got section %u\n",
			  (unsigned int) sym->st_shndx);
		  result = 1;
		}

	      if (sym->st_value != 0xfeedbeef)
		{
		  printf ("requested value 0xfeedbeef, is %#" PRIxMAX "\n",
			  (uintmax_t) sym->st_value);
		  result = 1;
		}

	      if (sym->st_size != 4)
		{
		  printf ("requested size 4, is %" PRIuMAX "\n",
			  (uintmax_t) sym->st_value);
		  result = 1;
		}

	      if (GELF_ST_TYPE (sym->st_info) != STT_FILE)
		{
		  printf ("requested type FILE, is %u\n",
			  (unsigned int) GELF_ST_TYPE (sym->st_info));
		  result = 1;
		}
	    }
	}

      break;
    }

 out_close2:
  elf_end (elf);
 out_close:
  close (fd);
 out:
  /* We don't need the file anymore.  */
  unlink (fname);

  return result;
}
const char *
dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
		     GElf_Sym *closest_sym, GElf_Word *shndxp)
{
  int syments = INTUSE(dwfl_module_getsymtab) (mod);
  if (syments < 0)
    return NULL;

  /* Return true iff we consider ADDR to lie in the same section as SYM.  */
  GElf_Word addr_shndx = SHN_UNDEF;
  inline bool same_section (const GElf_Sym *sym, GElf_Word shndx)
    {
      /* For absolute symbols and the like, only match exactly.  */
      if (shndx >= SHN_LORESERVE)
	return sym->st_value == addr;

      /* Figure out what section ADDR lies in.  */
      if (addr_shndx == SHN_UNDEF)
	{
	  GElf_Addr mod_addr = dwfl_deadjust_st_value (mod, addr);
	  Elf_Scn *scn = NULL;
	  addr_shndx = SHN_ABS;
	  while ((scn = elf_nextscn (mod->symfile->elf, scn)) != NULL)
	    {
	      GElf_Shdr shdr_mem;
	      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
	      if (likely (shdr != NULL)
		  && mod_addr >= shdr->sh_addr
		  && mod_addr < shdr->sh_addr + shdr->sh_size)
		{
		  addr_shndx = elf_ndxscn (scn);
		  break;
		}
	    }
	}

      return shndx == addr_shndx;
    }

  /* Keep track of the closest symbol we have seen so far.
     Here we store only symbols with nonzero st_size.  */
  const char *closest_name = NULL;
  GElf_Word closest_shndx = SHN_UNDEF;

  /* Keep track of an eligible symbol with st_size == 0 as a fallback.  */
  const char *sizeless_name = NULL;
  GElf_Sym sizeless_sym = { 0, 0, 0, 0, 0, SHN_UNDEF };
  GElf_Word sizeless_shndx = SHN_UNDEF;

  /* Keep track of the lowest address a relevant sizeless symbol could have.  */
  GElf_Addr min_label = 0;

  /* Look through the symbol table for a matching symbol.  */
  inline void search_table (int start, int end)
    {
      for (int i = start; i < end; ++i)
	{
	  GElf_Sym sym;
	  GElf_Word shndx;
	  const char *name = INTUSE(dwfl_module_getsym) (mod, i, &sym, &shndx);
	  if (name != NULL && name[0] != '\0'
	      && sym.st_shndx != SHN_UNDEF
	      && sym.st_value <= addr
	      && GELF_ST_TYPE (sym.st_info) != STT_SECTION
	      && GELF_ST_TYPE (sym.st_info) != STT_FILE
	      && GELF_ST_TYPE (sym.st_info) != STT_TLS)
	    {
	      /* Even if we don't choose this symbol, its existence excludes
		 any sizeless symbol (assembly label) that is below its upper
		 bound.  */
	      if (sym.st_value + sym.st_size > min_label)
		min_label = sym.st_value + sym.st_size;

	      if (sym.st_size == 0 || addr - sym.st_value < sym.st_size)
		{
		  /* This symbol is a better candidate than the current one
		     if it's closer to ADDR or is global when it was local.  */
		  if (closest_name == NULL
		      || closest_sym->st_value < sym.st_value
		      || (GELF_ST_BIND (closest_sym->st_info)
			  < GELF_ST_BIND (sym.st_info)))
		    {
		      if (sym.st_size != 0)
			{
			  *closest_sym = sym;
			  closest_shndx = shndx;
			  closest_name = name;
			}
		      else if (closest_name == NULL
			       && sym.st_value >= min_label
			       && same_section (&sym, shndx))
			{
			  /* Handwritten assembly symbols sometimes have no
			     st_size.  If no symbol with proper size includes
			     the address, we'll use the closest one that is in
			     the same section as ADDR.  */
			  sizeless_sym = sym;
			  sizeless_shndx = shndx;
			  sizeless_name = name;
			}
		    }
		  /* When the beginning of its range is no closer,
		     the end of its range might be.  But do not
		     replace a global symbol with a local!  */
		  else if (sym.st_size != 0
			   && closest_sym->st_value == sym.st_value
			   && closest_sym->st_size > sym.st_size
			   && (GELF_ST_BIND (closest_sym->st_info)
			       <= GELF_ST_BIND (sym.st_info)))
		    {
		      *closest_sym = sym;
		      closest_shndx = shndx;
		      closest_name = name;
		    }
		}
	    }
	}
    }

  /* First go through global symbols.  mod->first_global is setup by
     dwfl_module_getsymtab to the index of the first global symbol in
     the module's symbol table, or -1 when unknown.  All symbols with
     local binding come first in the symbol table, then all globals.  */
  search_table (mod->first_global < 0 ? 1 : mod->first_global, syments);

  /* If we found nothing searching the global symbols, then try the locals.
     Unless we have a global sizeless symbol that matches exactly.  */
  if (closest_name == NULL && mod->first_global > 1
      && (sizeless_name == NULL || sizeless_sym.st_value != addr))
    search_table (1, mod->first_global);

  /* If we found no proper sized symbol to use, fall back to the best
     candidate sizeless symbol we found, if any.  */
  if (closest_name == NULL
      && sizeless_name != NULL && sizeless_sym.st_value >= min_label)
    {
      *closest_sym = sizeless_sym;
      closest_shndx = sizeless_shndx;
      closest_name = sizeless_name;
    }

  if (shndxp != NULL)
    *shndxp = closest_shndx;
  return closest_name;
}
Ejemplo n.º 27
0
int
proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which,
    int mask, proc_sym_f *func, void *cd)
{
	Elf *e;
	int i, fd;
	prmap_t *map;
	Elf_Scn *scn, *foundscn = NULL;
	Elf_Data *data;
	GElf_Shdr shdr;
	GElf_Sym sym;
	unsigned long stridx = -1;
	char *s;
	int error = -1;

	if ((map = proc_name2map(p, object)) == NULL)
		return (-1);
	if ((fd = open(map->pr_mapname, O_RDONLY)) < 0) {
		warn("ERROR: open %s failed", map->pr_mapname);
		goto err0;
	}
	if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
		warn("ERROR: elf_begin() failed");
		goto err1;
	}
	/*
	 * Find the section we are looking for.
	 */
	scn = NULL;
	while ((scn = elf_nextscn(e, scn)) != NULL) {
		gelf_getshdr(scn, &shdr);
		if (which == PR_SYMTAB && 
		    shdr.sh_type == SHT_SYMTAB) {
			foundscn = scn;
			break;
		} else if (which == PR_DYNSYM &&
		    shdr.sh_type == SHT_DYNSYM) {
			foundscn = scn;
			break;
		}
	}
	if (!foundscn)
		return (-1);
	stridx = shdr.sh_link;
	if ((data = elf_getdata(foundscn, NULL)) == NULL) {
		DPRINTF("ERROR: elf_getdata() failed");
		goto err2;
	}
	i = 0;
	while (gelf_getsym(data, i++, &sym) != NULL) {
		if (GELF_ST_BIND(sym.st_info) == STB_LOCAL &&
		    (mask & BIND_LOCAL) == 0)
			continue;
		if (GELF_ST_BIND(sym.st_info) == STB_GLOBAL &&
		    (mask & BIND_GLOBAL) == 0)
			continue;
		if (GELF_ST_BIND(sym.st_info) == STB_WEAK &&
		    (mask & BIND_WEAK) == 0)
			continue;
		if (GELF_ST_TYPE(sym.st_info) == STT_NOTYPE &&
		    (mask & TYPE_NOTYPE) == 0)
			continue;
		if (GELF_ST_TYPE(sym.st_info) == STT_OBJECT &&
		    (mask & TYPE_OBJECT) == 0)
			continue;
		if (GELF_ST_TYPE(sym.st_info) == STT_FUNC &&
		    (mask & TYPE_FUNC) == 0)
			continue;
		if (GELF_ST_TYPE(sym.st_info) == STT_SECTION &&
		    (mask & TYPE_SECTION) == 0)
			continue;
		if (GELF_ST_TYPE(sym.st_info) == STT_FILE &&
		    (mask & TYPE_FILE) == 0)
			continue;
		s = elf_strptr(e, stridx, sym.st_name);
		sym.st_value += map->pr_vaddr;
		(*func)(cd, &sym, s);
	}
	error = 0;
err2:
	elf_end(e);
err1:
	close(fd);
err0:
	free(map);
	return (error);
}
Ejemplo n.º 28
0
/*
 * scan the ELF image to build table of global symbold and the image
 * regions where they can be found (BSS and DATA)
 */
static inline int
table_init_helper (void)
{
    Elf *e = NULL;
    GElf_Ehdr ehdr;
    char *shstr_name = NULL;
    size_t shstrndx;
    Elf_Scn *scn = NULL;
    GElf_Shdr shdr;
    int ret = -1;
#if 0
    int (*getsi) ();            /* look up name of elf_get... routine */
#endif

    /* unrecognized format */
    if (elf_version (EV_CURRENT) == EV_NONE) {
        goto bail;
    }

    /* get the ELF object from already opened state */
    e = elf_begin (GET_STATE (exe_fd), ELF_C_READ, NULL);
    if (e == NULL) {
        goto bail;
    }

    /* do some sanity checks */
    if (elf_kind (e) != ELF_K_ELF) {
        goto bail;
    }
    if (gelf_getehdr (e, &ehdr) == NULL) {
        goto bail;
    }
    if (gelf_getclass (e) == ELFCLASSNONE) {
        goto bail;
    }

    /*
     * There are various elf_get* routines with different return values
     * in differnt libraries/versions - name of routine does not tell us
     * all we ned to know.  So let it go here, and we'll mop up any
     * problems later on.
     */

    /*
     * This routine is either "elf_getshdrstrndx" in newer ELF
     * libraries, or "elf_getshstrndx" in older ones.  Hard-code older
     * one for now since it is in the newer libraries, although marked as
     * deprecated.  This will be detected by autoconf later
     *
     * DEPRECATED
     */
    (void) elf_getshstrndx (e, &shstrndx);

    /* walk sections, look for RO/BSS/DATA and symbol table */
    scn = NULL;

    while ((scn = elf_nextscn (e, scn)) != NULL) {

        if (gelf_getshdr (scn, &shdr) != &shdr) {
            goto bail;
        }
        shstr_name = elf_strptr (e, shstrndx, shdr.sh_name);
        if (shstr_name == NULL) {
            goto bail;
        }

        /* found the read-only data */
        if (shdr.sh_type == SHT_PROGBITS && strcmp (shstr_name, ".rodata") == 0) {

            elfro.start = shdr.sh_addr;
            elfro.end = elfro.start + shdr.sh_size;

            shmemi_trace (SHMEM_LOG_SYMBOLS,
                          "ELF section .rodata for global variables = 0x%lX -> 0x%lX",
                          elfro.start, elfro.end);
            continue;           /* move to next scan */
        }

        /* found the uninitialized globals */
        if (shdr.sh_type == SHT_NOBITS && strcmp (shstr_name, ".bss") == 0) {

            elfbss.start = shdr.sh_addr;
            elfbss.end = elfbss.start + shdr.sh_size;

            shmemi_trace (SHMEM_LOG_SYMBOLS,
                          "ELF section .bss for global variables = 0x%lX -> 0x%lX",
                          elfbss.start, elfbss.end);
            continue;           /* move to next scan */
        }

        /* found the initialized globals */
        if (shdr.sh_type == SHT_PROGBITS && strcmp (shstr_name, ".data") == 0) {

            elfdata.start = shdr.sh_addr;
            elfdata.end = elfdata.start + shdr.sh_size;

            shmemi_trace (SHMEM_LOG_SYMBOLS,
                          "ELF section .data for global variables = 0x%lX -> 0x%lX",
                          elfdata.start, elfdata.end);
            continue;           /* move to next scan */
        }

        /* keep looking until we find the symbol table */
        if (shdr.sh_type == SHT_SYMTAB) {
            Elf_Data *data = NULL;
            while ((data = elf_getdata (scn, data)) != NULL) {
                GElf_Sym *es;
                GElf_Sym *last_es;

                es = (GElf_Sym *) data->d_buf;
                if (es == NULL) {
                    continue;
                }

                /* find out how many entries to look for */
                last_es = (GElf_Sym *) ((char *) data->d_buf + data->d_size);

                for (; es < last_es; es += 1) {
                    char *name;

                    /*
                     * need visible global or local (Fortran save) object with
                     * some kind of content
                     */
                    if (es->st_value == 0 || es->st_size == 0) {
                        continue;
                    }
                    /*
                     * this macro handles a symbol that is present
                     * in one libelf implementation but isn't in another
                     * (elfutils vs. libelf)
                     */
#ifndef GELF_ST_VISIBILITY
#define GELF_ST_VISIBILITY(o) ELF64_ST_VISIBILITY(o)
#endif
                    if (GELF_ST_TYPE (es->st_info) != STT_OBJECT &&
                        GELF_ST_VISIBILITY (es->st_info) != STV_DEFAULT) {
                        continue;
                    }
                    name = elf_strptr (e, shdr.sh_link, (size_t) es->st_name);
                    if (name == NULL || *name == '\0') {
                        continue;
                    }
                    /* put the symbol and info into the symbol hash table */
                    {
                        globalvar_t *gv = (globalvar_t *) malloc (sizeof (*gv));
                        if (gv == NULL) {
                            goto bail;
                        }
                        gv->name = strdup (name);
                        if (gv->name == NULL) {
                            free (gv);
                            goto bail;
                        }
                        gv->addr = (void *) es->st_value;
                        gv->size = es->st_size;
                        HASH_ADD_PTR (gvp, addr, gv);
                    }
                }
            }
            /*
             * pulled out all the global symbols => success,
             * don't need to scan further
             */
            ret = 0;
            break;
        }
    }

  bail:

    if (elf_end (e) != 0) {
        ret = -1;
    }

    return ret;
}