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