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