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