dwfl_module_addrsym.c revision de2ed97f33139af5c7a0811e4ec66fc896a13cf2
16258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper/* Find debugging and symbol information for a module in libdwfl. 2ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard Copyright (C) 2005-2011 Red Hat, Inc. 3de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard This file is part of elfutils. 46258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper 5de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard This file is free software; you can redistribute it and/or modify 6de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard it under the terms of either 76258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper 8de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard * the GNU Lesser General Public License as published by the Free 9de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard Software Foundation; either version 3 of the License, or (at 10de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard your option) any later version 11de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard 12de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard or 13de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard 14de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard * the GNU General Public License as published by the Free 15de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard Software Foundation; either version 2 of the License, or (at 16de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard your option) any later version 17de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard 18de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard or both in parallel, as here. 19de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard 20de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard elfutils is distributed in the hope that it will be useful, but 216258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper WITHOUT ANY WARRANTY; without even the implied warranty of 226258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 236258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper General Public License for more details. 246258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper 25de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard You should have received copies of the GNU General Public License and 26de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard the GNU Lesser General Public License along with this program. If 27de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard not, see <http://www.gnu.org/licenses/>. */ 286258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper 296258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper#include "libdwflP.h" 306258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper 31b4d6f0f8064f2b706ea9035ef0393d8299671390Roland McGrath/* Returns the name of the symbol "closest" to ADDR. 32b4d6f0f8064f2b706ea9035ef0393d8299671390Roland McGrath Never returns symbols at addresses above ADDR. */ 33b4d6f0f8064f2b706ea9035ef0393d8299671390Roland McGrath 346258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepperconst char * 356258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepperdwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr, 366258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper GElf_Sym *closest_sym, GElf_Word *shndxp) 376258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper{ 386258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper int syments = INTUSE(dwfl_module_getsymtab) (mod); 396258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper if (syments < 0) 406258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper return NULL; 416258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper 426258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper /* Return true iff we consider ADDR to lie in the same section as SYM. */ 436258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper GElf_Word addr_shndx = SHN_UNDEF; 446258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper inline bool same_section (const GElf_Sym *sym, GElf_Word shndx) 456258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper { 466258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper /* For absolute symbols and the like, only match exactly. */ 476258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper if (shndx >= SHN_LORESERVE) 486258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper return sym->st_value == addr; 496258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper 506258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper /* Figure out what section ADDR lies in. */ 516258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper if (addr_shndx == SHN_UNDEF) 526258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper { 531743d7f010bead5e869d097e23ce840583913381Roland McGrath GElf_Addr mod_addr = dwfl_deadjust_st_value (mod, addr); 546258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper Elf_Scn *scn = NULL; 556258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper addr_shndx = SHN_ABS; 566258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper while ((scn = elf_nextscn (mod->symfile->elf, scn)) != NULL) 576258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper { 586258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper GElf_Shdr shdr_mem; 596258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 606258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper if (likely (shdr != NULL) 616258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper && mod_addr >= shdr->sh_addr 626258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper && mod_addr < shdr->sh_addr + shdr->sh_size) 636258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper { 646258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper addr_shndx = elf_ndxscn (scn); 656258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper break; 666258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper } 676258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper } 686258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper } 696258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper 706258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper return shndx == addr_shndx; 716258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper } 726258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper 7342f686820a19806da629990bf7ae69a6a2fcfb1fRoland McGrath /* Keep track of the closest symbol we have seen so far. 7442f686820a19806da629990bf7ae69a6a2fcfb1fRoland McGrath Here we store only symbols with nonzero st_size. */ 756258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper const char *closest_name = NULL; 766258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper GElf_Word closest_shndx = SHN_UNDEF; 7742f686820a19806da629990bf7ae69a6a2fcfb1fRoland McGrath 7842f686820a19806da629990bf7ae69a6a2fcfb1fRoland McGrath /* Keep track of an eligible symbol with st_size == 0 as a fallback. */ 7942f686820a19806da629990bf7ae69a6a2fcfb1fRoland McGrath const char *sizeless_name = NULL; 80099dd52727f2ce1a2c73cde82af8cd5e06368aecRoland McGrath GElf_Sym sizeless_sym = { 0, 0, 0, 0, 0, SHN_UNDEF }; 8142f686820a19806da629990bf7ae69a6a2fcfb1fRoland McGrath GElf_Word sizeless_shndx = SHN_UNDEF; 8242f686820a19806da629990bf7ae69a6a2fcfb1fRoland McGrath 8342f686820a19806da629990bf7ae69a6a2fcfb1fRoland McGrath /* Keep track of the lowest address a relevant sizeless symbol could have. */ 84b4d6f0f8064f2b706ea9035ef0393d8299671390Roland McGrath GElf_Addr min_label = 0; 8542f686820a19806da629990bf7ae69a6a2fcfb1fRoland McGrath 8642f686820a19806da629990bf7ae69a6a2fcfb1fRoland McGrath /* Look through the symbol table for a matching symbol. */ 87ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard inline void search_table (int start, int end) 886258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper { 89ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard for (int i = start; i < end; ++i) 906258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper { 91ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard GElf_Sym sym; 92ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard GElf_Word shndx; 93ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard const char *name = INTUSE(dwfl_module_getsym) (mod, i, &sym, &shndx); 94ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard if (name != NULL && name[0] != '\0' 95ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard && sym.st_shndx != SHN_UNDEF 96ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard && sym.st_value <= addr 97ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard && GELF_ST_TYPE (sym.st_info) != STT_SECTION 98ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard && GELF_ST_TYPE (sym.st_info) != STT_FILE 99ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard && GELF_ST_TYPE (sym.st_info) != STT_TLS) 100c76f0b05676f6207affbfd85e75063db3b6eeccfRoland McGrath { 101ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard /* Even if we don't choose this symbol, its existence excludes 102ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard any sizeless symbol (assembly label) that is below its upper 103ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard bound. */ 104ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard if (sym.st_value + sym.st_size > min_label) 105ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard min_label = sym.st_value + sym.st_size; 106ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard 107ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard if (sym.st_size == 0 || addr - sym.st_value < sym.st_size) 108c76f0b05676f6207affbfd85e75063db3b6eeccfRoland McGrath { 109ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard /* This symbol is a better candidate than the current one 110ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard if it's closer to ADDR or is global when it was local. */ 111ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard if (closest_name == NULL 112ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard || closest_sym->st_value < sym.st_value 113ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard || (GELF_ST_BIND (closest_sym->st_info) 114ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard < GELF_ST_BIND (sym.st_info))) 115ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard { 116ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard if (sym.st_size != 0) 117ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard { 118ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard *closest_sym = sym; 119ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard closest_shndx = shndx; 120ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard closest_name = name; 121ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard } 122ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard else if (closest_name == NULL 123ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard && sym.st_value >= min_label 124ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard && same_section (&sym, shndx)) 125ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard { 126ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard /* Handwritten assembly symbols sometimes have no 127ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard st_size. If no symbol with proper size includes 128ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard the address, we'll use the closest one that is in 129ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard the same section as ADDR. */ 130ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard sizeless_sym = sym; 131ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard sizeless_shndx = shndx; 132ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard sizeless_name = name; 133ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard } 134ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard } 135ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard /* When the beginning of its range is no closer, 136ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard the end of its range might be. But do not 137ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard replace a global symbol with a local! */ 138ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard else if (sym.st_size != 0 139ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard && closest_sym->st_value == sym.st_value 140ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard && closest_sym->st_size > sym.st_size 141ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard && (GELF_ST_BIND (closest_sym->st_info) 142ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard <= GELF_ST_BIND (sym.st_info))) 143c76f0b05676f6207affbfd85e75063db3b6eeccfRoland McGrath { 144c76f0b05676f6207affbfd85e75063db3b6eeccfRoland McGrath *closest_sym = sym; 145c76f0b05676f6207affbfd85e75063db3b6eeccfRoland McGrath closest_shndx = shndx; 146c76f0b05676f6207affbfd85e75063db3b6eeccfRoland McGrath closest_name = name; 147c76f0b05676f6207affbfd85e75063db3b6eeccfRoland McGrath } 14842f686820a19806da629990bf7ae69a6a2fcfb1fRoland McGrath } 1496258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper } 1506258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper } 1516258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper } 1526258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper 153ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard /* First go through global symbols. mod->first_global is setup by 154ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard dwfl_module_getsymtab to the index of the first global symbol in 155ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard the module's symbol table, or -1 when unknown. All symbols with 156ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard local binding come first in the symbol table, then all globals. */ 157ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard search_table (mod->first_global < 0 ? 1 : mod->first_global, syments); 158ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard 159ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard /* If we found nothing searching the global symbols, then try the locals. 160ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard Unless we have a global sizeless symbol that matches exactly. */ 161ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard if (closest_name == NULL && mod->first_global > 1 162ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard && (sizeless_name == NULL || sizeless_sym.st_value != addr)) 163ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard search_table (1, mod->first_global); 164ef431cd30b8a1a6b12a8783516fc95da88a9a636Mark Wielaard 16542f686820a19806da629990bf7ae69a6a2fcfb1fRoland McGrath /* If we found no proper sized symbol to use, fall back to the best 16642f686820a19806da629990bf7ae69a6a2fcfb1fRoland McGrath candidate sizeless symbol we found, if any. */ 16742f686820a19806da629990bf7ae69a6a2fcfb1fRoland McGrath if (closest_name == NULL 16842f686820a19806da629990bf7ae69a6a2fcfb1fRoland McGrath && sizeless_name != NULL && sizeless_sym.st_value >= min_label) 16942f686820a19806da629990bf7ae69a6a2fcfb1fRoland McGrath { 17042f686820a19806da629990bf7ae69a6a2fcfb1fRoland McGrath *closest_sym = sizeless_sym; 17142f686820a19806da629990bf7ae69a6a2fcfb1fRoland McGrath closest_shndx = sizeless_shndx; 17242f686820a19806da629990bf7ae69a6a2fcfb1fRoland McGrath closest_name = sizeless_name; 17342f686820a19806da629990bf7ae69a6a2fcfb1fRoland McGrath } 17442f686820a19806da629990bf7ae69a6a2fcfb1fRoland McGrath 1756258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper if (shndxp != NULL) 1766258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper *shndxp = closest_shndx; 1776258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper return closest_name; 1786258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper} 1796258e7486eb3eed6e50005946795c5fbf73aa106Ulrich DrepperINTDEF (dwfl_module_addrsym) 180