From 99d2372b25d1231d786b70278478c7a112f2b27c Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Sun, 14 Jun 2009 20:19:45 -0700 Subject: Squashed commit of the following: commit 77abb31cb8d55980ef92260917a7ecdd228b1a44 Author: Petr Machata Date: Mon Jun 8 15:46:16 2009 +0200 Fix a bug in offset checking commit b794eac4f8d3e08101b5d2924523b1259bbc1b17 Author: Petr Machata Date: Wed Jun 3 16:00:01 2009 +0200 Cosmetic, get rid of defining several variables per line commit a23938fe35d515a3d75a51f6204771f3cf6c9ec4 Author: Petr Machata Date: Wed Jun 3 15:50:03 2009 +0200 Restructure the code to decrease the binary size commit 7c301e3d4e8584dfb3174855fb6af3d5791dfeed Author: Petr Machata 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 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 Date: Fri May 22 08:40:25 2009 +0200 Call reloc hook with the original address, not incremented commit f1996388745566abc1ca1c1700b3b7eded208575 Author: Petr Machata 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 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 Date: Wed May 6 15:51:20 2009 +0200 Check for presence of data before loading the offset commit a2e7612b165d83dd241225f87075fa4f58d18781 Author: Petr Machata Date: Wed May 6 15:04:16 2009 +0200 Cosmetic changes commit 8b1aad2c2f6c8dc02b3e704e4f386c1827e385cb Author: Petr Machata 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 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 Date: Tue May 5 14:32:39 2009 +0200 Rename __libdw_read_udata_addr to __libdw_formptr commit 8273a2adaf8cb2ee203926af2849e4f96f8a6eaf Author: Petr Machata 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 Date: Mon May 4 18:09:13 2009 +0200 ChangeLog entries for previous commit commit 90d7c39454468b91c0fd6514a4e8d821222d6adb Author: Petr Machata 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 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 Date: Wed Apr 29 15:31:28 2009 +0200 dwarf_getlocation_addr uses read hooks commit ecbb8cdd8b500e37dc34fc246b912f704fe31ca4 Author: Petr Machata Date: Wed Apr 29 15:16:09 2009 +0200 dwarf_ranges and dwarf_formref use read hooks commit cb8f67b29a896c2660c10aa1028a9dbb377553e9 Author: Petr Machata Date: Tue Apr 28 18:39:04 2009 +0200 Convert several new functions to use read hooks commit b130453eb16a8cf042915e312cc5f189b8b92c01 Author: Petr Machata Date: Tue Apr 28 18:38:27 2009 +0200 Add length read hooks commit bd885ff694817b965231d99f1ab867947998e734 Author: Petr Machata Date: Tue Apr 28 18:36:17 2009 +0200 Constify read hook arguments commit 66fe03f1e489a88b89a15c9e13f9bd33db2729b1 Author: Petr Machata 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 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 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 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 Date: Thu Apr 23 17:44:48 2009 +0200 Use the new reader hooks in several places commit 11c3d97a5b40ea15edf324092b03da3050610d01 Author: Petr Machata Date: Thu Apr 23 17:40:03 2009 +0200 Introduce reader hooks --- libdw/ChangeLog | 34 +++++++++++ libdw/dwarf_formaddr.c | 8 +-- libdw/dwarf_formref_die.c | 7 +-- libdw/dwarf_formstring.c | 12 +--- libdw/dwarf_formudata.c | 53 ++++++++++++++-- libdw/dwarf_getaranges.c | 27 ++++----- libdw/dwarf_getlocation.c | 94 ++++++++++------------------- libdw/dwarf_getpubnames.c | 15 ++--- libdw/dwarf_getsrclines.c | 27 ++++----- libdw/dwarf_nextcu.c | 15 +++-- libdw/dwarf_ranges.c | 105 +++++++++++++++++++++----------- libdw/libdwP.h | 150 ++++++++++++++++++++++++++++++++++++++++++++++ 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 + + * 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 + + * 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 + + * 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 + + * 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 * 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 #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 #include +/* 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) -- cgit v1.2.3