Example #1
0
ATF_TC_BODY(symbol_sort_local, tc)
{
	char symname[32];
	GElf_Sym bar_sym;
	struct proc_handle *phdl;
	int error;

	phdl = start_prog(tc, true);

	error = proc_name2sym(phdl, target_prog_file, "bar", &bar_sym, NULL);
	ATF_REQUIRE_MSG(error == 0, "failed to look up 'bar' in %s",
	    target_prog_file);
	ATF_REQUIRE(GELF_ST_BIND(bar_sym.st_info) == STB_LOCAL);

	error = proc_addr2sym(phdl, bar_sym.st_value, symname, sizeof(symname),
	    &bar_sym);
	ATF_REQUIRE_MSG(error == 0, "failed to resolve 'bar' by addr");

	ATF_REQUIRE_MSG(strcmp(symname, "baz") == 0,
	    "unexpected symbol name '%s'", symname);
	ATF_REQUIRE(GELF_ST_BIND(bar_sym.st_info) == STB_GLOBAL);
}
Example #2
0
/* Given Elf header, Elf_Scn, and Elf32_Shdr 
 * print out the symbol table 
 */
static _Bool print_symbols(Elf *elf, Elf_Scn *scn, GElf_Shdr *shdr)
{
	Elf_Data *data;
	char *name;
	char *stringName;
	data = 0;
	int number = 0;
	if ((data = elf_getdata(scn, data)) == 0 || data->d_size == 0)
	{
		/* error or no data */
		fprintf(stderr, "Section had no data!\n");
			exit(-1);
	}
	/*now print the symbols*/
	unsigned count = symtab_shdr.sh_size / symtab_shdr.sh_entsize;
	//fprintf(stderr, "Total symbols count: %u\n", count);
	/* now loop through the symbol table and print it*/
	for (unsigned i = 0; i < count; ++i)
	{
		//fprintf(stderr, "Index is %u\n", i);
		GElf_Sym esym;
		GElf_Sym *ret = gelf_getsym(data, i, &esym);
		if (ret == 0) { fprintf(stderr, "Error!\n"); return FALSE; }
		if ((esym.st_value == 0) ||
			(GELF_ST_BIND(esym.st_info)== STB_WEAK) ||
			(GELF_ST_BIND(esym.st_info)== STB_NUM)) 
				continue;
		//fprintf(stderr, "Symbol has strtab offset %zu\n", (size_t)esym.st_name);
		name = elf_strptr(elf, shdr->sh_link, (size_t)esym.st_name);
		if(!name)
		{
			fprintf(stderr,"%s\n",elf_errmsg(elf_errno()));
			exit(-1);
		}
		printf("%d: %s\n", number++, name);
	}
	return TRUE;
}
Example #3
0
static const char *
nm_bind2str(uchar_t info)
{
	switch (GELF_ST_BIND(info)) {
	case STB_LOCAL:
		return ("LOCL");
	case STB_GLOBAL:
		return ("GLOB");
	case STB_WEAK:
		return ("WEAK");
	default:
		return ("?");
	}
}
Example #4
0
static int
gelf_bind_order (GElf_Sym *sym)
{
  switch (GELF_ST_BIND (sym->st_info))
    {
    case STB_LOCAL:
      return 1;
    case STB_WEAK:
      return 2;
    case STB_GLOBAL:
      return 3;
    default:
      return 0;
    }
}
Example #5
0
static const char *
gelf_bind (GElf_Sym *sym)
{
  switch (GELF_ST_BIND (sym->st_info))
    {
    case STB_LOCAL:
      return "LOCAL";
    case STB_GLOBAL:
      return "GLOBAL";
    case STB_WEAK:
      return "WEAK";
    default:
      return "UNKNOWN";
    }
}
Example #6
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);
}
Example #7
0
static void parse_symbol_table(Elf_Data *symbol_table_data,
				const GElf_Shdr *symbol_table_header,
				struct radeon_shader_binary *binary)
{
	GElf_Sym symbol;
	unsigned i = 0;
	unsigned symbol_count =
		symbol_table_header->sh_size / symbol_table_header->sh_entsize;

	/* We are over allocating this list, because symbol_count gives the
 	 * total number of symbols, and we will only be filling the list
 	 * with offsets of global symbols.  The memory savings from
 	 * allocating the correct size of this list will be small, and
 	 * I don't think it is worth the cost of pre-computing the number
 	 * of global symbols.
 	 */
	binary->global_symbol_offsets = CALLOC(symbol_count, sizeof(uint64_t));

	while (gelf_getsym(symbol_table_data, i++, &symbol)) {
		unsigned i;
		if (GELF_ST_BIND(symbol.st_info) != STB_GLOBAL ||
		    symbol.st_shndx == 0 /* Undefined symbol */) {
			continue;
		}

		binary->global_symbol_offsets[binary->global_symbol_count] =
					symbol.st_value;

		/* Sort the list using bubble sort.  This list will usually
		 * be small. */
		for (i = binary->global_symbol_count; i > 0; --i) {
			uint64_t lhs = binary->global_symbol_offsets[i - 1];
			uint64_t rhs = binary->global_symbol_offsets[i];
			if (lhs < rhs) {
				break;
			}
			binary->global_symbol_offsets[i] = lhs;
			binary->global_symbol_offsets[i - 1] = rhs;
		}
		++binary->global_symbol_count;
	}
}
Example #8
0
File: ctf.c Project: DataIX/src
static void
resurrect_objects(ctf_header_t *h, tdata_t *td, tdesc_t **tdarr, int tdsize,
    caddr_t ctfdata, symit_data_t *si)
{
	caddr_t buf = ctfdata + h->cth_objtoff;
	size_t bufsz = h->cth_funcoff - h->cth_objtoff;
	caddr_t dptr;

	symit_reset(si);
	for (dptr = buf; dptr < buf + bufsz; dptr += 2) {
		void *v = (void *) dptr;
		ushort_t id = *((ushort_t *)v);
		iidesc_t *ii;
		GElf_Sym *sym;

		if (!(sym = symit_next(si, STT_OBJECT)) && id != 0) {
			parseterminate(
			    "Unexpected end of object symbols at %x of %x",
			    dptr - buf, bufsz);
		}

		if (id == 0) {
			debug(3, "Skipping null object\n");
			continue;
		} else if (id >= tdsize) {
			parseterminate("Reference to invalid type %d", id);
		}

		ii = iidesc_new(symit_name(si));
		ii->ii_dtype = tdarr[id];
		if (GELF_ST_BIND(sym->st_info) == STB_LOCAL) {
			ii->ii_type = II_SVAR;
			ii->ii_owner = xstrdup(symit_curfile(si));
		} else
			ii->ii_type = II_GVAR;
		hash_add(td->td_iihash, ii);

		debug(3, "Resurrected %s object %s (%d) from %s\n",
		    (ii->ii_type == II_GVAR ? "global" : "static"),
		    ii->ii_name, id, (ii->ii_owner ? ii->ii_owner : "(none)"));
	}
}
Example #9
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);
}
Example #10
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);
}
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;
}
Example #12
0
File: ctf.c Project: DataIX/src
static void
resurrect_functions(ctf_header_t *h, tdata_t *td, tdesc_t **tdarr, int tdsize,
    caddr_t ctfdata, symit_data_t *si)
{
	caddr_t buf = ctfdata + h->cth_funcoff;
	size_t bufsz = h->cth_typeoff - h->cth_funcoff;
	caddr_t dptr = buf;
	iidesc_t *ii;
	ushort_t info;
	ushort_t retid;
	GElf_Sym *sym;
	int i;

	symit_reset(si);
	while (dptr < buf + bufsz) {
		void *v = (void *) dptr;
		info = *((ushort_t *)v);
		dptr += 2;

		if (!(sym = symit_next(si, STT_FUNC)) && info != 0)
			parseterminate("Unexpected end of function symbols");

		if (info == 0) {
			debug(3, "Skipping null function (%s)\n",
			    symit_name(si));
			continue;
		}

		v = (void *) dptr;
		retid = *((ushort_t *)v);
		dptr += 2;

		if (retid >= tdsize)
			parseterminate("Reference to invalid type %d", retid);

		ii = iidesc_new(symit_name(si));
		ii->ii_dtype = tdarr[retid];
		if (GELF_ST_BIND(sym->st_info) == STB_LOCAL) {
			ii->ii_type = II_SFUN;
			ii->ii_owner = xstrdup(symit_curfile(si));
		} else
			ii->ii_type = II_GFUN;
		ii->ii_nargs = CTF_INFO_VLEN(info);
		if (ii->ii_nargs)
			ii->ii_args =
			    xmalloc(sizeof (tdesc_t *) * ii->ii_nargs);

		for (i = 0; i < ii->ii_nargs; i++, dptr += 2) {
			v = (void *) dptr;
			ushort_t id = *((ushort_t *)v);
			if (id >= tdsize)
				parseterminate("Reference to invalid type %d",
				    id);
			ii->ii_args[i] = tdarr[id];
		}

		if (ii->ii_nargs && ii->ii_args[ii->ii_nargs - 1] == NULL) {
			ii->ii_nargs--;
			ii->ii_vargs = 1;
		}

		hash_add(td->td_iihash, ii);

		debug(3, "Resurrected %s function %s (%d, %d args)\n",
		    (ii->ii_type == II_GFUN ? "global" : "static"),
		    ii->ii_name, retid, ii->ii_nargs);
	}
}
/* Handle an undefined symbol.  We really only support ET_REL for Linux
   kernel modules, and offline archives.  The behavior of the Linux module
   loader is very simple and easy to mimic.  It only matches magically
   exported symbols, and we match any defined symbols.  But we get the same
   answer except when the module's symbols are undefined and would prevent
   it from being loaded.  */
static Dwfl_Error
resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
		GElf_Sym *sym, GElf_Word shndx)
{
  /* First we need its name.  */
  if (sym->st_name != 0)
    {
      if (symtab->symstrdata == NULL)
	{
	  /* Cache the strtab for this symtab.  */
	  assert (referer->symfile == NULL
		  || referer->symfile->elf != symtab->symelf);
	  symtab->symstrdata = elf_getdata (elf_getscn (symtab->symelf,
							symtab->strtabndx),
					    NULL);
	  if (unlikely (symtab->symstrdata == NULL))
	    return DWFL_E_LIBELF;
	}
      if (unlikely (sym->st_name >= symtab->symstrdata->d_size))
	return DWFL_E_BADSTROFF;

      const char *name = symtab->symstrdata->d_buf;
      name += sym->st_name;

      for (Dwfl_Module *m = referer->dwfl->modulelist; m != NULL; m = m->next)
	if (m != referer)
	  {
	    /* Get this module's symtab.
	       If we got a fresh error reading the table, report it.
	       If we just have no symbols in this module, no harm done.  */
	    if (m->symdata == NULL
		&& m->symerr == DWFL_E_NOERROR
		&& INTUSE(dwfl_module_getsymtab) (m) < 0
		&& m->symerr != DWFL_E_NO_SYMTAB)
	      return m->symerr;

	    for (size_t ndx = 1; ndx < m->syments; ++ndx)
	      {
		sym = gelf_getsymshndx (m->symdata, m->symxndxdata,
					ndx, sym, &shndx);
		if (unlikely (sym == NULL))
		  return DWFL_E_LIBELF;
		if (sym->st_shndx != SHN_XINDEX)
		  shndx = sym->st_shndx;

		/* We are looking for a defined global symbol with a name.  */
		if (shndx == SHN_UNDEF || shndx == SHN_COMMON
		    || GELF_ST_BIND (sym->st_info) == STB_LOCAL
		    || sym->st_name == 0)
		  continue;

		/* Get this candidate symbol's name.  */
		if (unlikely (sym->st_name >= m->symstrdata->d_size))
		  return DWFL_E_BADSTROFF;
		const char *n = m->symstrdata->d_buf;
		n += sym->st_name;

		/* Does the name match?  */
		if (strcmp (name, n))
		  continue;

		/* We found it!  */
		if (shndx == SHN_ABS) /* XXX maybe should apply bias? */
		  return DWFL_E_NOERROR;

		if (m->e_type != ET_REL)
		  {
		    sym->st_value = dwfl_adjusted_st_value (m, sym->st_value);
		    return DWFL_E_NOERROR;
		  }

		/* 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;
		return __libdwfl_relocate_value (m, m->symfile->elf,
						 &symshstrndx,
						 shndx, &sym->st_value);
	      }
	  }
    }

  return DWFL_E_RELUNDEF;
}
Example #14
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));
		}
	}
}
Example #15
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);
}
Example #16
0
static retc_t
addr_map_sym(map_info_t *mp, ulong_t addr, GElf_Sym *symptr, char **str)
{
	sym_tbl_t	*symp;
	GElf_Sym	sym;
	GElf_Sym	*symr = NULL;
	GElf_Sym	*lsymr = NULL;
	GElf_Sym	rsym;
	GElf_Sym	lsym;
	ulong_t		baseaddr = 0;
	int		i;

	if ((mp->mi_flags & FLG_MI_EXEC) == 0)
		baseaddr = (ulong_t)mp->mi_addr;

	if (mp->mi_symtab.st_syms_pri)
		symp = &(mp->mi_symtab);
	else if (mp->mi_dynsym.st_syms_pri)
		symp = &(mp->mi_dynsym);
	else
		return (RET_FAILED);

	/*
	 * normalize address
	 */
	addr -= baseaddr;
	for (i = 0; i < (int)symp->st_symn; i++) {
		ulong_t	svalue;

		if (symtab_getsym(symp, i, &sym) == NULL) {
			(void) printf("symtab_getsym(): %s\n", elf_errmsg(-1));
			return (RET_FAILED);
		}
		if ((sym.st_name == 0) || (sym.st_shndx == SHN_UNDEF))
			continue;

		svalue = (ulong_t)sym.st_value;

		if (svalue <= addr) {
			/*
			 * track both the best local and best
			 * global fit for this address.  Later
			 * we will favor the global over the local
			 */
			if ((GELF_ST_BIND(sym.st_info) == STB_LOCAL) &&
			    ((lsymr == NULL) ||
			    (svalue >= (ulong_t)lsymr->st_value))) {
				if (lsymr && (lsymr->st_value == svalue))
					*lsymr = sym_swap(lsymr, &sym);
				else {
					lsymr = &lsym;
					*lsymr = sym;
				}
			} else if ((symr == NULL) ||
			    (svalue >= (ulong_t)symr->st_value)) {
				if (symr && (symr->st_value == svalue))
					*symr = sym_swap(symr, &sym);
				else {
					symr = &rsym;
					*symr = sym;
				}
			}
		}
	}
	if ((symr == NULL) && (lsymr == NULL))
		return (RET_FAILED);

	if (lsymr) {
		/*
		 * If a possible local symbol was found should
		 * we use it.
		 */
		if (symr && (lsymr->st_value > symr->st_value))
			symr = lsymr;
		else if (symr == NULL)
			symr = lsymr;
	}

	*symptr = *symr;
	*str = (char *)(symp->st_strs + symptr->st_name);
	symptr->st_value += baseaddr;
	return (RET_OK);
}