1cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Find debugging and symbol information for a module in libdwfl. 2cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Copyright (C) 2005, 2006, 2007, 2008 Red Hat, Inc. 3cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng This file is part of Red Hat elfutils. 4cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 5cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Red Hat elfutils is free software; you can redistribute it and/or modify 6cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng it under the terms of the GNU General Public License as published by the 7cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Free Software Foundation; version 2 of the License. 8cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 9cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Red Hat elfutils is distributed in the hope that it will be useful, but 10cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng WITHOUT ANY WARRANTY; without even the implied warranty of 11cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng General Public License for more details. 13cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 14cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng You should have received a copy of the GNU General Public License along 15cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng with Red Hat elfutils; if not, write to the Free Software Foundation, 16cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. 17cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 18cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng In addition, as a special exception, Red Hat, Inc. gives You the 19cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng additional right to link the code of Red Hat elfutils with code licensed 20cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng under any Open Source Initiative certified open source license 21cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng (http://www.opensource.org/licenses/index.php) which requires the 22cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng distribution of source code with any binary distribution and to 23cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng distribute linked combinations of the two. Non-GPL Code permitted under 24cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng this exception must only link to the code of Red Hat elfutils through 25cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng those well defined interfaces identified in the file named EXCEPTION 26cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng found in the source code files (the "Approved Interfaces"). The files 27cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng of Non-GPL Code may instantiate templates or use macros or inline 28cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng functions from the Approved Interfaces without causing the resulting 29cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng work to be covered by the GNU General Public License. Only Red Hat, 30cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Inc. may make changes or additions to the list of Approved Interfaces. 31cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Red Hat's grant of this exception is conditioned upon your not adding 32cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng any new exceptions. If you wish to add a new Approved Interface or 33cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng exception, please contact Red Hat. You must obey the GNU General Public 34cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng License in all respects for all of the Red Hat elfutils code and other 35cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng code used in conjunction with Red Hat elfutils except the Non-GPL Code 36cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng covered by this exception. If you modify this file, you may extend this 37cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng exception to your version of the file, but you are not obligated to do 38cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng so. If you do not wish to provide this exception without modification, 39cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng you must delete this exception statement from your version and license 40cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng this file solely under the GPL without exception. 41cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 42cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Red Hat elfutils is an included package of the Open Invention Network. 43cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng An included package of the Open Invention Network is a package for which 44cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Open Invention Network licensees cross-license their patents. No patent 45cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng license is granted, either expressly or impliedly, by designation as an 46cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng included package. Should you wish to participate in the Open Invention 47cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Network licensing program, please visit www.openinventionnetwork.com 48cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng <http://www.openinventionnetwork.com>. */ 49cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 50cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include "libdwflP.h" 51cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 52cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Returns the name of the symbol "closest" to ADDR. 53cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Never returns symbols at addresses above ADDR. */ 54cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 55cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengconst char * 56cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengdwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr, 57cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Sym *closest_sym, GElf_Word *shndxp) 58cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{ 59cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng int syments = INTUSE(dwfl_module_getsymtab) (mod); 60cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (syments < 0) 61cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return NULL; 62cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 63cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Return true iff we consider ADDR to lie in the same section as SYM. */ 64cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Word addr_shndx = SHN_UNDEF; 65cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng inline bool same_section (const GElf_Sym *sym, GElf_Word shndx) 66cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 67cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* For absolute symbols and the like, only match exactly. */ 68cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (shndx >= SHN_LORESERVE) 69cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return sym->st_value == addr; 70cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 71cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Figure out what section ADDR lies in. */ 72cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (addr_shndx == SHN_UNDEF) 73cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 74cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Addr mod_addr = addr - mod->symfile->bias; 75cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf_Scn *scn = NULL; 76cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng addr_shndx = SHN_ABS; 77cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng while ((scn = elf_nextscn (mod->symfile->elf, scn)) != NULL) 78cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 79cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Shdr shdr_mem; 80cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 81cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (likely (shdr != NULL) 82cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && mod_addr >= shdr->sh_addr 83cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && mod_addr < shdr->sh_addr + shdr->sh_size) 84cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 85cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng addr_shndx = elf_ndxscn (scn); 86cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng break; 87cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 88cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 89cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 90cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 91cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return shndx == addr_shndx; 92cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 93cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 94cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Keep track of the closest symbol we have seen so far. 95cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Here we store only symbols with nonzero st_size. */ 96cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng const char *closest_name = NULL; 97cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Word closest_shndx = SHN_UNDEF; 98cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 99cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Keep track of an eligible symbol with st_size == 0 as a fallback. */ 100cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng const char *sizeless_name = NULL; 101cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Sym sizeless_sym = { 0, 0, 0, 0, 0, SHN_UNDEF }; 102cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Word sizeless_shndx = SHN_UNDEF; 103cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 104cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Keep track of the lowest address a relevant sizeless symbol could have. */ 105cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Addr min_label = 0; 106cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 107cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Look through the symbol table for a matching symbol. */ 108cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng for (int i = 1; i < syments; ++i) 109cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 110cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Sym sym; 111cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Word shndx; 112cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng const char *name = INTUSE(dwfl_module_getsym) (mod, i, &sym, &shndx); 113cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (name != NULL && name[0] != '\0' 114cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && sym.st_shndx != SHN_UNDEF 115cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && sym.st_value <= addr 116cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && GELF_ST_TYPE (sym.st_info) != STT_SECTION 117cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && GELF_ST_TYPE (sym.st_info) != STT_FILE 118cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && GELF_ST_TYPE (sym.st_info) != STT_TLS) 119cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 120cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Even if we don't choose this symbol, its existence excludes 121cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng any sizeless symbol (assembly label) that is below its upper 122cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng bound. */ 123cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (sym.st_value + sym.st_size > min_label) 124cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng min_label = sym.st_value + sym.st_size; 125cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 126cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (sym.st_size == 0 || addr - sym.st_value < sym.st_size) 127cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 128cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* This symbol is a better candidate than the current one 129cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if it's closer to ADDR or is global when it was local. */ 130cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (closest_name == NULL 131cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng || closest_sym->st_value < sym.st_value 132cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng || (GELF_ST_BIND (closest_sym->st_info) 133cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng < GELF_ST_BIND (sym.st_info))) 134cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 135cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (sym.st_size != 0) 136cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 137cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng *closest_sym = sym; 138cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng closest_shndx = shndx; 139cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng closest_name = name; 140cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 141cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng else if (same_section (&sym, shndx)) 142cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 143cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Handwritten assembly symbols sometimes have no 144cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng st_size. If no symbol with proper size includes 145cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng the address, we'll use the closest one that is in 146cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng the same section as ADDR. */ 147cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng sizeless_sym = sym; 148cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng sizeless_shndx = shndx; 149cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng sizeless_name = name; 150cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 151cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 152cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* When the beginning of its range is no closer, 153cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng the end of its range might be. But do not 154cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng replace a global symbol with a local! */ 155cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng else if (sym.st_size != 0 156cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && closest_sym->st_value == sym.st_value 157cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && closest_sym->st_size > sym.st_size 158cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && (GELF_ST_BIND (closest_sym->st_info) 159cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng <= GELF_ST_BIND (sym.st_info))) 160cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 161cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng *closest_sym = sym; 162cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng closest_shndx = shndx; 163cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng closest_name = name; 164cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 165cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 166cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 167cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 168cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 169cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* If we found no proper sized symbol to use, fall back to the best 170cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng candidate sizeless symbol we found, if any. */ 171cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (closest_name == NULL 172cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && sizeless_name != NULL && sizeless_sym.st_value >= min_label) 173cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 174cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng *closest_sym = sizeless_sym; 175cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng closest_shndx = sizeless_shndx; 176cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng closest_name = sizeless_name; 177cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 178cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 179cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (shndxp != NULL) 180cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng *shndxp = closest_shndx; 181cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return closest_name; 182cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng} 183cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengINTDEF (dwfl_module_addrsym) 184