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