[PATCH] libdw: Search skeleton DIE for split compile unit DIE attributes.

2018-05-17 Thread Mark Wielaard
dwarf_attr_integrate and dwarf_hasattr_integrate should also search
for attributes from the skeleton DIE in case the given DIE is a split
compile unit DIE. Split compile unit DIEs inherit various attributes
from their skeleton unit DIE in DWARF5.

Signed-off-by: Mark Wielaard 
---
 libdw/ChangeLog  |   7 ++
 libdw/dwarf_attr_integrate.c |  15 -
 libdw/dwarf_hasattr_integrate.c  |  16 -
 libdw/libdwP.h   |   2 +-
 tests/ChangeLog  |   9 +++
 tests/Makefile.am|  11 ++--
 tests/attr-integrate-skel.c  | 109 +++
 tests/run-attr-integrate-skel.sh |  52 +++
 8 files changed, 214 insertions(+), 7 deletions(-)
 create mode 100644 tests/attr-integrate-skel.c
 create mode 100755 tests/run-attr-integrate-skel.sh

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index a87a7092..c22811ec 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,10 @@
+2018-05-17  Mark Wielaard  
+
+   * dwarf_attr_integrate.c (dwarf_attr_integrate): Handle split_compile
+   unit DIE, search skeleton_compile unit DIE.
+   * dwarf_hasattr_integrate.c (dwarf_hasattr_integrate): Likewise.
+   * libdwP.h (is_cudie): Check cu is not NULL.
+
 2018-05-15  Mark Wielaard  
 
* Makefile.am (libdw_a_SOURCES): Add libdw_find_split_unit.c.
diff --git a/libdw/dwarf_attr_integrate.c b/libdw/dwarf_attr_integrate.c
index 812d74b9..748d988d 100644
--- a/libdw/dwarf_attr_integrate.c
+++ b/libdw/dwarf_attr_integrate.c
@@ -1,5 +1,5 @@
 /* Return specific DWARF attribute of a DIE, integrating indirections.
-   Copyright (C) 2005 Red Hat, Inc.
+   Copyright (C) 2005, 2018 Red Hat, Inc.
This file is part of elfutils.
 
This file is free software; you can redistribute it and/or modify
@@ -55,6 +55,19 @@ dwarf_attr_integrate (Dwarf_Die *die, unsigned int 
search_name,
 }
   while (die != NULL);
 
+  /* Not NULL if it didn't have abstract_origin and specification
+ attributes.  If it is a split CU then see if the skeleton
+ has it.  */
+  if (die != NULL && is_cudie (die)
+  && die->cu->unit_type == DW_UT_split_compile)
+{
+  Dwarf_CU *skel_cu = __libdw_find_split_unit (die->cu);
+  if (skel_cu != NULL)
+   {
+ Dwarf_Die skel_die = CUDIE (skel_cu);
+ return INTUSE(dwarf_attr) (&skel_die, search_name, result);
+   }
+}
   return NULL;
 }
 INTDEF (dwarf_attr_integrate)
diff --git a/libdw/dwarf_hasattr_integrate.c b/libdw/dwarf_hasattr_integrate.c
index 2d5348cf..4d4b4c54 100644
--- a/libdw/dwarf_hasattr_integrate.c
+++ b/libdw/dwarf_hasattr_integrate.c
@@ -1,5 +1,5 @@
 /* Check whether DIE has specific attribute, integrating DW_AT_abstract_origin.
-   Copyright (C) 2005 Red Hat, Inc.
+   Copyright (C) 2005, 2018 Red Hat, Inc.
This file is part of elfutils.
 
This file is free software; you can redistribute it and/or modify
@@ -55,5 +55,19 @@ dwarf_hasattr_integrate (Dwarf_Die *die, unsigned int 
search_name)
 }
   while (die != NULL);
 
+  /* Not NULL if it didn't have abstract_origin and specification
+ attributes.  If it is a split CU then see if the skeleton
+ has it.  */
+  if (die != NULL && is_cudie (die)
+  && die->cu->unit_type == DW_UT_split_compile)
+{
+  Dwarf_CU *skel_cu = __libdw_find_split_unit (die->cu);
+  if (skel_cu != NULL)
+   {
+ Dwarf_Die skel_die = CUDIE (skel_cu);
+ return INTUSE(dwarf_hasattr) (&skel_die, search_name);
+   }
+}
+
   return 0;
 }
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index 60572276..08d144ba 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -892,7 +892,7 @@ cu_sec_idx (struct Dwarf_CU *cu)
 static inline bool
 is_cudie (Dwarf_Die *cudie)
 {
-  return CUDIE (cudie->cu).addr == cudie->addr;
+  return cudie->cu != NULL && CUDIE (cudie->cu).addr == cudie->addr;
 }
 
 /* Read up begin/end pair and increment read pointer.
diff --git a/tests/ChangeLog b/tests/ChangeLog
index b865ad54..05e8f26c 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,12 @@
+2018-05-17  Mark Wielaard  
+
+   * Makefile.am (check_PROGRAMS): Add attr-integrate-skel.
+   (TESTS): Add run-attr-integrate-skel.
+   (EXTRA_DIST): Likewise.
+   (attr_integrate_skel_LDADD): New variable.
+   * attr-integrate-skel.c: New test.
+   * run-attr-integrate-skel.sh: New test runner.
+
 2018-05-16  Mark Wielaard  
 
* Makefile.am (check_PROGRAMS): Add get-units-split.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 07165d84..05a5441b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,6 +1,6 @@
 ## Process this file with automake to create Makefile.in
 ##
-## Copyright (C) 1996-2017 Red Hat, Inc.
+## Copyright (C) 1996-2018 Red Hat, Inc.
 ## This file is part of elfutils.
 ##
 ## This file is free software; you can redistribute it and/or modify
@@ -56,7 +56,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames 
sectiondump \

[PATCH] libdw: Cache ELF directory early. Explicitly set it in dwfl.

2018-05-17 Thread Mark Wielaard
The logic that finds alt files and dwo files relies on having an open
file descriptor. But after all needed ELF data has been read the
underlying Elf file descriptor can be closed. libdwfl in particular
closes file descriptor fairly aggressively. So capture the directory
early on. And make dwfl set it if it has recorded it. Which it will
do now before closing a file descriptor for the main Dwfl_Module file.

Signed-off-by: Mark Wielaard 
---
 libdw/ChangeLog| 15 ++
 libdw/dwarf_begin_elf.c| 24 +++
 libdw/dwarf_end.c  |  3 +++
 libdw/dwarf_getalt.c   | 44 +++---
 libdw/libdwP.h | 26 +
 libdw/libdw_find_split_unit.c  |  6 +++---
 libdwfl/ChangeLog  | 10 ++
 libdwfl/dwfl_module.c  |  1 +
 libdwfl/dwfl_module_getdwarf.c | 23 --
 libdwfl/libdwflP.h |  2 ++
 libdwfl/offline.c  |  3 +++
 11 files changed, 112 insertions(+), 45 deletions(-)

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index c22811e..0a0728b 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,5 +1,20 @@
 2018-05-17  Mark Wielaard  
 
+   * dwarf_begin_elf.c (__libdw_debugdir): New function.
+   (valid_p): Call __libdw_debugdir.
+   * dwarf_end.c (dwarf_end.c): Free debugdir.
+   * dwarf_getalt.c (__libdw_filepath): Extract __libdw_debugdir logic.
+   take debugdir as argument instead of fd.
+   (find_debug_altlink): Call __libdw_filepath with debugdir.
+   * libdwP.h (struct Dwarf): Add debugdir field.
+   (__libdw_debugdir): New function prototype.
+   (__libdw_filepath): Adjust prototype to take a const char * instead of
+   an int.
+   * libdw_find_split_unit.c (__libdw_find_split_unit): Call
+   __libdw_filepath with debugdir.
+
+2018-05-17  Mark Wielaard  
+
* dwarf_attr_integrate.c (dwarf_attr_integrate): Handle split_compile
unit DIE, search skeleton_compile unit DIE.
* dwarf_hasattr_integrate.c (dwarf_hasattr_integrate): Likewise.
diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c
index 61de752..0e435c5 100644
--- a/libdw/dwarf_begin_elf.c
+++ b/libdw/dwarf_begin_elf.c
@@ -42,6 +42,7 @@
 #include 
 #include 
 
+#include "libelfP.h"
 #include "libdwP.h"
 
 
@@ -184,6 +185,26 @@ check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn 
*scn, bool inscngrp)
 }
 
 
+/* Helper function to set debugdir field.  We want to cache the dir
+   where we found this Dwarf ELF file to locate alt and dwo files.  */
+char *
+__libdw_debugdir (int fd)
+{
+  /* strlen ("/proc/self/fd/") = 14 + strlen () = 10 + 1 = 25.  */
+  char devfdpath[25];
+  sprintf (devfdpath, "/proc/self/fd/%u", fd);
+  char *fdpath = realpath (devfdpath, NULL);
+  char *fddir;
+  if (fdpath != NULL && fdpath[0] == '/'
+  && (fddir = strrchr (fdpath, '/')) != NULL)
+{
+  *++fddir = '\0';
+  return fdpath;
+}
+  return NULL;
+}
+
+
 /* Check whether all the necessary DWARF information is available.  */
 static Dwarf *
 valid_p (Dwarf *result)
@@ -225,6 +246,9 @@ valid_p (Dwarf *result)
}
 }
 
+  if (result != NULL)
+result->debugdir = __libdw_debugdir (result->elf->fildes);
+
   return result;
 }
 
diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c
index 43223de..4702f1b 100644
--- a/libdw/dwarf_end.c
+++ b/libdw/dwarf_end.c
@@ -116,6 +116,9 @@ dwarf_end (Dwarf *dwarf)
  close (dwarf->alt_fd);
}
 
+  /* The cached dir we found the Dwarf ELF file in.  */
+  free (dwarf->debugdir);
+
   /* Free the context descriptor.  */
   free (dwarf);
 }
diff --git a/libdw/dwarf_getalt.c b/libdw/dwarf_getalt.c
index 3e5af15..3339b3e 100644
--- a/libdw/dwarf_getalt.c
+++ b/libdw/dwarf_getalt.c
@@ -47,7 +47,7 @@
 
 char *
 internal_function
-__libdw_filepath (int fd, const char *dir, const char *file)
+__libdw_filepath (const char *debugdir, const char *dir, const char *file)
 {
   if (file == NULL)
 return NULL;
@@ -71,37 +71,25 @@ __libdw_filepath (int fd, const char *dir, const char *file)
   return path;
 }
 
-  if (fd >= 0)
+  if (debugdir != NULL)
 {
-  /* strlen ("/proc/self/fd/") = 14 + strlen () = 10 + 1 = 25.  */
-  char devfdpath[25];
-  sprintf (devfdpath, "/proc/self/fd/%u", fd);
-  char *fdpath = realpath (devfdpath, NULL);
-  char *path = NULL;
-  char *fddir;
-  if (fdpath != NULL && fdpath[0] == '/'
- && (fddir = strrchr (fdpath, '/')) != NULL)
+  size_t debugdirlen = strlen (debugdir);
+  size_t dirlen = dir != NULL ? strlen (dir) : 0;
+  size_t filelen = strlen (file);
+  size_t len = debugdirlen + 1 + dirlen + 1 + filelen + 1;
+  char *path = malloc (len);
+  if (path != NULL)
{
- *++fddir = '\0';
- size_t fdpathlen = strlen (fdpath);
- size_t dirlen = dir != NULL ? strlen (dir) : 0;
- size