]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Fix bugs, introduce __libdw_read_begin_end_pair_inc
authorPetr Machata <pmachata@redhat.com>
Mon, 4 May 2009 16:07:54 +0000 (18:07 +0200)
committerPetr Machata <pmachata@redhat.com>
Mon, 4 May 2009 16:07:54 +0000 (18:07 +0200)
12 files changed:
libdw/dwarf_formblock.c
libdw/dwarf_formref.c
libdw/dwarf_formref_die.c
libdw/dwarf_formstring.c
libdw/dwarf_formudata.c
libdw/dwarf_getaranges.c
libdw/dwarf_getlocation.c
libdw/dwarf_getpubnames.c
libdw/dwarf_nextcu.c
libdw/dwarf_ranges.c
libdw/libdwP.h
libdw/libdw_readhooks.c

index 486dc19837b8a98cc333c12b73cd1f378ca5cb8a..51396d47078a0f347d10f49226553581d14686ab 100644 (file)
@@ -79,9 +79,7 @@ dwarf_formblock (attr, return_block)
       break;
 
     case DW_FORM_block4:
-      if (__libdw_read_length (attr->cu->dbg, IDX_debug_info, attr->valp,
-                              4, &return_block->length))
-       return -1;
+      return_block->length = read_4ubyte_unaligned (attr->cu->dbg, attr->valp);
       return_block->data = attr->valp + 4;
       break;
 
index 3595184cdb34453e558de61355bde48f9457b307..b8463b70b16e82b90ce5331babc75c0ad00080c2 100644 (file)
@@ -79,11 +79,11 @@ __libdw_formref (attr, return_offset)
       break;
 
     case DW_FORM_ref4:
+      *return_offset = read_4ubyte_unaligned (attr->cu->dbg, attr->valp);
+      break;
+
     case DW_FORM_ref8:
-      if (__libdw_read_offset (attr->cu->dbg, IDX_debug_info, attr->valp,
-                              attr->form == DW_FORM_ref4 ? 4 : 8,
-                              return_offset))
-       return -1;
+      *return_offset = read_8ubyte_unaligned (attr->cu->dbg, attr->valp);
       break;
 
     case DW_FORM_ref_udata:
index 128ee137d08b3423f12018ada3785b114895f1df..a6ef7e48ab6ab88638f7d8b2b1b9e07091b6ebe1 100644 (file)
@@ -72,9 +72,9 @@ dwarf_formref_die (attr, die_mem)
                          ? attr->cu->address_size
                          : attr->cu->offset_size);
 
-      if (__libdw_read_address (attr->cu->dbg,
-                               IDX_debug_info, attr->valp,
-                               ref_size, &offset))
+      if (__libdw_read_offset (attr->cu->dbg,
+                              IDX_debug_info, attr->valp,
+                              ref_size, &offset, IDX_debug_info))
        return NULL;
     }
   else
index 63eca9b1dd13c843f1e18a20d7a3cafbab02b5ad..f960f51d2d70477d7f91c9d62a813d1fa2c0c524 100644 (file)
@@ -74,19 +74,15 @@ dwarf_formstring (attrp)
   if (unlikely (attrp->form != DW_FORM_strp)
       || dbg->sectiondata[IDX_debug_str] == NULL)
     {
-    invalid_error:
       __libdw_seterrno (DWARF_E_NO_STRING);
       return NULL;
     }
 
   uint64_t off;
   if (__libdw_read_offset (dbg, IDX_debug_info, attrp->valp,
-                          attrp->cu->offset_size, &off))
+                          attrp->cu->offset_size, &off, IDX_debug_str))
     return NULL;
 
-  if (off  >= dbg->sectiondata[IDX_debug_str]->d_size)
-    goto invalid_error;
-
   return (const char *) dbg->sectiondata[IDX_debug_str]->d_buf + off;
 }
 INTDEF(dwarf_formstring)
index e2f1d023b95aadfe5c6548c685777a48ecdecf15..b346afb388e80d4aaf0e3014eae8886fe101aba2 100644 (file)
@@ -78,9 +78,9 @@ dwarf_formudata (attr, return_uval)
 
     case DW_FORM_data4:
     case DW_FORM_data8:
-      if (__libdw_read_offset (attr->cu->dbg, IDX_debug_info, attr->valp,
-                              attr->form == DW_FORM_data4 ? 4 : 8,
-                              return_uval))
+      if (__libdw_read_address (attr->cu->dbg, IDX_debug_info, attr->valp,
+                               attr->form == DW_FORM_data4 ? 4 : 8,
+                               return_uval))
        return -1;
       break;
 
index 78086fb8a179804f79aed1c1ab1e0c53b8c2673c..7aeb293b732091b830033b01fd178718f41a2e6b 100644 (file)
@@ -151,13 +151,9 @@ dwarf_getaranges (dbg, aranges, naranges)
       Dwarf_Word offset;
       if (__libdw_read_offset_inc (dbg,
                                   IDX_debug_aranges, (unsigned char **)&readp,
-                                  length_bytes, &offset))
+                                  length_bytes, &offset, IDX_debug_info))
        return -1;
 
-      /* Sanity-check the offset.  */
-      if (offset + 4 > dbg->sectiondata[IDX_debug_info]->d_size)
-       goto invalid;
-
       unsigned int address_size = *readp++;
       if (address_size != 4 && address_size != 8)
        goto invalid;
@@ -177,12 +173,14 @@ dwarf_getaranges (dbg, aranges, naranges)
 
          if (__libdw_read_address_inc (dbg, IDX_debug_aranges,
                                        (unsigned char **)&readp,
-                                       address_size, &range_address)
-             || __libdw_read_length_inc (dbg, IDX_debug_aranges,
-                                         (unsigned char **)&readp,
-                                         address_size, &range_length))
+                                       address_size, &range_address))
            return -1;
 
+         if (address_size == 4)
+           range_length = read_4ubyte_unaligned_inc (dbg, readp);
+         else
+           range_length = read_8ubyte_unaligned_inc (dbg, readp);
+
          /* Two zero values mark the end.  */
          if (range_address == 0 && range_length == 0)
            break;
index f9573877c50a09916c643564eaba04ea20dd245d..95ad5259c14f2a2711db2629d75b8695a2500f13 100644 (file)
@@ -405,26 +405,17 @@ dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs)
 
       Dwarf_Addr begin;
       Dwarf_Addr end;
-      Dwarf_Addr escape = ADDR_ESCAPE (attr->cu->address_size);
-
-      if (__libdw_read_address_inc (attr->cu->dbg,
-                                   IDX_debug_line, &readp,
-                                   attr->cu->address_size, &begin)
-         || __libdw_read_address_inc (attr->cu->dbg,
-                                      IDX_debug_line, &readp,
-                                      attr->cu->address_size, &end))
-       goto invalid;
-
-      if (begin == escape)
-       {
-         base = end;
-         if (unlikely (base == escape))
-           goto invalid;
-         continue;
-       }
 
-      if (begin == 0 && end == 0) /* End of list entry.  */
+      int status
+       = __libdw_read_begin_end_pair_inc (attr->cu->dbg, IDX_debug_loc,
+                                          &readp, attr->cu->address_size,
+                                          &begin, &end, &base);
+      if (status == 2) /* End of list entry.  */
        break;
+      else if (status == 1) /* Base address selected.  */
+       continue;
+      else if (status < 0)
+       return status;
 
       if ((unsigned char *) d->d_buf + d->d_size - readp < 2)
        goto invalid;
@@ -470,7 +461,7 @@ dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs)
          if (llbufs != NULL
              && unlikely (getlocation (attr->cu, &block,
                                        &llbufs[got], &listlens[got],
-                                       IDX_debug_line) != 0))
+                                       IDX_debug_loc) != 0))
            return -1;
          ++got;
        }
index f8f34c50f4261992a855599ce5c7cc493989d5aa..c16f683842d205e06cce1e8b557be8ca7a4409d0 100644 (file)
@@ -124,16 +124,14 @@ get_offsets (Dwarf *dbg)
        }
 
       /* Get the CU offset.  */
-      if (__libdw_read_address (dbg, IDX_debug_pubnames, readp + 2, len_bytes,
-                               &mem[cnt].cu_offset))
+      if (__libdw_read_offset (dbg, IDX_debug_pubnames, readp + 2, len_bytes,
+                              &mem[cnt].cu_offset, IDX_debug_info))
        /* Error has been already set in reader.  */
        goto err_return;
 
       /* Determine the size of the CU header.  */
       if (unlikely (dbg->sectiondata[IDX_debug_info] == NULL
-                   || dbg->sectiondata[IDX_debug_info]->d_buf == NULL
-                   || (mem[cnt].cu_offset + 3
-                       >= dbg->sectiondata[IDX_debug_info]->d_size)))
+                   || dbg->sectiondata[IDX_debug_info]->d_buf == NULL))
        goto invalid_dwarf;
 
       unsigned char *infop
@@ -222,10 +220,10 @@ dwarf_getpubnames (dbg, callback, arg, offset)
       while (1)
        {
          /* READP points to the next offset/name pair.  */
-         if (__libdw_read_address_inc (dbg, IDX_debug_pubnames, &readp,
-                                       dbg->pubnames_sets[cnt].address_len,
-                                       &gl.die_offset))
-           return -1l;
+         if (dbg->pubnames_sets[cnt].address_len == 4)
+           gl.die_offset = read_4ubyte_unaligned_inc (dbg, readp);
+         else
+           gl.die_offset = read_8ubyte_unaligned_inc (dbg, readp);
 
          /* If the offset is zero we reached the end of the set.  */
          if (gl.die_offset == 0)
index abffe7ec088ef0dd020132383a36ed112e4b03a4..91cd3f2ed2afa8104bc6be09f20fc236b788d606 100644 (file)
@@ -84,7 +84,7 @@ dwarf_nextcu (dwarf, off, next_off, header_sizep, abbrev_offsetp,
 
   /* This points into the .debug_info section to the beginning of the
      CU entry.  */
-  unsigned char *data = (unsigned char *) dwarf->sectiondata[IDX_debug_info]->d_buf;
+  unsigned char *data = dwarf->sectiondata[IDX_debug_info]->d_buf;
   unsigned char *bytes = data + off;
 
   /* The format of the CU header is described in dwarf2p1 7.5.1:
@@ -146,7 +146,7 @@ dwarf_nextcu (dwarf, off, next_off, header_sizep, abbrev_offsetp,
      depends on whether this is a 32-bit or 64-bit DWARF definition.  */
   uint64_t abbrev_offset;
   if (__libdw_read_offset_inc (dwarf, IDX_debug_info, &bytes,
-                              offset_size, &abbrev_offset))
+                              offset_size, &abbrev_offset, IDX_debug_abbrev))
     return -1;
 
   if (abbrev_offsetp != NULL)
index 7dbfb9f54931b6829a341e788535c9c3d370f299..ccb4f6b7c53f00fc462b63ee228846d050d66f42 100644 (file)
 #include <dwarf.h>
 #include <assert.h>
 
+/* Read up begin/end pair and increment read pointer.
+    - If it's normal range record, set up `*beginp' and `*endp' and return 0.
+    - If it's base address selection record, set up `*basep' and return 1.
+    - If it's end of rangelist, don't set anything and return 2
+    - If an error occurs, don't set anything and return -1.  */
+internal_function int
+__libdw_read_begin_end_pair_inc (Dwarf *dbg, int sec_index,
+                                unsigned char **addr, int width,
+                                Dwarf_Addr *beginp, Dwarf_Addr *endp,
+                                Dwarf_Addr *basep)
+{
+  Dwarf_Addr escape
+    = width == 8 ? (Elf64_Addr) -1 : (Elf64_Addr) (Elf32_Addr) -1;
+  Dwarf_Addr begin, end;
+
+  bool begin_relocated
+    = !READ_AND_RELOCATE (__libdw_relocate_address, begin);
+  bool end_relocated
+    = !READ_AND_RELOCATE (__libdw_relocate_address, end);
+
+  /* Unrelocated escape for begin means base address selection.  */
+  if (begin == escape && !begin_relocated)
+    {
+      if (unlikely (end == escape))
+       {
+         __libdw_seterrno (DWARF_E_INVALID_DWARF);
+         return -1;
+       }
+
+      if (basep != NULL)
+       *basep = end;
+      return 1;
+    }
+
+  /* Unrelocated pair of zeroes means end of range list.  */
+  if (begin == 0 && end == 0 && !begin_relocated && !end_relocated)
+    return 2;
+
+  /* Don't check for begin_relocated == end_relocated.  Serve the data
+     to the client even though it may be buggy.  */
+  *beginp = begin;
+  *endp = end;
+
+  return 0;
+}
 
 ptrdiff_t
 dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
@@ -142,23 +187,21 @@ dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
 
   Dwarf_Addr begin;
   Dwarf_Addr end;
-  if (__libdw_read_address_inc (die->cu->dbg,
-                               IDX_debug_ranges, &readp,
-                               die->cu->address_size, &begin)
-      || __libdw_read_address_inc (die->cu->dbg,
-                                  IDX_debug_ranges, &readp,
-                                  die->cu->address_size, &end))
-    return -1l;
-
-  if (begin == ADDR_ESCAPE (die->cu->address_size))
+
+  switch (__libdw_read_begin_end_pair_inc (die->cu->dbg, IDX_debug_ranges,
+                                          &readp, die->cu->address_size,
+                                          &begin, &end, basep))
     {
-      *basep = end;
+    case 0:
+      break;
+    case 1:
       goto next;
+    case 2:
+      return 0;
+    default:
+      return -1l;
     }
 
-  if (begin == 0 && end == 0) /* End of list entry.  */
-    return 0;
-
   /* We have an address range entry.  */
   *startp = *basep + begin;
   *endp = *basep + end;
index 4a1e4b2bf308cc44c0e8bab67e86bb05e5c06280..be0b99a8e2961cbda7fa94654867852361747a7d 100644 (file)
@@ -422,7 +422,7 @@ extern int __dwarf_errno_internal (void);
 
 /* Reader hooks.  */
 
-static inline int
+static inline bool
 __libdw_in_section (Dwarf *dbg, int sec_index,
                    unsigned char *addr, int width)
 {
@@ -432,12 +432,14 @@ __libdw_in_section (Dwarf *dbg, int sec_index,
       || (void *)addr + width > data->d_buf + data->d_size)
     {
       __libdw_seterrno (DWARF_E_INVALID_OFFSET);
-      return 1;
+      return false;
     }
 
-  return 0;
+  return true;
 }
 
+/* Relocation hooks return -1 on error, 0 if there is no relocation
+   and 1 if a relocation was present.*/
 int __libdw_relocate_address (Dwarf *dbg,
                              int sec_index, uintptr_t addr,
                              int width, Dwarf_Addr *val)
@@ -448,60 +450,65 @@ int __libdw_relocate_offset (Dwarf *dbg,
                             int width, Dwarf_Off *val)
   internal_function;
 
-int __libdw_relocate_length (Dwarf *dbg,
-                            int sec_index, uintptr_t addr,
-                            int width, Dwarf_Addr *val)
-  internal_function;
-
-#define READ_AND_RELOCATE(RELOC_HOOK)                                  \
-  {                                                                    \
-    int status;                                                                \
-    if ((status = __libdw_in_section (dbg, sec_index, *addr, width)))  \
-      return status;                                                   \
+#define READ_AND_RELOCATE(RELOC_HOOK, VAL)                             \
+  ({                                                                   \
+    if (!__libdw_in_section (dbg, sec_index, *addr, width))            \
+      return -1;                                                       \
                                                                        \
-    uintptr_t addr0 = (uintptr_t)*addr;                                        \
-    __typeof (*ret) val;                                               \
+    uintptr_t addr0 = (uintptr_t) *addr;                               \
                                                                        \
     if (width == 4)                                                    \
-      val = read_4ubyte_unaligned_inc (dbg, *addr);                    \
+      VAL = read_4ubyte_unaligned_inc (dbg, *addr);                    \
     else                                                               \
       {                                                                        \
        assert (width == 8);                                            \
-       val = read_8ubyte_unaligned_inc (dbg, *addr);                   \
+       VAL = read_8ubyte_unaligned_inc (dbg, *addr);                   \
       }                                                                        \
                                                                        \
-    if ((status = RELOC_HOOK (dbg, sec_index, addr0, width, &val)))    \
+    int status = RELOC_HOOK (dbg, sec_index, addr0, width, &VAL);      \
+    if (status == -1)                                                  \
       return status;                                                   \
-                                                                       \
-    *ret = val;                                                                \
-    return 0;                                                          \
-  }
+    status;                                                            \
+   })
 
 static inline int
 __libdw_read_address_inc (Dwarf *dbg,
                          int sec_index, unsigned char **addr,
                          int width, Dwarf_Addr *ret)
 {
-  READ_AND_RELOCATE (__libdw_relocate_address)
+  Dwarf_Addr val;
+  READ_AND_RELOCATE (__libdw_relocate_address, val);
+  *ret = val;
+  return 0;
 }
 
 static inline int
 __libdw_read_offset_inc (Dwarf *dbg,
                         int sec_index, unsigned char **addr,
-                        int width, Dwarf_Off *ret)
+                        int width, Dwarf_Off *ret, int sec_ret)
 {
-  READ_AND_RELOCATE (__libdw_relocate_offset)
-}
+  Dwarf_Off val;
+  READ_AND_RELOCATE (__libdw_relocate_offset, val);
 
-static inline int
-__libdw_read_length_inc (Dwarf *dbg,
-                        int sec_index, unsigned char **addr,
-                        int width, Dwarf_Addr *ret)
-{
-  READ_AND_RELOCATE (__libdw_relocate_length)
+  Elf_Data *data = dbg->sectiondata[sec_ret];
+  if (!__libdw_in_section (dbg, sec_ret, data->d_buf + val, width))
+    return -1;
+
+  *ret = val;
+  return 0;
 }
 
-#undef READ_AND_RELOCATE
+/* Read up begin/end pair and increment read pointer.
+    - If it's normal range record, set up `*beginp' and `*endp' and return 0.
+    - If it's base address selection record, set up `*basep' and return 1.
+    - If it's end of rangelist, don't set anything and return 2
+    - If an error occurs, don't set anything and return <0.  */
+int
+__libdw_read_begin_end_pair_inc (Dwarf *dbg, int sec_index,
+                                unsigned char **addr, int width,
+                                Dwarf_Addr *beginp, Dwarf_Addr *endp,
+                                Dwarf_Addr *basep)
+  internal_function;
 
 static inline int
 __libdw_read_address (Dwarf *dbg,
@@ -515,24 +522,12 @@ __libdw_read_address (Dwarf *dbg,
 static inline int
 __libdw_read_offset (Dwarf *dbg,
                     int sec_index, const unsigned char *addr,
-                    int width, Dwarf_Addr *ret)
+                    int width, Dwarf_Off *ret, int sec_ret)
 {
   return __libdw_read_offset_inc (dbg, sec_index, (unsigned char **)&addr,
-                                 width, ret);
+                                 width, ret, sec_ret);
 }
 
-static inline int
-__libdw_read_length (Dwarf *dbg,
-                    int sec_index, const unsigned char *addr,
-                    int width, Dwarf_Word *ret)
-{
-  return __libdw_read_length_inc (dbg, sec_index, (unsigned char **)&addr,
-                                 width, ret);
-}
-
-#define ADDR_ESCAPE(width) \
-  (width == 8 ? (Elf64_Addr)-1 : (Elf64_Addr)(Elf32_Addr)-1)
-
 
 
 /* Aliases to avoid PLTs.  */
index 93c98642907714e8d2f4316ba1e6aa3cc999874d..404f12aa72efaca057b4d93a7146b0a581e846fd 100644 (file)
@@ -72,13 +72,3 @@ __libdw_relocate_offset (Dwarf *dbg __attribute__ ((unused)),
 {
   return 0;
 }
-
-internal_function int
-__libdw_relocate_length (Dwarf *dbg __attribute__ ((unused)),
-                        int sec_index __attribute__ ((unused)),
-                        uintptr_t addr __attribute__ ((unused)),
-                        int width __attribute__ ((unused)),
-                        Dwarf_Addr *val __attribute__ ((unused)))
-{
-  return 0;
-}