1da0c48c4Sopenharmony_ci/* Recover relocatibility for addresses computed from debug information.
2da0c48c4Sopenharmony_ci   Copyright (C) 2005-2009, 2012 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   Copyright (C) 2022 Mark J. Wielaard <mark@klomp.org>
4da0c48c4Sopenharmony_ci   Copyright (C) 2022 Google LLC
5da0c48c4Sopenharmony_ci   This file is part of elfutils.
6da0c48c4Sopenharmony_ci
7da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
8da0c48c4Sopenharmony_ci   it under the terms of either
9da0c48c4Sopenharmony_ci
10da0c48c4Sopenharmony_ci     * the GNU Lesser General Public License as published by the Free
11da0c48c4Sopenharmony_ci       Software Foundation; either version 3 of the License, or (at
12da0c48c4Sopenharmony_ci       your option) any later version
13da0c48c4Sopenharmony_ci
14da0c48c4Sopenharmony_ci   or
15da0c48c4Sopenharmony_ci
16da0c48c4Sopenharmony_ci     * the GNU General Public License as published by the Free
17da0c48c4Sopenharmony_ci       Software Foundation; either version 2 of the License, or (at
18da0c48c4Sopenharmony_ci       your option) any later version
19da0c48c4Sopenharmony_ci
20da0c48c4Sopenharmony_ci   or both in parallel, as here.
21da0c48c4Sopenharmony_ci
22da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
23da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
24da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25da0c48c4Sopenharmony_ci   General Public License for more details.
26da0c48c4Sopenharmony_ci
27da0c48c4Sopenharmony_ci   You should have received copies of the GNU General Public License and
28da0c48c4Sopenharmony_ci   the GNU Lesser General Public License along with this program.  If
29da0c48c4Sopenharmony_ci   not, see <http://www.gnu.org/licenses/>.  */
30da0c48c4Sopenharmony_ci
31da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H
32da0c48c4Sopenharmony_ci# include <config.h>
33da0c48c4Sopenharmony_ci#endif
34da0c48c4Sopenharmony_ci
35da0c48c4Sopenharmony_ci#include "libdwflP.h"
36da0c48c4Sopenharmony_ci#include <fcntl.h>
37da0c48c4Sopenharmony_ci
38da0c48c4Sopenharmony_ci/* Since dwfl_report_elf lays out the sections already, this will only be
39da0c48c4Sopenharmony_ci   called when the section headers of the debuginfo file are being
40da0c48c4Sopenharmony_ci   consulted instead, or for the section placed at 0.  With binutils
41da0c48c4Sopenharmony_ci   strip-to-debug, the symbol table is in the debuginfo file and relocation
42da0c48c4Sopenharmony_ci   looks there.  */
43da0c48c4Sopenharmony_ciint
44da0c48c4Sopenharmony_cidwfl_offline_section_address (Dwfl_Module *mod,
45da0c48c4Sopenharmony_ci			      void **userdata __attribute__ ((unused)),
46da0c48c4Sopenharmony_ci			      const char *modname __attribute__ ((unused)),
47da0c48c4Sopenharmony_ci			      Dwarf_Addr base __attribute__ ((unused)),
48da0c48c4Sopenharmony_ci			      const char *secname __attribute__ ((unused)),
49da0c48c4Sopenharmony_ci			      Elf32_Word shndx,
50da0c48c4Sopenharmony_ci			      const GElf_Shdr *shdr __attribute__ ((unused)),
51da0c48c4Sopenharmony_ci			      Dwarf_Addr *addr)
52da0c48c4Sopenharmony_ci{
53da0c48c4Sopenharmony_ci  assert (mod->e_type == ET_REL);
54da0c48c4Sopenharmony_ci  assert (shdr->sh_addr == 0);
55da0c48c4Sopenharmony_ci  assert (shdr->sh_flags & SHF_ALLOC);
56da0c48c4Sopenharmony_ci  assert (shndx != 0);
57da0c48c4Sopenharmony_ci
58da0c48c4Sopenharmony_ci  if (mod->debug.elf == NULL)
59da0c48c4Sopenharmony_ci    /* We are only here because sh_addr is zero even though layout is complete.
60da0c48c4Sopenharmony_ci       The first section in the first file under -e is placed at 0.  */
61da0c48c4Sopenharmony_ci    return 0;
62da0c48c4Sopenharmony_ci
63da0c48c4Sopenharmony_ci  /* The section numbers might not match between the two files.
64da0c48c4Sopenharmony_ci     The best we can rely on is the order of SHF_ALLOC sections.  */
65da0c48c4Sopenharmony_ci
66da0c48c4Sopenharmony_ci  Elf_Scn *ourscn = elf_getscn (mod->debug.elf, shndx);
67da0c48c4Sopenharmony_ci  Elf_Scn *scn = NULL;
68da0c48c4Sopenharmony_ci  uint_fast32_t skip_alloc = 0;
69da0c48c4Sopenharmony_ci  while ((scn = elf_nextscn (mod->debug.elf, scn)) != ourscn)
70da0c48c4Sopenharmony_ci    {
71da0c48c4Sopenharmony_ci      assert (scn != NULL);
72da0c48c4Sopenharmony_ci      GElf_Shdr shdr_mem;
73da0c48c4Sopenharmony_ci      GElf_Shdr *sh = gelf_getshdr (scn, &shdr_mem);
74da0c48c4Sopenharmony_ci      if (unlikely (sh == NULL))
75da0c48c4Sopenharmony_ci	return -1;
76da0c48c4Sopenharmony_ci      if (sh->sh_flags & SHF_ALLOC)
77da0c48c4Sopenharmony_ci	++skip_alloc;
78da0c48c4Sopenharmony_ci    }
79da0c48c4Sopenharmony_ci
80da0c48c4Sopenharmony_ci  scn = NULL;
81da0c48c4Sopenharmony_ci  while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
82da0c48c4Sopenharmony_ci    {
83da0c48c4Sopenharmony_ci      GElf_Shdr shdr_mem;
84da0c48c4Sopenharmony_ci      GElf_Shdr *main_shdr = gelf_getshdr (scn, &shdr_mem);
85da0c48c4Sopenharmony_ci      if (unlikely (main_shdr == NULL))
86da0c48c4Sopenharmony_ci	return -1;
87da0c48c4Sopenharmony_ci      if ((main_shdr->sh_flags & SHF_ALLOC) && skip_alloc-- == 0)
88da0c48c4Sopenharmony_ci	{
89da0c48c4Sopenharmony_ci	  assert (main_shdr->sh_flags == shdr->sh_flags);
90da0c48c4Sopenharmony_ci	  *addr = main_shdr->sh_addr;
91da0c48c4Sopenharmony_ci	  return 0;
92da0c48c4Sopenharmony_ci	}
93da0c48c4Sopenharmony_ci    }
94da0c48c4Sopenharmony_ci
95da0c48c4Sopenharmony_ci  /* This should never happen.  */
96da0c48c4Sopenharmony_ci  return -1;
97da0c48c4Sopenharmony_ci}
98da0c48c4Sopenharmony_ciINTDEF (dwfl_offline_section_address)
99da0c48c4Sopenharmony_ci
100da0c48c4Sopenharmony_ci/* Forward declarations.  */
101da0c48c4Sopenharmony_cistatic Dwfl_Module *process_elf (Dwfl *dwfl, const char *name,
102da0c48c4Sopenharmony_ci				 const char *file_name, int fd, Elf *elf);
103da0c48c4Sopenharmony_cistatic Dwfl_Module *process_archive (Dwfl *dwfl, const char *name,
104da0c48c4Sopenharmony_ci				     const char *file_name, int fd, Elf *elf,
105da0c48c4Sopenharmony_ci				     int (*predicate) (const char *module,
106da0c48c4Sopenharmony_ci						       const char *file));
107da0c48c4Sopenharmony_ci
108da0c48c4Sopenharmony_ci/* Report one module for an ELF file, or many for an archive.
109da0c48c4Sopenharmony_ci   Always consumes ELF and FD.  */
110da0c48c4Sopenharmony_cistatic Dwfl_Module *
111da0c48c4Sopenharmony_ciprocess_file (Dwfl *dwfl, const char *name, const char *file_name, int fd,
112da0c48c4Sopenharmony_ci	      Elf *elf, int (*predicate) (const char *module,
113da0c48c4Sopenharmony_ci					  const char *file))
114da0c48c4Sopenharmony_ci{
115da0c48c4Sopenharmony_ci  switch (elf_kind (elf))
116da0c48c4Sopenharmony_ci    {
117da0c48c4Sopenharmony_ci    default:
118da0c48c4Sopenharmony_ci    case ELF_K_NONE:
119da0c48c4Sopenharmony_ci      __libdwfl_seterrno (elf == NULL ? DWFL_E_LIBELF : DWFL_E_BADELF);
120da0c48c4Sopenharmony_ci      return NULL;
121da0c48c4Sopenharmony_ci
122da0c48c4Sopenharmony_ci    case ELF_K_ELF:
123da0c48c4Sopenharmony_ci      return process_elf (dwfl, name, file_name, fd, elf);
124da0c48c4Sopenharmony_ci
125da0c48c4Sopenharmony_ci    case ELF_K_AR:
126da0c48c4Sopenharmony_ci      return process_archive (dwfl, name, file_name, fd, elf, predicate);
127da0c48c4Sopenharmony_ci    }
128da0c48c4Sopenharmony_ci}
129da0c48c4Sopenharmony_ci
130da0c48c4Sopenharmony_ci/* Report the open ELF file as a module.  Always consumes ELF and FD.  */
131da0c48c4Sopenharmony_cistatic Dwfl_Module *
132da0c48c4Sopenharmony_ciprocess_elf (Dwfl *dwfl, const char *name, const char *file_name, int fd,
133da0c48c4Sopenharmony_ci	     Elf *elf)
134da0c48c4Sopenharmony_ci{
135da0c48c4Sopenharmony_ci  Dwfl_Module *mod = __libdwfl_report_elf (dwfl, name, file_name, fd, elf,
136da0c48c4Sopenharmony_ci					   dwfl->offline_next_address, true,
137da0c48c4Sopenharmony_ci					   false);
138da0c48c4Sopenharmony_ci  if (mod != NULL)
139da0c48c4Sopenharmony_ci    {
140da0c48c4Sopenharmony_ci      /* If this is an ET_EXEC file with fixed addresses, the address range
141da0c48c4Sopenharmony_ci	 it consumed may or may not intersect with the arbitrary range we
142da0c48c4Sopenharmony_ci	 will use for relocatable modules.  Make sure we always use a free
143da0c48c4Sopenharmony_ci	 range for the offline allocations.  If this module did use
144da0c48c4Sopenharmony_ci	 offline_next_address, it may have rounded it up for the module's
145da0c48c4Sopenharmony_ci	 alignment requirements.  */
146da0c48c4Sopenharmony_ci      if ((dwfl->offline_next_address >= mod->low_addr
147da0c48c4Sopenharmony_ci	   || mod->low_addr - dwfl->offline_next_address < OFFLINE_REDZONE)
148da0c48c4Sopenharmony_ci	  && dwfl->offline_next_address < mod->high_addr + OFFLINE_REDZONE)
149da0c48c4Sopenharmony_ci	dwfl->offline_next_address = mod->high_addr + OFFLINE_REDZONE;
150da0c48c4Sopenharmony_ci
151da0c48c4Sopenharmony_ci      /* Don't keep the file descriptor around.  */
152da0c48c4Sopenharmony_ci      if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0)
153da0c48c4Sopenharmony_ci	{
154da0c48c4Sopenharmony_ci	  /* Grab the dir path in case we want to report this file as
155da0c48c4Sopenharmony_ci	     Dwarf later.  */
156da0c48c4Sopenharmony_ci	  mod->elfdir = __libdw_debugdir (mod->main.fd);
157da0c48c4Sopenharmony_ci	  close (mod->main.fd);
158da0c48c4Sopenharmony_ci	  mod->main.fd = -1;
159da0c48c4Sopenharmony_ci	}
160da0c48c4Sopenharmony_ci    }
161da0c48c4Sopenharmony_ci
162da0c48c4Sopenharmony_ci  return mod;
163da0c48c4Sopenharmony_ci}
164da0c48c4Sopenharmony_ci
165da0c48c4Sopenharmony_ci/* Always consumes MEMBER.  Returns elf_next result on success.
166da0c48c4Sopenharmony_ci   For errors returns ELF_C_NULL with *MOD set to null.  */
167da0c48c4Sopenharmony_cistatic Elf_Cmd
168da0c48c4Sopenharmony_ciprocess_archive_member (Dwfl *dwfl, const char *name, const char *file_name,
169da0c48c4Sopenharmony_ci			int (*predicate) (const char *module, const char *file),
170da0c48c4Sopenharmony_ci			int fd, Elf *member, Dwfl_Module **mod)
171da0c48c4Sopenharmony_ci{
172da0c48c4Sopenharmony_ci  const Elf_Arhdr *h = elf_getarhdr (member);
173da0c48c4Sopenharmony_ci  if (unlikely (h == NULL))
174da0c48c4Sopenharmony_ci    {
175da0c48c4Sopenharmony_ci      __libdwfl_seterrno (DWFL_E_LIBELF);
176da0c48c4Sopenharmony_ci    fail:
177da0c48c4Sopenharmony_ci      elf_end (member);
178da0c48c4Sopenharmony_ci      *mod = NULL;
179da0c48c4Sopenharmony_ci      return ELF_C_NULL;
180da0c48c4Sopenharmony_ci    }
181da0c48c4Sopenharmony_ci
182da0c48c4Sopenharmony_ci  if (!strcmp (h->ar_name, "/") || !strcmp (h->ar_name, "//")
183da0c48c4Sopenharmony_ci      || !strcmp (h->ar_name, "/SYM64/"))
184da0c48c4Sopenharmony_ci    {
185da0c48c4Sopenharmony_ci    skip:;
186da0c48c4Sopenharmony_ci      /* Skip this and go to the next.  */
187da0c48c4Sopenharmony_ci      Elf_Cmd result = elf_next (member);
188da0c48c4Sopenharmony_ci      elf_end (member);
189da0c48c4Sopenharmony_ci      return result;
190da0c48c4Sopenharmony_ci    }
191da0c48c4Sopenharmony_ci
192da0c48c4Sopenharmony_ci  char *member_name;
193da0c48c4Sopenharmony_ci  if (unlikely (asprintf (&member_name, "%s(%s)", file_name, h->ar_name) < 0))
194da0c48c4Sopenharmony_ci    {
195da0c48c4Sopenharmony_ci    nomem:
196da0c48c4Sopenharmony_ci      __libdwfl_seterrno (DWFL_E_NOMEM);
197da0c48c4Sopenharmony_ci      elf_end (member);
198da0c48c4Sopenharmony_ci      *mod = NULL;
199da0c48c4Sopenharmony_ci      return ELF_C_NULL;
200da0c48c4Sopenharmony_ci    }
201da0c48c4Sopenharmony_ci
202da0c48c4Sopenharmony_ci  char *module_name = NULL;
203da0c48c4Sopenharmony_ci  if (name == NULL || name[0] == '\0')
204da0c48c4Sopenharmony_ci    name = h->ar_name;
205da0c48c4Sopenharmony_ci  else if (unlikely (asprintf (&module_name, "%s:%s", name, h->ar_name) < 0))
206da0c48c4Sopenharmony_ci    {
207da0c48c4Sopenharmony_ci      free (member_name);
208da0c48c4Sopenharmony_ci      goto nomem;
209da0c48c4Sopenharmony_ci    }
210da0c48c4Sopenharmony_ci  else
211da0c48c4Sopenharmony_ci    name = module_name;
212da0c48c4Sopenharmony_ci
213da0c48c4Sopenharmony_ci  if (predicate != NULL)
214da0c48c4Sopenharmony_ci    {
215da0c48c4Sopenharmony_ci      /* Let the predicate decide whether to use this one.  */
216da0c48c4Sopenharmony_ci      int want = (*predicate) (name, member_name);
217da0c48c4Sopenharmony_ci      if (want <= 0)
218da0c48c4Sopenharmony_ci	{
219da0c48c4Sopenharmony_ci	  free (member_name);
220da0c48c4Sopenharmony_ci	  free (module_name);
221da0c48c4Sopenharmony_ci	  if (unlikely (want < 0))
222da0c48c4Sopenharmony_ci	    {
223da0c48c4Sopenharmony_ci	      __libdwfl_seterrno (DWFL_E_CB);
224da0c48c4Sopenharmony_ci	      goto fail;
225da0c48c4Sopenharmony_ci	    }
226da0c48c4Sopenharmony_ci	  goto skip;
227da0c48c4Sopenharmony_ci	}
228da0c48c4Sopenharmony_ci    }
229da0c48c4Sopenharmony_ci
230da0c48c4Sopenharmony_ci  /* We let __libdwfl_report_elf cache the fd in mod->main.fd,
231da0c48c4Sopenharmony_ci     though it's the same fd for all the members.
232da0c48c4Sopenharmony_ci     On module teardown we will close it only on the last Elf reference.  */
233da0c48c4Sopenharmony_ci  *mod = process_file (dwfl, name, member_name, fd, member, predicate);
234da0c48c4Sopenharmony_ci  free (member_name);
235da0c48c4Sopenharmony_ci  free (module_name);
236da0c48c4Sopenharmony_ci
237da0c48c4Sopenharmony_ci  if (*mod == NULL)
238da0c48c4Sopenharmony_ci    {
239da0c48c4Sopenharmony_ci      elf_end (member);
240da0c48c4Sopenharmony_ci      return ELF_C_NULL;
241da0c48c4Sopenharmony_ci    }
242da0c48c4Sopenharmony_ci
243da0c48c4Sopenharmony_ci  /* Advance the archive-reading offset for the next iteration.  */
244da0c48c4Sopenharmony_ci  return elf_next (member);
245da0c48c4Sopenharmony_ci}
246da0c48c4Sopenharmony_ci
247da0c48c4Sopenharmony_ci/* Report each member of the archive as its own module.  */
248da0c48c4Sopenharmony_cistatic Dwfl_Module *
249da0c48c4Sopenharmony_ciprocess_archive (Dwfl *dwfl, const char *name, const char *file_name, int fd,
250da0c48c4Sopenharmony_ci		 Elf *archive,
251da0c48c4Sopenharmony_ci		 int (*predicate) (const char *module, const char *file))
252da0c48c4Sopenharmony_ci
253da0c48c4Sopenharmony_ci{
254da0c48c4Sopenharmony_ci  Dwfl_Module *mod = NULL;
255da0c48c4Sopenharmony_ci  /* elf_begin supports opening archives even with fd == -1 passed.  */
256da0c48c4Sopenharmony_ci  Elf *member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive);
257da0c48c4Sopenharmony_ci  if (unlikely (member == NULL)) /* Empty archive.  */
258da0c48c4Sopenharmony_ci    {
259da0c48c4Sopenharmony_ci      __libdwfl_seterrno (DWFL_E_BADELF);
260da0c48c4Sopenharmony_ci      return NULL;
261da0c48c4Sopenharmony_ci    }
262da0c48c4Sopenharmony_ci
263da0c48c4Sopenharmony_ci  while (process_archive_member (dwfl, name, file_name, predicate,
264da0c48c4Sopenharmony_ci				 fd, member, &mod) != ELF_C_NULL)
265da0c48c4Sopenharmony_ci    member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive);
266da0c48c4Sopenharmony_ci
267da0c48c4Sopenharmony_ci  /* We can drop the archive Elf handle even if we're still using members
268da0c48c4Sopenharmony_ci     in live modules.  When the last module's elf_end on a member returns
269da0c48c4Sopenharmony_ci     zero, that module will close FD.  If no modules survived the predicate,
270da0c48c4Sopenharmony_ci     we are all done with the file right here.  */
271da0c48c4Sopenharmony_ci  if (mod != NULL		/* If no modules, caller will clean up.  */
272da0c48c4Sopenharmony_ci      && elf_end (archive) == 0)
273da0c48c4Sopenharmony_ci    close (fd);
274da0c48c4Sopenharmony_ci
275da0c48c4Sopenharmony_ci  return mod;
276da0c48c4Sopenharmony_ci}
277da0c48c4Sopenharmony_ci
278da0c48c4Sopenharmony_ciDwfl_Module *
279da0c48c4Sopenharmony_ciinternal_function
280da0c48c4Sopenharmony_ci__libdwfl_report_offline (Dwfl *dwfl, const char *name,
281da0c48c4Sopenharmony_ci			  const char *file_name, int fd, bool closefd,
282da0c48c4Sopenharmony_ci			  int (*predicate) (const char *module,
283da0c48c4Sopenharmony_ci					    const char *file))
284da0c48c4Sopenharmony_ci{
285da0c48c4Sopenharmony_ci  Elf *elf;
286da0c48c4Sopenharmony_ci  Dwfl_Error error = __libdw_open_file (&fd, &elf, closefd, true);
287da0c48c4Sopenharmony_ci  if (error != DWFL_E_NOERROR)
288da0c48c4Sopenharmony_ci    {
289da0c48c4Sopenharmony_ci      __libdwfl_seterrno (error);
290da0c48c4Sopenharmony_ci      return NULL;
291da0c48c4Sopenharmony_ci    }
292da0c48c4Sopenharmony_ci  Dwfl_Module *mod = process_file (dwfl, name, file_name, fd, elf, predicate);
293da0c48c4Sopenharmony_ci  if (mod == NULL)
294da0c48c4Sopenharmony_ci    {
295da0c48c4Sopenharmony_ci      elf_end (elf);
296da0c48c4Sopenharmony_ci      if (closefd)
297da0c48c4Sopenharmony_ci	close (fd);
298da0c48c4Sopenharmony_ci    }
299da0c48c4Sopenharmony_ci  return mod;
300da0c48c4Sopenharmony_ci}
301da0c48c4Sopenharmony_ci
302da0c48c4Sopenharmony_ciDwfl_Module *
303da0c48c4Sopenharmony_cidwfl_report_offline (Dwfl *dwfl, const char *name,
304da0c48c4Sopenharmony_ci		     const char *file_name, int fd)
305da0c48c4Sopenharmony_ci{
306da0c48c4Sopenharmony_ci  if (dwfl == NULL)
307da0c48c4Sopenharmony_ci    return NULL;
308da0c48c4Sopenharmony_ci
309da0c48c4Sopenharmony_ci  bool closefd = false;
310da0c48c4Sopenharmony_ci  if (fd < 0)
311da0c48c4Sopenharmony_ci    {
312da0c48c4Sopenharmony_ci      closefd = true;
313da0c48c4Sopenharmony_ci      fd = open (file_name, O_RDONLY);
314da0c48c4Sopenharmony_ci      if (fd < 0)
315da0c48c4Sopenharmony_ci	{
316da0c48c4Sopenharmony_ci	  __libdwfl_seterrno (DWFL_E_ERRNO);
317da0c48c4Sopenharmony_ci	  return NULL;
318da0c48c4Sopenharmony_ci	}
319da0c48c4Sopenharmony_ci    }
320da0c48c4Sopenharmony_ci
321da0c48c4Sopenharmony_ci  return __libdwfl_report_offline (dwfl, name, file_name, fd, closefd, NULL);
322da0c48c4Sopenharmony_ci}
323da0c48c4Sopenharmony_ciINTDEF (dwfl_report_offline)
324da0c48c4Sopenharmony_ci
325da0c48c4Sopenharmony_ciDwfl_Module *
326da0c48c4Sopenharmony_cidwfl_report_offline_memory (Dwfl *dwfl, const char *name,
327da0c48c4Sopenharmony_ci			    const char *file_name, char *data, size_t size)
328da0c48c4Sopenharmony_ci{
329da0c48c4Sopenharmony_ci  if (dwfl == NULL)
330da0c48c4Sopenharmony_ci    return NULL;
331da0c48c4Sopenharmony_ci
332da0c48c4Sopenharmony_ci  Elf *elf;
333da0c48c4Sopenharmony_ci  Dwfl_Error error = __libdw_open_elf_memory (data, size, &elf, true);
334da0c48c4Sopenharmony_ci  if (error != DWFL_E_NOERROR)
335da0c48c4Sopenharmony_ci    {
336da0c48c4Sopenharmony_ci      __libdwfl_seterrno (error);
337da0c48c4Sopenharmony_ci      return NULL;
338da0c48c4Sopenharmony_ci    }
339da0c48c4Sopenharmony_ci  /* It is ok to pass fd == -1 here, because libelf uses it as a value for
340da0c48c4Sopenharmony_ci     "no file opened" and supports working with files without fd, thanks to
341da0c48c4Sopenharmony_ci     the existence of the elf_memory function.  */
342da0c48c4Sopenharmony_ci  Dwfl_Module *mod = process_file (dwfl, name, file_name, -1, elf, NULL);
343da0c48c4Sopenharmony_ci  if (mod == NULL)
344da0c48c4Sopenharmony_ci    elf_end (elf);
345da0c48c4Sopenharmony_ci  return mod;
346da0c48c4Sopenharmony_ci}
347da0c48c4Sopenharmony_ciINTDEF (dwfl_report_offline_memory)
348