libdw: Handle DWARF5 DW_FORM_implicit_const. Add dwarf_getabbrevattr_data.
authorMark Wielaard <mark@klomp.org>
Sun, 26 Nov 2017 16:51:11 +0000 (17:51 +0100)
committerMark Wielaard <mark@klomp.org>
Wed, 21 Feb 2018 16:19:33 +0000 (17:19 +0100)
Handle the new DW_FORM_implicit_const. The value of this form is embedded
in the abbrev data (as sleb128) and not in the info DIE data. This also
adds a new function dwarf_getabbrevattr_data which allows getting any
data/value associated with a form. eu-readelf will use this new function
to show the DW_FORM_implicit_const value.

Signed-off-by: Mark Wielaard <mark@klomp.org>
14 files changed:
libdw/ChangeLog
libdw/dwarf_child.c
libdw/dwarf_formsdata.c
libdw/dwarf_formudata.c
libdw/dwarf_getabbrev.c
libdw/dwarf_getabbrevattr.c
libdw/dwarf_getattrs.c
libdw/dwarf_hasattr.c
libdw/libdw.h
libdw/libdw.map
libdw/libdwP.h
libdw/memory-access.h
src/ChangeLog
src/readelf.c

index 35ce554..888e509 100644 (file)
@@ -1,3 +1,22 @@
+2018-02-09  Mark Wielaard  <mark@klomp.org>
+
+       * dwarf_child.c (__libdw_find_attr): Handle DW_FORM_implicit_const.
+       * dwarf_formsdata.c (dwarf_formsdata): Likewise.
+       * dwarf_formudata.c (dwarf_formudata): Likewise.
+       * dwarf_getabbrev.c (__libdw_getabbrev): Likewise.
+       * dwarf_getattrs.c (dwarf_getattrs): Likewise.
+       * dwarf_hasattr.c (dwarf_hasattr): Likewise.
+       * dwarf_getabbrevattr.c (dwarf_getabbrevattr_data): New function
+       that will also return any data associated with the abbrev. Which
+       currently is only for DW_FORM_implicit_const. Based on...
+       (dwarf_getabbrevattr): ... this function. Which now just calls
+       dwarf_getabbrevattr_data.
+       * libdw.h (dwarf_getabbrevattr_data): Declare new function.
+       * libdw.map (ELFUTILS_0.170): Add dwarf_getabbrevattr_data.
+       * libdwP.h (dwarf_getabbrevattr_data): INTDECL.
+       * memory-access.h (__libdw_get_sleb128_unchecked): New inlined
+       function based on __libdw_get_uleb128_unchecked.
+
 2018-02-08  Mark Wielaard  <mark@klomp.org>
 
        * dwarf.h: Add DWARF5 DW_FORMs.
index 248338e..9446b88 100644 (file)
@@ -77,7 +77,12 @@ __libdw_find_attr (Dwarf_Die *die, unsigned int search_name,
          if (formp != NULL)
            *formp = attr_form;
 
-         return (unsigned char *) readp;
+         /* Normally the attribute data comes from the DIE/info,
+            except for implicit_form, where it comes from the abbrev.  */
+         if (attr_form == DW_FORM_implicit_const)
+           return (unsigned char *) attrp;
+         else
+           return (unsigned char *) readp;
        }
 
       /* Skip over the rest of this attribute (if there is any).  */
@@ -92,6 +97,13 @@ __libdw_find_attr (Dwarf_Die *die, unsigned int search_name,
 
          // __libdw_form_val_len will have done a bounds check.
          readp += len;
+
+         // If the value is in the abbrev data, skip it.
+         if (attr_form == DW_FORM_implicit_const)
+           {
+             int64_t attr_value __attribute__((__unused__));
+             get_sleb128_unchecked (attr_value, attrp);
+           }
        }
     }
 
index bc2b508..def32c9 100644 (file)
@@ -1,5 +1,5 @@
 /* Return signed constant represented by attribute.
-   Copyright (C) 2003, 2005, 2014 Red Hat, Inc.
+   Copyright (C) 2003, 2005, 2014, 2017 Red Hat, Inc.
    This file is part of elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2003.
 
@@ -86,6 +86,11 @@ dwarf_formsdata (Dwarf_Attribute *attr, Dwarf_Sword *return_sval)
       get_uleb128 (*return_sval, datap, endp);
       break;
 
+    case DW_FORM_implicit_const:
+      // The data comes from the abbrev, which has been bounds checked.
+      get_sleb128_unchecked (*return_sval, datap);
+      break;
+
     default:
       __libdw_seterrno (DWARF_E_NO_CONSTANT);
       return -1;
index e41981a..9c1644e 100644 (file)
@@ -1,5 +1,5 @@
 /* Return unsigned constant represented by attribute.
-   Copyright (C) 2003-2012, 2014 Red Hat, Inc.
+   Copyright (C) 2003-2012, 2014, 2017 Red Hat, Inc.
    This file is part of elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2003.
 
@@ -221,6 +221,11 @@ dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval)
       get_uleb128 (*return_uval, datap, endp);
       break;
 
+    case DW_FORM_implicit_const:
+      // The data comes from the abbrev, which has been bounds checked.
+      get_sleb128_unchecked (*return_uval, datap);
+      break;
+
     default:
       __libdw_seterrno (DWARF_E_NO_CONSTANT);
       return -1;
index a3a68b3..1e113db 100644 (file)
@@ -132,6 +132,13 @@ __libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu, Dwarf_Off offset,
       if (abbrevp >= end)
        goto invalid;
       get_uleb128 (attrform, abbrevp, end);
+      if (attrform == DW_FORM_implicit_const)
+       {
+         int64_t formval __attribute__((__unused__));
+         if (abbrevp >= end)
+           goto invalid;
+         get_sleb128 (formval, abbrevp, end);
+       }
     }
   while (attrname != 0 && attrform != 0);
 
index 57fe363..54ff604 100644 (file)
@@ -37,8 +37,9 @@
 
 
 int
-dwarf_getabbrevattr (Dwarf_Abbrev *abbrev, size_t idx, unsigned int *namep,
-                    unsigned int *formp, Dwarf_Off *offsetp)
+dwarf_getabbrevattr_data (Dwarf_Abbrev *abbrev, size_t idx,
+                         unsigned int *namep, unsigned int *formp,
+                         Dwarf_Sword *datap, Dwarf_Off *offsetp)
 {
   if (abbrev == NULL)
     return -1;
@@ -48,6 +49,7 @@ dwarf_getabbrevattr (Dwarf_Abbrev *abbrev, size_t idx, unsigned int *namep,
   const unsigned char *start_attrp;
   unsigned int name;
   unsigned int form;
+  Dwarf_Word data;
 
   do
     {
@@ -58,6 +60,11 @@ dwarf_getabbrevattr (Dwarf_Abbrev *abbrev, size_t idx, unsigned int *namep,
       get_uleb128_unchecked (name, attrp);
       get_uleb128_unchecked (form, attrp);
 
+      if (form == DW_FORM_implicit_const)
+       get_sleb128_unchecked (data, attrp);
+      else
+       data = 0;
+
       /* If both values are zero the index is out of range.  */
       if (name == 0 && form == 0)
        return -1;
@@ -69,8 +76,19 @@ dwarf_getabbrevattr (Dwarf_Abbrev *abbrev, size_t idx, unsigned int *namep,
     *namep = name;
   if (formp != NULL)
     *formp = form;
+  if (datap != NULL)
+    *datap = data;
   if (offsetp != NULL)
     *offsetp = (start_attrp - abbrev->attrp) + abbrev->offset;
 
   return 0;
 }
+INTDEF(dwarf_getabbrevattr_data)
+
+int
+dwarf_getabbrevattr (Dwarf_Abbrev *abbrev, size_t idx, unsigned int *namep,
+                    unsigned int *formp, Dwarf_Off *offsetp)
+{
+  return INTUSE(dwarf_getabbrevattr_data) (abbrev, idx, namep, formp,
+                                          NULL, offsetp);
+}
index 7f55faf..50faf98 100644 (file)
@@ -83,7 +83,10 @@ dwarf_getattrs (Dwarf_Die *die, int (*callback) (Dwarf_Attribute *, void *),
       if (remembered_attrp >= offset_attrp)
        {
          /* Fill in the rest.  */
-         attr.valp = (unsigned char *) die_addr;
+         if (attr.form == DW_FORM_implicit_const)
+           attr.valp = (unsigned char *) attrp;
+         else
+           attr.valp = (unsigned char *) die_addr;
          attr.cu = die->cu;
 
          /* Now call the callback function.  */
@@ -104,6 +107,12 @@ dwarf_getattrs (Dwarf_Die *die, int (*callback) (Dwarf_Attribute *, void *),
 
          // __libdw_form_val_len will have done a bounds check.
          die_addr += len;
+
+         if (attr.form == DW_FORM_implicit_const)
+           {
+             int64_t attr_value __attribute__((__unused__));
+             get_sleb128_unchecked (attr_value, attrp);
+           }
        }
     }
   /* NOTREACHED */
index 90b333e..90053b1 100644 (file)
@@ -66,6 +66,12 @@ dwarf_hasattr (Dwarf_Die *die, unsigned int search_name)
 
       if (attr_name == search_name)
        return 1;
+
+      if (attr_form == DW_FORM_implicit_const)
+       {
+         int64_t attr_value __attribute__ ((unused));
+         get_sleb128_unchecked (attr_value, attrp);
+       }
     }
 }
 INTDEF (dwarf_hasattr)
index acc3891..ac43ad9 100644 (file)
@@ -594,6 +594,12 @@ extern int dwarf_getabbrevattr (Dwarf_Abbrev *abbrev, size_t idx,
                                unsigned int *namep, unsigned int *formp,
                                Dwarf_Off *offset);
 
+/* Get specific attribute of abbreviation and any data encoded with it.
+   Specifically for DW_FORM_implicit_const data will be set to the
+   constant value associated.  */
+extern int dwarf_getabbrevattr_data (Dwarf_Abbrev *abbrev, size_t idx,
+                                    unsigned int *namep, unsigned int *formp,
+                                    Dwarf_Sword *datap, Dwarf_Off *offset);
 
 /* Get string from-debug_str section.  */
 extern const char *dwarf_getstring (Dwarf *dbg, Dwarf_Off offset,
index 8d12e89..4577d05 100644 (file)
@@ -349,4 +349,5 @@ ELFUTILS_0.171 {
   global:
     dwarf_die_addr_die;
     dwarf_get_units;
+    dwarf_getabbrevattr_data;
 } ELFUTILS_0.170;
index b31497d..ad55558 100644 (file)
@@ -901,6 +901,7 @@ INTDECL (dwarf_formref_die)
 INTDECL (dwarf_formsdata)
 INTDECL (dwarf_formstring)
 INTDECL (dwarf_formudata)
+INTDECL (dwarf_getabbrevattr_data)
 INTDECL (dwarf_getalt)
 INTDECL (dwarf_getarange_addr)
 INTDECL (dwarf_getarangeinfo)
index ed68bdb..5f96a14 100644 (file)
@@ -139,7 +139,26 @@ __libdw_get_sleb128 (const unsigned char **addrp, const unsigned char *end)
   return INT64_MAX;
 }
 
+static inline int64_t
+__libdw_get_sleb128_unchecked (const unsigned char **addrp)
+{
+  int64_t acc = 0;
+
+  /* Unroll the first step to help the compiler optimize
+     for the common single-byte case.  */
+  get_sleb128_step (acc, *addrp, 0);
+
+  /* Subtract one step, so we don't shift into sign bit.  */
+  const size_t max = len_leb128 (int64_t) - 1;
+  for (size_t i = 1; i < max; ++i)
+    get_sleb128_step (acc, *addrp, i);
+  /* Other implementations set VALUE to INT_MAX in this
+     case.  So we better do this as well.  */
+  return INT64_MAX;
+}
+
 #define get_sleb128(var, addr, end) ((var) = __libdw_get_sleb128 (&(addr), end))
+#define get_sleb128_unchecked(var, addr) ((var) = __libdw_get_sleb128_unchecked (&(addr)))
 
 
 /* We use simple memory access functions in case the hardware allows it.
index a828966..2827366 100644 (file)
@@ -1,3 +1,9 @@
+2018-02-09  Mark Wielaard  <mark@klomp.org>
+
+       * readelf.c (print_debug_abbrev_section): Print the value of a
+       DW_FORM_implicit_const using dwarf_getabbrevattr_data.
+       (attr_callback): Handle DW_FORM_implicit_const.
+
 2018-01-30  Mark Wielaard  <mark@klomp.org>
 
        * readelf.c (dwarf_unit_string): New function.
index 93bc45d..bdeba4b 100644 (file)
@@ -4758,14 +4758,16 @@ print_debug_abbrev_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
          size_t cnt = 0;
          unsigned int name;
          unsigned int form;
+         Dwarf_Sword data;
          Dwarf_Off enoffset;
-         while (dwarf_getabbrevattr (&abbrev, cnt,
-                                     &name, &form, &enoffset) == 0)
+         while (dwarf_getabbrevattr_data (&abbrev, cnt, &name, &form,
+                                          &data, &enoffset) == 0)
            {
-             printf ("          attr: %s, form: %s, offset: %#" PRIx64 "\n",
-                     dwarf_attr_name (name), dwarf_form_name (form),
-                     (uint64_t) enoffset);
-
+             printf ("          attr: %s, form: %s",
+                     dwarf_attr_name (name), dwarf_form_name (form));
+             if (form == DW_FORM_implicit_const)
+               printf (" (%" PRId64 ")", data);
+             printf (", offset: %#" PRIx64 "\n", (uint64_t) enoffset);
              ++cnt;
            }
 
@@ -6078,6 +6080,7 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
       break;
 
     case DW_FORM_sec_offset:
+    case DW_FORM_implicit_const:
     case DW_FORM_udata:
     case DW_FORM_sdata:
     case DW_FORM_data8: