Blame libelf/nlist.c

Packit Service 97d2fb
/* Extract symbol list from binary.
Packit Service 97d2fb
   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005, 2007, 2015 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
Packit Service 97d2fb
   Written by Ulrich Drepper <drepper@redhat.com>, 1998.
Packit Service 97d2fb
Packit Service 97d2fb
   This file is free software; you can redistribute it and/or modify
Packit Service 97d2fb
   it under the terms of either
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU Lesser General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 3 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 2 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or both in parallel, as here.
Packit Service 97d2fb
Packit Service 97d2fb
   elfutils is distributed in the hope that it will be useful, but
Packit Service 97d2fb
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 97d2fb
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 97d2fb
   General Public License for more details.
Packit Service 97d2fb
Packit Service 97d2fb
   You should have received copies of the GNU General Public License and
Packit Service 97d2fb
   the GNU Lesser General Public License along with this program.  If
Packit Service 97d2fb
   not, see <http://www.gnu.org/licenses/>.  */
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef HAVE_CONFIG_H
Packit Service 97d2fb
# include <config.h>
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
#include <fcntl.h>
Packit Service 97d2fb
#include <gelf.h>
Packit Service 97d2fb
#include <libelf.h>
Packit Service 97d2fb
#include <nlist.h>
Packit Service 97d2fb
#include <unistd.h>
Packit Service 97d2fb
Packit Service 97d2fb
#include "libelfP.h"
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
struct hashentry
Packit Service 97d2fb
{
Packit Service 97d2fb
  const char *str;
Packit Service 97d2fb
  GElf_Sym sym;
Packit Service 97d2fb
};
Packit Service 97d2fb
#define TYPE struct hashentry
Packit Service 97d2fb
/* XXX Use a better hash function some day.  */
Packit Service 97d2fb
#define HASHFCT(str, len) INTUSE(elf_hash) (str)
Packit Service 97d2fb
#define COMPARE(p1, p2) strcmp ((p1)->str, (p2)->str)
Packit Service 97d2fb
#define CLASS static
Packit Service 97d2fb
#define PREFIX nlist_
Packit Service 97d2fb
#define xcalloc(n, m) calloc (n, m)
Packit Service 97d2fb
#define next_prime(s) __libelf_next_prime (s)
Packit Service 97d2fb
#include <fixedsizehash.h>
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
nlist (const char *filename, struct nlist *nl)
Packit Service 97d2fb
{
Packit Service 97d2fb
  int fd;
Packit Service 97d2fb
  Elf *elf;
Packit Service 97d2fb
  Elf_Scn *scn = NULL;
Packit Service 97d2fb
  Elf_Scn *symscn = NULL;
Packit Service 97d2fb
  GElf_Shdr shdr_mem;
Packit Service 97d2fb
  GElf_Shdr *shdr = NULL;
Packit Service 97d2fb
  Elf_Data *data;
Packit Service 97d2fb
  struct nlist_fshash *table;
Packit Service 97d2fb
  size_t nsyms;
Packit Service 97d2fb
  size_t cnt;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Open the file.  */
Packit Service 97d2fb
  fd = open (filename, O_RDONLY);
Packit Service 97d2fb
  if (fd == -1)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libelf_seterrno (ELF_E_NOFILE);
Packit Service 97d2fb
      goto fail;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* For compatibility reasons (`nlist' existed before ELF and libelf)
Packit Service 97d2fb
     we don't expect the caller to set the ELF version.  Do this here
Packit Service 97d2fb
     as if it hasn't happened yet.  */
Packit Service 97d2fb
  INTUSE(elf_version) (EV_CURRENT);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Now get an ELF descriptor.  */
Packit Service 97d2fb
  elf = INTUSE(elf_begin) (fd, ELF_C_READ_MMAP, NULL);
Packit Service 97d2fb
  if (elf == NULL)
Packit Service 97d2fb
    goto fail_fd;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Find a symbol table.  We prefer the real symbol table but if it
Packit Service 97d2fb
     does not exist use the dynamic symbol table.  */
Packit Service 97d2fb
  while ((scn = INTUSE(elf_nextscn) (elf, scn)) != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      shdr = INTUSE(gelf_getshdr) (scn, &shdr_mem);
Packit Service 97d2fb
      if (shdr == NULL)
Packit Service 97d2fb
	goto fail_close;
Packit Service 97d2fb
Packit Service 97d2fb
      /* That is what we are looking for.  */
Packit Service 97d2fb
      if (shdr->sh_type == SHT_SYMTAB)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  symscn = scn;
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Better than nothing.  Remember this section.  */
Packit Service 97d2fb
      if (shdr->sh_type == SHT_DYNSYM)
Packit Service 97d2fb
	symscn = scn;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (symscn == NULL)
Packit Service 97d2fb
    /* We haven't found anything.  Fail.  */
Packit Service 97d2fb
    goto fail_close;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Re-get the section header in case we found only the dynamic symbol
Packit Service 97d2fb
     table.  */
Packit Service 97d2fb
  if (scn == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      shdr = INTUSE(gelf_getshdr) (symscn, &shdr_mem);
Packit Service 97d2fb
      if (unlikely (shdr == NULL))
Packit Service 97d2fb
	goto fail_close;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  /* SHDR->SH_LINK now contains the index of the string section.  */
Packit Service 97d2fb
Packit Service 97d2fb
  /* Get the data for the symbol section.  */
Packit Service 97d2fb
  data = INTUSE(elf_getdata) (symscn, NULL);
Packit Service 97d2fb
  if (data == NULL)
Packit Service 97d2fb
    goto fail_close;
Packit Service 97d2fb
Packit Service 97d2fb
  /* How many symbols are there?  */
Packit Service 97d2fb
  nsyms = (shdr->sh_size
Packit Service 97d2fb
	   / INTUSE(gelf_fsize) (elf, ELF_T_SYM, 1, EV_CURRENT));
Packit Service 97d2fb
Packit Service 97d2fb
  /* Create the hash table.  */
Packit Service 97d2fb
  table = nlist_fshash_init (nsyms);
Packit Service 97d2fb
  if (table == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libelf_seterrno (ELF_E_NOMEM);
Packit Service 97d2fb
      goto fail_close;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Iterate over all the symbols in the section.  */
Packit Service 97d2fb
  for (cnt = 0; cnt < nsyms; ++cnt)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      struct hashentry mem;
Packit Service 97d2fb
      GElf_Sym *sym;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Get the symbol.  */
Packit Service 97d2fb
      sym = INTUSE(gelf_getsym) (data, cnt, &mem.sym);
Packit Service 97d2fb
      if (sym == NULL)
Packit Service 97d2fb
	goto fail_dealloc;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Get the name of the symbol.  */
Packit Service 97d2fb
      mem.str = INTUSE(elf_strptr) (elf, shdr->sh_link, sym->st_name);
Packit Service 97d2fb
      if (mem.str == NULL)
Packit Service 97d2fb
	goto fail_dealloc;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Don't allow zero-length strings.  */
Packit Service 97d2fb
      if (mem.str[0] == '\0')
Packit Service 97d2fb
	continue;
Packit Service 97d2fb
Packit Service 97d2fb
      /* And add it to the hash table.  Note that we are using the
Packit Service 97d2fb
         overwrite version.  This will ensure that
Packit Service 97d2fb
	 a) global symbols are preferred over local symbols since
Packit Service 97d2fb
	    they are all located at the end
Packit Service 97d2fb
	 b) if there are multiple local symbols with the same name
Packit Service 97d2fb
	    the last one is used.
Packit Service 97d2fb
      */
Packit Service 97d2fb
      (void) nlist_fshash_overwrite (table, mem.str, 0, &mem;;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Now it is time to look for the symbols the user asked for.
Packit Service 97d2fb
     XXX What is a `null name/null string'?  This is what the
Packit Service 97d2fb
     standard says terminates the list.  Is it a null pointer
Packit Service 97d2fb
     or a zero-length string?  We test for both...  */
Packit Service 97d2fb
  while (nl->n_name != NULL && nl->n_name[0] != '\0')
Packit Service 97d2fb
    {
Packit Service 97d2fb
      struct hashentry search;
Packit Service 97d2fb
      const struct hashentry *found;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Search for a matching entry in the hash table.  */
Packit Service 97d2fb
      search.str = nl->n_name;
Packit Service 97d2fb
      found = nlist_fshash_find (table, nl->n_name, 0, &search);
Packit Service 97d2fb
Packit Service 97d2fb
      if (found != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Found it.  */
Packit Service 97d2fb
	  nl->n_value = found->sym.st_value;
Packit Service 97d2fb
	  nl->n_scnum = found->sym.st_shndx;
Packit Service 97d2fb
	  nl->n_type = GELF_ST_TYPE (found->sym.st_info);
Packit Service 97d2fb
	  /* XXX What shall we fill in the next fields?  */
Packit Service 97d2fb
	  nl->n_sclass = 0;
Packit Service 97d2fb
	  nl->n_numaux = 0;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Not there.  */
Packit Service 97d2fb
	  nl->n_value = 0;
Packit Service 97d2fb
	  nl->n_scnum = 0;
Packit Service 97d2fb
	  nl->n_type = 0;
Packit Service 97d2fb
	  nl->n_sclass = 0;
Packit Service 97d2fb
	  nl->n_numaux = 0;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Next search request.  */
Packit Service 97d2fb
      ++nl;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Free the resources.  */
Packit Service 97d2fb
  nlist_fshash_fini (table);
Packit Service 97d2fb
Packit Service 97d2fb
  /* We do not need the ELF descriptor anymore.  */
Packit Service 97d2fb
  (void) INTUSE(elf_end) (elf);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Neither the file descriptor.  */
Packit Service 97d2fb
  (void) close (fd);
Packit Service 97d2fb
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
Packit Service 97d2fb
 fail_dealloc:
Packit Service 97d2fb
  nlist_fshash_fini (table);
Packit Service 97d2fb
Packit Service 97d2fb
 fail_close:
Packit Service 97d2fb
  /* We do not need the ELF descriptor anymore.  */
Packit Service 97d2fb
  (void) INTUSE(elf_end) (elf);
Packit Service 97d2fb
Packit Service 97d2fb
 fail_fd:
Packit Service 97d2fb
  /* Neither the file descriptor.  */
Packit Service 97d2fb
  (void) close (fd);
Packit Service 97d2fb
Packit Service 97d2fb
 fail:
Packit Service 97d2fb
  /* We have to set all entries to zero.  */
Packit Service 97d2fb
  while (nl->n_name != NULL && nl->n_name[0] != '\0')
Packit Service 97d2fb
    {
Packit Service 97d2fb
      nl->n_value = 0;
Packit Service 97d2fb
      nl->n_scnum = 0;
Packit Service 97d2fb
      nl->n_type = 0;
Packit Service 97d2fb
      nl->n_sclass = 0;
Packit Service 97d2fb
      nl->n_numaux = 0;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Next entry.  */
Packit Service 97d2fb
      ++nl;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return -1;
Packit Service 97d2fb
}