libdw: Handle empty location expression for (indirect) DIE locations.
authorMark Wielaard <mjw@redhat.com>
Mon, 9 Dec 2013 15:33:26 +0000 (16:33 +0100)
committerMark Wielaard <mjw@redhat.com>
Fri, 13 Dec 2013 13:23:02 +0000 (14:23 +0100)
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
libdw/dwarf_getlocation.c
libdw/dwarf_getlocation_attr.c
libdw/dwarf_getlocation_implicit_pointer.c
libdw/libdwP.h
tests/ChangeLog
tests/varlocs.c

index 91e1083..79bb4b5 100644 (file)
@@ -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
index ff25fc7..4124ae3 100644 (file)
@@ -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;
     }
 
index bf15584..cb29045 100644 (file)
@@ -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;
index 322fdb8..f93d17e 100644 (file)
 #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;
index f02a5bf..35ab6e7 100644 (file)
@@ -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)
index 9e4cd9a..31638d3 100644 (file)
@@ -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.
index 6f4d490..04f17ff 100644 (file)
@@ -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