This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] libdw: Handle empty location expression for (indirect) DIE locations.


During a discussion on irc and offlist Josh pointed out that tests/varlocs
didn't cleanly handly all of the vmlinux kernel debuginfo. That was because
it flagged a DIE referring to another DIE that didn't actually have an
DW_AT_location as DWARF_E_INVALID_DWARF. Causing varlocs to error out.
But Jakub pointed out that isn't correct. It is valid DWARF, it just means
the dereferrenced value of the synthetic pointer isn't available. So this
patch makes sure that in such situations we don't return an error but just
an empty location expression.

With this varlocs can handle all of the vmlinux debuginfo on my machine.

<- snip ->

When dwarf_getlocation_implicit_pointer and dwarf_getlocation_attr
refer to a DIE that doesn't contain a DW_AT_location then don't generate
an error, but return an empty location expression to signal the actual
value pointed to is not available. This isn't invalid DWARF. Also make
sure that __libdw_intern_expression handles empty location expressions.

Signed-off-by: Mark Wielaard <mjw@redhat.com>
---
 libdw/ChangeLog                            |   11 +++++++++++
 libdw/dwarf_getlocation.c                  |   11 +++++++++--
 libdw/dwarf_getlocation_attr.c             |    8 ++++----
 libdw/dwarf_getlocation_implicit_pointer.c |   16 ++++++++++++++--
 libdw/libdwP.h                             |    4 ++++
 tests/ChangeLog                            |    5 +++++
 tests/varlocs.c                            |    2 +-
 7 files changed, 48 insertions(+), 9 deletions(-)

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 91e1083..79bb4b5 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,14 @@
+2013-12-09  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getlocation.c (__libdw_intern_expression): Handle empty
+	location expressions.
+	* dwarf_getlocation_attr.c (dwarf_getlocation_attr): When no
+	location found, return empty location expression.
+	* dwarf_getlocation_implicit_pointer.c
+	(dwarf_getlocation_implicit_pointer): Likewise.
+	(__libdw_empty_loc_attr): New internal function.
+	* libdwP.h (__libdw_empty_loc_attr): Define.
+
 2013-11-27  Mark Wielaard  <mjw@redhat.com>
 
 	* libdw.map (ELFUTILS_0.158): Add dwfl_module_addrsym_elf and
diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c
index ff25fc7..4124ae3 100644
--- a/libdw/dwarf_getlocation.c
+++ b/libdw/dwarf_getlocation.c
@@ -202,6 +202,13 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
 			   bool cfap, bool valuep,
 			   Dwarf_Op **llbuf, size_t *listlen, int sec_index)
 {
+  /* Empty location expressions don't have any ops to intern.  */
+  if (block->length == 0)
+    {
+      *listlen = 0;
+      return 0;
+    }
+
   /* Check whether we already looked at this list.  */
   struct loc_s fake = { .addr = block->data };
   struct loc_s **found = tfind (&fake, cache, loc_compare);
@@ -465,8 +472,8 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
   if (unlikely (n == 0))
     {
       /* This is not allowed.
-
-	 XXX Is it?  */
+	 It would mean an empty location expression, which we handled
+	 already as a special case above.  */
       goto invalid;
     }
 
diff --git a/libdw/dwarf_getlocation_attr.c b/libdw/dwarf_getlocation_attr.c
index bf15584..cb29045 100644
--- a/libdw/dwarf_getlocation_attr.c
+++ b/libdw/dwarf_getlocation_attr.c
@@ -74,8 +74,8 @@ dwarf_getlocation_attr (attr, op, result)
 	    return -1;
 	  if (INTUSE(dwarf_attr) (&die, DW_AT_location, result) == NULL)
 	    {
-	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
-	      return -1;
+	      __libdw_empty_loc_attr (result, attr->cu);
+	      return 0;
 	    }
 	}
 	break;
@@ -88,8 +88,8 @@ dwarf_getlocation_attr (attr, op, result)
 	  if (INTUSE(dwarf_attr) (&die, DW_AT_location, result) == NULL
 	      && INTUSE(dwarf_attr) (&die, DW_AT_const_value, result) == NULL)
 	    {
-	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
-	      return -1;
+	      __libdw_empty_loc_attr (result, attr->cu);
+	      return 0;
 	    }
 	}
 	break;
diff --git a/libdw/dwarf_getlocation_implicit_pointer.c b/libdw/dwarf_getlocation_implicit_pointer.c
index 322fdb8..f93d17e 100644
--- a/libdw/dwarf_getlocation_implicit_pointer.c
+++ b/libdw/dwarf_getlocation_implicit_pointer.c
@@ -34,6 +34,18 @@
 #include <dwarf.h>
 
 
+static unsigned char empty_exprloc = 0;
+
+void
+internal_function
+__libdw_empty_loc_attr (Dwarf_Attribute *attr, struct Dwarf_CU *cu )
+{
+  attr->code = DW_AT_location;
+  attr->form = DW_FORM_exprloc;
+  attr->valp = &empty_exprloc;
+  attr->cu = cu;
+}
+
 int
 dwarf_getlocation_implicit_pointer (attr, op, result)
      Dwarf_Attribute *attr;
@@ -57,8 +69,8 @@ dwarf_getlocation_implicit_pointer (attr, op, result)
   if (INTUSE(dwarf_attr) (&die, DW_AT_location, result) == NULL
       && INTUSE(dwarf_attr) (&die, DW_AT_const_value, result) == NULL)
     {
-      __libdw_seterrno (DWARF_E_INVALID_DWARF);
-      return -1;
+      __libdw_empty_loc_attr (result, attr->cu);
+      return 0;
     }
 
   return 0;
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index f02a5bf..35ab6e7 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -632,6 +632,10 @@ int __check_build_id (Dwarf *dw, const uint8_t *build_id, const size_t id_len)
   internal_function;
 #endif /* ENABLE_DWZ */
 
+/* Fills in the given attribute to point at an empty location expression.  */
+void __libdw_empty_loc_attr (Dwarf_Attribute *attr, struct Dwarf_CU *cu)
+  internal_function;
+
 
 /* Aliases to avoid PLTs.  */
 INTDECL (dwarf_aggregate_size)
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 9e4cd9a..31638d3 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,8 @@
+2013-12-09  Mark Wielaard  <mjw@redhat.com>
+
+	* varlocs.c (print_expr): Update comment to explain empty location
+	associated with DW_OP_GNU_implicit_pointer.
+
 2013-12-05  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
 	Fix test FAIL with -O2.
diff --git a/tests/varlocs.c b/tests/varlocs.c
index 6f4d490..04f17ff 100644
--- a/tests/varlocs.c
+++ b/tests/varlocs.c
@@ -404,7 +404,7 @@ print_expr (Dwarf_Attribute *attr, Dwarf_Op *expr, Dwarf_Addr addr)
 	    int locs = dwarf_getlocation_addr (&attrval, addr,
 					       &exprval, &exprval_len, 1);
 	    if (locs == 0)
-	      printf ("<no location>"); // XXX should that be flagged?
+	      printf ("<no location>"); // This means "optimized out".
 	    else if (locs == 1)
 	      print_expr_block (&attrval, exprval, exprval_len, addr);
 	    else
-- 
1.7.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]