xref: /aosp_15_r20/external/elfutils/libdwfl/derelocate.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
1*7304104dSAndroid Build Coastguard Worker /* Recover relocatibility for addresses computed from debug information.
2*7304104dSAndroid Build Coastguard Worker    Copyright (C) 2005-2010, 2013, 2015 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 dwfl_relocation
36*7304104dSAndroid Build Coastguard Worker {
37*7304104dSAndroid Build Coastguard Worker   size_t count;
38*7304104dSAndroid Build Coastguard Worker   struct
39*7304104dSAndroid Build Coastguard Worker   {
40*7304104dSAndroid Build Coastguard Worker     Elf_Scn *scn;
41*7304104dSAndroid Build Coastguard Worker     Elf_Scn *relocs;
42*7304104dSAndroid Build Coastguard Worker     const char *name;
43*7304104dSAndroid Build Coastguard Worker     GElf_Addr start, end;
44*7304104dSAndroid Build Coastguard Worker   } refs[0];
45*7304104dSAndroid Build Coastguard Worker };
46*7304104dSAndroid Build Coastguard Worker 
47*7304104dSAndroid Build Coastguard Worker 
48*7304104dSAndroid Build Coastguard Worker struct secref
49*7304104dSAndroid Build Coastguard Worker {
50*7304104dSAndroid Build Coastguard Worker   struct secref *next;
51*7304104dSAndroid Build Coastguard Worker   Elf_Scn *scn;
52*7304104dSAndroid Build Coastguard Worker   Elf_Scn *relocs;
53*7304104dSAndroid Build Coastguard Worker   const char *name;
54*7304104dSAndroid Build Coastguard Worker   GElf_Addr start, end;
55*7304104dSAndroid Build Coastguard Worker };
56*7304104dSAndroid Build Coastguard Worker 
57*7304104dSAndroid Build Coastguard Worker static int
compare_secrefs(const void * a,const void * b)58*7304104dSAndroid Build Coastguard Worker compare_secrefs (const void *a, const void *b)
59*7304104dSAndroid Build Coastguard Worker {
60*7304104dSAndroid Build Coastguard Worker   struct secref *const *p1 = a;
61*7304104dSAndroid Build Coastguard Worker   struct secref *const *p2 = b;
62*7304104dSAndroid Build Coastguard Worker 
63*7304104dSAndroid Build Coastguard Worker   /* No signed difference calculation is correct here, since the
64*7304104dSAndroid Build Coastguard Worker      terms are unsigned and could be more than INT64_MAX apart.  */
65*7304104dSAndroid Build Coastguard Worker   if ((*p1)->start < (*p2)->start)
66*7304104dSAndroid Build Coastguard Worker     return -1;
67*7304104dSAndroid Build Coastguard Worker   if ((*p1)->start > (*p2)->start)
68*7304104dSAndroid Build Coastguard Worker     return 1;
69*7304104dSAndroid Build Coastguard Worker 
70*7304104dSAndroid Build Coastguard Worker   if ((*p1)->end < (*p2)->end)
71*7304104dSAndroid Build Coastguard Worker     return -1;
72*7304104dSAndroid Build Coastguard Worker   if ((*p1)->end > (*p2)->end)
73*7304104dSAndroid Build Coastguard Worker     return 1;
74*7304104dSAndroid Build Coastguard Worker 
75*7304104dSAndroid Build Coastguard Worker   /* Same start/end, then just compare which section came first.  */
76*7304104dSAndroid Build Coastguard Worker   return elf_ndxscn ((*p1)->scn) - elf_ndxscn ((*p2)->scn);
77*7304104dSAndroid Build Coastguard Worker }
78*7304104dSAndroid Build Coastguard Worker 
79*7304104dSAndroid Build Coastguard Worker static int
cache_sections(Dwfl_Module * mod)80*7304104dSAndroid Build Coastguard Worker cache_sections (Dwfl_Module *mod)
81*7304104dSAndroid Build Coastguard Worker {
82*7304104dSAndroid Build Coastguard Worker   if (likely (mod->reloc_info != NULL))
83*7304104dSAndroid Build Coastguard Worker     return mod->reloc_info->count;
84*7304104dSAndroid Build Coastguard Worker 
85*7304104dSAndroid Build Coastguard Worker   struct secref *refs = NULL;
86*7304104dSAndroid Build Coastguard Worker   size_t nrefs = 0;
87*7304104dSAndroid Build Coastguard Worker 
88*7304104dSAndroid Build Coastguard Worker   size_t shstrndx;
89*7304104dSAndroid Build Coastguard Worker   if (unlikely (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0))
90*7304104dSAndroid Build Coastguard Worker     {
91*7304104dSAndroid Build Coastguard Worker     elf_error:
92*7304104dSAndroid Build Coastguard Worker       __libdwfl_seterrno (DWFL_E_LIBELF);
93*7304104dSAndroid Build Coastguard Worker       nrefs = -1;
94*7304104dSAndroid Build Coastguard Worker       goto free_refs;
95*7304104dSAndroid Build Coastguard Worker     }
96*7304104dSAndroid Build Coastguard Worker 
97*7304104dSAndroid Build Coastguard Worker   bool check_reloc_sections = false;
98*7304104dSAndroid Build Coastguard Worker   Elf_Scn *scn = NULL;
99*7304104dSAndroid Build Coastguard Worker   while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
100*7304104dSAndroid Build Coastguard Worker     {
101*7304104dSAndroid Build Coastguard Worker       GElf_Shdr shdr_mem;
102*7304104dSAndroid Build Coastguard Worker       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
103*7304104dSAndroid Build Coastguard Worker       if (shdr == NULL)
104*7304104dSAndroid Build Coastguard Worker 	goto elf_error;
105*7304104dSAndroid Build Coastguard Worker 
106*7304104dSAndroid Build Coastguard Worker       if ((shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr == 0
107*7304104dSAndroid Build Coastguard Worker 	  && mod->e_type == ET_REL)
108*7304104dSAndroid Build Coastguard Worker 	{
109*7304104dSAndroid Build Coastguard Worker 	  /* This section might not yet have been looked at.  */
110*7304104dSAndroid Build Coastguard Worker 	  if (__libdwfl_relocate_value (mod, mod->main.elf, &shstrndx,
111*7304104dSAndroid Build Coastguard Worker 					elf_ndxscn (scn),
112*7304104dSAndroid Build Coastguard Worker 					&shdr->sh_addr) != DWFL_E_NOERROR)
113*7304104dSAndroid Build Coastguard Worker 	    continue;
114*7304104dSAndroid Build Coastguard Worker 	  shdr = gelf_getshdr (scn, &shdr_mem);
115*7304104dSAndroid Build Coastguard Worker 	  if (unlikely (shdr == NULL))
116*7304104dSAndroid Build Coastguard Worker 	    goto elf_error;
117*7304104dSAndroid Build Coastguard Worker 	}
118*7304104dSAndroid Build Coastguard Worker 
119*7304104dSAndroid Build Coastguard Worker       if (shdr->sh_flags & SHF_ALLOC)
120*7304104dSAndroid Build Coastguard Worker 	{
121*7304104dSAndroid Build Coastguard Worker 	  const char *name = elf_strptr (mod->main.elf, shstrndx,
122*7304104dSAndroid Build Coastguard Worker 					 shdr->sh_name);
123*7304104dSAndroid Build Coastguard Worker 	  if (unlikely (name == NULL))
124*7304104dSAndroid Build Coastguard Worker 	    goto elf_error;
125*7304104dSAndroid Build Coastguard Worker 
126*7304104dSAndroid Build Coastguard Worker 	  struct secref *newref = malloc (sizeof *newref);
127*7304104dSAndroid Build Coastguard Worker 	  if (unlikely (newref == NULL))
128*7304104dSAndroid Build Coastguard Worker 	    {
129*7304104dSAndroid Build Coastguard Worker 	    nomem:
130*7304104dSAndroid Build Coastguard Worker 	      __libdwfl_seterrno (DWFL_E_NOMEM);
131*7304104dSAndroid Build Coastguard Worker 	      nrefs = -1;
132*7304104dSAndroid Build Coastguard Worker 	      goto free_refs;
133*7304104dSAndroid Build Coastguard Worker 	    }
134*7304104dSAndroid Build Coastguard Worker 
135*7304104dSAndroid Build Coastguard Worker 	  newref->scn = scn;
136*7304104dSAndroid Build Coastguard Worker 	  newref->relocs = NULL;
137*7304104dSAndroid Build Coastguard Worker 	  newref->name = name;
138*7304104dSAndroid Build Coastguard Worker 	  newref->start = dwfl_adjusted_address (mod, shdr->sh_addr);
139*7304104dSAndroid Build Coastguard Worker 	  newref->end = newref->start + shdr->sh_size;
140*7304104dSAndroid Build Coastguard Worker 	  newref->next = refs;
141*7304104dSAndroid Build Coastguard Worker 	  refs = newref;
142*7304104dSAndroid Build Coastguard Worker 	  ++nrefs;
143*7304104dSAndroid Build Coastguard Worker 	}
144*7304104dSAndroid Build Coastguard Worker 
145*7304104dSAndroid Build Coastguard Worker       if (mod->e_type == ET_REL
146*7304104dSAndroid Build Coastguard Worker 	  && shdr->sh_size != 0
147*7304104dSAndroid Build Coastguard Worker 	  && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
148*7304104dSAndroid Build Coastguard Worker 	  && mod->dwfl->callbacks->section_address != NULL)
149*7304104dSAndroid Build Coastguard Worker 	{
150*7304104dSAndroid Build Coastguard Worker 	  if (shdr->sh_info < elf_ndxscn (scn))
151*7304104dSAndroid Build Coastguard Worker 	    {
152*7304104dSAndroid Build Coastguard Worker 	      /* We've already looked at the section these relocs apply to.  */
153*7304104dSAndroid Build Coastguard Worker 	      Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info);
154*7304104dSAndroid Build Coastguard Worker 	      if (likely (tscn != NULL))
155*7304104dSAndroid Build Coastguard Worker 		for (struct secref *sec = refs; sec != NULL; sec = sec->next)
156*7304104dSAndroid Build Coastguard Worker 		  if (sec->scn == tscn)
157*7304104dSAndroid Build Coastguard Worker 		    {
158*7304104dSAndroid Build Coastguard Worker 		      sec->relocs = scn;
159*7304104dSAndroid Build Coastguard Worker 		      break;
160*7304104dSAndroid Build Coastguard Worker 		    }
161*7304104dSAndroid Build Coastguard Worker 	    }
162*7304104dSAndroid Build Coastguard Worker 	  else
163*7304104dSAndroid Build Coastguard Worker 	    /* We'll have to do a second pass.  */
164*7304104dSAndroid Build Coastguard Worker 	    check_reloc_sections = true;
165*7304104dSAndroid Build Coastguard Worker 	}
166*7304104dSAndroid Build Coastguard Worker     }
167*7304104dSAndroid Build Coastguard Worker 
168*7304104dSAndroid Build Coastguard Worker   mod->reloc_info = malloc (offsetof (struct dwfl_relocation, refs[nrefs]));
169*7304104dSAndroid Build Coastguard Worker   if (unlikely (mod->reloc_info == NULL))
170*7304104dSAndroid Build Coastguard Worker     goto nomem;
171*7304104dSAndroid Build Coastguard Worker 
172*7304104dSAndroid Build Coastguard Worker   struct secref **sortrefs = malloc (nrefs * sizeof sortrefs[0]);
173*7304104dSAndroid Build Coastguard Worker   if (unlikely (sortrefs == NULL))
174*7304104dSAndroid Build Coastguard Worker     goto nomem;
175*7304104dSAndroid Build Coastguard Worker 
176*7304104dSAndroid Build Coastguard Worker   for (size_t i = nrefs; i-- > 0; refs = refs->next)
177*7304104dSAndroid Build Coastguard Worker     sortrefs[i] = refs;
178*7304104dSAndroid Build Coastguard Worker   assert (refs == NULL);
179*7304104dSAndroid Build Coastguard Worker 
180*7304104dSAndroid Build Coastguard Worker   qsort (sortrefs, nrefs, sizeof sortrefs[0], &compare_secrefs);
181*7304104dSAndroid Build Coastguard Worker 
182*7304104dSAndroid Build Coastguard Worker   mod->reloc_info->count = nrefs;
183*7304104dSAndroid Build Coastguard Worker   for (size_t i = 0; i < nrefs; ++i)
184*7304104dSAndroid Build Coastguard Worker     {
185*7304104dSAndroid Build Coastguard Worker       mod->reloc_info->refs[i].name = sortrefs[i]->name;
186*7304104dSAndroid Build Coastguard Worker       mod->reloc_info->refs[i].scn = sortrefs[i]->scn;
187*7304104dSAndroid Build Coastguard Worker       mod->reloc_info->refs[i].relocs = sortrefs[i]->relocs;
188*7304104dSAndroid Build Coastguard Worker       mod->reloc_info->refs[i].start = sortrefs[i]->start;
189*7304104dSAndroid Build Coastguard Worker       mod->reloc_info->refs[i].end = sortrefs[i]->end;
190*7304104dSAndroid Build Coastguard Worker       free (sortrefs[i]);
191*7304104dSAndroid Build Coastguard Worker     }
192*7304104dSAndroid Build Coastguard Worker 
193*7304104dSAndroid Build Coastguard Worker   free (sortrefs);
194*7304104dSAndroid Build Coastguard Worker 
195*7304104dSAndroid Build Coastguard Worker   if (unlikely (check_reloc_sections))
196*7304104dSAndroid Build Coastguard Worker     {
197*7304104dSAndroid Build Coastguard Worker       /* There was a reloc section that preceded its target section.
198*7304104dSAndroid Build Coastguard Worker 	 So we have to scan again now that we have cached all the
199*7304104dSAndroid Build Coastguard Worker 	 possible target sections we care about.  */
200*7304104dSAndroid Build Coastguard Worker 
201*7304104dSAndroid Build Coastguard Worker       scn = NULL;
202*7304104dSAndroid Build Coastguard Worker       while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
203*7304104dSAndroid Build Coastguard Worker 	{
204*7304104dSAndroid Build Coastguard Worker 	  GElf_Shdr shdr_mem;
205*7304104dSAndroid Build Coastguard Worker 	  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
206*7304104dSAndroid Build Coastguard Worker 	  if (shdr == NULL)
207*7304104dSAndroid Build Coastguard Worker 	    goto elf_error;
208*7304104dSAndroid Build Coastguard Worker 
209*7304104dSAndroid Build Coastguard Worker       	  if (shdr->sh_size != 0
210*7304104dSAndroid Build Coastguard Worker 	      && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA))
211*7304104dSAndroid Build Coastguard Worker 	    {
212*7304104dSAndroid Build Coastguard Worker 	      Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info);
213*7304104dSAndroid Build Coastguard Worker 	      if (likely (tscn != NULL))
214*7304104dSAndroid Build Coastguard Worker 		for (size_t i = 0; i < nrefs; ++i)
215*7304104dSAndroid Build Coastguard Worker 		  if (mod->reloc_info->refs[i].scn == tscn)
216*7304104dSAndroid Build Coastguard Worker 		    {
217*7304104dSAndroid Build Coastguard Worker 		      mod->reloc_info->refs[i].relocs = scn;
218*7304104dSAndroid Build Coastguard Worker 		      break;
219*7304104dSAndroid Build Coastguard Worker 		    }
220*7304104dSAndroid Build Coastguard Worker 	    }
221*7304104dSAndroid Build Coastguard Worker 	}
222*7304104dSAndroid Build Coastguard Worker     }
223*7304104dSAndroid Build Coastguard Worker 
224*7304104dSAndroid Build Coastguard Worker free_refs:
225*7304104dSAndroid Build Coastguard Worker   while (refs != NULL)
226*7304104dSAndroid Build Coastguard Worker     {
227*7304104dSAndroid Build Coastguard Worker       struct secref *ref = refs;
228*7304104dSAndroid Build Coastguard Worker       refs = ref->next;
229*7304104dSAndroid Build Coastguard Worker       free (ref);
230*7304104dSAndroid Build Coastguard Worker     }
231*7304104dSAndroid Build Coastguard Worker 
232*7304104dSAndroid Build Coastguard Worker   return nrefs;
233*7304104dSAndroid Build Coastguard Worker }
234*7304104dSAndroid Build Coastguard Worker 
235*7304104dSAndroid Build Coastguard Worker 
236*7304104dSAndroid Build Coastguard Worker int
dwfl_module_relocations(Dwfl_Module * mod)237*7304104dSAndroid Build Coastguard Worker dwfl_module_relocations (Dwfl_Module *mod)
238*7304104dSAndroid Build Coastguard Worker {
239*7304104dSAndroid Build Coastguard Worker   if (mod == NULL)
240*7304104dSAndroid Build Coastguard Worker     return -1;
241*7304104dSAndroid Build Coastguard Worker 
242*7304104dSAndroid Build Coastguard Worker   switch (mod->e_type)
243*7304104dSAndroid Build Coastguard Worker     {
244*7304104dSAndroid Build Coastguard Worker     case ET_REL:
245*7304104dSAndroid Build Coastguard Worker       return cache_sections (mod);
246*7304104dSAndroid Build Coastguard Worker 
247*7304104dSAndroid Build Coastguard Worker     case ET_DYN:
248*7304104dSAndroid Build Coastguard Worker       return 1;
249*7304104dSAndroid Build Coastguard Worker 
250*7304104dSAndroid Build Coastguard Worker     case ET_EXEC:
251*7304104dSAndroid Build Coastguard Worker       assert (mod->main.vaddr == mod->low_addr);
252*7304104dSAndroid Build Coastguard Worker       break;
253*7304104dSAndroid Build Coastguard Worker     }
254*7304104dSAndroid Build Coastguard Worker 
255*7304104dSAndroid Build Coastguard Worker   return 0;
256*7304104dSAndroid Build Coastguard Worker }
257*7304104dSAndroid Build Coastguard Worker 
258*7304104dSAndroid Build Coastguard Worker const char *
dwfl_module_relocation_info(Dwfl_Module * mod,unsigned int idx,Elf32_Word * shndxp)259*7304104dSAndroid Build Coastguard Worker dwfl_module_relocation_info (Dwfl_Module *mod, unsigned int idx,
260*7304104dSAndroid Build Coastguard Worker 			     Elf32_Word *shndxp)
261*7304104dSAndroid Build Coastguard Worker {
262*7304104dSAndroid Build Coastguard Worker   if (mod == NULL)
263*7304104dSAndroid Build Coastguard Worker     return NULL;
264*7304104dSAndroid Build Coastguard Worker 
265*7304104dSAndroid Build Coastguard Worker   switch (mod->e_type)
266*7304104dSAndroid Build Coastguard Worker     {
267*7304104dSAndroid Build Coastguard Worker     case ET_REL:
268*7304104dSAndroid Build Coastguard Worker       break;
269*7304104dSAndroid Build Coastguard Worker 
270*7304104dSAndroid Build Coastguard Worker     case ET_DYN:
271*7304104dSAndroid Build Coastguard Worker       if (idx != 0)
272*7304104dSAndroid Build Coastguard Worker 	return NULL;
273*7304104dSAndroid Build Coastguard Worker       if (shndxp)
274*7304104dSAndroid Build Coastguard Worker 	*shndxp = SHN_ABS;
275*7304104dSAndroid Build Coastguard Worker       return "";
276*7304104dSAndroid Build Coastguard Worker 
277*7304104dSAndroid Build Coastguard Worker     default:
278*7304104dSAndroid Build Coastguard Worker       return NULL;
279*7304104dSAndroid Build Coastguard Worker     }
280*7304104dSAndroid Build Coastguard Worker 
281*7304104dSAndroid Build Coastguard Worker   if (cache_sections (mod) < 0)
282*7304104dSAndroid Build Coastguard Worker     return NULL;
283*7304104dSAndroid Build Coastguard Worker 
284*7304104dSAndroid Build Coastguard Worker   struct dwfl_relocation *sections = mod->reloc_info;
285*7304104dSAndroid Build Coastguard Worker 
286*7304104dSAndroid Build Coastguard Worker   if (idx >= sections->count)
287*7304104dSAndroid Build Coastguard Worker     return NULL;
288*7304104dSAndroid Build Coastguard Worker 
289*7304104dSAndroid Build Coastguard Worker   if (shndxp)
290*7304104dSAndroid Build Coastguard Worker     *shndxp = elf_ndxscn (sections->refs[idx].scn);
291*7304104dSAndroid Build Coastguard Worker 
292*7304104dSAndroid Build Coastguard Worker   return sections->refs[idx].name;
293*7304104dSAndroid Build Coastguard Worker }
294*7304104dSAndroid Build Coastguard Worker 
295*7304104dSAndroid Build Coastguard Worker /* Check that MOD is valid and make sure its relocation has been done.  */
296*7304104dSAndroid Build Coastguard Worker static bool
check_module(Dwfl_Module * mod)297*7304104dSAndroid Build Coastguard Worker check_module (Dwfl_Module *mod)
298*7304104dSAndroid Build Coastguard Worker {
299*7304104dSAndroid Build Coastguard Worker   if (mod == NULL)
300*7304104dSAndroid Build Coastguard Worker     return true;
301*7304104dSAndroid Build Coastguard Worker 
302*7304104dSAndroid Build Coastguard Worker   if (INTUSE(dwfl_module_getsymtab) (mod) < 0)
303*7304104dSAndroid Build Coastguard Worker     {
304*7304104dSAndroid Build Coastguard Worker       Dwfl_Error error = dwfl_errno ();
305*7304104dSAndroid Build Coastguard Worker       if (error != DWFL_E_NO_SYMTAB)
306*7304104dSAndroid Build Coastguard Worker 	{
307*7304104dSAndroid Build Coastguard Worker 	  __libdwfl_seterrno (error);
308*7304104dSAndroid Build Coastguard Worker 	  return true;
309*7304104dSAndroid Build Coastguard Worker 	}
310*7304104dSAndroid Build Coastguard Worker     }
311*7304104dSAndroid Build Coastguard Worker 
312*7304104dSAndroid Build Coastguard Worker   if (mod->dw == NULL)
313*7304104dSAndroid Build Coastguard Worker     {
314*7304104dSAndroid Build Coastguard Worker       Dwarf_Addr bias;
315*7304104dSAndroid Build Coastguard Worker       if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
316*7304104dSAndroid Build Coastguard Worker 	{
317*7304104dSAndroid Build Coastguard Worker 	  Dwfl_Error error = dwfl_errno ();
318*7304104dSAndroid Build Coastguard Worker 	  if (error != DWFL_E_NO_DWARF)
319*7304104dSAndroid Build Coastguard Worker 	    {
320*7304104dSAndroid Build Coastguard Worker 	      __libdwfl_seterrno (error);
321*7304104dSAndroid Build Coastguard Worker 	      return true;
322*7304104dSAndroid Build Coastguard Worker 	    }
323*7304104dSAndroid Build Coastguard Worker 	}
324*7304104dSAndroid Build Coastguard Worker     }
325*7304104dSAndroid Build Coastguard Worker 
326*7304104dSAndroid Build Coastguard Worker   return false;
327*7304104dSAndroid Build Coastguard Worker }
328*7304104dSAndroid Build Coastguard Worker 
329*7304104dSAndroid Build Coastguard Worker /* Find the index in MOD->reloc_info.refs containing *ADDR.  */
330*7304104dSAndroid Build Coastguard Worker static int
find_section(Dwfl_Module * mod,Dwarf_Addr * addr)331*7304104dSAndroid Build Coastguard Worker find_section (Dwfl_Module *mod, Dwarf_Addr *addr)
332*7304104dSAndroid Build Coastguard Worker {
333*7304104dSAndroid Build Coastguard Worker   if (cache_sections (mod) < 0)
334*7304104dSAndroid Build Coastguard Worker     return -1;
335*7304104dSAndroid Build Coastguard Worker 
336*7304104dSAndroid Build Coastguard Worker   struct dwfl_relocation *sections = mod->reloc_info;
337*7304104dSAndroid Build Coastguard Worker 
338*7304104dSAndroid Build Coastguard Worker   /* The sections are sorted by address, so we can use binary search.  */
339*7304104dSAndroid Build Coastguard Worker   size_t l = 0, u = sections->count;
340*7304104dSAndroid Build Coastguard Worker   while (l < u)
341*7304104dSAndroid Build Coastguard Worker     {
342*7304104dSAndroid Build Coastguard Worker       size_t idx = (l + u) / 2;
343*7304104dSAndroid Build Coastguard Worker       if (*addr < sections->refs[idx].start)
344*7304104dSAndroid Build Coastguard Worker 	u = idx;
345*7304104dSAndroid Build Coastguard Worker       else if (*addr > sections->refs[idx].end)
346*7304104dSAndroid Build Coastguard Worker 	l = idx + 1;
347*7304104dSAndroid Build Coastguard Worker       else
348*7304104dSAndroid Build Coastguard Worker 	{
349*7304104dSAndroid Build Coastguard Worker 	  /* Consider the limit of a section to be inside it, unless it's
350*7304104dSAndroid Build Coastguard Worker 	     inside the next one.  A section limit address can appear in
351*7304104dSAndroid Build Coastguard Worker 	     line records.  */
352*7304104dSAndroid Build Coastguard Worker 	  if (*addr == sections->refs[idx].end
353*7304104dSAndroid Build Coastguard Worker 	      && idx + 1 < sections->count
354*7304104dSAndroid Build Coastguard Worker 	      && *addr == sections->refs[idx + 1].start)
355*7304104dSAndroid Build Coastguard Worker 	    ++idx;
356*7304104dSAndroid Build Coastguard Worker 
357*7304104dSAndroid Build Coastguard Worker 	  *addr -= sections->refs[idx].start;
358*7304104dSAndroid Build Coastguard Worker 	  return idx;
359*7304104dSAndroid Build Coastguard Worker 	}
360*7304104dSAndroid Build Coastguard Worker     }
361*7304104dSAndroid Build Coastguard Worker 
362*7304104dSAndroid Build Coastguard Worker   __libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_NO_MATCH));
363*7304104dSAndroid Build Coastguard Worker   return -1;
364*7304104dSAndroid Build Coastguard Worker }
365*7304104dSAndroid Build Coastguard Worker 
366*7304104dSAndroid Build Coastguard Worker size_t
367*7304104dSAndroid Build Coastguard Worker internal_function
__libdwfl_find_section_ndx(Dwfl_Module * mod,Dwarf_Addr * addr)368*7304104dSAndroid Build Coastguard Worker __libdwfl_find_section_ndx (Dwfl_Module *mod, Dwarf_Addr *addr)
369*7304104dSAndroid Build Coastguard Worker {
370*7304104dSAndroid Build Coastguard Worker   int idx = find_section (mod, addr);
371*7304104dSAndroid Build Coastguard Worker   if (unlikely (idx == -1))
372*7304104dSAndroid Build Coastguard Worker     return SHN_UNDEF;
373*7304104dSAndroid Build Coastguard Worker 
374*7304104dSAndroid Build Coastguard Worker   return elf_ndxscn (mod->reloc_info->refs[idx].scn);
375*7304104dSAndroid Build Coastguard Worker }
376*7304104dSAndroid Build Coastguard Worker 
377*7304104dSAndroid Build Coastguard Worker int
dwfl_module_relocate_address(Dwfl_Module * mod,Dwarf_Addr * addr)378*7304104dSAndroid Build Coastguard Worker dwfl_module_relocate_address (Dwfl_Module *mod, Dwarf_Addr *addr)
379*7304104dSAndroid Build Coastguard Worker {
380*7304104dSAndroid Build Coastguard Worker   if (unlikely (check_module (mod)))
381*7304104dSAndroid Build Coastguard Worker     return -1;
382*7304104dSAndroid Build Coastguard Worker 
383*7304104dSAndroid Build Coastguard Worker   switch (mod->e_type)
384*7304104dSAndroid Build Coastguard Worker     {
385*7304104dSAndroid Build Coastguard Worker     case ET_REL:
386*7304104dSAndroid Build Coastguard Worker       return find_section (mod, addr);
387*7304104dSAndroid Build Coastguard Worker 
388*7304104dSAndroid Build Coastguard Worker     case ET_DYN:
389*7304104dSAndroid Build Coastguard Worker       /* All relative to first and only relocation base: module start.  */
390*7304104dSAndroid Build Coastguard Worker       *addr -= mod->low_addr;
391*7304104dSAndroid Build Coastguard Worker       break;
392*7304104dSAndroid Build Coastguard Worker 
393*7304104dSAndroid Build Coastguard Worker     default:
394*7304104dSAndroid Build Coastguard Worker       /* Already absolute, dwfl_module_relocations returned zero.  We
395*7304104dSAndroid Build Coastguard Worker 	 shouldn't really have been called, but it's a harmless no-op.  */
396*7304104dSAndroid Build Coastguard Worker       break;
397*7304104dSAndroid Build Coastguard Worker     }
398*7304104dSAndroid Build Coastguard Worker 
399*7304104dSAndroid Build Coastguard Worker   return 0;
400*7304104dSAndroid Build Coastguard Worker }
INTDEF(dwfl_module_relocate_address)401*7304104dSAndroid Build Coastguard Worker INTDEF (dwfl_module_relocate_address)
402*7304104dSAndroid Build Coastguard Worker 
403*7304104dSAndroid Build Coastguard Worker Elf_Scn *
404*7304104dSAndroid Build Coastguard Worker dwfl_module_address_section (Dwfl_Module *mod, Dwarf_Addr *address,
405*7304104dSAndroid Build Coastguard Worker 			     Dwarf_Addr *bias)
406*7304104dSAndroid Build Coastguard Worker {
407*7304104dSAndroid Build Coastguard Worker   if (check_module (mod))
408*7304104dSAndroid Build Coastguard Worker     return NULL;
409*7304104dSAndroid Build Coastguard Worker 
410*7304104dSAndroid Build Coastguard Worker   int idx = find_section (mod, address);
411*7304104dSAndroid Build Coastguard Worker   if (idx < 0)
412*7304104dSAndroid Build Coastguard Worker     return NULL;
413*7304104dSAndroid Build Coastguard Worker 
414*7304104dSAndroid Build Coastguard Worker   if (mod->reloc_info->refs[idx].relocs != NULL)
415*7304104dSAndroid Build Coastguard Worker     {
416*7304104dSAndroid Build Coastguard Worker       assert (mod->e_type == ET_REL);
417*7304104dSAndroid Build Coastguard Worker 
418*7304104dSAndroid Build Coastguard Worker       Elf_Scn *tscn = mod->reloc_info->refs[idx].scn;
419*7304104dSAndroid Build Coastguard Worker       Elf_Scn *relocscn = mod->reloc_info->refs[idx].relocs;
420*7304104dSAndroid Build Coastguard Worker       Dwfl_Error result = __libdwfl_relocate_section (mod, mod->main.elf,
421*7304104dSAndroid Build Coastguard Worker 						      relocscn, tscn, true);
422*7304104dSAndroid Build Coastguard Worker       if (likely (result == DWFL_E_NOERROR))
423*7304104dSAndroid Build Coastguard Worker 	mod->reloc_info->refs[idx].relocs = NULL;
424*7304104dSAndroid Build Coastguard Worker       else
425*7304104dSAndroid Build Coastguard Worker 	{
426*7304104dSAndroid Build Coastguard Worker 	  __libdwfl_seterrno (result);
427*7304104dSAndroid Build Coastguard Worker 	  return NULL;
428*7304104dSAndroid Build Coastguard Worker 	}
429*7304104dSAndroid Build Coastguard Worker     }
430*7304104dSAndroid Build Coastguard Worker 
431*7304104dSAndroid Build Coastguard Worker   *bias = dwfl_adjusted_address (mod, 0);
432*7304104dSAndroid Build Coastguard Worker   return mod->reloc_info->refs[idx].scn;
433*7304104dSAndroid Build Coastguard Worker }
434*7304104dSAndroid Build Coastguard Worker INTDEF (dwfl_module_address_section)
435