[COMMITTED] readelf: Fix crash on reading loc data or range data with bad/no CUs.

2018-01-25 Thread Mark Wielaard
In print_debug_ranges_section and print_debug_loc_section we try to
get the associated CU through skip_listptr_hole for the first data data.
If no CU at all can be found (because the .debug_info section was bogus)
this would keep the Dwarf_CU uninitialized causing a crash later on
when it was compared to the last_cu and used because it was unequal.
Fix this by explicitly initializing cu to last_cu (which is NULL on
first use).

Signed-off-by: Mark Wielaard 
---
 src/ChangeLog | 5 +
 src/readelf.c | 4 ++--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/src/ChangeLog b/src/ChangeLog
index 49b0cc0..a0bb7a2 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,8 @@
+2018-01-25  Mark Wielaard  
+
+   * readelf.c (print_debug_ranges_section): Initialize cu to last_cu.
+   (print_debug_loc_section): Likewise.
+
 2018-01-01  Mark Wielaard  
 
* readelf.c (attr_callback): Use dwarf_form_name for unknown forms.
diff --git a/src/readelf.c b/src/readelf.c
index 4bdaef2..6c49d30 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -5014,7 +5014,7 @@ print_debug_ranges_section (Dwfl_Module *dwflmod,
   while (readp < endp)
 {
   ptrdiff_t offset = readp - (unsigned char *) data->d_buf;
-  Dwarf_CU *cu;
+  Dwarf_CU *cu = last_cu;
 
   if (first && skip_listptr_hole (&known_rangelistptr, &listptr_idx,
  &address_size, NULL, &base, &cu,
@@ -7140,7 +7140,7 @@ print_debug_loc_section (Dwfl_Module *dwflmod,
   while (readp < endp)
 {
   ptrdiff_t offset = readp - (unsigned char *) data->d_buf;
-  Dwarf_CU *cu;
+  Dwarf_CU *cu = last_cu;
 
   if (first && skip_listptr_hole (&known_loclistptr, &listptr_idx,
  &address_size, &offset_size, &base,
-- 
1.8.3.1



[COMMITTED] tests: Check symtabshdr instead of symtabndx in elfstrmerge.c.

2018-01-25 Thread Mark Wielaard
Some gcc omptimization levels (-Og in particular) didn't see that when
symtabndx != 0, then symtabshdr was certain to be initialized. Change
the symtabndx == 0 check to symtabshdr == NULL and initialize symtabshdr
to work around that.

Signed-off-by: Mark Wielaard 
---
 tests/ChangeLog | 11 ---
 tests/elfstrmerge.c |  4 ++--
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/tests/ChangeLog b/tests/ChangeLog
index 758f20e..be203ad 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,8 @@
+2018-01-25  Mark Wielaard  
+
+   * elfstrmerge.c (main): Initialize and check symtabshdr instead of
+   symtabndx.
+
 2018-01-14  Petr Machata  
 
* testfile-sizes4.o.bz2: New test file.
 
diff --git a/tests/elfstrmerge.c b/tests/elfstrmerge.c
index 8d5b53c..6924d0e 100644
--- a/tests/elfstrmerge.c
+++ b/tests/elfstrmerge.c
@@ -195,7 +195,7 @@ main (int argc, char **argv)
   size_t symtabndx = 0;
   Elf_Scn *symtabscn = NULL;
   GElf_Shdr symtabshdr_mem;
-  GElf_Shdr *symtabshdr;
+  GElf_Shdr *symtabshdr = NULL;
   while ((symtabscn = elf_nextscn (elf, symtabscn)) != NULL)
 {
   symtabshdr = gelf_getshdr (symtabscn, &symtabshdr_mem);
@@ -210,7 +210,7 @@ main (int argc, char **argv)
}
 }
 
-  if (symtabndx == 0)
+  if (symtabshdr == NULL)
 fail ("No symtab found", fname);
 
   if ((symtabshdr->sh_flags & SHF_ALLOC) != 0)
-- 
1.8.3.1



[PATCH] libdw: Add dwarf_die_addr_die function.

2018-01-25 Thread Mark Wielaard
Currently storing a lot of Dwarf_Dies might be inefficient since it
costs a lot of memory since the sizeof (Dwarf_Die) == 32 bytes on 64bit
arches. You can try storing just the Dwarf_Off from dwarf_dieoffset.
Which is just 8 bytes. But then you have to keep track of whether to
call dwarf_dieoffset, if the Dwarf_Die came from the main .debug_info,
or call dwarf_dieoffset_types, if it came from .debug_types. And you'll
have to keep track of whether it came from the main Dwarf or the alt
Dwarf (dwz multi file). With DWARF5 or GNU DebugFission split-dwarf
you will also need to know which split Dwarf file the original DIE
came from.

A Dwarf_Die consists of an addr pointer where the actual DIE data
comes from, a CU pointer that provides context (and has a pointer
to the Dwarf file the Die is associated with) and a (cached)
Dwarf_Abbrev pointer that is initialized when the Dwarf_Die is
first read and describes how to interpret the DIE data.

libdw already keeps track of the data pointers (sections) of a
Dwarf file and given an offset it can already reconstruct the
other Dwarf_Die fields. So this patch introduces dwarf_die_addr_die.
Given a Dwarf_Die addr dwarf_die_addr_die returns a (reconstructed)
Dwarf_Die, or NULL if the given addr didn't come from a valid
Dwarf_Die. In particular it will make sure that the correct Dwarf_CU
pointer is set for the Dwarf_Die, the Dwarf_Abbrev pointer will not
be set up yet (it will only be once the Dwarf_Die is used to read
attributes, children or siblings).

This functions can be used to keep a reference to a Dwarf_Die which
you want to refer to later. The addr, and the result of this function,
is only valid while the associated Dwarf is valid.

Since libdw already had to lookup the Dwarf_CU given an offset, this
function is as efficient as dwarf_dieoffset (or dwarf_dieoffset_types)
without having to know the original origin of the Dwarf_Die. It will
search both the .debug_info and .debug_types data sections from both
the main Dwarf or the alt Dwarf file. Once split dwarf support is added
it will also look in any split dwarf .dwo (or the .dwp) file.

The only limitation, compared to using a Dwarf_Off and dwarf_dieoffset,
is that it only works during runtime while the main Dwarf object is
valid (till dwarf_end has been called on it).

Signed-off-by: Mark Wielaard 
---
 libdw/ChangeLog |   9 +++
 libdw/Makefile.am   |   3 +-
 libdw/dwarf_die_addr_die.c  |  58 ++
 libdw/libdw.h   |  12 +++
 libdw/libdw.map |   5 ++
 libdw/libdwP.h  |   4 +
 libdw/libdw_findcu.c|  35 +++-
 tests/ChangeLog |   9 +++
 tests/Makefile.am   |   9 ++-
 tests/dwarf-die-addr-die.c  | 172 
 tests/run-dwarf-die-addr-die.sh |  38 +
 11 files changed, 349 insertions(+), 5 deletions(-)
 create mode 100644 libdw/dwarf_die_addr_die.c
 create mode 100644 tests/dwarf-die-addr-die.c
 create mode 100755 tests/run-dwarf-die-addr-die.sh

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index cb5e61a..37edcd7 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,12 @@
+2018-01-25  Mark Wielaard  
+
+   * Makefile.am (libdw_a_SOURCES): Add dwarf_die_addr_die.c.
+   * dwarf_die_addr_die.c: New file.
+   * libdw.h (dwarf_die_addr_die): New function declaration.
+   * libdw.map (ELFUTILS_0.171): New section with dwarf_die_addr_die.
+   * libdwP.h (__libdw_findcu_addr): New internal function declaration.
+   * libdw_findcu.c (__libdw_findcu_addr): New internal function.
+
 2018-01-22  Mark Wielaard  
 
* Makefile.am (AM_CPPFLAGS): Add -I libdwelf.
diff --git a/libdw/Makefile.am b/libdw/Makefile.am
index 8545b5b..b1da440 100644
--- a/libdw/Makefile.am
+++ b/libdw/Makefile.am
@@ -89,7 +89,8 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c 
dwarf_getelf.c \
  dwarf_aggregate_size.c dwarf_getlocation_implicit_pointer.c \
  dwarf_getlocation_die.c dwarf_getlocation_attr.c \
  dwarf_getalt.c dwarf_setalt.c dwarf_cu_getdwarf.c \
- dwarf_cu_die.c dwarf_peel_type.c dwarf_default_lower_bound.c
+ dwarf_cu_die.c dwarf_peel_type.c dwarf_default_lower_bound.c \
+ dwarf_die_addr_die.c
 
 if MAINTAINER_MODE
 BUILT_SOURCES = $(srcdir)/known-dwarf.h
diff --git a/libdw/dwarf_die_addr_die.c b/libdw/dwarf_die_addr_die.c
new file mode 100644
index 000..02d63b7
--- /dev/null
+++ b/libdw/dwarf_die_addr_die.c
@@ -0,0 +1,58 @@
+/* Return offset of DIE.
+   Copyright (C) 2018 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
+

Re: [PATCH] libdw: Resolve alt file on first use.

2018-01-25 Thread Mark Wielaard
On Mon, 2018-01-22 at 12:30 +0100, Mark Wielaard wrote:
> +static void
> +find_debug_altlink (Dwarf *dbg)
> +{
> +  const char *altname;
> +  const void *build_id;
> +  ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (dbg,
> > +      &altname,
> > +      &build_id);
> +
> +  /* Couldn't even get the debugaltlink.  It probably doesn't exist.  */
> +  if (build_id_len < 0)
> +return;

Testing under valgrind showed that this should be build_id_len <= 0.
When dwelf_dwarf_gnu_debugaltlink returns 0 it means there was no
.gnu_debugaltlink section at all. A negative return value means the
data found was corrupt. In both cases neither altname nor build_id
might be set up. So I added the following fixup:

diff --git a/libdw/dwarf_getalt.c b/libdw/dwarf_getalt.c
index 7b41a2b..3e5af15 100644
--- a/libdw/dwarf_getalt.c
+++ b/libdw/dwarf_getalt.c
@@ -117,7 +117,7 @@ find_debug_altlink (Dwarf *dbg)
   &build_id);
 
   /* Couldn't even get the debugaltlink.  It probably doesn't exist.  */
-  if (build_id_len < 0)
+  if (build_id_len <= 0)
 return;
 
   const uint8_t *id = (const uint8_t *) build_id;