[patch 2/2] Fix loading core files without build-ids

Jan Kratochvil jan.kratochvil at redhat.com
Fri Apr 26 18:57:39 UTC 2013


Hi,

jankratochvil/move-core

New testcase:
	run-addrname-test.sh -> libfunc+0x9

a follow-up to:
	Re: [commit] [patch] Fix dwfl_report_elf BASE alignment  [Re: pending patches ping#2]
	https://lists.fedorahosted.org/pipermail/elfutils-devel/2013-April/003015.html
	Message-ID: <20130401192624.GA17190 at host2.jankratochvil.net>

With my former patches I improved some cases and regressed different cases, so
with this patch it should behave better in general - but not in 100% cases.
The former code using ELF headers from segments could find more modules but
their proper address was only a luck, sometimes wrong, as proven in the mail
above ELF.

"Fix loading core files without build-ids" - with build-id header the ELF
headers from segments method almost always works, it has more wrong results
when build-ids are missing, therefore even the ELF headers are missing.

elfutils was always fragile by searching for ELF headers in core files
segments first
	/* Now sniff segment contents for modules.  */
and only then trying to adjust them from libc link_map list.
	/* Next, we should follow the chain from DT_DEBUG.  */
+
	/* If content-sniffing already reported a module covering
	   the same area, find that existing module to adjust.
	   The l_ld address is the only one we know for sure
	   to be within the module's own segments (its .dynamic).  */

But that adjustment currently does not work as it uses
	Dwfl_Module *mod = INTUSE(dwfl_addrmodule) (dwfl, l_ld);
but if the module is placed incorrectly one cannot find the proper module by
its address -- by its placement.

IMO one should follow link_map first and fall back to the ELF headers only if
it fails.

Not sure if one should try to map address-non-conflicting files from ELF
headers, this patch does not do it.  (That could better fit case (2) below.)

There are IMO two basic use cases with different pros/cons:

(1) Map address -> symbol: eu-addr2line -S --core=xxx 0xaddress
    Exact modules placement is needed and it is better to report no symbol
    than a wrong symbol.

(2) I want to know all build-ids: eu-unstrip -n --core=xxx
    Modules placement does not matter, excessive output does not matter,
    I need to only install needed debuginfos.

This change will behave better in (1) but it may regress (2), for example in
cases where link_map list is overwritten/corrupted in its middle.

I admit I do not fully understand how the current raw segments ELF headers
reporting code worked and how well it copes with overlapping files due to the
false matches.

Also there are some FIXMEs how this patch could behave better.  But the
current patch should be an improvement (at least for the case (1)) already so
those further fixes for various corner cases can be incremental updates.
Unfortunately it is duplicating more and more the work already done in GDB.

The testcase run-unstrip-n.sh had to be updated:
(a) It was currently reporting filenames like /lib/libc.so.6 but those were
    a false match, the system files do not match build-ids from the core file,
    therefore there should be no successful match to system files.
(b) Current code outputs [exe] and [vdso] in slightly different order.


Thanks,
Jan


commit e88be1bac6665f8905ef1cb6e3003267f92e912d
Author: Jan Kratochvil <jan.kratochvil at redhat.com>
Date:   Fri Apr 26 20:27:10 2013 +0200

    Use DT_DEBUG library search first.
    
    libdwfl/
    2013-04-26  Jan Kratochvil  <jan.kratochvil at redhat.com>
    
    	* argp-std.c (parse_opt) <ARGP_KEY_SUCCESS> <opt->core> <opt->e>: Set
    	executable_for_core before calling dwfl_core_file_report.
    	* core-file.c (dwfl_core_file_report): Move raw segments reporting
    	lower.  New variables vdso_bias, vdso_l_ld and exec_vaddr.  Call also
    	dwfl_segment_report_module for EXEC_VADDR and VDSO_L_LD.  Call
    	dwfl_segment_report_module for raw segments only if LISTED is zero.
    	* dwfl_module_build_id.c (check_notes): Move into
    	__libdwfl_find_elf_build_id.
    	(__libdwfl_find_build_id): Rename to ...
    	(__libdwfl_find_elf_build_id): ... here.  Add parameters build_id_bits,
    	build_id_elfaddr and build_id_len.  Verify MOD vs. ELF.
    	(__libdwfl_find_elf_build_id) (check_notes): Remove parameters mod and
    	set, rename data_vaddr to data_elfaddr.  Do not call found_build_id.
    	(__libdwfl_find_elf_build_id): Update the check_notes caller, do not
    	adjust its data_elfaddr parameter.
    	(__libdwfl_find_build_id): New wrapper of __libdwfl_find_elf_build_id.
    	* libdwflP.h (__libdwfl_find_elf_build_id): New declaration.
    	(dwfl_link_map_report): Add parameters vdso_bias, vdso_l_ld and
    	exec_vaddr.
    	* link_map.c: Include system.h and fcntl.h.
    	(report_r_debug): Add parameters vdso_bias, vdso_l_ld and exec_vaddr,
    	describe them in the function comment.  Delete dwfl_addrmodule call and
    	its dependent code.  Verify build-id before calling dwfl_report_elf,
    	also supply executable_for_core to it and skip vDSO.  Report vdso_bias
    	and vdso_l_ld when found.  Clear exec_vaddr when found.
    	(dwfl_link_map_report): Add parameters vdso_bias, vdso_l_ld and
    	exec_vaddr.
    	(dwfl_link_map_report) (consider_phdr): Add parameter offset.  Set
    	exec_vaddr when found.
    	(dwfl_link_map_report): New variable in_ok.  Try to read IN from
    	EXECUTABLE_FOR_CORE.  Update consider_phdr caller parameters.  Update
    	report_r_debug caller parameters.
    
    tests/
    2013-04-26  Jan Kratochvil  <jan.kratochvil at redhat.com>
    
    	* Makefile.am (EXTRA_DIST): Add test-core-lib.so.bz2,
    	test-core.core.bz2 and test-core.exec.bz2.
    	* run-addrname-test.sh: New test for these files.
    	* run-unstrip-n.sh: Update expected output.
    	* test-core-lib.so.bz2: New file.
    	* test-core.core.bz2: New file.
    	* test-core.exec.bz2: New file.
    
    Signed-off-by: Jan Kratochvil <jan.kratochvil at redhat.com>

diff --git a/libdwfl/argp-std.c b/libdwfl/argp-std.c
index e54f720..c884390 100644
--- a/libdwfl/argp-std.c
+++ b/libdwfl/argp-std.c
@@ -295,6 +295,9 @@ parse_opt (int key, char *arg, struct argp_state *state)
 
 	if (opt->core)
 	  {
+	    if (opt->e)
+	      dwfl->executable_for_core = strdup (opt->e);
+
 	    int fd = open64 (opt->core, O_RDONLY);
 	    if (fd < 0)
 	      {
@@ -330,9 +333,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)
 	  {
diff --git a/libdwfl/core-file.c b/libdwfl/core-file.c
index ac2aa8c..bf6630b 100644
--- a/libdwfl/core-file.c
+++ b/libdwfl/core-file.c
@@ -431,11 +431,47 @@ dwfl_core_file_report (Dwfl *dwfl, Elf *elf)
   /* Now we have NT_AUXV contents.  From here on this processing could be
      used for a live process with auxv read from /proc.  */
 
+  GElf_Addr vdso_bias = 0;
+  GElf_Addr vdso_l_ld = 0;
+  GElf_Addr exec_vaddr = 0;
   int listed = dwfl_link_map_report (dwfl, auxv, auxv_size,
-				     dwfl_elf_phdr_memory_callback, elf);
+				     dwfl_elf_phdr_memory_callback, elf,
+				     &vdso_bias, &vdso_l_ld, &exec_vaddr);
+  if (listed > 0 && (vdso_l_ld != 0 || exec_vaddr != 0))
+    {
+      for (ndx = 0; ndx < (int) phnum; ++ndx)
+	{
+	  GElf_Phdr phdr_mem;
+	  GElf_Phdr *phdr = gelf_getphdr (elf, ndx, &phdr_mem);
+	  if (unlikely (phdr == NULL))
+	    {
+	      __libdwfl_seterrno (DWFL_E_LIBELF);
+	      return -1;
+	    }
+	  if (phdr->p_type != PT_LOAD)
+	    continue;
+	  if (exec_vaddr != 0 && phdr->p_vaddr == exec_vaddr)
+	    dwfl_segment_report_module (dwfl, ndx, "[exe]",
+					&dwfl_elf_phdr_memory_callback, elf,
+					core_file_read_eagerly, elf);
+	  if (vdso_l_ld != 0 && phdr->p_filesz == phdr->p_memsz
+	      && phdr->p_vaddr <= vdso_l_ld
+	      && vdso_l_ld < phdr->p_vaddr + phdr->p_memsz)
+	    {
+	      /* FIXME: Use vdso_bias.  Currently dwfl_segment_report_module
+		 detects the bias on its own.  */
+	      dwfl_segment_report_module (dwfl, ndx, "[vdso]",
+					  &dwfl_elf_phdr_memory_callback, elf,
+					  core_file_read_eagerly, elf);
+	      break;
+	    }
+	}
+    }
 
   /* Now sniff segment contents for modules.  */
   int sniffed = 0;
+  if (listed == 0)
+    {
       ndx = 0;
       do
 	{
@@ -453,6 +489,7 @@ dwfl_core_file_report (Dwfl *dwfl, Elf *elf)
 	    ++ndx;
 	}
       while (ndx < (int) phnum);
+    }
 
   /* We return the number of modules we found if we found any.
      If we found none, we return -1 instead of 0 if there was an
diff --git a/libdwfl/dwfl_module_build_id.c b/libdwfl/dwfl_module_build_id.c
index 98cb9f4..b19bc9c 100644
--- a/libdwfl/dwfl_module_build_id.c
+++ b/libdwfl/dwfl_module_build_id.c
@@ -56,10 +56,17 @@ found_build_id (Dwfl_Module *mod, bool set,
 
 int
 internal_function
-__libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf)
+__libdwfl_find_elf_build_id (Dwfl_Module *mod, Elf *elf,
+			     const void **build_id_bits,
+			     GElf_Addr *build_id_elfaddr, int *build_id_len)
 {
-  int
-  check_notes (Dwfl_Module *mod, bool set, Elf_Data *data, GElf_Addr data_vaddr)
+  {
+    GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
+    assert (mod == NULL || ehdr->e_type == mod->e_type);
+    assert (ehdr->e_type != ET_REL || mod != NULL);
+  }
+
+  int check_notes (Elf_Data *data, GElf_Addr data_elfaddr)
   {
     size_t pos = 0;
     GElf_Nhdr nhdr;
@@ -69,10 +76,13 @@ __libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf)
       if (nhdr.n_type == NT_GNU_BUILD_ID
 	  && nhdr.n_namesz == sizeof "GNU" && !memcmp (data->d_buf + name_pos,
 						       "GNU", sizeof "GNU"))
-	return found_build_id (mod, set,
-			       data->d_buf + desc_pos, nhdr.n_descsz,
-			       data_vaddr == NO_VADDR ? 0
-			       : data_vaddr + desc_pos);
+	{
+	  *build_id_bits = data->d_buf + desc_pos;
+	  *build_id_elfaddr = (data_elfaddr == NO_VADDR
+			       ? 0 : data_elfaddr + desc_pos);
+	  *build_id_len = nhdr.n_descsz;
+	  return 1;
+	}
     return 0;
   }
 
@@ -98,12 +108,11 @@ __libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf)
 	  GElf_Phdr phdr_mem;
 	  GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
 	  if (likely (phdr != NULL) && phdr->p_type == PT_NOTE)
-	    result = check_notes (mod, set,
-				  elf_getdata_rawchunk (elf,
+	    result = check_notes (elf_getdata_rawchunk (elf,
 							phdr->p_offset,
 							phdr->p_filesz,
 							ELF_T_NHDR),
-				  dwfl_adjusted_address (mod, phdr->p_vaddr));
+				  phdr->p_vaddr);
 	}
     }
   else
@@ -117,12 +126,12 @@ __libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf)
 	    GElf_Addr vaddr = 0;
 	    if (!(shdr->sh_flags & SHF_ALLOC))
 	      vaddr = NO_VADDR;
-	    else if (mod->e_type != ET_REL)
-	      vaddr = dwfl_adjusted_address (mod, shdr->sh_addr);
+	    else if (mod == NULL || mod->e_type != ET_REL)
+	      vaddr = shdr->sh_addr;
 	    else if (__libdwfl_relocate_value (mod, elf, &shstrndx,
 					       elf_ndxscn (scn), &vaddr))
 	      vaddr = NO_VADDR;
-	    result = check_notes (mod, set, elf_getdata (scn, NULL), vaddr);
+	    result = check_notes (elf_getdata (scn, NULL), vaddr);
 	  }
       }
     while (result == 0 && (scn = elf_nextscn (elf, scn)) != NULL);
@@ -131,6 +140,24 @@ __libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf)
 }
 
 int
+internal_function
+__libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf)
+{
+  const void *build_id_bits;
+  GElf_Addr build_id_elfaddr;
+  int build_id_len;
+
+  int result = __libdwfl_find_elf_build_id (mod, elf, &build_id_bits,
+					    &build_id_elfaddr, &build_id_len);
+  if (result <= 0)
+    return result;
+
+  GElf_Addr build_id_vaddr = build_id_elfaddr + (build_id_elfaddr != 0
+						 ? mod->main_bias : 0);
+  return found_build_id (mod, set, build_id_bits, build_id_len, build_id_vaddr);
+}
+
+int
 dwfl_module_build_id (Dwfl_Module *mod,
 		      const unsigned char **bits, GElf_Addr *vaddr)
 {
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index 5aaa778..7777b53 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -362,6 +362,16 @@ extern Dwfl_Error __libdwfl_addrcu (Dwfl_Module *mod, Dwarf_Addr addr,
 extern Dwfl_Error __libdwfl_cu_getsrclines (struct dwfl_cu *cu)
   internal_function;
 
+/* Look in ELF for an NT_GNU_BUILD_ID note.  Store it to BUILD_ID_BITS,
+   its vaddr in ELF to BUILD_ID_VADDR (it is unrelocated, even if MOD is not
+   NULL) and store length to BUILD_ID_LEN.  Returns -1 for errors, 1 if it was
+   stored and 0 if no note is found.  MOD may be NULL, MOD must be non-NULL
+   only if ELF is ET_REL.  */
+extern int __libdwfl_find_elf_build_id (Dwfl_Module *mod, Elf *elf,
+					const void **build_id_bits,
+					GElf_Addr *build_id_elfaddr,
+					int *build_id_len);
+
 /* Look in ELF for an NT_GNU_BUILD_ID note.  If SET is true, store it
    in MOD and return its length.  If SET is false, instead compare it
    to that stored in MOD and return 2 if they match, 1 if they do not.
@@ -458,10 +468,18 @@ extern int dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
    only find where to begin if the correct executable file was
    previously reported and preloaded as with dwfl_report_elf.
 
+   Return found l_addr and l_ld fields for vDSO in VDSO_BIAS and
+   VDSO_L_LD respectively.  Return found memory address of start of the
+   executable in EXEC_VADDR.  If either vDSO or executable is not found
+   the referenced addresses are not modified by this function.  Any of
+   these parameters can be NULL.
+
    Returns the number of modules found, or -1 for errors.  */
 extern int dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 				 Dwfl_Memory_Callback *memory_callback,
-				 void *memory_callback_arg);
+				 void *memory_callback_arg,
+				 GElf_Addr *vdso_bias, GElf_Addr *vdso_l_ld,
+				 GElf_Addr *exec_vaddr);
 
 
 /* Avoid PLT entries.  */
diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c
index c79a2bf..8a81c47 100644
--- a/libdwfl/link_map.c
+++ b/libdwfl/link_map.c
@@ -29,9 +29,11 @@
 #include <config.h>
 #include "libdwflP.h"
 #include "../libdw/memory-access.h"
+#include "system.h"
 
 #include <byteswap.h>
 #include <endian.h>
+#include <fcntl.h>
 
 /* This element is always provided and always has a constant value.
    This makes it an easy thing to scan for to discern the format.  */
@@ -221,7 +223,8 @@ addrsize (uint_fast8_t elfclass)
 }
 
 /* Report a module for each struct link_map in the linked list at r_map
-   in the struct r_debug at R_DEBUG_VADDR.
+   in the struct r_debug at R_DEBUG_VADDR.  For vdso_bias, vdso_l_ld and
+   exec_vaddr descriptions see dwfl_link_map_report in libdwflP.h.
 
    For each link_map entry, if an existing module resides at its address,
    this just modifies that module's name and suggested file name.  If
@@ -233,7 +236,9 @@ static int
 report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
 		Dwfl *dwfl, GElf_Addr r_debug_vaddr,
 		Dwfl_Memory_Callback *memory_callback,
-		void *memory_callback_arg)
+		void *memory_callback_arg,
+		GElf_Addr *vdso_bias, GElf_Addr *vdso_l_ld,
+		GElf_Addr *exec_vaddr)
 {
   /* Skip r_version, to aligned r_map field.  */
   GElf_Addr read_vaddr = r_debug_vaddr + addrsize (elfclass);
@@ -351,9 +356,93 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
       /* We have to find the file's phdrs to compute along with l_addr
 	 what its runtime address boundaries are.  */
 
-      // XXX hook for sysroot
-      mod = INTUSE(dwfl_report_elf) (dwfl, basename (name),
-				     name, -1, l_addr);
+      Dwfl_Module *mod = NULL;
+      if (iterations == 1 && dwfl->executable_for_core != NULL)
+	{
+	  /* Find the main executable.
+	     FIXME: Try to also find it via build-id.  */
+	  name = dwfl->executable_for_core;
+	}
+      if (iterations != 2 && name != NULL)
+	{
+	  /* Find a shared library or main executable.  Do not try to
+	     find a file for vDSO (where ITERATIONS equals 2).  */
+
+	  /* This code is mostly inlined dwfl_report_elf.  */
+	  // XXX hook for sysroot
+	  int fd = open64 (name, O_RDONLY);
+	  if (fd >= 0)
+	    {
+	      Elf *elf;
+	      Dwfl_Error error = __libdw_open_file (&fd, &elf, true, false);
+	      if (error == DWFL_E_NOERROR)
+		{
+		  const void *build_id_bits;
+		  GElf_Addr build_id_elfaddr;
+		  int build_id_len;
+		  bool valid = true;
+
+		  /* FIXME: Bias L_ADDR should be computed from the prelink
+		     state in memory (when the file got loaded), not against
+		     the current on-disk file state as is computed below.
+
+		     This verification gives false positive if in-core ELF had
+		     build-id but on-disk ELF does not have any.  But we cannot
+		     reliably find ELF header and/or the ELF build id just from
+		     the link map (and checking core segments is also not
+		     reliable).  */
+
+		  if (__libdwfl_find_elf_build_id (NULL, elf, &build_id_bits,
+						   &build_id_elfaddr,
+						   &build_id_len) > 0
+		      && build_id_elfaddr != 0)
+		    {
+		      GElf_Addr build_id_vaddr = build_id_elfaddr + l_addr;
+		      release_buffer (0);
+		      int segndx = INTUSE(dwfl_addrsegment) (dwfl,
+							     build_id_vaddr,
+							     NULL);
+		      if (! (*memory_callback) (dwfl, segndx,
+						&buffer, &buffer_available,
+						build_id_vaddr, build_id_len,
+						memory_callback_arg)
+			  || memcmp (build_id_bits, buffer, build_id_len) != 0)
+			{
+			  /* File has valid build-id which cannot be verified
+			     in memory.  */
+			  valid = false;
+			}
+		    }
+
+		  if (valid)
+		    // XXX hook for sysroot
+		    mod = __libdwfl_report_elf (dwfl, basename (name), name,
+						fd, elf, l_addr, true);
+		  if (mod == NULL)
+		    {
+		      elf_end (elf);
+		      close (fd);
+		    }
+		}
+	    }
+	}
+      if (mod != NULL && iterations == 1)
+	{
+	  /* Cancel reporting of raw segments for the main executable as
+	     its file has been found now.  */
+	  if (exec_vaddr)
+	    *exec_vaddr = 0;
+	}
+      if (iterations == 2)
+	{
+	  /* vDSO is only reported to the caller, it is never searched
+	     for on the disk.  */
+	  assert (mod == NULL);
+	  if (vdso_bias)
+	    *vdso_bias = l_addr;
+	  if (vdso_l_ld)
+	    *vdso_l_ld = l_ld;
+	}
 
       if (mod != NULL)
 	{
@@ -569,7 +658,9 @@ find_executable (Dwfl *dwfl, GElf_Addr at_phdr, GElf_Addr at_entry,
 int
 dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 		      Dwfl_Memory_Callback *memory_callback,
-		      void *memory_callback_arg)
+		      void *memory_callback_arg,
+		      GElf_Addr *vdso_bias, GElf_Addr *vdso_l_ld,
+		      GElf_Addr *exec_vaddr)
 {
   GElf_Addr r_debug_vaddr = 0;
 
@@ -631,8 +722,8 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
       GElf_Xword dyn_filesz = 0;
       GElf_Addr dyn_bias = (GElf_Addr) -1;
 
-      inline bool consider_phdr (GElf_Word type,
-				 GElf_Addr vaddr, GElf_Xword filesz)
+      inline bool consider_phdr (GElf_Word type, GElf_Addr vaddr,
+				 GElf_Xword filesz, Elf32_Off offset)
       {
 	switch (type)
 	  {
@@ -643,6 +734,8 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 		    == (phdr & (dwfl->segment_align - 1))))
 	      {
 		dyn_bias = phdr - vaddr;
+		if (exec_vaddr)
+		  *exec_vaddr = phdr - offset;
 		return dyn_vaddr != 0;
 	      }
 	    break;
@@ -667,8 +760,65 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 	      .d_size = phnum * phent,
 	      .d_buf = NULL
 	    };
-	  if ((*memory_callback) (dwfl, phdr_segndx, &in.d_buf, &in.d_size,
-				  phdr, phnum * phent, memory_callback_arg))
+	  bool in_ok = (*memory_callback) (dwfl, phdr_segndx, &in.d_buf,
+					   &in.d_size, phdr, phnum * phent,
+					   memory_callback_arg);
+	  if (! in_ok && dwfl->executable_for_core != NULL)
+	    {
+	      /* AUXV -> PHDR -> DYNAMIC
+		 Both AUXV and DYNAMIC should be always present in a core file.
+		 PHDR may be missing in core file, try to read it from
+		 EXECUTABLE_FOR_CORE to find where DYNAMIC is located in the
+		 core file.  */
+
+	      int fd = open (dwfl->executable_for_core, O_RDONLY);
+	      Elf *elf;
+	      Dwfl_Error error = DWFL_E_ERRNO;
+	      if (fd != -1)
+		error = __libdw_open_file (&fd, &elf, true, false);
+	      if (error != DWFL_E_NOERROR)
+		{
+		  __libdwfl_seterrno (error);
+		  return false;
+		}
+	      GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
+	      if (ehdr == NULL)
+		{
+		  elf_end (elf);
+		  close (fd);
+		  __libdwfl_seterrno (DWFL_E_LIBELF);
+		  return false;
+		}
+	      if (ehdr->e_phnum != phnum || ehdr->e_phentsize != phent)
+		{
+		  elf_end (elf);
+		  close (fd);
+		  __libdwfl_seterrno (DWFL_E_BADELF);
+		  return false;
+		}
+	      off_t off = ehdr->e_phoff;
+	      assert (in.d_buf == NULL);
+	      assert (in.d_size == phnum * phent);
+	      in.d_buf = malloc (in.d_size);
+	      if (unlikely (in.d_buf == NULL))
+		{
+		  elf_end (elf);
+		  close (fd);
+		  __libdwfl_seterrno (DWFL_E_NOMEM);
+		  return false;
+		}
+	      ssize_t nread = pread_retry (fd, in.d_buf, in.d_size, off);
+	      elf_end (elf);
+	      close (fd);
+	      if (nread != (ssize_t) in.d_size)
+		{
+		  free (in.d_buf);
+		  __libdwfl_seterrno (DWFL_E_ERRNO);
+		  return false;
+		}
+	      in_ok = true;
+	    }
+	  if (in_ok)
 	    {
 	      union
 	      {
@@ -699,7 +849,8 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 		      for (size_t i = 0; i < phnum; ++i)
 			if (consider_phdr (u->p32[i].p_type,
 					   u->p32[i].p_vaddr,
-					   u->p32[i].p_filesz))
+					   u->p32[i].p_filesz,
+					   u->p32[i].p_offset))
 			  break;
 		    }
 		  else
@@ -707,7 +858,8 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 		      for (size_t i = 0; i < phnum; ++i)
 			if (consider_phdr (u->p64[i].p_type,
 					   u->p64[i].p_vaddr,
-					   u->p64[i].p_filesz))
+					   u->p64[i].p_filesz,
+					   u->p64[i].p_offset))
 			  break;
 		    }
 		}
@@ -830,6 +982,7 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 
   /* Now we can follow the dynamic linker's library list.  */
   return report_r_debug (elfclass, elfdata, dwfl, r_debug_vaddr,
-			 &integrated_memory_callback, &mcb);
+			 &integrated_memory_callback, &mcb,
+			 vdso_bias, vdso_l_ld, exec_vaddr);
 }
 INTDEF (dwfl_link_map_report)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index e10da8a..31c8fba 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -198,7 +198,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/run-unstrip-n.sh b/tests/run-unstrip-n.sh
index 1353b1d..0d93b29 100755
--- a/tests/run-unstrip-n.sh
+++ b/tests/run-unstrip-n.sh
@@ -35,20 +35,20 @@ testfiles testcore-rtlib testcore-rtlib-ppc
 
 testrun_compare ../src/unstrip -n --core=testcore-rtlib <<\EOF
 0x8048000+0x2000 f1c600bc36cb91bf01f9a63a634ecb79aa4c3199 at 0x8048178 . - [exe]
+0xf75e9000+0x1a000 29a103420abe341e92072fb14274e250e4072148 at 0xf75e9164 - - [dso]
+0xf7603000+0x1b0000 0b9bf374699e141e5dfc14757ff42b8c2373b4de at 0xf7603184 - - [dso]
+0xf77b3000+0x9000 c6c5b5e35ab9589d4762ac85b4bd56b1b2720e37 at 0xf77b3164 - - [dso]
 0xf77d6000+0x1000 676560b1b765cde9c2e53f134f4ee354ea894747 at 0xf77d6210 . - linux-gate.so.1
-0xf77b3000+0x9000 c6c5b5e35ab9589d4762ac85b4bd56b1b2720e37 at 0xf77b3164 /lib/librt.so.1 - librt.so.1
-0xf7603000+0x1b0000 0b9bf374699e141e5dfc14757ff42b8c2373b4de at 0xf7603184 /lib/libc.so.6 - libc.so.6
-0xf75e9000+0x1a000 29a103420abe341e92072fb14274e250e4072148 at 0xf75e9164 /lib/libpthread.so.0 - libpthread.so.0
-0xf77d7000+0x21000 6d2cb32650054f1c176d01d48713a4a5e5e84c1a at 0xf77d7124 /lib/ld-linux.so.2 - ld-linux.so.2
+0xf77d7000+0x21000 6d2cb32650054f1c176d01d48713a4a5e5e84c1a at 0xf77d7124 - - ld-linux.so.2
 EOF
 
 testrun_compare ../src/unstrip -n --core=testcore-rtlib-ppc <<\EOF
-0x10000000+0x20000 979b7a26747cc09bd84a42b311b5288c704baea5 at 0x10000174 . - [exe]
 0x100000+0x10000 708b900b05176964512a6b0fe90c2a0c9d73d726 at 0x100334 . - linux-vdso32.so.1
-0xfd50000+0x30000 3f7d21508470322d2f47acddc20ab10516edba99 at 0xfd50164 /lib/librt.so.1 - librt.so.1
-0xfdf0000+0x1c0000 edf3dd232e09d01b90683889bd16b9406c52d4de at 0xfdf0184 /lib/libc.so.6 - libc.so.6
-0xfdb0000+0x40000 f6ee91d4c629bc7dacc10534cb30056914e7e0b5 at 0xfdb0164 /lib/libpthread.so.0 - libpthread.so.0
-0xffb0000+0x50000 edec437a85026a1cf8cda94003706202733130c1 at 0xffb0124 /lib/ld.so.1 - ld.so.1
+0xfd50000+0x30000 3f7d21508470322d2f47acddc20ab10516edba99 at 0xfd50164 . - librt.so.1
+0xfdb0000+0x40000 f6ee91d4c629bc7dacc10534cb30056914e7e0b5 at 0xfdb0164 - - libpthread.so.0
+0xfdf0000+0x1c0000 edf3dd232e09d01b90683889bd16b9406c52d4de at 0xfdf0184 - - [dso]
+0xffb0000+0x50000 edec437a85026a1cf8cda94003706202733130c1 at 0xffb0124 - - ld.so.1
+0x10000000+0x20000 979b7a26747cc09bd84a42b311b5288c704baea5 at 0x10000174 . - [exe]
 EOF
 
 test_cleanup
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