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