1/* Relocate debug information.
2   Copyright (C) 2005, 2006, 2007, 2008 Red Hat, Inc.
3   This file is part of Red Hat elfutils.
4
5   Red Hat elfutils is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by the
7   Free Software Foundation; version 2 of the License.
8
9   Red Hat elfutils is distributed in the hope that it will be useful, but
10   WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   General Public License for more details.
13
14   You should have received a copy of the GNU General Public License along
15   with Red Hat elfutils; if not, write to the Free Software Foundation,
16   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
17
18   In addition, as a special exception, Red Hat, Inc. gives You the
19   additional right to link the code of Red Hat elfutils with code licensed
20   under any Open Source Initiative certified open source license
21   (http://www.opensource.org/licenses/index.php) which requires the
22   distribution of source code with any binary distribution and to
23   distribute linked combinations of the two.  Non-GPL Code permitted under
24   this exception must only link to the code of Red Hat elfutils through
25   those well defined interfaces identified in the file named EXCEPTION
26   found in the source code files (the "Approved Interfaces").  The files
27   of Non-GPL Code may instantiate templates or use macros or inline
28   functions from the Approved Interfaces without causing the resulting
29   work to be covered by the GNU General Public License.  Only Red Hat,
30   Inc. may make changes or additions to the list of Approved Interfaces.
31   Red Hat's grant of this exception is conditioned upon your not adding
32   any new exceptions.  If you wish to add a new Approved Interface or
33   exception, please contact Red Hat.  You must obey the GNU General Public
34   License in all respects for all of the Red Hat elfutils code and other
35   code used in conjunction with Red Hat elfutils except the Non-GPL Code
36   covered by this exception.  If you modify this file, you may extend this
37   exception to your version of the file, but you are not obligated to do
38   so.  If you do not wish to provide this exception without modification,
39   you must delete this exception statement from your version and license
40   this file solely under the GPL without exception.
41
42   Red Hat elfutils is an included package of the Open Invention Network.
43   An included package of the Open Invention Network is a package for which
44   Open Invention Network licensees cross-license their patents.  No patent
45   license is granted, either expressly or impliedly, by designation as an
46   included package.  Should you wish to participate in the Open Invention
47   Network licensing program, please visit www.openinventionnetwork.com
48   <http://www.openinventionnetwork.com>.  */
49
50#include "libdwflP.h"
51
52typedef uint8_t GElf_Byte;
53
54/* Adjust *VALUE to add the load address of the SHNDX section.
55   We update the section header in place to cache the result.  */
56
57Dwfl_Error
58internal_function
59__libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx,
60			  Elf32_Word shndx, GElf_Addr *value)
61{
62  Elf_Scn *refscn = elf_getscn (elf, shndx);
63  GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem);
64  if (refshdr == NULL)
65    return DWFL_E_LIBELF;
66
67  if (refshdr->sh_addr == 0 && (refshdr->sh_flags & SHF_ALLOC))
68    {
69      /* This is a loaded section.  Find its actual
70	 address and update the section header.  */
71
72      if (*shstrndx == SHN_UNDEF
73	  && unlikely (elf_getshstrndx (elf, shstrndx) < 0))
74	return DWFL_E_LIBELF;
75
76      const char *name = elf_strptr (elf, *shstrndx, refshdr->sh_name);
77      if (unlikely (name == NULL))
78	return DWFL_E_LIBELF;
79
80      if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod),
81						    name, shndx, refshdr,
82						    &refshdr->sh_addr))
83	return CBFAIL;
84
85      if (refshdr->sh_addr == (Dwarf_Addr) -1l)
86	/* The callback indicated this section wasn't really loaded but we
87	   don't really care.  */
88	refshdr->sh_addr = 0;	/* Make no adjustment below.  */
89
90      /* Update the in-core file's section header to show the final
91	 load address (or unloadedness).  This serves as a cache,
92	 so we won't get here again for the same section.  */
93      if (likely (refshdr->sh_addr != 0)
94	  && unlikely (! gelf_update_shdr (refscn, refshdr)))
95	return DWFL_E_LIBELF;
96    }
97
98  /* Apply the adjustment.  */
99  *value += refshdr->sh_addr;
100  return DWFL_E_NOERROR;
101}
102
103
104/* Cache used by relocate_getsym.  */
105struct reloc_symtab_cache
106{
107  Elf *symelf;
108  Elf_Data *symdata;
109  Elf_Data *symxndxdata;
110  Elf_Data *symstrdata;
111  size_t symshstrndx;
112  size_t strtabndx;
113};
114#define RELOC_SYMTAB_CACHE(cache)	\
115  struct reloc_symtab_cache cache =	\
116    { NULL, NULL, NULL, NULL, SHN_UNDEF, SHN_UNDEF }
117
118/* This is just doing dwfl_module_getsym, except that we must always use
119   the symbol table in RELOCATED itself when it has one, not MOD->symfile.  */
120static Dwfl_Error
121relocate_getsym (Dwfl_Module *mod,
122		 Elf *relocated, struct reloc_symtab_cache *cache,
123		 int symndx, GElf_Sym *sym, GElf_Word *shndx)
124{
125  if (cache->symdata == NULL)
126    {
127      if (mod->symfile == NULL || mod->symfile->elf != relocated)
128	{
129	  /* We have to look up the symbol table in the file we are
130	     relocating, if it has its own.  These reloc sections refer to
131	     the symbol table in this file, and a symbol table in the main
132	     file might not match.  However, some tools did produce ET_REL
133	     .debug files with relocs but no symtab of their own.  */
134	  Elf_Scn *scn = NULL;
135	  while ((scn = elf_nextscn (relocated, scn)) != NULL)
136	    {
137	      GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
138	      if (shdr != NULL)
139		switch (shdr->sh_type)
140		  {
141		  default:
142		    continue;
143		  case SHT_SYMTAB:
144		    cache->symelf = relocated;
145		    cache->symdata = elf_getdata (scn, NULL);
146		    cache->strtabndx = shdr->sh_link;
147		    if (unlikely (cache->symdata == NULL))
148		      return DWFL_E_LIBELF;
149		    break;
150		  case SHT_SYMTAB_SHNDX:
151		    cache->symxndxdata = elf_getdata (scn, NULL);
152		    if (unlikely (cache->symxndxdata == NULL))
153		      return DWFL_E_LIBELF;
154		    break;
155		  }
156	      if (cache->symdata != NULL && cache->symxndxdata != NULL)
157		break;
158	    }
159	}
160      if (cache->symdata == NULL)
161	{
162	  /* We might not have looked for a symbol table file yet,
163	     when coming from __libdwfl_relocate_section.  */
164	  if (unlikely (mod->symfile == NULL)
165	      && unlikely (INTUSE(dwfl_module_getsymtab) (mod) < 0))
166	    return dwfl_errno ();
167
168	  /* The symbol table we have already cached is the one from
169	     the file being relocated, so it's what we need.  Or else
170	     this is an ET_REL .debug file with no .symtab of its own;
171	     the symbols refer to the section indices in the main file.  */
172	  cache->symelf = mod->symfile->elf;
173	  cache->symdata = mod->symdata;
174	  cache->symxndxdata = mod->symxndxdata;
175	  cache->symstrdata = mod->symstrdata;
176	}
177    }
178
179  if (unlikely (gelf_getsymshndx (cache->symdata, cache->symxndxdata,
180				  symndx, sym, shndx) == NULL))
181    return DWFL_E_LIBELF;
182
183  if (sym->st_shndx != SHN_XINDEX)
184    *shndx = sym->st_shndx;
185
186  switch (*shndx)
187    {
188    case SHN_ABS:
189    case SHN_UNDEF:
190    case SHN_COMMON:
191      return DWFL_E_NOERROR;
192    }
193
194  return __libdwfl_relocate_value (mod, cache->symelf, &cache->symshstrndx,
195				   *shndx, &sym->st_value);
196}
197
198/* Handle an undefined symbol.  We really only support ET_REL for Linux
199   kernel modules, and offline archives.  The behavior of the Linux module
200   loader is very simple and easy to mimic.  It only matches magically
201   exported symbols, and we match any defined symbols.  But we get the same
202   answer except when the module's symbols are undefined and would prevent
203   it from being loaded.  */
204static Dwfl_Error
205resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
206		GElf_Sym *sym, GElf_Word shndx)
207{
208  /* First we need its name.  */
209  if (sym->st_name != 0)
210    {
211      if (symtab->symstrdata == NULL)
212	{
213	  /* Cache the strtab for this symtab.  */
214	  assert (referer->symfile == NULL
215		  || referer->symfile->elf != symtab->symelf);
216	  symtab->symstrdata = elf_getdata (elf_getscn (symtab->symelf,
217							symtab->strtabndx),
218					    NULL);
219	  if (unlikely (symtab->symstrdata == NULL))
220	    return DWFL_E_LIBELF;
221	}
222      if (unlikely (sym->st_name >= symtab->symstrdata->d_size))
223	return DWFL_E_BADSTROFF;
224
225      const char *name = symtab->symstrdata->d_buf;
226      name += sym->st_name;
227
228      for (Dwfl_Module *m = referer->dwfl->modulelist; m != NULL; m = m->next)
229	if (m != referer)
230	  {
231	    /* Get this module's symtab.
232	       If we got a fresh error reading the table, report it.
233	       If we just have no symbols in this module, no harm done.  */
234	    if (m->symdata == NULL
235		&& m->symerr == DWFL_E_NOERROR
236		&& INTUSE(dwfl_module_getsymtab) (m) < 0
237		&& m->symerr != DWFL_E_NO_SYMTAB)
238	      return m->symerr;
239
240	    for (size_t ndx = 1; ndx < m->syments; ++ndx)
241	      {
242		sym = gelf_getsymshndx (m->symdata, m->symxndxdata,
243					ndx, sym, &shndx);
244		if (unlikely (sym == NULL))
245		  return DWFL_E_LIBELF;
246		if (sym->st_shndx != SHN_XINDEX)
247		  shndx = sym->st_shndx;
248
249		/* We are looking for a defined global symbol with a name.  */
250		if (shndx == SHN_UNDEF || shndx == SHN_COMMON
251		    || GELF_ST_BIND (sym->st_info) == STB_LOCAL
252		    || sym->st_name == 0)
253		  continue;
254
255		/* Get this candidate symbol's name.  */
256		if (unlikely (sym->st_name >= m->symstrdata->d_size))
257		  return DWFL_E_BADSTROFF;
258		const char *n = m->symstrdata->d_buf;
259		n += sym->st_name;
260
261		/* Does the name match?  */
262		if (strcmp (name, n))
263		  continue;
264
265		/* We found it!  */
266		if (shndx == SHN_ABS)
267		  return DWFL_E_NOERROR;
268
269		/* In an ET_REL file, the symbol table values are relative
270		   to the section, not to the module's load base.  */
271		size_t symshstrndx = SHN_UNDEF;
272		return __libdwfl_relocate_value (m, m->symfile->elf,
273						 &symshstrndx,
274						 shndx, &sym->st_value);
275	      }
276	  }
277    }
278
279  return DWFL_E_RELUNDEF;
280}
281
282static Dwfl_Error
283relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
284		  size_t shstrndx, struct reloc_symtab_cache *reloc_symtab,
285		  Elf_Scn *scn, GElf_Shdr *shdr,
286		  Elf_Scn *tscn, bool debugscn, bool partial)
287{
288  /* First, fetch the name of the section these relocations apply to.  */
289  GElf_Shdr tshdr_mem;
290  GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
291  const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name);
292  if (tname == NULL)
293    return DWFL_E_LIBELF;
294
295  if (debugscn && ! ebl_debugscn_p (mod->ebl, tname))
296    /* This relocation section is not for a debugging section.
297       Nothing to do here.  */
298    return DWFL_E_NOERROR;
299
300  /* Fetch the section data that needs the relocations applied.  */
301  Elf_Data *tdata = elf_rawdata (tscn, NULL);
302  if (tdata == NULL)
303    return DWFL_E_LIBELF;
304
305  /* Apply one relocation.  Returns true for any invalid data.  */
306  Dwfl_Error relocate (GElf_Addr offset, const GElf_Sxword *addend,
307		       int rtype, int symndx)
308  {
309    /* First see if this is a reloc we can handle.
310       If we are skipping it, don't bother resolving the symbol.  */
311    Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype);
312    if (unlikely (type == ELF_T_NUM))
313      return DWFL_E_BADRELTYPE;
314
315    /* First, resolve the symbol to an absolute value.  */
316    GElf_Addr value;
317
318    if (symndx == STN_UNDEF)
319      /* When strip removes a section symbol referring to a
320	 section moved into the debuginfo file, it replaces
321	 that symbol index in relocs with STN_UNDEF.  We
322	 don't actually need the symbol, because those relocs
323	 are always references relative to the nonallocated
324	 debugging sections, which start at zero.  */
325      value = 0;
326    else
327      {
328	GElf_Sym sym;
329	GElf_Word shndx;
330	Dwfl_Error error = relocate_getsym (mod, relocated, reloc_symtab,
331					    symndx, &sym, &shndx);
332	if (unlikely (error != DWFL_E_NOERROR))
333	  return error;
334
335	if (shndx == SHN_UNDEF || shndx == SHN_COMMON)
336	  {
337	    /* Maybe we can figure it out anyway.  */
338	    error = resolve_symbol (mod, reloc_symtab, &sym, shndx);
339	    if (error != DWFL_E_NOERROR)
340	      return error;
341	  }
342
343	value = sym.st_value;
344      }
345
346    /* These are the types we can relocate.  */
347#define TYPES		DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half);	\
348    DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword);			\
349    DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
350    size_t size;
351    switch (type)
352      {
353#define DO_TYPE(NAME, Name)			\
354	case ELF_T_##NAME:			\
355	  size = sizeof (GElf_##Name);		\
356	break
357	TYPES;
358#undef DO_TYPE
359      default:
360	return DWFL_E_BADRELTYPE;
361      }
362
363    if (offset + size > tdata->d_size)
364      return DWFL_E_BADRELOFF;
365
366#define DO_TYPE(NAME, Name) GElf_##Name Name;
367    union { TYPES; } tmpbuf;
368#undef DO_TYPE
369    Elf_Data tmpdata =
370      {
371	.d_type = type,
372	.d_buf = &tmpbuf,
373	.d_size = size,
374	.d_version = EV_CURRENT,
375      };
376    Elf_Data rdata =
377      {
378	.d_type = type,
379	.d_buf = tdata->d_buf + offset,
380	.d_size = size,
381	.d_version = EV_CURRENT,
382      };
383
384    /* XXX check for overflow? */
385    if (addend)
386      {
387	/* For the addend form, we have the value already.  */
388	value += *addend;
389	switch (type)
390	  {
391#define DO_TYPE(NAME, Name)			\
392	    case ELF_T_##NAME:			\
393	      tmpbuf.Name = value;		\
394	    break
395	    TYPES;
396#undef DO_TYPE
397	  default:
398	    abort ();
399	  }
400      }
401    else
402      {
403	/* Extract the original value and apply the reloc.  */
404	Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
405				     ehdr->e_ident[EI_DATA]);
406	if (d == NULL)
407	  return DWFL_E_LIBELF;
408	assert (d == &tmpdata);
409	switch (type)
410	  {
411#define DO_TYPE(NAME, Name)				\
412	    case ELF_T_##NAME:				\
413	      tmpbuf.Name += (GElf_##Name) value;	\
414	    break
415	    TYPES;
416#undef DO_TYPE
417	  default:
418	    abort ();
419	  }
420      }
421
422    /* Now convert the relocated datum back to the target
423       format.  This will write into rdata.d_buf, which
424       points into the raw section data being relocated.  */
425    Elf_Data *s = gelf_xlatetof (relocated, &rdata, &tmpdata,
426				 ehdr->e_ident[EI_DATA]);
427    if (s == NULL)
428      return DWFL_E_LIBELF;
429    assert (s == &rdata);
430
431    /* We have applied this relocation!  */
432    return DWFL_E_NOERROR;
433  }
434
435  /* Fetch the relocation section and apply each reloc in it.  */
436  Elf_Data *reldata = elf_getdata (scn, NULL);
437  if (reldata == NULL)
438    return DWFL_E_LIBELF;
439
440  Dwfl_Error result = DWFL_E_NOERROR;
441  bool first_badreltype = true;
442  inline void check_badreltype (void)
443  {
444    if (first_badreltype)
445      {
446	first_badreltype = false;
447	if (ebl_get_elfmachine (mod->ebl) == EM_NONE)
448	  /* This might be because ebl_openbackend failed to find
449	     any libebl_CPU.so library.  Diagnose that clearly.  */
450	  result = DWFL_E_UNKNOWN_MACHINE;
451      }
452  }
453
454  size_t nrels = shdr->sh_size / shdr->sh_entsize;
455  size_t complete = 0;
456  if (shdr->sh_type == SHT_REL)
457    for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
458      {
459	GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem);
460	if (r == NULL)
461	  return DWFL_E_LIBELF;
462	result = relocate (r->r_offset, NULL,
463			   GELF_R_TYPE (r->r_info),
464			   GELF_R_SYM (r->r_info));
465	check_badreltype ();
466	if (partial)
467	  switch (result)
468	    {
469	    case DWFL_E_NOERROR:
470	      /* We applied the relocation.  Elide it.  */
471	      memset (&rel_mem, 0, sizeof rel_mem);
472	      gelf_update_rel (reldata, relidx, &rel_mem);
473	      ++complete;
474	      break;
475	    case DWFL_E_BADRELTYPE:
476	    case DWFL_E_RELUNDEF:
477	      /* We couldn't handle this relocation.  Skip it.  */
478	      result = DWFL_E_NOERROR;
479	      break;
480	    default:
481	      break;
482	    }
483      }
484  else
485    for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
486      {
487	GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx,
488					       &rela_mem);
489	if (r == NULL)
490	  return DWFL_E_LIBELF;
491	result = relocate (r->r_offset, &r->r_addend,
492			   GELF_R_TYPE (r->r_info),
493			   GELF_R_SYM (r->r_info));
494	check_badreltype ();
495	if (partial)
496	  switch (result)
497	    {
498	    case DWFL_E_NOERROR:
499	      /* We applied the relocation.  Elide it.  */
500	      memset (&rela_mem, 0, sizeof rela_mem);
501	      gelf_update_rela (reldata, relidx, &rela_mem);
502	      ++complete;
503	      break;
504	    case DWFL_E_BADRELTYPE:
505	    case DWFL_E_RELUNDEF:
506	      /* We couldn't handle this relocation.  Skip it.  */
507	      result = DWFL_E_NOERROR;
508	      break;
509	    default:
510	      break;
511	    }
512      }
513
514  if (likely (result == DWFL_E_NOERROR))
515    {
516      if (!partial || complete == nrels)
517	/* Mark this relocation section as being empty now that we have
518	   done its work.  This affects unstrip -R, so e.g. it emits an
519	   empty .rela.debug_info along with a .debug_info that has
520	   already been fully relocated.  */
521	nrels = 0;
522      else if (complete != 0)
523	{
524	  /* We handled some of the relocations but not all.
525	     We've zeroed out the ones we processed.
526	     Now remove them from the section.  */
527
528	  size_t next = 0;
529	  if (shdr->sh_type == SHT_REL)
530	    for (size_t relidx = 0; relidx < nrels; ++relidx)
531	      {
532		GElf_Rel rel_mem;
533		GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem);
534		if (r->r_info != 0 || r->r_offset != 0)
535		  {
536		    if (next != relidx)
537		      gelf_update_rel (reldata, next, r);
538		    ++next;
539		  }
540	      }
541	  else
542	    for (size_t relidx = 0; relidx < nrels; ++relidx)
543	      {
544		GElf_Rela rela_mem;
545		GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
546		if (r->r_info != 0 || r->r_offset != 0 || r->r_addend != 0)
547		  {
548		    if (next != relidx)
549		      gelf_update_rela (reldata, next, r);
550		    ++next;
551		  }
552	      }
553	  nrels = next;
554	}
555
556      shdr->sh_size = reldata->d_size = nrels * shdr->sh_entsize;
557      gelf_update_shdr (scn, shdr);
558    }
559
560  return result;
561}
562
563Dwfl_Error
564internal_function
565__libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug)
566{
567  assert (mod->e_type == ET_REL);
568
569  GElf_Ehdr ehdr_mem;
570  const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem);
571  if (ehdr == NULL)
572    return DWFL_E_LIBELF;
573
574  size_t d_shstrndx;
575  if (elf_getshstrndx (debugfile, &d_shstrndx) < 0)
576    return DWFL_E_LIBELF;
577
578  RELOC_SYMTAB_CACHE (reloc_symtab);
579
580  /* Look at each section in the debuginfo file, and process the
581     relocation sections for debugging sections.  */
582  Dwfl_Error result = DWFL_E_NOERROR;
583  Elf_Scn *scn = NULL;
584  while (result == DWFL_E_NOERROR
585	 && (scn = elf_nextscn (debugfile, scn)) != NULL)
586    {
587      GElf_Shdr shdr_mem;
588      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
589
590      if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
591	  && shdr->sh_size != 0)
592	{
593	  /* It's a relocation section.  */
594
595	  Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info);
596	  if (unlikely (tscn == NULL))
597	    result = DWFL_E_LIBELF;
598	  else
599	    result = relocate_section (mod, debugfile, ehdr, d_shstrndx,
600				       &reloc_symtab, scn, shdr, tscn,
601				       debug, !debug);
602	}
603    }
604
605  return result;
606}
607
608Dwfl_Error
609internal_function
610__libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated,
611			    Elf_Scn *relocscn, Elf_Scn *tscn, bool partial)
612{
613  GElf_Ehdr ehdr_mem;
614  GElf_Shdr shdr_mem;
615
616  RELOC_SYMTAB_CACHE (reloc_symtab);
617
618  size_t shstrndx;
619  if (elf_getshstrndx (relocated, &shstrndx) < 0)
620    return DWFL_E_LIBELF;
621
622  return (__libdwfl_module_getebl (mod)
623	  ?: relocate_section (mod, relocated,
624			       gelf_getehdr (relocated, &ehdr_mem), shstrndx,
625			       &reloc_symtab,
626			       relocscn, gelf_getshdr (relocscn, &shdr_mem),
627			       tscn, false, partial));
628}
629