[commit] [patch] Fix dwfl_report_elf BASE alignment [Re: pending patches ping#2]

Jan Kratochvil jan.kratochvil at redhat.com
Mon Apr 1 19:26:24 UTC 2013


Hi Roland,

work in progress in: jankratochvil/corewithnobuildid

This mail is just FYI, the patch/branch is not yet suitable for a review.


On Wed, 20 Mar 2013 23:09:22 +0100, Roland McGrath wrote:
> Please fix that regression soon.  We certainly need good test coverage for
> both the partial-segments and no-text-segments flavors of core files.
> If it will take you longer than a day or two to get the fix in, please
> put in the new failing test case anyway.  It's better to have a 'make check'
> failure on the trunk than just an informally known regression.

I had some difficulties isolating the regression and then I found core files
have never worked (reliably) with elfutils - at least as tested with
e3e3ee261e0d2f8716b5011ca5fcfc88766146f5 before I started my contributions in
2012.

The new testcase in this branch/patch was created with:
	echo 'libfunc(){*(int*)0=0;}'|gcc -Wl,--build-id=none -o test-core-lib.so -shared -fPIC -x c -;echo 'const char x[4000]={0};main(){libfunc();}'|gcc -Wl,--build-id=none -o test-core-main ./test-core-lib.so -x c -
	(ulimit -c unlimited;echo 0x23 >/proc/self/coredump_filter;cat /proc/self/coredump_filter;./test-core-main)

* there is no build-id
* first ELF pages is not dumped by kernel

This leads to /proc/PID/maps layout:

7ffff7bda000-7ffff7bdb000 r-xp 00000000 fd:01 25079538 test-core-lib.so
7ffff7bdb000-7ffff7dda000 ---p 00001000 fd:01 25079538 test-core-lib.so
7ffff7dda000-7ffff7ddb000 r--p 00000000 fd:01 25079538 test-core-lib.so
7ffff7ddb000-7ffff7ddc000 rw-p 00001000 fd:01 25079538 test-core-lib.so

which gets dumped as (addresses do not match - it was a different session):

Type Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
LOAD 0x014000 0x00007f67f2aaf000 0x0000000000000000 0x000000 0x001000 R E 0x1000
LOAD 0x014000 0x00007f67f2ab0000 0x0000000000000000 0x000000 0x1ff000     0x1000
LOAD 0x014000 0x00007f67f2caf000 0x0000000000000000 0x001000 0x001000 R   0x1000
LOAD 0x015000 0x00007f67f2cb0000 0x0000000000000000 0x001000 0x001000 RW  0x1000

Due to FileSiz == 0 elfutils will find the first ELF page at the 3rd entry
during the elfutils pass:
	/* Now sniff segment contents for modules.  */
	call dwfl_segment_report_module

Which will place the library incorrectly 2MB higher than it should be, later
dwfl_link_map_report pass will not fix that.

I have deleted the whole dwfl_segment_report_module pass as it cannot work.
One needs to find libraries from the link map otherwise one may get false
positives (finding libraries which were not in the link map) even for example
from mmapped (and for some reason dumped) files.

And even if one could ignore additional false positives the current
dwfl_link_map_report code tries to match the link map entries back to the
entries (incorrectly) found by dwfl_segment_report_module.

But the patch/branch currently has multiple regressions, the elfutils code was
relying too much on the dwfl_segment_report_module pass.


Regards,
Jan
-------------- next part --------------
commit 79098a0798b3e988908a3c735cc8986f15c25fcf
Author: Jan Kratochvil <jan.kratochvil at redhat.com>
Date:   Mon Apr 1 20:54:36 2013 +0200

    ../src/addr2line -S -e test-core.exec --core=test-core.core 0x7f67f2aaf619
    libfunc+0x9
    ??:0

diff --git a/libdwfl/Makefile.am b/libdwfl/Makefile.am
index 0ef4928..339b36b 100644
--- a/libdwfl/Makefile.am
+++ b/libdwfl/Makefile.am
@@ -67,7 +67,6 @@ libdwfl_a_SOURCES = dwfl_begin.c dwfl_end.c dwfl_error.c dwfl_version.c \
 		    dwfl_module_addrname.c dwfl_module_addrsym.c \
 		    dwfl_module_return_value_location.c \
 		    dwfl_module_register_names.c \
-		    dwfl_segment_report_module.c \
 		    link_map.c core-file.c open.c image-header.c
 
 if ZLIB
diff --git a/libdwfl/argp-std.c b/libdwfl/argp-std.c
index e54f720..d0d49a7 100644
--- a/libdwfl/argp-std.c
+++ b/libdwfl/argp-std.c
@@ -60,32 +60,6 @@ static const struct argp_option options[] =
   { NULL, 0, NULL, 0, NULL, 0 }
 };
 
-/* Wrapper to provide proper FILE_NAME for -e|--executable.  */
-static int
-offline_find_elf (Dwfl_Module *mod, void **userdata, const char *modname,
-		  Dwarf_Addr base, char **file_name, Elf **elfp)
-{
-  if (modname != NULL && (strcmp (modname, "[exe]") == 0
-			  || strcmp (modname, "[pie]") == 0)
-      && mod->dwfl->executable_for_core)
-    {
-      /* When both --core and --executable are given in whatever order
-	 dwfl_core_file_report is called first and this callback will replace
-	 the Dwfl_Module main.name with the recorded --executable file when the
-	 modname is [exe] or [pie] (which then triggers opening and reporting
-	 of the executable).  */
-      char *e_dup = strdup (mod->dwfl->executable_for_core);
-      if (e_dup)
-	{
-	  free (*file_name);
-	  *file_name = e_dup;
-	  return -1;
-	}
-    }
-  return INTUSE(dwfl_build_id_find_elf) (mod, userdata, modname, base,
-                                         file_name, elfp);
-}
-
 static char *debuginfo_path;
 
 static const Dwfl_Callbacks offline_callbacks =
@@ -96,7 +70,7 @@ static const Dwfl_Callbacks offline_callbacks =
     .section_address = INTUSE(dwfl_offline_section_address),
 
     /* We use this table for core files too.  */
-    .find_elf = offline_find_elf,
+    .find_elf = INTUSE(dwfl_build_id_find_elf),
   };
 
 static const Dwfl_Callbacks proc_callbacks =
@@ -293,6 +267,12 @@ parse_opt (int key, char *arg, struct argp_state *state)
 	    opt->dwfl = dwfl;
 	  }
 
+	if (opt->e)
+	  {
+	    if (INTUSE(dwfl_report_offline) (dwfl, "", opt->e, -1) == NULL)
+	      return fail (dwfl, -1, opt->e);
+	  }
+
 	if (opt->core)
 	  {
 	    int fd = open64 (opt->core, O_RDONLY);
@@ -330,14 +310,6 @@ parse_opt (int key, char *arg, struct argp_state *state)
 			      _("No modules recognized in core file"));
 		return ENOENT;
 	      }
-
-	    if (opt->e)
-	      dwfl->executable_for_core = strdup (opt->e);
-	  }
-	else if (opt->e)
-	  {
-	    if (INTUSE(dwfl_report_offline) (dwfl, "", opt->e, -1) == NULL)
-	      return fail (dwfl, -1, opt->e);
 	  }
 
 	/* One of the three flavors has done dwfl_begin and some reporting
diff --git a/libdwfl/core-file.c b/libdwfl/core-file.c
index 1545ca8..784b97d 100644
--- a/libdwfl/core-file.c
+++ b/libdwfl/core-file.c
@@ -39,86 +39,6 @@
 #include "system.h"
 
 
-/* This is a prototype of what a new libelf interface might be.
-   This implementation is pessimal for non-mmap cases and should
-   be replaced by more diddling inside libelf internals.  */
-static Elf *
-elf_begin_rand (Elf *parent, loff_t offset, loff_t size, loff_t *next)
-{
-  if (parent == NULL)
-    return NULL;
-
-  /* On failure return, we update *NEXT to point back at OFFSET.  */
-  inline Elf *fail (int error)
-  {
-    if (next != NULL)
-      *next = offset;
-    //__libelf_seterrno (error);
-    __libdwfl_seterrno (DWFL_E (LIBELF, error));
-    return NULL;
-  }
-
-  loff_t min = (parent->kind == ELF_K_ELF ?
-		(parent->class == ELFCLASS32
-		 ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr))
-		: parent->kind == ELF_K_AR ? SARMAG
-		: 0);
-
-  if (unlikely (offset < min)
-      || unlikely (offset >= (loff_t) parent->maximum_size))
-    return fail (ELF_E_RANGE);
-
-  /* For an archive, fetch just the size field
-     from the archive header to override SIZE.  */
-  if (parent->kind == ELF_K_AR)
-    {
-      struct ar_hdr h = { .ar_size = "" };
-
-      if (unlikely (parent->maximum_size - offset < sizeof h))
-	return fail (ELF_E_RANGE);
-
-      if (parent->map_address != NULL)
-	memcpy (h.ar_size, parent->map_address + parent->start_offset + offset,
-		sizeof h.ar_size);
-      else if (unlikely (pread_retry (parent->fildes,
-				      h.ar_size, sizeof (h.ar_size),
-				      parent->start_offset + offset
-				      + offsetof (struct ar_hdr, ar_size))
-			 != sizeof (h.ar_size)))
-	return fail (ELF_E_READ_ERROR);
-
-      offset += sizeof h;
-
-      char *endp;
-      size = strtoll (h.ar_size, &endp, 10);
-      if (unlikely (endp == h.ar_size)
-	  || unlikely ((loff_t) parent->maximum_size - offset < size))
-	return fail (ELF_E_INVALID_ARCHIVE);
-    }
-
-  if (unlikely ((loff_t) parent->maximum_size - offset < size))
-    return fail (ELF_E_RANGE);
-
-  /* Even if we fail at this point, update *NEXT to point past the file.  */
-  if (next != NULL)
-    *next = offset + size;
-
-  if (unlikely (offset == 0)
-      && unlikely (size == (loff_t) parent->maximum_size))
-    return elf_clone (parent, parent->cmd);
-
-  /* Note the image is guaranteed live only as long as PARENT
-     lives.  Using elf_memory is quite suboptimal if the whole
-     file is not mmap'd.  We really should have something like
-     a generalization of the archive support.  */
-  Elf_Data *data = elf_getdata_rawchunk (parent, offset, size, ELF_T_BYTE);
-  if (data == NULL)
-    return NULL;
-  assert ((loff_t) data->d_size == size);
-  return elf_memory (data->d_buf, size);
-}
-
-
 int
 dwfl_report_core_segments (Dwfl *dwfl, Elf *elf, size_t phnum, GElf_Phdr *notes)
 {
@@ -158,74 +78,6 @@ dwfl_report_core_segments (Dwfl *dwfl, Elf *elf, size_t phnum, GElf_Phdr *notes)
   return result;
 }
 
-/* Never read more than this much without mmap.  */
-#define MAX_EAGER_COST	8192
-
-static bool
-core_file_read_eagerly (Dwfl_Module *mod,
-			void **userdata __attribute__ ((unused)),
-			const char *name __attribute__ ((unused)),
-			Dwarf_Addr start __attribute__ ((unused)),
-			void **buffer, size_t *buffer_available,
-			GElf_Off cost, GElf_Off worthwhile,
-			GElf_Off whole,
-			GElf_Off contiguous __attribute__ ((unused)),
-			void *arg, Elf **elfp)
-{
-  Elf *core = arg;
-
-  if (whole <= *buffer_available)
-    {
-      /* All there ever was, we already have on hand.  */
-
-      if (core->map_address == NULL)
-	{
-	  /* We already malloc'd the buffer.  */
-	  *elfp = elf_memory (*buffer, whole);
-	  if (unlikely (*elfp == NULL))
-	    return false;
-
-	  (*elfp)->flags |= ELF_F_MALLOCED;
-	  *buffer = NULL;
-	  *buffer_available = 0;
-	  return true;
-	}
-
-      /* We can use the image inside the core file directly.  */
-      *elfp = elf_begin_rand (core, *buffer - core->map_address, whole, NULL);
-      *buffer = NULL;
-      *buffer_available = 0;
-      return *elfp != NULL;
-    }
-
-  /* We don't have the whole file.
-     Figure out if this is better than nothing.  */
-
-  if (worthwhile == 0)
-    /* Caller doesn't think so.  */
-    return false;
-
-  /*
-    XXX would like to fall back to partial file via memory
-    when build id find_elf fails
-    also, link_map name may give file name from disk better than partial here
-    requires find_elf hook re-doing the magic to fall back if no file found
-  */
-
-  if (mod->build_id_len > 0)
-    /* There is a build ID that could help us find the whole file,
-       which might be more useful than what we have.
-       We'll just rely on that.  */
-    return false;
-
-  if (core->map_address != NULL)
-    /* It's cheap to get, so get it.  */
-    return true;
-
-  /* Only use it if there isn't too much to be read.  */
-  return cost <= MAX_EAGER_COST;
-}
-
 bool
 dwfl_elf_phdr_memory_callback (Dwfl *dwfl, int ndx,
 			       void **buffer, size_t *buffer_available,
@@ -397,26 +249,6 @@ dwfl_core_file_report (Dwfl *dwfl, Elf *elf)
   if (unlikely (ndx <= 0))
     return ndx;
 
-  /* Now sniff segment contents for modules.  */
-  int sniffed = 0;
-  ndx = 0;
-  do
-    {
-      int seg = dwfl_segment_report_module (dwfl, ndx, NULL,
-					    &dwfl_elf_phdr_memory_callback, elf,
-					    core_file_read_eagerly, elf);
-      if (unlikely (seg < 0))
-	return seg;
-      if (seg > ndx)
-	{
-	  ndx = seg;
-	  ++sniffed;
-	}
-      else
-	++ndx;
-    }
-  while (ndx < (int) phnum);
-
   /* Next, we should follow the chain from DT_DEBUG.  */
 
   const void *auxv = NULL;
@@ -458,6 +290,6 @@ dwfl_core_file_report (Dwfl *dwfl, Elf *elf)
      If we found none, we return -1 instead of 0 if there was an
      error rather than just nothing found.  If link_map handling
      failed, we still have the sniffed modules.  */
-  return sniffed == 0 || listed > sniffed ? listed : sniffed;
+  return listed;
 }
 INTDEF (dwfl_core_file_report)
diff --git a/libdwfl/dwfl_end.c b/libdwfl/dwfl_end.c
index 94fcfc6..18dc123 100644
--- a/libdwfl/dwfl_end.c
+++ b/libdwfl/dwfl_end.c
@@ -46,6 +46,5 @@ dwfl_end (Dwfl *dwfl)
       __libdwfl_module_free (dead);
     }
 
-  free (dwfl->executable_for_core);
   free (dwfl);
 }
diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
deleted file mode 100644
index 7cf7499..0000000
--- a/libdwfl/dwfl_segment_report_module.c
+++ /dev/null
@@ -1,657 +0,0 @@
-/* Sniff out modules from ELF headers visible in memory segments.
-   Copyright (C) 2008-2012 Red Hat, Inc.
-   This file is part of elfutils.
-
-   This file is free software; you can redistribute it and/or modify
-   it under the terms of either
-
-     * the GNU Lesser General Public License as published by the Free
-       Software Foundation; either version 3 of the License, or (at
-       your option) any later version
-
-   or
-
-     * the GNU General Public License as published by the Free
-       Software Foundation; either version 2 of the License, or (at
-       your option) any later version
-
-   or both in parallel, as here.
-
-   elfutils is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
-
-   You should have received copies of the GNU General Public License and
-   the GNU Lesser General Public License along with this program.  If
-   not, see <http://www.gnu.org/licenses/>.  */
-
-#include <config.h>
-#include "../libelf/libelfP.h"	/* For NOTE_ALIGN.  */
-#undef	_
-#include "libdwflP.h"
-
-#include <elf.h>
-#include <gelf.h>
-#include <inttypes.h>
-#include <sys/param.h>
-#include <alloca.h>
-#include <endian.h>
-
-
-/* A good size for the initial read from memory, if it's not too costly.
-   This more than covers the phdrs and note segment in the average 64-bit
-   binary.  */
-
-#define INITIAL_READ	1024
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-# define MY_ELFDATA	ELFDATA2LSB
-#else
-# define MY_ELFDATA	ELFDATA2MSB
-#endif
-
-
-/* Return user segment index closest to ADDR but not above it.
-   If NEXT, return the closest to ADDR but not below it.  */
-static int
-addr_segndx (Dwfl *dwfl, size_t segment, GElf_Addr addr, bool next)
-{
-  int ndx = -1;
-  do
-    {
-      if (dwfl->lookup_segndx[segment] >= 0)
-	ndx = dwfl->lookup_segndx[segment];
-      if (++segment >= dwfl->lookup_elts - 1)
-	return next ? ndx + 1 : ndx;
-    }
-  while (dwfl->lookup_addr[segment] < addr);
-
-  if (next)
-    {
-      while (dwfl->lookup_segndx[segment] < 0)
-	if (++segment >= dwfl->lookup_elts - 1)
-	  return ndx + 1;
-      ndx = dwfl->lookup_segndx[segment];
-    }
-
-  return ndx;
-}
-
-int
-dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
-			    Dwfl_Memory_Callback *memory_callback,
-			    void *memory_callback_arg,
-			    Dwfl_Module_Callback *read_eagerly,
-			    void *read_eagerly_arg)
-{
-  size_t segment = ndx;
-
-  if (segment >= dwfl->lookup_elts)
-    segment = dwfl->lookup_elts - 1;
-
-  while (segment > 0
-	 && (dwfl->lookup_segndx[segment] > ndx
-	     || dwfl->lookup_segndx[segment] == -1))
-    --segment;
-
-  while (dwfl->lookup_segndx[segment] < ndx)
-    if (++segment == dwfl->lookup_elts)
-      return 0;
-
-  GElf_Addr start = dwfl->lookup_addr[segment];
-
-  inline bool segment_read (int segndx,
-			    void **buffer, size_t *buffer_available,
-			    GElf_Addr addr, size_t minread)
-  {
-    return ! (*memory_callback) (dwfl, segndx, buffer, buffer_available,
-				 addr, minread, memory_callback_arg);
-  }
-
-  inline void release_buffer (void **buffer, size_t *buffer_available)
-  {
-    if (*buffer != NULL)
-      (void) segment_read (-1, buffer, buffer_available, 0, 0);
-  }
-
-  /* First read in the file header and check its sanity.  */
-
-  void *buffer = NULL;
-  size_t buffer_available = INITIAL_READ;
-
-  inline int finish (void)
-  {
-    release_buffer (&buffer, &buffer_available);
-    return ndx;
-  }
-
-  if (segment_read (ndx, &buffer, &buffer_available,
-		    start, sizeof (Elf64_Ehdr))
-      || memcmp (buffer, ELFMAG, SELFMAG) != 0)
-    return finish ();
-
-  inline bool read_portion (void **data, size_t *data_size,
-			    GElf_Addr vaddr, size_t filesz)
-  {
-    if (vaddr - start + filesz > buffer_available
-	/* If we're in string mode, then don't consider the buffer we have
-	   sufficient unless it contains the terminator of the string.  */
-	|| (filesz == 0 && memchr (vaddr - start + buffer, '\0',
-				   buffer_available - (vaddr - start)) == NULL))
-      {
-	*data = NULL;
-	*data_size = filesz;
-	return segment_read (addr_segndx (dwfl, segment, vaddr, false),
-			     data, data_size, vaddr, filesz);
-      }
-
-    /* We already have this whole note segment from our initial read.  */
-    *data = vaddr - start + buffer;
-    *data_size = 0;
-    return false;
-  }
-
-  inline void finish_portion (void **data, size_t *data_size)
-  {
-    if (*data_size != 0)
-      release_buffer (data, data_size);
-  }
-
-  /* Extract the information we need from the file header.  */
-  union
-  {
-    Elf32_Ehdr e32;
-    Elf64_Ehdr e64;
-  } ehdr;
-  GElf_Off phoff;
-  uint_fast16_t phnum;
-  uint_fast16_t phentsize;
-  GElf_Off shdrs_end;
-  Elf_Data xlatefrom =
-    {
-      .d_type = ELF_T_EHDR,
-      .d_buf = (void *) buffer,
-      .d_version = EV_CURRENT,
-    };
-  Elf_Data xlateto =
-    {
-      .d_type = ELF_T_EHDR,
-      .d_buf = &ehdr,
-      .d_size = sizeof ehdr,
-      .d_version = EV_CURRENT,
-    };
-  switch (((const unsigned char *) buffer)[EI_CLASS])
-    {
-    case ELFCLASS32:
-      xlatefrom.d_size = sizeof (Elf32_Ehdr);
-      if (elf32_xlatetom (&xlateto, &xlatefrom,
-			  ((const unsigned char *) buffer)[EI_DATA]) == NULL)
-	return finish ();
-      phoff = ehdr.e32.e_phoff;
-      phnum = ehdr.e32.e_phnum;
-      phentsize = ehdr.e32.e_phentsize;
-      if (phentsize != sizeof (Elf32_Phdr))
-	return finish ();
-      shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize;
-      break;
-
-    case ELFCLASS64:
-      xlatefrom.d_size = sizeof (Elf64_Ehdr);
-      if (elf64_xlatetom (&xlateto, &xlatefrom,
-			  ((const unsigned char *) buffer)[EI_DATA]) == NULL)
-	return finish ();
-      phoff = ehdr.e64.e_phoff;
-      phnum = ehdr.e64.e_phnum;
-      phentsize = ehdr.e64.e_phentsize;
-      if (phentsize != sizeof (Elf64_Phdr))
-	return finish ();
-      shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize;
-      break;
-
-    default:
-      return finish ();
-    }
-
-  /* The file header tells where to find the program headers.
-     These are what we need to find the boundaries of the module.
-     Without them, we don't have a module to report.  */
-
-  if (phnum == 0)
-    return finish ();
-
-  xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR;
-  xlatefrom.d_size = phnum * phentsize;
-
-  void *ph_buffer = NULL;
-  size_t ph_buffer_size = 0;
-  if (read_portion (&ph_buffer, &ph_buffer_size,
-		    start + phoff, xlatefrom.d_size))
-    return finish ();
-
-  xlatefrom.d_buf = ph_buffer;
-
-  union
-  {
-    Elf32_Phdr p32[phnum];
-    Elf64_Phdr p64[phnum];
-  } phdrs;
-
-  xlateto.d_buf = &phdrs;
-  xlateto.d_size = sizeof phdrs;
-
-  /* Track the bounds of the file visible in memory.  */
-  GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end.  */
-  GElf_Off file_end = 0;	 /* Rounded up to effective page size.  */
-  GElf_Off contiguous = 0;	 /* Visible as contiguous file from START.  */
-  GElf_Off total_filesz = 0;	 /* Total size of data to read.  */
-
-  /* Collect the bias between START and the containing PT_LOAD's p_vaddr.  */
-  GElf_Addr bias = 0;
-  bool found_bias = false;
-
-  /* Collect the unbiased bounds of the module here.  */
-  GElf_Addr module_start = -1l;
-  GElf_Addr module_end = 0;
-  GElf_Addr module_address_sync = 0;
-
-  /* If we see PT_DYNAMIC, record it here.  */
-  GElf_Addr dyn_vaddr = 0;
-  GElf_Xword dyn_filesz = 0;
-
-  /* Collect the build ID bits here.  */
-  void *build_id = NULL;
-  size_t build_id_len = 0;
-  GElf_Addr build_id_vaddr = 0;
-
-  /* Consider a PT_NOTE we've found in the image.  */
-  inline void consider_notes (GElf_Addr vaddr, GElf_Xword filesz)
-  {
-    /* If we have already seen a build ID, we don't care any more.  */
-    if (build_id != NULL || filesz == 0)
-      return;
-
-    void *data;
-    size_t data_size;
-    if (read_portion (&data, &data_size, vaddr, filesz))
-      return;
-
-    assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr));
-
-    void *notes;
-    if (ehdr.e32.e_ident[EI_DATA] == MY_ELFDATA)
-      notes = data;
-    else
-      {
-	notes = malloc (filesz);
-	if (unlikely (notes == NULL))
-	  return;
-	xlatefrom.d_type = xlateto.d_type = ELF_T_NHDR;
-	xlatefrom.d_buf = (void *) data;
-	xlatefrom.d_size = filesz;
-	xlateto.d_buf = notes;
-	xlateto.d_size = filesz;
-	if (elf32_xlatetom (&xlateto, &xlatefrom,
-			    ehdr.e32.e_ident[EI_DATA]) == NULL)
-	  goto done;
-      }
-
-    const GElf_Nhdr *nh = notes;
-    while ((const void *) nh < (const void *) notes + filesz)
-     {
-	const void *note_name = nh + 1;
-	const void *note_desc = note_name + NOTE_ALIGN (nh->n_namesz);
-	if (unlikely ((size_t) ((const void *) notes + filesz
-				- note_desc) < nh->n_descsz))
-	  break;
-
-	if (nh->n_type == NT_GNU_BUILD_ID
-	    && nh->n_descsz > 0
-	    && nh->n_namesz == sizeof "GNU"
-	    && !memcmp (note_name, "GNU", sizeof "GNU"))
-	  {
-	    build_id_vaddr = note_desc - (const void *) notes + vaddr;
-	    build_id_len = nh->n_descsz;
-	    build_id = malloc (nh->n_descsz);
-	    if (likely (build_id != NULL))
-	      memcpy (build_id, note_desc, build_id_len);
-	    break;
-	  }
-
-	nh = note_desc + NOTE_ALIGN (nh->n_descsz);
-      }
-
-  done:
-    if (notes != data)
-      free (notes);
-    finish_portion (&data, &data_size);
-  }
-
-  /* Consider each of the program headers we've read from the image.  */
-  inline void consider_phdr (GElf_Word type,
-			     GElf_Addr vaddr, GElf_Xword memsz,
-			     GElf_Off offset, GElf_Xword filesz,
-			     GElf_Xword align)
-  {
-    switch (type)
-      {
-      case PT_DYNAMIC:
-	dyn_vaddr = vaddr;
-	dyn_filesz = filesz;
-	break;
-
-      case PT_NOTE:
-	/* We calculate from the p_offset of the note segment,
-	   because we don't yet know the bias for its p_vaddr.  */
-	consider_notes (start + offset, filesz);
-	break;
-
-      case PT_LOAD:
-	align = dwfl->segment_align > 1 ? dwfl->segment_align : align ?: 1;
-
-	GElf_Addr vaddr_end = (vaddr + memsz + align - 1) & -align;
-	GElf_Addr filesz_vaddr = filesz < memsz ? vaddr + filesz : vaddr_end;
-	GElf_Off filesz_offset = filesz_vaddr - vaddr + offset;
-
-	if (file_trimmed_end < offset + filesz)
-	  {
-	    file_trimmed_end = offset + filesz;
-
-	    /* Trim the last segment so we don't bother with zeros
-	       in the last page that are off the end of the file.
-	       However, if the extra bit in that page includes the
-	       section headers, keep them.  */
-	    if (shdrs_end <= filesz_offset && shdrs_end > file_trimmed_end)
-	      {
-		filesz += shdrs_end - file_trimmed_end;
-		file_trimmed_end = shdrs_end;
-	      }
-	  }
-
-	total_filesz += filesz;
-
-	if (file_end < filesz_offset)
-	  {
-	    file_end = filesz_offset;
-	    if (filesz_vaddr - start == filesz_offset)
-	      contiguous = file_end;
-	  }
-
-	if (!found_bias && (offset & -align) == 0
-	    && likely (filesz_offset >= phoff + phnum * phentsize))
-	  {
-	    bias = start - vaddr;
-	    found_bias = true;
-	  }
-
-	if ((vaddr & -align) < module_start)
-	  {
-	    module_start = vaddr & -align;
-	    module_address_sync = vaddr + memsz;
-	  }
-
-	if (module_end < vaddr_end)
-	  module_end = vaddr_end;
-	break;
-      }
-  }
-  if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
-    {
-      if (elf32_xlatetom (&xlateto, &xlatefrom,
-			  ehdr.e32.e_ident[EI_DATA]) == NULL)
-	found_bias = false;	/* Trigger error check.  */
-      else
-	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  consider_phdr (phdrs.p32[i].p_type,
-			 phdrs.p32[i].p_vaddr, phdrs.p32[i].p_memsz,
-			 phdrs.p32[i].p_offset, phdrs.p32[i].p_filesz,
-			 phdrs.p32[i].p_align);
-    }
-  else
-    {
-      if (elf64_xlatetom (&xlateto, &xlatefrom,
-			  ehdr.e32.e_ident[EI_DATA]) == NULL)
-	found_bias = false;	/* Trigger error check.  */
-      else
-	for (uint_fast16_t i = 0; i < phnum; ++i)
-	  consider_phdr (phdrs.p64[i].p_type,
-			 phdrs.p64[i].p_vaddr, phdrs.p64[i].p_memsz,
-			 phdrs.p64[i].p_offset, phdrs.p64[i].p_filesz,
-			 phdrs.p64[i].p_align);
-    }
-
-  finish_portion (&ph_buffer, &ph_buffer_size);
-
-  /* We must have seen the segment covering offset 0, or else the ELF
-     header we read at START was not produced by these program headers.  */
-  if (unlikely (!found_bias))
-    return finish ();
-
-  /* Now we know enough to report a module for sure: its bounds.  */
-  module_start += bias;
-  module_end += bias;
-
-  dyn_vaddr += bias;
-
-  /* Our return value now says to skip the segments contained
-     within the module.  */
-  ndx = addr_segndx (dwfl, segment, module_end, true);
-
-  /* Examine its .dynamic section to get more interesting details.
-     If it has DT_SONAME, we'll use that as the module name.
-     If it has a DT_DEBUG, then it's actually a PIE rather than a DSO.
-     We need its DT_STRTAB and DT_STRSZ to decipher DT_SONAME,
-     and they also tell us the essential portion of the file
-     for fetching symbols.  */
-  GElf_Addr soname_stroff = 0;
-  GElf_Addr dynstr_vaddr = 0;
-  GElf_Xword dynstrsz = 0;
-  bool execlike = false;
-  inline bool consider_dyn (GElf_Sxword tag, GElf_Xword val)
-  {
-    switch (tag)
-      {
-      default:
-	return false;
-
-      case DT_DEBUG:
-	execlike = true;
-	break;
-
-      case DT_SONAME:
-	soname_stroff = val;
-	break;
-
-      case DT_STRTAB:
-	dynstr_vaddr = val;
-	break;
-
-      case DT_STRSZ:
-	dynstrsz = val;
-	break;
-      }
-
-    return soname_stroff != 0 && dynstr_vaddr != 0 && dynstrsz != 0;
-  }
-
-  const size_t dyn_entsize = (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32
-			      ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn));
-  void *dyn_data = NULL;
-  size_t dyn_data_size = 0;
-  if (dyn_filesz != 0 && dyn_filesz % dyn_entsize == 0
-      && ! read_portion (&dyn_data, &dyn_data_size, dyn_vaddr, dyn_filesz))
-    {
-      union
-      {
-	Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
-	Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
-      } dyn;
-
-      xlatefrom.d_type = xlateto.d_type = ELF_T_DYN;
-      xlatefrom.d_buf = (void *) dyn_data;
-      xlatefrom.d_size = dyn_filesz;
-      xlateto.d_buf = &dyn;
-      xlateto.d_size = sizeof dyn;
-
-      if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
-	{
-	  if (elf32_xlatetom (&xlateto, &xlatefrom,
-			      ehdr.e32.e_ident[EI_DATA]) != NULL)
-	    for (size_t i = 0; i < dyn_filesz / sizeof dyn.d32[0]; ++i)
-	      if (consider_dyn (dyn.d32[i].d_tag, dyn.d32[i].d_un.d_val))
-		break;
-	}
-      else
-	{
-	  if (elf64_xlatetom (&xlateto, &xlatefrom,
-			      ehdr.e32.e_ident[EI_DATA]) != NULL)
-	    for (size_t i = 0; i < dyn_filesz / sizeof dyn.d64[0]; ++i)
-	      if (consider_dyn (dyn.d64[i].d_tag, dyn.d64[i].d_un.d_val))
-		break;
-	}
-    }
-  finish_portion (&dyn_data, &dyn_data_size);
-
-  /* We'll use the name passed in or a stupid default if not DT_SONAME.  */
-  if (name == NULL)
-    name = ehdr.e32.e_type == ET_EXEC ? "[exe]" : execlike ? "[pie]" : "[dso]";
-
-  void *soname = NULL;
-  size_t soname_size = 0;
-  if (dynstrsz != 0 && dynstr_vaddr != 0)
-    {
-      /* We know the bounds of the .dynstr section.
-
-	 The DYNSTR_VADDR pointer comes from the .dynamic section
-	 (DT_STRTAB, detected above).  Ordinarily the dynamic linker
-	 will have adjusted this pointer in place so it's now an
-	 absolute address.  But sometimes .dynamic is read-only (in
-	 vDSOs and odd architectures), and sometimes the adjustment
-	 just hasn't happened yet in the memory image we looked at.
-	 So treat DYNSTR_VADDR as an absolute address if it falls
-	 within the module bounds, or try applying the phdr bias
-	 when that adjusts it to fall within the module bounds.  */
-
-      if ((dynstr_vaddr < module_start || dynstr_vaddr >= module_end)
-	  && dynstr_vaddr + bias >= module_start
-	  && dynstr_vaddr + bias < module_end)
-	dynstr_vaddr += bias;
-
-      if (unlikely (dynstr_vaddr + dynstrsz > module_end))
-	dynstrsz = 0;
-
-      /* Try to get the DT_SONAME string.  */
-      if (soname_stroff != 0 && soname_stroff + 1 < dynstrsz
-	  && ! read_portion (&soname, &soname_size,
-			     dynstr_vaddr + soname_stroff, 0))
-	name = soname;
-    }
-
-  /* Now that we have chosen the module's name and bounds, report it.
-     If we found a build ID, report that too.  */
-
-  Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, name,
-						 module_start, module_end);
-  if (likely (mod != NULL) && build_id != NULL
-      && unlikely (INTUSE(dwfl_module_report_build_id) (mod,
-							build_id,
-							build_id_len,
-							build_id_vaddr)))
-    {
-      mod->gc = true;
-      mod = NULL;
-    }
-
-  /* At this point we do not need BUILD_ID or NAME any more.
-     They have been copied.  */
-  free (build_id);
-  finish_portion (&soname, &soname_size);
-
-  if (unlikely (mod == NULL))
-    {
-      ndx = -1;
-      return finish ();
-    }
-
-  /* We have reported the module.  Now let the caller decide whether we
-     should read the whole thing in right now.  */
-
-  const GElf_Off cost = (contiguous < file_trimmed_end ? total_filesz
-			 : buffer_available >= contiguous ? 0
-			 : contiguous - buffer_available);
-  const GElf_Off worthwhile = ((dynstr_vaddr == 0 || dynstrsz == 0) ? 0
-			       : dynstr_vaddr + dynstrsz - start);
-  const GElf_Off whole = MAX (file_trimmed_end, shdrs_end);
-
-  Elf *elf = NULL;
-  if ((*read_eagerly) (MODCB_ARGS (mod), &buffer, &buffer_available,
-		       cost, worthwhile, whole, contiguous,
-		       read_eagerly_arg, &elf)
-      && elf == NULL)
-    {
-      /* The caller wants to read the whole file in right now, but hasn't
-	 done it for us.  Fill in a local image of the virtual file.  */
-
-      void *contents = calloc (1, file_trimmed_end);
-      if (unlikely (contents == NULL))
-	return finish ();
-
-      inline void final_read (size_t offset, GElf_Addr vaddr, size_t size)
-      {
-	void *into = contents + offset;
-	size_t read_size = size;
-	(void) segment_read (addr_segndx (dwfl, segment, vaddr, false),
-			     &into, &read_size, vaddr, size);
-      }
-
-      if (contiguous < file_trimmed_end)
-	{
-	  /* We can't use the memory image verbatim as the file image.
-	     So we'll be reading into a local image of the virtual file.  */
-
-	  inline void read_phdr (GElf_Word type, GElf_Addr vaddr,
-				 GElf_Off offset, GElf_Xword filesz)
-	  {
-	    if (type == PT_LOAD)
-	      final_read (offset, vaddr + bias, filesz);
-	  }
-
-	  if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
-	    for (uint_fast16_t i = 0; i < phnum; ++i)
-	      read_phdr (phdrs.p32[i].p_type, phdrs.p32[i].p_vaddr,
-			 phdrs.p32[i].p_offset, phdrs.p32[i].p_filesz);
-	  else
-	    for (uint_fast16_t i = 0; i < phnum; ++i)
-	      read_phdr (phdrs.p64[i].p_type, phdrs.p64[i].p_vaddr,
-			 phdrs.p64[i].p_offset, phdrs.p64[i].p_filesz);
-	}
-      else
-	{
-	  /* The whole file sits contiguous in memory,
-	     but the caller didn't want to just do it.  */
-
-	  const size_t have = MIN (buffer_available, file_trimmed_end);
-	  memcpy (contents, buffer, have);
-
-	  if (have < file_trimmed_end)
-	    final_read (have, start + have, file_trimmed_end - have);
-	}
-
-      elf = elf_memory (contents, file_trimmed_end);
-      if (unlikely (elf == NULL))
-	free (contents);
-      else
-	elf->flags |= ELF_F_MALLOCED;
-    }
-
-  if (elf != NULL)
-    {
-      /* Install the file in the module.  */
-      mod->main.elf = elf;
-      mod->main.vaddr = module_start - bias;
-      mod->main.address_sync = module_address_sync;
-      mod->main_bias = bias;
-    }
-
-  return finish ();
-}
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index 5aaa778..036f1e4 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -108,8 +108,6 @@ struct Dwfl
   GElf_Off lookup_tail_vaddr;
   GElf_Off lookup_tail_offset;
   int lookup_tail_ndx;
-
-  char *executable_for_core;	/* --executable if --core was specified.  */
 };
 
 #define OFFLINE_REDZONE		0x10000
@@ -442,9 +440,7 @@ typedef bool Dwfl_Module_Callback (Dwfl_Module *mod, void **userdata,
  */
 extern int dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 				       Dwfl_Memory_Callback *memory_callback,
-				       void *memory_callback_arg,
-				       Dwfl_Module_Callback *read_eagerly,
-				       void *read_eagerly_arg);
+				       void *memory_callback_arg);
 
 /* Report a module for entry in the dynamic linker's struct link_map list.
    For each link_map entry, if an existing module resides at its address,
diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c
index 00913fe..489319b 100644
--- a/libdwfl/link_map.c
+++ b/libdwfl/link_map.c
@@ -388,11 +388,21 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
 	  if (name != NULL && mod->main.name == NULL)
 	    mod->main.name = strdup (name);
 	}
-      else if (name != NULL)
+      else
 	{
 	  /* We have to find the file's phdrs to compute along with l_addr
 	     what its runtime address boundaries are.  */
 
+	  if (name == NULL)
+	    switch (iterations)
+	    {
+	      case 1:
+		name = "[exe]";
+		break;
+	      case 2:
+		name = "[vdso]";
+		break;
+	    }
 	  // XXX hook for sysroot
 	  mod = INTUSE(dwfl_report_elf) (dwfl, basename (name),
 					 name, -1, l_addr);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 9b0bbf1..a1cd64b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -196,7 +196,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
 	     testfile69.core.bz2 testfile69.so.bz2 \
 	     testfile70.core.bz2 testfile70.exec.bz2 \
 	     run-dwfllines.sh run-dwfl-report-elf-align.sh \
-	     testfile-dwfl-report-elf-align-shlib.so.bz2
+	     testfile-dwfl-report-elf-align-shlib.so.bz2 \
+	     test-core-lib.so.bz2 test-core.core.bz2 test-core.exec.bz2
 
 if USE_VALGRIND
 valgrind_cmd="valgrind -q --trace-children=yes --error-exitcode=1 --run-libc-freeres=no"
diff --git a/tests/run-addrname-test.sh b/tests/run-addrname-test.sh
index 99abf9d..dd6a8f0 100755
--- a/tests/run-addrname-test.sh
+++ b/tests/run-addrname-test.sh
@@ -292,6 +292,12 @@ l0local2
 ??:0
 EOF
 
+testfiles test-core-lib.so test-core.core test-core.exec
+testrun_compare ../src/addr2line -S -e test-core.exec --core=test-core.core 0x7f67f2aaf619 <<\EOF
+libfunc+0x9
+??:0
+EOF
+
 testfiles testfile65
 testrun_compare ../src/addr2line -S --core=testfile65 0x7fff94bffa30 <<\EOF
 __vdso_time
diff --git a/tests/test-core-lib.so.bz2 b/tests/test-core-lib.so.bz2
new file mode 100755
index 0000000..bb2da88
Binary files /dev/null and b/tests/test-core-lib.so.bz2 differ
diff --git a/tests/test-core.core.bz2 b/tests/test-core.core.bz2
new file mode 100644
index 0000000..4d4346b
Binary files /dev/null and b/tests/test-core.core.bz2 differ
diff --git a/tests/test-core.exec.bz2 b/tests/test-core.exec.bz2
new file mode 100755
index 0000000..49ce551
Binary files /dev/null and b/tests/test-core.exec.bz2 differ


More information about the elfutils-devel mailing list