1da0c48c4Sopenharmony_ci/* Test program for libdwfl symbol resolving 2da0c48c4Sopenharmony_ci Copyright (C) 2013 Red Hat, Inc. 3da0c48c4Sopenharmony_ci This file is part of elfutils. 4da0c48c4Sopenharmony_ci 5da0c48c4Sopenharmony_ci This file is free software; you can redistribute it and/or modify 6da0c48c4Sopenharmony_ci it under the terms of the GNU General Public License as published by 7da0c48c4Sopenharmony_ci the Free Software Foundation; either version 3 of the License, or 8da0c48c4Sopenharmony_ci (at your option) any later version. 9da0c48c4Sopenharmony_ci 10da0c48c4Sopenharmony_ci elfutils is distributed in the hope that it will be useful, but 11da0c48c4Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 12da0c48c4Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13da0c48c4Sopenharmony_ci GNU General Public License for more details. 14da0c48c4Sopenharmony_ci 15da0c48c4Sopenharmony_ci You should have received a copy of the GNU General Public License 16da0c48c4Sopenharmony_ci along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17da0c48c4Sopenharmony_ci 18da0c48c4Sopenharmony_ci#include <config.h> 19da0c48c4Sopenharmony_ci#include <assert.h> 20da0c48c4Sopenharmony_ci#include <inttypes.h> 21da0c48c4Sopenharmony_ci#include ELFUTILS_HEADER(dwfl) 22da0c48c4Sopenharmony_ci#include <elf.h> 23da0c48c4Sopenharmony_ci#include <dwarf.h> 24da0c48c4Sopenharmony_ci#include <argp.h> 25da0c48c4Sopenharmony_ci#include <stdio.h> 26da0c48c4Sopenharmony_ci#include <stdio_ext.h> 27da0c48c4Sopenharmony_ci#include <stdlib.h> 28da0c48c4Sopenharmony_ci#include <string.h> 29da0c48c4Sopenharmony_ci 30da0c48c4Sopenharmony_cistatic const char * 31da0c48c4Sopenharmony_cigelf_type (GElf_Sym *sym) 32da0c48c4Sopenharmony_ci{ 33da0c48c4Sopenharmony_ci switch (GELF_ST_TYPE (sym->st_info)) 34da0c48c4Sopenharmony_ci { 35da0c48c4Sopenharmony_ci case STT_NOTYPE: 36da0c48c4Sopenharmony_ci return "NOTYPE"; 37da0c48c4Sopenharmony_ci case STT_OBJECT: 38da0c48c4Sopenharmony_ci return "OBJECT"; 39da0c48c4Sopenharmony_ci case STT_FUNC: 40da0c48c4Sopenharmony_ci return "FUNC"; 41da0c48c4Sopenharmony_ci case STT_SECTION: 42da0c48c4Sopenharmony_ci return "SECTION"; 43da0c48c4Sopenharmony_ci case STT_FILE: 44da0c48c4Sopenharmony_ci return "FILE"; 45da0c48c4Sopenharmony_ci case STT_COMMON: 46da0c48c4Sopenharmony_ci return "COMMON"; 47da0c48c4Sopenharmony_ci case STT_TLS: 48da0c48c4Sopenharmony_ci return "TLS"; 49da0c48c4Sopenharmony_ci default: 50da0c48c4Sopenharmony_ci return "UNKNOWN"; 51da0c48c4Sopenharmony_ci } 52da0c48c4Sopenharmony_ci} 53da0c48c4Sopenharmony_ci 54da0c48c4Sopenharmony_cistatic const char * 55da0c48c4Sopenharmony_cigelf_bind (GElf_Sym *sym) 56da0c48c4Sopenharmony_ci{ 57da0c48c4Sopenharmony_ci switch (GELF_ST_BIND (sym->st_info)) 58da0c48c4Sopenharmony_ci { 59da0c48c4Sopenharmony_ci case STB_LOCAL: 60da0c48c4Sopenharmony_ci return "LOCAL"; 61da0c48c4Sopenharmony_ci case STB_GLOBAL: 62da0c48c4Sopenharmony_ci return "GLOBAL"; 63da0c48c4Sopenharmony_ci case STB_WEAK: 64da0c48c4Sopenharmony_ci return "WEAK"; 65da0c48c4Sopenharmony_ci default: 66da0c48c4Sopenharmony_ci return "UNKNOWN"; 67da0c48c4Sopenharmony_ci } 68da0c48c4Sopenharmony_ci} 69da0c48c4Sopenharmony_ci 70da0c48c4Sopenharmony_cistatic int 71da0c48c4Sopenharmony_cigelf_bind_order (GElf_Sym *sym) 72da0c48c4Sopenharmony_ci{ 73da0c48c4Sopenharmony_ci switch (GELF_ST_BIND (sym->st_info)) 74da0c48c4Sopenharmony_ci { 75da0c48c4Sopenharmony_ci case STB_LOCAL: 76da0c48c4Sopenharmony_ci return 1; 77da0c48c4Sopenharmony_ci case STB_WEAK: 78da0c48c4Sopenharmony_ci return 2; 79da0c48c4Sopenharmony_ci case STB_GLOBAL: 80da0c48c4Sopenharmony_ci return 3; 81da0c48c4Sopenharmony_ci default: 82da0c48c4Sopenharmony_ci return 0; 83da0c48c4Sopenharmony_ci } 84da0c48c4Sopenharmony_ci} 85da0c48c4Sopenharmony_ci 86da0c48c4Sopenharmony_cistatic const char * 87da0c48c4Sopenharmony_cielf_section_name (Elf *elf, GElf_Word shndx) 88da0c48c4Sopenharmony_ci{ 89da0c48c4Sopenharmony_ci GElf_Ehdr ehdr; 90da0c48c4Sopenharmony_ci GElf_Shdr shdr; 91da0c48c4Sopenharmony_ci Elf_Scn *scn = elf_getscn (elf, shndx); 92da0c48c4Sopenharmony_ci gelf_getshdr (scn, &shdr); 93da0c48c4Sopenharmony_ci gelf_getehdr (elf, &ehdr); 94da0c48c4Sopenharmony_ci return elf_strptr (elf, ehdr.e_shstrndx, shdr.sh_name); 95da0c48c4Sopenharmony_ci} 96da0c48c4Sopenharmony_ci 97da0c48c4Sopenharmony_cibool 98da0c48c4Sopenharmony_ciaddr_in_section (Elf *elf, GElf_Word shndx, GElf_Addr addr) 99da0c48c4Sopenharmony_ci{ 100da0c48c4Sopenharmony_ci GElf_Shdr shdr; 101da0c48c4Sopenharmony_ci Elf_Scn *scn = elf_getscn (elf, shndx); 102da0c48c4Sopenharmony_ci gelf_getshdr (scn, &shdr); 103da0c48c4Sopenharmony_ci return addr >= shdr.sh_addr && addr < shdr.sh_addr + shdr.sh_size; 104da0c48c4Sopenharmony_ci} 105da0c48c4Sopenharmony_ci 106da0c48c4Sopenharmony_cistatic int 107da0c48c4Sopenharmony_cilist_syms (struct Dwfl_Module *mod, 108da0c48c4Sopenharmony_ci void **user __attribute__ ((unused)), const char *mod_name, 109da0c48c4Sopenharmony_ci Dwarf_Addr low_addr __attribute__ ((unused)), 110da0c48c4Sopenharmony_ci void *arg __attribute__ ((unused))) 111da0c48c4Sopenharmony_ci{ 112da0c48c4Sopenharmony_ci int syms = dwfl_module_getsymtab (mod); 113da0c48c4Sopenharmony_ci if (syms < 0) 114da0c48c4Sopenharmony_ci { 115da0c48c4Sopenharmony_ci printf ("%s: %s\n", mod_name, dwfl_errmsg (-1)); 116da0c48c4Sopenharmony_ci return DWARF_CB_OK; 117da0c48c4Sopenharmony_ci } 118da0c48c4Sopenharmony_ci 119da0c48c4Sopenharmony_ci for (int ndx = 0; ndx < syms; ndx++) 120da0c48c4Sopenharmony_ci { 121da0c48c4Sopenharmony_ci GElf_Sym sym; 122da0c48c4Sopenharmony_ci GElf_Word shndxp; 123da0c48c4Sopenharmony_ci Elf *elf; 124da0c48c4Sopenharmony_ci Dwarf_Addr bias; 125da0c48c4Sopenharmony_ci const char *name = dwfl_module_getsym (mod, ndx, &sym, &shndxp); 126da0c48c4Sopenharmony_ci 127da0c48c4Sopenharmony_ci printf("%4d: %s\t%s\t%s (%" PRIu64 ") %#" PRIx64, 128da0c48c4Sopenharmony_ci ndx, gelf_type (&sym), gelf_bind (&sym), name, 129da0c48c4Sopenharmony_ci sym.st_size, sym.st_value); 130da0c48c4Sopenharmony_ci 131da0c48c4Sopenharmony_ci /* The info variant doesn't adjust st_value but returns the (possible) 132da0c48c4Sopenharmony_ci adjusted value separately. */ 133da0c48c4Sopenharmony_ci GElf_Addr value; 134da0c48c4Sopenharmony_ci GElf_Sym isym; 135da0c48c4Sopenharmony_ci name = dwfl_module_getsym_info (mod, ndx, &isym, &value, &shndxp, 136da0c48c4Sopenharmony_ci &elf, &bias); 137da0c48c4Sopenharmony_ci 138da0c48c4Sopenharmony_ci GElf_Ehdr ehdr; 139da0c48c4Sopenharmony_ci gelf_getehdr (elf, &ehdr); 140da0c48c4Sopenharmony_ci 141da0c48c4Sopenharmony_ci // getsym st_values might or might not be adjusted depending on section. 142da0c48c4Sopenharmony_ci // For ET_REL the adjustment is section relative. 143da0c48c4Sopenharmony_ci assert (sym.st_value == isym.st_value 144da0c48c4Sopenharmony_ci || sym.st_value == isym.st_value + bias 145da0c48c4Sopenharmony_ci || ehdr.e_type == ET_REL); 146da0c48c4Sopenharmony_ci 147da0c48c4Sopenharmony_ci /* And the reverse, which works for function symbols at least. 148da0c48c4Sopenharmony_ci Note this only works because the st.value is adjusted by 149da0c48c4Sopenharmony_ci dwfl_module_getsym (). */ 150da0c48c4Sopenharmony_ci if (GELF_ST_TYPE (sym.st_info) == STT_FUNC && shndxp != SHN_UNDEF) 151da0c48c4Sopenharmony_ci { 152da0c48c4Sopenharmony_ci /* Make sure the adjusted value really falls in the elf section. */ 153da0c48c4Sopenharmony_ci assert (addr_in_section (elf, shndxp, sym.st_value - bias)); 154da0c48c4Sopenharmony_ci 155da0c48c4Sopenharmony_ci GElf_Addr addr = value; 156da0c48c4Sopenharmony_ci GElf_Sym asym; 157da0c48c4Sopenharmony_ci GElf_Word ashndxp; 158da0c48c4Sopenharmony_ci Elf *aelf; 159da0c48c4Sopenharmony_ci Dwarf_Addr abias; 160da0c48c4Sopenharmony_ci GElf_Off off; 161da0c48c4Sopenharmony_ci const char *aname = dwfl_module_addrinfo (mod, addr, &off, &asym, 162da0c48c4Sopenharmony_ci &ashndxp, &aelf, &abias); 163da0c48c4Sopenharmony_ci 164da0c48c4Sopenharmony_ci /* Make sure the adjusted value really falls in the elf section. */ 165da0c48c4Sopenharmony_ci assert (addr_in_section (aelf, ashndxp, asym.st_value) 166da0c48c4Sopenharmony_ci || ehdr.e_type == ET_REL); 167da0c48c4Sopenharmony_ci 168da0c48c4Sopenharmony_ci /* Either they are the same symbol (name), the binding of 169da0c48c4Sopenharmony_ci asym is "stronger" (or equal) to sym or asym is more specific 170da0c48c4Sopenharmony_ci (has a lower address) than sym. */ 171da0c48c4Sopenharmony_ci assert ((strcmp (name, aname) == 0 172da0c48c4Sopenharmony_ci || gelf_bind_order (&asym) >= gelf_bind_order (&sym)) 173da0c48c4Sopenharmony_ci && value <= sym.st_value); 174da0c48c4Sopenharmony_ci 175da0c48c4Sopenharmony_ci addr = sym.st_value; 176da0c48c4Sopenharmony_ci int res = dwfl_module_relocate_address (mod, &addr); 177da0c48c4Sopenharmony_ci assert (res != -1); 178da0c48c4Sopenharmony_ci if (shndxp < SHN_LORESERVE) 179da0c48c4Sopenharmony_ci printf(", rel: %#" PRIx64 " (%s)", addr, 180da0c48c4Sopenharmony_ci elf_section_name (elf, shndxp)); 181da0c48c4Sopenharmony_ci else 182da0c48c4Sopenharmony_ci printf(", rel: %#" PRIx64 "", addr); 183da0c48c4Sopenharmony_ci 184da0c48c4Sopenharmony_ci /* Print the section of the actual value if different from sym. */ 185da0c48c4Sopenharmony_ci if (value != isym.st_value + bias && ehdr.e_type != ET_REL) 186da0c48c4Sopenharmony_ci { 187da0c48c4Sopenharmony_ci GElf_Addr ebias; 188da0c48c4Sopenharmony_ci addr = value; 189da0c48c4Sopenharmony_ci Elf_Scn *scn = dwfl_module_address_section (mod, &addr, &ebias); 190da0c48c4Sopenharmony_ci GElf_Shdr shdr_mem; 191da0c48c4Sopenharmony_ci GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 192da0c48c4Sopenharmony_ci Elf *melf = dwfl_module_getelf (mod, &ebias); 193da0c48c4Sopenharmony_ci gelf_getehdr (melf, &ehdr); 194da0c48c4Sopenharmony_ci const char *sname = elf_strptr (melf, ehdr.e_shstrndx, 195da0c48c4Sopenharmony_ci shdr->sh_name); 196da0c48c4Sopenharmony_ci printf (" [%#" PRIx64 ", rel: %#" PRIx64 " (%s)]", 197da0c48c4Sopenharmony_ci value, addr, sname); 198da0c48c4Sopenharmony_ci } 199da0c48c4Sopenharmony_ci 200da0c48c4Sopenharmony_ci } 201da0c48c4Sopenharmony_ci printf ("\n"); 202da0c48c4Sopenharmony_ci } 203da0c48c4Sopenharmony_ci 204da0c48c4Sopenharmony_ci return DWARF_CB_OK; 205da0c48c4Sopenharmony_ci} 206da0c48c4Sopenharmony_ci 207da0c48c4Sopenharmony_ciint 208da0c48c4Sopenharmony_cimain (int argc, char *argv[]) 209da0c48c4Sopenharmony_ci{ 210da0c48c4Sopenharmony_ci int remaining; 211da0c48c4Sopenharmony_ci Dwfl *dwfl; 212da0c48c4Sopenharmony_ci error_t res; 213da0c48c4Sopenharmony_ci 214da0c48c4Sopenharmony_ci res = argp_parse (dwfl_standard_argp (), argc, argv, 0, &remaining, &dwfl); 215da0c48c4Sopenharmony_ci assert (res == 0 && dwfl != NULL); 216da0c48c4Sopenharmony_ci 217da0c48c4Sopenharmony_ci ptrdiff_t off = 0; 218da0c48c4Sopenharmony_ci do 219da0c48c4Sopenharmony_ci off = dwfl_getmodules (dwfl, list_syms, NULL, off); 220da0c48c4Sopenharmony_ci while (off > 0); 221da0c48c4Sopenharmony_ci 222da0c48c4Sopenharmony_ci dwfl_end (dwfl); 223da0c48c4Sopenharmony_ci 224da0c48c4Sopenharmony_ci return off; 225da0c48c4Sopenharmony_ci} 226