103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes/* Test program for libdwfl symbol resolving
203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   Copyright (C) 2013 Red Hat, Inc.
303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   This file is part of elfutils.
403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   This file is free software; you can redistribute it and/or modify
603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   it under the terms of the GNU General Public License as published by
703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   the Free Software Foundation; either version 3 of the License, or
803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   (at your option) any later version.
903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   elfutils is distributed in the hope that it will be useful, but
1103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   WITHOUT ANY WARRANTY; without even the implied warranty of
1203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   GNU General Public License for more details.
1403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   You should have received a copy of the GNU General Public License
1603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
1703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <config.h>
1903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <assert.h>
2003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <inttypes.h>
2103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include ELFUTILS_HEADER(dwfl)
2203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <elf.h>
2303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <dwarf.h>
2403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <argp.h>
2503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <stdio.h>
2603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <stdio_ext.h>
2703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <stdlib.h>
2803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <error.h>
2903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <string.h>
3003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
3103333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic const char *
3203333823c75a1c1887e923828113a1b0fd12020cElliott Hughesgelf_type (GElf_Sym *sym)
3303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
3403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  switch (GELF_ST_TYPE (sym->st_info))
3503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
3603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case STT_NOTYPE:
3703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return "NOTYPE";
3803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case STT_OBJECT:
3903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return "OBJECT";
4003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case STT_FUNC:
4103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return "FUNC";
4203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case STT_SECTION:
4303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return "SECTION";
4403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case STT_FILE:
4503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return "FILE";
4603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case STT_COMMON:
4703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return "COMMON";
4803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case STT_TLS:
4903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return "TLS";
5003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    default:
5103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return "UNKNOWN";
5203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
5303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
5403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
5503333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic const char *
5603333823c75a1c1887e923828113a1b0fd12020cElliott Hughesgelf_bind (GElf_Sym *sym)
5703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
5803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  switch (GELF_ST_BIND (sym->st_info))
5903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
6003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case STB_LOCAL:
6103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return "LOCAL";
6203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case STB_GLOBAL:
6303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return "GLOBAL";
6403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case STB_WEAK:
6503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return "WEAK";
6603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    default:
6703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return "UNKNOWN";
6803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
6903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
7003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
7103333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic int
7203333823c75a1c1887e923828113a1b0fd12020cElliott Hughesgelf_bind_order (GElf_Sym *sym)
7303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
7403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  switch (GELF_ST_BIND (sym->st_info))
7503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
7603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case STB_LOCAL:
7703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return 1;
7803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case STB_WEAK:
7903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return 2;
8003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case STB_GLOBAL:
8103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return 3;
8203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    default:
8303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return 0;
8403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
8503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
8603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
8703333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic const char *
8803333823c75a1c1887e923828113a1b0fd12020cElliott Hugheself_section_name (Elf *elf, GElf_Word shndx)
8903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
9003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  GElf_Ehdr ehdr;
9103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  GElf_Shdr shdr;
9203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  Elf_Scn *scn = elf_getscn (elf, shndx);
9303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  gelf_getshdr (scn, &shdr);
9403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  gelf_getehdr (elf, &ehdr);
9503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return elf_strptr (elf, ehdr.e_shstrndx, shdr.sh_name);
9603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
9703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
9803333823c75a1c1887e923828113a1b0fd12020cElliott Hughesbool
9903333823c75a1c1887e923828113a1b0fd12020cElliott Hughesaddr_in_section (Elf *elf, GElf_Word shndx, GElf_Addr addr)
10003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
10103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  GElf_Shdr shdr;
10203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  Elf_Scn *scn = elf_getscn (elf, shndx);
10303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  gelf_getshdr (scn, &shdr);
10403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return addr >= shdr.sh_addr && addr < shdr.sh_addr + shdr.sh_size;
10503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
10603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
10703333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic int
10803333823c75a1c1887e923828113a1b0fd12020cElliott Hugheslist_syms (struct Dwfl_Module *mod,
10903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	   void **user __attribute__ ((unused)), const char *mod_name,
11003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	   Dwarf_Addr low_addr __attribute__ ((unused)),
11103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	   void *arg __attribute__ ((unused)))
11203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
11303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  int syms = dwfl_module_getsymtab (mod);
11403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (syms < 0)
11503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
11603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      printf ("%s: %s\n", mod_name, dwfl_errmsg (-1));
11703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return DWARF_CB_OK;
11803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
11903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
12003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  for (int ndx = 0; ndx < syms; ndx++)
12103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
12203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      GElf_Sym sym;
12303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      GElf_Word shndxp;
12403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      Elf *elf;
12503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      Dwarf_Addr bias;
12603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      const char *name = dwfl_module_getsym (mod, ndx, &sym, &shndxp);
12703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
12803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      printf("%4d: %s\t%s\t%s (%" PRIu64 ") %#" PRIx64,
12903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	     ndx, gelf_type (&sym), gelf_bind (&sym), name,
13003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	     sym.st_size, sym.st_value);
13103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
13203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      /* The info variant doesn't adjust st_value but returns the (possible)
13303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	 adjusted value separately. */
13403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      GElf_Addr value;
13503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      GElf_Sym isym;
13603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      name = dwfl_module_getsym_info (mod, ndx, &isym, &value, &shndxp,
13703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes				      &elf, &bias);
13803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
13903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      GElf_Ehdr ehdr;
14003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      gelf_getehdr (elf, &ehdr);
14103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
14203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      // getsym st_values might or might not be adjusted depending on section.
14303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      // For ET_REL the adjustment is section relative.
14403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      assert (sym.st_value == isym.st_value
14503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      || sym.st_value == isym.st_value + bias
14603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      || ehdr.e_type == ET_REL);
14703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
14803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      /* And the reverse, which works for function symbols at least.
14903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	 Note this only works because the st.value is adjusted by
15003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	 dwfl_module_getsym ().  */
15103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (GELF_ST_TYPE (sym.st_info) == STT_FUNC && shndxp != SHN_UNDEF)
15203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
15303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  /* Make sure the adjusted value really falls in the elf section. */
15403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes          assert (addr_in_section (elf, shndxp, sym.st_value - bias));
15503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
15603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  GElf_Addr addr = value;
15703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  GElf_Sym asym;
15803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  GElf_Word ashndxp;
15903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  Elf *aelf;
16003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  Dwarf_Addr abias;
16103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  GElf_Off off;
16203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  const char *aname = dwfl_module_addrinfo (mod, addr, &off, &asym,
16303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes						    &ashndxp, &aelf, &abias);
16403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
16503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  /* Make sure the adjusted value really falls in the elf section. */
16603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes          assert (addr_in_section (aelf, ashndxp, asym.st_value)
16703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  || ehdr.e_type == ET_REL);
16803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
16903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  /* Either they are the same symbol (name), the binding of
17003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	     asym is "stronger" (or equal) to sym or asym is more specific
17103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	     (has a lower address) than sym.  */
17203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  assert ((strcmp (name, aname) == 0
17303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		   || gelf_bind_order (&asym) >= gelf_bind_order (&sym))
17403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  && value <= sym.st_value);
17503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
17603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  addr = sym.st_value;
17703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  int res = dwfl_module_relocate_address (mod, &addr);
17803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  assert (res != -1);
17903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (shndxp < SHN_LORESERVE)
18003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    printf(", rel: %#" PRIx64 " (%s)", addr,
18103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		   elf_section_name (elf, shndxp));
18203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  else
18303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    printf(", rel: %#" PRIx64 "", addr);
18403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
18503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  /* Print the section of the actual value if different from sym.  */
18603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (value != isym.st_value + bias && ehdr.e_type != ET_REL)
18703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    {
18803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      GElf_Addr ebias;
18903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      addr = value;
19003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      Elf_Scn *scn = dwfl_module_address_section (mod, &addr, &ebias);
19103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      GElf_Shdr shdr_mem;
19203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
19303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      Elf *melf = dwfl_module_getelf (mod, &ebias);
19403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      gelf_getehdr (melf, &ehdr);
19503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      const char *sname = elf_strptr (melf, ehdr.e_shstrndx,
19603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes					      shdr->sh_name);
19703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      printf (" [%#" PRIx64 ", rel: %#" PRIx64 " (%s)]",
19803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      value, addr, sname);
19903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    }
20003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
20103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
20203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      printf ("\n");
20303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
20403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
20503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return DWARF_CB_OK;
20603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
20703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
20803333823c75a1c1887e923828113a1b0fd12020cElliott Hughesint
20903333823c75a1c1887e923828113a1b0fd12020cElliott Hughesmain (int argc, char *argv[])
21003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
21103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  int remaining;
21203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  Dwfl *dwfl;
21303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  error_t res;
21403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
21503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  res = argp_parse (dwfl_standard_argp (), argc, argv, 0, &remaining, &dwfl);
21603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  assert (res == 0 && dwfl != NULL);
21703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
21803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  ptrdiff_t off = 0;
21903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  do
22003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    off = dwfl_getmodules (dwfl, list_syms, NULL, off);
22103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  while (off > 0);
22203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
22303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  dwfl_end (dwfl);
22403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
22503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return off;
22603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
227