[PATCH] libdw: Add support for reading DW_FORM_strx[1234] in .debug_str_offsets.

Mark Wielaard mark@klomp.org
Fri Mar 30 15:57:00 GMT 2018


Recognize the new .debug_str_offsets section. The CU will now hold a new
str_off_base offset in that section for that CU. dwarf_form_string will
decode DW_FORM_strx[1234] and return strings using that str_off_base
from the .debug_addr.

Signed-off-by: Mark Wielaard <mark@klomp.org>
---
 libdw/ChangeLog          |  13 +++++
 libdw/dwarf_begin_elf.c  |   5 +-
 libdw/dwarf_error.c      |   1 +
 libdw/dwarf_formstring.c | 124 +++++++++++++++++++++++++++++++++++++++++++----
 libdw/dwarf_formudata.c  |   8 +++
 libdw/libdwP.h           |   9 ++++
 src/ChangeLog            |   4 ++
 src/readelf.c            |   5 ++
 8 files changed, 158 insertions(+), 11 deletions(-)

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 8423cb3..a5bb6c4 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,16 @@
+2018-03-23  Mark Wielaard  <mark@klomp.org>
+
+	* dwarf_begin_elf.c (dwarf_scnnames): Add IDX_debug_str_offsets,
+	increase size.
+	* dwarf_error.c (errmsgs): Add DWARF_E_NO_STR_OFFSETS.
+	* dwarf_formstring.c (dwarf_formstring): Handle DW_FORM_strx[1234].
+	(__libdw_cu_str_off_base): New function.
+	* dwarf_formudata.c (dwarf_formudata): Handle IDX_debug_str_offsets
+	as stroffsetsptr.
+	* libdwP.h: Add IDX_debug_str_offsets and DWARF_E_NO_STR_OFFSETS.
+	(struct Dwarf_CU): Add str_off_base field.
+	(__libdw_cu_str_off_base): New function declaration.
+
 2018-03-22  Mark Wielaard  <mark@klomp.org>
 
 	* dwarf_begin_elf.c (dwarf_scnnames): Add IDX_debug_addr.
diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c
index 1ffa6c9..19a5fbb 100644
--- a/libdw/dwarf_begin_elf.c
+++ b/libdw/dwarf_begin_elf.c
@@ -46,8 +46,8 @@
 #include "libdwP.h"
 
 
-/* Section names.  */
-static const char dwarf_scnnames[IDX_last][18] =
+/* Section names.  (Note .debug_str_offsets is the largest 19 chars.)  */
+static const char dwarf_scnnames[IDX_last][19] =
 {
   [IDX_debug_info] = ".debug_info",
   [IDX_debug_types] = ".debug_types",
@@ -59,6 +59,7 @@ static const char dwarf_scnnames[IDX_last][18] =
   [IDX_debug_loc] = ".debug_loc",
   [IDX_debug_pubnames] = ".debug_pubnames",
   [IDX_debug_str] = ".debug_str",
+  [IDX_debug_str_offsets] = ".debug_str_offsets",
   [IDX_debug_macinfo] = ".debug_macinfo",
   [IDX_debug_macro] = ".debug_macro",
   [IDX_debug_ranges] = ".debug_ranges",
diff --git a/libdw/dwarf_error.c b/libdw/dwarf_error.c
index 212f32e..cbf573f 100644
--- a/libdw/dwarf_error.c
+++ b/libdw/dwarf_error.c
@@ -73,6 +73,7 @@ static const char *errmsgs[] =
     [DWARF_E_NO_ENTRY] = N_("no entries found"),
     [DWARF_E_INVALID_DWARF] = N_("invalid DWARF"),
     [DWARF_E_NO_STRING] = N_("no string data"),
+    [DWARF_E_NO_STR_OFFSETS] = N_(".debug_str_offsets section missing"),
     [DWARF_E_NO_ADDR] = N_("no address value"),
     [DWARF_E_NO_CONSTANT] = N_("no constant value"),
     [DWARF_E_NO_REFERENCE] = N_("no reference value"),
diff --git a/libdw/dwarf_formstring.c b/libdw/dwarf_formstring.c
index 4eae0ed..39766ad 100644
--- a/libdw/dwarf_formstring.c
+++ b/libdw/dwarf_formstring.c
@@ -1,7 +1,6 @@
 /* Return string associated with given attribute.
    Copyright (C) 2003-2010, 2013, 2018 Red Hat, Inc.
    This file is part of elfutils.
-   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
 
    This file is free software; you can redistribute it and/or modify
    it under the terms of either
@@ -47,7 +46,8 @@ dwarf_formstring (Dwarf_Attribute *attrp)
     /* A simple inlined string.  */
     return (const char *) attrp->valp;
 
-  Dwarf *dbg = attrp->cu->dbg;
+  Dwarf_CU *cu = attrp->cu;
+  Dwarf *dbg = cu->dbg;
   Dwarf *dbg_ret = (attrp->form == DW_FORM_GNU_strp_alt
 		    ? INTUSE(dwarf_getalt) (dbg) : dbg);
 
@@ -57,20 +57,126 @@ dwarf_formstring (Dwarf_Attribute *attrp)
       return NULL;
     }
 
-
-  if (unlikely (attrp->form != DW_FORM_strp
-		   && attrp->form != DW_FORM_GNU_strp_alt)
-      || dbg_ret->sectiondata[IDX_debug_str] == NULL)
+  if (dbg_ret->sectiondata[IDX_debug_str] == NULL)
     {
       __libdw_seterrno (DWARF_E_NO_STRING);
       return NULL;
     }
 
   uint64_t off;
-  if (__libdw_read_offset (dbg, dbg_ret, cu_sec_idx (attrp->cu), attrp->valp,
-			   attrp->cu->offset_size, &off, IDX_debug_str, 1))
-    return NULL;
+  if (attrp->form == DW_FORM_strp
+      || attrp->form == DW_FORM_GNU_strp_alt)
+    {
+      if (__libdw_read_offset (dbg, dbg_ret, cu_sec_idx (cu),
+			       attrp->valp, cu->offset_size, &off,
+			       IDX_debug_str, 1))
+	return NULL;
+    }
+  else
+    {
+      Dwarf_Word idx;
+      const unsigned char *datap = attrp->valp;
+      const unsigned char *endp = cu->endp;
+      switch (attrp->form)
+	{
+	case DW_FORM_strx:
+	  if (datap >= endp)
+	    {
+	    invalid:
+	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+	      return NULL;
+	    }
+	  get_uleb128 (idx, datap, endp);
+	  break;
+
+	case DW_FORM_strx1:
+	  if (datap >= endp - 1)
+	    goto invalid;
+	  idx = *datap;
+	  break;
+
+	case DW_FORM_strx2:
+	  if (datap >= endp - 2)
+	    goto invalid;
+	  idx = read_2ubyte_unaligned (dbg, datap);
+	  break;
+
+	case DW_FORM_strx3:
+	  if (datap >= endp - 3)
+	    goto invalid;
+	  idx = read_3ubyte_unaligned (dbg, datap);
+	  break;
+
+	case DW_FORM_strx4:
+	  if (datap >= endp - 4)
+	    goto invalid;
+	  idx = read_4ubyte_unaligned (dbg, datap);
+	  break;
+
+	default:
+	  __libdw_seterrno (DWARF_E_NO_STRING);
+	  return NULL;
+	}
+
+      /* So we got an index in the .debug_str_offsets.  Lets see if it
+	 is valid and we can get the actual .debug_str offset.  */
+      Dwarf_Off str_off = __libdw_cu_str_off_base (cu);
+      if (str_off == (Dwarf_Off) -1)
+	return NULL;
+
+      if (dbg->sectiondata[IDX_debug_str_offsets] == NULL)
+	{
+	  __libdw_seterrno (DWARF_E_NO_STR_OFFSETS);
+	  return NULL;
+	}
+
+      /* The section should at least contain room for one offset.  */
+      int offset_size = cu->offset_size;
+      if (cu->offset_size > dbg->sectiondata[IDX_debug_str_offsets]->d_size)
+	{
+	invalid_offset:
+	  __libdw_seterrno (DWARF_E_INVALID_OFFSET);
+	  return NULL;
+	}
+
+      /* And the base offset should be at least inside the section.  */
+      if (str_off > (dbg->sectiondata[IDX_debug_str_offsets]->d_size
+		     - offset_size))
+	goto invalid_offset;
+
+      size_t max_idx = (dbg->sectiondata[IDX_debug_str_offsets]->d_size
+			- offset_size - str_off) / offset_size;
+      if (idx > max_idx)
+	goto invalid_offset;
+
+      datap = (dbg->sectiondata[IDX_debug_str_offsets]->d_buf
+	       + str_off + (idx * offset_size));
+      if (offset_size == 4)
+	off = read_4ubyte_unaligned (dbg, datap);
+      else
+	off = read_8ubyte_unaligned (dbg, datap);
+
+      if (off > dbg->sectiondata[IDX_debug_str]->d_size)
+	goto invalid_offset;
+    }
 
   return (const char *) dbg_ret->sectiondata[IDX_debug_str]->d_buf + off;
 }
 INTDEF(dwarf_formstring)
+
+Dwarf_Off __libdw_cu_str_off_base (Dwarf_CU *cu)
+{
+  if (cu->str_off_base == (Dwarf_Off) -1)
+    {
+      Dwarf_Die cu_die = CUDIE(cu);
+      Dwarf_Attribute attr;
+      if (dwarf_attr (&cu_die, DW_AT_str_offsets_base, &attr) != NULL)
+	{
+	  Dwarf_Word off;
+	  if (dwarf_formudata (&attr, &off) == 0)
+	    cu->str_off_base = off;
+	}
+    }
+
+  return cu->str_off_base;
+}
diff --git a/libdw/dwarf_formudata.c b/libdw/dwarf_formudata.c
index 5d5fc63..0aaea24 100644
--- a/libdw/dwarf_formudata.c
+++ b/libdw/dwarf_formudata.c
@@ -190,6 +190,14 @@ dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval)
 		return -1;
 	      break;
 
+	    case DW_AT_str_offsets_base:
+	      /* stroffsetsptr */
+	      if (__libdw_formptr (attr, IDX_debug_str_offsets,
+				   DWARF_E_NO_STR_OFFSETS, NULL,
+				   return_uval) == NULL)
+		return -1;
+	      break;
+
 	    default:
 	      /* sec_offset can only be used by one of the above attrs.  */
 	      if (attr->form == DW_FORM_sec_offset)
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index ba50c35..9413705 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -80,6 +80,7 @@ enum
     IDX_debug_loc,
     IDX_debug_pubnames,
     IDX_debug_str,
+    IDX_debug_str_offsets,
     IDX_debug_macinfo,
     IDX_debug_macro,
     IDX_debug_ranges,
@@ -109,6 +110,7 @@ enum
   DWARF_E_NO_ENTRY,
   DWARF_E_INVALID_DWARF,
   DWARF_E_NO_STRING,
+  DWARF_E_NO_STR_OFFSETS,
   DWARF_E_NO_ADDR,
   DWARF_E_NO_CONSTANT,
   DWARF_E_NO_REFERENCE,
@@ -330,6 +332,10 @@ struct Dwarf_CU
      Don't access directly, call __libdw_cu_addr_base.  */
   Dwarf_Off addr_base;
 
+  /* The offset into the .debug_str_offsets section where index zero begins.
+     Don't access directly, call __libdw_cu_str_off_base.  */
+  Dwarf_Off str_off_base;
+
   /* Memory boundaries of this CU.  */
   void *startp;
   void *endp;
@@ -874,6 +880,9 @@ const char *__libdw_getcompdir (Dwarf_Die *cudie);
 /* Get the address base for the CU, fetches it when not yet set.  */
 Dwarf_Off __libdw_cu_addr_base (Dwarf_CU *cu);
 
+/* Get the string offsets base for the CU, fetches it when not yet set.  */
+Dwarf_Off __libdw_cu_str_off_base (Dwarf_CU *cu);
+
 /* Given a file descriptor, dir and file returns a full path.  If the
    file is absolute (starts with a /) a copy of file is returned.  If
    the file isn't absolute, but dir is absolute, then a path that is
diff --git a/src/ChangeLog b/src/ChangeLog
index 7b8084f..37c9cb3 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,7 @@
+2018-03-23  Mark Wielaard  <mark@klomp.org>
+
+	* readelf.c (attr_callback): Handle DW_FORM_strx[1234].
+
 2018-03-22  Mark Wielaard  <mark@klomp.org>
 
 	* readelf.c (attr_callback): Handle DW_FORM_addrx[1234].
diff --git a/src/readelf.c b/src/readelf.c
index c1d6ac1..933eab1 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -6097,6 +6097,11 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
 
     case DW_FORM_indirect:
     case DW_FORM_strp:
+    case DW_FORM_strx:
+    case DW_FORM_strx1:
+    case DW_FORM_strx2:
+    case DW_FORM_strx3:
+    case DW_FORM_strx4:
     case DW_FORM_string:
     case DW_FORM_GNU_strp_alt:
       if (cbargs->silent)
-- 
1.8.3.1



More information about the Elfutils-devel mailing list