[PATCH] libdw: Handle DWARF5 DW_FORM_implicit_const. Add dwarf_getabbrevattr_data.

Mark Wielaard mark@klomp.org
Fri Feb 9 17:25:00 GMT 2018


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>
---
 libdw/ChangeLog             | 19 +++++++++++++++++++
 libdw/dwarf_child.c         | 14 +++++++++++++-
 libdw/dwarf_formsdata.c     |  7 ++++++-
 libdw/dwarf_formudata.c     |  7 ++++++-
 libdw/dwarf_getabbrev.c     |  7 +++++++
 libdw/dwarf_getabbrevattr.c | 22 ++++++++++++++++++++--
 libdw/dwarf_getattrs.c      | 11 ++++++++++-
 libdw/dwarf_hasattr.c       |  6 ++++++
 libdw/libdw.h               |  6 ++++++
 libdw/libdw.map             |  1 +
 libdw/libdwP.h              |  1 +
 libdw/memory-access.h       | 19 +++++++++++++++++++
 src/ChangeLog               |  6 ++++++
 src/readelf.c               | 15 +++++++++------
 14 files changed, 129 insertions(+), 12 deletions(-)

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 65e4ddc..f52ce58 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -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.
diff --git a/libdw/dwarf_child.c b/libdw/dwarf_child.c
index 248338e..9446b88 100644
--- a/libdw/dwarf_child.c
+++ b/libdw/dwarf_child.c
@@ -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);
+	    }
 	}
     }
 
diff --git a/libdw/dwarf_formsdata.c b/libdw/dwarf_formsdata.c
index bc2b508..def32c9 100644
--- a/libdw/dwarf_formsdata.c
+++ b/libdw/dwarf_formsdata.c
@@ -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;
diff --git a/libdw/dwarf_formudata.c b/libdw/dwarf_formudata.c
index e41981a..9c1644e 100644
--- a/libdw/dwarf_formudata.c
+++ b/libdw/dwarf_formudata.c
@@ -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;
diff --git a/libdw/dwarf_getabbrev.c b/libdw/dwarf_getabbrev.c
index a3a68b3..1e113db 100644
--- a/libdw/dwarf_getabbrev.c
+++ b/libdw/dwarf_getabbrev.c
@@ -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);
 
diff --git a/libdw/dwarf_getabbrevattr.c b/libdw/dwarf_getabbrevattr.c
index 57fe363..54ff604 100644
--- a/libdw/dwarf_getabbrevattr.c
+++ b/libdw/dwarf_getabbrevattr.c
@@ -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);
+}
diff --git a/libdw/dwarf_getattrs.c b/libdw/dwarf_getattrs.c
index 7f55faf..50faf98 100644
--- a/libdw/dwarf_getattrs.c
+++ b/libdw/dwarf_getattrs.c
@@ -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 */
diff --git a/libdw/dwarf_hasattr.c b/libdw/dwarf_hasattr.c
index 90b333e..90053b1 100644
--- a/libdw/dwarf_hasattr.c
+++ b/libdw/dwarf_hasattr.c
@@ -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)
diff --git a/libdw/libdw.h b/libdw/libdw.h
index acc3891..ac43ad9 100644
--- a/libdw/libdw.h
+++ b/libdw/libdw.h
@@ -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,
diff --git a/libdw/libdw.map b/libdw/libdw.map
index 8d12e89..4577d05 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -349,4 +349,5 @@ ELFUTILS_0.171 {
   global:
     dwarf_die_addr_die;
     dwarf_get_units;
+    dwarf_getabbrevattr_data;
 } ELFUTILS_0.170;
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index b31497d..ad55558 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -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)
diff --git a/libdw/memory-access.h b/libdw/memory-access.h
index ed68bdb..5f96a14 100644
--- a/libdw/memory-access.h
+++ b/libdw/memory-access.h
@@ -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.
diff --git a/src/ChangeLog b/src/ChangeLog
index c724c6a..ebd6f55 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -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.
diff --git a/src/readelf.c b/src/readelf.c
index 4449584..c57d7fe 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -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:
-- 
1.8.3.1



More information about the Elfutils-devel mailing list