xref: /aosp_15_r20/external/elfutils/libdwfl/dwfl_module_addrsym.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
1*7304104dSAndroid Build Coastguard Worker /* Find debugging and symbol information for a module in libdwfl.
2*7304104dSAndroid Build Coastguard Worker    Copyright (C) 2005-2013 Red Hat, Inc.
3*7304104dSAndroid Build Coastguard Worker    This file is part of elfutils.
4*7304104dSAndroid Build Coastguard Worker 
5*7304104dSAndroid Build Coastguard Worker    This file is free software; you can redistribute it and/or modify
6*7304104dSAndroid Build Coastguard Worker    it under the terms of either
7*7304104dSAndroid Build Coastguard Worker 
8*7304104dSAndroid Build Coastguard Worker      * the GNU Lesser General Public License as published by the Free
9*7304104dSAndroid Build Coastguard Worker        Software Foundation; either version 3 of the License, or (at
10*7304104dSAndroid Build Coastguard Worker        your option) any later version
11*7304104dSAndroid Build Coastguard Worker 
12*7304104dSAndroid Build Coastguard Worker    or
13*7304104dSAndroid Build Coastguard Worker 
14*7304104dSAndroid Build Coastguard Worker      * the GNU General Public License as published by the Free
15*7304104dSAndroid Build Coastguard Worker        Software Foundation; either version 2 of the License, or (at
16*7304104dSAndroid Build Coastguard Worker        your option) any later version
17*7304104dSAndroid Build Coastguard Worker 
18*7304104dSAndroid Build Coastguard Worker    or both in parallel, as here.
19*7304104dSAndroid Build Coastguard Worker 
20*7304104dSAndroid Build Coastguard Worker    elfutils is distributed in the hope that it will be useful, but
21*7304104dSAndroid Build Coastguard Worker    WITHOUT ANY WARRANTY; without even the implied warranty of
22*7304104dSAndroid Build Coastguard Worker    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23*7304104dSAndroid Build Coastguard Worker    General Public License for more details.
24*7304104dSAndroid Build Coastguard Worker 
25*7304104dSAndroid Build Coastguard Worker    You should have received copies of the GNU General Public License and
26*7304104dSAndroid Build Coastguard Worker    the GNU Lesser General Public License along with this program.  If
27*7304104dSAndroid Build Coastguard Worker    not, see <http://www.gnu.org/licenses/>.  */
28*7304104dSAndroid Build Coastguard Worker 
29*7304104dSAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
30*7304104dSAndroid Build Coastguard Worker # include <config.h>
31*7304104dSAndroid Build Coastguard Worker #endif
32*7304104dSAndroid Build Coastguard Worker 
33*7304104dSAndroid Build Coastguard Worker #include "libdwflP.h"
34*7304104dSAndroid Build Coastguard Worker 
35*7304104dSAndroid Build Coastguard Worker struct search_state
36*7304104dSAndroid Build Coastguard Worker {
37*7304104dSAndroid Build Coastguard Worker   Dwfl_Module *mod;
38*7304104dSAndroid Build Coastguard Worker   GElf_Addr addr;
39*7304104dSAndroid Build Coastguard Worker 
40*7304104dSAndroid Build Coastguard Worker   GElf_Sym *closest_sym;
41*7304104dSAndroid Build Coastguard Worker   bool adjust_st_value;
42*7304104dSAndroid Build Coastguard Worker   GElf_Word addr_shndx;
43*7304104dSAndroid Build Coastguard Worker   Elf *addr_symelf;
44*7304104dSAndroid Build Coastguard Worker 
45*7304104dSAndroid Build Coastguard Worker   /* Keep track of the closest symbol we have seen so far.
46*7304104dSAndroid Build Coastguard Worker      Here we store only symbols with nonzero st_size.  */
47*7304104dSAndroid Build Coastguard Worker   const char *closest_name;
48*7304104dSAndroid Build Coastguard Worker   GElf_Addr closest_value;
49*7304104dSAndroid Build Coastguard Worker   GElf_Word closest_shndx;
50*7304104dSAndroid Build Coastguard Worker   Elf *closest_elf;
51*7304104dSAndroid Build Coastguard Worker 
52*7304104dSAndroid Build Coastguard Worker   /* Keep track of an eligible symbol with st_size == 0 as a fallback.  */
53*7304104dSAndroid Build Coastguard Worker   const char *sizeless_name;
54*7304104dSAndroid Build Coastguard Worker   GElf_Sym sizeless_sym;
55*7304104dSAndroid Build Coastguard Worker   GElf_Addr sizeless_value;
56*7304104dSAndroid Build Coastguard Worker   GElf_Word sizeless_shndx;
57*7304104dSAndroid Build Coastguard Worker   Elf *sizeless_elf;
58*7304104dSAndroid Build Coastguard Worker 
59*7304104dSAndroid Build Coastguard Worker   /* Keep track of the lowest address a relevant sizeless symbol could have.  */
60*7304104dSAndroid Build Coastguard Worker   GElf_Addr min_label;
61*7304104dSAndroid Build Coastguard Worker };
62*7304104dSAndroid Build Coastguard Worker 
63*7304104dSAndroid Build Coastguard Worker /* Return true iff we consider ADDR to lie in the same section as SYM.  */
64*7304104dSAndroid Build Coastguard Worker static inline bool
same_section(struct search_state * state,GElf_Addr value,Elf * symelf,GElf_Word shndx)65*7304104dSAndroid Build Coastguard Worker same_section (struct search_state *state,
66*7304104dSAndroid Build Coastguard Worker 	      GElf_Addr value, Elf *symelf, GElf_Word shndx)
67*7304104dSAndroid Build Coastguard Worker {
68*7304104dSAndroid Build Coastguard Worker   /* For absolute symbols and the like, only match exactly.  */
69*7304104dSAndroid Build Coastguard Worker   if (shndx >= SHN_LORESERVE)
70*7304104dSAndroid Build Coastguard Worker     return value == state->addr;
71*7304104dSAndroid Build Coastguard Worker 
72*7304104dSAndroid Build Coastguard Worker   /* If value might not be st_value, the shndx of the symbol might
73*7304104dSAndroid Build Coastguard Worker       not match the section of the value. Explicitly look both up.  */
74*7304104dSAndroid Build Coastguard Worker   if (! state->adjust_st_value)
75*7304104dSAndroid Build Coastguard Worker     {
76*7304104dSAndroid Build Coastguard Worker       Dwarf_Addr v;
77*7304104dSAndroid Build Coastguard Worker       if (state->addr_shndx == SHN_UNDEF)
78*7304104dSAndroid Build Coastguard Worker         {
79*7304104dSAndroid Build Coastguard Worker           v = state->addr;
80*7304104dSAndroid Build Coastguard Worker           state->addr_shndx = __libdwfl_find_section_ndx (state->mod, &v);
81*7304104dSAndroid Build Coastguard Worker         }
82*7304104dSAndroid Build Coastguard Worker 
83*7304104dSAndroid Build Coastguard Worker       v = value;
84*7304104dSAndroid Build Coastguard Worker       return state->addr_shndx == __libdwfl_find_section_ndx (state->mod, &v);
85*7304104dSAndroid Build Coastguard Worker     }
86*7304104dSAndroid Build Coastguard Worker 
87*7304104dSAndroid Build Coastguard Worker   /* Figure out what section ADDR lies in.  */
88*7304104dSAndroid Build Coastguard Worker   if (state->addr_shndx == SHN_UNDEF || state->addr_symelf != symelf)
89*7304104dSAndroid Build Coastguard Worker     {
90*7304104dSAndroid Build Coastguard Worker       GElf_Addr mod_addr = dwfl_deadjust_st_value (state->mod, symelf,
91*7304104dSAndroid Build Coastguard Worker 						   state->addr);
92*7304104dSAndroid Build Coastguard Worker       Elf_Scn *scn = NULL;
93*7304104dSAndroid Build Coastguard Worker       state->addr_shndx = SHN_ABS;
94*7304104dSAndroid Build Coastguard Worker       state->addr_symelf = symelf;
95*7304104dSAndroid Build Coastguard Worker       while ((scn = elf_nextscn (symelf, scn)) != NULL)
96*7304104dSAndroid Build Coastguard Worker         {
97*7304104dSAndroid Build Coastguard Worker           GElf_Shdr shdr_mem;
98*7304104dSAndroid Build Coastguard Worker           GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
99*7304104dSAndroid Build Coastguard Worker           if (likely (shdr != NULL)
100*7304104dSAndroid Build Coastguard Worker               && mod_addr >= shdr->sh_addr
101*7304104dSAndroid Build Coastguard Worker               && mod_addr < shdr->sh_addr + shdr->sh_size)
102*7304104dSAndroid Build Coastguard Worker             {
103*7304104dSAndroid Build Coastguard Worker               state->addr_shndx = elf_ndxscn (scn);
104*7304104dSAndroid Build Coastguard Worker               break;
105*7304104dSAndroid Build Coastguard Worker             }
106*7304104dSAndroid Build Coastguard Worker         }
107*7304104dSAndroid Build Coastguard Worker     }
108*7304104dSAndroid Build Coastguard Worker 
109*7304104dSAndroid Build Coastguard Worker   return shndx == state->addr_shndx && state->addr_symelf == symelf;
110*7304104dSAndroid Build Coastguard Worker }
111*7304104dSAndroid Build Coastguard Worker 
112*7304104dSAndroid Build Coastguard Worker /* Return GELF_ST_BIND as higher-is-better integer.  */
113*7304104dSAndroid Build Coastguard Worker static inline int
binding_value(const GElf_Sym * symp)114*7304104dSAndroid Build Coastguard Worker binding_value (const GElf_Sym *symp)
115*7304104dSAndroid Build Coastguard Worker {
116*7304104dSAndroid Build Coastguard Worker   switch (GELF_ST_BIND (symp->st_info))
117*7304104dSAndroid Build Coastguard Worker     {
118*7304104dSAndroid Build Coastguard Worker     case STB_GLOBAL:
119*7304104dSAndroid Build Coastguard Worker       return 3;
120*7304104dSAndroid Build Coastguard Worker     case STB_WEAK:
121*7304104dSAndroid Build Coastguard Worker       return 2;
122*7304104dSAndroid Build Coastguard Worker     case STB_LOCAL:
123*7304104dSAndroid Build Coastguard Worker       return 1;
124*7304104dSAndroid Build Coastguard Worker     default:
125*7304104dSAndroid Build Coastguard Worker       return 0;
126*7304104dSAndroid Build Coastguard Worker     }
127*7304104dSAndroid Build Coastguard Worker }
128*7304104dSAndroid Build Coastguard Worker 
129*7304104dSAndroid Build Coastguard Worker /* Try one symbol and associated value from the search table.  */
130*7304104dSAndroid Build Coastguard Worker static inline void
try_sym_value(struct search_state * state,GElf_Addr value,GElf_Sym * sym,const char * name,GElf_Word shndx,Elf * elf,bool resolved)131*7304104dSAndroid Build Coastguard Worker try_sym_value (struct search_state *state,
132*7304104dSAndroid Build Coastguard Worker                GElf_Addr value, GElf_Sym *sym,
133*7304104dSAndroid Build Coastguard Worker                const char *name, GElf_Word shndx,
134*7304104dSAndroid Build Coastguard Worker                Elf *elf, bool resolved)
135*7304104dSAndroid Build Coastguard Worker {
136*7304104dSAndroid Build Coastguard Worker     /* Even if we don't choose this symbol, its existence excludes
137*7304104dSAndroid Build Coastguard Worker        any sizeless symbol (assembly label) that is below its upper
138*7304104dSAndroid Build Coastguard Worker        bound.  */
139*7304104dSAndroid Build Coastguard Worker     if (value + sym->st_size > state->min_label)
140*7304104dSAndroid Build Coastguard Worker       state->min_label = value + sym->st_size;
141*7304104dSAndroid Build Coastguard Worker 
142*7304104dSAndroid Build Coastguard Worker     if (sym->st_size == 0 || state->addr - value < sym->st_size)
143*7304104dSAndroid Build Coastguard Worker       {
144*7304104dSAndroid Build Coastguard Worker 	/* This symbol is a better candidate than the current one
145*7304104dSAndroid Build Coastguard Worker 	   if it's closer to ADDR or is global when it was local.  */
146*7304104dSAndroid Build Coastguard Worker 	if (state->closest_name == NULL
147*7304104dSAndroid Build Coastguard Worker 	    || state->closest_value < value
148*7304104dSAndroid Build Coastguard Worker 	    || binding_value (state->closest_sym) < binding_value (sym))
149*7304104dSAndroid Build Coastguard Worker 	  {
150*7304104dSAndroid Build Coastguard Worker 	    if (sym->st_size != 0)
151*7304104dSAndroid Build Coastguard Worker 	      {
152*7304104dSAndroid Build Coastguard Worker 		*state->closest_sym = *sym;
153*7304104dSAndroid Build Coastguard Worker 		state->closest_value = value;
154*7304104dSAndroid Build Coastguard Worker 		state->closest_shndx = shndx;
155*7304104dSAndroid Build Coastguard Worker 		state->closest_elf = elf;
156*7304104dSAndroid Build Coastguard Worker 		state->closest_name = name;
157*7304104dSAndroid Build Coastguard Worker 	      }
158*7304104dSAndroid Build Coastguard Worker 	    else if (state->closest_name == NULL
159*7304104dSAndroid Build Coastguard Worker 		     && value >= state->min_label
160*7304104dSAndroid Build Coastguard Worker 		     && same_section (state, value,
161*7304104dSAndroid Build Coastguard Worker 				      resolved ? state->mod->main.elf : elf,
162*7304104dSAndroid Build Coastguard Worker 				      shndx))
163*7304104dSAndroid Build Coastguard Worker 	      {
164*7304104dSAndroid Build Coastguard Worker 		/* Handwritten assembly symbols sometimes have no
165*7304104dSAndroid Build Coastguard Worker 		   st_size.  If no symbol with proper size includes
166*7304104dSAndroid Build Coastguard Worker 		   the address, we'll use the closest one that is in
167*7304104dSAndroid Build Coastguard Worker 		   the same section as ADDR.  */
168*7304104dSAndroid Build Coastguard Worker 		state->sizeless_sym = *sym;
169*7304104dSAndroid Build Coastguard Worker 		state->sizeless_value = value;
170*7304104dSAndroid Build Coastguard Worker 		state->sizeless_shndx = shndx;
171*7304104dSAndroid Build Coastguard Worker 		state->sizeless_elf = elf;
172*7304104dSAndroid Build Coastguard Worker 		state->sizeless_name = name;
173*7304104dSAndroid Build Coastguard Worker 	      }
174*7304104dSAndroid Build Coastguard Worker 	  }
175*7304104dSAndroid Build Coastguard Worker 	/* When the beginning of its range is no closer,
176*7304104dSAndroid Build Coastguard Worker 	   the end of its range might be.  Otherwise follow
177*7304104dSAndroid Build Coastguard Worker 	   GELF_ST_BIND preference.  If all are equal prefer
178*7304104dSAndroid Build Coastguard Worker 	   the first symbol found.  */
179*7304104dSAndroid Build Coastguard Worker 	else if (sym->st_size != 0
180*7304104dSAndroid Build Coastguard Worker 		 && state->closest_value == value
181*7304104dSAndroid Build Coastguard Worker 		 && ((state->closest_sym->st_size > sym->st_size
182*7304104dSAndroid Build Coastguard Worker 		      && (binding_value (state->closest_sym)
183*7304104dSAndroid Build Coastguard Worker 			  <= binding_value (sym)))
184*7304104dSAndroid Build Coastguard Worker 		     || (state->closest_sym->st_size >= sym->st_size
185*7304104dSAndroid Build Coastguard Worker 			 && (binding_value (state->closest_sym)
186*7304104dSAndroid Build Coastguard Worker 			     < binding_value (sym)))))
187*7304104dSAndroid Build Coastguard Worker 	  {
188*7304104dSAndroid Build Coastguard Worker 	    *state->closest_sym = *sym;
189*7304104dSAndroid Build Coastguard Worker 	    state->closest_value = value;
190*7304104dSAndroid Build Coastguard Worker 	    state->closest_shndx = shndx;
191*7304104dSAndroid Build Coastguard Worker 	    state->closest_elf = elf;
192*7304104dSAndroid Build Coastguard Worker 	    state->closest_name = name;
193*7304104dSAndroid Build Coastguard Worker 	  }
194*7304104dSAndroid Build Coastguard Worker       }
195*7304104dSAndroid Build Coastguard Worker }
196*7304104dSAndroid Build Coastguard Worker 
197*7304104dSAndroid Build Coastguard Worker /* Look through the symbol table for a matching symbol.  */
198*7304104dSAndroid Build Coastguard Worker static inline void
search_table(struct search_state * state,int start,int end)199*7304104dSAndroid Build Coastguard Worker search_table (struct search_state *state, int start, int end)
200*7304104dSAndroid Build Coastguard Worker {
201*7304104dSAndroid Build Coastguard Worker       for (int i = start; i < end; ++i)
202*7304104dSAndroid Build Coastguard Worker 	{
203*7304104dSAndroid Build Coastguard Worker 	  GElf_Sym sym;
204*7304104dSAndroid Build Coastguard Worker 	  GElf_Addr value;
205*7304104dSAndroid Build Coastguard Worker 	  GElf_Word shndx;
206*7304104dSAndroid Build Coastguard Worker 	  Elf *elf;
207*7304104dSAndroid Build Coastguard Worker 	  bool resolved;
208*7304104dSAndroid Build Coastguard Worker 	  const char *name = __libdwfl_getsym (state->mod, i, &sym, &value,
209*7304104dSAndroid Build Coastguard Worker 					       &shndx, &elf, NULL,
210*7304104dSAndroid Build Coastguard Worker 					       &resolved,
211*7304104dSAndroid Build Coastguard Worker 					       state->adjust_st_value);
212*7304104dSAndroid Build Coastguard Worker 	  if (name != NULL && name[0] != '\0'
213*7304104dSAndroid Build Coastguard Worker 	      && sym.st_shndx != SHN_UNDEF
214*7304104dSAndroid Build Coastguard Worker 	      && value <= state->addr
215*7304104dSAndroid Build Coastguard Worker 	      && GELF_ST_TYPE (sym.st_info) != STT_SECTION
216*7304104dSAndroid Build Coastguard Worker 	      && GELF_ST_TYPE (sym.st_info) != STT_FILE
217*7304104dSAndroid Build Coastguard Worker 	      && GELF_ST_TYPE (sym.st_info) != STT_TLS)
218*7304104dSAndroid Build Coastguard Worker 	    {
219*7304104dSAndroid Build Coastguard Worker 	      try_sym_value (state, value, &sym, name, shndx, elf, resolved);
220*7304104dSAndroid Build Coastguard Worker 
221*7304104dSAndroid Build Coastguard Worker 	      /* If this is an addrinfo variant and the value could be
222*7304104dSAndroid Build Coastguard Worker 		 resolved then also try matching the (adjusted) st_value.  */
223*7304104dSAndroid Build Coastguard Worker 	      if (resolved && state->mod->e_type != ET_REL)
224*7304104dSAndroid Build Coastguard Worker 		{
225*7304104dSAndroid Build Coastguard Worker 		  GElf_Addr adjusted_st_value;
226*7304104dSAndroid Build Coastguard Worker 		  adjusted_st_value = dwfl_adjusted_st_value (state->mod, elf,
227*7304104dSAndroid Build Coastguard Worker 							      sym.st_value);
228*7304104dSAndroid Build Coastguard Worker 		  if (value != adjusted_st_value
229*7304104dSAndroid Build Coastguard Worker 		      && adjusted_st_value <= state->addr)
230*7304104dSAndroid Build Coastguard Worker 		    try_sym_value (state, adjusted_st_value, &sym, name, shndx,
231*7304104dSAndroid Build Coastguard Worker 				   elf, false);
232*7304104dSAndroid Build Coastguard Worker 		}
233*7304104dSAndroid Build Coastguard Worker 	    }
234*7304104dSAndroid Build Coastguard Worker 	}
235*7304104dSAndroid Build Coastguard Worker }
236*7304104dSAndroid Build Coastguard Worker 
237*7304104dSAndroid Build Coastguard Worker /* Returns the name of the symbol "closest" to ADDR.
238*7304104dSAndroid Build Coastguard Worker    Never returns symbols at addresses above ADDR.
239*7304104dSAndroid Build Coastguard Worker 
240*7304104dSAndroid Build Coastguard Worker    Wrapper for old dwfl_module_addrsym and new dwfl_module_addrinfo.
241*7304104dSAndroid Build Coastguard Worker    adjust_st_value set to true returns adjusted SYM st_value, set to false
242*7304104dSAndroid Build Coastguard Worker    it will not adjust SYM at all, but does match against resolved values.   */
243*7304104dSAndroid Build Coastguard Worker static const char *
__libdwfl_addrsym(Dwfl_Module * _mod,GElf_Addr _addr,GElf_Off * off,GElf_Sym * _closest_sym,GElf_Word * shndxp,Elf ** elfp,Dwarf_Addr * biasp,bool _adjust_st_value)244*7304104dSAndroid Build Coastguard Worker __libdwfl_addrsym (Dwfl_Module *_mod, GElf_Addr _addr, GElf_Off *off,
245*7304104dSAndroid Build Coastguard Worker 		   GElf_Sym *_closest_sym, GElf_Word *shndxp,
246*7304104dSAndroid Build Coastguard Worker 		   Elf **elfp, Dwarf_Addr *biasp, bool _adjust_st_value)
247*7304104dSAndroid Build Coastguard Worker {
248*7304104dSAndroid Build Coastguard Worker   int syments = INTUSE(dwfl_module_getsymtab) (_mod);
249*7304104dSAndroid Build Coastguard Worker   if (syments < 0)
250*7304104dSAndroid Build Coastguard Worker     return NULL;
251*7304104dSAndroid Build Coastguard Worker 
252*7304104dSAndroid Build Coastguard Worker   struct search_state state =
253*7304104dSAndroid Build Coastguard Worker     {
254*7304104dSAndroid Build Coastguard Worker       .addr = _addr,
255*7304104dSAndroid Build Coastguard Worker       .mod = _mod,
256*7304104dSAndroid Build Coastguard Worker       .closest_sym = _closest_sym,
257*7304104dSAndroid Build Coastguard Worker       .adjust_st_value = _adjust_st_value,
258*7304104dSAndroid Build Coastguard Worker       .addr_shndx = SHN_UNDEF,
259*7304104dSAndroid Build Coastguard Worker       .addr_symelf = NULL,
260*7304104dSAndroid Build Coastguard Worker       .closest_name = NULL,
261*7304104dSAndroid Build Coastguard Worker       .closest_value = 0,
262*7304104dSAndroid Build Coastguard Worker       .closest_shndx = SHN_UNDEF,
263*7304104dSAndroid Build Coastguard Worker       .closest_elf = NULL,
264*7304104dSAndroid Build Coastguard Worker       .sizeless_name = NULL,
265*7304104dSAndroid Build Coastguard Worker       .sizeless_sym = { 0, 0, 0, 0, 0, SHN_UNDEF },
266*7304104dSAndroid Build Coastguard Worker       .sizeless_value = 0,
267*7304104dSAndroid Build Coastguard Worker       .sizeless_shndx = SHN_UNDEF,
268*7304104dSAndroid Build Coastguard Worker       .sizeless_elf = NULL,
269*7304104dSAndroid Build Coastguard Worker       .min_label = 0
270*7304104dSAndroid Build Coastguard Worker     };
271*7304104dSAndroid Build Coastguard Worker 
272*7304104dSAndroid Build Coastguard Worker   /* First go through global symbols.  mod->first_global and
273*7304104dSAndroid Build Coastguard Worker      mod->aux_first_global are setup by dwfl_module_getsymtab to the
274*7304104dSAndroid Build Coastguard Worker      index of the first global symbol in those symbol tables.  Both
275*7304104dSAndroid Build Coastguard Worker      are non-zero when the table exist, except when there is only a
276*7304104dSAndroid Build Coastguard Worker      dynsym table loaded through phdrs, then first_global is zero and
277*7304104dSAndroid Build Coastguard Worker      there will be no auxiliary table.  All symbols with local binding
278*7304104dSAndroid Build Coastguard Worker      come first in the symbol table, then all globals.  The zeroth,
279*7304104dSAndroid Build Coastguard Worker      null entry, in the auxiliary table is skipped if there is a main
280*7304104dSAndroid Build Coastguard Worker      table.  */
281*7304104dSAndroid Build Coastguard Worker   int first_global = INTUSE (dwfl_module_getsymtab_first_global) (state.mod);
282*7304104dSAndroid Build Coastguard Worker   if (first_global < 0)
283*7304104dSAndroid Build Coastguard Worker     return NULL;
284*7304104dSAndroid Build Coastguard Worker   search_table (&state, first_global == 0 ? 1 : first_global, syments);
285*7304104dSAndroid Build Coastguard Worker 
286*7304104dSAndroid Build Coastguard Worker   /* If we found nothing searching the global symbols, then try the locals.
287*7304104dSAndroid Build Coastguard Worker      Unless we have a global sizeless symbol that matches exactly.  */
288*7304104dSAndroid Build Coastguard Worker   if (state.closest_name == NULL && first_global > 1
289*7304104dSAndroid Build Coastguard Worker       && (state.sizeless_name == NULL || state.sizeless_value != state.addr))
290*7304104dSAndroid Build Coastguard Worker     search_table (&state, 1, first_global);
291*7304104dSAndroid Build Coastguard Worker 
292*7304104dSAndroid Build Coastguard Worker   /* If we found no proper sized symbol to use, fall back to the best
293*7304104dSAndroid Build Coastguard Worker      candidate sizeless symbol we found, if any.  */
294*7304104dSAndroid Build Coastguard Worker   if (state.closest_name == NULL
295*7304104dSAndroid Build Coastguard Worker       && state.sizeless_name != NULL
296*7304104dSAndroid Build Coastguard Worker       && state.sizeless_value >= state.min_label)
297*7304104dSAndroid Build Coastguard Worker     {
298*7304104dSAndroid Build Coastguard Worker       *state.closest_sym = state.sizeless_sym;
299*7304104dSAndroid Build Coastguard Worker       state.closest_value = state.sizeless_value;
300*7304104dSAndroid Build Coastguard Worker       state.closest_shndx = state.sizeless_shndx;
301*7304104dSAndroid Build Coastguard Worker       state.closest_elf = state.sizeless_elf;
302*7304104dSAndroid Build Coastguard Worker       state.closest_name = state.sizeless_name;
303*7304104dSAndroid Build Coastguard Worker     }
304*7304104dSAndroid Build Coastguard Worker 
305*7304104dSAndroid Build Coastguard Worker   *off = state.addr - state.closest_value;
306*7304104dSAndroid Build Coastguard Worker 
307*7304104dSAndroid Build Coastguard Worker   if (shndxp != NULL)
308*7304104dSAndroid Build Coastguard Worker     *shndxp = state.closest_shndx;
309*7304104dSAndroid Build Coastguard Worker   if (elfp != NULL)
310*7304104dSAndroid Build Coastguard Worker     *elfp = state.closest_elf;
311*7304104dSAndroid Build Coastguard Worker   if (biasp != NULL)
312*7304104dSAndroid Build Coastguard Worker     *biasp = dwfl_adjusted_st_value (state.mod, state.closest_elf, 0);
313*7304104dSAndroid Build Coastguard Worker   return state.closest_name;
314*7304104dSAndroid Build Coastguard Worker }
315*7304104dSAndroid Build Coastguard Worker 
316*7304104dSAndroid Build Coastguard Worker 
317*7304104dSAndroid Build Coastguard Worker const char *
dwfl_module_addrsym(Dwfl_Module * mod,GElf_Addr addr,GElf_Sym * closest_sym,GElf_Word * shndxp)318*7304104dSAndroid Build Coastguard Worker dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
319*7304104dSAndroid Build Coastguard Worker 		     GElf_Sym *closest_sym, GElf_Word *shndxp)
320*7304104dSAndroid Build Coastguard Worker {
321*7304104dSAndroid Build Coastguard Worker   GElf_Off off;
322*7304104dSAndroid Build Coastguard Worker   return __libdwfl_addrsym (mod, addr, &off, closest_sym, shndxp,
323*7304104dSAndroid Build Coastguard Worker 			    NULL, NULL, true);
324*7304104dSAndroid Build Coastguard Worker }
INTDEF(dwfl_module_addrsym)325*7304104dSAndroid Build Coastguard Worker INTDEF (dwfl_module_addrsym)
326*7304104dSAndroid Build Coastguard Worker 
327*7304104dSAndroid Build Coastguard Worker const char
328*7304104dSAndroid Build Coastguard Worker *dwfl_module_addrinfo (Dwfl_Module *mod, GElf_Addr address,
329*7304104dSAndroid Build Coastguard Worker 		       GElf_Off *offset, GElf_Sym *sym,
330*7304104dSAndroid Build Coastguard Worker 		       GElf_Word *shndxp, Elf **elfp, Dwarf_Addr *bias)
331*7304104dSAndroid Build Coastguard Worker {
332*7304104dSAndroid Build Coastguard Worker   return __libdwfl_addrsym (mod, address, offset, sym, shndxp, elfp, bias,
333*7304104dSAndroid Build Coastguard Worker 			    false);
334*7304104dSAndroid Build Coastguard Worker }
335*7304104dSAndroid Build Coastguard Worker INTDEF (dwfl_module_addrinfo)
336