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