1da0c48c4Sopenharmony_ci/* Sniff out modules from ELF headers visible in memory segments.
2da0c48c4Sopenharmony_ci   Copyright (C) 2008-2012, 2014, 2015, 2018 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   Copyright (C) 2021 Mark J. Wielaard <mark@klomp.org>
4da0c48c4Sopenharmony_ci   This file is part of elfutils.
5da0c48c4Sopenharmony_ci
6da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
7da0c48c4Sopenharmony_ci   it under the terms of either
8da0c48c4Sopenharmony_ci
9da0c48c4Sopenharmony_ci     * the GNU Lesser General Public License as published by the Free
10da0c48c4Sopenharmony_ci       Software Foundation; either version 3 of the License, or (at
11da0c48c4Sopenharmony_ci       your option) any later version
12da0c48c4Sopenharmony_ci
13da0c48c4Sopenharmony_ci   or
14da0c48c4Sopenharmony_ci
15da0c48c4Sopenharmony_ci     * the GNU General Public License as published by the Free
16da0c48c4Sopenharmony_ci       Software Foundation; either version 2 of the License, or (at
17da0c48c4Sopenharmony_ci       your option) any later version
18da0c48c4Sopenharmony_ci
19da0c48c4Sopenharmony_ci   or both in parallel, as here.
20da0c48c4Sopenharmony_ci
21da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
22da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
23da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24da0c48c4Sopenharmony_ci   General Public License for more details.
25da0c48c4Sopenharmony_ci
26da0c48c4Sopenharmony_ci   You should have received copies of the GNU General Public License and
27da0c48c4Sopenharmony_ci   the GNU Lesser General Public License along with this program.  If
28da0c48c4Sopenharmony_ci   not, see <http://www.gnu.org/licenses/>.  */
29da0c48c4Sopenharmony_ci
30da0c48c4Sopenharmony_ci#include <config.h>
31da0c48c4Sopenharmony_ci#include "../libelf/libelfP.h"	/* For NOTE_ALIGN4 and NOTE_ALIGN8.  */
32da0c48c4Sopenharmony_ci#undef	_
33da0c48c4Sopenharmony_ci#include "libdwflP.h"
34da0c48c4Sopenharmony_ci#include "common.h"
35da0c48c4Sopenharmony_ci
36da0c48c4Sopenharmony_ci#include <elf.h>
37da0c48c4Sopenharmony_ci#include <gelf.h>
38da0c48c4Sopenharmony_ci#include <inttypes.h>
39da0c48c4Sopenharmony_ci#include <fcntl.h>
40da0c48c4Sopenharmony_ci
41da0c48c4Sopenharmony_ci#include <system.h>
42da0c48c4Sopenharmony_ci
43da0c48c4Sopenharmony_ci
44da0c48c4Sopenharmony_ci/* A good size for the initial read from memory, if it's not too costly.
45da0c48c4Sopenharmony_ci   This more than covers the phdrs and note segment in the average 64-bit
46da0c48c4Sopenharmony_ci   binary.  */
47da0c48c4Sopenharmony_ci
48da0c48c4Sopenharmony_ci#define INITIAL_READ	1024
49da0c48c4Sopenharmony_ci
50da0c48c4Sopenharmony_ci#if BYTE_ORDER == LITTLE_ENDIAN
51da0c48c4Sopenharmony_ci# define MY_ELFDATA	ELFDATA2LSB
52da0c48c4Sopenharmony_ci#else
53da0c48c4Sopenharmony_ci# define MY_ELFDATA	ELFDATA2MSB
54da0c48c4Sopenharmony_ci#endif
55da0c48c4Sopenharmony_ci
56da0c48c4Sopenharmony_cistruct elf_build_id
57da0c48c4Sopenharmony_ci{
58da0c48c4Sopenharmony_ci  void *memory;
59da0c48c4Sopenharmony_ci  size_t len;
60da0c48c4Sopenharmony_ci  GElf_Addr vaddr;
61da0c48c4Sopenharmony_ci};
62da0c48c4Sopenharmony_ci
63da0c48c4Sopenharmony_cistruct read_state
64da0c48c4Sopenharmony_ci{
65da0c48c4Sopenharmony_ci  Dwfl *dwfl;
66da0c48c4Sopenharmony_ci  Dwfl_Memory_Callback *memory_callback;
67da0c48c4Sopenharmony_ci  void *memory_callback_arg;
68da0c48c4Sopenharmony_ci  void **buffer;
69da0c48c4Sopenharmony_ci  size_t *buffer_available;
70da0c48c4Sopenharmony_ci};
71da0c48c4Sopenharmony_ci
72da0c48c4Sopenharmony_ci/* Return user segment index closest to ADDR but not above it.
73da0c48c4Sopenharmony_ci   If NEXT, return the closest to ADDR but not below it.  */
74da0c48c4Sopenharmony_cistatic int
75da0c48c4Sopenharmony_ciaddr_segndx (Dwfl *dwfl, size_t segment, GElf_Addr addr, bool next)
76da0c48c4Sopenharmony_ci{
77da0c48c4Sopenharmony_ci  int ndx = -1;
78da0c48c4Sopenharmony_ci  do
79da0c48c4Sopenharmony_ci    {
80da0c48c4Sopenharmony_ci      if (dwfl->lookup_segndx[segment] >= 0)
81da0c48c4Sopenharmony_ci	ndx = dwfl->lookup_segndx[segment];
82da0c48c4Sopenharmony_ci      if (++segment >= dwfl->lookup_elts - 1)
83da0c48c4Sopenharmony_ci	return next ? ndx + 1 : ndx;
84da0c48c4Sopenharmony_ci    }
85da0c48c4Sopenharmony_ci  while (dwfl->lookup_addr[segment] < addr);
86da0c48c4Sopenharmony_ci
87da0c48c4Sopenharmony_ci  if (next)
88da0c48c4Sopenharmony_ci    {
89da0c48c4Sopenharmony_ci      while (dwfl->lookup_segndx[segment] < 0)
90da0c48c4Sopenharmony_ci	if (++segment >= dwfl->lookup_elts - 1)
91da0c48c4Sopenharmony_ci	  return ndx + 1;
92da0c48c4Sopenharmony_ci      ndx = dwfl->lookup_segndx[segment];
93da0c48c4Sopenharmony_ci    }
94da0c48c4Sopenharmony_ci
95da0c48c4Sopenharmony_ci  return ndx;
96da0c48c4Sopenharmony_ci}
97da0c48c4Sopenharmony_ci
98da0c48c4Sopenharmony_ci/* Return whether there is SZ bytes available at PTR till END.  */
99da0c48c4Sopenharmony_ci
100da0c48c4Sopenharmony_cistatic bool
101da0c48c4Sopenharmony_cibuf_has_data (const void *ptr, const void *end, size_t sz)
102da0c48c4Sopenharmony_ci{
103da0c48c4Sopenharmony_ci  return ptr < end && (size_t) (end - ptr) >= sz;
104da0c48c4Sopenharmony_ci}
105da0c48c4Sopenharmony_ci
106da0c48c4Sopenharmony_ci/* Read SZ bytes into *RETP from *PTRP (limited by END) in format EI_DATA.
107da0c48c4Sopenharmony_ci   Function comes from src/readelf.c .  */
108da0c48c4Sopenharmony_ci
109da0c48c4Sopenharmony_cistatic bool
110da0c48c4Sopenharmony_cibuf_read_ulong (unsigned char ei_data, size_t sz,
111da0c48c4Sopenharmony_ci		const void **ptrp, const void *end, uint64_t *retp)
112da0c48c4Sopenharmony_ci{
113da0c48c4Sopenharmony_ci  if (! buf_has_data (*ptrp, end, sz))
114da0c48c4Sopenharmony_ci    return false;
115da0c48c4Sopenharmony_ci
116da0c48c4Sopenharmony_ci  union
117da0c48c4Sopenharmony_ci  {
118da0c48c4Sopenharmony_ci    uint64_t u64;
119da0c48c4Sopenharmony_ci    uint32_t u32;
120da0c48c4Sopenharmony_ci  } u;
121da0c48c4Sopenharmony_ci
122da0c48c4Sopenharmony_ci  memcpy (&u, *ptrp, sz);
123da0c48c4Sopenharmony_ci  (*ptrp) += sz;
124da0c48c4Sopenharmony_ci
125da0c48c4Sopenharmony_ci  if (retp == NULL)
126da0c48c4Sopenharmony_ci    return true;
127da0c48c4Sopenharmony_ci
128da0c48c4Sopenharmony_ci  if (MY_ELFDATA != ei_data)
129da0c48c4Sopenharmony_ci    {
130da0c48c4Sopenharmony_ci      if (sz == 4)
131da0c48c4Sopenharmony_ci	CONVERT (u.u32);
132da0c48c4Sopenharmony_ci      else
133da0c48c4Sopenharmony_ci	CONVERT (u.u64);
134da0c48c4Sopenharmony_ci    }
135da0c48c4Sopenharmony_ci  if (sz == 4)
136da0c48c4Sopenharmony_ci    *retp = u.u32;
137da0c48c4Sopenharmony_ci  else
138da0c48c4Sopenharmony_ci    *retp = u.u64;
139da0c48c4Sopenharmony_ci  return true;
140da0c48c4Sopenharmony_ci}
141da0c48c4Sopenharmony_ci
142da0c48c4Sopenharmony_ci/* Try to find matching entry for module from address MODULE_START to
143da0c48c4Sopenharmony_ci   MODULE_END in NT_FILE note located at NOTE_FILE of NOTE_FILE_SIZE
144da0c48c4Sopenharmony_ci   bytes in format EI_CLASS and EI_DATA.  */
145da0c48c4Sopenharmony_ci
146da0c48c4Sopenharmony_cistatic const char *
147da0c48c4Sopenharmony_cihandle_file_note (GElf_Addr module_start, GElf_Addr module_end,
148da0c48c4Sopenharmony_ci		  unsigned char ei_class, unsigned char ei_data,
149da0c48c4Sopenharmony_ci		  const void *note_file, size_t note_file_size)
150da0c48c4Sopenharmony_ci{
151da0c48c4Sopenharmony_ci  if (note_file == NULL)
152da0c48c4Sopenharmony_ci    return NULL;
153da0c48c4Sopenharmony_ci
154da0c48c4Sopenharmony_ci  size_t sz;
155da0c48c4Sopenharmony_ci  switch (ei_class)
156da0c48c4Sopenharmony_ci    {
157da0c48c4Sopenharmony_ci    case ELFCLASS32:
158da0c48c4Sopenharmony_ci      sz = 4;
159da0c48c4Sopenharmony_ci      break;
160da0c48c4Sopenharmony_ci    case ELFCLASS64:
161da0c48c4Sopenharmony_ci      sz = 8;
162da0c48c4Sopenharmony_ci      break;
163da0c48c4Sopenharmony_ci    default:
164da0c48c4Sopenharmony_ci      return NULL;
165da0c48c4Sopenharmony_ci    }
166da0c48c4Sopenharmony_ci
167da0c48c4Sopenharmony_ci  const void *ptr = note_file;
168da0c48c4Sopenharmony_ci  const void *end = note_file + note_file_size;
169da0c48c4Sopenharmony_ci  uint64_t count;
170da0c48c4Sopenharmony_ci  if (! buf_read_ulong (ei_data, sz, &ptr, end, &count))
171da0c48c4Sopenharmony_ci    return NULL;
172da0c48c4Sopenharmony_ci  if (! buf_read_ulong (ei_data, sz, &ptr, end, NULL)) // page_size
173da0c48c4Sopenharmony_ci    return NULL;
174da0c48c4Sopenharmony_ci
175da0c48c4Sopenharmony_ci  uint64_t maxcount = (size_t) (end - ptr) / (3 * sz);
176da0c48c4Sopenharmony_ci  if (count > maxcount)
177da0c48c4Sopenharmony_ci    return NULL;
178da0c48c4Sopenharmony_ci
179da0c48c4Sopenharmony_ci  /* Where file names are stored.  */
180da0c48c4Sopenharmony_ci  const char *fptr = ptr + 3 * count * sz;
181da0c48c4Sopenharmony_ci
182da0c48c4Sopenharmony_ci  ssize_t firstix = -1;
183da0c48c4Sopenharmony_ci  ssize_t lastix = -1;
184da0c48c4Sopenharmony_ci  for (size_t mix = 0; mix < count; mix++)
185da0c48c4Sopenharmony_ci    {
186da0c48c4Sopenharmony_ci      uint64_t mstart, mend, moffset;
187da0c48c4Sopenharmony_ci      if (! buf_read_ulong (ei_data, sz, &ptr, fptr, &mstart)
188da0c48c4Sopenharmony_ci	  || ! buf_read_ulong (ei_data, sz, &ptr, fptr, &mend)
189da0c48c4Sopenharmony_ci	  || ! buf_read_ulong (ei_data, sz, &ptr, fptr, &moffset))
190da0c48c4Sopenharmony_ci	return NULL;
191da0c48c4Sopenharmony_ci      if (mstart == module_start && moffset == 0)
192da0c48c4Sopenharmony_ci	firstix = lastix = mix;
193da0c48c4Sopenharmony_ci      if (firstix != -1 && mstart < module_end)
194da0c48c4Sopenharmony_ci	lastix = mix;
195da0c48c4Sopenharmony_ci      if (mend >= module_end)
196da0c48c4Sopenharmony_ci	break;
197da0c48c4Sopenharmony_ci    }
198da0c48c4Sopenharmony_ci  if (firstix == -1)
199da0c48c4Sopenharmony_ci    return NULL;
200da0c48c4Sopenharmony_ci
201da0c48c4Sopenharmony_ci  const char *retval = NULL;
202da0c48c4Sopenharmony_ci  for (ssize_t mix = 0; mix <= lastix; mix++)
203da0c48c4Sopenharmony_ci    {
204da0c48c4Sopenharmony_ci      const char *fnext = memchr (fptr, 0, (const char *) end - fptr);
205da0c48c4Sopenharmony_ci      if (fnext == NULL)
206da0c48c4Sopenharmony_ci	return NULL;
207da0c48c4Sopenharmony_ci      if (mix == firstix)
208da0c48c4Sopenharmony_ci	retval = fptr;
209da0c48c4Sopenharmony_ci      if (firstix < mix && mix <= lastix && strcmp (fptr, retval) != 0)
210da0c48c4Sopenharmony_ci	return NULL;
211da0c48c4Sopenharmony_ci      fptr = fnext + 1;
212da0c48c4Sopenharmony_ci    }
213da0c48c4Sopenharmony_ci  return retval;
214da0c48c4Sopenharmony_ci}
215da0c48c4Sopenharmony_ci
216da0c48c4Sopenharmony_ci/* Return true iff we are certain ELF cannot match BUILD_ID of
217da0c48c4Sopenharmony_ci   BUILD_ID_LEN bytes.  Pass DISK_FILE_HAS_BUILD_ID as false if it is
218da0c48c4Sopenharmony_ci   certain ELF does not contain build-id (it is only a performance hit
219da0c48c4Sopenharmony_ci   to pass it always as true).  */
220da0c48c4Sopenharmony_ci
221da0c48c4Sopenharmony_cistatic bool
222da0c48c4Sopenharmony_ciinvalid_elf (Elf *elf, bool disk_file_has_build_id,
223da0c48c4Sopenharmony_ci             struct elf_build_id *build_id)
224da0c48c4Sopenharmony_ci{
225da0c48c4Sopenharmony_ci  if (! disk_file_has_build_id && build_id->len > 0)
226da0c48c4Sopenharmony_ci    {
227da0c48c4Sopenharmony_ci      /* Module found in segments with build-id is more reliable
228da0c48c4Sopenharmony_ci	 than a module found via DT_DEBUG on disk without any
229da0c48c4Sopenharmony_ci	 build-id.   */
230da0c48c4Sopenharmony_ci      return true;
231da0c48c4Sopenharmony_ci    }
232da0c48c4Sopenharmony_ci  if (disk_file_has_build_id && build_id->len > 0)
233da0c48c4Sopenharmony_ci    {
234da0c48c4Sopenharmony_ci      const void *elf_build_id;
235da0c48c4Sopenharmony_ci      ssize_t elf_build_id_len;
236da0c48c4Sopenharmony_ci
237da0c48c4Sopenharmony_ci      /* If there is a build id in the elf file, check it.  */
238da0c48c4Sopenharmony_ci      elf_build_id_len = INTUSE(dwelf_elf_gnu_build_id) (elf, &elf_build_id);
239da0c48c4Sopenharmony_ci      if (elf_build_id_len > 0)
240da0c48c4Sopenharmony_ci	{
241da0c48c4Sopenharmony_ci	  if (build_id->len != (size_t) elf_build_id_len
242da0c48c4Sopenharmony_ci	      || memcmp (build_id->memory, elf_build_id, build_id->len) != 0)
243da0c48c4Sopenharmony_ci	    return true;
244da0c48c4Sopenharmony_ci	}
245da0c48c4Sopenharmony_ci    }
246da0c48c4Sopenharmony_ci  return false;
247da0c48c4Sopenharmony_ci}
248da0c48c4Sopenharmony_ci
249da0c48c4Sopenharmony_cistatic void
250da0c48c4Sopenharmony_cifinish_portion (struct read_state *read_state,
251da0c48c4Sopenharmony_ci		void **data, size_t *data_size)
252da0c48c4Sopenharmony_ci{
253da0c48c4Sopenharmony_ci  if (*data_size != 0 && *data != NULL)
254da0c48c4Sopenharmony_ci    (*read_state->memory_callback) (read_state->dwfl, -1, data, data_size,
255da0c48c4Sopenharmony_ci				    0, 0, read_state->memory_callback_arg);
256da0c48c4Sopenharmony_ci}
257da0c48c4Sopenharmony_ci
258da0c48c4Sopenharmony_cistatic inline bool
259da0c48c4Sopenharmony_ciread_portion (struct read_state *read_state,
260da0c48c4Sopenharmony_ci	      void **data, size_t *data_size,
261da0c48c4Sopenharmony_ci	      GElf_Addr start, size_t segment,
262da0c48c4Sopenharmony_ci	      GElf_Addr vaddr, size_t filesz)
263da0c48c4Sopenharmony_ci{
264da0c48c4Sopenharmony_ci  /* Check whether we will have to read the segment data, or if it
265da0c48c4Sopenharmony_ci     can be returned from the existing buffer.  */
266da0c48c4Sopenharmony_ci  if (filesz > *read_state->buffer_available
267da0c48c4Sopenharmony_ci      || vaddr - start > *read_state->buffer_available - filesz
268da0c48c4Sopenharmony_ci      /* If we're in string mode, then don't consider the buffer we have
269da0c48c4Sopenharmony_ci	 sufficient unless it contains the terminator of the string.  */
270da0c48c4Sopenharmony_ci      || (filesz == 0 && memchr (vaddr - start + *read_state->buffer, '\0',
271da0c48c4Sopenharmony_ci				 (*read_state->buffer_available
272da0c48c4Sopenharmony_ci				  - (vaddr - start))) == NULL))
273da0c48c4Sopenharmony_ci    {
274da0c48c4Sopenharmony_ci      *data = NULL;
275da0c48c4Sopenharmony_ci      *data_size = filesz;
276da0c48c4Sopenharmony_ci      return !(*read_state->memory_callback) (read_state->dwfl,
277da0c48c4Sopenharmony_ci					      addr_segndx (read_state->dwfl,
278da0c48c4Sopenharmony_ci							   segment, vaddr,
279da0c48c4Sopenharmony_ci							   false),
280da0c48c4Sopenharmony_ci					      data, data_size, vaddr, filesz,
281da0c48c4Sopenharmony_ci					      read_state->memory_callback_arg);
282da0c48c4Sopenharmony_ci    }
283da0c48c4Sopenharmony_ci
284da0c48c4Sopenharmony_ci  /* We already have this whole note segment from our initial read.  */
285da0c48c4Sopenharmony_ci  *data = vaddr - start + (*read_state->buffer);
286da0c48c4Sopenharmony_ci  *data_size = 0;
287da0c48c4Sopenharmony_ci  return false;
288da0c48c4Sopenharmony_ci}
289da0c48c4Sopenharmony_ci
290da0c48c4Sopenharmony_ciint
291da0c48c4Sopenharmony_cidwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
292da0c48c4Sopenharmony_ci			    Dwfl_Memory_Callback *memory_callback,
293da0c48c4Sopenharmony_ci			    void *memory_callback_arg,
294da0c48c4Sopenharmony_ci			    Dwfl_Module_Callback *read_eagerly,
295da0c48c4Sopenharmony_ci			    void *read_eagerly_arg,
296da0c48c4Sopenharmony_ci			    size_t maxread,
297da0c48c4Sopenharmony_ci			    const void *note_file, size_t note_file_size,
298da0c48c4Sopenharmony_ci			    const struct r_debug_info *r_debug_info)
299da0c48c4Sopenharmony_ci{
300da0c48c4Sopenharmony_ci  size_t segment = ndx;
301da0c48c4Sopenharmony_ci  struct read_state read_state;
302da0c48c4Sopenharmony_ci
303da0c48c4Sopenharmony_ci  if (segment >= dwfl->lookup_elts)
304da0c48c4Sopenharmony_ci    segment = dwfl->lookup_elts - 1;
305da0c48c4Sopenharmony_ci
306da0c48c4Sopenharmony_ci  while (segment > 0
307da0c48c4Sopenharmony_ci	 && (dwfl->lookup_segndx[segment] > ndx
308da0c48c4Sopenharmony_ci	     || dwfl->lookup_segndx[segment] == -1))
309da0c48c4Sopenharmony_ci    --segment;
310da0c48c4Sopenharmony_ci
311da0c48c4Sopenharmony_ci  while (dwfl->lookup_segndx[segment] < ndx)
312da0c48c4Sopenharmony_ci    if (++segment == dwfl->lookup_elts)
313da0c48c4Sopenharmony_ci      return 0;
314da0c48c4Sopenharmony_ci
315da0c48c4Sopenharmony_ci  GElf_Addr start = dwfl->lookup_addr[segment];
316da0c48c4Sopenharmony_ci
317da0c48c4Sopenharmony_ci  /* First read in the file header and check its sanity.  */
318da0c48c4Sopenharmony_ci
319da0c48c4Sopenharmony_ci  void *buffer = NULL;
320da0c48c4Sopenharmony_ci  size_t buffer_available = INITIAL_READ;
321da0c48c4Sopenharmony_ci  Elf *elf = NULL;
322da0c48c4Sopenharmony_ci  int fd = -1;
323da0c48c4Sopenharmony_ci
324da0c48c4Sopenharmony_ci  read_state.dwfl = dwfl;
325da0c48c4Sopenharmony_ci  read_state.memory_callback = memory_callback;
326da0c48c4Sopenharmony_ci  read_state.memory_callback_arg = memory_callback_arg;
327da0c48c4Sopenharmony_ci  read_state.buffer = &buffer;
328da0c48c4Sopenharmony_ci  read_state.buffer_available = &buffer_available;
329da0c48c4Sopenharmony_ci
330da0c48c4Sopenharmony_ci  /* We might have to reserve some memory for the phdrs.  Set to NULL
331da0c48c4Sopenharmony_ci     here so we can always safely free it.  */
332da0c48c4Sopenharmony_ci  void *phdrsp = NULL;
333da0c48c4Sopenharmony_ci
334da0c48c4Sopenharmony_ci  /* Collect the build ID bits here.  */
335da0c48c4Sopenharmony_ci  struct elf_build_id build_id;
336da0c48c4Sopenharmony_ci  build_id.memory = NULL;
337da0c48c4Sopenharmony_ci  build_id.len = 0;
338da0c48c4Sopenharmony_ci  build_id.vaddr = 0;
339da0c48c4Sopenharmony_ci
340da0c48c4Sopenharmony_ci  if (! (*memory_callback) (dwfl, ndx, &buffer, &buffer_available,
341da0c48c4Sopenharmony_ci			    start, sizeof (Elf64_Ehdr), memory_callback_arg)
342da0c48c4Sopenharmony_ci      || memcmp (buffer, ELFMAG, SELFMAG) != 0)
343da0c48c4Sopenharmony_ci    goto out;
344da0c48c4Sopenharmony_ci
345da0c48c4Sopenharmony_ci  /* Extract the information we need from the file header.  */
346da0c48c4Sopenharmony_ci  const unsigned char *e_ident;
347da0c48c4Sopenharmony_ci  unsigned char ei_class;
348da0c48c4Sopenharmony_ci  unsigned char ei_data;
349da0c48c4Sopenharmony_ci  uint16_t e_type;
350da0c48c4Sopenharmony_ci  union
351da0c48c4Sopenharmony_ci  {
352da0c48c4Sopenharmony_ci    Elf32_Ehdr e32;
353da0c48c4Sopenharmony_ci    Elf64_Ehdr e64;
354da0c48c4Sopenharmony_ci  } ehdr;
355da0c48c4Sopenharmony_ci  GElf_Off phoff;
356da0c48c4Sopenharmony_ci  uint_fast16_t phnum;
357da0c48c4Sopenharmony_ci  uint_fast16_t phentsize;
358da0c48c4Sopenharmony_ci  GElf_Off shdrs_end;
359da0c48c4Sopenharmony_ci  Elf_Data xlatefrom =
360da0c48c4Sopenharmony_ci    {
361da0c48c4Sopenharmony_ci      .d_type = ELF_T_EHDR,
362da0c48c4Sopenharmony_ci      .d_buf = (void *) buffer,
363da0c48c4Sopenharmony_ci      .d_version = EV_CURRENT,
364da0c48c4Sopenharmony_ci    };
365da0c48c4Sopenharmony_ci  Elf_Data xlateto =
366da0c48c4Sopenharmony_ci    {
367da0c48c4Sopenharmony_ci      .d_type = ELF_T_EHDR,
368da0c48c4Sopenharmony_ci      .d_buf = &ehdr,
369da0c48c4Sopenharmony_ci      .d_size = sizeof ehdr,
370da0c48c4Sopenharmony_ci      .d_version = EV_CURRENT,
371da0c48c4Sopenharmony_ci    };
372da0c48c4Sopenharmony_ci  e_ident = ((const unsigned char *) buffer);
373da0c48c4Sopenharmony_ci  ei_class = e_ident[EI_CLASS];
374da0c48c4Sopenharmony_ci  ei_data = e_ident[EI_DATA];
375da0c48c4Sopenharmony_ci  /* buffer may be unaligned, in which case xlatetom would not work.
376da0c48c4Sopenharmony_ci     xlatetom does work when the in and out d_buf are equal (but not
377da0c48c4Sopenharmony_ci     for any other overlap).  */
378da0c48c4Sopenharmony_ci  size_t ehdr_align = (ei_class == ELFCLASS32
379da0c48c4Sopenharmony_ci		       ? __alignof__ (Elf32_Ehdr)
380da0c48c4Sopenharmony_ci		       : __alignof__ (Elf64_Ehdr));
381da0c48c4Sopenharmony_ci  if (((uintptr_t) buffer & (ehdr_align - 1)) != 0)
382da0c48c4Sopenharmony_ci    {
383da0c48c4Sopenharmony_ci      memcpy (&ehdr, buffer,
384da0c48c4Sopenharmony_ci	      (ei_class == ELFCLASS32
385da0c48c4Sopenharmony_ci	       ? sizeof (Elf32_Ehdr)
386da0c48c4Sopenharmony_ci	       : sizeof (Elf64_Ehdr)));
387da0c48c4Sopenharmony_ci      xlatefrom.d_buf = &ehdr;
388da0c48c4Sopenharmony_ci    }
389da0c48c4Sopenharmony_ci  switch (ei_class)
390da0c48c4Sopenharmony_ci    {
391da0c48c4Sopenharmony_ci    case ELFCLASS32:
392da0c48c4Sopenharmony_ci      xlatefrom.d_size = sizeof (Elf32_Ehdr);
393da0c48c4Sopenharmony_ci      if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL)
394da0c48c4Sopenharmony_ci	goto out;
395da0c48c4Sopenharmony_ci      e_type = ehdr.e32.e_type;
396da0c48c4Sopenharmony_ci      phoff = ehdr.e32.e_phoff;
397da0c48c4Sopenharmony_ci      phnum = ehdr.e32.e_phnum;
398da0c48c4Sopenharmony_ci      phentsize = ehdr.e32.e_phentsize;
399da0c48c4Sopenharmony_ci      if (phentsize != sizeof (Elf32_Phdr))
400da0c48c4Sopenharmony_ci	goto out;
401da0c48c4Sopenharmony_ci      /* NOTE if the number of sections is > 0xff00 then e_shnum
402da0c48c4Sopenharmony_ci	 is zero and the actual number would come from the section
403da0c48c4Sopenharmony_ci	 zero sh_size field. We ignore this here because getting shdrs
404da0c48c4Sopenharmony_ci	 is just a nice bonus (see below in the type == PT_LOAD case
405da0c48c4Sopenharmony_ci	 where we trim the last segment).  */
406da0c48c4Sopenharmony_ci      shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * sizeof (Elf32_Shdr);
407da0c48c4Sopenharmony_ci      break;
408da0c48c4Sopenharmony_ci
409da0c48c4Sopenharmony_ci    case ELFCLASS64:
410da0c48c4Sopenharmony_ci      xlatefrom.d_size = sizeof (Elf64_Ehdr);
411da0c48c4Sopenharmony_ci      if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL)
412da0c48c4Sopenharmony_ci	goto out;
413da0c48c4Sopenharmony_ci      e_type = ehdr.e64.e_type;
414da0c48c4Sopenharmony_ci      phoff = ehdr.e64.e_phoff;
415da0c48c4Sopenharmony_ci      phnum = ehdr.e64.e_phnum;
416da0c48c4Sopenharmony_ci      phentsize = ehdr.e64.e_phentsize;
417da0c48c4Sopenharmony_ci      if (phentsize != sizeof (Elf64_Phdr))
418da0c48c4Sopenharmony_ci	goto out;
419da0c48c4Sopenharmony_ci      /* See the NOTE above for shdrs_end and ehdr.e32.e_shnum.  */
420da0c48c4Sopenharmony_ci      shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * sizeof (Elf64_Shdr);
421da0c48c4Sopenharmony_ci      break;
422da0c48c4Sopenharmony_ci
423da0c48c4Sopenharmony_ci    default:
424da0c48c4Sopenharmony_ci      goto out;
425da0c48c4Sopenharmony_ci    }
426da0c48c4Sopenharmony_ci
427da0c48c4Sopenharmony_ci  /* The file header tells where to find the program headers.
428da0c48c4Sopenharmony_ci     These are what we need to find the boundaries of the module.
429da0c48c4Sopenharmony_ci     Without them, we don't have a module to report.  */
430da0c48c4Sopenharmony_ci
431da0c48c4Sopenharmony_ci  if (phnum == 0)
432da0c48c4Sopenharmony_ci    goto out;
433da0c48c4Sopenharmony_ci
434da0c48c4Sopenharmony_ci  xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR;
435da0c48c4Sopenharmony_ci  xlatefrom.d_size = phnum * phentsize;
436da0c48c4Sopenharmony_ci
437da0c48c4Sopenharmony_ci  void *ph_buffer = NULL;
438da0c48c4Sopenharmony_ci  size_t ph_buffer_size = 0;
439da0c48c4Sopenharmony_ci  if (read_portion (&read_state, &ph_buffer, &ph_buffer_size,
440da0c48c4Sopenharmony_ci		    start, segment,
441da0c48c4Sopenharmony_ci		    start + phoff, xlatefrom.d_size))
442da0c48c4Sopenharmony_ci    goto out;
443da0c48c4Sopenharmony_ci
444da0c48c4Sopenharmony_ci  /* ph_buffer_size will be zero if we got everything from the initial
445da0c48c4Sopenharmony_ci     buffer, otherwise it will be the size of the new buffer that
446da0c48c4Sopenharmony_ci     could be read.  */
447da0c48c4Sopenharmony_ci  if (ph_buffer_size != 0)
448da0c48c4Sopenharmony_ci    {
449da0c48c4Sopenharmony_ci      phnum = ph_buffer_size / phentsize;
450da0c48c4Sopenharmony_ci      if (phnum == 0)
451da0c48c4Sopenharmony_ci	goto out;
452da0c48c4Sopenharmony_ci      xlatefrom.d_size = ph_buffer_size;
453da0c48c4Sopenharmony_ci    }
454da0c48c4Sopenharmony_ci
455da0c48c4Sopenharmony_ci  xlatefrom.d_buf = ph_buffer;
456da0c48c4Sopenharmony_ci
457da0c48c4Sopenharmony_ci  bool class32 = ei_class == ELFCLASS32;
458da0c48c4Sopenharmony_ci  size_t phdr_size = class32 ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr);
459da0c48c4Sopenharmony_ci  if (unlikely (phnum > SIZE_MAX / phdr_size))
460da0c48c4Sopenharmony_ci    goto out;
461da0c48c4Sopenharmony_ci  const size_t phdrsp_bytes = phnum * phdr_size;
462da0c48c4Sopenharmony_ci  phdrsp = malloc (phdrsp_bytes);
463da0c48c4Sopenharmony_ci  if (unlikely (phdrsp == NULL))
464da0c48c4Sopenharmony_ci    goto out;
465da0c48c4Sopenharmony_ci
466da0c48c4Sopenharmony_ci  xlateto.d_buf = phdrsp;
467da0c48c4Sopenharmony_ci  xlateto.d_size = phdrsp_bytes;
468da0c48c4Sopenharmony_ci
469da0c48c4Sopenharmony_ci  /* ph_ buffer may be unaligned, in which case xlatetom would not work.
470da0c48c4Sopenharmony_ci     xlatetom does work when the in and out d_buf are equal (but not
471da0c48c4Sopenharmony_ci     for any other overlap).  */
472da0c48c4Sopenharmony_ci  size_t phdr_align = (class32
473da0c48c4Sopenharmony_ci		       ? __alignof__ (Elf32_Phdr)
474da0c48c4Sopenharmony_ci		       : __alignof__ (Elf64_Phdr));
475da0c48c4Sopenharmony_ci  if (((uintptr_t) ph_buffer & (phdr_align - 1)) != 0)
476da0c48c4Sopenharmony_ci    {
477da0c48c4Sopenharmony_ci      memcpy (phdrsp, ph_buffer, phdrsp_bytes);
478da0c48c4Sopenharmony_ci      xlatefrom.d_buf = phdrsp;
479da0c48c4Sopenharmony_ci    }
480da0c48c4Sopenharmony_ci
481da0c48c4Sopenharmony_ci  /* Track the bounds of the file visible in memory.  */
482da0c48c4Sopenharmony_ci  GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end.  */
483da0c48c4Sopenharmony_ci  GElf_Off file_end = 0;	 /* Rounded up to effective page size.  */
484da0c48c4Sopenharmony_ci  GElf_Off contiguous = 0;	 /* Visible as contiguous file from START.  */
485da0c48c4Sopenharmony_ci  GElf_Off total_filesz = 0;	 /* Total size of data to read.  */
486da0c48c4Sopenharmony_ci
487da0c48c4Sopenharmony_ci  /* Collect the bias between START and the containing PT_LOAD's p_vaddr.  */
488da0c48c4Sopenharmony_ci  GElf_Addr bias = 0;
489da0c48c4Sopenharmony_ci  bool found_bias = false;
490da0c48c4Sopenharmony_ci
491da0c48c4Sopenharmony_ci  /* Collect the unbiased bounds of the module here.  */
492da0c48c4Sopenharmony_ci  GElf_Addr module_start = -1l;
493da0c48c4Sopenharmony_ci  GElf_Addr module_end = 0;
494da0c48c4Sopenharmony_ci  GElf_Addr module_address_sync = 0;
495da0c48c4Sopenharmony_ci
496da0c48c4Sopenharmony_ci  /* If we see PT_DYNAMIC, record it here.  */
497da0c48c4Sopenharmony_ci  GElf_Addr dyn_vaddr = 0;
498da0c48c4Sopenharmony_ci  GElf_Xword dyn_filesz = 0;
499da0c48c4Sopenharmony_ci
500da0c48c4Sopenharmony_ci  Elf32_Phdr *p32 = phdrsp;
501da0c48c4Sopenharmony_ci  Elf64_Phdr *p64 = phdrsp;
502da0c48c4Sopenharmony_ci  if ((ei_class == ELFCLASS32
503da0c48c4Sopenharmony_ci       && elf32_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL)
504da0c48c4Sopenharmony_ci      || (ei_class == ELFCLASS64
505da0c48c4Sopenharmony_ci          && elf64_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL))
506da0c48c4Sopenharmony_ci    {
507da0c48c4Sopenharmony_ci      found_bias = false; /* Trigger error check */
508da0c48c4Sopenharmony_ci    }
509da0c48c4Sopenharmony_ci  else
510da0c48c4Sopenharmony_ci    {
511da0c48c4Sopenharmony_ci      /* Consider each of the program headers we've read from the image.  */
512da0c48c4Sopenharmony_ci      for (uint_fast16_t i = 0; i < phnum; ++i)
513da0c48c4Sopenharmony_ci        {
514da0c48c4Sopenharmony_ci          bool is32 = (ei_class == ELFCLASS32);
515da0c48c4Sopenharmony_ci          GElf_Word type = is32 ? p32[i].p_type : p64[i].p_type;
516da0c48c4Sopenharmony_ci          GElf_Addr vaddr = is32 ? p32[i].p_vaddr : p64[i].p_vaddr;
517da0c48c4Sopenharmony_ci          GElf_Xword memsz = is32 ? p32[i].p_memsz : p64[i].p_memsz;
518da0c48c4Sopenharmony_ci          GElf_Off offset = is32 ? p32[i].p_offset : p64[i].p_offset;
519da0c48c4Sopenharmony_ci          GElf_Xword filesz = is32 ? p32[i].p_filesz : p64[i].p_filesz;
520da0c48c4Sopenharmony_ci          GElf_Xword align = is32 ? p32[i].p_align : p64[i].p_align;
521da0c48c4Sopenharmony_ci
522da0c48c4Sopenharmony_ci          if (type == PT_DYNAMIC)
523da0c48c4Sopenharmony_ci            {
524da0c48c4Sopenharmony_ci              dyn_vaddr = vaddr;
525da0c48c4Sopenharmony_ci              dyn_filesz = filesz;
526da0c48c4Sopenharmony_ci            }
527da0c48c4Sopenharmony_ci          else if (type == PT_NOTE)
528da0c48c4Sopenharmony_ci            {
529da0c48c4Sopenharmony_ci              /* If we have already seen a build ID, we don't care any more.  */
530da0c48c4Sopenharmony_ci              if (build_id.memory != NULL || filesz == 0)
531da0c48c4Sopenharmony_ci                continue; /* Next header */
532da0c48c4Sopenharmony_ci
533da0c48c4Sopenharmony_ci              /* We calculate from the p_offset of the note segment,
534da0c48c4Sopenharmony_ci               because we don't yet know the bias for its p_vaddr.  */
535da0c48c4Sopenharmony_ci              const GElf_Addr note_vaddr = start + offset;
536da0c48c4Sopenharmony_ci              void *data;
537da0c48c4Sopenharmony_ci              size_t data_size;
538da0c48c4Sopenharmony_ci              if (read_portion (&read_state, &data, &data_size,
539da0c48c4Sopenharmony_ci				start, segment, note_vaddr, filesz))
540da0c48c4Sopenharmony_ci                continue; /* Next header */
541da0c48c4Sopenharmony_ci
542da0c48c4Sopenharmony_ci              /* data_size will be zero if we got everything from the initial
543da0c48c4Sopenharmony_ci                 buffer, otherwise it will be the size of the new buffer that
544da0c48c4Sopenharmony_ci                 could be read.  */
545da0c48c4Sopenharmony_ci              if (data_size != 0)
546da0c48c4Sopenharmony_ci                filesz = data_size;
547da0c48c4Sopenharmony_ci
548da0c48c4Sopenharmony_ci	      if (filesz > SIZE_MAX / sizeof (Elf32_Nhdr))
549da0c48c4Sopenharmony_ci		continue;
550da0c48c4Sopenharmony_ci
551da0c48c4Sopenharmony_ci              assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr));
552da0c48c4Sopenharmony_ci
553da0c48c4Sopenharmony_ci              void *notes;
554da0c48c4Sopenharmony_ci              if (ei_data == MY_ELFDATA
555da0c48c4Sopenharmony_ci		  && (uintptr_t) data == (align == 8
556da0c48c4Sopenharmony_ci					  ? NOTE_ALIGN8 ((uintptr_t) data)
557da0c48c4Sopenharmony_ci					  : NOTE_ALIGN4 ((uintptr_t) data)))
558da0c48c4Sopenharmony_ci                notes = data;
559da0c48c4Sopenharmony_ci              else
560da0c48c4Sopenharmony_ci                {
561da0c48c4Sopenharmony_ci                  const unsigned int xencoding = ehdr.e32.e_ident[EI_DATA];
562da0c48c4Sopenharmony_ci
563da0c48c4Sopenharmony_ci		  if (filesz > SIZE_MAX / sizeof (Elf32_Nhdr))
564da0c48c4Sopenharmony_ci		    continue;
565da0c48c4Sopenharmony_ci                  notes = malloc (filesz);
566da0c48c4Sopenharmony_ci                  if (unlikely (notes == NULL))
567da0c48c4Sopenharmony_ci                    continue; /* Next header */
568da0c48c4Sopenharmony_ci                  xlatefrom.d_type = xlateto.d_type = (align == 8
569da0c48c4Sopenharmony_ci                                                       ? ELF_T_NHDR8
570da0c48c4Sopenharmony_ci						       : ELF_T_NHDR);
571da0c48c4Sopenharmony_ci                  xlatefrom.d_buf = (void *) data;
572da0c48c4Sopenharmony_ci                  xlatefrom.d_size = filesz;
573da0c48c4Sopenharmony_ci                  xlateto.d_buf = notes;
574da0c48c4Sopenharmony_ci                  xlateto.d_size = filesz;
575da0c48c4Sopenharmony_ci
576da0c48c4Sopenharmony_ci		  /* data may be unaligned, in which case xlatetom would not work.
577da0c48c4Sopenharmony_ci		     xlatetom does work when the in and out d_buf are equal (but not
578da0c48c4Sopenharmony_ci		     for any other overlap).  */
579da0c48c4Sopenharmony_ci		  if ((uintptr_t) data != (align == 8
580da0c48c4Sopenharmony_ci					   ? NOTE_ALIGN8 ((uintptr_t) data)
581da0c48c4Sopenharmony_ci					   : NOTE_ALIGN4 ((uintptr_t) data)))
582da0c48c4Sopenharmony_ci		    {
583da0c48c4Sopenharmony_ci		      memcpy (notes, data, filesz);
584da0c48c4Sopenharmony_ci		      xlatefrom.d_buf = notes;
585da0c48c4Sopenharmony_ci		    }
586da0c48c4Sopenharmony_ci
587da0c48c4Sopenharmony_ci                  if (elf32_xlatetom (&xlateto, &xlatefrom, xencoding) == NULL)
588da0c48c4Sopenharmony_ci                    {
589da0c48c4Sopenharmony_ci                      free (notes);
590da0c48c4Sopenharmony_ci                      finish_portion (&read_state, &data, &data_size);
591da0c48c4Sopenharmony_ci                      continue;
592da0c48c4Sopenharmony_ci                    }
593da0c48c4Sopenharmony_ci                }
594da0c48c4Sopenharmony_ci
595da0c48c4Sopenharmony_ci              const GElf_Nhdr *nh = notes;
596da0c48c4Sopenharmony_ci              size_t len = 0;
597da0c48c4Sopenharmony_ci              while (filesz - len > sizeof (*nh))
598da0c48c4Sopenharmony_ci                {
599da0c48c4Sopenharmony_ci		  len += sizeof (*nh);
600da0c48c4Sopenharmony_ci
601da0c48c4Sopenharmony_ci		  size_t namesz = nh->n_namesz;
602da0c48c4Sopenharmony_ci		  namesz = align == 8 ? NOTE_ALIGN8 (namesz) : NOTE_ALIGN4 (namesz);
603da0c48c4Sopenharmony_ci		  if (namesz > filesz - len || len + namesz < namesz)
604da0c48c4Sopenharmony_ci		    break;
605da0c48c4Sopenharmony_ci
606da0c48c4Sopenharmony_ci		  void *note_name = notes + len;
607da0c48c4Sopenharmony_ci		  len += namesz;
608da0c48c4Sopenharmony_ci
609da0c48c4Sopenharmony_ci		  size_t descsz = nh->n_descsz;
610da0c48c4Sopenharmony_ci		  descsz = align == 8 ? NOTE_ALIGN8 (descsz) : NOTE_ALIGN4 (descsz);
611da0c48c4Sopenharmony_ci		  if (descsz > filesz - len || len + descsz < descsz)
612da0c48c4Sopenharmony_ci		    break;
613da0c48c4Sopenharmony_ci
614da0c48c4Sopenharmony_ci		  void *note_desc = notes + len;
615da0c48c4Sopenharmony_ci		  len += descsz;
616da0c48c4Sopenharmony_ci
617da0c48c4Sopenharmony_ci		  /* We don't handle very short or really large build-ids.  We need at
618da0c48c4Sopenharmony_ci		     at least 3 and allow for up to 64 (normally ids are 20 long).  */
619da0c48c4Sopenharmony_ci#define MIN_BUILD_ID_BYTES 3
620da0c48c4Sopenharmony_ci#define MAX_BUILD_ID_BYTES 64
621da0c48c4Sopenharmony_ci		  if (nh->n_type == NT_GNU_BUILD_ID
622da0c48c4Sopenharmony_ci		      && nh->n_descsz >= MIN_BUILD_ID_BYTES
623da0c48c4Sopenharmony_ci		      && nh->n_descsz <= MAX_BUILD_ID_BYTES
624da0c48c4Sopenharmony_ci		      && nh->n_namesz == sizeof "GNU"
625da0c48c4Sopenharmony_ci		      && !memcmp (note_name, "GNU", sizeof "GNU"))
626da0c48c4Sopenharmony_ci		    {
627da0c48c4Sopenharmony_ci		      build_id.vaddr = (note_desc
628da0c48c4Sopenharmony_ci					- (const void *) notes
629da0c48c4Sopenharmony_ci					+ note_vaddr);
630da0c48c4Sopenharmony_ci		      build_id.len = nh->n_descsz;
631da0c48c4Sopenharmony_ci		      build_id.memory = malloc (build_id.len);
632da0c48c4Sopenharmony_ci		      if (likely (build_id.memory != NULL))
633da0c48c4Sopenharmony_ci			memcpy (build_id.memory, note_desc, build_id.len);
634da0c48c4Sopenharmony_ci		      break;
635da0c48c4Sopenharmony_ci		    }
636da0c48c4Sopenharmony_ci
637da0c48c4Sopenharmony_ci		  nh = (void *) notes + len;
638da0c48c4Sopenharmony_ci		}
639da0c48c4Sopenharmony_ci
640da0c48c4Sopenharmony_ci              if (notes != data)
641da0c48c4Sopenharmony_ci                free (notes);
642da0c48c4Sopenharmony_ci              finish_portion (&read_state, &data, &data_size);
643da0c48c4Sopenharmony_ci            }
644da0c48c4Sopenharmony_ci          else if (type == PT_LOAD)
645da0c48c4Sopenharmony_ci            {
646da0c48c4Sopenharmony_ci              align = (dwfl->segment_align > 1
647da0c48c4Sopenharmony_ci                       ? dwfl->segment_align : (align ?: 1));
648da0c48c4Sopenharmony_ci
649da0c48c4Sopenharmony_ci              GElf_Addr vaddr_end = (vaddr + memsz + align - 1) & -align;
650da0c48c4Sopenharmony_ci              GElf_Addr filesz_vaddr = (filesz < memsz
651da0c48c4Sopenharmony_ci                                        ? vaddr + filesz : vaddr_end);
652da0c48c4Sopenharmony_ci              GElf_Off filesz_offset = filesz_vaddr - vaddr + offset;
653da0c48c4Sopenharmony_ci
654da0c48c4Sopenharmony_ci              if (file_trimmed_end < offset + filesz)
655da0c48c4Sopenharmony_ci                {
656da0c48c4Sopenharmony_ci                  file_trimmed_end = offset + filesz;
657da0c48c4Sopenharmony_ci
658da0c48c4Sopenharmony_ci                  /* Trim the last segment so we don't bother with zeros
659da0c48c4Sopenharmony_ci                     in the last page that are off the end of the file.
660da0c48c4Sopenharmony_ci                     However, if the extra bit in that page includes the
661da0c48c4Sopenharmony_ci                     section headers, keep them.  */
662da0c48c4Sopenharmony_ci                  if (shdrs_end <= filesz_offset
663da0c48c4Sopenharmony_ci                      && shdrs_end > file_trimmed_end)
664da0c48c4Sopenharmony_ci                    {
665da0c48c4Sopenharmony_ci                      filesz += shdrs_end - file_trimmed_end;
666da0c48c4Sopenharmony_ci                      file_trimmed_end = shdrs_end;
667da0c48c4Sopenharmony_ci                    }
668da0c48c4Sopenharmony_ci                }
669da0c48c4Sopenharmony_ci
670da0c48c4Sopenharmony_ci              total_filesz += filesz;
671da0c48c4Sopenharmony_ci
672da0c48c4Sopenharmony_ci              if (file_end < filesz_offset)
673da0c48c4Sopenharmony_ci                {
674da0c48c4Sopenharmony_ci                  file_end = filesz_offset;
675da0c48c4Sopenharmony_ci                  if (filesz_vaddr - start == filesz_offset)
676da0c48c4Sopenharmony_ci                    contiguous = file_end;
677da0c48c4Sopenharmony_ci                }
678da0c48c4Sopenharmony_ci
679da0c48c4Sopenharmony_ci              if (!found_bias && (offset & -align) == 0
680da0c48c4Sopenharmony_ci                  && likely (filesz_offset >= phoff + phnum * phentsize))
681da0c48c4Sopenharmony_ci                {
682da0c48c4Sopenharmony_ci                  bias = start - vaddr;
683da0c48c4Sopenharmony_ci                  found_bias = true;
684da0c48c4Sopenharmony_ci                }
685da0c48c4Sopenharmony_ci
686da0c48c4Sopenharmony_ci              if ((vaddr & -align) < module_start)
687da0c48c4Sopenharmony_ci                {
688da0c48c4Sopenharmony_ci                  module_start = vaddr & -align;
689da0c48c4Sopenharmony_ci                  module_address_sync = vaddr + memsz;
690da0c48c4Sopenharmony_ci                }
691da0c48c4Sopenharmony_ci
692da0c48c4Sopenharmony_ci              if (module_end < vaddr_end)
693da0c48c4Sopenharmony_ci                module_end = vaddr_end;
694da0c48c4Sopenharmony_ci            }
695da0c48c4Sopenharmony_ci        }
696da0c48c4Sopenharmony_ci    }
697da0c48c4Sopenharmony_ci
698da0c48c4Sopenharmony_ci  finish_portion (&read_state, &ph_buffer, &ph_buffer_size);
699da0c48c4Sopenharmony_ci
700da0c48c4Sopenharmony_ci  /* We must have seen the segment covering offset 0, or else the ELF
701da0c48c4Sopenharmony_ci     header we read at START was not produced by these program headers.  */
702da0c48c4Sopenharmony_ci  if (unlikely (!found_bias))
703da0c48c4Sopenharmony_ci    goto out;
704da0c48c4Sopenharmony_ci
705da0c48c4Sopenharmony_ci  /* Now we know enough to report a module for sure: its bounds.  */
706da0c48c4Sopenharmony_ci  module_start += bias;
707da0c48c4Sopenharmony_ci  module_end += bias;
708da0c48c4Sopenharmony_ci
709da0c48c4Sopenharmony_ci  dyn_vaddr += bias;
710da0c48c4Sopenharmony_ci
711da0c48c4Sopenharmony_ci  /* NAME found from link map has precedence over DT_SONAME possibly read
712da0c48c4Sopenharmony_ci     below.  */
713da0c48c4Sopenharmony_ci  bool name_is_final = false;
714da0c48c4Sopenharmony_ci
715da0c48c4Sopenharmony_ci  /* Try to match up DYN_VADDR against L_LD as found in link map.
716da0c48c4Sopenharmony_ci     Segments sniffing may guess invalid address as the first read-only memory
717da0c48c4Sopenharmony_ci     mapping may not be dumped to the core file (if ELF headers are not dumped)
718da0c48c4Sopenharmony_ci     and the ELF header is dumped first with the read/write mapping of the same
719da0c48c4Sopenharmony_ci     file at higher addresses.  */
720da0c48c4Sopenharmony_ci  if (r_debug_info != NULL)
721da0c48c4Sopenharmony_ci    for (const struct r_debug_info_module *module = r_debug_info->module;
722da0c48c4Sopenharmony_ci	 module != NULL; module = module->next)
723da0c48c4Sopenharmony_ci      if (module_start <= module->l_ld && module->l_ld < module_end)
724da0c48c4Sopenharmony_ci	{
725da0c48c4Sopenharmony_ci	  /* L_LD read from link map must be right while DYN_VADDR is unsafe.
726da0c48c4Sopenharmony_ci	     Therefore subtract DYN_VADDR and add L_LD to get a possibly
727da0c48c4Sopenharmony_ci	     corrective displacement for all addresses computed so far.  */
728da0c48c4Sopenharmony_ci	  GElf_Addr fixup = module->l_ld - dyn_vaddr;
729da0c48c4Sopenharmony_ci	  if ((fixup & (dwfl->segment_align - 1)) == 0
730da0c48c4Sopenharmony_ci	      && module_start + fixup <= module->l_ld
731da0c48c4Sopenharmony_ci	      && module->l_ld < module_end + fixup)
732da0c48c4Sopenharmony_ci	    {
733da0c48c4Sopenharmony_ci	      module_start += fixup;
734da0c48c4Sopenharmony_ci	      module_end += fixup;
735da0c48c4Sopenharmony_ci	      dyn_vaddr += fixup;
736da0c48c4Sopenharmony_ci	      bias += fixup;
737da0c48c4Sopenharmony_ci	      if (module->name[0] != '\0')
738da0c48c4Sopenharmony_ci		{
739da0c48c4Sopenharmony_ci		  name = basename (module->name);
740da0c48c4Sopenharmony_ci		  name_is_final = true;
741da0c48c4Sopenharmony_ci		}
742da0c48c4Sopenharmony_ci	      break;
743da0c48c4Sopenharmony_ci	    }
744da0c48c4Sopenharmony_ci	}
745da0c48c4Sopenharmony_ci
746da0c48c4Sopenharmony_ci  if (r_debug_info != NULL)
747da0c48c4Sopenharmony_ci    {
748da0c48c4Sopenharmony_ci      bool skip_this_module = false;
749da0c48c4Sopenharmony_ci      for (struct r_debug_info_module *module = r_debug_info->module;
750da0c48c4Sopenharmony_ci	   module != NULL; module = module->next)
751da0c48c4Sopenharmony_ci	if ((module_end > module->start && module_start < module->end)
752da0c48c4Sopenharmony_ci	    || dyn_vaddr == module->l_ld)
753da0c48c4Sopenharmony_ci	  {
754da0c48c4Sopenharmony_ci	    if (module->elf != NULL
755da0c48c4Sopenharmony_ci	        && invalid_elf (module->elf, module->disk_file_has_build_id,
756da0c48c4Sopenharmony_ci				&build_id))
757da0c48c4Sopenharmony_ci	      {
758da0c48c4Sopenharmony_ci		elf_end (module->elf);
759da0c48c4Sopenharmony_ci		close (module->fd);
760da0c48c4Sopenharmony_ci		module->elf = NULL;
761da0c48c4Sopenharmony_ci		module->fd = -1;
762da0c48c4Sopenharmony_ci	      }
763da0c48c4Sopenharmony_ci	    if (module->elf != NULL)
764da0c48c4Sopenharmony_ci	      {
765da0c48c4Sopenharmony_ci		/* Ignore this found module if it would conflict in address
766da0c48c4Sopenharmony_ci		   space with any already existing module of DWFL.  */
767da0c48c4Sopenharmony_ci		skip_this_module = true;
768da0c48c4Sopenharmony_ci	      }
769da0c48c4Sopenharmony_ci	  }
770da0c48c4Sopenharmony_ci      if (skip_this_module)
771da0c48c4Sopenharmony_ci	goto out;
772da0c48c4Sopenharmony_ci    }
773da0c48c4Sopenharmony_ci
774da0c48c4Sopenharmony_ci  const char *file_note_name = handle_file_note (module_start, module_end,
775da0c48c4Sopenharmony_ci						 ei_class, ei_data,
776da0c48c4Sopenharmony_ci						 note_file, note_file_size);
777da0c48c4Sopenharmony_ci  if (file_note_name)
778da0c48c4Sopenharmony_ci    {
779da0c48c4Sopenharmony_ci      name = file_note_name;
780da0c48c4Sopenharmony_ci      name_is_final = true;
781da0c48c4Sopenharmony_ci      bool invalid = false;
782da0c48c4Sopenharmony_ci      fd = open (name, O_RDONLY);
783da0c48c4Sopenharmony_ci      if (fd >= 0)
784da0c48c4Sopenharmony_ci	{
785da0c48c4Sopenharmony_ci	  Dwfl_Error error = __libdw_open_file (&fd, &elf, true, false);
786da0c48c4Sopenharmony_ci	  if (error == DWFL_E_NOERROR)
787da0c48c4Sopenharmony_ci	    invalid = invalid_elf (elf, true /* disk_file_has_build_id */,
788da0c48c4Sopenharmony_ci                                   &build_id);
789da0c48c4Sopenharmony_ci	}
790da0c48c4Sopenharmony_ci      if (invalid)
791da0c48c4Sopenharmony_ci	{
792da0c48c4Sopenharmony_ci	  /* The file was there, but the build_id didn't match.  We
793da0c48c4Sopenharmony_ci	     still want to report the module, but need to get the ELF
794da0c48c4Sopenharmony_ci	     some other way if possible.  */
795da0c48c4Sopenharmony_ci	  close (fd);
796da0c48c4Sopenharmony_ci	  fd = -1;
797da0c48c4Sopenharmony_ci	  elf_end (elf);
798da0c48c4Sopenharmony_ci	  elf = NULL;
799da0c48c4Sopenharmony_ci	}
800da0c48c4Sopenharmony_ci    }
801da0c48c4Sopenharmony_ci
802da0c48c4Sopenharmony_ci  /* Our return value now says to skip the segments contained
803da0c48c4Sopenharmony_ci     within the module.  */
804da0c48c4Sopenharmony_ci  ndx = addr_segndx (dwfl, segment, module_end, true);
805da0c48c4Sopenharmony_ci
806da0c48c4Sopenharmony_ci  /* Examine its .dynamic section to get more interesting details.
807da0c48c4Sopenharmony_ci     If it has DT_SONAME, we'll use that as the module name.
808da0c48c4Sopenharmony_ci     If it has a DT_DEBUG, then it's actually a PIE rather than a DSO.
809da0c48c4Sopenharmony_ci     We need its DT_STRTAB and DT_STRSZ to decipher DT_SONAME,
810da0c48c4Sopenharmony_ci     and they also tell us the essential portion of the file
811da0c48c4Sopenharmony_ci     for fetching symbols.  */
812da0c48c4Sopenharmony_ci  GElf_Addr soname_stroff = 0;
813da0c48c4Sopenharmony_ci  GElf_Addr dynstr_vaddr = 0;
814da0c48c4Sopenharmony_ci  GElf_Xword dynstrsz = 0;
815da0c48c4Sopenharmony_ci  bool execlike = false;
816da0c48c4Sopenharmony_ci  const size_t dyn_entsize = (ei_class == ELFCLASS32
817da0c48c4Sopenharmony_ci			      ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn));
818da0c48c4Sopenharmony_ci  void *dyn_data = NULL;
819da0c48c4Sopenharmony_ci  size_t dyn_data_size = 0;
820da0c48c4Sopenharmony_ci  if (dyn_filesz != 0 && dyn_filesz % dyn_entsize == 0
821da0c48c4Sopenharmony_ci      && ! read_portion (&read_state, &dyn_data, &dyn_data_size,
822da0c48c4Sopenharmony_ci			 start, segment, dyn_vaddr, dyn_filesz))
823da0c48c4Sopenharmony_ci    {
824da0c48c4Sopenharmony_ci      /* dyn_data_size will be zero if we got everything from the initial
825da0c48c4Sopenharmony_ci         buffer, otherwise it will be the size of the new buffer that
826da0c48c4Sopenharmony_ci         could be read.  */
827da0c48c4Sopenharmony_ci      if (dyn_data_size != 0)
828da0c48c4Sopenharmony_ci	dyn_filesz = dyn_data_size;
829da0c48c4Sopenharmony_ci
830da0c48c4Sopenharmony_ci      if ((dyn_filesz / dyn_entsize) == 0
831da0c48c4Sopenharmony_ci	  || dyn_filesz > (SIZE_MAX / dyn_entsize))
832da0c48c4Sopenharmony_ci	goto out;
833da0c48c4Sopenharmony_ci      void *dyns = malloc (dyn_filesz);
834da0c48c4Sopenharmony_ci      Elf32_Dyn *d32 = dyns;
835da0c48c4Sopenharmony_ci      Elf64_Dyn *d64 = dyns;
836da0c48c4Sopenharmony_ci      if (unlikely (dyns == NULL))
837da0c48c4Sopenharmony_ci	goto out;
838da0c48c4Sopenharmony_ci
839da0c48c4Sopenharmony_ci      xlatefrom.d_type = xlateto.d_type = ELF_T_DYN;
840da0c48c4Sopenharmony_ci      xlatefrom.d_buf = (void *) dyn_data;
841da0c48c4Sopenharmony_ci      xlatefrom.d_size = dyn_filesz;
842da0c48c4Sopenharmony_ci      xlateto.d_buf = dyns;
843da0c48c4Sopenharmony_ci      xlateto.d_size = dyn_filesz;
844da0c48c4Sopenharmony_ci
845da0c48c4Sopenharmony_ci      /* dyn_data may be unaligned, in which case xlatetom would not work.
846da0c48c4Sopenharmony_ci	 xlatetom does work when the in and out d_buf are equal (but not
847da0c48c4Sopenharmony_ci	 for any other overlap).  */
848da0c48c4Sopenharmony_ci      bool is32 = (ei_class == ELFCLASS32);
849da0c48c4Sopenharmony_ci      size_t dyn_align = (is32
850da0c48c4Sopenharmony_ci			  ? __alignof__ (Elf32_Dyn)
851da0c48c4Sopenharmony_ci			  : __alignof__ (Elf64_Dyn));
852da0c48c4Sopenharmony_ci      if (((uintptr_t) dyn_data & (dyn_align - 1)) != 0)
853da0c48c4Sopenharmony_ci	{
854da0c48c4Sopenharmony_ci	  memcpy (dyns, dyn_data, dyn_filesz);
855da0c48c4Sopenharmony_ci	  xlatefrom.d_buf = dyns;
856da0c48c4Sopenharmony_ci	}
857da0c48c4Sopenharmony_ci
858da0c48c4Sopenharmony_ci      if ((is32 && elf32_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)
859da0c48c4Sopenharmony_ci          || (!is32 && elf64_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL))
860da0c48c4Sopenharmony_ci        {
861da0c48c4Sopenharmony_ci          size_t n = (is32
862da0c48c4Sopenharmony_ci		      ? (dyn_filesz / sizeof (Elf32_Dyn))
863da0c48c4Sopenharmony_ci		      : (dyn_filesz / sizeof (Elf64_Dyn)));
864da0c48c4Sopenharmony_ci          for (size_t i = 0; i < n; ++i)
865da0c48c4Sopenharmony_ci            {
866da0c48c4Sopenharmony_ci              GElf_Sxword tag = is32 ? d32[i].d_tag : d64[i].d_tag;
867da0c48c4Sopenharmony_ci              GElf_Xword val = is32 ? d32[i].d_un.d_val : d64[i].d_un.d_val;
868da0c48c4Sopenharmony_ci
869da0c48c4Sopenharmony_ci              if (tag == DT_DEBUG)
870da0c48c4Sopenharmony_ci                execlike = true;
871da0c48c4Sopenharmony_ci              else if (tag == DT_SONAME)
872da0c48c4Sopenharmony_ci                soname_stroff = val;
873da0c48c4Sopenharmony_ci              else if (tag == DT_STRTAB)
874da0c48c4Sopenharmony_ci                dynstr_vaddr = val;
875da0c48c4Sopenharmony_ci              else if (tag == DT_STRSZ)
876da0c48c4Sopenharmony_ci                dynstrsz = val;
877da0c48c4Sopenharmony_ci              else
878da0c48c4Sopenharmony_ci                continue;
879da0c48c4Sopenharmony_ci
880da0c48c4Sopenharmony_ci              if (soname_stroff != 0 && dynstr_vaddr != 0 && dynstrsz != 0)
881da0c48c4Sopenharmony_ci                break;
882da0c48c4Sopenharmony_ci            }
883da0c48c4Sopenharmony_ci        }
884da0c48c4Sopenharmony_ci      free (dyns);
885da0c48c4Sopenharmony_ci    }
886da0c48c4Sopenharmony_ci  finish_portion (&read_state, &dyn_data, &dyn_data_size);
887da0c48c4Sopenharmony_ci
888da0c48c4Sopenharmony_ci  /* We'll use the name passed in or a stupid default if not DT_SONAME.  */
889da0c48c4Sopenharmony_ci  if (name == NULL)
890da0c48c4Sopenharmony_ci    name = e_type == ET_EXEC ? "[exe]" : execlike ? "[pie]" : "[dso]";
891da0c48c4Sopenharmony_ci
892da0c48c4Sopenharmony_ci  void *soname = NULL;
893da0c48c4Sopenharmony_ci  size_t soname_size = 0;
894da0c48c4Sopenharmony_ci  if (! name_is_final && dynstrsz != 0 && dynstr_vaddr != 0)
895da0c48c4Sopenharmony_ci    {
896da0c48c4Sopenharmony_ci      /* We know the bounds of the .dynstr section.
897da0c48c4Sopenharmony_ci
898da0c48c4Sopenharmony_ci	 The DYNSTR_VADDR pointer comes from the .dynamic section
899da0c48c4Sopenharmony_ci	 (DT_STRTAB, detected above).  Ordinarily the dynamic linker
900da0c48c4Sopenharmony_ci	 will have adjusted this pointer in place so it's now an
901da0c48c4Sopenharmony_ci	 absolute address.  But sometimes .dynamic is read-only (in
902da0c48c4Sopenharmony_ci	 vDSOs and odd architectures), and sometimes the adjustment
903da0c48c4Sopenharmony_ci	 just hasn't happened yet in the memory image we looked at.
904da0c48c4Sopenharmony_ci	 So treat DYNSTR_VADDR as an absolute address if it falls
905da0c48c4Sopenharmony_ci	 within the module bounds, or try applying the phdr bias
906da0c48c4Sopenharmony_ci	 when that adjusts it to fall within the module bounds.  */
907da0c48c4Sopenharmony_ci
908da0c48c4Sopenharmony_ci      if ((dynstr_vaddr < module_start || dynstr_vaddr >= module_end)
909da0c48c4Sopenharmony_ci	  && dynstr_vaddr + bias >= module_start
910da0c48c4Sopenharmony_ci	  && dynstr_vaddr + bias < module_end)
911da0c48c4Sopenharmony_ci	dynstr_vaddr += bias;
912da0c48c4Sopenharmony_ci
913da0c48c4Sopenharmony_ci      if (unlikely (dynstr_vaddr + dynstrsz > module_end))
914da0c48c4Sopenharmony_ci	dynstrsz = 0;
915da0c48c4Sopenharmony_ci
916da0c48c4Sopenharmony_ci      /* Try to get the DT_SONAME string.  */
917da0c48c4Sopenharmony_ci      if (soname_stroff != 0 && soname_stroff + 1 < dynstrsz
918da0c48c4Sopenharmony_ci	  && ! read_portion (&read_state, &soname, &soname_size,
919da0c48c4Sopenharmony_ci			     start, segment,
920da0c48c4Sopenharmony_ci			     dynstr_vaddr + soname_stroff, 0))
921da0c48c4Sopenharmony_ci	name = soname;
922da0c48c4Sopenharmony_ci    }
923da0c48c4Sopenharmony_ci
924da0c48c4Sopenharmony_ci  /* Now that we have chosen the module's name and bounds, report it.
925da0c48c4Sopenharmony_ci     If we found a build ID, report that too.  */
926da0c48c4Sopenharmony_ci
927da0c48c4Sopenharmony_ci  Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, name,
928da0c48c4Sopenharmony_ci						 module_start, module_end);
929da0c48c4Sopenharmony_ci
930da0c48c4Sopenharmony_ci  // !execlike && ET_EXEC is PIE.
931da0c48c4Sopenharmony_ci  // execlike && !ET_EXEC is a static executable.
932da0c48c4Sopenharmony_ci  if (mod != NULL && (execlike || ehdr.e32.e_type == ET_EXEC))
933da0c48c4Sopenharmony_ci    mod->is_executable = true;
934da0c48c4Sopenharmony_ci
935da0c48c4Sopenharmony_ci  if (likely (mod != NULL) && build_id.memory != NULL
936da0c48c4Sopenharmony_ci      && unlikely (INTUSE(dwfl_module_report_build_id) (mod,
937da0c48c4Sopenharmony_ci							build_id.memory,
938da0c48c4Sopenharmony_ci							build_id.len,
939da0c48c4Sopenharmony_ci							build_id.vaddr)))
940da0c48c4Sopenharmony_ci    {
941da0c48c4Sopenharmony_ci      mod->gc = true;
942da0c48c4Sopenharmony_ci      mod = NULL;
943da0c48c4Sopenharmony_ci    }
944da0c48c4Sopenharmony_ci
945da0c48c4Sopenharmony_ci  /* At this point we do not need BUILD_ID or NAME any more.
946da0c48c4Sopenharmony_ci     They have been copied.  */
947da0c48c4Sopenharmony_ci  free (build_id.memory);
948da0c48c4Sopenharmony_ci  build_id.memory = NULL;
949da0c48c4Sopenharmony_ci  finish_portion (&read_state, &soname, &soname_size);
950da0c48c4Sopenharmony_ci
951da0c48c4Sopenharmony_ci  if (unlikely (mod == NULL))
952da0c48c4Sopenharmony_ci    {
953da0c48c4Sopenharmony_ci      ndx = -1;
954da0c48c4Sopenharmony_ci      goto out;
955da0c48c4Sopenharmony_ci    }
956da0c48c4Sopenharmony_ci
957da0c48c4Sopenharmony_ci  /* We have reported the module.  Now let the caller decide whether we
958da0c48c4Sopenharmony_ci     should read the whole thing in right now.  */
959da0c48c4Sopenharmony_ci
960da0c48c4Sopenharmony_ci  const GElf_Off cost = (contiguous < file_trimmed_end ? total_filesz
961da0c48c4Sopenharmony_ci			 : buffer_available >= contiguous ? 0
962da0c48c4Sopenharmony_ci			 : contiguous - buffer_available);
963da0c48c4Sopenharmony_ci  const GElf_Off worthwhile = ((dynstr_vaddr == 0 || dynstrsz == 0) ? 0
964da0c48c4Sopenharmony_ci			       : dynstr_vaddr + dynstrsz - start);
965da0c48c4Sopenharmony_ci  const GElf_Off whole = MAX (file_trimmed_end, shdrs_end);
966da0c48c4Sopenharmony_ci
967da0c48c4Sopenharmony_ci  if (elf == NULL
968da0c48c4Sopenharmony_ci      && (*read_eagerly) (MODCB_ARGS (mod), &buffer, &buffer_available,
969da0c48c4Sopenharmony_ci			  cost, worthwhile, whole, contiguous,
970da0c48c4Sopenharmony_ci			  read_eagerly_arg, &elf)
971da0c48c4Sopenharmony_ci      && elf == NULL)
972da0c48c4Sopenharmony_ci    {
973da0c48c4Sopenharmony_ci      /* The caller wants to read the whole file in right now, but hasn't
974da0c48c4Sopenharmony_ci	 done it for us.  Fill in a local image of the virtual file.  */
975da0c48c4Sopenharmony_ci
976da0c48c4Sopenharmony_ci      if (file_trimmed_end > maxread)
977da0c48c4Sopenharmony_ci	file_trimmed_end = maxread;
978da0c48c4Sopenharmony_ci
979da0c48c4Sopenharmony_ci      void *contents = calloc (1, file_trimmed_end);
980da0c48c4Sopenharmony_ci      if (unlikely (contents == NULL))
981da0c48c4Sopenharmony_ci	goto out;
982da0c48c4Sopenharmony_ci
983da0c48c4Sopenharmony_ci      if (contiguous < file_trimmed_end)
984da0c48c4Sopenharmony_ci	{
985da0c48c4Sopenharmony_ci	  /* We can't use the memory image verbatim as the file image.
986da0c48c4Sopenharmony_ci	     So we'll be reading into a local image of the virtual file.  */
987da0c48c4Sopenharmony_ci          for (uint_fast16_t i = 0; i < phnum; ++i)
988da0c48c4Sopenharmony_ci            {
989da0c48c4Sopenharmony_ci              bool is32 = (ei_class == ELFCLASS32);
990da0c48c4Sopenharmony_ci              GElf_Word type = is32 ? p32[i].p_type : p64[i].p_type;
991da0c48c4Sopenharmony_ci
992da0c48c4Sopenharmony_ci              if (type != PT_LOAD)
993da0c48c4Sopenharmony_ci                continue;
994da0c48c4Sopenharmony_ci
995da0c48c4Sopenharmony_ci              GElf_Addr vaddr = is32 ? p32[i].p_vaddr : p64[i].p_vaddr;
996da0c48c4Sopenharmony_ci              GElf_Off offset = is32 ? p32[i].p_offset : p64[i].p_offset;
997da0c48c4Sopenharmony_ci              GElf_Xword filesz = is32 ? p32[i].p_filesz : p64[i].p_filesz;
998da0c48c4Sopenharmony_ci
999da0c48c4Sopenharmony_ci              /* Don't try to read beyond the actual end of file.  */
1000da0c48c4Sopenharmony_ci              if (offset >= file_trimmed_end)
1001da0c48c4Sopenharmony_ci                continue;
1002da0c48c4Sopenharmony_ci
1003da0c48c4Sopenharmony_ci              void *into = contents + offset;
1004da0c48c4Sopenharmony_ci              size_t read_size = MIN (filesz, file_trimmed_end - offset);
1005da0c48c4Sopenharmony_ci              (*memory_callback) (dwfl, addr_segndx (dwfl, segment,
1006da0c48c4Sopenharmony_ci                                                     vaddr + bias, false),
1007da0c48c4Sopenharmony_ci                                  &into, &read_size, vaddr + bias, read_size,
1008da0c48c4Sopenharmony_ci                                  memory_callback_arg);
1009da0c48c4Sopenharmony_ci            }
1010da0c48c4Sopenharmony_ci	}
1011da0c48c4Sopenharmony_ci      else
1012da0c48c4Sopenharmony_ci	{
1013da0c48c4Sopenharmony_ci	  /* The whole file sits contiguous in memory,
1014da0c48c4Sopenharmony_ci	     but the caller didn't want to just do it.  */
1015da0c48c4Sopenharmony_ci
1016da0c48c4Sopenharmony_ci	  const size_t have = MIN (buffer_available, file_trimmed_end);
1017da0c48c4Sopenharmony_ci	  memcpy (contents, buffer, have);
1018da0c48c4Sopenharmony_ci
1019da0c48c4Sopenharmony_ci	  if (have < file_trimmed_end)
1020da0c48c4Sopenharmony_ci            {
1021da0c48c4Sopenharmony_ci	      void *into = contents + have;
1022da0c48c4Sopenharmony_ci	      size_t read_size = file_trimmed_end - have;
1023da0c48c4Sopenharmony_ci	      (*memory_callback) (dwfl,
1024da0c48c4Sopenharmony_ci				  addr_segndx (dwfl, segment,
1025da0c48c4Sopenharmony_ci					       start + have, false),
1026da0c48c4Sopenharmony_ci				  &into, &read_size, start + have,
1027da0c48c4Sopenharmony_ci				  read_size, memory_callback_arg);
1028da0c48c4Sopenharmony_ci            }
1029da0c48c4Sopenharmony_ci	}
1030da0c48c4Sopenharmony_ci
1031da0c48c4Sopenharmony_ci      elf = elf_memory (contents, file_trimmed_end);
1032da0c48c4Sopenharmony_ci      if (unlikely (elf == NULL))
1033da0c48c4Sopenharmony_ci	free (contents);
1034da0c48c4Sopenharmony_ci      else
1035da0c48c4Sopenharmony_ci	elf->flags |= ELF_F_MALLOCED;
1036da0c48c4Sopenharmony_ci    }
1037da0c48c4Sopenharmony_ci
1038da0c48c4Sopenharmony_ci  if (elf != NULL && mod->main.elf == NULL)
1039da0c48c4Sopenharmony_ci    {
1040da0c48c4Sopenharmony_ci      /* Install the file in the module.  */
1041da0c48c4Sopenharmony_ci      mod->main.elf = elf;
1042da0c48c4Sopenharmony_ci      mod->main.fd = fd;
1043da0c48c4Sopenharmony_ci      elf = NULL;
1044da0c48c4Sopenharmony_ci      fd = -1;
1045da0c48c4Sopenharmony_ci      mod->main.vaddr = module_start - bias;
1046da0c48c4Sopenharmony_ci      mod->main.address_sync = module_address_sync;
1047da0c48c4Sopenharmony_ci      mod->main_bias = bias;
1048da0c48c4Sopenharmony_ci    }
1049da0c48c4Sopenharmony_ci
1050da0c48c4Sopenharmony_ciout:
1051da0c48c4Sopenharmony_ci  if (build_id.memory != NULL)
1052da0c48c4Sopenharmony_ci    free (build_id.memory);
1053da0c48c4Sopenharmony_ci  free (phdrsp);
1054da0c48c4Sopenharmony_ci  if (buffer != NULL)
1055da0c48c4Sopenharmony_ci    (*memory_callback) (dwfl, -1, &buffer, &buffer_available, 0, 0,
1056da0c48c4Sopenharmony_ci                        memory_callback_arg);
1057da0c48c4Sopenharmony_ci
1058da0c48c4Sopenharmony_ci  if (elf != NULL)
1059da0c48c4Sopenharmony_ci    elf_end (elf);
1060da0c48c4Sopenharmony_ci  if (fd != -1)
1061da0c48c4Sopenharmony_ci    close (fd);
1062da0c48c4Sopenharmony_ci  return ndx;
1063da0c48c4Sopenharmony_ci}
1064