125b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Recover relocatibility for addresses computed from debug information.
203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   Copyright (C) 2005-2009, 2012 Red Hat, Inc.
303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   This file is part of elfutils.
425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   This file is free software; you can redistribute it and/or modify
603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   it under the terms of either
725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes     * the GNU Lesser General Public License as published by the Free
903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       Software Foundation; either version 3 of the License, or (at
1003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       your option) any later version
1103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   or
1303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes     * the GNU General Public License as published by the Free
1503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       Software Foundation; either version 2 of the License, or (at
1603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       your option) any later version
1703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   or both in parallel, as here.
1903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
2003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   elfutils is distributed in the hope that it will be useful, but
2125b3c049e70834cf33790a28643ab058b507b35cBen Cheng   WITHOUT ANY WARRANTY; without even the implied warranty of
2225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   General Public License for more details.
2425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
2503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   You should have received copies of the GNU General Public License and
2603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   the GNU Lesser General Public License along with this program.  If
2703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   not, see <http://www.gnu.org/licenses/>.  */
2825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
2925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "libdwflP.h"
3025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <fcntl.h>
3125b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <unistd.h>
3225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
3325b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Since dwfl_report_elf lays out the sections already, this will only be
3425b3c049e70834cf33790a28643ab058b507b35cBen Cheng   called when the section headers of the debuginfo file are being
3525b3c049e70834cf33790a28643ab058b507b35cBen Cheng   consulted instead, or for the section placed at 0.  With binutils
3625b3c049e70834cf33790a28643ab058b507b35cBen Cheng   strip-to-debug, the symbol table is in the debuginfo file and relocation
3725b3c049e70834cf33790a28643ab058b507b35cBen Cheng   looks there.  */
3825b3c049e70834cf33790a28643ab058b507b35cBen Chengint
3925b3c049e70834cf33790a28643ab058b507b35cBen Chengdwfl_offline_section_address (Dwfl_Module *mod,
4025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      void **userdata __attribute__ ((unused)),
4125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      const char *modname __attribute__ ((unused)),
4225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      Dwarf_Addr base __attribute__ ((unused)),
4325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      const char *secname __attribute__ ((unused)),
4425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      Elf32_Word shndx,
4525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      const GElf_Shdr *shdr __attribute__ ((unused)),
4625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      Dwarf_Addr *addr)
4725b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
4825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  assert (mod->e_type == ET_REL);
4925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  assert (shdr->sh_addr == 0);
5025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  assert (shdr->sh_flags & SHF_ALLOC);
5103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  assert (shndx != 0);
5225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
5325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (mod->debug.elf == NULL)
5425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    /* We are only here because sh_addr is zero even though layout is complete.
5525b3c049e70834cf33790a28643ab058b507b35cBen Cheng       The first section in the first file under -e is placed at 0.  */
5625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return 0;
5725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
5825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* The section numbers might not match between the two files.
5925b3c049e70834cf33790a28643ab058b507b35cBen Cheng     The best we can rely on is the order of SHF_ALLOC sections.  */
6025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
6125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Scn *ourscn = elf_getscn (mod->debug.elf, shndx);
6225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Scn *scn = NULL;
6325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  uint_fast32_t skip_alloc = 0;
6425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  while ((scn = elf_nextscn (mod->debug.elf, scn)) != ourscn)
6525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
6625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      assert (scn != NULL);
6725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Shdr shdr_mem;
6825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Shdr *sh = gelf_getshdr (scn, &shdr_mem);
6925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (unlikely (sh == NULL))
7025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return -1;
7125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (sh->sh_flags & SHF_ALLOC)
7225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	++skip_alloc;
7325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
7425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
7525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  scn = NULL;
7625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
7725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
7825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Shdr shdr_mem;
7925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Shdr *main_shdr = gelf_getshdr (scn, &shdr_mem);
8025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (unlikely (main_shdr == NULL))
8125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return -1;
8225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if ((main_shdr->sh_flags & SHF_ALLOC) && skip_alloc-- == 0)
8325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
8425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  assert (main_shdr->sh_flags == shdr->sh_flags);
8525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  *addr = main_shdr->sh_addr;
8625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  return 0;
8725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
8825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
8925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
9025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* This should never happen.  */
9125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return -1;
9225b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
9325b3c049e70834cf33790a28643ab058b507b35cBen ChengINTDEF (dwfl_offline_section_address)
9425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
9525b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Forward declarations.  */
9625b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic Dwfl_Module *process_elf (Dwfl *dwfl, const char *name,
9725b3c049e70834cf33790a28643ab058b507b35cBen Cheng				 const char *file_name, int fd, Elf *elf);
9825b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic Dwfl_Module *process_archive (Dwfl *dwfl, const char *name,
9925b3c049e70834cf33790a28643ab058b507b35cBen Cheng				     const char *file_name, int fd, Elf *elf,
10025b3c049e70834cf33790a28643ab058b507b35cBen Cheng				     int (*predicate) (const char *module,
10125b3c049e70834cf33790a28643ab058b507b35cBen Cheng						       const char *file));
10225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
10325b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Report one module for an ELF file, or many for an archive.
10425b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Always consumes ELF and FD.  */
10525b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic Dwfl_Module *
10625b3c049e70834cf33790a28643ab058b507b35cBen Chengprocess_file (Dwfl *dwfl, const char *name, const char *file_name, int fd,
10725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      Elf *elf, int (*predicate) (const char *module,
10825b3c049e70834cf33790a28643ab058b507b35cBen Cheng					  const char *file))
10925b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
11025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  switch (elf_kind (elf))
11125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
11225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    default:
11325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    case ELF_K_NONE:
11425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      __libdwfl_seterrno (elf == NULL ? DWFL_E_LIBELF : DWFL_E_BADELF);
11525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return NULL;
11625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
11725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    case ELF_K_ELF:
11825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return process_elf (dwfl, name, file_name, fd, elf);
11925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
12025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    case ELF_K_AR:
12125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return process_archive (dwfl, name, file_name, fd, elf, predicate);
12225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
12325b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
12425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
12525b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Report the open ELF file as a module.  Always consumes ELF and FD.  */
12625b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic Dwfl_Module *
12725b3c049e70834cf33790a28643ab058b507b35cBen Chengprocess_elf (Dwfl *dwfl, const char *name, const char *file_name, int fd,
12825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     Elf *elf)
12925b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
13025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Dwfl_Module *mod = __libdwfl_report_elf (dwfl, name, file_name, fd, elf,
13103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes					   dwfl->offline_next_address, true,
13203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes					   false);
13325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (mod != NULL)
13425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
13525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* If this is an ET_EXEC file with fixed addresses, the address range
13625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 it consumed may or may not intersect with the arbitrary range we
13725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 will use for relocatable modules.  Make sure we always use a free
13825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 range for the offline allocations.  If this module did use
13925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 offline_next_address, it may have rounded it up for the module's
14025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 alignment requirements.  */
14125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if ((dwfl->offline_next_address >= mod->low_addr
14225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   || mod->low_addr - dwfl->offline_next_address < OFFLINE_REDZONE)
14325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && dwfl->offline_next_address < mod->high_addr + OFFLINE_REDZONE)
14425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	dwfl->offline_next_address = mod->high_addr + OFFLINE_REDZONE;
14525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
14625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Don't keep the file descriptor around.  */
14725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0)
14825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
14925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  close (mod->main.fd);
15025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  mod->main.fd = -1;
15125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
15225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
15325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
15425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return mod;
15525b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
15625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
15725b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Always consumes MEMBER.  Returns elf_next result on success.
15825b3c049e70834cf33790a28643ab058b507b35cBen Cheng   For errors returns ELF_C_NULL with *MOD set to null.  */
15925b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic Elf_Cmd
16025b3c049e70834cf33790a28643ab058b507b35cBen Chengprocess_archive_member (Dwfl *dwfl, const char *name, const char *file_name,
16125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			int (*predicate) (const char *module, const char *file),
16225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			int fd, Elf *member, Dwfl_Module **mod)
16325b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
16425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  const Elf_Arhdr *h = elf_getarhdr (member);
16525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (unlikely (h == NULL))
16625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
16725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      __libdwfl_seterrno (DWFL_E_LIBELF);
16825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    fail:
16925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      elf_end (member);
17025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      *mod = NULL;
17125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return ELF_C_NULL;
17225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
17325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
17403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (!strcmp (h->ar_name, "/") || !strcmp (h->ar_name, "//")
17503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      || !strcmp (h->ar_name, "/SYM64/"))
17625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
17725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    skip:;
17825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Skip this and go to the next.  */
17925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      Elf_Cmd result = elf_next (member);
18025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      elf_end (member);
18125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return result;
18225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
18325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
18425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  char *member_name;
18525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (unlikely (asprintf (&member_name, "%s(%s)", file_name, h->ar_name) < 0))
18625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
18725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    nomem:
18825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      __libdwfl_seterrno (DWFL_E_NOMEM);
18925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      elf_end (member);
19025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      *mod = NULL;
19125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return ELF_C_NULL;
19225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
19325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
19425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  char *module_name = NULL;
19525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (name == NULL || name[0] == '\0')
19625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    name = h->ar_name;
19725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  else if (unlikely (asprintf (&module_name, "%s:%s", name, h->ar_name) < 0))
19825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
19925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      free (member_name);
20025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      goto nomem;
20125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
20225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  else
20325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    name = module_name;
20425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
20525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (predicate != NULL)
20625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
20725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Let the predicate decide whether to use this one.  */
20825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      int want = (*predicate) (name, member_name);
20925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (want <= 0)
21025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
21125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  free (member_name);
21225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  free (module_name);
21325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (unlikely (want < 0))
21425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
21525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      __libdwfl_seterrno (DWFL_E_CB);
21625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      goto fail;
21725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
21825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  goto skip;
21925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
22025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
22125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
22225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* We let __libdwfl_report_elf cache the fd in mod->main.fd,
22325b3c049e70834cf33790a28643ab058b507b35cBen Cheng     though it's the same fd for all the members.
22425b3c049e70834cf33790a28643ab058b507b35cBen Cheng     On module teardown we will close it only on the last Elf reference.  */
22525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  *mod = process_file (dwfl, name, member_name, fd, member, predicate);
22625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  free (member_name);
22725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  free (module_name);
22825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
22925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (*mod == NULL)		/* process_file called elf_end.  */
23025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return ELF_C_NULL;
23125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
23225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Advance the archive-reading offset for the next iteration.  */
23325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return elf_next (member);
23425b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
23525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
23625b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Report each member of the archive as its own module.  */
23725b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic Dwfl_Module *
23825b3c049e70834cf33790a28643ab058b507b35cBen Chengprocess_archive (Dwfl *dwfl, const char *name, const char *file_name, int fd,
23925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 Elf *archive,
24025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 int (*predicate) (const char *module, const char *file))
24125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
24225b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
24325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Dwfl_Module *mod = NULL;
24425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf *member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive);
24525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (unlikely (member == NULL)) /* Empty archive.  */
24625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
24725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      __libdwfl_seterrno (DWFL_E_BADELF);
24825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return NULL;
24925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
25025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
25125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  while (process_archive_member (dwfl, name, file_name, predicate,
25225b3c049e70834cf33790a28643ab058b507b35cBen Cheng				 fd, member, &mod) != ELF_C_NULL)
25325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive);
25425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
25525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* We can drop the archive Elf handle even if we're still using members
25625b3c049e70834cf33790a28643ab058b507b35cBen Cheng     in live modules.  When the last module's elf_end on a member returns
25725b3c049e70834cf33790a28643ab058b507b35cBen Cheng     zero, that module will close FD.  If no modules survived the predicate,
25825b3c049e70834cf33790a28643ab058b507b35cBen Cheng     we are all done with the file right here.  */
25925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (mod != NULL		/* If no modules, caller will clean up.  */
26025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && elf_end (archive) == 0)
26125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    close (fd);
26225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
26325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return mod;
26425b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
26525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
26625b3c049e70834cf33790a28643ab058b507b35cBen ChengDwfl_Module *
26725b3c049e70834cf33790a28643ab058b507b35cBen Chenginternal_function
26825b3c049e70834cf33790a28643ab058b507b35cBen Cheng__libdwfl_report_offline (Dwfl *dwfl, const char *name,
26925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  const char *file_name, int fd, bool closefd,
27025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  int (*predicate) (const char *module,
27125b3c049e70834cf33790a28643ab058b507b35cBen Cheng					    const char *file))
27225b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
27325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf *elf;
27425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Dwfl_Error error = __libdw_open_file (&fd, &elf, closefd, true);
27525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (error != DWFL_E_NOERROR)
27625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
27725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      __libdwfl_seterrno (error);
27825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return NULL;
27925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
28025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Dwfl_Module *mod = process_file (dwfl, name, file_name, fd, elf, predicate);
28125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (mod == NULL)
28225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
28325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      elf_end (elf);
28425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (closefd)
28525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	close (fd);
28625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
28725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return mod;
28825b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
28925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
29025b3c049e70834cf33790a28643ab058b507b35cBen ChengDwfl_Module *
29125b3c049e70834cf33790a28643ab058b507b35cBen Chengdwfl_report_offline (Dwfl *dwfl, const char *name,
29225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     const char *file_name, int fd)
29325b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
29425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (dwfl == NULL)
29525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return NULL;
29625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
29725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  bool closefd = false;
29825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (fd < 0)
29925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
30025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      closefd = true;
30125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      fd = open64 (file_name, O_RDONLY);
30225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (fd < 0)
30325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
30425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  __libdwfl_seterrno (DWFL_E_ERRNO);
30525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  return NULL;
30625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
30725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
30825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
30925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return __libdwfl_report_offline (dwfl, name, file_name, fd, closefd, NULL);
31025b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
31125b3c049e70834cf33790a28643ab058b507b35cBen ChengINTDEF (dwfl_report_offline)
312