Exemplo n.º 1
0
static inline Dwfl_Error
open_elf_file (Elf **elf, int *fd, char **name)
{
  if (*elf == NULL)
    {
      /* CBFAIL uses errno if it's set, so clear it first in case we don't
	 set it with an open failure below.  */
      errno = 0;

      /* If there was a pre-primed file name left that the callback left
	 behind, try to open that file name.  */
      if (*fd < 0 && *name != NULL)
	*fd = TEMP_FAILURE_RETRY (open (*name, O_RDONLY));

      if (*fd < 0)
	return CBFAIL;

      return __libdw_open_file (fd, elf, true, false);
    }
  else if (unlikely (elf_kind (*elf) != ELF_K_ELF))
    {
      elf_end (*elf);
      *elf = NULL;
      close (*fd);
      *fd = -1;
      return DWFL_E_BADELF;
    }

  /* Elf file already open and looks fine.  */
  return DWFL_E_NOERROR;
}
/* Open libelf FILE->fd and compute the load base of ELF as loaded in MOD.
   When we return success, FILE->elf and FILE->bias are set up.  */
static inline Dwfl_Error
open_elf (Dwfl_Module *mod, struct dwfl_file *file)
{
  if (file->elf == NULL)
    {
      /* If there was a pre-primed file name left that the callback left
	 behind, try to open that file name.  */
      if (file->fd < 0 && file->name != NULL)
	file->fd = TEMP_FAILURE_RETRY (open64 (file->name, O_RDONLY));

      if (file->fd < 0)
	return CBFAIL;

      Dwfl_Error error = __libdw_open_file (&file->fd, &file->elf, true, false);
      if (error != DWFL_E_NOERROR)
	return error;
    }
  else if (unlikely (elf_kind (file->elf) != ELF_K_ELF))
    {
      close (file->fd);
      file->fd = -1;
      return DWFL_E_BADELF;
    }

  GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (file->elf, &ehdr_mem);
  if (ehdr == NULL)
    {
    elf_error:
      close (file->fd);
      file->fd = -1;
      return DWFL_E (LIBELF, elf_errno ());
    }

  /* The addresses in an ET_EXEC file are absolute.  The lowest p_vaddr of
     the main file can differ from that of the debug file due to prelink.
     But that doesn't not change addresses that symbols, debuginfo, or
     sh_addr of any program sections refer to.  */
  file->bias = 0;
  if (mod->e_type != ET_EXEC)
    for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
      {
	GElf_Phdr ph_mem;
	GElf_Phdr *ph = gelf_getphdr (file->elf, i, &ph_mem);
	if (ph == NULL)
	  goto elf_error;
	if (ph->p_type == PT_LOAD)
	  {
	    file->bias = ((mod->low_addr & -ph->p_align)
			  - (ph->p_vaddr & -ph->p_align));
	    break;
	  }
      }

  mod->e_type = ehdr->e_type;

  /* Relocatable Linux kernels are ET_EXEC but act like ET_DYN.  */
  if (mod->e_type == ET_EXEC && file->bias != 0)
    mod->e_type = ET_DYN;

  return DWFL_E_NOERROR;
}
static bool
validate (Dwfl_Module *mod, int fd, bool check, GElf_Word debuglink_crc)
{
  /* For alt debug files always check the build-id from the Dwarf and alt.  */
  if (mod->dw != NULL)
    {
      bool valid = false;
      const void *build_id;
      const char *altname;
      ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (mod->dw,
								   &altname,
								   &build_id);
      if (build_id_len > 0)
	{
	  /* We need to open an Elf handle on the file so we can check its
	     build ID note for validation.  Backdoor the handle into the
	     module data structure since we had to open it early anyway.  */
	  Dwfl_Error error = __libdw_open_file (&fd, &mod->alt_elf,
						false, false);
	  if (error != DWFL_E_NOERROR)
	    __libdwfl_seterrno (error);
	  else
	    {
	      const void *alt_build_id;
	      ssize_t alt_len = INTUSE(dwelf_elf_gnu_build_id) (mod->alt_elf,
								&alt_build_id);
	      if (alt_len > 0 && alt_len == build_id_len
		  && memcmp (build_id, alt_build_id, alt_len) == 0)
		valid = true;
	      else
		{
		  /* A mismatch!  */
		  elf_end (mod->alt_elf);
		  mod->alt_elf = NULL;
		  close (fd);
		  fd = -1;
		}
	    }
	}
      return valid;
    }

  /* If we have a build ID, check only that.  */
  if (mod->build_id_len > 0)
    {
      /* We need to open an Elf handle on the file so we can check its
	 build ID note for validation.  Backdoor the handle into the
	 module data structure since we had to open it early anyway.  */

      mod->debug.valid = false;
      Dwfl_Error error = __libdw_open_file (&fd, &mod->debug.elf, false, false);
      if (error != DWFL_E_NOERROR)
	__libdwfl_seterrno (error);
      else if (likely (__libdwfl_find_build_id (mod, false,
						mod->debug.elf) == 2))
	/* Also backdoor the gratuitous flag.  */
	mod->debug.valid = true;
      else
	{
	  /* A mismatch!  */
	  elf_end (mod->debug.elf);
	  mod->debug.elf = NULL;
	  close (fd);
	  fd = -1;
	}

      return mod->debug.valid;
    }

  return !check || check_crc (fd, debuglink_crc);
}
Exemplo n.º 4
0
/* Open libelf FILE->fd and compute the load base of ELF as loaded in MOD.
   When we return success, FILE->elf and FILE->vaddr are set up.  */
static inline Dwfl_Error
open_elf (Dwfl_Module *mod, struct dwfl_file *file)
{
  if (file->elf == NULL)
    {
      /* CBFAIL uses errno if it's set, so clear it first in case we don't
	 set it with an open failure below.  */
      errno = 0;

      /* If there was a pre-primed file name left that the callback left
	 behind, try to open that file name.  */
      if (file->fd < 0 && file->name != NULL)
	file->fd = TEMP_FAILURE_RETRY (open64 (file->name, O_RDONLY));

      if (file->fd < 0)
	return CBFAIL;

      Dwfl_Error error = __libdw_open_file (&file->fd, &file->elf, true, false);
      if (error != DWFL_E_NOERROR)
	return error;
    }
  else if (unlikely (elf_kind (file->elf) != ELF_K_ELF))
    {
      elf_end (file->elf);
      file->elf = NULL;
      close (file->fd);
      file->fd = -1;
      return DWFL_E_BADELF;
    }

  GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (file->elf, &ehdr_mem);
  if (ehdr == NULL)
    {
    elf_error:
      elf_end (file->elf);
      file->elf = NULL;
      close (file->fd);
      file->fd = -1;
      return DWFL_E (LIBELF, elf_errno ());
    }

  if (ehdr->e_type != ET_REL)
    {
      /* In any non-ET_REL file, we compute the "synchronization address".

	 We start with the address at the end of the first PT_LOAD
	 segment.  When prelink converts REL to RELA in an ET_DYN
	 file, it expands the space between the beginning of the
	 segment and the actual code/data addresses.  Since that
	 change wasn't made in the debug file, the distance from
	 p_vaddr to an address of interest (in an st_value or DWARF
	 data) now differs between the main and debug files.  The
	 distance from address_sync to an address of interest remains
	 consistent.

	 If there are no section headers at all (full stripping), then
	 the end of the first segment is a valid synchronization address.
	 This cannot happen in a prelinked file, since prelink itself
	 relies on section headers for prelinking and for undoing it.
	 (If you do full stripping on a prelinked file, then you get what
	 you deserve--you can neither undo the prelinking, nor expect to
	 line it up with a debug file separated before prelinking.)

	 However, when prelink processes an ET_EXEC file, it can do
	 something different.  There it juggles the "special" sections
	 (SHT_DYNSYM et al) to make space for the additional prelink
	 special sections.  Sometimes it will do this by moving a special
	 section like .dynstr after the real program sections in the first
	 PT_LOAD segment--i.e. to the end.  That changes the end address of
	 the segment, so it no longer lines up correctly and is not a valid
	 synchronization address to use.  Because of this, we need to apply
	 a different prelink-savvy means to discover the synchronization
	 address when there is a separate debug file and a prelinked main
	 file.  That is done in find_debuginfo, below.  */

      size_t phnum;
      if (unlikely (elf_getphdrnum (file->elf, &phnum) != 0))
	goto elf_error;

      file->vaddr = file->address_sync = 0;
      for (size_t i = 0; i < phnum; ++i)
	{
	  GElf_Phdr ph_mem;
	  GElf_Phdr *ph = gelf_getphdr (file->elf, i, &ph_mem);
	  if (unlikely (ph == NULL))
	    goto elf_error;
	  if (ph->p_type == PT_LOAD)
	    {
	      file->vaddr = ph->p_vaddr & -ph->p_align;
	      file->address_sync = ph->p_vaddr + ph->p_memsz;
	      break;
	    }
	}
    }

  /* We only want to set the module e_type explictly once, derived from
     the main ELF file.  (It might be changed for the kernel, because
     that is special - see below.)  open_elf is always called first for
     the main ELF file, because both find_dw and find_symtab call
     __libdwfl_getelf first to open the main file.  So don't let debug
     or aux files override the module e_type.  The kernel heuristic
     below could otherwise trigger for non-kernel/non-main files, since
     their phdrs might not match the actual load addresses.  */
  if (file == &mod->main)
    {
      mod->e_type = ehdr->e_type;

      /* Relocatable Linux kernels are ET_EXEC but act like ET_DYN.  */
      if (mod->e_type == ET_EXEC && file->vaddr != mod->low_addr)
	mod->e_type = ET_DYN;
    }
  else
    assert (mod->main.elf != NULL);

  return DWFL_E_NOERROR;
}