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