Blame tests/dwflsyms.c

Packit Service 97d2fb
/* Test program for libdwfl symbol resolving
Packit Service 97d2fb
   Copyright (C) 2013 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
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 the GNU General Public License as published by
Packit Service 97d2fb
   the Free Software Foundation; either version 3 of the License, or
Packit Service 97d2fb
   (at your option) any later version.
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
Packit Service 97d2fb
   GNU General Public License for more details.
Packit Service 97d2fb
Packit Service 97d2fb
   You should have received a copy of the GNU General Public License
Packit Service 97d2fb
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit Service 97d2fb
Packit Service 97d2fb
#include <config.h>
Packit Service 97d2fb
#include <assert.h>
Packit Service 97d2fb
#include <inttypes.h>
Packit Service 97d2fb
#include ELFUTILS_HEADER(dwfl)
Packit Service 97d2fb
#include <elf.h>
Packit Service 97d2fb
#include <dwarf.h>
Packit Service 97d2fb
#include <argp.h>
Packit Service 97d2fb
#include <stdio.h>
Packit Service 97d2fb
#include <stdio_ext.h>
Packit Service 97d2fb
#include <stdlib.h>
Packit Service 97d2fb
#include <string.h>
Packit Service 97d2fb
Packit Service 97d2fb
static const char *
Packit Service 97d2fb
gelf_type (GElf_Sym *sym)
Packit Service 97d2fb
{
Packit Service 97d2fb
  switch (GELF_ST_TYPE (sym->st_info))
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case STT_NOTYPE:
Packit Service 97d2fb
      return "NOTYPE";
Packit Service 97d2fb
    case STT_OBJECT:
Packit Service 97d2fb
      return "OBJECT";
Packit Service 97d2fb
    case STT_FUNC:
Packit Service 97d2fb
      return "FUNC";
Packit Service 97d2fb
    case STT_SECTION:
Packit Service 97d2fb
      return "SECTION";
Packit Service 97d2fb
    case STT_FILE:
Packit Service 97d2fb
      return "FILE";
Packit Service 97d2fb
    case STT_COMMON:
Packit Service 97d2fb
      return "COMMON";
Packit Service 97d2fb
    case STT_TLS:
Packit Service 97d2fb
      return "TLS";
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      return "UNKNOWN";
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static const char *
Packit Service 97d2fb
gelf_bind (GElf_Sym *sym)
Packit Service 97d2fb
{
Packit Service 97d2fb
  switch (GELF_ST_BIND (sym->st_info))
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case STB_LOCAL:
Packit Service 97d2fb
      return "LOCAL";
Packit Service 97d2fb
    case STB_GLOBAL:
Packit Service 97d2fb
      return "GLOBAL";
Packit Service 97d2fb
    case STB_WEAK:
Packit Service 97d2fb
      return "WEAK";
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      return "UNKNOWN";
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
gelf_bind_order (GElf_Sym *sym)
Packit Service 97d2fb
{
Packit Service 97d2fb
  switch (GELF_ST_BIND (sym->st_info))
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case STB_LOCAL:
Packit Service 97d2fb
      return 1;
Packit Service 97d2fb
    case STB_WEAK:
Packit Service 97d2fb
      return 2;
Packit Service 97d2fb
    case STB_GLOBAL:
Packit Service 97d2fb
      return 3;
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      return 0;
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static const char *
Packit Service 97d2fb
elf_section_name (Elf *elf, GElf_Word shndx)
Packit Service 97d2fb
{
Packit Service 97d2fb
  GElf_Ehdr ehdr;
Packit Service 97d2fb
  GElf_Shdr shdr;
Packit Service 97d2fb
  Elf_Scn *scn = elf_getscn (elf, shndx);
Packit Service 97d2fb
  gelf_getshdr (scn, &shdr);
Packit Service 97d2fb
  gelf_getehdr (elf, &ehdr);
Packit Service 97d2fb
  return elf_strptr (elf, ehdr.e_shstrndx, shdr.sh_name);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
bool
Packit Service 97d2fb
addr_in_section (Elf *elf, GElf_Word shndx, GElf_Addr addr)
Packit Service 97d2fb
{
Packit Service 97d2fb
  GElf_Shdr shdr;
Packit Service 97d2fb
  Elf_Scn *scn = elf_getscn (elf, shndx);
Packit Service 97d2fb
  gelf_getshdr (scn, &shdr);
Packit Service 97d2fb
  return addr >= shdr.sh_addr && addr < shdr.sh_addr + shdr.sh_size;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
list_syms (struct Dwfl_Module *mod,
Packit Service 97d2fb
	   void **user __attribute__ ((unused)), const char *mod_name,
Packit Service 97d2fb
	   Dwarf_Addr low_addr __attribute__ ((unused)),
Packit Service 97d2fb
	   void *arg __attribute__ ((unused)))
Packit Service 97d2fb
{
Packit Service 97d2fb
  int syms = dwfl_module_getsymtab (mod);
Packit Service 97d2fb
  if (syms < 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      printf ("%s: %s\n", mod_name, dwfl_errmsg (-1));
Packit Service 97d2fb
      return DWARF_CB_OK;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  for (int ndx = 0; ndx < syms; ndx++)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Sym sym;
Packit Service 97d2fb
      GElf_Word shndxp;
Packit Service 97d2fb
      Elf *elf;
Packit Service 97d2fb
      Dwarf_Addr bias;
Packit Service 97d2fb
      const char *name = dwfl_module_getsym (mod, ndx, &sym, &shndxp);
Packit Service 97d2fb
Packit Service 97d2fb
      printf("%4d: %s\t%s\t%s (%" PRIu64 ") %#" PRIx64,
Packit Service 97d2fb
	     ndx, gelf_type (&sym), gelf_bind (&sym), name,
Packit Service 97d2fb
	     sym.st_size, sym.st_value);
Packit Service 97d2fb
Packit Service 97d2fb
      /* The info variant doesn't adjust st_value but returns the (possible)
Packit Service 97d2fb
	 adjusted value separately. */
Packit Service 97d2fb
      GElf_Addr value;
Packit Service 97d2fb
      GElf_Sym isym;
Packit Service 97d2fb
      name = dwfl_module_getsym_info (mod, ndx, &isym, &value, &shndxp,
Packit Service 97d2fb
				      &elf, &bias);
Packit Service 97d2fb
Packit Service 97d2fb
      GElf_Ehdr ehdr;
Packit Service 97d2fb
      gelf_getehdr (elf, &ehdr);
Packit Service 97d2fb
Packit Service 97d2fb
      // getsym st_values might or might not be adjusted depending on section.
Packit Service 97d2fb
      // For ET_REL the adjustment is section relative.
Packit Service 97d2fb
      assert (sym.st_value == isym.st_value
Packit Service 97d2fb
	      || sym.st_value == isym.st_value + bias
Packit Service 97d2fb
	      || ehdr.e_type == ET_REL);
Packit Service 97d2fb
Packit Service 97d2fb
      /* And the reverse, which works for function symbols at least.
Packit Service 97d2fb
	 Note this only works because the st.value is adjusted by
Packit Service 97d2fb
	 dwfl_module_getsym ().  */
Packit Service 97d2fb
      if (GELF_ST_TYPE (sym.st_info) == STT_FUNC && shndxp != SHN_UNDEF)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Make sure the adjusted value really falls in the elf section. */
Packit Service 97d2fb
          assert (addr_in_section (elf, shndxp, sym.st_value - bias));
Packit Service 97d2fb
Packit Service 97d2fb
	  GElf_Addr addr = value;
Packit Service 97d2fb
	  GElf_Sym asym;
Packit Service 97d2fb
	  GElf_Word ashndxp;
Packit Service 97d2fb
	  Elf *aelf;
Packit Service 97d2fb
	  Dwarf_Addr abias;
Packit Service 97d2fb
	  GElf_Off off;
Packit Service 97d2fb
	  const char *aname = dwfl_module_addrinfo (mod, addr, &off, &asym,
Packit Service 97d2fb
						    &ashndxp, &aelf, &abias);
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Make sure the adjusted value really falls in the elf section. */
Packit Service 97d2fb
          assert (addr_in_section (aelf, ashndxp, asym.st_value)
Packit Service 97d2fb
		  || ehdr.e_type == ET_REL);
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Either they are the same symbol (name), the binding of
Packit Service 97d2fb
	     asym is "stronger" (or equal) to sym or asym is more specific
Packit Service 97d2fb
	     (has a lower address) than sym.  */
Packit Service 97d2fb
	  assert ((strcmp (name, aname) == 0
Packit Service 97d2fb
		   || gelf_bind_order (&asym) >= gelf_bind_order (&sym))
Packit Service 97d2fb
		  && value <= sym.st_value);
Packit Service 97d2fb
Packit Service 97d2fb
	  addr = sym.st_value;
Packit Service 97d2fb
	  int res = dwfl_module_relocate_address (mod, &addr);
Packit Service 97d2fb
	  assert (res != -1);
Packit Service 97d2fb
	  if (shndxp < SHN_LORESERVE)
Packit Service 97d2fb
	    printf(", rel: %#" PRIx64 " (%s)", addr,
Packit Service 97d2fb
		   elf_section_name (elf, shndxp));
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    printf(", rel: %#" PRIx64 "", addr);
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Print the section of the actual value if different from sym.  */
Packit Service 97d2fb
	  if (value != isym.st_value + bias && ehdr.e_type != ET_REL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      GElf_Addr ebias;
Packit Service 97d2fb
	      addr = value;
Packit Service 97d2fb
	      Elf_Scn *scn = dwfl_module_address_section (mod, &addr, &ebias);
Packit Service 97d2fb
	      GElf_Shdr shdr_mem;
Packit Service 97d2fb
	      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
Packit Service 97d2fb
	      Elf *melf = dwfl_module_getelf (mod, &ebias);
Packit Service 97d2fb
	      gelf_getehdr (melf, &ehdr);
Packit Service 97d2fb
	      const char *sname = elf_strptr (melf, ehdr.e_shstrndx,
Packit Service 97d2fb
					      shdr->sh_name);
Packit Service 97d2fb
	      printf (" [%#" PRIx64 ", rel: %#" PRIx64 " (%s)]",
Packit Service 97d2fb
		      value, addr, sname);
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	}
Packit Service 97d2fb
      printf ("\n");
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return DWARF_CB_OK;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
main (int argc, char *argv[])
Packit Service 97d2fb
{
Packit Service 97d2fb
  int remaining;
Packit Service 97d2fb
  Dwfl *dwfl;
Packit Service 97d2fb
  error_t res;
Packit Service 97d2fb
Packit Service 97d2fb
  res = argp_parse (dwfl_standard_argp (), argc, argv, 0, &remaining, &dwfl);
Packit Service 97d2fb
  assert (res == 0 && dwfl != NULL);
Packit Service 97d2fb
Packit Service 97d2fb
  ptrdiff_t off = 0;
Packit Service 97d2fb
  do
Packit Service 97d2fb
    off = dwfl_getmodules (dwfl, list_syms, NULL, off);
Packit Service 97d2fb
  while (off > 0);
Packit Service 97d2fb
Packit Service 97d2fb
  dwfl_end (dwfl);
Packit Service 97d2fb
Packit Service 97d2fb
  return off;
Packit Service 97d2fb
}