1da0c48c4Sopenharmony_ci/* Find debugging and symbol information for a module in libdwfl.
2da0c48c4Sopenharmony_ci   Copyright (C) 2005-2012, 2014, 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#include <inttypes.h>
35da0c48c4Sopenharmony_ci#include <fcntl.h>
36da0c48c4Sopenharmony_ci#include <string.h>
37da0c48c4Sopenharmony_ci#include "../libdw/libdwP.h"	/* DWARF_E_* values are here.  */
38da0c48c4Sopenharmony_ci#include "../libelf/libelfP.h"
39da0c48c4Sopenharmony_ci#include "system.h"
40da0c48c4Sopenharmony_ci
41da0c48c4Sopenharmony_cistatic inline Dwfl_Error
42da0c48c4Sopenharmony_ciopen_elf_file (Elf **elf, int *fd, char **name)
43da0c48c4Sopenharmony_ci{
44da0c48c4Sopenharmony_ci  if (*elf == NULL)
45da0c48c4Sopenharmony_ci    {
46da0c48c4Sopenharmony_ci      /* CBFAIL uses errno if it's set, so clear it first in case we don't
47da0c48c4Sopenharmony_ci	 set it with an open failure below.  */
48da0c48c4Sopenharmony_ci      errno = 0;
49da0c48c4Sopenharmony_ci
50da0c48c4Sopenharmony_ci      /* If there was a pre-primed file name left that the callback left
51da0c48c4Sopenharmony_ci	 behind, try to open that file name.  */
52da0c48c4Sopenharmony_ci      if (*fd < 0 && *name != NULL)
53da0c48c4Sopenharmony_ci	*fd = TEMP_FAILURE_RETRY (open (*name, O_RDONLY));
54da0c48c4Sopenharmony_ci
55da0c48c4Sopenharmony_ci      if (*fd < 0)
56da0c48c4Sopenharmony_ci	return CBFAIL;
57da0c48c4Sopenharmony_ci
58da0c48c4Sopenharmony_ci      return __libdw_open_file (fd, elf, true, false);
59da0c48c4Sopenharmony_ci    }
60da0c48c4Sopenharmony_ci  else if (unlikely (elf_kind (*elf) != ELF_K_ELF))
61da0c48c4Sopenharmony_ci    {
62da0c48c4Sopenharmony_ci      elf_end (*elf);
63da0c48c4Sopenharmony_ci      *elf = NULL;
64da0c48c4Sopenharmony_ci      close (*fd);
65da0c48c4Sopenharmony_ci      *fd = -1;
66da0c48c4Sopenharmony_ci      return DWFL_E_BADELF;
67da0c48c4Sopenharmony_ci    }
68da0c48c4Sopenharmony_ci
69da0c48c4Sopenharmony_ci  /* Elf file already open and looks fine.  */
70da0c48c4Sopenharmony_ci  return DWFL_E_NOERROR;
71da0c48c4Sopenharmony_ci}
72da0c48c4Sopenharmony_ci
73da0c48c4Sopenharmony_ci/* Open libelf FILE->fd and compute the load base of ELF as loaded in MOD.
74da0c48c4Sopenharmony_ci   When we return success, FILE->elf and FILE->vaddr are set up.  */
75da0c48c4Sopenharmony_cistatic inline Dwfl_Error
76da0c48c4Sopenharmony_ciopen_elf (Dwfl_Module *mod, struct dwfl_file *file)
77da0c48c4Sopenharmony_ci{
78da0c48c4Sopenharmony_ci  Dwfl_Error error = open_elf_file (&file->elf, &file->fd, &file->name);
79da0c48c4Sopenharmony_ci  if (error != DWFL_E_NOERROR)
80da0c48c4Sopenharmony_ci    return error;
81da0c48c4Sopenharmony_ci
82da0c48c4Sopenharmony_ci  GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (file->elf, &ehdr_mem);
83da0c48c4Sopenharmony_ci  if (ehdr == NULL)
84da0c48c4Sopenharmony_ci    {
85da0c48c4Sopenharmony_ci    elf_error:
86da0c48c4Sopenharmony_ci      elf_end (file->elf);
87da0c48c4Sopenharmony_ci      file->elf = NULL;
88da0c48c4Sopenharmony_ci      close (file->fd);
89da0c48c4Sopenharmony_ci      file->fd = -1;
90da0c48c4Sopenharmony_ci      return DWFL_E (LIBELF, elf_errno ());
91da0c48c4Sopenharmony_ci    }
92da0c48c4Sopenharmony_ci
93da0c48c4Sopenharmony_ci  if (ehdr->e_type != ET_REL)
94da0c48c4Sopenharmony_ci    {
95da0c48c4Sopenharmony_ci      /* In any non-ET_REL file, we compute the "synchronization address".
96da0c48c4Sopenharmony_ci
97da0c48c4Sopenharmony_ci	 We start with the address at the end of the first PT_LOAD
98da0c48c4Sopenharmony_ci	 segment.  When prelink converts REL to RELA in an ET_DYN
99da0c48c4Sopenharmony_ci	 file, it expands the space between the beginning of the
100da0c48c4Sopenharmony_ci	 segment and the actual code/data addresses.  Since that
101da0c48c4Sopenharmony_ci	 change wasn't made in the debug file, the distance from
102da0c48c4Sopenharmony_ci	 p_vaddr to an address of interest (in an st_value or DWARF
103da0c48c4Sopenharmony_ci	 data) now differs between the main and debug files.  The
104da0c48c4Sopenharmony_ci	 distance from address_sync to an address of interest remains
105da0c48c4Sopenharmony_ci	 consistent.
106da0c48c4Sopenharmony_ci
107da0c48c4Sopenharmony_ci	 If there are no section headers at all (full stripping), then
108da0c48c4Sopenharmony_ci	 the end of the first segment is a valid synchronization address.
109da0c48c4Sopenharmony_ci	 This cannot happen in a prelinked file, since prelink itself
110da0c48c4Sopenharmony_ci	 relies on section headers for prelinking and for undoing it.
111da0c48c4Sopenharmony_ci	 (If you do full stripping on a prelinked file, then you get what
112da0c48c4Sopenharmony_ci	 you deserve--you can neither undo the prelinking, nor expect to
113da0c48c4Sopenharmony_ci	 line it up with a debug file separated before prelinking.)
114da0c48c4Sopenharmony_ci
115da0c48c4Sopenharmony_ci	 However, when prelink processes an ET_EXEC file, it can do
116da0c48c4Sopenharmony_ci	 something different.  There it juggles the "special" sections
117da0c48c4Sopenharmony_ci	 (SHT_DYNSYM et al) to make space for the additional prelink
118da0c48c4Sopenharmony_ci	 special sections.  Sometimes it will do this by moving a special
119da0c48c4Sopenharmony_ci	 section like .dynstr after the real program sections in the first
120da0c48c4Sopenharmony_ci	 PT_LOAD segment--i.e. to the end.  That changes the end address of
121da0c48c4Sopenharmony_ci	 the segment, so it no longer lines up correctly and is not a valid
122da0c48c4Sopenharmony_ci	 synchronization address to use.  Because of this, we need to apply
123da0c48c4Sopenharmony_ci	 a different prelink-savvy means to discover the synchronization
124da0c48c4Sopenharmony_ci	 address when there is a separate debug file and a prelinked main
125da0c48c4Sopenharmony_ci	 file.  That is done in find_debuginfo, below.  */
126da0c48c4Sopenharmony_ci
127da0c48c4Sopenharmony_ci      size_t phnum;
128da0c48c4Sopenharmony_ci      if (unlikely (elf_getphdrnum (file->elf, &phnum) != 0))
129da0c48c4Sopenharmony_ci	goto elf_error;
130da0c48c4Sopenharmony_ci
131da0c48c4Sopenharmony_ci      file->vaddr = file->address_sync = 0;
132da0c48c4Sopenharmony_ci      for (size_t i = 0; i < phnum; ++i)
133da0c48c4Sopenharmony_ci	{
134da0c48c4Sopenharmony_ci	  GElf_Phdr ph_mem;
135da0c48c4Sopenharmony_ci	  GElf_Phdr *ph = gelf_getphdr (file->elf, i, &ph_mem);
136da0c48c4Sopenharmony_ci	  if (unlikely (ph == NULL))
137da0c48c4Sopenharmony_ci	    goto elf_error;
138da0c48c4Sopenharmony_ci	  if (ph->p_type == PT_LOAD)
139da0c48c4Sopenharmony_ci	    {
140da0c48c4Sopenharmony_ci	      file->vaddr = ph->p_vaddr & -ph->p_align;
141da0c48c4Sopenharmony_ci	      file->address_sync = ph->p_vaddr + ph->p_memsz;
142da0c48c4Sopenharmony_ci	      break;
143da0c48c4Sopenharmony_ci	    }
144da0c48c4Sopenharmony_ci	}
145da0c48c4Sopenharmony_ci    }
146da0c48c4Sopenharmony_ci
147da0c48c4Sopenharmony_ci  /* We only want to set the module e_type explicitly once, derived from
148da0c48c4Sopenharmony_ci     the main ELF file.  (It might be changed for the kernel, because
149da0c48c4Sopenharmony_ci     that is special - see below.)  open_elf is always called first for
150da0c48c4Sopenharmony_ci     the main ELF file, because both find_dw and find_symtab call
151da0c48c4Sopenharmony_ci     __libdwfl_getelf first to open the main file.  So don't let debug
152da0c48c4Sopenharmony_ci     or aux files override the module e_type.  The kernel heuristic
153da0c48c4Sopenharmony_ci     below could otherwise trigger for non-kernel/non-main files, since
154da0c48c4Sopenharmony_ci     their phdrs might not match the actual load addresses.  */
155da0c48c4Sopenharmony_ci  if (file == &mod->main)
156da0c48c4Sopenharmony_ci    {
157da0c48c4Sopenharmony_ci      mod->e_type = ehdr->e_type;
158da0c48c4Sopenharmony_ci
159da0c48c4Sopenharmony_ci      /* Relocatable Linux kernels are ET_EXEC but act like ET_DYN.  */
160da0c48c4Sopenharmony_ci      if (mod->e_type == ET_EXEC && file->vaddr != mod->low_addr)
161da0c48c4Sopenharmony_ci	mod->e_type = ET_DYN;
162da0c48c4Sopenharmony_ci    }
163da0c48c4Sopenharmony_ci  else
164da0c48c4Sopenharmony_ci    assert (mod->main.elf != NULL);
165da0c48c4Sopenharmony_ci
166da0c48c4Sopenharmony_ci  return DWFL_E_NOERROR;
167da0c48c4Sopenharmony_ci}
168da0c48c4Sopenharmony_ci
169da0c48c4Sopenharmony_ci/* We have an authoritative build ID for this module MOD, so don't use
170da0c48c4Sopenharmony_ci   a file by name that doesn't match that ID.  */
171da0c48c4Sopenharmony_cistatic void
172da0c48c4Sopenharmony_cimod_verify_build_id (Dwfl_Module *mod)
173da0c48c4Sopenharmony_ci{
174da0c48c4Sopenharmony_ci  assert (mod->build_id_len > 0);
175da0c48c4Sopenharmony_ci
176da0c48c4Sopenharmony_ci  switch (__builtin_expect (__libdwfl_find_build_id (mod, false,
177da0c48c4Sopenharmony_ci						     mod->main.elf), 2))
178da0c48c4Sopenharmony_ci    {
179da0c48c4Sopenharmony_ci    case 2:
180da0c48c4Sopenharmony_ci      /* Build ID matches as it should. */
181da0c48c4Sopenharmony_ci      return;
182da0c48c4Sopenharmony_ci
183da0c48c4Sopenharmony_ci    case -1:			/* ELF error.  */
184da0c48c4Sopenharmony_ci      mod->elferr = INTUSE(dwfl_errno) ();
185da0c48c4Sopenharmony_ci      break;
186da0c48c4Sopenharmony_ci
187da0c48c4Sopenharmony_ci    case 0:			/* File has no build ID note.  */
188da0c48c4Sopenharmony_ci    case 1:			/* FIle has a build ID that does not match.  */
189da0c48c4Sopenharmony_ci      mod->elferr = DWFL_E_WRONG_ID_ELF;
190da0c48c4Sopenharmony_ci      break;
191da0c48c4Sopenharmony_ci
192da0c48c4Sopenharmony_ci    default:
193da0c48c4Sopenharmony_ci      abort ();
194da0c48c4Sopenharmony_ci    }
195da0c48c4Sopenharmony_ci
196da0c48c4Sopenharmony_ci  /* We get here when it was the right ELF file.  Clear it out.  */
197da0c48c4Sopenharmony_ci  elf_end (mod->main.elf);
198da0c48c4Sopenharmony_ci  mod->main.elf = NULL;
199da0c48c4Sopenharmony_ci  if (mod->main.fd >= 0)
200da0c48c4Sopenharmony_ci    {
201da0c48c4Sopenharmony_ci      close (mod->main.fd);
202da0c48c4Sopenharmony_ci      mod->main.fd = -1;
203da0c48c4Sopenharmony_ci    }
204da0c48c4Sopenharmony_ci}
205da0c48c4Sopenharmony_ci
206da0c48c4Sopenharmony_ci/* Find the main ELF file for this module and open libelf on it.
207da0c48c4Sopenharmony_ci   When we return success, MOD->main.elf and MOD->main.bias are set up.  */
208da0c48c4Sopenharmony_civoid
209da0c48c4Sopenharmony_ciinternal_function
210da0c48c4Sopenharmony_ci__libdwfl_getelf (Dwfl_Module *mod)
211da0c48c4Sopenharmony_ci{
212da0c48c4Sopenharmony_ci  if (mod->main.elf != NULL	/* Already done.  */
213da0c48c4Sopenharmony_ci      || mod->elferr != DWFL_E_NOERROR)	/* Cached failure.  */
214da0c48c4Sopenharmony_ci    return;
215da0c48c4Sopenharmony_ci
216da0c48c4Sopenharmony_ci  mod->main.fd = (*mod->dwfl->callbacks->find_elf) (MODCB_ARGS (mod),
217da0c48c4Sopenharmony_ci						    &mod->main.name,
218da0c48c4Sopenharmony_ci						    &mod->main.elf);
219da0c48c4Sopenharmony_ci  const bool fallback = mod->main.elf == NULL && mod->main.fd < 0;
220da0c48c4Sopenharmony_ci  mod->elferr = open_elf (mod, &mod->main);
221da0c48c4Sopenharmony_ci  if (mod->elferr != DWFL_E_NOERROR)
222da0c48c4Sopenharmony_ci    return;
223da0c48c4Sopenharmony_ci
224da0c48c4Sopenharmony_ci  if (!mod->main.valid)
225da0c48c4Sopenharmony_ci    {
226da0c48c4Sopenharmony_ci      /* Clear any explicitly reported build ID, just in case it was wrong.
227da0c48c4Sopenharmony_ci	 We'll fetch it from the file when asked.  */
228da0c48c4Sopenharmony_ci      free (mod->build_id_bits);
229da0c48c4Sopenharmony_ci      mod->build_id_bits = NULL;
230da0c48c4Sopenharmony_ci      mod->build_id_len = 0;
231da0c48c4Sopenharmony_ci    }
232da0c48c4Sopenharmony_ci  else if (fallback)
233da0c48c4Sopenharmony_ci    mod_verify_build_id (mod);
234da0c48c4Sopenharmony_ci
235da0c48c4Sopenharmony_ci  mod->main_bias = mod->e_type == ET_REL ? 0 : mod->low_addr - mod->main.vaddr;
236da0c48c4Sopenharmony_ci}
237da0c48c4Sopenharmony_ci
238da0c48c4Sopenharmony_cistatic inline void
239da0c48c4Sopenharmony_ciconsider_shdr (GElf_Addr interp,
240da0c48c4Sopenharmony_ci               GElf_Word sh_type,
241da0c48c4Sopenharmony_ci               GElf_Xword sh_flags,
242da0c48c4Sopenharmony_ci               GElf_Addr sh_addr,
243da0c48c4Sopenharmony_ci               GElf_Xword sh_size,
244da0c48c4Sopenharmony_ci               GElf_Addr *phighest)
245da0c48c4Sopenharmony_ci{
246da0c48c4Sopenharmony_ci  if ((sh_flags & SHF_ALLOC)
247da0c48c4Sopenharmony_ci      && ((sh_type == SHT_PROGBITS && sh_addr != interp)
248da0c48c4Sopenharmony_ci          || sh_type == SHT_NOBITS))
249da0c48c4Sopenharmony_ci    {
250da0c48c4Sopenharmony_ci      const GElf_Addr sh_end = sh_addr + sh_size;
251da0c48c4Sopenharmony_ci      if (sh_end > *phighest)
252da0c48c4Sopenharmony_ci        *phighest = sh_end;
253da0c48c4Sopenharmony_ci    }
254da0c48c4Sopenharmony_ci}
255da0c48c4Sopenharmony_ci
256da0c48c4Sopenharmony_ci/* If the main file might have been prelinked, then we need to
257da0c48c4Sopenharmony_ci   discover the correct synchronization address between the main and
258da0c48c4Sopenharmony_ci   debug files.  Because of prelink's section juggling, we cannot rely
259da0c48c4Sopenharmony_ci   on the address_sync computed from PT_LOAD segments (see open_elf).
260da0c48c4Sopenharmony_ci
261da0c48c4Sopenharmony_ci   We will attempt to discover a synchronization address based on the
262da0c48c4Sopenharmony_ci   section headers instead.  But finding a section address that is
263da0c48c4Sopenharmony_ci   safe to use requires identifying which sections are SHT_PROGBITS.
264da0c48c4Sopenharmony_ci   We can do that in the main file, but in the debug file all the
265da0c48c4Sopenharmony_ci   allocated sections have been transformed into SHT_NOBITS so we have
266da0c48c4Sopenharmony_ci   lost the means to match them up correctly.
267da0c48c4Sopenharmony_ci
268da0c48c4Sopenharmony_ci   The only method left to us is to decode the .gnu.prelink_undo
269da0c48c4Sopenharmony_ci   section in the prelinked main file.  This shows what the sections
270da0c48c4Sopenharmony_ci   looked like before prelink juggled them--when they still had a
271da0c48c4Sopenharmony_ci   direct correspondence to the debug file.  */
272da0c48c4Sopenharmony_cistatic Dwfl_Error
273da0c48c4Sopenharmony_cifind_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
274da0c48c4Sopenharmony_ci{
275da0c48c4Sopenharmony_ci  /* The magic section is only identified by name.  */
276da0c48c4Sopenharmony_ci  size_t shstrndx;
277da0c48c4Sopenharmony_ci  if (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0)
278da0c48c4Sopenharmony_ci    return DWFL_E_LIBELF;
279da0c48c4Sopenharmony_ci
280da0c48c4Sopenharmony_ci  Elf_Scn *scn = NULL;
281da0c48c4Sopenharmony_ci  while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
282da0c48c4Sopenharmony_ci    {
283da0c48c4Sopenharmony_ci      GElf_Shdr shdr_mem;
284da0c48c4Sopenharmony_ci      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
285da0c48c4Sopenharmony_ci      if (unlikely (shdr == NULL))
286da0c48c4Sopenharmony_ci	return DWFL_E_LIBELF;
287da0c48c4Sopenharmony_ci      if (shdr->sh_type == SHT_PROGBITS
288da0c48c4Sopenharmony_ci	  && !(shdr->sh_flags & SHF_ALLOC)
289da0c48c4Sopenharmony_ci	  && shdr->sh_name != 0)
290da0c48c4Sopenharmony_ci	{
291da0c48c4Sopenharmony_ci	  const char *secname = elf_strptr (mod->main.elf, shstrndx,
292da0c48c4Sopenharmony_ci					    shdr->sh_name);
293da0c48c4Sopenharmony_ci	  if (unlikely (secname == NULL))
294da0c48c4Sopenharmony_ci	    return DWFL_E_LIBELF;
295da0c48c4Sopenharmony_ci	  if (!strcmp (secname, ".gnu.prelink_undo"))
296da0c48c4Sopenharmony_ci	    break;
297da0c48c4Sopenharmony_ci	}
298da0c48c4Sopenharmony_ci    }
299da0c48c4Sopenharmony_ci
300da0c48c4Sopenharmony_ci  if (scn == NULL)
301da0c48c4Sopenharmony_ci    /* There was no .gnu.prelink_undo section.  */
302da0c48c4Sopenharmony_ci    return DWFL_E_NOERROR;
303da0c48c4Sopenharmony_ci
304da0c48c4Sopenharmony_ci  Elf_Data *undodata = elf_rawdata (scn, NULL);
305da0c48c4Sopenharmony_ci  if (unlikely (undodata == NULL))
306da0c48c4Sopenharmony_ci    return DWFL_E_LIBELF;
307da0c48c4Sopenharmony_ci
308da0c48c4Sopenharmony_ci  /* Decode the section.  It consists of the original ehdr, phdrs,
309da0c48c4Sopenharmony_ci     and shdrs (but omits section 0).  */
310da0c48c4Sopenharmony_ci
311da0c48c4Sopenharmony_ci  union
312da0c48c4Sopenharmony_ci  {
313da0c48c4Sopenharmony_ci    Elf32_Ehdr e32;
314da0c48c4Sopenharmony_ci    Elf64_Ehdr e64;
315da0c48c4Sopenharmony_ci  } ehdr;
316da0c48c4Sopenharmony_ci  Elf_Data dst =
317da0c48c4Sopenharmony_ci    {
318da0c48c4Sopenharmony_ci      .d_buf = &ehdr,
319da0c48c4Sopenharmony_ci      .d_size = sizeof ehdr,
320da0c48c4Sopenharmony_ci      .d_type = ELF_T_EHDR,
321da0c48c4Sopenharmony_ci      .d_version = EV_CURRENT
322da0c48c4Sopenharmony_ci    };
323da0c48c4Sopenharmony_ci  Elf_Data src = *undodata;
324da0c48c4Sopenharmony_ci  src.d_size = gelf_fsize (mod->main.elf, ELF_T_EHDR, 1, EV_CURRENT);
325da0c48c4Sopenharmony_ci  src.d_type = ELF_T_EHDR;
326da0c48c4Sopenharmony_ci  if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
327da0c48c4Sopenharmony_ci			       elf_getident (mod->main.elf, NULL)[EI_DATA])
328da0c48c4Sopenharmony_ci		== NULL))
329da0c48c4Sopenharmony_ci    return DWFL_E_LIBELF;
330da0c48c4Sopenharmony_ci
331da0c48c4Sopenharmony_ci  size_t shentsize = gelf_fsize (mod->main.elf, ELF_T_SHDR, 1, EV_CURRENT);
332da0c48c4Sopenharmony_ci  size_t phentsize = gelf_fsize (mod->main.elf, ELF_T_PHDR, 1, EV_CURRENT);
333da0c48c4Sopenharmony_ci
334da0c48c4Sopenharmony_ci  uint_fast16_t phnum;
335da0c48c4Sopenharmony_ci  uint_fast16_t shnum;
336da0c48c4Sopenharmony_ci  if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
337da0c48c4Sopenharmony_ci    {
338da0c48c4Sopenharmony_ci      if (ehdr.e32.e_shentsize != shentsize
339da0c48c4Sopenharmony_ci	  || ehdr.e32.e_phentsize != phentsize)
340da0c48c4Sopenharmony_ci	return DWFL_E_BAD_PRELINK;
341da0c48c4Sopenharmony_ci      phnum = ehdr.e32.e_phnum;
342da0c48c4Sopenharmony_ci      shnum = ehdr.e32.e_shnum;
343da0c48c4Sopenharmony_ci    }
344da0c48c4Sopenharmony_ci  else
345da0c48c4Sopenharmony_ci    {
346da0c48c4Sopenharmony_ci      if (ehdr.e64.e_shentsize != shentsize
347da0c48c4Sopenharmony_ci	  || ehdr.e64.e_phentsize != phentsize)
348da0c48c4Sopenharmony_ci	return DWFL_E_BAD_PRELINK;
349da0c48c4Sopenharmony_ci      phnum = ehdr.e64.e_phnum;
350da0c48c4Sopenharmony_ci      shnum = ehdr.e64.e_shnum;
351da0c48c4Sopenharmony_ci    }
352da0c48c4Sopenharmony_ci
353da0c48c4Sopenharmony_ci  /* Since prelink does not store the zeroth section header in the undo
354da0c48c4Sopenharmony_ci     section, it cannot support SHN_XINDEX encoding.  */
355da0c48c4Sopenharmony_ci  if (unlikely (shnum >= SHN_LORESERVE) || unlikely(shnum == 0)
356da0c48c4Sopenharmony_ci      || unlikely (undodata->d_size != (src.d_size
357da0c48c4Sopenharmony_ci					+ phnum * phentsize
358da0c48c4Sopenharmony_ci					+ (shnum - 1) * shentsize)))
359da0c48c4Sopenharmony_ci    return DWFL_E_BAD_PRELINK;
360da0c48c4Sopenharmony_ci
361da0c48c4Sopenharmony_ci  --shnum;
362da0c48c4Sopenharmony_ci
363da0c48c4Sopenharmony_ci  /* We look at the allocated SHT_PROGBITS (or SHT_NOBITS) sections.  (Most
364da0c48c4Sopenharmony_ci     every file will have some SHT_PROGBITS sections, but it's possible to
365da0c48c4Sopenharmony_ci     have one with nothing but .bss, i.e. SHT_NOBITS.)  The special sections
366da0c48c4Sopenharmony_ci     that can be moved around have different sh_type values--except for
367da0c48c4Sopenharmony_ci     .interp, the section that became the PT_INTERP segment.  So we exclude
368da0c48c4Sopenharmony_ci     the SHT_PROGBITS section whose address matches the PT_INTERP p_vaddr.
369da0c48c4Sopenharmony_ci     For this reason, we must examine the phdrs first to find PT_INTERP.  */
370da0c48c4Sopenharmony_ci
371da0c48c4Sopenharmony_ci  GElf_Addr main_interp = 0;
372da0c48c4Sopenharmony_ci  {
373da0c48c4Sopenharmony_ci    size_t main_phnum;
374da0c48c4Sopenharmony_ci    if (unlikely (elf_getphdrnum (mod->main.elf, &main_phnum)))
375da0c48c4Sopenharmony_ci      return DWFL_E_LIBELF;
376da0c48c4Sopenharmony_ci    for (size_t i = 0; i < main_phnum; ++i)
377da0c48c4Sopenharmony_ci      {
378da0c48c4Sopenharmony_ci	GElf_Phdr phdr;
379da0c48c4Sopenharmony_ci	if (unlikely (gelf_getphdr (mod->main.elf, i, &phdr) == NULL))
380da0c48c4Sopenharmony_ci	  return DWFL_E_LIBELF;
381da0c48c4Sopenharmony_ci	if (phdr.p_type == PT_INTERP)
382da0c48c4Sopenharmony_ci	  {
383da0c48c4Sopenharmony_ci	    main_interp = phdr.p_vaddr;
384da0c48c4Sopenharmony_ci	    break;
385da0c48c4Sopenharmony_ci	  }
386da0c48c4Sopenharmony_ci      }
387da0c48c4Sopenharmony_ci  }
388da0c48c4Sopenharmony_ci
389da0c48c4Sopenharmony_ci  src.d_buf += src.d_size;
390da0c48c4Sopenharmony_ci  src.d_type = ELF_T_PHDR;
391da0c48c4Sopenharmony_ci  src.d_size = phnum * phentsize;
392da0c48c4Sopenharmony_ci
393da0c48c4Sopenharmony_ci  GElf_Addr undo_interp = 0;
394da0c48c4Sopenharmony_ci  bool class32 = ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32;
395da0c48c4Sopenharmony_ci  {
396da0c48c4Sopenharmony_ci    size_t phdr_size = class32 ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr);
397da0c48c4Sopenharmony_ci    if (unlikely (phnum > SIZE_MAX / phdr_size))
398da0c48c4Sopenharmony_ci      return DWFL_E_NOMEM;
399da0c48c4Sopenharmony_ci    const size_t phdrs_bytes = phnum * phdr_size;
400da0c48c4Sopenharmony_ci    void *phdrs = malloc (phdrs_bytes);
401da0c48c4Sopenharmony_ci    if (unlikely (phdrs == NULL))
402da0c48c4Sopenharmony_ci      return DWFL_E_NOMEM;
403da0c48c4Sopenharmony_ci    dst.d_buf = phdrs;
404da0c48c4Sopenharmony_ci    dst.d_size = phdrs_bytes;
405da0c48c4Sopenharmony_ci    if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
406da0c48c4Sopenharmony_ci				 ehdr.e32.e_ident[EI_DATA]) == NULL))
407da0c48c4Sopenharmony_ci      {
408da0c48c4Sopenharmony_ci	free (phdrs);
409da0c48c4Sopenharmony_ci	return DWFL_E_LIBELF;
410da0c48c4Sopenharmony_ci      }
411da0c48c4Sopenharmony_ci    if (class32)
412da0c48c4Sopenharmony_ci      {
413da0c48c4Sopenharmony_ci	Elf32_Phdr (*p32)[phnum] = phdrs;
414da0c48c4Sopenharmony_ci	for (uint_fast16_t i = 0; i < phnum; ++i)
415da0c48c4Sopenharmony_ci	  if ((*p32)[i].p_type == PT_INTERP)
416da0c48c4Sopenharmony_ci	    {
417da0c48c4Sopenharmony_ci	      undo_interp = (*p32)[i].p_vaddr;
418da0c48c4Sopenharmony_ci	      break;
419da0c48c4Sopenharmony_ci	    }
420da0c48c4Sopenharmony_ci      }
421da0c48c4Sopenharmony_ci    else
422da0c48c4Sopenharmony_ci      {
423da0c48c4Sopenharmony_ci	Elf64_Phdr (*p64)[phnum] = phdrs;
424da0c48c4Sopenharmony_ci	for (uint_fast16_t i = 0; i < phnum; ++i)
425da0c48c4Sopenharmony_ci	  if ((*p64)[i].p_type == PT_INTERP)
426da0c48c4Sopenharmony_ci	    {
427da0c48c4Sopenharmony_ci	      undo_interp = (*p64)[i].p_vaddr;
428da0c48c4Sopenharmony_ci	      break;
429da0c48c4Sopenharmony_ci	    }
430da0c48c4Sopenharmony_ci      }
431da0c48c4Sopenharmony_ci    free (phdrs);
432da0c48c4Sopenharmony_ci  }
433da0c48c4Sopenharmony_ci
434da0c48c4Sopenharmony_ci  if (unlikely ((main_interp == 0) != (undo_interp == 0)))
435da0c48c4Sopenharmony_ci    return DWFL_E_BAD_PRELINK;
436da0c48c4Sopenharmony_ci
437da0c48c4Sopenharmony_ci  src.d_buf += src.d_size;
438da0c48c4Sopenharmony_ci  src.d_type = ELF_T_SHDR;
439da0c48c4Sopenharmony_ci  src.d_size = gelf_fsize (mod->main.elf, ELF_T_SHDR, shnum, EV_CURRENT);
440da0c48c4Sopenharmony_ci
441da0c48c4Sopenharmony_ci  size_t shdr_size = class32 ? sizeof (Elf32_Shdr) : sizeof (Elf64_Shdr);
442da0c48c4Sopenharmony_ci  if (unlikely (shnum > SIZE_MAX / shdr_size))
443da0c48c4Sopenharmony_ci    return DWFL_E_NOMEM;
444da0c48c4Sopenharmony_ci  const size_t shdrs_bytes = shnum * shdr_size;
445da0c48c4Sopenharmony_ci  void *shdrs = malloc (shdrs_bytes);
446da0c48c4Sopenharmony_ci  if (unlikely (shdrs == NULL))
447da0c48c4Sopenharmony_ci    return DWFL_E_NOMEM;
448da0c48c4Sopenharmony_ci  dst.d_buf = shdrs;
449da0c48c4Sopenharmony_ci  dst.d_size = shdrs_bytes;
450da0c48c4Sopenharmony_ci  if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
451da0c48c4Sopenharmony_ci			       ehdr.e32.e_ident[EI_DATA]) == NULL))
452da0c48c4Sopenharmony_ci    {
453da0c48c4Sopenharmony_ci      free (shdrs);
454da0c48c4Sopenharmony_ci      return DWFL_E_LIBELF;
455da0c48c4Sopenharmony_ci    }
456da0c48c4Sopenharmony_ci
457da0c48c4Sopenharmony_ci  /* Now we can look at the original section headers of the main file
458da0c48c4Sopenharmony_ci     before it was prelinked.  First we'll apply our method to the main
459da0c48c4Sopenharmony_ci     file sections as they are after prelinking, to calculate the
460da0c48c4Sopenharmony_ci     synchronization address of the main file.  Then we'll apply that
461da0c48c4Sopenharmony_ci     same method to the saved section headers, to calculate the matching
462da0c48c4Sopenharmony_ci     synchronization address of the debug file.
463da0c48c4Sopenharmony_ci
464da0c48c4Sopenharmony_ci     The method is to consider SHF_ALLOC sections that are either
465da0c48c4Sopenharmony_ci     SHT_PROGBITS or SHT_NOBITS, excluding the section whose sh_addr
466da0c48c4Sopenharmony_ci     matches the PT_INTERP p_vaddr.  The special sections that can be
467da0c48c4Sopenharmony_ci     moved by prelink have other types, except for .interp (which
468da0c48c4Sopenharmony_ci     becomes PT_INTERP).  The "real" sections cannot move as such, but
469da0c48c4Sopenharmony_ci     .bss can be split into .dynbss and .bss, with the total memory
470da0c48c4Sopenharmony_ci     image remaining the same but being spread across the two sections.
471da0c48c4Sopenharmony_ci     So we consider the highest section end, which still matches up.  */
472da0c48c4Sopenharmony_ci
473da0c48c4Sopenharmony_ci  GElf_Addr highest;
474da0c48c4Sopenharmony_ci
475da0c48c4Sopenharmony_ci  highest = 0;
476da0c48c4Sopenharmony_ci  scn = NULL;
477da0c48c4Sopenharmony_ci  while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
478da0c48c4Sopenharmony_ci    {
479da0c48c4Sopenharmony_ci      GElf_Shdr sh_mem;
480da0c48c4Sopenharmony_ci      GElf_Shdr *sh = gelf_getshdr (scn, &sh_mem);
481da0c48c4Sopenharmony_ci      if (unlikely (sh == NULL))
482da0c48c4Sopenharmony_ci	{
483da0c48c4Sopenharmony_ci	  free (shdrs);
484da0c48c4Sopenharmony_ci	  return DWFL_E_LIBELF;
485da0c48c4Sopenharmony_ci	}
486da0c48c4Sopenharmony_ci      consider_shdr (main_interp, sh->sh_type, sh->sh_flags,
487da0c48c4Sopenharmony_ci		     sh->sh_addr, sh->sh_size, &highest);
488da0c48c4Sopenharmony_ci    }
489da0c48c4Sopenharmony_ci  if (highest > mod->main.vaddr)
490da0c48c4Sopenharmony_ci    {
491da0c48c4Sopenharmony_ci      mod->main.address_sync = highest;
492da0c48c4Sopenharmony_ci
493da0c48c4Sopenharmony_ci      highest = 0;
494da0c48c4Sopenharmony_ci      if (class32)
495da0c48c4Sopenharmony_ci	{
496da0c48c4Sopenharmony_ci	  Elf32_Shdr (*s32)[shnum] = shdrs;
497da0c48c4Sopenharmony_ci	  for (size_t i = 0; i < shnum; ++i)
498da0c48c4Sopenharmony_ci	    consider_shdr (undo_interp, (*s32)[i].sh_type,
499da0c48c4Sopenharmony_ci			   (*s32)[i].sh_flags, (*s32)[i].sh_addr,
500da0c48c4Sopenharmony_ci			   (*s32)[i].sh_size, &highest);
501da0c48c4Sopenharmony_ci	}
502da0c48c4Sopenharmony_ci      else
503da0c48c4Sopenharmony_ci	{
504da0c48c4Sopenharmony_ci	  Elf64_Shdr (*s64)[shnum] = shdrs;
505da0c48c4Sopenharmony_ci	  for (size_t i = 0; i < shnum; ++i)
506da0c48c4Sopenharmony_ci	    consider_shdr (undo_interp, (*s64)[i].sh_type,
507da0c48c4Sopenharmony_ci			   (*s64)[i].sh_flags, (*s64)[i].sh_addr,
508da0c48c4Sopenharmony_ci			   (*s64)[i].sh_size, &highest);
509da0c48c4Sopenharmony_ci	}
510da0c48c4Sopenharmony_ci
511da0c48c4Sopenharmony_ci      if (highest > file->vaddr)
512da0c48c4Sopenharmony_ci	file->address_sync = highest;
513da0c48c4Sopenharmony_ci      else
514da0c48c4Sopenharmony_ci	{
515da0c48c4Sopenharmony_ci	  free (shdrs);
516da0c48c4Sopenharmony_ci	  return DWFL_E_BAD_PRELINK;
517da0c48c4Sopenharmony_ci	}
518da0c48c4Sopenharmony_ci    }
519da0c48c4Sopenharmony_ci
520da0c48c4Sopenharmony_ci  free (shdrs);
521da0c48c4Sopenharmony_ci
522da0c48c4Sopenharmony_ci  return DWFL_E_NOERROR;
523da0c48c4Sopenharmony_ci}
524da0c48c4Sopenharmony_ci
525da0c48c4Sopenharmony_ci/* Find the separate debuginfo file for this module and open libelf on it.
526da0c48c4Sopenharmony_ci   When we return success, MOD->debug is set up.  */
527da0c48c4Sopenharmony_cistatic Dwfl_Error
528da0c48c4Sopenharmony_cifind_debuginfo (Dwfl_Module *mod)
529da0c48c4Sopenharmony_ci{
530da0c48c4Sopenharmony_ci  if (mod->debug.elf != NULL)
531da0c48c4Sopenharmony_ci    return DWFL_E_NOERROR;
532da0c48c4Sopenharmony_ci
533da0c48c4Sopenharmony_ci  GElf_Word debuglink_crc = 0;
534da0c48c4Sopenharmony_ci  const char *debuglink_file;
535da0c48c4Sopenharmony_ci  debuglink_file = INTUSE(dwelf_elf_gnu_debuglink) (mod->main.elf,
536da0c48c4Sopenharmony_ci						    &debuglink_crc);
537da0c48c4Sopenharmony_ci
538da0c48c4Sopenharmony_ci  mod->debug.fd = (*mod->dwfl->callbacks->find_debuginfo) (MODCB_ARGS (mod),
539da0c48c4Sopenharmony_ci							   mod->main.name,
540da0c48c4Sopenharmony_ci							   debuglink_file,
541da0c48c4Sopenharmony_ci							   debuglink_crc,
542da0c48c4Sopenharmony_ci							   &mod->debug.name);
543da0c48c4Sopenharmony_ci  Dwfl_Error result = open_elf (mod, &mod->debug);
544da0c48c4Sopenharmony_ci  if (result == DWFL_E_NOERROR && mod->debug.address_sync != 0)
545da0c48c4Sopenharmony_ci    result = find_prelink_address_sync (mod, &mod->debug);
546da0c48c4Sopenharmony_ci  return result;
547da0c48c4Sopenharmony_ci}
548da0c48c4Sopenharmony_ci
549da0c48c4Sopenharmony_ci/* Try to find the alternative debug link for the given DWARF and set
550da0c48c4Sopenharmony_ci   it if found.  Only called when mod->dw is already setup but still
551da0c48c4Sopenharmony_ci   might need an alternative (dwz multi) debug file.  filename is either
552da0c48c4Sopenharmony_ci   the main or debug name from which the Dwarf was created. */
553da0c48c4Sopenharmony_cistatic void
554da0c48c4Sopenharmony_cifind_debug_altlink (Dwfl_Module *mod, const char *filename)
555da0c48c4Sopenharmony_ci{
556da0c48c4Sopenharmony_ci  assert (mod->dw != NULL);
557da0c48c4Sopenharmony_ci
558da0c48c4Sopenharmony_ci  const char *altname;
559da0c48c4Sopenharmony_ci  const void *build_id;
560da0c48c4Sopenharmony_ci  ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (mod->dw,
561da0c48c4Sopenharmony_ci							       &altname,
562da0c48c4Sopenharmony_ci							       &build_id);
563da0c48c4Sopenharmony_ci
564da0c48c4Sopenharmony_ci  if (build_id_len > 0)
565da0c48c4Sopenharmony_ci    {
566da0c48c4Sopenharmony_ci      /* We could store altfile in the module, but don't really need it.  */
567da0c48c4Sopenharmony_ci      char *altfile = NULL;
568da0c48c4Sopenharmony_ci      mod->alt_fd = (*mod->dwfl->callbacks->find_debuginfo) (MODCB_ARGS (mod),
569da0c48c4Sopenharmony_ci							     filename,
570da0c48c4Sopenharmony_ci							     altname,
571da0c48c4Sopenharmony_ci							     0,
572da0c48c4Sopenharmony_ci							     &altfile);
573da0c48c4Sopenharmony_ci
574da0c48c4Sopenharmony_ci      /* The (internal) callbacks might just set mod->alt_elf directly
575da0c48c4Sopenharmony_ci	 because they open the Elf anyway for sanity checking.
576da0c48c4Sopenharmony_ci	 Otherwise open either the given file name or use the fd
577da0c48c4Sopenharmony_ci	 returned.  */
578da0c48c4Sopenharmony_ci      Dwfl_Error error = open_elf_file (&mod->alt_elf, &mod->alt_fd,
579da0c48c4Sopenharmony_ci					&altfile);
580da0c48c4Sopenharmony_ci      if (error == DWFL_E_NOERROR)
581da0c48c4Sopenharmony_ci	{
582da0c48c4Sopenharmony_ci	  mod->alt = INTUSE(dwarf_begin_elf) (mod->alt_elf,
583da0c48c4Sopenharmony_ci					      DWARF_C_READ, NULL);
584da0c48c4Sopenharmony_ci	  if (mod->alt == NULL)
585da0c48c4Sopenharmony_ci	    {
586da0c48c4Sopenharmony_ci	      elf_end (mod->alt_elf);
587da0c48c4Sopenharmony_ci	      mod->alt_elf = NULL;
588da0c48c4Sopenharmony_ci	      close (mod->alt_fd);
589da0c48c4Sopenharmony_ci	      mod->alt_fd = -1;
590da0c48c4Sopenharmony_ci	    }
591da0c48c4Sopenharmony_ci	  else
592da0c48c4Sopenharmony_ci	    dwarf_setalt (mod->dw, mod->alt);
593da0c48c4Sopenharmony_ci	}
594da0c48c4Sopenharmony_ci
595da0c48c4Sopenharmony_ci      free (altfile); /* See above, we don't really need it.  */
596da0c48c4Sopenharmony_ci    }
597da0c48c4Sopenharmony_ci}
598da0c48c4Sopenharmony_ci
599da0c48c4Sopenharmony_ci/* Try to find a symbol table in FILE.
600da0c48c4Sopenharmony_ci   Returns DWFL_E_NOERROR if a proper one is found.
601da0c48c4Sopenharmony_ci   Returns DWFL_E_NO_SYMTAB if not, but still sets results for SHT_DYNSYM.  */
602da0c48c4Sopenharmony_cistatic Dwfl_Error
603da0c48c4Sopenharmony_ciload_symtab (struct dwfl_file *file, struct dwfl_file **symfile,
604da0c48c4Sopenharmony_ci	     Elf_Scn **symscn, Elf_Scn **xndxscn,
605da0c48c4Sopenharmony_ci	     size_t *syments, int *first_global, GElf_Word *strshndx)
606da0c48c4Sopenharmony_ci{
607da0c48c4Sopenharmony_ci  bool symtab = false;
608da0c48c4Sopenharmony_ci  Elf_Scn *scn = NULL;
609da0c48c4Sopenharmony_ci  while ((scn = elf_nextscn (file->elf, scn)) != NULL)
610da0c48c4Sopenharmony_ci    {
611da0c48c4Sopenharmony_ci      GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
612da0c48c4Sopenharmony_ci      if (shdr != NULL)
613da0c48c4Sopenharmony_ci	switch (shdr->sh_type)
614da0c48c4Sopenharmony_ci	  {
615da0c48c4Sopenharmony_ci	  case SHT_SYMTAB:
616da0c48c4Sopenharmony_ci	    if (shdr->sh_entsize == 0)
617da0c48c4Sopenharmony_ci	      break;
618da0c48c4Sopenharmony_ci	    symtab = true;
619da0c48c4Sopenharmony_ci	    *symscn = scn;
620da0c48c4Sopenharmony_ci	    *symfile = file;
621da0c48c4Sopenharmony_ci	    *strshndx = shdr->sh_link;
622da0c48c4Sopenharmony_ci	    *syments = shdr->sh_size / shdr->sh_entsize;
623da0c48c4Sopenharmony_ci	    *first_global = shdr->sh_info;
624da0c48c4Sopenharmony_ci	    if (*xndxscn != NULL)
625da0c48c4Sopenharmony_ci	      return DWFL_E_NOERROR;
626da0c48c4Sopenharmony_ci	    break;
627da0c48c4Sopenharmony_ci
628da0c48c4Sopenharmony_ci	  case SHT_DYNSYM:
629da0c48c4Sopenharmony_ci	    if (symtab)
630da0c48c4Sopenharmony_ci	      break;
631da0c48c4Sopenharmony_ci	    /* Use this if need be, but keep looking for SHT_SYMTAB.  */
632da0c48c4Sopenharmony_ci	    if (shdr->sh_entsize == 0)
633da0c48c4Sopenharmony_ci	      break;
634da0c48c4Sopenharmony_ci	    *symscn = scn;
635da0c48c4Sopenharmony_ci	    *symfile = file;
636da0c48c4Sopenharmony_ci	    *strshndx = shdr->sh_link;
637da0c48c4Sopenharmony_ci	    *syments = shdr->sh_size / shdr->sh_entsize;
638da0c48c4Sopenharmony_ci	    *first_global = shdr->sh_info;
639da0c48c4Sopenharmony_ci	    break;
640da0c48c4Sopenharmony_ci
641da0c48c4Sopenharmony_ci	  case SHT_SYMTAB_SHNDX:
642da0c48c4Sopenharmony_ci	    *xndxscn = scn;
643da0c48c4Sopenharmony_ci	    if (symtab)
644da0c48c4Sopenharmony_ci	      return DWFL_E_NOERROR;
645da0c48c4Sopenharmony_ci	    break;
646da0c48c4Sopenharmony_ci
647da0c48c4Sopenharmony_ci	  default:
648da0c48c4Sopenharmony_ci	    break;
649da0c48c4Sopenharmony_ci	  }
650da0c48c4Sopenharmony_ci    }
651da0c48c4Sopenharmony_ci
652da0c48c4Sopenharmony_ci  if (symtab)
653da0c48c4Sopenharmony_ci    /* We found one, though no SHT_SYMTAB_SHNDX to go with it.  */
654da0c48c4Sopenharmony_ci    return DWFL_E_NOERROR;
655da0c48c4Sopenharmony_ci
656da0c48c4Sopenharmony_ci  /* We found no SHT_SYMTAB, so any SHT_SYMTAB_SHNDX was bogus.
657da0c48c4Sopenharmony_ci     We might have found an SHT_DYNSYM and set *SYMSCN et al though.  */
658da0c48c4Sopenharmony_ci  *xndxscn = NULL;
659da0c48c4Sopenharmony_ci  return DWFL_E_NO_SYMTAB;
660da0c48c4Sopenharmony_ci}
661da0c48c4Sopenharmony_ci
662da0c48c4Sopenharmony_ci
663da0c48c4Sopenharmony_ci/* Translate addresses into file offsets.
664da0c48c4Sopenharmony_ci   OFFS[*] start out zero and remain zero if unresolved.  */
665da0c48c4Sopenharmony_cistatic void
666da0c48c4Sopenharmony_cifind_offsets (Elf *elf, GElf_Addr main_bias, size_t phnum, size_t n,
667da0c48c4Sopenharmony_ci	      GElf_Addr addrs[n], GElf_Off offs[n])
668da0c48c4Sopenharmony_ci{
669da0c48c4Sopenharmony_ci  size_t unsolved = n;
670da0c48c4Sopenharmony_ci  for (size_t i = 0; i < phnum; ++i)
671da0c48c4Sopenharmony_ci    {
672da0c48c4Sopenharmony_ci      GElf_Phdr phdr_mem;
673da0c48c4Sopenharmony_ci      GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
674da0c48c4Sopenharmony_ci      if (phdr != NULL && phdr->p_type == PT_LOAD && phdr->p_memsz > 0)
675da0c48c4Sopenharmony_ci	for (size_t j = 0; j < n; ++j)
676da0c48c4Sopenharmony_ci	  if (offs[j] == 0
677da0c48c4Sopenharmony_ci	      && addrs[j] >= phdr->p_vaddr + main_bias
678da0c48c4Sopenharmony_ci	      && addrs[j] - (phdr->p_vaddr + main_bias) < phdr->p_filesz)
679da0c48c4Sopenharmony_ci	    {
680da0c48c4Sopenharmony_ci	      offs[j] = addrs[j] - (phdr->p_vaddr + main_bias) + phdr->p_offset;
681da0c48c4Sopenharmony_ci	      if (--unsolved == 0)
682da0c48c4Sopenharmony_ci		break;
683da0c48c4Sopenharmony_ci	    }
684da0c48c4Sopenharmony_ci    }
685da0c48c4Sopenharmony_ci}
686da0c48c4Sopenharmony_ci
687da0c48c4Sopenharmony_ci/* Various addresses we might want to pull from the dynamic segment.  */
688da0c48c4Sopenharmony_cienum
689da0c48c4Sopenharmony_ci{
690da0c48c4Sopenharmony_ci  i_symtab,
691da0c48c4Sopenharmony_ci  i_strtab,
692da0c48c4Sopenharmony_ci  i_hash,
693da0c48c4Sopenharmony_ci  i_gnu_hash,
694da0c48c4Sopenharmony_ci  i_max
695da0c48c4Sopenharmony_ci};
696da0c48c4Sopenharmony_ci
697da0c48c4Sopenharmony_ci/* Translate pointers into file offsets.  ADJUST is either zero
698da0c48c4Sopenharmony_ci   in case the dynamic segment wasn't adjusted or mod->main_bias.
699da0c48c4Sopenharmony_ci   Will set mod->symfile if the translated offsets can be used as
700da0c48c4Sopenharmony_ci   symbol table.  */
701da0c48c4Sopenharmony_cistatic void
702da0c48c4Sopenharmony_citranslate_offs (GElf_Addr adjust,
703da0c48c4Sopenharmony_ci                Dwfl_Module *mod, size_t phnum,
704da0c48c4Sopenharmony_ci                GElf_Addr addrs[i_max], GElf_Xword strsz,
705da0c48c4Sopenharmony_ci                GElf_Ehdr *ehdr)
706da0c48c4Sopenharmony_ci{
707da0c48c4Sopenharmony_ci  GElf_Off offs[i_max] = { 0, };
708da0c48c4Sopenharmony_ci  find_offsets (mod->main.elf, adjust, phnum, i_max, addrs, offs);
709da0c48c4Sopenharmony_ci
710da0c48c4Sopenharmony_ci  /* Figure out the size of the symbol table.  */
711da0c48c4Sopenharmony_ci  if (offs[i_hash] != 0)
712da0c48c4Sopenharmony_ci    {
713da0c48c4Sopenharmony_ci      /* In the original format, .hash says the size of .dynsym.  */
714da0c48c4Sopenharmony_ci
715da0c48c4Sopenharmony_ci      size_t entsz = SH_ENTSIZE_HASH (ehdr);
716da0c48c4Sopenharmony_ci      Elf_Data *data = elf_getdata_rawchunk (mod->main.elf,
717da0c48c4Sopenharmony_ci					     offs[i_hash] + entsz, entsz,
718da0c48c4Sopenharmony_ci					     (entsz == 4
719da0c48c4Sopenharmony_ci					      ? ELF_T_WORD : ELF_T_XWORD));
720da0c48c4Sopenharmony_ci      if (data != NULL)
721da0c48c4Sopenharmony_ci	mod->syments = (entsz == 4
722da0c48c4Sopenharmony_ci			? *(const GElf_Word *) data->d_buf
723da0c48c4Sopenharmony_ci			: *(const GElf_Xword *) data->d_buf);
724da0c48c4Sopenharmony_ci    }
725da0c48c4Sopenharmony_ci  if (offs[i_gnu_hash] != 0 && mod->syments == 0)
726da0c48c4Sopenharmony_ci    {
727da0c48c4Sopenharmony_ci      /* In the new format, we can derive it with some work.  */
728da0c48c4Sopenharmony_ci
729da0c48c4Sopenharmony_ci      const struct
730da0c48c4Sopenharmony_ci      {
731da0c48c4Sopenharmony_ci        Elf32_Word nbuckets;
732da0c48c4Sopenharmony_ci        Elf32_Word symndx;
733da0c48c4Sopenharmony_ci        Elf32_Word maskwords;
734da0c48c4Sopenharmony_ci        Elf32_Word shift2;
735da0c48c4Sopenharmony_ci      } *header;
736da0c48c4Sopenharmony_ci
737da0c48c4Sopenharmony_ci      Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, offs[i_gnu_hash],
738da0c48c4Sopenharmony_ci					     sizeof *header, ELF_T_WORD);
739da0c48c4Sopenharmony_ci      if (data != NULL)
740da0c48c4Sopenharmony_ci        {
741da0c48c4Sopenharmony_ci          header = data->d_buf;
742da0c48c4Sopenharmony_ci          Elf32_Word nbuckets = header->nbuckets;
743da0c48c4Sopenharmony_ci          Elf32_Word symndx = header->symndx;
744da0c48c4Sopenharmony_ci          GElf_Off buckets_at = (offs[i_gnu_hash] + sizeof *header
745da0c48c4Sopenharmony_ci				 + (gelf_getclass (mod->main.elf)
746da0c48c4Sopenharmony_ci				    * sizeof (Elf32_Word)
747da0c48c4Sopenharmony_ci				    * header->maskwords));
748da0c48c4Sopenharmony_ci
749da0c48c4Sopenharmony_ci          // elf_getdata_rawchunk takes a size_t, make sure it
750da0c48c4Sopenharmony_ci          // doesn't overflow.
751da0c48c4Sopenharmony_ci#if SIZE_MAX <= UINT32_MAX
752da0c48c4Sopenharmony_ci          if (nbuckets > SIZE_MAX / sizeof (Elf32_Word))
753da0c48c4Sopenharmony_ci            data = NULL;
754da0c48c4Sopenharmony_ci          else
755da0c48c4Sopenharmony_ci#endif
756da0c48c4Sopenharmony_ci            data = elf_getdata_rawchunk (mod->main.elf, buckets_at,
757da0c48c4Sopenharmony_ci					   nbuckets * sizeof (Elf32_Word),
758da0c48c4Sopenharmony_ci					   ELF_T_WORD);
759da0c48c4Sopenharmony_ci	  if (data != NULL && symndx < nbuckets)
760da0c48c4Sopenharmony_ci	    {
761da0c48c4Sopenharmony_ci	      const Elf32_Word *const buckets = data->d_buf;
762da0c48c4Sopenharmony_ci	      Elf32_Word maxndx = symndx;
763da0c48c4Sopenharmony_ci	      for (Elf32_Word bucket = 0; bucket < nbuckets; ++bucket)
764da0c48c4Sopenharmony_ci		if (buckets[bucket] > maxndx)
765da0c48c4Sopenharmony_ci		  maxndx = buckets[bucket];
766da0c48c4Sopenharmony_ci
767da0c48c4Sopenharmony_ci	      GElf_Off hasharr_at = (buckets_at
768da0c48c4Sopenharmony_ci				     + nbuckets * sizeof (Elf32_Word));
769da0c48c4Sopenharmony_ci	      hasharr_at += (maxndx - symndx) * sizeof (Elf32_Word);
770da0c48c4Sopenharmony_ci	      do
771da0c48c4Sopenharmony_ci		{
772da0c48c4Sopenharmony_ci		  data = elf_getdata_rawchunk (mod->main.elf,
773da0c48c4Sopenharmony_ci					       hasharr_at,
774da0c48c4Sopenharmony_ci					       sizeof (Elf32_Word),
775da0c48c4Sopenharmony_ci					       ELF_T_WORD);
776da0c48c4Sopenharmony_ci		  if (data != NULL
777da0c48c4Sopenharmony_ci		      && (*(const Elf32_Word *) data->d_buf & 1u))
778da0c48c4Sopenharmony_ci		    {
779da0c48c4Sopenharmony_ci		      mod->syments = maxndx + 1;
780da0c48c4Sopenharmony_ci		      break;
781da0c48c4Sopenharmony_ci		    }
782da0c48c4Sopenharmony_ci		  ++maxndx;
783da0c48c4Sopenharmony_ci		  hasharr_at += sizeof (Elf32_Word);
784da0c48c4Sopenharmony_ci		}
785da0c48c4Sopenharmony_ci	      while (data != NULL);
786da0c48c4Sopenharmony_ci	    }
787da0c48c4Sopenharmony_ci	}
788da0c48c4Sopenharmony_ci    }
789da0c48c4Sopenharmony_ci  if (offs[i_strtab] > offs[i_symtab] && mod->syments == 0)
790da0c48c4Sopenharmony_ci    mod->syments = ((offs[i_strtab] - offs[i_symtab])
791da0c48c4Sopenharmony_ci		    / gelf_fsize (mod->main.elf,
792da0c48c4Sopenharmony_ci				  ELF_T_SYM, 1, EV_CURRENT));
793da0c48c4Sopenharmony_ci
794da0c48c4Sopenharmony_ci  if (mod->syments > 0)
795da0c48c4Sopenharmony_ci    {
796da0c48c4Sopenharmony_ci      mod->symdata = elf_getdata_rawchunk (mod->main.elf,
797da0c48c4Sopenharmony_ci					   offs[i_symtab],
798da0c48c4Sopenharmony_ci					   gelf_fsize (mod->main.elf,
799da0c48c4Sopenharmony_ci						       ELF_T_SYM,
800da0c48c4Sopenharmony_ci						       mod->syments,
801da0c48c4Sopenharmony_ci						       EV_CURRENT),
802da0c48c4Sopenharmony_ci						       ELF_T_SYM);
803da0c48c4Sopenharmony_ci      if (mod->symdata != NULL)
804da0c48c4Sopenharmony_ci	{
805da0c48c4Sopenharmony_ci	  mod->symstrdata = elf_getdata_rawchunk (mod->main.elf,
806da0c48c4Sopenharmony_ci						  offs[i_strtab],
807da0c48c4Sopenharmony_ci						  strsz,
808da0c48c4Sopenharmony_ci						  ELF_T_BYTE);
809da0c48c4Sopenharmony_ci	  if (mod->symstrdata == NULL)
810da0c48c4Sopenharmony_ci	    mod->symdata = NULL;
811da0c48c4Sopenharmony_ci	}
812da0c48c4Sopenharmony_ci      if (mod->symdata == NULL)
813da0c48c4Sopenharmony_ci	mod->symerr = DWFL_E (LIBELF, elf_errno ());
814da0c48c4Sopenharmony_ci      else
815da0c48c4Sopenharmony_ci	{
816da0c48c4Sopenharmony_ci	  mod->symfile = &mod->main;
817da0c48c4Sopenharmony_ci	  mod->symerr = DWFL_E_NOERROR;
818da0c48c4Sopenharmony_ci	}
819da0c48c4Sopenharmony_ci    }
820da0c48c4Sopenharmony_ci}
821da0c48c4Sopenharmony_ci
822da0c48c4Sopenharmony_ci/* Try to find a dynamic symbol table via phdrs.  */
823da0c48c4Sopenharmony_cistatic void
824da0c48c4Sopenharmony_cifind_dynsym (Dwfl_Module *mod)
825da0c48c4Sopenharmony_ci{
826da0c48c4Sopenharmony_ci  GElf_Ehdr ehdr_mem;
827da0c48c4Sopenharmony_ci  GElf_Ehdr *ehdr = gelf_getehdr (mod->main.elf, &ehdr_mem);
828da0c48c4Sopenharmony_ci
829da0c48c4Sopenharmony_ci  size_t phnum;
830da0c48c4Sopenharmony_ci  if (unlikely (elf_getphdrnum (mod->main.elf, &phnum) != 0))
831da0c48c4Sopenharmony_ci    return;
832da0c48c4Sopenharmony_ci
833da0c48c4Sopenharmony_ci  for (size_t i = 0; i < phnum; ++i)
834da0c48c4Sopenharmony_ci    {
835da0c48c4Sopenharmony_ci      GElf_Phdr phdr_mem;
836da0c48c4Sopenharmony_ci      GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem);
837da0c48c4Sopenharmony_ci      if (phdr == NULL)
838da0c48c4Sopenharmony_ci	break;
839da0c48c4Sopenharmony_ci
840da0c48c4Sopenharmony_ci      if (phdr->p_type == PT_DYNAMIC)
841da0c48c4Sopenharmony_ci	{
842da0c48c4Sopenharmony_ci	  /* Examine the dynamic section for the pointers we need.  */
843da0c48c4Sopenharmony_ci
844da0c48c4Sopenharmony_ci	  Elf_Data *data = elf_getdata_rawchunk (mod->main.elf,
845da0c48c4Sopenharmony_ci						 phdr->p_offset, phdr->p_filesz,
846da0c48c4Sopenharmony_ci						 ELF_T_DYN);
847da0c48c4Sopenharmony_ci	  if (data == NULL)
848da0c48c4Sopenharmony_ci	    continue;
849da0c48c4Sopenharmony_ci
850da0c48c4Sopenharmony_ci	  GElf_Addr addrs[i_max] = { 0, };
851da0c48c4Sopenharmony_ci	  GElf_Xword strsz = 0;
852da0c48c4Sopenharmony_ci	  size_t n = data->d_size / gelf_fsize (mod->main.elf,
853da0c48c4Sopenharmony_ci						ELF_T_DYN, 1, EV_CURRENT);
854da0c48c4Sopenharmony_ci	  for (size_t j = 0; j < n; ++j)
855da0c48c4Sopenharmony_ci	    {
856da0c48c4Sopenharmony_ci	      GElf_Dyn dyn_mem;
857da0c48c4Sopenharmony_ci	      GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem);
858da0c48c4Sopenharmony_ci	      if (dyn != NULL)
859da0c48c4Sopenharmony_ci		switch (dyn->d_tag)
860da0c48c4Sopenharmony_ci		  {
861da0c48c4Sopenharmony_ci		  case DT_SYMTAB:
862da0c48c4Sopenharmony_ci		    addrs[i_symtab] = dyn->d_un.d_ptr;
863da0c48c4Sopenharmony_ci		    continue;
864da0c48c4Sopenharmony_ci
865da0c48c4Sopenharmony_ci		  case DT_HASH:
866da0c48c4Sopenharmony_ci		    addrs[i_hash] = dyn->d_un.d_ptr;
867da0c48c4Sopenharmony_ci		    continue;
868da0c48c4Sopenharmony_ci
869da0c48c4Sopenharmony_ci		  case DT_GNU_HASH:
870da0c48c4Sopenharmony_ci		    addrs[i_gnu_hash] = dyn->d_un.d_ptr;
871da0c48c4Sopenharmony_ci		    continue;
872da0c48c4Sopenharmony_ci
873da0c48c4Sopenharmony_ci		  case DT_STRTAB:
874da0c48c4Sopenharmony_ci		    addrs[i_strtab] = dyn->d_un.d_ptr;
875da0c48c4Sopenharmony_ci		    continue;
876da0c48c4Sopenharmony_ci
877da0c48c4Sopenharmony_ci		  case DT_STRSZ:
878da0c48c4Sopenharmony_ci		    strsz = dyn->d_un.d_val;
879da0c48c4Sopenharmony_ci		    continue;
880da0c48c4Sopenharmony_ci
881da0c48c4Sopenharmony_ci		  default:
882da0c48c4Sopenharmony_ci		    continue;
883da0c48c4Sopenharmony_ci
884da0c48c4Sopenharmony_ci		  case DT_NULL:
885da0c48c4Sopenharmony_ci		    break;
886da0c48c4Sopenharmony_ci		  }
887da0c48c4Sopenharmony_ci	      break;
888da0c48c4Sopenharmony_ci	    }
889da0c48c4Sopenharmony_ci
890da0c48c4Sopenharmony_ci	  /* First try unadjusted, like ELF files from disk, vdso.
891da0c48c4Sopenharmony_ci	     Then try for already adjusted dynamic section, like ELF
892da0c48c4Sopenharmony_ci	     from remote memory.  */
893da0c48c4Sopenharmony_ci	  translate_offs (0, mod, phnum, addrs, strsz, ehdr);
894da0c48c4Sopenharmony_ci	  if (mod->symfile == NULL)
895da0c48c4Sopenharmony_ci	    translate_offs (mod->main_bias, mod, phnum, addrs, strsz, ehdr);
896da0c48c4Sopenharmony_ci
897da0c48c4Sopenharmony_ci	  return;
898da0c48c4Sopenharmony_ci	}
899da0c48c4Sopenharmony_ci    }
900da0c48c4Sopenharmony_ci}
901da0c48c4Sopenharmony_ci
902da0c48c4Sopenharmony_ci
903da0c48c4Sopenharmony_ci#if USE_LZMA
904da0c48c4Sopenharmony_ci/* Try to find the offset between the main file and .gnu_debugdata.  */
905da0c48c4Sopenharmony_cistatic bool
906da0c48c4Sopenharmony_cifind_aux_address_sync (Dwfl_Module *mod)
907da0c48c4Sopenharmony_ci{
908da0c48c4Sopenharmony_ci  /* Don't trust the phdrs in the minisymtab elf file to be setup correctly.
909da0c48c4Sopenharmony_ci     The address_sync is equal to the main file it is embedded in at first.  */
910da0c48c4Sopenharmony_ci  mod->aux_sym.address_sync = mod->main.address_sync;
911da0c48c4Sopenharmony_ci
912da0c48c4Sopenharmony_ci  /* Adjust address_sync for the difference in entry addresses, attempting to
913da0c48c4Sopenharmony_ci     account for ELF relocation changes after aux was split.  */
914da0c48c4Sopenharmony_ci  GElf_Ehdr ehdr_main, ehdr_aux;
915da0c48c4Sopenharmony_ci  if (unlikely (gelf_getehdr (mod->main.elf, &ehdr_main) == NULL)
916da0c48c4Sopenharmony_ci      || unlikely (gelf_getehdr (mod->aux_sym.elf, &ehdr_aux) == NULL))
917da0c48c4Sopenharmony_ci    return false;
918da0c48c4Sopenharmony_ci  mod->aux_sym.address_sync += ehdr_aux.e_entry - ehdr_main.e_entry;
919da0c48c4Sopenharmony_ci
920da0c48c4Sopenharmony_ci  /* The shdrs are setup OK to make find_prelink_address_sync () do the right
921da0c48c4Sopenharmony_ci     thing, which is possibly more reliable, but it needs .gnu.prelink_undo.  */
922da0c48c4Sopenharmony_ci  if (mod->aux_sym.address_sync != 0)
923da0c48c4Sopenharmony_ci    return find_prelink_address_sync (mod, &mod->aux_sym) == DWFL_E_NOERROR;
924da0c48c4Sopenharmony_ci
925da0c48c4Sopenharmony_ci  return true;
926da0c48c4Sopenharmony_ci}
927da0c48c4Sopenharmony_ci#endif
928da0c48c4Sopenharmony_ci
929da0c48c4Sopenharmony_ci/* Try to find the auxiliary symbol table embedded in the main elf file
930da0c48c4Sopenharmony_ci   section .gnu_debugdata.  Only matters if the symbol information comes
931da0c48c4Sopenharmony_ci   from the main file dynsym.  No harm done if not found.  */
932da0c48c4Sopenharmony_cistatic void
933da0c48c4Sopenharmony_cifind_aux_sym (Dwfl_Module *mod __attribute__ ((unused)),
934da0c48c4Sopenharmony_ci	      Elf_Scn **aux_symscn __attribute__ ((unused)),
935da0c48c4Sopenharmony_ci	      Elf_Scn **aux_xndxscn __attribute__ ((unused)),
936da0c48c4Sopenharmony_ci	      GElf_Word *aux_strshndx __attribute__ ((unused)))
937da0c48c4Sopenharmony_ci{
938da0c48c4Sopenharmony_ci  /* Since a .gnu_debugdata section is compressed using lzma don't do
939da0c48c4Sopenharmony_ci     anything unless we have support for that.  */
940da0c48c4Sopenharmony_ci#if USE_LZMA
941da0c48c4Sopenharmony_ci  Elf *elf = mod->main.elf;
942da0c48c4Sopenharmony_ci
943da0c48c4Sopenharmony_ci  size_t shstrndx;
944da0c48c4Sopenharmony_ci  if (elf_getshdrstrndx (elf, &shstrndx) < 0)
945da0c48c4Sopenharmony_ci    return;
946da0c48c4Sopenharmony_ci
947da0c48c4Sopenharmony_ci  Elf_Scn *scn = NULL;
948da0c48c4Sopenharmony_ci  while ((scn = elf_nextscn (elf, scn)) != NULL)
949da0c48c4Sopenharmony_ci    {
950da0c48c4Sopenharmony_ci      GElf_Shdr shdr_mem;
951da0c48c4Sopenharmony_ci      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
952da0c48c4Sopenharmony_ci      if (shdr == NULL)
953da0c48c4Sopenharmony_ci	return;
954da0c48c4Sopenharmony_ci
955da0c48c4Sopenharmony_ci      const char *name = elf_strptr (elf, shstrndx, shdr->sh_name);
956da0c48c4Sopenharmony_ci      if (name == NULL)
957da0c48c4Sopenharmony_ci	return;
958da0c48c4Sopenharmony_ci
959da0c48c4Sopenharmony_ci      if (!strcmp (name, ".gnu_debugdata"))
960da0c48c4Sopenharmony_ci	break;
961da0c48c4Sopenharmony_ci    }
962da0c48c4Sopenharmony_ci
963da0c48c4Sopenharmony_ci  if (scn == NULL)
964da0c48c4Sopenharmony_ci    return;
965da0c48c4Sopenharmony_ci
966da0c48c4Sopenharmony_ci  /* Found the .gnu_debugdata section.  Uncompress the lzma image and
967da0c48c4Sopenharmony_ci     turn it into an ELF image.  */
968da0c48c4Sopenharmony_ci  Elf_Data *rawdata = elf_rawdata (scn, NULL);
969da0c48c4Sopenharmony_ci  if (rawdata == NULL)
970da0c48c4Sopenharmony_ci    return;
971da0c48c4Sopenharmony_ci
972da0c48c4Sopenharmony_ci  Dwfl_Error error;
973da0c48c4Sopenharmony_ci  void *buffer = NULL;
974da0c48c4Sopenharmony_ci  size_t size = 0;
975da0c48c4Sopenharmony_ci  error = __libdw_unlzma (-1, 0, rawdata->d_buf, rawdata->d_size,
976da0c48c4Sopenharmony_ci			  &buffer, &size);
977da0c48c4Sopenharmony_ci  if (error == DWFL_E_NOERROR)
978da0c48c4Sopenharmony_ci    {
979da0c48c4Sopenharmony_ci      if (unlikely (size == 0))
980da0c48c4Sopenharmony_ci	free (buffer);
981da0c48c4Sopenharmony_ci      else
982da0c48c4Sopenharmony_ci	{
983da0c48c4Sopenharmony_ci	  mod->aux_sym.elf = elf_memory (buffer, size);
984da0c48c4Sopenharmony_ci	  if (mod->aux_sym.elf == NULL)
985da0c48c4Sopenharmony_ci	    free (buffer);
986da0c48c4Sopenharmony_ci	  else
987da0c48c4Sopenharmony_ci	    {
988da0c48c4Sopenharmony_ci	      mod->aux_sym.fd = -1;
989da0c48c4Sopenharmony_ci	      mod->aux_sym.elf->flags |= ELF_F_MALLOCED;
990da0c48c4Sopenharmony_ci	      if (open_elf (mod, &mod->aux_sym) != DWFL_E_NOERROR)
991da0c48c4Sopenharmony_ci		return;
992da0c48c4Sopenharmony_ci	      if (! find_aux_address_sync (mod))
993da0c48c4Sopenharmony_ci		{
994da0c48c4Sopenharmony_ci		  elf_end (mod->aux_sym.elf);
995da0c48c4Sopenharmony_ci		  mod->aux_sym.elf = NULL;
996da0c48c4Sopenharmony_ci		  return;
997da0c48c4Sopenharmony_ci		}
998da0c48c4Sopenharmony_ci
999da0c48c4Sopenharmony_ci	      /* So far, so good. Get minisymtab table data and cache it. */
1000da0c48c4Sopenharmony_ci	      bool minisymtab = false;
1001da0c48c4Sopenharmony_ci	      scn = NULL;
1002da0c48c4Sopenharmony_ci	      while ((scn = elf_nextscn (mod->aux_sym.elf, scn)) != NULL)
1003da0c48c4Sopenharmony_ci		{
1004da0c48c4Sopenharmony_ci		  GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
1005da0c48c4Sopenharmony_ci		  if (shdr != NULL)
1006da0c48c4Sopenharmony_ci		    switch (shdr->sh_type)
1007da0c48c4Sopenharmony_ci		      {
1008da0c48c4Sopenharmony_ci		      case SHT_SYMTAB:
1009da0c48c4Sopenharmony_ci			if (shdr->sh_entsize == 0)
1010da0c48c4Sopenharmony_ci			  return;
1011da0c48c4Sopenharmony_ci			minisymtab = true;
1012da0c48c4Sopenharmony_ci			*aux_symscn = scn;
1013da0c48c4Sopenharmony_ci			*aux_strshndx = shdr->sh_link;
1014da0c48c4Sopenharmony_ci			mod->aux_syments = shdr->sh_size / shdr->sh_entsize;
1015da0c48c4Sopenharmony_ci			mod->aux_first_global = shdr->sh_info;
1016da0c48c4Sopenharmony_ci			if (*aux_xndxscn != NULL)
1017da0c48c4Sopenharmony_ci			  return;
1018da0c48c4Sopenharmony_ci			break;
1019da0c48c4Sopenharmony_ci
1020da0c48c4Sopenharmony_ci		      case SHT_SYMTAB_SHNDX:
1021da0c48c4Sopenharmony_ci			*aux_xndxscn = scn;
1022da0c48c4Sopenharmony_ci			if (minisymtab)
1023da0c48c4Sopenharmony_ci			  return;
1024da0c48c4Sopenharmony_ci			break;
1025da0c48c4Sopenharmony_ci
1026da0c48c4Sopenharmony_ci		      default:
1027da0c48c4Sopenharmony_ci			break;
1028da0c48c4Sopenharmony_ci		      }
1029da0c48c4Sopenharmony_ci		}
1030da0c48c4Sopenharmony_ci
1031da0c48c4Sopenharmony_ci	      if (minisymtab)
1032da0c48c4Sopenharmony_ci		/* We found one, though no SHT_SYMTAB_SHNDX to go with it.  */
1033da0c48c4Sopenharmony_ci		return;
1034da0c48c4Sopenharmony_ci
1035da0c48c4Sopenharmony_ci	      /* We found no SHT_SYMTAB, so everything else is bogus.  */
1036da0c48c4Sopenharmony_ci	      *aux_xndxscn = NULL;
1037da0c48c4Sopenharmony_ci	      *aux_strshndx = 0;
1038da0c48c4Sopenharmony_ci	      mod->aux_syments = 0;
1039da0c48c4Sopenharmony_ci	      elf_end (mod->aux_sym.elf);
1040da0c48c4Sopenharmony_ci	      mod->aux_sym.elf = NULL;
1041da0c48c4Sopenharmony_ci	      return;
1042da0c48c4Sopenharmony_ci	    }
1043da0c48c4Sopenharmony_ci	}
1044da0c48c4Sopenharmony_ci    }
1045da0c48c4Sopenharmony_ci  else
1046da0c48c4Sopenharmony_ci    free (buffer);
1047da0c48c4Sopenharmony_ci#endif
1048da0c48c4Sopenharmony_ci}
1049da0c48c4Sopenharmony_ci
1050da0c48c4Sopenharmony_ci/* Try to find a symbol table in either MOD->main.elf or MOD->debug.elf.  */
1051da0c48c4Sopenharmony_cistatic void
1052da0c48c4Sopenharmony_cifind_symtab (Dwfl_Module *mod)
1053da0c48c4Sopenharmony_ci{
1054da0c48c4Sopenharmony_ci  if (mod->symdata != NULL || mod->aux_symdata != NULL	/* Already done.  */
1055da0c48c4Sopenharmony_ci      || mod->symerr != DWFL_E_NOERROR) /* Cached previous failure.  */
1056da0c48c4Sopenharmony_ci    return;
1057da0c48c4Sopenharmony_ci
1058da0c48c4Sopenharmony_ci  __libdwfl_getelf (mod);
1059da0c48c4Sopenharmony_ci  mod->symerr = mod->elferr;
1060da0c48c4Sopenharmony_ci  if (mod->symerr != DWFL_E_NOERROR)
1061da0c48c4Sopenharmony_ci    return;
1062da0c48c4Sopenharmony_ci
1063da0c48c4Sopenharmony_ci  /* First see if the main ELF file has the debugging information.  */
1064da0c48c4Sopenharmony_ci  Elf_Scn *symscn = NULL, *xndxscn = NULL;
1065da0c48c4Sopenharmony_ci  Elf_Scn *aux_symscn = NULL, *aux_xndxscn = NULL;
1066da0c48c4Sopenharmony_ci  GElf_Word strshndx, aux_strshndx = 0;
1067da0c48c4Sopenharmony_ci  mod->symerr = load_symtab (&mod->main, &mod->symfile, &symscn,
1068da0c48c4Sopenharmony_ci			     &xndxscn, &mod->syments, &mod->first_global,
1069da0c48c4Sopenharmony_ci			     &strshndx);
1070da0c48c4Sopenharmony_ci  switch (mod->symerr)
1071da0c48c4Sopenharmony_ci    {
1072da0c48c4Sopenharmony_ci    default:
1073da0c48c4Sopenharmony_ci      return;
1074da0c48c4Sopenharmony_ci
1075da0c48c4Sopenharmony_ci    case DWFL_E_NOERROR:
1076da0c48c4Sopenharmony_ci      break;
1077da0c48c4Sopenharmony_ci
1078da0c48c4Sopenharmony_ci    case DWFL_E_NO_SYMTAB:
1079da0c48c4Sopenharmony_ci      /* Now we have to look for a separate debuginfo file.  */
1080da0c48c4Sopenharmony_ci      mod->symerr = find_debuginfo (mod);
1081da0c48c4Sopenharmony_ci      switch (mod->symerr)
1082da0c48c4Sopenharmony_ci	{
1083da0c48c4Sopenharmony_ci	default:
1084da0c48c4Sopenharmony_ci	  return;
1085da0c48c4Sopenharmony_ci
1086da0c48c4Sopenharmony_ci	case DWFL_E_NOERROR:
1087da0c48c4Sopenharmony_ci	  mod->symerr = load_symtab (&mod->debug, &mod->symfile, &symscn,
1088da0c48c4Sopenharmony_ci				     &xndxscn, &mod->syments,
1089da0c48c4Sopenharmony_ci				     &mod->first_global, &strshndx);
1090da0c48c4Sopenharmony_ci	  break;
1091da0c48c4Sopenharmony_ci
1092da0c48c4Sopenharmony_ci	case DWFL_E_CB:		/* The find_debuginfo hook failed.  */
1093da0c48c4Sopenharmony_ci	  mod->symerr = DWFL_E_NO_SYMTAB;
1094da0c48c4Sopenharmony_ci	  break;
1095da0c48c4Sopenharmony_ci	}
1096da0c48c4Sopenharmony_ci
1097da0c48c4Sopenharmony_ci      switch (mod->symerr)
1098da0c48c4Sopenharmony_ci	{
1099da0c48c4Sopenharmony_ci	default:
1100da0c48c4Sopenharmony_ci	  return;
1101da0c48c4Sopenharmony_ci
1102da0c48c4Sopenharmony_ci	case DWFL_E_NOERROR:
1103da0c48c4Sopenharmony_ci	  break;
1104da0c48c4Sopenharmony_ci
1105da0c48c4Sopenharmony_ci	case DWFL_E_NO_SYMTAB:
1106da0c48c4Sopenharmony_ci	  /* There might be an auxiliary table.  */
1107da0c48c4Sopenharmony_ci	  find_aux_sym (mod, &aux_symscn, &aux_xndxscn, &aux_strshndx);
1108da0c48c4Sopenharmony_ci
1109da0c48c4Sopenharmony_ci	  if (symscn != NULL)
1110da0c48c4Sopenharmony_ci	    {
1111da0c48c4Sopenharmony_ci	      /* We still have the dynamic symbol table.  */
1112da0c48c4Sopenharmony_ci	      mod->symerr = DWFL_E_NOERROR;
1113da0c48c4Sopenharmony_ci	      break;
1114da0c48c4Sopenharmony_ci	    }
1115da0c48c4Sopenharmony_ci
1116da0c48c4Sopenharmony_ci	  if (aux_symscn != NULL)
1117da0c48c4Sopenharmony_ci	    {
1118da0c48c4Sopenharmony_ci	      /* We still have the auxiliary symbol table.  */
1119da0c48c4Sopenharmony_ci	      mod->symerr = DWFL_E_NOERROR;
1120da0c48c4Sopenharmony_ci	      goto aux_cache;
1121da0c48c4Sopenharmony_ci	    }
1122da0c48c4Sopenharmony_ci
1123da0c48c4Sopenharmony_ci	  /* Last ditch, look for dynamic symbols without section headers.  */
1124da0c48c4Sopenharmony_ci	  find_dynsym (mod);
1125da0c48c4Sopenharmony_ci	  return;
1126da0c48c4Sopenharmony_ci	}
1127da0c48c4Sopenharmony_ci      break;
1128da0c48c4Sopenharmony_ci    }
1129da0c48c4Sopenharmony_ci
1130da0c48c4Sopenharmony_ci  /* This does some sanity checks on the string table section.  */
1131da0c48c4Sopenharmony_ci  if (elf_strptr (mod->symfile->elf, strshndx, 0) == NULL)
1132da0c48c4Sopenharmony_ci    {
1133da0c48c4Sopenharmony_ci    elferr:
1134da0c48c4Sopenharmony_ci      mod->symdata = NULL;
1135da0c48c4Sopenharmony_ci      mod->syments = 0;
1136da0c48c4Sopenharmony_ci      mod->first_global = 0;
1137da0c48c4Sopenharmony_ci      mod->symerr = DWFL_E (LIBELF, elf_errno ());
1138da0c48c4Sopenharmony_ci      goto aux_cleanup; /* This cleans up some more and tries find_dynsym.  */
1139da0c48c4Sopenharmony_ci    }
1140da0c48c4Sopenharmony_ci
1141da0c48c4Sopenharmony_ci  /* Cache the data; MOD->syments and MOD->first_global were set
1142da0c48c4Sopenharmony_ci     above.  If any of the sections is compressed, uncompress it
1143da0c48c4Sopenharmony_ci     first.  Only the string data section could theoretically be
1144da0c48c4Sopenharmony_ci     compressed GNU style (as .zdebug_str).  Everything else only ELF
1145da0c48c4Sopenharmony_ci     gabi style (SHF_COMPRESSED).  */
1146da0c48c4Sopenharmony_ci
1147da0c48c4Sopenharmony_ci  Elf_Scn *symstrscn = elf_getscn (mod->symfile->elf, strshndx);
1148da0c48c4Sopenharmony_ci  if (symstrscn == NULL)
1149da0c48c4Sopenharmony_ci    goto elferr;
1150da0c48c4Sopenharmony_ci
1151da0c48c4Sopenharmony_ci  GElf_Shdr shdr_mem;
1152da0c48c4Sopenharmony_ci  GElf_Shdr *shdr = gelf_getshdr (symstrscn, &shdr_mem);
1153da0c48c4Sopenharmony_ci  if (shdr == NULL)
1154da0c48c4Sopenharmony_ci    goto elferr;
1155da0c48c4Sopenharmony_ci
1156da0c48c4Sopenharmony_ci  size_t shstrndx;
1157da0c48c4Sopenharmony_ci  if (elf_getshdrstrndx (mod->symfile->elf, &shstrndx) < 0)
1158da0c48c4Sopenharmony_ci    goto elferr;
1159da0c48c4Sopenharmony_ci
1160da0c48c4Sopenharmony_ci  const char *sname = elf_strptr (mod->symfile->elf, shstrndx, shdr->sh_name);
1161da0c48c4Sopenharmony_ci  if (sname == NULL)
1162da0c48c4Sopenharmony_ci    goto elferr;
1163da0c48c4Sopenharmony_ci
1164da0c48c4Sopenharmony_ci  if (startswith (sname, ".zdebug"))
1165da0c48c4Sopenharmony_ci    /* Try to uncompress, but it might already have been, an error
1166da0c48c4Sopenharmony_ci       might just indicate, already uncompressed.  */
1167da0c48c4Sopenharmony_ci    elf_compress_gnu (symstrscn, 0, 0);
1168da0c48c4Sopenharmony_ci
1169da0c48c4Sopenharmony_ci  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
1170da0c48c4Sopenharmony_ci    if (elf_compress (symstrscn, 0, 0) < 0)
1171da0c48c4Sopenharmony_ci      goto elferr;
1172da0c48c4Sopenharmony_ci
1173da0c48c4Sopenharmony_ci  mod->symstrdata = elf_getdata (symstrscn, NULL);
1174da0c48c4Sopenharmony_ci  if (mod->symstrdata == NULL || mod->symstrdata->d_buf == NULL)
1175da0c48c4Sopenharmony_ci    goto elferr;
1176da0c48c4Sopenharmony_ci
1177da0c48c4Sopenharmony_ci  if (xndxscn == NULL)
1178da0c48c4Sopenharmony_ci    mod->symxndxdata = NULL;
1179da0c48c4Sopenharmony_ci  else
1180da0c48c4Sopenharmony_ci    {
1181da0c48c4Sopenharmony_ci      shdr = gelf_getshdr (xndxscn, &shdr_mem);
1182da0c48c4Sopenharmony_ci      if (shdr == NULL)
1183da0c48c4Sopenharmony_ci	goto elferr;
1184da0c48c4Sopenharmony_ci
1185da0c48c4Sopenharmony_ci      if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
1186da0c48c4Sopenharmony_ci	if (elf_compress (xndxscn, 0, 0) < 0)
1187da0c48c4Sopenharmony_ci	  goto elferr;
1188da0c48c4Sopenharmony_ci
1189da0c48c4Sopenharmony_ci      mod->symxndxdata = elf_getdata (xndxscn, NULL);
1190da0c48c4Sopenharmony_ci      if (mod->symxndxdata == NULL || mod->symxndxdata->d_buf == NULL)
1191da0c48c4Sopenharmony_ci	goto elferr;
1192da0c48c4Sopenharmony_ci    }
1193da0c48c4Sopenharmony_ci
1194da0c48c4Sopenharmony_ci  shdr = gelf_getshdr (symscn, &shdr_mem);
1195da0c48c4Sopenharmony_ci  if (shdr == NULL)
1196da0c48c4Sopenharmony_ci    goto elferr;
1197da0c48c4Sopenharmony_ci
1198da0c48c4Sopenharmony_ci  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
1199da0c48c4Sopenharmony_ci    if (elf_compress (symscn, 0, 0) < 0)
1200da0c48c4Sopenharmony_ci      goto elferr;
1201da0c48c4Sopenharmony_ci
1202da0c48c4Sopenharmony_ci  mod->symdata = elf_getdata (symscn, NULL);
1203da0c48c4Sopenharmony_ci  if (mod->symdata == NULL || mod->symdata->d_buf == NULL)
1204da0c48c4Sopenharmony_ci    goto elferr;
1205da0c48c4Sopenharmony_ci
1206da0c48c4Sopenharmony_ci  // Sanity check number of symbols.
1207da0c48c4Sopenharmony_ci  shdr = gelf_getshdr (symscn, &shdr_mem);
1208da0c48c4Sopenharmony_ci  if (shdr == NULL || shdr->sh_entsize == 0
1209da0c48c4Sopenharmony_ci      || mod->syments > mod->symdata->d_size / shdr->sh_entsize
1210da0c48c4Sopenharmony_ci      || (size_t) mod->first_global > mod->syments)
1211da0c48c4Sopenharmony_ci    goto elferr;
1212da0c48c4Sopenharmony_ci
1213da0c48c4Sopenharmony_ci  /* Cache any auxiliary symbol info, when it fails, just ignore aux_sym.  */
1214da0c48c4Sopenharmony_ci  if (aux_symscn != NULL)
1215da0c48c4Sopenharmony_ci    {
1216da0c48c4Sopenharmony_ci  aux_cache:
1217da0c48c4Sopenharmony_ci      /* This does some sanity checks on the string table section.  */
1218da0c48c4Sopenharmony_ci      if (elf_strptr (mod->aux_sym.elf, aux_strshndx, 0) == NULL)
1219da0c48c4Sopenharmony_ci	{
1220da0c48c4Sopenharmony_ci	aux_cleanup:
1221da0c48c4Sopenharmony_ci	  mod->aux_syments = 0;
1222da0c48c4Sopenharmony_ci	  elf_end (mod->aux_sym.elf);
1223da0c48c4Sopenharmony_ci	  mod->aux_sym.elf = NULL;
1224da0c48c4Sopenharmony_ci	  /* We thought we had something through shdrs, but it failed...
1225da0c48c4Sopenharmony_ci	     Last ditch, look for dynamic symbols without section headers.  */
1226da0c48c4Sopenharmony_ci	  find_dynsym (mod);
1227da0c48c4Sopenharmony_ci	  return;
1228da0c48c4Sopenharmony_ci	}
1229da0c48c4Sopenharmony_ci
1230da0c48c4Sopenharmony_ci      Elf_Scn *aux_strscn = elf_getscn (mod->aux_sym.elf, aux_strshndx);
1231da0c48c4Sopenharmony_ci      if (aux_strscn == NULL)
1232da0c48c4Sopenharmony_ci	goto elferr;
1233da0c48c4Sopenharmony_ci
1234da0c48c4Sopenharmony_ci      shdr = gelf_getshdr (aux_strscn, &shdr_mem);
1235da0c48c4Sopenharmony_ci      if (shdr == NULL)
1236da0c48c4Sopenharmony_ci	goto elferr;
1237da0c48c4Sopenharmony_ci
1238da0c48c4Sopenharmony_ci      size_t aux_shstrndx;
1239da0c48c4Sopenharmony_ci      if (elf_getshdrstrndx (mod->aux_sym.elf, &aux_shstrndx) < 0)
1240da0c48c4Sopenharmony_ci	goto elferr;
1241da0c48c4Sopenharmony_ci
1242da0c48c4Sopenharmony_ci      sname = elf_strptr (mod->aux_sym.elf, aux_shstrndx,
1243da0c48c4Sopenharmony_ci				      shdr->sh_name);
1244da0c48c4Sopenharmony_ci      if (sname == NULL)
1245da0c48c4Sopenharmony_ci	goto elferr;
1246da0c48c4Sopenharmony_ci
1247da0c48c4Sopenharmony_ci      if (startswith (sname, ".zdebug"))
1248da0c48c4Sopenharmony_ci	/* Try to uncompress, but it might already have been, an error
1249da0c48c4Sopenharmony_ci	   might just indicate, already uncompressed.  */
1250da0c48c4Sopenharmony_ci	elf_compress_gnu (aux_strscn, 0, 0);
1251da0c48c4Sopenharmony_ci
1252da0c48c4Sopenharmony_ci      if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
1253da0c48c4Sopenharmony_ci	if (elf_compress (aux_strscn, 0, 0) < 0)
1254da0c48c4Sopenharmony_ci	  goto elferr;
1255da0c48c4Sopenharmony_ci
1256da0c48c4Sopenharmony_ci      mod->aux_symstrdata = elf_getdata (aux_strscn, NULL);
1257da0c48c4Sopenharmony_ci      if (mod->aux_symstrdata == NULL || mod->aux_symstrdata->d_buf == NULL)
1258da0c48c4Sopenharmony_ci	goto aux_cleanup;
1259da0c48c4Sopenharmony_ci
1260da0c48c4Sopenharmony_ci      if (aux_xndxscn == NULL)
1261da0c48c4Sopenharmony_ci	mod->aux_symxndxdata = NULL;
1262da0c48c4Sopenharmony_ci      else
1263da0c48c4Sopenharmony_ci	{
1264da0c48c4Sopenharmony_ci	  shdr = gelf_getshdr (aux_xndxscn, &shdr_mem);
1265da0c48c4Sopenharmony_ci	  if (shdr == NULL)
1266da0c48c4Sopenharmony_ci	    goto elferr;
1267da0c48c4Sopenharmony_ci
1268da0c48c4Sopenharmony_ci	  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
1269da0c48c4Sopenharmony_ci	    if (elf_compress (aux_xndxscn, 0, 0) < 0)
1270da0c48c4Sopenharmony_ci	      goto elferr;
1271da0c48c4Sopenharmony_ci
1272da0c48c4Sopenharmony_ci	  mod->aux_symxndxdata = elf_getdata (aux_xndxscn, NULL);
1273da0c48c4Sopenharmony_ci	  if (mod->aux_symxndxdata == NULL
1274da0c48c4Sopenharmony_ci	      || mod->aux_symxndxdata->d_buf == NULL)
1275da0c48c4Sopenharmony_ci	    goto aux_cleanup;
1276da0c48c4Sopenharmony_ci	}
1277da0c48c4Sopenharmony_ci
1278da0c48c4Sopenharmony_ci      shdr = gelf_getshdr (aux_symscn, &shdr_mem);
1279da0c48c4Sopenharmony_ci      if (shdr == NULL)
1280da0c48c4Sopenharmony_ci	goto elferr;
1281da0c48c4Sopenharmony_ci
1282da0c48c4Sopenharmony_ci      if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
1283da0c48c4Sopenharmony_ci	if (elf_compress (aux_symscn, 0, 0) < 0)
1284da0c48c4Sopenharmony_ci	  goto elferr;
1285da0c48c4Sopenharmony_ci
1286da0c48c4Sopenharmony_ci      mod->aux_symdata = elf_getdata (aux_symscn, NULL);
1287da0c48c4Sopenharmony_ci      if (mod->aux_symdata == NULL || mod->aux_symdata->d_buf == NULL)
1288da0c48c4Sopenharmony_ci	goto aux_cleanup;
1289da0c48c4Sopenharmony_ci
1290da0c48c4Sopenharmony_ci      // Sanity check number of aux symbols.
1291da0c48c4Sopenharmony_ci      shdr = gelf_getshdr (aux_symscn, &shdr_mem);
1292da0c48c4Sopenharmony_ci      if (mod->aux_syments > mod->aux_symdata->d_size / shdr->sh_entsize
1293da0c48c4Sopenharmony_ci	  || (size_t) mod->aux_first_global > mod->aux_syments)
1294da0c48c4Sopenharmony_ci	goto aux_cleanup;
1295da0c48c4Sopenharmony_ci    }
1296da0c48c4Sopenharmony_ci}
1297da0c48c4Sopenharmony_ci
1298da0c48c4Sopenharmony_ci
1299da0c48c4Sopenharmony_ci/* Try to open a libebl backend for MOD.  */
1300da0c48c4Sopenharmony_ciDwfl_Error
1301da0c48c4Sopenharmony_ciinternal_function
1302da0c48c4Sopenharmony_ci__libdwfl_module_getebl (Dwfl_Module *mod)
1303da0c48c4Sopenharmony_ci{
1304da0c48c4Sopenharmony_ci  if (mod->ebl == NULL)
1305da0c48c4Sopenharmony_ci    {
1306da0c48c4Sopenharmony_ci      __libdwfl_getelf (mod);
1307da0c48c4Sopenharmony_ci      if (mod->elferr != DWFL_E_NOERROR)
1308da0c48c4Sopenharmony_ci	return mod->elferr;
1309da0c48c4Sopenharmony_ci
1310da0c48c4Sopenharmony_ci      mod->ebl = ebl_openbackend (mod->main.elf);
1311da0c48c4Sopenharmony_ci      if (mod->ebl == NULL)
1312da0c48c4Sopenharmony_ci	return DWFL_E_LIBEBL;
1313da0c48c4Sopenharmony_ci    }
1314da0c48c4Sopenharmony_ci  return DWFL_E_NOERROR;
1315da0c48c4Sopenharmony_ci}
1316da0c48c4Sopenharmony_ci
1317da0c48c4Sopenharmony_ci/* Try to start up libdw on DEBUGFILE.  */
1318da0c48c4Sopenharmony_cistatic Dwfl_Error
1319da0c48c4Sopenharmony_ciload_dw (Dwfl_Module *mod, struct dwfl_file *debugfile)
1320da0c48c4Sopenharmony_ci{
1321da0c48c4Sopenharmony_ci  if (mod->e_type == ET_REL && !debugfile->relocated)
1322da0c48c4Sopenharmony_ci    {
1323da0c48c4Sopenharmony_ci      const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
1324da0c48c4Sopenharmony_ci
1325da0c48c4Sopenharmony_ci      /* The debugging sections have to be relocated.  */
1326da0c48c4Sopenharmony_ci      if (cb->section_address == NULL)
1327da0c48c4Sopenharmony_ci	return DWFL_E_NOREL;
1328da0c48c4Sopenharmony_ci
1329da0c48c4Sopenharmony_ci      Dwfl_Error error = __libdwfl_module_getebl (mod);
1330da0c48c4Sopenharmony_ci      if (error != DWFL_E_NOERROR)
1331da0c48c4Sopenharmony_ci	return error;
1332da0c48c4Sopenharmony_ci
1333da0c48c4Sopenharmony_ci      find_symtab (mod);
1334da0c48c4Sopenharmony_ci      Dwfl_Error result = mod->symerr;
1335da0c48c4Sopenharmony_ci      if (result == DWFL_E_NOERROR)
1336da0c48c4Sopenharmony_ci	result = __libdwfl_relocate (mod, debugfile->elf, true);
1337da0c48c4Sopenharmony_ci      if (result != DWFL_E_NOERROR)
1338da0c48c4Sopenharmony_ci	return result;
1339da0c48c4Sopenharmony_ci    }
1340da0c48c4Sopenharmony_ci
1341da0c48c4Sopenharmony_ci  mod->dw = INTUSE(dwarf_begin_elf) (debugfile->elf, DWARF_C_READ, NULL);
1342da0c48c4Sopenharmony_ci  if (mod->dw == NULL)
1343da0c48c4Sopenharmony_ci    {
1344da0c48c4Sopenharmony_ci      int err = INTUSE(dwarf_errno) ();
1345da0c48c4Sopenharmony_ci      return err == DWARF_E_NO_DWARF ? DWFL_E_NO_DWARF : DWFL_E (LIBDW, err);
1346da0c48c4Sopenharmony_ci    }
1347da0c48c4Sopenharmony_ci
1348da0c48c4Sopenharmony_ci  /* Do this after dwarf_begin_elf has a chance to process the fd.  */
1349da0c48c4Sopenharmony_ci  if (mod->e_type == ET_REL && !debugfile->relocated)
1350da0c48c4Sopenharmony_ci    {
1351da0c48c4Sopenharmony_ci      /* Don't keep the file descriptors around.  */
1352da0c48c4Sopenharmony_ci      if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0)
1353da0c48c4Sopenharmony_ci	{
1354da0c48c4Sopenharmony_ci	  close (mod->main.fd);
1355da0c48c4Sopenharmony_ci	  mod->main.fd = -1;
1356da0c48c4Sopenharmony_ci	}
1357da0c48c4Sopenharmony_ci      if (debugfile->fd != -1 && elf_cntl (debugfile->elf, ELF_C_FDREAD) == 0)
1358da0c48c4Sopenharmony_ci	{
1359da0c48c4Sopenharmony_ci	  close (debugfile->fd);
1360da0c48c4Sopenharmony_ci	  debugfile->fd = -1;
1361da0c48c4Sopenharmony_ci	}
1362da0c48c4Sopenharmony_ci    }
1363da0c48c4Sopenharmony_ci
1364da0c48c4Sopenharmony_ci  /* We might have already closed the fd when we asked dwarf_begin_elf to
1365da0c48c4Sopenharmony_ci     create an Dwarf.  Help out a little in case we need to find an alt or
1366da0c48c4Sopenharmony_ci     dwo file later.  */
1367da0c48c4Sopenharmony_ci  if (mod->dw->debugdir == NULL && mod->elfdir != NULL
1368da0c48c4Sopenharmony_ci      && debugfile == &mod->main)
1369da0c48c4Sopenharmony_ci    mod->dw->debugdir = strdup (mod->elfdir);
1370da0c48c4Sopenharmony_ci
1371da0c48c4Sopenharmony_ci  /* Until we have iterated through all CU's, we might do lazy lookups.  */
1372da0c48c4Sopenharmony_ci  mod->lazycu = 1;
1373da0c48c4Sopenharmony_ci
1374da0c48c4Sopenharmony_ci  return DWFL_E_NOERROR;
1375da0c48c4Sopenharmony_ci}
1376da0c48c4Sopenharmony_ci
1377da0c48c4Sopenharmony_ci/* Try to start up libdw on either the main file or the debuginfo file.  */
1378da0c48c4Sopenharmony_cistatic void
1379da0c48c4Sopenharmony_cifind_dw (Dwfl_Module *mod)
1380da0c48c4Sopenharmony_ci{
1381da0c48c4Sopenharmony_ci  if (mod->dw != NULL		/* Already done.  */
1382da0c48c4Sopenharmony_ci      || mod->dwerr != DWFL_E_NOERROR) /* Cached previous failure.  */
1383da0c48c4Sopenharmony_ci    return;
1384da0c48c4Sopenharmony_ci
1385da0c48c4Sopenharmony_ci  __libdwfl_getelf (mod);
1386da0c48c4Sopenharmony_ci  mod->dwerr = mod->elferr;
1387da0c48c4Sopenharmony_ci  if (mod->dwerr != DWFL_E_NOERROR)
1388da0c48c4Sopenharmony_ci    return;
1389da0c48c4Sopenharmony_ci
1390da0c48c4Sopenharmony_ci  /* First see if the main ELF file has the debugging information.  */
1391da0c48c4Sopenharmony_ci  mod->dwerr = load_dw (mod, &mod->main);
1392da0c48c4Sopenharmony_ci  switch (mod->dwerr)
1393da0c48c4Sopenharmony_ci    {
1394da0c48c4Sopenharmony_ci    case DWFL_E_NOERROR:
1395da0c48c4Sopenharmony_ci      mod->debug.elf = mod->main.elf;
1396da0c48c4Sopenharmony_ci      mod->debug.address_sync = mod->main.address_sync;
1397da0c48c4Sopenharmony_ci
1398da0c48c4Sopenharmony_ci      /* The Dwarf might need an alt debug file, find that now after
1399da0c48c4Sopenharmony_ci	 everything about the debug file has been setup (the
1400da0c48c4Sopenharmony_ci	 find_debuginfo callback might need it).  */
1401da0c48c4Sopenharmony_ci      find_debug_altlink (mod, mod->main.name);
1402da0c48c4Sopenharmony_ci      return;
1403da0c48c4Sopenharmony_ci
1404da0c48c4Sopenharmony_ci    case DWFL_E_NO_DWARF:
1405da0c48c4Sopenharmony_ci      break;
1406da0c48c4Sopenharmony_ci
1407da0c48c4Sopenharmony_ci    default:
1408da0c48c4Sopenharmony_ci      goto canonicalize;
1409da0c48c4Sopenharmony_ci    }
1410da0c48c4Sopenharmony_ci
1411da0c48c4Sopenharmony_ci  /* Now we have to look for a separate debuginfo file.  */
1412da0c48c4Sopenharmony_ci  mod->dwerr = find_debuginfo (mod);
1413da0c48c4Sopenharmony_ci  switch (mod->dwerr)
1414da0c48c4Sopenharmony_ci    {
1415da0c48c4Sopenharmony_ci    case DWFL_E_NOERROR:
1416da0c48c4Sopenharmony_ci      mod->dwerr = load_dw (mod, &mod->debug);
1417da0c48c4Sopenharmony_ci      if (mod->dwerr == DWFL_E_NOERROR)
1418da0c48c4Sopenharmony_ci	{
1419da0c48c4Sopenharmony_ci	  /* The Dwarf might need an alt debug file, find that now after
1420da0c48c4Sopenharmony_ci	     everything about the debug file has been setup (the
1421da0c48c4Sopenharmony_ci	     find_debuginfo callback might need it).  */
1422da0c48c4Sopenharmony_ci	  find_debug_altlink (mod, mod->debug.name);
1423da0c48c4Sopenharmony_ci	  return;
1424da0c48c4Sopenharmony_ci	}
1425da0c48c4Sopenharmony_ci
1426da0c48c4Sopenharmony_ci      break;
1427da0c48c4Sopenharmony_ci
1428da0c48c4Sopenharmony_ci    case DWFL_E_CB:		/* The find_debuginfo hook failed.  */
1429da0c48c4Sopenharmony_ci      mod->dwerr = DWFL_E_NO_DWARF;
1430da0c48c4Sopenharmony_ci      return;
1431da0c48c4Sopenharmony_ci
1432da0c48c4Sopenharmony_ci    default:
1433da0c48c4Sopenharmony_ci      break;
1434da0c48c4Sopenharmony_ci    }
1435da0c48c4Sopenharmony_ci
1436da0c48c4Sopenharmony_ci canonicalize:
1437da0c48c4Sopenharmony_ci  mod->dwerr = __libdwfl_canon_error (mod->dwerr);
1438da0c48c4Sopenharmony_ci}
1439da0c48c4Sopenharmony_ci
1440da0c48c4Sopenharmony_ciDwarf *
1441da0c48c4Sopenharmony_cidwfl_module_getdwarf (Dwfl_Module *mod, Dwarf_Addr *bias)
1442da0c48c4Sopenharmony_ci{
1443da0c48c4Sopenharmony_ci  if (mod == NULL)
1444da0c48c4Sopenharmony_ci    return NULL;
1445da0c48c4Sopenharmony_ci
1446da0c48c4Sopenharmony_ci  find_dw (mod);
1447da0c48c4Sopenharmony_ci  if (mod->dwerr == DWFL_E_NOERROR)
1448da0c48c4Sopenharmony_ci    {
1449da0c48c4Sopenharmony_ci      /* If dwfl_module_getelf was used previously, then partial apply
1450da0c48c4Sopenharmony_ci	 relocation to miscellaneous sections in the debug file too.  */
1451da0c48c4Sopenharmony_ci      if (mod->e_type == ET_REL
1452da0c48c4Sopenharmony_ci	  && mod->main.relocated && ! mod->debug.relocated)
1453da0c48c4Sopenharmony_ci	{
1454da0c48c4Sopenharmony_ci	  mod->debug.relocated = true;
1455da0c48c4Sopenharmony_ci	  if (mod->debug.elf != mod->main.elf)
1456da0c48c4Sopenharmony_ci	    (void) __libdwfl_relocate (mod, mod->debug.elf, false);
1457da0c48c4Sopenharmony_ci	}
1458da0c48c4Sopenharmony_ci
1459da0c48c4Sopenharmony_ci      *bias = dwfl_adjusted_dwarf_addr (mod, 0);
1460da0c48c4Sopenharmony_ci      return mod->dw;
1461da0c48c4Sopenharmony_ci    }
1462da0c48c4Sopenharmony_ci
1463da0c48c4Sopenharmony_ci  __libdwfl_seterrno (mod->dwerr);
1464da0c48c4Sopenharmony_ci  return NULL;
1465da0c48c4Sopenharmony_ci}
1466da0c48c4Sopenharmony_ciINTDEF (dwfl_module_getdwarf)
1467da0c48c4Sopenharmony_ci
1468da0c48c4Sopenharmony_ciint
1469da0c48c4Sopenharmony_cidwfl_module_getsymtab (Dwfl_Module *mod)
1470da0c48c4Sopenharmony_ci{
1471da0c48c4Sopenharmony_ci  if (mod == NULL)
1472da0c48c4Sopenharmony_ci    return -1;
1473da0c48c4Sopenharmony_ci
1474da0c48c4Sopenharmony_ci  find_symtab (mod);
1475da0c48c4Sopenharmony_ci  if (mod->symerr == DWFL_E_NOERROR)
1476da0c48c4Sopenharmony_ci    /* We will skip the auxiliary zero entry if there is another one.  */
1477da0c48c4Sopenharmony_ci    return (mod->syments + mod->aux_syments
1478da0c48c4Sopenharmony_ci	    - (mod->syments > 0 && mod->aux_syments > 0 ? 1 : 0));
1479da0c48c4Sopenharmony_ci
1480da0c48c4Sopenharmony_ci  __libdwfl_seterrno (mod->symerr);
1481da0c48c4Sopenharmony_ci  return -1;
1482da0c48c4Sopenharmony_ci}
1483da0c48c4Sopenharmony_ciINTDEF (dwfl_module_getsymtab)
1484da0c48c4Sopenharmony_ci
1485da0c48c4Sopenharmony_ciint
1486da0c48c4Sopenharmony_cidwfl_module_getsymtab_first_global (Dwfl_Module *mod)
1487da0c48c4Sopenharmony_ci{
1488da0c48c4Sopenharmony_ci  if (mod == NULL)
1489da0c48c4Sopenharmony_ci    return -1;
1490da0c48c4Sopenharmony_ci
1491da0c48c4Sopenharmony_ci  find_symtab (mod);
1492da0c48c4Sopenharmony_ci  if (mod->symerr == DWFL_E_NOERROR)
1493da0c48c4Sopenharmony_ci    {
1494da0c48c4Sopenharmony_ci      /* All local symbols should come before all global symbols.  If
1495da0c48c4Sopenharmony_ci	 we have an auxiliary table make sure all the main locals come
1496da0c48c4Sopenharmony_ci	 first, then all aux locals, then all main globals and finally all
1497da0c48c4Sopenharmony_ci	 aux globals.  And skip the auxiliary table zero undefined
1498da0c48c4Sopenharmony_ci	 entry.  */
1499da0c48c4Sopenharmony_ci      int skip_aux_zero = (mod->syments > 0 && mod->aux_syments > 0) ? 1 : 0;
1500da0c48c4Sopenharmony_ci      return mod->first_global + mod->aux_first_global - skip_aux_zero;
1501da0c48c4Sopenharmony_ci    }
1502da0c48c4Sopenharmony_ci
1503da0c48c4Sopenharmony_ci  __libdwfl_seterrno (mod->symerr);
1504da0c48c4Sopenharmony_ci  return -1;
1505da0c48c4Sopenharmony_ci}
1506da0c48c4Sopenharmony_ciINTDEF (dwfl_module_getsymtab_first_global)
1507