summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2009-06-14 20:19:45 -0700
committerUlrich Drepper <drepper@redhat.com>2009-06-14 20:19:45 -0700
commit99d2372b25d1231d786b70278478c7a112f2b27c (patch)
treeca307d5078971fdef16f324e8ffd32b25ddd0df1
parentf189493154d0041deced00e6a99cc5426dc9d260 (diff)
Squashed commit of the following:
commit 77abb31cb8d55980ef92260917a7ecdd228b1a44 Author: Petr Machata <pmachata@redhat.com> Date: Mon Jun 8 15:46:16 2009 +0200 Fix a bug in offset checking commit b794eac4f8d3e08101b5d2924523b1259bbc1b17 Author: Petr Machata <pmachata@redhat.com> Date: Wed Jun 3 16:00:01 2009 +0200 Cosmetic, get rid of defining several variables per line commit a23938fe35d515a3d75a51f6204771f3cf6c9ec4 Author: Petr Machata <pmachata@redhat.com> Date: Wed Jun 3 15:50:03 2009 +0200 Restructure the code to decrease the binary size commit 7c301e3d4e8584dfb3174855fb6af3d5791dfeed Author: Petr Machata <pmachata@redhat.com> Date: Mon Jun 1 19:43:28 2009 +0200 Shuffle a couple pieces of code around to make the code smaller commit 6325323482c2a3e17409d32c7feec9461be26614 Merge: 83ac53d... e94b1b2... Author: Petr Machata <pmachata@redhat.com> Date: Fri May 22 08:49:07 2009 +0200 Merge branch 'master' of ssh://pmachata@git.fedorahosted.org/git/elfutils into pmachata/reader_hooks Conflicts: libdw/ChangeLog commit 83ac53db400945c074e77ec9904efe550903a0e2 Author: Petr Machata <pmachata@redhat.com> Date: Fri May 22 08:40:25 2009 +0200 Call reloc hook with the original address, not incremented commit f1996388745566abc1ca1c1700b3b7eded208575 Author: Petr Machata <pmachata@redhat.com> Date: Wed May 6 16:53:03 2009 +0200 Rewrite boundary checking logic so that it's immune to arithmetic overflow * ... also get rid of some code redundancy. commit 0c1df732822d83548edd0d005f3450281ed1701b Author: Petr Machata <pmachata@redhat.com> Date: Wed May 6 16:25:09 2009 +0200 __libdw_read_offset* take extra argument for header size checks * also presence of debug data and buffer is checked in __libdw_in_section commit 6fb192e360f842cacb34a90c03cd0524cccc3dec Author: Petr Machata <pmachata@redhat.com> Date: Wed May 6 15:51:20 2009 +0200 Check for presence of data before loading the offset commit a2e7612b165d83dd241225f87075fa4f58d18781 Author: Petr Machata <pmachata@redhat.com> Date: Wed May 6 15:04:16 2009 +0200 Cosmetic changes commit 8b1aad2c2f6c8dc02b3e704e4f386c1827e385cb Author: Petr Machata <pmachata@redhat.com> Date: Tue May 5 15:34:13 2009 +0200 Improve reader hook functions a bit * ... so that they are closer match to what's need on call sites commit 3854b7fbab2fe331711365f94a295af82164d0d2 Author: Petr Machata <pmachata@redhat.com> Date: Tue May 5 14:33:50 2009 +0200 Fixes in use of reader hooks in __libdw_formptr and dwarf_formudata * and a bit more commit 335075596b6acef6e59919155e2b087e690a572d Author: Petr Machata <pmachata@redhat.com> Date: Tue May 5 14:32:39 2009 +0200 Rename __libdw_read_udata_addr to __libdw_formptr commit 8273a2adaf8cb2ee203926af2849e4f96f8a6eaf Author: Petr Machata <pmachata@redhat.com> Date: Tue May 5 02:53:40 2009 +0200 Introduce __libdw_read_udata_address * the use in dwarf_ranges is iffy, there's a functionality mismatch. Need to find some better way commit 1c897f4abde1530038d332f4fc03a596a24f6aaf Author: Petr Machata <pmachata@redhat.com> Date: Mon May 4 18:09:13 2009 +0200 ChangeLog entries for previous commit commit 90d7c39454468b91c0fd6514a4e8d821222d6adb Author: Petr Machata <pmachata@redhat.com> Date: Mon May 4 18:07:54 2009 +0200 Fix bugs, introduce __libdw_read_begin_end_pair_inc commit 9b3923f5b69a3e56590769435c4693f057acdc1f Merge: 6200ba6... 589b3d3... Author: Petr Machata <pmachata@redhat.com> Date: Mon May 4 12:22:21 2009 +0200 Merge branch 'master' of ssh://pmachata@git.fedorahosted.org/git/elfutils into pmachata/reader_hooks commit 6200ba62aa9ea3cb9318f73a27181907a528dbe4 Author: Petr Machata <pmachata@redhat.com> Date: Wed Apr 29 15:31:28 2009 +0200 dwarf_getlocation_addr uses read hooks commit ecbb8cdd8b500e37dc34fc246b912f704fe31ca4 Author: Petr Machata <pmachata@redhat.com> Date: Wed Apr 29 15:16:09 2009 +0200 dwarf_ranges and dwarf_formref use read hooks commit cb8f67b29a896c2660c10aa1028a9dbb377553e9 Author: Petr Machata <pmachata@redhat.com> Date: Tue Apr 28 18:39:04 2009 +0200 Convert several new functions to use read hooks commit b130453eb16a8cf042915e312cc5f189b8b92c01 Author: Petr Machata <pmachata@redhat.com> Date: Tue Apr 28 18:38:27 2009 +0200 Add length read hooks commit bd885ff694817b965231d99f1ab867947998e734 Author: Petr Machata <pmachata@redhat.com> Date: Tue Apr 28 18:36:17 2009 +0200 Constify read hook arguments commit 66fe03f1e489a88b89a15c9e13f9bd33db2729b1 Author: Petr Machata <pmachata@redhat.com> Date: Tue Apr 28 16:11:05 2009 +0200 Change type of return value of offset read hooks to Dwarf_Off commit 22b36e00cc228f5a966f84ca3323e5d652923ce8 Merge: 5b3534b... a7cb532... Author: Petr Machata <pmachata@redhat.com> Date: Mon Apr 27 19:05:25 2009 +0200 Merge branch 'master' of ssh://pmachata@git.fedorahosted.org/git/elfutils into pmachata/reader_hooks commit 5b3534b62cbd45fe4f11dd1be3e492237938cce0 Author: Petr Machata <pmachata@redhat.com> Date: Mon Apr 27 18:53:06 2009 +0200 Rewrites in read hooks * Have the checking and reading logic itself in the header so that it gets optimized out/inlined. Call external relocating hook from there, there will presumably be more work to do, and we presumably don't want to keep this in the header. commit 9e265d71d0eb900e76d6fdb0196ef4fc6507f3a7 Merge: 1783089... 300f3a4... Author: Petr Machata <pmachata@redhat.com> Date: Thu Apr 23 17:45:25 2009 +0200 Merge branch 'master' of ssh://pmachata@git.fedorahosted.org/git/elfutils into pmachata/reader_hooks commit 1783089b184ddea2081bbe5ac4e80420cb6b0803 Author: Petr Machata <pmachata@redhat.com> Date: Thu Apr 23 17:44:48 2009 +0200 Use the new reader hooks in several places commit 11c3d97a5b40ea15edf324092b03da3050610d01 Author: Petr Machata <pmachata@redhat.com> Date: Thu Apr 23 17:40:03 2009 +0200 Introduce reader hooks
-rw-r--r--libdw/ChangeLog34
-rw-r--r--libdw/dwarf_formaddr.c8
-rw-r--r--libdw/dwarf_formref_die.c7
-rw-r--r--libdw/dwarf_formstring.c12
-rw-r--r--libdw/dwarf_formudata.c53
-rw-r--r--libdw/dwarf_getaranges.c27
-rw-r--r--libdw/dwarf_getlocation.c94
-rw-r--r--libdw/dwarf_getpubnames.c15
-rw-r--r--libdw/dwarf_getsrclines.c27
-rw-r--r--libdw/dwarf_nextcu.c15
-rw-r--r--libdw/dwarf_ranges.c105
-rw-r--r--libdw/libdwP.h150
12 files changed, 377 insertions, 170 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 0e317d7c..525bb329 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,37 @@
+2009-05-05 Petr Machata <pmachata@redhat.com>
+
+ * libdwP.h (__libdw_formptr): Declare new function.
+ * dwarf_formudata.c: Implement it here.
+ * dwarf_getlocation.c (dwarf_getlocation_addr):
+ Call it instead of hand-rolled offset handling code.
+ * dwarf_getsrclines.c (dwarf_getsrclines): Likewise.
+ * dwarf_ranges.c (dwarf_ranges): Likewise.
+
+2009-05-04 Petr Machata <pmachata@redhat.com>
+
+ * libdwP.h (__libdw_read_begin_end_pair_inc): Declare new function.
+ * dwarf_ranges.c: Implement it here.
+ (dwarf_ranges): Call it.
+ * dwarf_getlocation.c (dwarf_getlocation_addr): Call it also here.
+
+2009-04-23 Petr Machata <pmachata@redhat.com>
+
+ * dwarf_formaddr.c (dwarf_formaddr): Call __libdw_read_* instead
+ of read_*ubyte_unaligned.
+ * dwarf_formref_die.c (dwarf_formref_die): Likewise.
+ * dwarf_formstring.c (dwarf_formstring): Likewise.
+ * dwarf_formudate.c (dwarf_formudata): Likewise.
+ * dwarf_getaranges.c (dwarf_getaranges): Likewise.
+ * dwarf_getlocation.c (dwarf_getlocation_addr): Likewise.
+ * dwarf_getpubnames.c (get_offsets): Likewise.
+ * dwarf_nextcu.c (dwarf_nextcu): Likewise.
+
+2009-04-23 Petr Machata <pmachata@redhat.com>
+
+ * libdwP.h (__libdw_read_addr_inc, __libdw_read_off_inc,
+ __libdw_read_addr, __libdw_read_off): Add four new internal
+ functions.
+
2009-05-07 Roland McGrath <roland@redhat.com>
* dwarf_getmacros.c (dwarf_getmacros): Use absolute section offset in
diff --git a/libdw/dwarf_formaddr.c b/libdw/dwarf_formaddr.c
index dcb58d43..9938be7e 100644
--- a/libdw/dwarf_formaddr.c
+++ b/libdw/dwarf_formaddr.c
@@ -70,10 +70,10 @@ dwarf_formaddr (attr, return_addr)
return -1;
}
- if (attr->cu->address_size == 8)
- *return_addr = read_8ubyte_unaligned (attr->cu->dbg, attr->valp);
- else
- *return_addr = read_4ubyte_unaligned (attr->cu->dbg, attr->valp);
+ if (__libdw_read_address (attr->cu->dbg,
+ IDX_debug_info, attr->valp,
+ attr->cu->address_size, return_addr))
+ return -1;
return 0;
}
diff --git a/libdw/dwarf_formref_die.c b/libdw/dwarf_formref_die.c
index 90a4b2d3..a004a0fd 100644
--- a/libdw/dwarf_formref_die.c
+++ b/libdw/dwarf_formref_die.c
@@ -72,10 +72,9 @@ dwarf_formref_die (attr, die_mem)
? attr->cu->address_size
: attr->cu->offset_size);
- if (ref_size == 8)
- offset = read_8ubyte_unaligned (attr->cu->dbg, attr->valp);
- else
- offset = read_4ubyte_unaligned (attr->cu->dbg, attr->valp);
+ if (__libdw_read_offset (attr->cu->dbg, IDX_debug_info, attr->valp,
+ ref_size, &offset, IDX_debug_info, 0))
+ return NULL;
}
else
{
diff --git a/libdw/dwarf_formstring.c b/libdw/dwarf_formstring.c
index 790831ea..f95d31b8 100644
--- a/libdw/dwarf_formstring.c
+++ b/libdw/dwarf_formstring.c
@@ -74,20 +74,14 @@ 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;
- // XXX We need better boundary checks.
- if (attrp->cu->offset_size == 8)
- off = read_8ubyte_unaligned (dbg, attrp->valp);
- else
- off = read_4ubyte_unaligned (dbg, attrp->valp);
-
- if (off >= dbg->sectiondata[IDX_debug_str]->d_size)
- goto invalid_error;
+ if (__libdw_read_offset (dbg, IDX_debug_info, attrp->valp,
+ attrp->cu->offset_size, &off, IDX_debug_str, 1))
+ return NULL;
return (const char *) dbg->sectiondata[IDX_debug_str]->d_buf + off;
}
diff --git a/libdw/dwarf_formudata.c b/libdw/dwarf_formudata.c
index b5c40bb5..04f04aae 100644
--- a/libdw/dwarf_formudata.c
+++ b/libdw/dwarf_formudata.c
@@ -55,6 +55,51 @@
#include <dwarf.h>
#include "libdwP.h"
+internal_function unsigned char *
+__libdw_formptr (Dwarf_Attribute *attr, int sec_index,
+ int err_nodata, unsigned char **endpp,
+ Dwarf_Off *offsetp)
+{
+ if (attr == NULL)
+ return NULL;
+
+ const Elf_Data *d = attr->cu->dbg->sectiondata[sec_index];
+ if (unlikely (d == NULL))
+ {
+ __libdw_seterrno (err_nodata);
+ return NULL;
+ }
+
+ Dwarf_Word offset;
+ switch (attr->form)
+ {
+ 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,
+ &offset, sec_index, 0))
+ return NULL;
+ break;
+
+ default:
+ if (INTUSE(dwarf_formudata) (attr, &offset))
+ return NULL;
+ };
+
+ unsigned char *readp = d->d_buf + offset;
+ unsigned char *endp = d->d_buf + d->d_size;
+ if (unlikely (readp >= endp))
+ {
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return NULL;
+ }
+
+ if (endpp != NULL)
+ *endpp = endp;
+ if (offsetp != NULL)
+ *offsetp = offset;
+ return readp;
+}
int
dwarf_formudata (attr, return_uval)
@@ -77,11 +122,11 @@ dwarf_formudata (attr, return_uval)
break;
case DW_FORM_data4:
- *return_uval = read_4ubyte_unaligned (attr->cu->dbg, attr->valp);
- break;
-
case DW_FORM_data8:
- *return_uval = read_8ubyte_unaligned (attr->cu->dbg, attr->valp);
+ if (__libdw_read_address (attr->cu->dbg, IDX_debug_info, attr->valp,
+ attr->form == DW_FORM_data4 ? 4 : 8,
+ return_uval))
+ return -1;
break;
case DW_FORM_sdata:
diff --git a/libdw/dwarf_getaranges.c b/libdw/dwarf_getaranges.c
index 96e99620..74f04ea5 100644
--- a/libdw/dwarf_getaranges.c
+++ b/libdw/dwarf_getaranges.c
@@ -149,14 +149,10 @@ dwarf_getaranges (dbg, aranges, naranges)
}
Dwarf_Word offset;
- if (length_bytes == 4)
- offset = read_4ubyte_unaligned_inc (dbg, readp);
- else
- offset = read_8ubyte_unaligned_inc (dbg, readp);
-
- /* Sanity-check the offset. */
- if (offset + 4 > dbg->sectiondata[IDX_debug_info]->d_size)
- goto invalid;
+ if (__libdw_read_offset_inc (dbg,
+ IDX_debug_aranges, (unsigned char **)&readp,
+ length_bytes, &offset, IDX_debug_info, 4))
+ return -1;
unsigned int address_size = *readp++;
if (address_size != 4 && address_size != 8)
@@ -175,16 +171,15 @@ dwarf_getaranges (dbg, aranges, naranges)
Dwarf_Word range_address;
Dwarf_Word range_length;
+ if (__libdw_read_address_inc (dbg, IDX_debug_aranges,
+ (unsigned char **)&readp,
+ address_size, &range_address))
+ return -1;
+
if (address_size == 4)
- {
- range_address = read_4ubyte_unaligned_inc (dbg, readp);
- range_length = read_4ubyte_unaligned_inc (dbg, readp);
- }
+ range_length = read_4ubyte_unaligned_inc (dbg, readp);
else
- {
- range_address = read_8ubyte_unaligned_inc (dbg, readp);
- range_length = read_8ubyte_unaligned_inc (dbg, readp);
- }
+ range_length = read_8ubyte_unaligned_inc (dbg, readp);
/* Two zero values mark the end. */
if (range_address == 0 && range_length == 0)
diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c
index f680aa96..f829e72b 100644
--- a/libdw/dwarf_getlocation.c
+++ b/libdw/dwarf_getlocation.c
@@ -113,7 +113,7 @@ loc_compare (const void *p1, const void *p2)
static int
getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
- Dwarf_Op **llbuf, size_t *listlen)
+ Dwarf_Op **llbuf, size_t *listlen, int sec_index)
{
Dwarf *dbg = cu->dbg;
@@ -151,24 +151,9 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
{
case DW_OP_addr:
/* Address, depends on address size of CU. */
- if (cu->address_size == 4)
- {
- if (unlikely (data + 4 > end_data))
- {
- invalid:
- __libdw_seterrno (DWARF_E_INVALID_DWARF);
- return -1;
- }
-
- newloc->number = read_4ubyte_unaligned_inc (dbg, data);
- }
- else
- {
- if (unlikely (data + 8 > end_data))
- goto invalid;
-
- newloc->number = read_8ubyte_unaligned_inc (dbg, data);
- }
+ if (__libdw_read_address_inc (dbg, sec_index, (unsigned char **)&data,
+ cu->address_size, &newloc->number))
+ return -1;
break;
case DW_OP_deref:
@@ -211,7 +196,11 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
case DW_OP_deref_size:
case DW_OP_xderef_size:
if (unlikely (data >= end_data))
- goto invalid;
+ {
+ invalid:
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return -1;
+ }
newloc->number = *data++;
break;
@@ -352,7 +341,7 @@ dwarf_getlocation (attr, llbuf, listlen)
if (INTUSE(dwarf_formblock) (attr, &block) != 0)
return -1;
- return getlocation (attr->cu, &block, llbuf, listlen);
+ return getlocation (attr->cu, &block, llbuf, listlen, IDX_debug_info);
}
int
@@ -376,7 +365,8 @@ dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs)
if (maxlocs == 0)
return 0;
if (llbufs != NULL &&
- getlocation (attr->cu, &block, &llbufs[0], &listlens[0]) != 0)
+ getlocation (attr->cu, &block, &llbufs[0], &listlens[0],
+ IDX_debug_info) != 0)
return -1;
return listlens[0] == 0 ? 0 : 1;
}
@@ -388,25 +378,17 @@ dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs)
return -1;
}
- /* Must have the form data4 or data8 which act as an offset. */
- Dwarf_Word offset;
- if (unlikely (INTUSE(dwarf_formudata) (attr, &offset) != 0))
+ unsigned char *endp;
+ unsigned char *readp = __libdw_formptr (attr, IDX_debug_loc,
+ DWARF_E_NO_LOCLIST, &endp, NULL);
+ if (readp == NULL)
return -1;
- const Elf_Data *d = attr->cu->dbg->sectiondata[IDX_debug_loc];
- if (unlikely (d == NULL))
- {
- __libdw_seterrno (DWARF_E_NO_LOCLIST);
- return -1;
- }
-
Dwarf_Addr base = (Dwarf_Addr) -1;
- unsigned char *readp = d->d_buf + offset;
size_t got = 0;
while (got < maxlocs)
{
- if ((unsigned char *) d->d_buf + d->d_size - readp
- < attr->cu->address_size * 2)
+ if (endp - readp < attr->cu->address_size * 2)
{
invalid:
__libdw_seterrno (DWARF_E_INVALID_DWARF);
@@ -415,42 +397,25 @@ dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs)
Dwarf_Addr begin;
Dwarf_Addr end;
- if (attr->cu->address_size == 8)
- {
- begin = read_8ubyte_unaligned_inc (attr->cu->dbg, readp);
- end = read_8ubyte_unaligned_inc (attr->cu->dbg, readp);
-
- if (begin == (Elf64_Addr) -1l) /* Base address entry. */
- {
- base = end;
- if (unlikely (base == (Dwarf_Addr) -1))
- goto invalid;
- continue;
- }
- }
- else
- {
- begin = read_4ubyte_unaligned_inc (attr->cu->dbg, readp);
- end = read_4ubyte_unaligned_inc (attr->cu->dbg, readp);
-
- if (begin == (Elf32_Addr) -1) /* Base address entry. */
- {
- base = end;
- 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)
+ if (endp - readp < 2)
goto invalid;
/* We have a location expression. */
block.length = read_2ubyte_unaligned_inc (attr->cu->dbg, readp);
block.data = readp;
- if ((unsigned char *) d->d_buf + d->d_size - readp
- < (ptrdiff_t) block.length)
+ if (endp - readp < (ptrdiff_t) block.length)
goto invalid;
readp += block.length;
@@ -486,7 +451,8 @@ dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs)
/* This one matches the address. */
if (llbufs != NULL
&& unlikely (getlocation (attr->cu, &block,
- &llbufs[got], &listlens[got]) != 0))
+ &llbufs[got], &listlens[got],
+ IDX_debug_loc) != 0))
return -1;
++got;
}
diff --git a/libdw/dwarf_getpubnames.c b/libdw/dwarf_getpubnames.c
index 1b054e26..5560a758 100644
--- a/libdw/dwarf_getpubnames.c
+++ b/libdw/dwarf_getpubnames.c
@@ -102,7 +102,6 @@ get_offsets (Dwarf *dbg)
else if (unlikely (len >= DWARF3_LENGTH_MIN_ESCAPE_CODE
&& len <= DWARF3_LENGTH_MAX_ESCAPE_CODE))
{
- invalid_dwarf:
__libdw_seterrno (DWARF_E_INVALID_DWARF);
goto err_return;
}
@@ -124,18 +123,12 @@ get_offsets (Dwarf *dbg)
}
/* Get the CU offset. */
- if (len_bytes == 4)
- mem[cnt].cu_offset = read_4ubyte_unaligned (dbg, readp + 2);
- else
- mem[cnt].cu_offset = read_8ubyte_unaligned (dbg, readp + 2);
+ if (__libdw_read_offset (dbg, IDX_debug_pubnames, readp + 2, len_bytes,
+ &mem[cnt].cu_offset, IDX_debug_info, 3))
+ /* 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)))
- goto invalid_dwarf;
-
unsigned char *infop
= ((unsigned char *) dbg->sectiondata[IDX_debug_info]->d_buf
+ mem[cnt].cu_offset);
diff --git a/libdw/dwarf_getsrclines.c b/libdw/dwarf_getsrclines.c
index fe0e67d6..efd0459f 100644
--- a/libdw/dwarf_getsrclines.c
+++ b/libdw/dwarf_getsrclines.c
@@ -135,20 +135,13 @@ dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines)
/* Get the offset into the .debug_line section. NB: this call
also checks whether the previous dwarf_attr call failed. */
- Dwarf_Word offset;
- if (INTUSE(dwarf_formudata) (stmt_list, &offset) != 0)
+ const unsigned char *lineendp;
+ const unsigned char *linep
+ = __libdw_formptr (stmt_list, IDX_debug_line, DWARF_E_NO_DEBUG_LINE,
+ (unsigned char **) &lineendp, NULL);
+ if (linep == NULL)
goto out;
- Dwarf *dbg = cu->dbg;
- if (dbg->sectiondata[IDX_debug_line] == NULL)
- {
- __libdw_seterrno (DWARF_E_NO_DEBUG_LINE);
- goto out;
- }
- const uint8_t *linep = dbg->sectiondata[IDX_debug_line]->d_buf + offset;
- const uint8_t *lineendp = (dbg->sectiondata[IDX_debug_line]->d_buf
- + dbg->sectiondata[IDX_debug_line]->d_size);
-
/* Get the compilation directory. */
Dwarf_Attribute compdir_attr_mem;
Dwarf_Attribute *compdir_attr = INTUSE(dwarf_attr) (cudie,
@@ -162,6 +155,8 @@ dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines)
__libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
goto out;
}
+
+ Dwarf *dbg = cu->dbg;
Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep);
unsigned int length = 4;
if (unlikely (unit_length == DWARF3_LENGTH_64_BIT))
@@ -429,10 +424,10 @@ dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines)
/* The value is an address. The size is defined as
apporiate for the target machine. We use the
address size field from the CU header. */
- if (cu->address_size == 4)
- address = read_4ubyte_unaligned_inc (dbg, linep);
- else
- address = read_8ubyte_unaligned_inc (dbg, linep);
+ if (__libdw_read_address_inc (dbg, IDX_debug_line,
+ (unsigned char **)&linep,
+ cu->address_size, &address))
+ goto out;
break;
case DW_LNE_define_file:
diff --git a/libdw/dwarf_nextcu.c b/libdw/dwarf_nextcu.c
index 9e5a96bc..66cde78a 100644
--- a/libdw/dwarf_nextcu.c
+++ b/libdw/dwarf_nextcu.c
@@ -84,7 +84,8 @@ dwarf_nextcu (dwarf, off, next_off, header_sizep, abbrev_offsetp,
/* This points into the .debug_info section to the beginning of the
CU entry. */
- char *bytes = (char *) dwarf->sectiondata[IDX_debug_info]->d_buf + off;
+ 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:
@@ -144,10 +145,10 @@ dwarf_nextcu (dwarf, off, next_off, header_sizep, abbrev_offsetp,
/* Get offset in .debug_abbrev. Note that the size of the entry
depends on whether this is a 32-bit or 64-bit DWARF definition. */
uint64_t abbrev_offset;
- if (offset_size == 4)
- abbrev_offset = read_4ubyte_unaligned_inc (dwarf, bytes);
- else
- abbrev_offset = read_8ubyte_unaligned_inc (dwarf, bytes);
+ if (__libdw_read_offset_inc (dwarf, IDX_debug_info, &bytes, offset_size,
+ &abbrev_offset, IDX_debug_abbrev, 0))
+ return -1;
+
if (abbrev_offsetp != NULL)
*abbrev_offsetp = abbrev_offset;
@@ -162,9 +163,7 @@ dwarf_nextcu (dwarf, off, next_off, header_sizep, abbrev_offsetp,
/* Store the header length. */
if (header_sizep != NULL)
- *header_sizep = (bytes
- - ((char *) dwarf->sectiondata[IDX_debug_info]->d_buf
- + off));
+ *header_sizep = bytes - (data + off);
/* See definition of DIE_OFFSET_FROM_CU_OFFSET macro
for an explanation of the trick in this expression. */
diff --git a/libdw/dwarf_ranges.c b/libdw/dwarf_ranges.c
index 1eef617b..50fb6ba2 100644
--- a/libdw/dwarf_ranges.c
+++ b/libdw/dwarf_ranges.c
@@ -55,6 +55,52 @@
#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 **addrp, 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;
+ Dwarf_Addr end;
+
+ unsigned char *addr = *addrp;
+ bool begin_relocated = READ_AND_RELOCATE (__libdw_relocate_address, begin);
+ bool end_relocated = READ_AND_RELOCATE (__libdw_relocate_address, end);
+ *addrp = addr;
+
+ /* 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,
@@ -80,11 +126,12 @@ dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
const Elf_Data *d = die->cu->dbg->sectiondata[IDX_debug_ranges];
if (d == NULL && offset != 0)
{
- no_ranges:
__libdw_seterrno (DWARF_E_NO_DEBUG_RANGES);
return -1;
}
+ unsigned char *readp;
+ unsigned char *readendp;
if (offset == 0)
{
Dwarf_Attribute attr_mem;
@@ -94,14 +141,12 @@ dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
/* No PC attributes in this DIE at all, so an empty range list. */
return 0;
- /* Must have the form data4 or data8 which act as an offset. */
Dwarf_Word start_offset;
- if (INTUSE(dwarf_formudata) (attr, &start_offset) != 0)
+ if ((readp = __libdw_formptr (attr, IDX_debug_ranges,
+ DWARF_E_NO_DEBUG_RANGES,
+ &readendp, &start_offset)) == NULL)
return -1;
- if (d == NULL)
- goto no_ranges;
-
offset = start_offset;
assert ((Dwarf_Word) offset == start_offset);
@@ -127,45 +172,37 @@ dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
return -1;
}
}
- else if (offset < 0 || (size_t) offset >= d->d_size)
+ else
{
- __libdw_seterrno (DWARF_E_INVALID_OFFSET);
- return -1l;
- }
+ if (__libdw_offset_in_section (die->cu->dbg,
+ IDX_debug_ranges, offset, 1))
+ return -1l;
- unsigned char *readp = d->d_buf + offset;
+ readp = d->d_buf + offset;
+ readendp = d->d_buf + d->d_size;
+ }
next:
- if ((unsigned char *) d->d_buf + d->d_size - readp
- < die->cu->address_size * 2)
+ if (readendp - readp < die->cu->address_size * 2)
goto invalid;
Dwarf_Addr begin;
Dwarf_Addr end;
- if (die->cu->address_size == 8)
- {
- begin = read_8ubyte_unaligned_inc (die->cu->dbg, readp);
- end = read_8ubyte_unaligned_inc (die->cu->dbg, readp);
- if (begin == (uint64_t) -1l) /* Base address entry. */
- {
- *basep = end;
- goto next;
- }
- }
- else
+
+ switch (__libdw_read_begin_end_pair_inc (die->cu->dbg, IDX_debug_ranges,
+ &readp, die->cu->address_size,
+ &begin, &end, basep))
{
- begin = read_4ubyte_unaligned_inc (die->cu->dbg, readp);
- end = read_4ubyte_unaligned_inc (die->cu->dbg, readp);
- if (begin == (uint32_t) -1) /* Base address entry. */
- {
- *basep = end;
- goto next;
- }
+ 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;
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index 1d5a9b27..97a2e042 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -419,6 +419,156 @@ extern int __libdw_visit_scopes (unsigned int depth,
extern int __dwarf_errno_internal (void);
+/* Reader hooks. */
+
+/* Relocation hooks return -1 on error (in that case the error code
+ must already have been set), 0 if there is no relocation and 1 if a
+ relocation was present.*/
+
+static inline int
+__libdw_relocate_address (Dwarf *dbg __attribute__ ((unused)),
+ int sec_index __attribute__ ((unused)),
+ const void *addr __attribute__ ((unused)),
+ int width __attribute__ ((unused)),
+ Dwarf_Addr *val __attribute__ ((unused)))
+{
+ return 0;
+}
+
+static inline int
+__libdw_relocate_offset (Dwarf *dbg __attribute__ ((unused)),
+ int sec_index __attribute__ ((unused)),
+ const void *addr __attribute__ ((unused)),
+ int width __attribute__ ((unused)),
+ Dwarf_Off *val __attribute__ ((unused)))
+{
+ return 0;
+}
+
+static inline Elf_Data *
+__libdw_checked_get_data (Dwarf *dbg, int sec_index)
+{
+ Elf_Data *data = dbg->sectiondata[sec_index];
+ if (unlikely (data == NULL)
+ || unlikely (data->d_buf == NULL))
+ {
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return NULL;
+ }
+ return data;
+}
+
+static inline int
+__libdw_offset_in_section (Dwarf *dbg, int sec_index,
+ Dwarf_Off offset, size_t size)
+{
+ Elf_Data *data = __libdw_checked_get_data (dbg, sec_index);
+ if (data == NULL)
+ return -1;
+ if (unlikely (offset > data->d_size)
+ || unlikely (data->d_size - offset < size))
+ {
+ __libdw_seterrno (DWARF_E_INVALID_OFFSET);
+ return -1;
+ }
+
+ return 0;
+}
+
+static inline bool
+__libdw_in_section (Dwarf *dbg, int sec_index,
+ const void *addr, size_t size)
+{
+ Elf_Data *data = __libdw_checked_get_data (dbg, sec_index);
+ if (data == NULL)
+ return false;
+ if (unlikely (addr < data->d_buf)
+ || unlikely (data->d_size - (addr - data->d_buf) < size))
+ {
+ __libdw_seterrno (DWARF_E_INVALID_OFFSET);
+ return false;
+ }
+
+ return true;
+}
+
+#define READ_AND_RELOCATE(RELOC_HOOK, VAL) \
+ ({ \
+ if (!__libdw_in_section (dbg, sec_index, addr, width)) \
+ return -1; \
+ \
+ const unsigned char *orig_addr = addr; \
+ if (width == 4) \
+ VAL = read_4ubyte_unaligned_inc (dbg, addr); \
+ else \
+ VAL = read_8ubyte_unaligned_inc (dbg, addr); \
+ \
+ int status = RELOC_HOOK (dbg, sec_index, orig_addr, width, &VAL); \
+ if (status < 0) \
+ return status; \
+ status > 0; \
+ })
+
+static inline int
+__libdw_read_address_inc (Dwarf *dbg,
+ int sec_index, unsigned char **addrp,
+ int width, Dwarf_Addr *ret)
+{
+ unsigned char *addr = *addrp;
+ READ_AND_RELOCATE (__libdw_relocate_address, (*ret));
+ *addrp = addr;
+ return 0;
+}
+
+static inline int
+__libdw_read_address (Dwarf *dbg,
+ int sec_index, const unsigned char *addr,
+ int width, Dwarf_Addr *ret)
+{
+ READ_AND_RELOCATE (__libdw_relocate_address, (*ret));
+ return 0;
+}
+
+static inline int
+__libdw_read_offset_inc (Dwarf *dbg,
+ int sec_index, unsigned char **addrp,
+ int width, Dwarf_Off *ret, int sec_ret,
+ size_t size)
+{
+ unsigned char *addr = *addrp;
+ READ_AND_RELOCATE (__libdw_relocate_offset, (*ret));
+ *addrp = addr;
+ return __libdw_offset_in_section (dbg, sec_ret, *ret, size);
+}
+
+static inline int
+__libdw_read_offset (Dwarf *dbg,
+ int sec_index, const unsigned char *addr,
+ int width, Dwarf_Off *ret, int sec_ret,
+ size_t size)
+{
+ READ_AND_RELOCATE (__libdw_relocate_offset, (*ret));
+ return __libdw_offset_in_section (dbg, sec_ret, *ret, size);
+}
+
+/* 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;
+
+unsigned char * __libdw_formptr (Dwarf_Attribute *attr, int sec_index,
+ int err_nodata, unsigned char **endpp,
+ Dwarf_Off *offsetp)
+ internal_function;
+
+
+
/* Aliases to avoid PLTs. */
INTDECL (dwarf_attr)
INTDECL (dwarf_attr_integrate)