summaryrefslogtreecommitdiff
path: root/usr/src/lib/libdwarf/common/dwarf_frame2.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libdwarf/common/dwarf_frame2.c')
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_frame2.c1736
1 files changed, 1015 insertions, 721 deletions
diff --git a/usr/src/lib/libdwarf/common/dwarf_frame2.c b/usr/src/lib/libdwarf/common/dwarf_frame2.c
index 01b9ec497b..923517640f 100644
--- a/usr/src/lib/libdwarf/common/dwarf_frame2.c
+++ b/usr/src/lib/libdwarf/common/dwarf_frame2.c
@@ -1,118 +1,152 @@
/*
-
Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved.
- Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of version 2.1 of the GNU Lesser General Public License
- as published by the Free Software Foundation.
-
- This program is distributed in the hope that it would be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ Portions Copyright (C) 2007-2020 David Anderson. All Rights Reserved.
+ Portions Copyright (C) 2010-2012 SN Systems Ltd. All Rights Reserved.
+
+ This program is free software; you can redistribute it
+ and/or modify it under the terms of version 2.1 of the
+ GNU Lesser General Public License as published by the Free
+ Software Foundation.
+
+ This program is distributed in the hope that it would be
+ useful, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+ Further, this software is distributed without any warranty
+ that it is free of the rightful claim of any third person
+ regarding infringement or the like. Any license provided
+ herein, whether implied or otherwise, applies only to this
+ software file. Patent licenses, if any, provided herein
+ do not apply to combinations of this program with other
+ software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this program; if not, write the
+ Free Software Foundation, Inc., 51 Franklin Street - Fifth
+ Floor, Boston MA 02110-1301, USA.
- Further, this software is distributed without any warranty that it is
- free of the rightful claim of any third person regarding infringement
- or the like. Any license provided herein, whether implied or
- otherwise, applies only to this software file. Patent licenses, if
- any, provided herein do not apply to combinations of this program with
- other software, or any other product whatsoever.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this program; if not, write the Free Software
- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
- USA.
-
- Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
- Mountain View, CA 94043, or:
+*/
- http://www.sgi.com
+/* This implements _dwarf_get_fde_list_internal()
+ and related helper functions for reading cie/fde data. */
- For further information regarding this notice, see:
+#include "config.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif /* HAVE_STDLIB_H */
+#include "dwarf_incl.h"
+#include "dwarf_alloc.h"
+#include "dwarf_error.h"
+#include "dwarf_util.h"
+#include "dwarf_frame.h"
+#include "dwarf_arange.h" /* using Arange as a way to build a list */
+#include "dwarfstring.h"
- http://oss.sgi.com/projects/GenInfo/NoticeExplan
+/* For a little information about .eh_frame see
+ https://stackoverflow.com/questions/14091231/what-do-the-eh-frame-and-eh-frame-hdr-sections-store-exactly
+ http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
+ The above give information about fields and sizes but
+ very very little about content.
-*/
-/* The address of the Free Software Foundation is
- Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- Boston, MA 02110-1301, USA.
- SGI has moved from the Crittenden Lane address.
+ .eh_frame_hdr contains data for C++ unwinding. Namely
+ tables for fast access into .eh_frame.
*/
-/*
- This implements _dwarf_get_fde_list_internal()
- and related helper functions for reading cie/fde data.
-*/
+#define TRUE 1
+#define FALSE 0
+#if 0 /* FOR DEBUGGING */
+/* For debugging only. */
+static void
+dump_bytes(const char *msg,Dwarf_Small * start, long len)
+{
+ Dwarf_Small *end = start + len;
+ Dwarf_Small *cur = start;
+ printf("%s (0x%lx) ",msg,(unsigned long)start);
+ for (; cur < end; cur++) {
+ printf("%02x", *cur);
+ }
+ printf("\n");
+}
-#include "config.h"
-#include "dwarf_incl.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include "dwarf_frame.h"
-#include "dwarf_arange.h" /* using Arange as a way to build a
- list */
-
+#endif
static int dwarf_find_existing_cie_ptr(Dwarf_Small * cie_ptr,
- Dwarf_Cie cur_cie_ptr,
- Dwarf_Cie * cie_ptr_to_use_out,
- Dwarf_Cie head_cie_ptr);
+ Dwarf_Cie cur_cie_ptr,
+ Dwarf_Cie * cie_ptr_to_use_out,
+ Dwarf_Cie head_cie_ptr);
static void dealloc_fde_cie_list_internal(Dwarf_Fde head_fde_ptr,
- Dwarf_Cie head_cie_ptr);
+ Dwarf_Cie head_cie_ptr);
static int dwarf_create_cie_from_start(Dwarf_Debug dbg,
- Dwarf_Small * cie_ptr_val,
- Dwarf_Small * section_ptr,
- Dwarf_Unsigned section_index,
- Dwarf_Unsigned section_length,
- Dwarf_Small * frame_ptr_end,
- Dwarf_Unsigned cie_id_value,
- Dwarf_Unsigned cie_count,
- int use_gnu_cie_calc,
- Dwarf_Cie * cie_ptr_to_use_out,
- Dwarf_Error * error);
-
-static Dwarf_Small *get_cieptr_given_offset(Dwarf_Unsigned cie_id_value,
- int use_gnu_cie_calc,
- Dwarf_Small * section_ptr,
- Dwarf_Small * cie_id_addr);
+ Dwarf_Small * cie_ptr_val,
+ Dwarf_Small * section_ptr,
+ Dwarf_Unsigned section_index,
+ Dwarf_Unsigned section_length,
+ Dwarf_Small * section_ptr_end,
+ Dwarf_Unsigned cie_id_value,
+ Dwarf_Unsigned cie_count,
+ int use_gnu_cie_calc,
+ Dwarf_Cie * cie_ptr_to_use_out,
+ Dwarf_Error * error);
+
static int get_gcc_eh_augmentation(Dwarf_Debug dbg,
- Dwarf_Small * frame_ptr,
- unsigned long
- *size_of_augmentation_data,
- enum Dwarf_augmentation_type augtype,
- Dwarf_Small * section_pointer,
- Dwarf_Small * fde_eh_encoding_out,
- char *augmentation);
+ Dwarf_Small * frame_ptr,
+ unsigned long
+ *size_of_augmentation_data,
+ enum Dwarf_augmentation_type augtype,
+ Dwarf_Small * section_end_pointer,
+ char *augmentation,
+ Dwarf_Error *error);
static int
- gnu_aug_encodings(Dwarf_Debug dbg, char *augmentation,
- Dwarf_Small * aug_data, Dwarf_Unsigned aug_data_len,
- Dwarf_Half address_size,
- unsigned char *pers_hand_enc_out,
- unsigned char *lsda_enc_out,
- unsigned char *fde_begin_enc_out,
- Dwarf_Addr * gnu_pers_addr_out);
+gnu_aug_encodings(Dwarf_Debug dbg, char *augmentation,
+ Dwarf_Small * aug_data, Dwarf_Unsigned aug_data_len,
+ Dwarf_Half address_size,
+ unsigned char *pers_hand_enc_out,
+ unsigned char *lsda_enc_out,
+ unsigned char *fde_begin_enc_out,
+ Dwarf_Addr * gnu_pers_addr_out,
+ Dwarf_Error *error);
static int read_encoded_ptr(Dwarf_Debug dbg,
- Dwarf_Small * section_pointer,
- Dwarf_Small * input_field,
- int gnu_encoding,
- Dwarf_Half address_size,
- Dwarf_Unsigned * addr,
- Dwarf_Small ** input_field_out);
+ Dwarf_Small * section_pointer,
+ Dwarf_Small * input_field,
+ int gnu_encoding,
+ Dwarf_Small * section_ptr_end,
+ Dwarf_Half address_size,
+ Dwarf_Unsigned * addr,
+ Dwarf_Small ** input_field_out,
+ Dwarf_Error *error);
-static int qsort_compare(const void *elem1, const void *elem2);
+/* Called by qsort to compare FDE entries.
+ Consumer code expects the array of FDE pointers to be
+ in address order.
+*/
+static int
+qsort_compare(const void *elem1, const void *elem2)
+{
+ const Dwarf_Fde fde1 = *(const Dwarf_Fde *) elem1;
+ const Dwarf_Fde fde2 = *(const Dwarf_Fde *) elem2;
+ Dwarf_Addr addr1 = fde1->fd_initial_location;
+ Dwarf_Addr addr2 = fde2->fd_initial_location;
+ if (addr1 < addr2) {
+ return -1;
+ } else if (addr1 > addr2) {
+ return 1;
+ }
+ return 0;
+}
-/* Adds 'newone' to the end of the list starting at 'head'
- and makes the new one 'cur'rent. */
+/* Adds 'newone' to the end of the list starting at 'head'
+ and makes the new one 'cur'rent. */
static void
chain_up_fde(Dwarf_Fde newone, Dwarf_Fde * head, Dwarf_Fde * cur)
{
@@ -125,8 +159,8 @@ chain_up_fde(Dwarf_Fde newone, Dwarf_Fde * head, Dwarf_Fde * cur)
}
-/* Adds 'newone' to the end of the list starting at 'head'
- and makes the new one 'cur'rent. */
+/* Adds 'newone' to the end of the list starting at 'head'
+ and makes the new one 'cur'rent. */
static void
chain_up_cie(Dwarf_Cie newone, Dwarf_Cie * head, Dwarf_Cie * cur)
{
@@ -138,16 +172,16 @@ chain_up_cie(Dwarf_Cie newone, Dwarf_Cie * head, Dwarf_Cie * cur)
*cur = newone;
}
-/* The size of the length field plus the
- value of length must be an integral
- multiple of the address size. Dwarf4 standard.
+/* The size of the length field plus the
+ value of length must be an integral
+ multiple of the address size. Dwarf4 standard.
- A constant that gives the number of bytes of the CIE
- structure, not including the length field itself
- (where length mod <size of an address> == 0)
+ A constant that gives the number of bytes of the CIE
+ structure, not including the length field itself
+ (where length mod <size of an address> == 0)
(see Section 7.2.2). Dwarf3 standard.
-
- A uword constant that gives the number of bytes of
+
+ A uword constant that gives the number of bytes of
the CIE structure, not including the
length field, itself (length mod <addressing unit size> == 0).
Dwarf2 standard.*/
@@ -160,67 +194,129 @@ validate_length(Dwarf_Debug dbg,
Dwarf_Small * ciefde_start,
const char * cieorfde)
{
- Dwarf_Unsigned address_size = cieptr->ci_address_size;
+ Dwarf_Unsigned address_size = 0;
Dwarf_Unsigned length_field_summed = length_size + extension_size;
Dwarf_Unsigned total_len = length + length_field_summed;
- Dwarf_Unsigned mod = total_len % address_size;
+ Dwarf_Unsigned mod = 0;
+ if (cieptr) {
+ address_size = cieptr->ci_address_size;
+ } else {
+ address_size = dbg->de_pointer_size;
+ }
+ mod = total_len % address_size;
if (mod != 0) {
- char msg[DW_HARMLESS_ERROR_MSG_STRING_SIZE];
+ dwarfstring harm;
Dwarf_Unsigned sectionoffset = ciefde_start - section_ptr;
- snprintf(msg,sizeof(msg),
+
+ dwarfstring_constructor(&harm);
+ if (!cieorfde || (strlen(cieorfde) > 3)) {
+ /* Coding error or memory corruption? */
+ cieorfde = "ERROR!";
+ }
+ dwarfstring_append_printf_u(&harm,
"DW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE"
- " len=0x%" DW_PR_DUx
- ", len size=0x%" DW_PR_DUx
- ", extn size=0x%" DW_PR_DUx
- ", totl length=0x%" DW_PR_DUx
- ", addr size=0x%" DW_PR_DUx
- ", mod=0x%" DW_PR_DUx " must be zero"
- " in %s"
- ", offset 0x%" DW_PR_DUx ".",
- length,
- length_size,
- extension_size,
- total_len,address_size, mod,
- cieorfde,
+ " len=0x%" DW_PR_XZEROS DW_PR_DUx,
+ length);
+ dwarfstring_append_printf_u(&harm,
+ ", len size=0x%" DW_PR_XZEROS DW_PR_DUx,
+ length_size);
+ dwarfstring_append_printf_u(&harm,
+ ", extn size=0x%" DW_PR_XZEROS DW_PR_DUx,
+ extension_size);
+ dwarfstring_append_printf_u(&harm,
+ ", totl length=0x%" DW_PR_XZEROS DW_PR_DUx,
+ total_len);
+ dwarfstring_append_printf_u(&harm,
+ ", addr size=0x%" DW_PR_XZEROS DW_PR_DUx,
+ address_size);
+ dwarfstring_append_printf_u(&harm,
+ ", mod=0x%" DW_PR_XZEROS DW_PR_DUx " must be zero",
+ mod);
+ dwarfstring_append_printf_s(&harm,
+ " in %s",(char *)cieorfde);
+ dwarfstring_append_printf_u(&harm,
+ ", offset 0x%" DW_PR_XZEROS DW_PR_DUx ".",
sectionoffset);
- dwarf_insert_harmless_error(dbg,msg);
+ dwarf_insert_harmless_error(dbg,
+ dwarfstring_string(&harm));
+ dwarfstring_destructor(&harm);
}
return;
}
-#if 0
+#if 0 /* FOR DEBUGGING */
/* For debugging only. */
static void
print_prefix(struct cie_fde_prefix_s *prefix, int line)
{
printf("prefix-print, prefix at 0x%lx, line %d\n",
- (long) prefix, line);
+ (unsigned long) prefix, line);
printf(" start addr 0x%lx after prefix 0x%lx\n",
- (long) prefix->cf_start_addr,
- (long) prefix->cf_addr_after_prefix);
- printf(" length 0x%" DW_PR_DUx ", len size %d ext size %d\n",
- (Dwarf_Unsigned) prefix->cf_length,
- prefix->cf_local_length_size,
- prefix->cf_local_extension_size);
+ (unsigned long) prefix->cf_start_addr,
+ (unsigned long) prefix->cf_addr_after_prefix);
+ printf(" length 0x%" DW_PR_DUx ", len size %d ext size %d\n",
+ (Dwarf_Unsigned) prefix->cf_length,
+ prefix->cf_local_length_size,
+ prefix->cf_local_extension_size);
printf(" cie_id 0x%" DW_PR_DUx " cie_id cie_id_addr 0x%lx\n",
- (Dwarf_Unsigned) prefix->cf_cie_id,
- (long) prefix->cf_cie_id_addr);
+ (Dwarf_Unsigned) prefix->cf_cie_id,
+ (long) prefix->cf_cie_id_addr);
printf
(" sec ptr 0x%lx sec index %" DW_PR_DSd " sec len 0x%" DW_PR_DUx " sec past end 0x%lx\n",
- (long) prefix->cf_section_ptr,
- (Dwarf_Signed) prefix->cf_section_index,
- (Dwarf_Unsigned) prefix->cf_section_length,
- (long) prefix->cf_section_ptr + prefix->cf_section_length);
+ (unsigned long) prefix->cf_section_ptr,
+ (Dwarf_Signed) prefix->cf_section_index,
+ (Dwarf_Unsigned) prefix->cf_section_length,
+ (unsigned long) prefix->cf_section_ptr +
+ (unsigned long)prefix->cf_section_length);
}
#endif
+/* Make the 'cieptr' consistent across .debug_frame and .eh_frame.
+ Calculate a pointer into section bytes given a cie_id in
+ an FDE header.
+
+ In .debug_frame, the CIE_pointer is an offset in .debug_frame.
+
+ In .eh_frame, the CIE Pointer is, when
+ cie_id_value subtracted from the
+ cie_id_addr, the address in memory of
+ a CIE length field.
+ Since cie_id_addr is the address of an FDE CIE_Pointer
+ field, cie_id_value for .eh_frame
+ has to account for the length-prefix.
+ so that the returned cieptr really points to
+ a CIE length field. Whew!
+ Available documentation on this is just a bit
+ ambiguous, but this calculation is correct.
+*/
+static Dwarf_Small *
+get_cieptr_given_offset(Dwarf_Unsigned cie_id_value,
+ int use_gnu_cie_calc,
+ Dwarf_Small * section_ptr,
+ Dwarf_Small * cie_id_addr)
+{
+ Dwarf_Small *cieptr = 0;
-/* Internal function called from various places to create
- lists of CIEs and FDEs. Not directly called
- by consumer code */
+ if (use_gnu_cie_calc) {
+ /* cie_id value is offset, in section, of the cie_id itself, to
+ use vm ptr of the value, less the value, to get to the cie
+ header. */
+ cieptr = cie_id_addr - cie_id_value;
+ } else {
+ /* Traditional dwarf section offset is in cie_id */
+ cieptr = section_ptr + cie_id_value;
+ }
+ return cieptr;
+}
+
+
+
+/* Internal function called from various places to create
+ lists of CIEs and FDEs. Not directly called
+ by consumer code */
int
_dwarf_get_fde_list_internal(Dwarf_Debug dbg, Dwarf_Cie ** cie_data,
Dwarf_Signed * cie_element_count,
@@ -234,114 +330,110 @@ _dwarf_get_fde_list_internal(Dwarf_Debug dbg, Dwarf_Cie ** cie_data,
{
/* Scans the debug_frame section. */
Dwarf_Small *frame_ptr = section_ptr;
- Dwarf_Small *frame_ptr_end = section_ptr + section_length;
+ Dwarf_Small *section_ptr_end = section_ptr + section_length;
- /*
- New_cie points to the Cie being read, and head_cie_ptr and
- cur_cie_ptr are used for chaining them up in sequence.
- In case cie's are reused aggressively we need tail_cie_ptr
- to add to the chain. If we re-use an early cie
- later on, that does not mean we chain a new cie to the early one,
- we always chain it to the tail. */
+ /* New_cie points to the Cie being read, and head_cie_ptr and
+ cur_cie_ptr are used for chaining them up in sequence.
+ In case cie's are reused aggressively we need tail_cie_ptr
+ to add to the chain. If we re-use an early cie
+ later on, that does not mean we chain a new cie to the early one,
+ we always chain it to the tail. */
Dwarf_Cie head_cie_ptr = NULL;
Dwarf_Cie cur_cie_ptr = NULL;
Dwarf_Cie tail_cie_ptr = NULL;
- Dwarf_Word cie_count = 0;
+ Dwarf_Unsigned cie_count = 0;
- /*
- Points to a list of contiguous pointers to Dwarf_Cie structures.
- */
+ /* Points to a list of contiguous pointers to Dwarf_Cie structures.
+ */
Dwarf_Cie *cie_list_ptr = 0;
- /*
- New_fde points to the Fde being created, and head_fde_ptr and
- cur_fde_ptr are used to chain them up. */
+ /* New_fde points to the Fde being created, and head_fde_ptr and
+ cur_fde_ptr are used to chain them up. */
Dwarf_Fde head_fde_ptr = NULL;
Dwarf_Fde cur_fde_ptr = NULL;
- Dwarf_Word fde_count = 0;
+ Dwarf_Unsigned fde_count = 0;
- /*
- Points to a list of contiguous pointers to Dwarf_Fde structures.
- */
+ /* Points to a list of contiguous pointers to Dwarf_Fde structures.
+ */
Dwarf_Fde *fde_list_ptr = NULL;
- Dwarf_Word i = 0;
+ Dwarf_Unsigned i = 0;
int res = DW_DLV_ERROR;
if (frame_ptr == 0) {
return DW_DLV_NO_ENTRY;
}
- /* We create the fde and cie arrays. Processing each CIE as we come
- to it or as an FDE refers to it. We cannot process 'late' CIEs
- late as GNU .eh_frame complexities mean we need the whole CIE
- before we can process the FDE correctly. */
- while (frame_ptr < frame_ptr_end) {
+ /* We create the fde and cie arrays. Processing each CIE as we come
+ to it or as an FDE refers to it. We cannot process 'late' CIEs
+ late as GNU .eh_frame complexities mean we need the whole CIE
+ before we can process the FDE correctly. */
+ while (frame_ptr < section_ptr_end) {
struct cie_fde_prefix_s prefix;
- /* First read in the 'common prefix' to figure out what we are
- to do with this entry. */
+ /* First read in the 'common prefix' to figure out what we are
+ to do with this entry. */
memset(&prefix, 0, sizeof(prefix));
res = dwarf_read_cie_fde_prefix(dbg,
- frame_ptr, section_ptr,
- section_index,
- section_length, &prefix, error);
+ frame_ptr, section_ptr,
+ section_index,
+ section_length, &prefix, error);
if (res == DW_DLV_ERROR) {
- dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr);
+ dealloc_fde_cie_list_internal(head_fde_ptr,
+ head_cie_ptr);
return res;
}
- if (res == DW_DLV_NO_ENTRY)
+ if (res == DW_DLV_NO_ENTRY) {
break;
+ }
frame_ptr = prefix.cf_addr_after_prefix;
- if (frame_ptr >= frame_ptr_end) {
+ if (frame_ptr >= section_ptr_end) {
dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr);
_dwarf_error(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
return DW_DLV_ERROR;
-
}
if (prefix.cf_cie_id == cie_id_value) {
/* This is a CIE. */
Dwarf_Cie cie_ptr_to_use = 0;
+ int resc = 0;
- int res = dwarf_find_existing_cie_ptr(prefix.cf_start_addr,
- cur_cie_ptr,
- &cie_ptr_to_use,
- head_cie_ptr);
-
- if (res == DW_DLV_OK) {
+ resc = dwarf_find_existing_cie_ptr(prefix.cf_start_addr,
+ cur_cie_ptr,
+ &cie_ptr_to_use,
+ head_cie_ptr);
+ if (resc == DW_DLV_OK) {
cur_cie_ptr = cie_ptr_to_use;
/* Ok. Seen already. */
- } else if (res == DW_DLV_NO_ENTRY) {
+ } else if (resc == DW_DLV_NO_ENTRY) {
/* CIE before its FDE in this case. */
- res = dwarf_create_cie_from_after_start(dbg,
- &prefix,
- section_ptr,
- frame_ptr,
- cie_count,
- use_gnu_cie_calc,
- &cie_ptr_to_use,
- error);
- /* ASSERT: res==DW_DLV_NO_ENTRY impossible. */
- if (res == DW_DLV_ERROR) {
+ resc = dwarf_create_cie_from_after_start(dbg,
+ &prefix,
+ section_ptr,
+ frame_ptr,
+ section_ptr_end,
+ cie_count,
+ use_gnu_cie_calc,
+ &cie_ptr_to_use,
+ error);
+ if (resc != DW_DLV_OK) {
dealloc_fde_cie_list_internal(head_fde_ptr,
- head_cie_ptr);
- return res;
+ head_cie_ptr);
+ return resc;
}
- /* ASSERT res != DW_DLV_NO_ENTRY */
cie_count++;
chain_up_cie(cie_ptr_to_use, &head_cie_ptr,
- &tail_cie_ptr);
+ &tail_cie_ptr);
cur_cie_ptr = tail_cie_ptr;
} else { /* res == DW_DLV_ERROR */
dealloc_fde_cie_list_internal(head_fde_ptr,
- head_cie_ptr);
- return res;
+ head_cie_ptr);
+ return resc;
}
frame_ptr = cie_ptr_to_use->ci_cie_start +
cie_ptr_to_use->ci_length +
@@ -349,87 +441,102 @@ _dwarf_get_fde_list_internal(Dwarf_Debug dbg, Dwarf_Cie ** cie_data,
cie_ptr_to_use->ci_extension_size;
continue;
} else {
- /* this is an FDE, Frame Description Entry, see the Dwarf
- Spec, section 6.4.1 */
- int res = DW_DLV_ERROR;
+ /* This is an FDE, Frame Description Entry, see the Dwarf
+ Spec, (section 6.4.1 in DWARF2, DWARF3, DWARF4, ...)
+ Or see the .eh_frame specification,
+ from the Linux Foundation (or other source). */
+ int resf = DW_DLV_ERROR;
Dwarf_Cie cie_ptr_to_use = 0;
Dwarf_Fde fde_ptr_to_use = 0;
-
- /* Do not call this twice on one prefix, as
- prefix.cf_cie_id_addr is altered as a side effect. */
- Dwarf_Small *cieptr_val =
- get_cieptr_given_offset(prefix.cf_cie_id,
- use_gnu_cie_calc,
- section_ptr,
- prefix.cf_cie_id_addr);
-
- res = dwarf_find_existing_cie_ptr(cieptr_val,
- cur_cie_ptr,
- &cie_ptr_to_use,
- head_cie_ptr);
- if (res == DW_DLV_OK) {
+ Dwarf_Small *cieptr_val = 0;
+
+ cieptr_val = get_cieptr_given_offset(prefix.cf_cie_id,
+ use_gnu_cie_calc,
+ section_ptr,
+ prefix.cf_cie_id_addr);
+ resf = dwarf_find_existing_cie_ptr(cieptr_val,
+ cur_cie_ptr,
+ &cie_ptr_to_use,
+ head_cie_ptr);
+ if (resf == DW_DLV_OK) {
cur_cie_ptr = cie_ptr_to_use;
/* Ok. Seen CIE already. */
- } else if (res == DW_DLV_NO_ENTRY) {
- res = dwarf_create_cie_from_start(dbg,
- cieptr_val,
- section_ptr,
- section_index,
- section_length,
- frame_ptr_end,
- cie_id_value,
- cie_count,
- use_gnu_cie_calc,
- &cie_ptr_to_use,
- error);
- if (res == DW_DLV_ERROR) {
+ } else if (resf == DW_DLV_NO_ENTRY) {
+ resf = dwarf_create_cie_from_start(dbg,
+ cieptr_val,
+ section_ptr,
+ section_index,
+ section_length,
+ section_ptr_end,
+ cie_id_value,
+ cie_count,
+ use_gnu_cie_calc,
+ &cie_ptr_to_use,
+ error);
+ if (resf == DW_DLV_ERROR) {
dealloc_fde_cie_list_internal(head_fde_ptr,
- head_cie_ptr);
- return res;
- } else if (res == DW_DLV_NO_ENTRY) {
- return res;
+ head_cie_ptr);
+ return resf;
+ } else if (resf == DW_DLV_NO_ENTRY) {
+ return resf;
}
++cie_count;
chain_up_cie(cie_ptr_to_use, &head_cie_ptr,
- &tail_cie_ptr);
+ &tail_cie_ptr);
cur_cie_ptr = tail_cie_ptr;
} else {
/* DW_DLV_ERROR */
- return res;
+ return resf;
}
- res = dwarf_create_fde_from_after_start(dbg,
- &prefix,
- section_ptr,
- frame_ptr,
- use_gnu_cie_calc,
- cie_ptr_to_use,
- &fde_ptr_to_use,
- error);
- if (res == DW_DLV_ERROR) {
- return res;
+ resf = dwarf_create_fde_from_after_start(dbg,
+ &prefix,
+ section_ptr,
+ frame_ptr,
+ section_ptr_end,
+ use_gnu_cie_calc,
+ cie_ptr_to_use,
+ &fde_ptr_to_use,
+ error);
+ if (resf == DW_DLV_ERROR) {
+ dealloc_fde_cie_list_internal(head_fde_ptr,
+ head_cie_ptr);
+ return resf;
+ } else if (resf == DW_DLV_NO_ENTRY) {
+ /* impossible. */
+ return resf;
}
chain_up_fde(fde_ptr_to_use, &head_fde_ptr, &cur_fde_ptr);
fde_count++;
/* ASSERT: DW_DLV_OK. */
- frame_ptr = fde_ptr_to_use->fd_fde_start +
- fde_ptr_to_use->fd_length +
- fde_ptr_to_use->fd_length_size +
- fde_ptr_to_use->fd_extension_size;
+ frame_ptr = cur_fde_ptr->fd_fde_start +
+ cur_fde_ptr->fd_length +
+ cur_fde_ptr->fd_length_size +
+ cur_fde_ptr->fd_extension_size;
+ if (frame_ptr < fde_ptr_to_use->fd_fde_instr_start) {
+ /* Sanity check. With a really short fde instruction
+ set and address_size we think is 8
+ as it is ELF64 (but is
+ really 4, as in DWARF{2,3} where we have
+ no FDE address_size) we emit an error.
+ This error means things will not go well. */
+ dealloc_fde_cie_list_internal(head_fde_ptr,
+ head_cie_ptr);
+ _dwarf_error(dbg,error,
+ DW_DLE_DEBUG_FRAME_POSSIBLE_ADDRESS_BOTCH);
+ return DW_DLV_ERROR;
+ }
continue;
-
}
-
}
-
- /* Now build list of CIEs from the list. If there are no CIEs
- there should be no FDEs. */
+ /* Now build list of CIEs from the list. If there are no CIEs
+ there should be no FDEs. */
if (cie_count > 0) {
cie_list_ptr = (Dwarf_Cie *)
_dwarf_get_alloc(dbg, DW_DLA_LIST, cie_count);
} else {
- if(fde_count > 0) {
+ if (fde_count > 0) {
dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr);
_dwarf_error(dbg, error, DW_DLE_ORPHAN_FDE);
return DW_DLV_ERROR;
@@ -442,16 +549,20 @@ _dwarf_get_fde_list_internal(Dwarf_Debug dbg, Dwarf_Cie ** cie_data,
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return DW_DLV_ERROR;
}
+ if (!head_cie_ptr) {
+ /* Should be impossible. */
+ _dwarf_error(dbg, error,DW_DLE_DEBUGFRAME_ERROR);
+ return DW_DLV_ERROR;
+ }
cur_cie_ptr = head_cie_ptr;
for (i = 0; i < cie_count; i++) {
*(cie_list_ptr + i) = cur_cie_ptr;
cur_cie_ptr = cur_cie_ptr->ci_next;
}
-
-
- /* Now build array of FDEs from the list.
- With orphan CIEs (meaning no FDEs) lets not return DW_DLV_NO_ENTRY */
+ /* Now build array of FDEs from the list.
+ With orphan CIEs (meaning no FDEs)
+ lets not return DW_DLV_NO_ENTRY */
if (fde_count > 0) {
fde_list_ptr = (Dwarf_Fde *)
_dwarf_get_alloc(dbg, DW_DLA_LIST, fde_count);
@@ -471,37 +582,38 @@ _dwarf_get_fde_list_internal(Dwarf_Debug dbg, Dwarf_Cie ** cie_data,
*fde_data = fde_list_ptr;
*fde_element_count = fde_count;
- if(use_gnu_cie_calc) {
- dbg->de_fde_data_eh = fde_list_ptr;
- dbg->de_fde_count_eh = fde_count;
- dbg->de_cie_data_eh = cie_list_ptr;
- dbg->de_cie_count_eh = cie_count;
+ if (use_gnu_cie_calc) {
+ dbg->de_fde_data_eh = fde_list_ptr;
+ dbg->de_fde_count_eh = fde_count;
+ dbg->de_cie_data_eh = cie_list_ptr;
+ dbg->de_cie_count_eh = cie_count;
} else {
- dbg->de_fde_data = fde_list_ptr;
- dbg->de_fde_count = fde_count;
- dbg->de_cie_data = cie_list_ptr;
- dbg->de_cie_count = cie_count;
+ dbg->de_fde_data = fde_list_ptr;
+ dbg->de_fde_count = fde_count;
+ dbg->de_cie_data = cie_list_ptr;
+ dbg->de_cie_count = cie_count;
}
- /* Sort the list by the address so that dwarf_get_fde_at_pc() can
- binary search this list. */
- if(fde_count > 0) {
+ /* Sort the list by the address so that dwarf_get_fde_at_pc() can
+ binary search this list. */
+ if (fde_count > 0) {
qsort((void *) fde_list_ptr, fde_count, sizeof(Dwarf_Ptr),
- qsort_compare);
+ qsort_compare);
}
return (DW_DLV_OK);
}
-/* Internal function, not called by consumer code.
- 'prefix' has accumulated the info up thru the cie-id
- and now we consume the rest and build a Dwarf_Cie_s structure.
+/* Internal function, not called by consumer code.
+ 'prefix' has accumulated the info up thru the cie-id
+ and now we consume the rest and build a Dwarf_Cie_s structure.
*/
int
dwarf_create_cie_from_after_start(Dwarf_Debug dbg,
struct cie_fde_prefix_s *prefix,
Dwarf_Small * section_pointer,
Dwarf_Small * frame_ptr,
+ Dwarf_Small * section_ptr_end,
Dwarf_Unsigned cie_count,
int use_gnu_cie_calc,
Dwarf_Cie * cie_ptr_out,
@@ -509,83 +621,170 @@ dwarf_create_cie_from_after_start(Dwarf_Debug dbg,
{
Dwarf_Cie new_cie = 0;
- /* egcs-1.1.2 .eh_frame uses 0 as the distinguishing id. sgi uses
- -1 (in .debug_frame). .eh_frame not quite identical to
- .debug_frame */
- /* We here default the address size as it is not present
- in DWARF2 or DWARF3 cie data, below we set it right if
- it is present. */
+ /* egcs-1.1.2 .eh_frame uses 0 as the distinguishing id. sgi uses
+ -1 (in .debug_frame). .eh_frame not quite identical to
+ .debug_frame */
+ /* We here default the address size as it is not present
+ in DWARF2 or DWARF3 cie data, below we set it right if
+ it is present. */
Dwarf_Half address_size = dbg->de_pointer_size;
- Dwarf_Small eh_fde_encoding = 0;
Dwarf_Small *augmentation = 0;
Dwarf_Half segment_size = 0;
- Dwarf_Sword data_alignment_factor = -1;
- Dwarf_Word code_alignment_factor = 4;
+ Dwarf_Signed data_alignment_factor = -1;
+ Dwarf_Unsigned code_alignment_factor = 4;
Dwarf_Unsigned return_address_register = 31;
int local_length_size = 0;
- Dwarf_Word leb128_length = 0;
+ Dwarf_Unsigned leb128_length = 0;
Dwarf_Unsigned cie_aug_data_len = 0;
Dwarf_Small *cie_aug_data = 0;
Dwarf_Addr gnu_personality_handler_addr = 0;
unsigned char gnu_personality_handler_encoding = 0;
unsigned char gnu_lsda_encoding = 0;
unsigned char gnu_fde_begin_encoding = 0;
+ int res = 0;
+ Dwarf_Small version = 0;
enum Dwarf_augmentation_type augt = aug_unknown;
+ /* This is a CIE, Common Information Entry: See the dwarf spec,
+ section 6.4.1 */
+ if (frame_ptr >= section_ptr_end) {
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
+ return DW_DLV_ERROR;
+ }
+ version = *(Dwarf_Small *) frame_ptr;
- /* this is a CIE, Common Information Entry: See the dwarf spec,
- section 6.4.1 */
- Dwarf_Small version = *(Dwarf_Small *) frame_ptr;
+ if ((frame_ptr+2) >= section_ptr_end) {
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
+ return DW_DLV_ERROR;
+ }
frame_ptr++;
if (version != DW_CIE_VERSION && version != DW_CIE_VERSION3 &&
- version != DW_CIE_VERSION4) {
+ version != DW_CIE_VERSION4 && version != DW_CIE_VERSION5) {
_dwarf_error(dbg, error, DW_DLE_FRAME_VERSION_BAD);
return (DW_DLV_ERROR);
}
augmentation = frame_ptr;
+
+ res = _dwarf_check_string_valid(dbg,section_pointer,
+ frame_ptr,section_ptr_end,
+ DW_DLE_AUGMENTATION_STRING_OFF_END,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
frame_ptr = frame_ptr + strlen((char *) frame_ptr) + 1;
+ if (frame_ptr >= section_ptr_end) {
+ _dwarf_error_string(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD,
+ "DW_DLE_DEBUG_FRAME_LENGTH_BAD: following any "
+ "augmentation field we have run off the end of the section "
+ "with the CIE incomplete. Corrupt Dwarf");
+ return DW_DLV_ERROR;
+ }
augt = _dwarf_get_augmentation_type(dbg,
- augmentation, use_gnu_cie_calc);
+ augmentation, use_gnu_cie_calc);
if (augt == aug_eh) {
/* REFERENCED *//* Not used in this instance */
- Dwarf_Unsigned exception_table_addr;
+ UNUSEDARG Dwarf_Unsigned exception_table_addr;
+ if ((frame_ptr+local_length_size) >= section_ptr_end) {
+ _dwarf_error_string(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD,
+ "DW_DLE_DEBUG_FRAME_LENGTH_BAD: following "
+ "type field we have run off the end of the section "
+ "with the CIE incomplete. Corrupt Dwarf");
+ return DW_DLV_ERROR;
+ }
/* this is per egcs-1.1.2 as on RH 6.0 */
- READ_UNALIGNED(dbg, exception_table_addr,
- Dwarf_Unsigned, frame_ptr, local_length_size);
+ READ_UNALIGNED_CK(dbg, exception_table_addr,
+ Dwarf_Unsigned, frame_ptr, local_length_size,
+ error,section_ptr_end);
frame_ptr += local_length_size;
}
{
Dwarf_Unsigned lreg = 0;
unsigned long size = 0;
- if( version == DW_CIE_VERSION4) {
+ if (version == DW_CIE_VERSION4) {
+ if ((frame_ptr+2) >= section_ptr_end) {
+ _dwarf_error_string(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD,
+ "DW_DLE_DEBUG_FRAME_LENGTH_BAD: "
+ "We would run off the end of the section "
+ "in a DWARF4 cie header. Corrupt Dwarf");
+ return DW_DLV_ERROR;
+ }
address_size = *((unsigned char *)frame_ptr);
+ if (address_size < 1) {
+ _dwarf_error_string(dbg, error, DW_DLE_ADDRESS_SIZE_ZERO,
+ "DW_DLE_ADDRESS_SIZE_ZERO: bad addres size "
+ "for a DWARF4 cie header");
+ return (DW_DLV_ERROR);
+ }
+ if (address_size > sizeof(Dwarf_Addr)) {
+ _dwarf_create_address_size_dwarf_error(dbg,
+ error,address_size,
+ DW_DLE_ADDRESS_SIZE_ERROR,
+ "DW_DLE_ADDRESS_SIZE_ERROR..:");
+ return DW_DLV_ERROR;
+ }
+ if ((frame_ptr+2) >= section_ptr_end) {
+ _dwarf_error_string(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD,
+ "DW_DLE_DEBUG_FRAME_LENGTH_BAD: Running off the end "
+ " of a CIE header. Corrupt DWARF4");
+ return DW_DLV_ERROR;
+ }
++frame_ptr;
segment_size = *((unsigned char *)frame_ptr);
++frame_ptr;
+ if (segment_size > sizeof(Dwarf_Addr)) {
+ _dwarf_error(dbg, error, DW_DLE_SEGMENT_SIZE_BAD);
+ return (DW_DLV_ERROR);
+ }
}
- DECODE_LEB128_UWORD(frame_ptr, lreg);
- code_alignment_factor = (Dwarf_Word) lreg;
-
- data_alignment_factor =
- (Dwarf_Sword) _dwarf_decode_s_leb128(frame_ptr,
- &leb128_length);
-
+ /* Not a great test. But the DECODE* do checking so ok. */
+ if ((frame_ptr+2) >= section_ptr_end) {
+ _dwarf_error_string(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD,
+ "DW_DLE_DEBUG_FRAME_LENGTH_BAD: Running off the end "
+ " of a CIE header before the code alignment value "
+ "read. Corrupt DWARF");
+ return DW_DLV_ERROR;
+ }
+ DECODE_LEB128_UWORD_CK(frame_ptr, lreg,dbg,error,section_ptr_end);
+ code_alignment_factor = (Dwarf_Unsigned) lreg;
+ res = (Dwarf_Signed) _dwarf_decode_s_leb128_chk(frame_ptr,
+ &leb128_length,&data_alignment_factor,section_ptr_end);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
frame_ptr = frame_ptr + leb128_length;
+ /* Not a great test. FIXME */
+ if ((frame_ptr+1) >= section_ptr_end) {
+ _dwarf_error_string(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD,
+ "DW_DLE_DEBUG_FRAME_LENGTH_BAD: Running off the end "
+ "of a CIE header before the return address register "
+ "number read. Corrupt DWARF");
- return_address_register =
- _dwarf_get_return_address_reg(frame_ptr, version, &size);
+ return DW_DLV_ERROR;
+ }
+ res = _dwarf_get_return_address_reg(frame_ptr, version,
+ dbg,section_ptr_end, &size,&return_address_register,error);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
if (return_address_register > dbg->de_frame_reg_rules_entry_count) {
_dwarf_error(dbg, error, DW_DLE_CIE_RET_ADDR_REG_ERROR);
return (DW_DLV_ERROR);
}
frame_ptr += size;
+ if ((frame_ptr) > section_ptr_end) {
+ _dwarf_error_string(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD,
+ "DW_DLE_DEBUG_FRAME_LENGTH_BAD: Past the end "
+ "of a CIE header before reading the augmentation string."
+ " Corrupt DWARF");
+ return DW_DLV_ERROR;
+ }
}
switch (augt) {
case aug_empty_string:
@@ -593,87 +792,116 @@ dwarf_create_cie_from_after_start(Dwarf_Debug dbg,
case aug_irix_mti_v1:
break;
case aug_irix_exception_table:{
- Dwarf_Unsigned lreg = 0;
- Dwarf_Word length_of_augmented_fields;
-
- /* Decode the length of augmented fields. */
- DECODE_LEB128_UWORD(frame_ptr, lreg);
- length_of_augmented_fields = (Dwarf_Word) lreg;
-
+ Dwarf_Unsigned lreg = 0;
+ Dwarf_Unsigned length_of_augmented_fields;
- /* set the frame_ptr to point at the instruction start. */
- frame_ptr += length_of_augmented_fields;
+ /* Decode the length of augmented fields. */
+ DECODE_LEB128_UWORD_CK(frame_ptr, lreg,dbg,error,section_ptr_end);
+ length_of_augmented_fields = (Dwarf_Unsigned) lreg;
+ /* set the frame_ptr to point at the instruction start. */
+ frame_ptr += length_of_augmented_fields;
}
break;
case aug_eh:{
+ int err = 0;
+ unsigned long increment = 0;
- int err = 0;
- unsigned long increment = 0;
-
- if (!use_gnu_cie_calc) {
- /* This should be impossible. */
- _dwarf_error(dbg, error,
- DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
- return DW_DLV_ERROR;
- }
+ if (!use_gnu_cie_calc) {
+ /* This should be impossible. */
+ _dwarf_error(dbg, error,DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
+ return DW_DLV_ERROR;
+ }
- err = get_gcc_eh_augmentation(dbg, frame_ptr, &increment,
- augt,
- prefix->cf_section_ptr,
- &eh_fde_encoding,
- (char *) augmentation);
- if (err == DW_DLV_ERROR) {
- _dwarf_error(dbg, error,
- DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
- return DW_DLV_ERROR;
- }
- frame_ptr += increment;
- break;
+ err = get_gcc_eh_augmentation(dbg, frame_ptr, &increment,
+ augt,
+ section_ptr_end,
+ (char *) augmentation,error);
+ if (err == DW_DLV_ERROR) {
+ _dwarf_error(dbg, error,DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
+ return DW_DLV_ERROR;
+ }
+ frame_ptr += increment;
}
+ break;
case aug_gcc_eh_z:{
- /* Here we have Augmentation Data Length (uleb128) followed
- by Augmentation Data bytes. */
- int res = DW_DLV_ERROR;
- Dwarf_Unsigned adlen = 0;
-
- DECODE_LEB128_UWORD(frame_ptr, adlen);
- cie_aug_data_len = adlen;
- cie_aug_data = frame_ptr;
- res = gnu_aug_encodings(dbg,
- (char *) augmentation,
- cie_aug_data,
- cie_aug_data_len,
- address_size,
- &gnu_personality_handler_encoding,
- &gnu_lsda_encoding,
- &gnu_fde_begin_encoding,
- &gnu_personality_handler_addr);
- if (res != DW_DLV_OK) {
- _dwarf_error(dbg, error,
- DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
- return res;
+ /* Here we have Augmentation Data Length (uleb128) followed
+ by Augmentation Data bytes (not a string). */
+ int resz = DW_DLV_ERROR;
+ Dwarf_Unsigned adlen = 0;
+
+ /* Not a great test. FIXME */
+ if ((frame_ptr+1) > section_ptr_end) {
+ _dwarf_error_string(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD,
+ "DW_DLE_AUG_DATA_LENGTH_BAD: The "
+ "gcc .eh_frame augmentation data "
+ "cannot be read. Out of room in the section."
+ " Corrupt DWARF.");
+ return DW_DLV_ERROR;
+ }
+ DECODE_LEB128_UWORD_CK(frame_ptr, adlen,
+ dbg,error,section_ptr_end);
+ cie_aug_data_len = adlen;
+ cie_aug_data = frame_ptr;
+ if (adlen) {
+ Dwarf_Small *cie_aug_data_end = cie_aug_data+adlen;
+ if (cie_aug_data_end < cie_aug_data ||
+ cie_aug_data_end > section_ptr_end) {
+ dwarfstring m;
+
+ dwarfstring_constructor(&m);
+ dwarfstring_append_printf_u(&m,
+ "DW_DLE_AUG_DATA_LENGTH_BAD: The "
+ "gcc .eh_frame augmentation data "
+ "length of %" DW_PR_DUu " is too long to"
+ " fit in the section.",adlen);
+ _dwarf_error_string(dbg, error,
+ DW_DLE_AUG_DATA_LENGTH_BAD,
+ dwarfstring_string(&m));
+ dwarfstring_destructor(&m);
+ return DW_DLV_ERROR;
}
-
-
- frame_ptr += adlen;
- break;
}
+ resz = gnu_aug_encodings(dbg,
+ (char *) augmentation,
+ cie_aug_data,
+ cie_aug_data_len,
+ address_size,
+ &gnu_personality_handler_encoding,
+ &gnu_lsda_encoding,
+ &gnu_fde_begin_encoding,
+ &gnu_personality_handler_addr,
+ error);
+ if (resz != DW_DLV_OK) {
+ _dwarf_error(dbg, error,
+ DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
+ return resz;
+ }
+ frame_ptr += adlen;
+ }
+ break;
case aug_armcc:
break;
default:{
- /* We do not understand the augmentation string. No
- assumption can be made about any fields other than what
- we have already read. */
- frame_ptr = prefix->cf_start_addr +
- prefix->cf_length + prefix->cf_local_length_size
- + prefix->cf_local_extension_size;
- /* FIX -- What are the values of data_alignment_factor,
- code_alignement_factor, return_address_register and
- instruction start? They were clearly uninitalized in the
- previous version and I am leaving them the same way. */
- break;
+ /* We do not understand the augmentation string. No
+ assumption can be made about any fields other than what
+ we have already read. */
+ frame_ptr = prefix->cf_start_addr +
+ prefix->cf_length + prefix->cf_local_length_size
+ + prefix->cf_local_extension_size;
+ /* FIX -- What are the values of data_alignment_factor,
+ code_alignement_factor, return_address_register and
+ instruction start? They were clearly uninitalized in the
+ previous version and I am leaving them the same way. */
+ }
+ if ((frame_ptr) > section_ptr_end) {
+ _dwarf_error_string(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD,
+ "DW_DLE_DEBUG_FRAME_LENGTH_BAD: "
+ "Reading an unknown type of augmentation string "
+ "run off the end of the section. Corrupt DWARF.");
+ return DW_DLV_ERROR;
}
+ break;
} /* End switch on augmentation type. */
new_cie = (Dwarf_Cie) _dwarf_get_alloc(dbg, DW_DLA_CIE, 1);
@@ -684,7 +912,7 @@ dwarf_create_cie_from_after_start(Dwarf_Debug dbg,
new_cie->ci_cie_version_number = version;
new_cie->ci_initial_table = NULL;
- new_cie->ci_length = (Dwarf_Word) prefix->cf_length;
+ new_cie->ci_length = (Dwarf_Unsigned) prefix->cf_length;
new_cie->ci_length_size = prefix->cf_local_length_size;
new_cie->ci_extension_size = prefix->cf_local_extension_size;
new_cie->ci_augmentation = (char *) augmentation;
@@ -695,6 +923,11 @@ dwarf_create_cie_from_after_start(Dwarf_Debug dbg,
(Dwarf_Small) code_alignment_factor;
new_cie->ci_return_address_register = return_address_register;
new_cie->ci_cie_start = prefix->cf_start_addr;
+
+ if ( frame_ptr > section_ptr_end) {
+ _dwarf_error(dbg, error, DW_DLE_DF_FRAME_DECODING_ERROR);
+ return (DW_DLV_ERROR);
+ }
new_cie->ci_cie_instr_start = frame_ptr;
new_cie->ci_dbg = dbg;
new_cie->ci_augmentation_type = augt;
@@ -709,6 +942,14 @@ dwarf_create_cie_from_after_start(Dwarf_Debug dbg,
new_cie->ci_index = cie_count;
new_cie->ci_section_ptr = prefix->cf_section_ptr;
+ new_cie->ci_section_end = section_ptr_end;
+ new_cie->ci_cie_end = new_cie->ci_cie_start + new_cie->ci_length +
+ new_cie->ci_length_size+ new_cie->ci_extension_size;
+ if ( new_cie->ci_cie_end > section_ptr_end) {
+ _dwarf_error(dbg, error, DW_DLE_DF_FRAME_DECODING_ERROR);
+ return (DW_DLV_ERROR);
+ }
+
/* The Following new in DWARF4 */
new_cie->ci_address_size = address_size;
new_cie->ci_segment_size = segment_size;
@@ -723,44 +964,52 @@ dwarf_create_cie_from_after_start(Dwarf_Debug dbg,
}
-/* Internal function, not called by consumer code.
- 'prefix' has accumulated the info up thru the cie-id
- and now we consume the rest and build a Dwarf_Fde_s structure.
-*/
+/* Internal function, not called by consumer code.
+ 'prefix' has accumulated the info up thru the cie-id
+ and now we consume the rest and build a Dwarf_Fde_s structure.
+ Can be called with cie_ptr_in NULL from dwarf_frame.c */
int
dwarf_create_fde_from_after_start(Dwarf_Debug dbg,
struct cie_fde_prefix_s *prefix,
Dwarf_Small * section_pointer,
Dwarf_Small * frame_ptr,
+ Dwarf_Small * section_ptr_end,
int use_gnu_cie_calc,
Dwarf_Cie cie_ptr_in,
Dwarf_Fde * fde_ptr_out,
Dwarf_Error * error)
{
Dwarf_Fde new_fde = 0;
- Dwarf_Cie cieptr = cie_ptr_in;
+ Dwarf_Cie cieptr = 0;
Dwarf_Small *saved_frame_ptr = 0;
Dwarf_Small *initloc = frame_ptr;
Dwarf_Signed offset_into_exception_tables
- /* must be min dwarf_sfixed in size */
= (Dwarf_Signed) DW_DLX_NO_EH_OFFSET;
Dwarf_Small *fde_aug_data = 0;
Dwarf_Unsigned fde_aug_data_len = 0;
Dwarf_Addr cie_base_offset = prefix->cf_cie_id;
Dwarf_Addr initial_location = 0; /* must be min de_pointer_size
- bytes in size */
+ bytes in size */
Dwarf_Addr address_range = 0; /* must be min de_pointer_size
- bytes in size */
- Dwarf_Half address_size = cie_ptr_in->ci_address_size;
-
- enum Dwarf_augmentation_type augt = cieptr->ci_augmentation_type;
+ bytes in size */
+ Dwarf_Half address_size = 0;
+ Dwarf_Unsigned eh_table_value = 0;
+ Dwarf_Bool eh_table_value_set = FALSE;
+ /* Temporary assumption. */
+ enum Dwarf_augmentation_type augt = aug_empty_string;
+
+ if (cie_ptr_in) {
+ cieptr = cie_ptr_in;
+ address_size = cieptr->ci_address_size;
+ augt = cieptr->ci_augmentation_type;
+ }
if (augt == aug_gcc_eh_z) {
- /* If z augmentation this is eh_frame, and initial_location and
- address_range in the FDE are read according to the CIE
- augmentation string instructions. */
+ /* If z augmentation this is eh_frame, and initial_location and
+ address_range in the FDE are read according to the CIE
+ augmentation string instructions. */
{
Dwarf_Small *fp_updated = 0;
@@ -768,109 +1017,144 @@ dwarf_create_fde_from_after_start(Dwarf_Debug dbg,
section_pointer,
frame_ptr,
cieptr-> ci_gnu_fde_begin_encoding,
+ section_ptr_end,
address_size,
&initial_location,
- &fp_updated);
+ &fp_updated,error);
if (res != DW_DLV_OK) {
- _dwarf_error(dbg, error,
- DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
- return DW_DLV_ERROR;
+ return res;
}
frame_ptr = fp_updated;
- /* For the address-range it makes no sense to be
- pc-relative, so we turn it off with a section_pointer of
- NULL. Masking off DW_EH_PE_pcrel from the
- ci_gnu_fde_begin_encoding in this call would also work
- to turn off DW_EH_PE_pcrel. */
+ /* For the address-range it makes no sense to be
+ pc-relative, so we turn it off with a section_pointer of
+ NULL. Masking off DW_EH_PE_pcrel from the
+ ci_gnu_fde_begin_encoding in this call would also work
+ to turn off DW_EH_PE_pcrel. */
res = read_encoded_ptr(dbg, (Dwarf_Small *) NULL,
- frame_ptr,
- cieptr->ci_gnu_fde_begin_encoding,
- address_size,
- &address_range, &fp_updated);
+ frame_ptr,
+ cieptr->ci_gnu_fde_begin_encoding,
+ section_ptr_end,
+ address_size,
+ &address_range, &fp_updated,error);
if (res != DW_DLV_OK) {
- _dwarf_error(dbg, error,
- DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
- return DW_DLV_ERROR;
+ return res;
}
frame_ptr = fp_updated;
}
{
Dwarf_Unsigned adlen = 0;
- DECODE_LEB128_UWORD(frame_ptr, adlen);
+ DECODE_LEB128_UWORD_CK(frame_ptr, adlen,
+ dbg,error,section_ptr_end);
fde_aug_data_len = adlen;
fde_aug_data = frame_ptr;
frame_ptr += adlen;
+ if (adlen) {
+ if (frame_ptr < fde_aug_data ||
+ frame_ptr >= section_ptr_end ) {
+ dwarfstring m;
+
+ dwarfstring_constructor(&m);
+ dwarfstring_append_printf_u(&m,
+ "DW_DLE_AUG_DATA_LENGTH_BAD: The "
+ "gcc .eh_frame augmentation data "
+ "length of %" DW_PR_DUu " is too long to"
+ " fit in the section.",adlen);
+ _dwarf_error_string(dbg, error,
+ DW_DLE_AUG_DATA_LENGTH_BAD,
+ dwarfstring_string(&m));
+ dwarfstring_destructor(&m);
+ return DW_DLV_ERROR;
+ }
+ }
}
} else {
- READ_UNALIGNED(dbg, initial_location, Dwarf_Addr,
- frame_ptr, address_size);
+ if ((frame_ptr + 2*address_size) > section_ptr_end) {
+ _dwarf_error(dbg,error,DW_DLE_DEBUG_FRAME_LENGTH_BAD);
+ return DW_DLV_ERROR;
+ }
+ READ_UNALIGNED_CK(dbg, initial_location, Dwarf_Addr,
+ frame_ptr, address_size,
+ error,section_ptr_end);
frame_ptr += address_size;
-
- READ_UNALIGNED(dbg, address_range, Dwarf_Addr,
- frame_ptr, address_size);
+ READ_UNALIGNED_CK(dbg, address_range, Dwarf_Addr,
+ frame_ptr, address_size,
+ error,section_ptr_end);
frame_ptr += address_size;
}
-
-
-
-
-
switch (augt) {
case aug_irix_mti_v1:
case aug_empty_string:
break;
case aug_irix_exception_table:{
- Dwarf_Unsigned lreg = 0;
- Dwarf_Word length_of_augmented_fields = 0;
-
- DECODE_LEB128_UWORD(frame_ptr, lreg);
- length_of_augmented_fields = (Dwarf_Word) lreg;
-
- saved_frame_ptr = frame_ptr;
- /* The first word is an offset into exception tables.
- Defined as a 32bit offset even for CC -64. */
- READ_UNALIGNED(dbg, offset_into_exception_tables,
- Dwarf_Addr, frame_ptr, sizeof(Dwarf_sfixed));
- SIGN_EXTEND(offset_into_exception_tables,
- sizeof(Dwarf_sfixed));
- frame_ptr = saved_frame_ptr + length_of_augmented_fields;
+ Dwarf_Unsigned lreg = 0;
+ Dwarf_Unsigned length_of_augmented_fields = 0;
+
+ DECODE_LEB128_UWORD_CK(frame_ptr, lreg,
+ dbg,error,section_ptr_end);
+ length_of_augmented_fields = (Dwarf_Unsigned) lreg;
+
+ saved_frame_ptr = frame_ptr;
+ /* The first word is an offset into exception tables.
+ Defined as a 32bit offset even for CC -64. */
+ if ((frame_ptr + DWARF_32BIT_SIZE) > section_ptr_end) {
+ _dwarf_error(dbg,error,DW_DLE_DEBUG_FRAME_LENGTH_BAD);
+ return DW_DLV_ERROR;
+ }
+ READ_UNALIGNED_CK(dbg, offset_into_exception_tables,
+ Dwarf_Addr, frame_ptr, DWARF_32BIT_SIZE,
+ error,section_ptr_end);
+ SIGN_EXTEND(offset_into_exception_tables,
+ DWARF_32BIT_SIZE);
+ frame_ptr = saved_frame_ptr + length_of_augmented_fields;
}
break;
case aug_eh:{
- Dwarf_Unsigned eh_table_value = 0;
- if (!use_gnu_cie_calc) {
- /* This should be impossible. */
- _dwarf_error(dbg, error,
- DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
- return DW_DLV_ERROR;
- }
+ if (!use_gnu_cie_calc) {
+ /* This should be impossible. */
+ _dwarf_error(dbg, error,DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
+ return DW_DLV_ERROR;
+ }
- /* gnu eh fde case. we do not need to do anything */
- /*REFERENCED*/ /* Not used in this instance of the
- macro */
- READ_UNALIGNED(dbg, eh_table_value,
- Dwarf_Unsigned, frame_ptr,
- address_size);
- frame_ptr += address_size;
+ /* gnu eh fde case. we do not need to do anything */
+ /*REFERENCED*/ /* Not used in this instance of the macro */
+ if ((frame_ptr + address_size) > section_ptr_end) {
+ _dwarf_error(dbg,error,DW_DLE_DEBUG_FRAME_LENGTH_BAD);
+ return DW_DLV_ERROR;
+ }
+ READ_UNALIGNED_CK(dbg, eh_table_value,
+ Dwarf_Unsigned, frame_ptr,
+ address_size,
+ error,section_ptr_end);
+ eh_table_value_set = TRUE;
+ frame_ptr += address_size;
}
break;
case aug_gcc_eh_z:{
- /* The Augmentation Data Length is here, followed by the
- Augmentation Data bytes themselves. */
+ /* The Augmentation Data Length is here, followed by the
+ Augmentation Data bytes themselves. */
}
break;
case aug_armcc:
break;
case aug_past_last:
break;
+
+ case aug_metaware: /* No special fields. See dwarf_util.h */
+ break;
+
case aug_unknown:
_dwarf_error(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
return DW_DLV_ERROR;
} /* End switch on augmentation type */
+ if ( frame_ptr > section_ptr_end) {
+ _dwarf_error(dbg, error, DW_DLE_DF_FRAME_DECODING_ERROR);
+ return (DW_DLV_ERROR);
+ }
+
new_fde = (Dwarf_Fde) _dwarf_get_alloc(dbg, DW_DLA_FDE, 1);
if (new_fde == NULL) {
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
@@ -882,63 +1166,57 @@ dwarf_create_fde_from_after_start(Dwarf_Debug dbg,
new_fde->fd_extension_size = prefix->cf_local_extension_size;
new_fde->fd_is_eh = use_gnu_cie_calc;
new_fde->fd_cie_offset = cie_base_offset;
- new_fde->fd_cie_index = cieptr->ci_index;
+ if (cieptr) {
+ new_fde->fd_cie_index = cieptr->ci_index;
+ }
new_fde->fd_cie = cieptr;
new_fde->fd_initial_location = initial_location;
new_fde->fd_initial_loc_pos = initloc;
new_fde->fd_address_range = address_range;
new_fde->fd_fde_start = prefix->cf_start_addr;
+
new_fde->fd_fde_instr_start = frame_ptr;
+ new_fde->fd_fde_end = prefix->cf_start_addr +
+ prefix->cf_length + prefix->cf_local_length_size +
+ prefix->cf_local_extension_size;
+ if ( new_fde->fd_fde_end > section_ptr_end) {
+ _dwarf_error(dbg, error, DW_DLE_DF_FRAME_DECODING_ERROR);
+ return (DW_DLV_ERROR);
+ }
+
new_fde->fd_dbg = dbg;
new_fde->fd_offset_into_exception_tables =
offset_into_exception_tables;
+ new_fde->fd_eh_table_value = eh_table_value;
+ new_fde->fd_eh_table_value_set = eh_table_value_set;
new_fde->fd_section_ptr = prefix->cf_section_ptr;
new_fde->fd_section_index = prefix->cf_section_index;
new_fde->fd_section_length = prefix->cf_section_length;
+ new_fde->fd_section_end = section_ptr_end;
+ if (augt == aug_gcc_eh_z) {
+ new_fde->fd_gnu_eh_aug_present = TRUE;
+ }
new_fde->fd_gnu_eh_augmentation_bytes = fde_aug_data;
new_fde->fd_gnu_eh_augmentation_len = fde_aug_data_len;
validate_length(dbg,cieptr,new_fde->fd_length,
new_fde->fd_length_size, new_fde->fd_extension_size,
new_fde->fd_section_ptr,new_fde->fd_fde_start,"fde");
-
-
*fde_ptr_out = new_fde;
return DW_DLV_OK;
}
-/* called by qsort to compare FDE entries.
- Consumer code expects the array of FDE pointers to be in address order.
-*/
-static int
-qsort_compare(const void *elem1, const void *elem2)
-{
- Dwarf_Fde fde1 = *(Dwarf_Fde *) elem1;
- Dwarf_Fde fde2 = *(Dwarf_Fde *) elem2;
- Dwarf_Addr addr1 = fde1->fd_initial_location;
- Dwarf_Addr addr2 = fde2->fd_initial_location;
-
- if (addr1 < addr2) {
- return -1;
- } else if (addr1 > addr2) {
- return 1;
- }
- return 0;
-}
-
-
-/* Read in the common cie/fde prefix, including reading
- * the cie-value which shows which this is: cie or fde.
- * */
+/* Read in the common cie/fde prefix, including reading
+ the cie-value which shows which this is: cie or fde. */
int
dwarf_read_cie_fde_prefix(Dwarf_Debug dbg,
- Dwarf_Small * frame_ptr_in,
- Dwarf_Small * section_ptr_in,
- Dwarf_Unsigned section_index_in,
- Dwarf_Unsigned section_length_in,
- struct cie_fde_prefix_s *data_out,
- Dwarf_Error * error)
+ Dwarf_Small * frame_ptr_in,
+ Dwarf_Small * section_ptr_in,
+ Dwarf_Unsigned section_index_in,
+ Dwarf_Unsigned section_length_in,
+ struct cie_fde_prefix_s *data_out,
+ Dwarf_Error * error)
{
Dwarf_Unsigned length = 0;
int local_length_size = 0;
@@ -946,22 +1224,44 @@ dwarf_read_cie_fde_prefix(Dwarf_Debug dbg,
Dwarf_Small *frame_ptr = frame_ptr_in;
Dwarf_Small *cie_ptr_addr = 0;
Dwarf_Unsigned cie_id = 0;
-
+ Dwarf_Small *section_end = section_ptr_in + section_length_in;
+
+ if(section_end < (frame_ptr +4)) {
+ dwarfstring m;
+ Dwarf_Unsigned u = (Dwarf_Unsigned)(uintptr_t)(frame_ptr+4) -
+ (Dwarf_Unsigned)(uintptr_t)section_end;
+
+ dwarfstring_constructor(&m);
+ dwarfstring_append_printf_u(&m,
+ "DW_DLE_DEBUG_FRAME_LENGTH_BAD: "
+ "Reading the cie/fde prefix would "
+ "put us %u bytes past the end of the "
+ "frame section. Corrupt Dwarf.",u);
+ _dwarf_error_string(dbg,error,DW_DLE_DEBUG_FRAME_LENGTH_BAD,
+ dwarfstring_string(&m));
+ dwarfstring_destructor(&m);
+ return DW_DLV_ERROR;
+ }
/* READ_AREA_LENGTH updates frame_ptr for consumed bytes */
- READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
- frame_ptr, local_length_size,
- local_extension_size);
+ READ_AREA_LENGTH_CK(dbg, length, Dwarf_Unsigned,
+ frame_ptr, local_length_size,
+ local_extension_size,error,
+ section_length_in,section_end);
if (length == 0) {
- /* nul bytes at end of section, seen at end of egcs eh_frame
- sections (in a.out). Take this as meaning no more CIE/FDE
- data. We should be very close to end of section. */
+ /* nul bytes at end of section, seen at end of egcs eh_frame
+ sections (in a.out). Take this as meaning no more CIE/FDE
+ data. We should be very close to end of section. */
return DW_DLV_NO_ENTRY;
}
+ if((frame_ptr + local_length_size) >= section_end) {
+ _dwarf_error(dbg,error,DW_DLE_DEBUG_FRAME_LENGTH_BAD);
+ return DW_DLV_ERROR;
+ }
cie_ptr_addr = frame_ptr;
- READ_UNALIGNED(dbg, cie_id, Dwarf_Unsigned,
- frame_ptr, local_length_size);
+ READ_UNALIGNED_CK(dbg, cie_id, Dwarf_Unsigned,
+ frame_ptr, local_length_size,error,section_end);
SIGN_EXTEND(cie_id, local_length_size);
frame_ptr += local_length_size;
@@ -969,19 +1269,35 @@ dwarf_read_cie_fde_prefix(Dwarf_Debug dbg,
data_out->cf_addr_after_prefix = frame_ptr;
data_out->cf_length = length;
+ if (length > section_length_in) {
+ _dwarf_error(dbg,error,DW_DLE_DEBUG_FRAME_LENGTH_BAD);
+ return DW_DLV_ERROR;
+ }
+ if (cie_ptr_addr+length > section_end) {
+ _dwarf_error(dbg,error,DW_DLE_DEBUG_FRAME_LENGTH_BAD);
+ return DW_DLV_ERROR;
+ }
data_out->cf_local_length_size = local_length_size;
data_out->cf_local_extension_size = local_extension_size;
+
+ /* We do not know if it is a CIE or FDE id yet.
+ How we check and what it means
+ depends whether it is .debug_frame
+ or .eh_frame. */
data_out->cf_cie_id = cie_id;
+
+ /* The address of the CIE_id or FDE_id value in memory. */
data_out->cf_cie_id_addr = cie_ptr_addr;
+
data_out->cf_section_ptr = section_ptr_in;
data_out->cf_section_index = section_index_in;
data_out->cf_section_length = section_length_in;
return DW_DLV_OK;
}
-/* On various errors previously-allocated CIEs and FDEs
- must be cleaned up.
- This helps avoid leaks in case of errors.
+/* On various errors previously-allocated CIEs and FDEs
+ must be cleaned up.
+ This helps avoid leaks in case of errors.
*/
static void
dealloc_fde_cie_list_internal(Dwarf_Fde head_fde_ptr,
@@ -1006,16 +1322,16 @@ dealloc_fde_cie_list_internal(Dwarf_Fde head_fde_ptr,
}
}
-/* Find the cie whose id value is given: the id
- * value is, per DWARF2/3, an offset in the section.
- * For .debug_frame, zero is a legal offset. For
- * GNU .eh_frame it is not a legal offset.
- * 'cie_ptr' is a pointer into our section, not an offset. */
+/* Find the cie whose id value is given: the id
+ value is, per DWARF2/3, an offset in the section.
+ For .debug_frame, zero is a legal offset. For
+ GNU .eh_frame it is not a legal offset.
+ 'cie_ptr' is a pointer into our section, not an offset. */
static int
dwarf_find_existing_cie_ptr(Dwarf_Small * cie_ptr,
- Dwarf_Cie cur_cie_ptr,
- Dwarf_Cie * cie_ptr_to_use_out,
- Dwarf_Cie head_cie_ptr)
+ Dwarf_Cie cur_cie_ptr,
+ Dwarf_Cie * cie_ptr_to_use_out,
+ Dwarf_Cie head_cie_ptr)
{
Dwarf_Cie next = 0;
@@ -1034,22 +1350,21 @@ dwarf_find_existing_cie_ptr(Dwarf_Small * cie_ptr,
}
-/* We have a valid cie_ptr_val that has not been
- * turned into an internal Cie yet. Do so now.
- * Returns DW_DLV_OK or DW_DLV_ERROR, never
- * DW_DLV_NO_ENTRY.
+/* We have a valid cie_ptr_val that has not been
+ turned into an internal Cie yet. Do so now.
+ Returns DW_DLV_OK or DW_DLV_ERROR, never
+ DW_DLV_NO_ENTRY.
- 'section_ptr' - Points to first byte of section data.
- 'section_length' - Length of the section, in bytes.
- 'frame_ptr_end' - Points 1-past last byte of section data.
- * */
+ 'section_ptr' - Points to first byte of section data.
+ 'section_length' - Length of the section, in bytes.
+ 'section_ptr_end' - Points 1-past last byte of section data. */
static int
dwarf_create_cie_from_start(Dwarf_Debug dbg,
Dwarf_Small * cie_ptr_val,
Dwarf_Small * section_ptr,
Dwarf_Unsigned section_index,
Dwarf_Unsigned section_length,
- Dwarf_Small * frame_ptr_end,
+ Dwarf_Small * section_ptr_end,
Dwarf_Unsigned cie_id_value,
Dwarf_Unsigned cie_count,
int use_gnu_cie_calc,
@@ -1060,12 +1375,12 @@ dwarf_create_cie_from_start(Dwarf_Debug dbg,
int res = DW_DLV_ERROR;
Dwarf_Small *frame_ptr = cie_ptr_val;
- if (frame_ptr < section_ptr || frame_ptr > frame_ptr_end) {
+ if (frame_ptr < section_ptr || frame_ptr >= section_ptr_end) {
_dwarf_error(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
return DW_DLV_ERROR;
}
- /* First read in the 'common prefix' to figure out what * we are to
- do with this entry. If it is not a cie * we are in big trouble. */
+ /* First read in the 'common prefix' to figure out what * we are to
+ do with this entry. If it is not a cie * we are in big trouble. */
memset(&prefix, 0, sizeof(prefix));
res = dwarf_read_cie_fde_prefix(dbg, frame_ptr, section_ptr,
section_index, section_length,
@@ -1089,6 +1404,7 @@ dwarf_create_cie_from_start(Dwarf_Debug dbg,
&prefix,
section_ptr,
frame_ptr,
+ section_ptr_end,
cie_count,
use_gnu_cie_calc,
cie_ptr_to_use_out, error);
@@ -1102,27 +1418,15 @@ dwarf_create_cie_from_start(Dwarf_Debug dbg,
Return the augmentation character and, if applicable,
the personality routine address.
- personality_routine_out -
- if 'P' is augchar, is personality handler addr.
+ personality_routine_out -
+ if 'P' is augchar, is personality handler addr.
Otherwise is not set.
aug_data - if 'P' points to data space of the
aug_data_len - length of areas aug_data points to.
-
-*/
-#if 0
-/* For debugging only. */
-void
-dump_bytes(Dwarf_Small * start, long len)
-{
- Dwarf_Small *end = start + len;
- Dwarf_Small *cur = start;
- for (; cur < end; cur++) {
- printf(" byte %d, data %02x\n", (int) (cur - start), *cur);
- }
+*/
-}
-#endif
+/* It is not clear if this is entirely correct. */
static int
gnu_aug_encodings(Dwarf_Debug dbg, char *augmentation,
Dwarf_Small * aug_data, Dwarf_Unsigned aug_data_len,
@@ -1130,7 +1434,8 @@ gnu_aug_encodings(Dwarf_Debug dbg, char *augmentation,
unsigned char *pers_hand_enc_out,
unsigned char *lsda_enc_out,
unsigned char *fde_begin_enc_out,
- Dwarf_Addr * gnu_pers_addr_out)
+ Dwarf_Addr * gnu_pers_addr_out,
+ Dwarf_Error * error)
{
char *nc = 0;
Dwarf_Small *cur_aug_p = aug_data;
@@ -1145,97 +1450,110 @@ gnu_aug_encodings(Dwarf_Debug dbg, char *augmentation,
continue;
case 'S':
- /* Indicates this is a signal stack frame. Debuggers have to do
- special handling. We don't need to do more than print this flag at
- the right time, though (see dwarfdump where it prints the augmentation
- string).
- A signal stack frame (in some OS's) can only be
- unwound (backtraced) by knowing it is a signal stack frame
- (perhaps by noticing the name of the function for the stack frame
- if the name can be found somehow) and figuring
- out (or knowing) how the kernel and libc pushed a structure
- onto the stack and loading registers from that structure.
- Totally different from normal stack unwinding.
- This flag gives an unwinder a big leg up by decoupling the
- 'hint: this is a stack frame' from knowledge like
- the function name (the name might be unavailable at unwind time).
+ /* Indicates this is a signal stack frame.
+ Debuggers have to do
+ special handling. We don't need to do more than
+ print this flag at the right time, though
+ (see dwarfdump where it prints the augmentation
+ string).
+ A signal stack frame (in some OS's) can only be
+ unwound (backtraced) by knowing it is a signal
+ stack frame (perhaps by noticing the name of the
+ function for the stack frame if the name can be
+ found somehow) and figuring
+ out (or knowing) how the kernel and libc
+ pushed a structure
+ onto the stack and loading registers from that structure.
+ Totally different from normal stack unwinding.
+ This flag gives an unwinder a big leg up by
+ decoupling the 'hint: this is a stack frame'
+ from knowledge like
+ the function name (the name might be
+ unavailable at unwind time).
*/
break;
-
+
case 'L':
if (cur_aug_p > end_aug_p) {
+ _dwarf_error(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
return DW_DLV_ERROR;
}
*lsda_enc_out = *(unsigned char *) cur_aug_p;
++cur_aug_p;
break;
case 'R':
- /* Followed by a one byte argument giving the
- pointer encoding for the address pointers in the fde. */
+ /* Followed by a one byte argument giving the
+ pointer encoding for the address pointers in the fde. */
if (cur_aug_p >= end_aug_p) {
+ _dwarf_error(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
return DW_DLV_ERROR;
}
*fde_begin_enc_out = *(unsigned char *) cur_aug_p;
++cur_aug_p;
break;
case 'P':{
- int res = DW_DLV_ERROR;
- Dwarf_Small *updated_aug_p = 0;
- unsigned char encoding = 0;
+ int res = DW_DLV_ERROR;
+ Dwarf_Small *updated_aug_p = 0;
+ unsigned char encoding = 0;
- if (cur_aug_p >= end_aug_p) {
- return DW_DLV_ERROR;
- }
- encoding = *(unsigned char *) cur_aug_p;
- *pers_hand_enc_out = encoding;
- ++cur_aug_p;
- if (cur_aug_p > end_aug_p) {
- return DW_DLV_ERROR;
- }
- /* DW_EH_PE_pcrel makes no sense here, so we turn it
- off via a section pointer of NULL. */
- res = read_encoded_ptr(dbg,
- (Dwarf_Small *) NULL,
- cur_aug_p,
- encoding,
- address_size,
- gnu_pers_addr_out,
- &updated_aug_p);
- if (res != DW_DLV_OK) {
- return res;
- }
- cur_aug_p = updated_aug_p;
- if (cur_aug_p > end_aug_p) {
- return DW_DLV_ERROR;
- }
+ if (cur_aug_p >= end_aug_p) {
+ _dwarf_error(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
+ return DW_DLV_ERROR;
+ }
+ encoding = *(unsigned char *) cur_aug_p;
+ *pers_hand_enc_out = encoding;
+ ++cur_aug_p;
+ if (cur_aug_p > end_aug_p) {
+ _dwarf_error(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
+ return DW_DLV_ERROR;
+ }
+ /* DW_EH_PE_pcrel makes no sense here, so we turn it
+ off via a section pointer of NULL. */
+ res = read_encoded_ptr(dbg,
+ (Dwarf_Small *) NULL,
+ cur_aug_p,
+ encoding,
+ end_aug_p,
+ address_size,
+ gnu_pers_addr_out,
+ &updated_aug_p,
+ error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ cur_aug_p = updated_aug_p;
+ if (cur_aug_p > end_aug_p) {
+ _dwarf_error(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
+ return DW_DLV_ERROR;
+ }
}
break;
default:
+ _dwarf_error(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
return DW_DLV_ERROR;
}
}
-
return DW_DLV_OK;
}
-/* Given augmentation character (the encoding) giving the
-address format, read the address from input_field
-and return an incremented value 1 past the input bytes of the
-address.
-Push the address read back thru the *addr pointer.
-See LSB (Linux Standar Base) exception handling documents.
-*/
+/* Given augmentation character (the encoding) giving the
+ address format, read the address from input_field
+ and return an incremented value 1 past the input bytes of the
+ address.
+ Push the address read back thru the *addr pointer.
+ See LSB (Linux Standard Base) exception handling documents. */
static int
read_encoded_ptr(Dwarf_Debug dbg,
Dwarf_Small * section_pointer,
Dwarf_Small * input_field,
int gnu_encoding,
+ Dwarf_Small * section_end,
Dwarf_Half address_size,
Dwarf_Unsigned * addr,
- Dwarf_Small ** input_field_updated)
+ Dwarf_Small ** input_field_updated,
+ Dwarf_Error *error)
{
- Dwarf_Word length = 0;
int value_type = gnu_encoding & 0xf;
Dwarf_Small *input_field_original = input_field;
@@ -1249,138 +1567,132 @@ read_encoded_ptr(Dwarf_Debug dbg,
}
switch (value_type) {
case DW_EH_PE_absptr:{
- /* value_type is zero. Treat as pointer size of the object.
- */
- Dwarf_Unsigned ret_value = 0;
-
- READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
- input_field, address_size);
- *addr = ret_value;
- *input_field_updated = input_field + address_size;
+ /* value_type is zero. Treat as pointer size of the object.
+ */
+ Dwarf_Unsigned ret_value = 0;
+
+ READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Unsigned,
+ input_field, address_size,error,section_end);
+ *addr = ret_value;
+ *input_field_updated = input_field + address_size;
}
break;
case DW_EH_PE_uleb128:{
- Dwarf_Unsigned val = _dwarf_decode_u_leb128(input_field,
- &length);
+ Dwarf_Unsigned val = 0;
- *addr = val;
- *input_field_updated = input_field + length;
+ DECODE_LEB128_UWORD_CK(input_field,val,dbg,error,section_end);
+ *addr = val;
+ *input_field_updated = input_field;
}
break;
case DW_EH_PE_udata2:{
- Dwarf_Unsigned ret_value = 0;
+ Dwarf_Unsigned ret_value = 0;
- READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
- input_field, 2);
- *addr = ret_value;
- *input_field_updated = input_field + 2;
+ READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Unsigned,
+ input_field, 2,error,section_end);
+ *addr = ret_value;
+ *input_field_updated = input_field + 2;
}
break;
case DW_EH_PE_udata4:{
+ Dwarf_Unsigned ret_value = 0;
- Dwarf_Unsigned ret_value = 0;
-
- /* ASSERT: sizeof(Dwarf_ufixed) == 4 */
- READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
- input_field, sizeof(Dwarf_ufixed));
- *addr = ret_value;
- *input_field_updated = input_field + sizeof(Dwarf_ufixed);
+ READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Unsigned,
+ input_field, DWARF_32BIT_SIZE,error,section_end);
+ *addr = ret_value;
+ *input_field_updated = input_field + DWARF_32BIT_SIZE;
}
break;
case DW_EH_PE_udata8:{
- Dwarf_Unsigned ret_value = 0;
+ Dwarf_Unsigned ret_value = 0;
- /* ASSERT: sizeof(Dwarf_Unsigned) == 8 */
- READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
- input_field, sizeof(Dwarf_Unsigned));
- *addr = ret_value;
- *input_field_updated = input_field + sizeof(Dwarf_Unsigned);
+ /* ASSERT: sizeof(Dwarf_Unsigned) == 8 */
+ READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Unsigned,
+ input_field, DWARF_64BIT_SIZE,error,section_end);
+ *addr = ret_value;
+ *input_field_updated = input_field + DWARF_64BIT_SIZE;
}
break;
case DW_EH_PE_sleb128:{
- Dwarf_Signed val = _dwarf_decode_s_leb128(input_field,
- &length);
+ Dwarf_Signed val = 0;
- *addr = (Dwarf_Unsigned) val;
- *input_field_updated = input_field + length;
+ DECODE_LEB128_SWORD_CK(input_field,val,dbg,error,section_end);
+ *addr = (Dwarf_Unsigned) val;
+ *input_field_updated = input_field;
}
break;
case DW_EH_PE_sdata2:{
- Dwarf_Unsigned val = 0;
+ Dwarf_Unsigned val = 0;
- READ_UNALIGNED(dbg, val, Dwarf_Unsigned, input_field, 2);
- SIGN_EXTEND(val, 2);
- *addr = (Dwarf_Unsigned) val;
- *input_field_updated = input_field + 2;
+ READ_UNALIGNED_CK(dbg, val, Dwarf_Unsigned, input_field, 2,
+ error,section_end);
+ SIGN_EXTEND(val, 2);
+ *addr = (Dwarf_Unsigned) val;
+ *input_field_updated = input_field + 2;
}
break;
case DW_EH_PE_sdata4:{
- Dwarf_Unsigned val = 0;
-
- /* ASSERT: sizeof(Dwarf_ufixed) == 4 */
- READ_UNALIGNED(dbg, val,
- Dwarf_Unsigned, input_field,
- sizeof(Dwarf_ufixed));
- SIGN_EXTEND(val, sizeof(Dwarf_ufixed));
- *addr = (Dwarf_Unsigned) val;
- *input_field_updated = input_field + sizeof(Dwarf_ufixed);
+ Dwarf_Unsigned val = 0;
+
+ READ_UNALIGNED_CK(dbg, val,
+ Dwarf_Unsigned, input_field,
+ DWARF_32BIT_SIZE,error,section_end);
+ SIGN_EXTEND(val, DWARF_32BIT_SIZE);
+ *addr = (Dwarf_Unsigned) val;
+ *input_field_updated = input_field + DWARF_32BIT_SIZE;
}
break;
case DW_EH_PE_sdata8:{
- Dwarf_Unsigned val = 0;
-
- /* ASSERT: sizeof(Dwarf_Unsigned) == 8 */
- READ_UNALIGNED(dbg, val,
- Dwarf_Unsigned, input_field,
- sizeof(Dwarf_Unsigned));
- *addr = (Dwarf_Unsigned) val;
- *input_field_updated = input_field + sizeof(Dwarf_Unsigned);
+ Dwarf_Unsigned val = 0;
+
+ /* ASSERT: sizeof(Dwarf_Unsigned) == 8 */
+ READ_UNALIGNED_CK(dbg, val,
+ Dwarf_Unsigned, input_field,
+ DWARF_64BIT_SIZE,error,section_end);
+ *addr = (Dwarf_Unsigned) val;
+ *input_field_updated = input_field + DWARF_64BIT_SIZE;
}
break;
default:
+ _dwarf_error(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
return DW_DLV_ERROR;
};
- /* The ELF ABI for gnu does not document the meaning of
- DW_EH_PE_pcrel, which is awkward. It apparently means the value
- we got above is pc-relative (meaning section-relative), so we
- adjust the value. Section_pointer may be null if it is known
- DW_EH_PE_pcrel cannot apply, such as for .debug_frame or for an
- address-range value. */
+ /* The ELF ABI for gnu does not document the meaning of
+ DW_EH_PE_pcrel, which is awkward. It apparently means the value
+ we got above is pc-relative (meaning section-relative), so we
+ adjust the value. Section_pointer may be null if it is known
+ DW_EH_PE_pcrel cannot apply, such as for .debug_frame or for an
+ address-range value. */
if (section_pointer && ((gnu_encoding & 0x70) == DW_EH_PE_pcrel)) {
- /* Address (*addr) above is pc relative with respect to a
- section. Add to the offset the base address (from elf) of
- section and the distance of the field we are reading from
- the section-beginning to get the actual address. */
- /* ASSERT: input_field_original >= section_pointer */
+ /* Address (*addr) above is pc relative with respect to a
+ section. Add to the offset the base address (from elf) of
+ section and the distance of the field we are reading from
+ the section-beginning to get the actual address. */
+ /* ASSERT: input_field_original >= section_pointer */
Dwarf_Unsigned distance =
input_field_original - section_pointer;
*addr += dbg->de_debug_frame_eh_gnu.dss_addr + distance;
}
-
return DW_DLV_OK;
}
+/* All augmentation string checking done here now.
+ For .eh_frame, gcc from 3.3 uses the z style, earlier used
+ only "eh" as augmentation. We don't yet handle
+ decoding .eh_frame with the z style extensions like L P.
+ gnu_aug_encodings() does handle L P.
-
-/*
- All augmentation string checking done here now.
-
- For .eh_frame, gcc from 3.3 uses the z style, earlier used
- only "eh" as augmentation. We don't yet handle
- decoding .eh_frame with the z style extensions like L P.
-
- These are nasty heuristics, but then that's life
- as augmentations are implementation specific.
-*/
+ These are nasty heuristics, but then that's life
+ as augmentations are implementation specific. */
/* ARGSUSED */
enum Dwarf_augmentation_type
-_dwarf_get_augmentation_type(Dwarf_Debug dbg,
+_dwarf_get_augmentation_type(UNUSEDARG Dwarf_Debug dbg,
Dwarf_Small * augmentation_string,
int is_gcc_eh_frame)
{
@@ -1388,89 +1700,96 @@ _dwarf_get_augmentation_type(Dwarf_Debug dbg,
char *ag_string = (char *) augmentation_string;
if (ag_string[0] == 0) {
- /* Empty string. We'll just guess that we know what this means:
- standard dwarf2/3 with no implementation-defined fields. */
+ /* Empty string. We'll just guess that we know what this means:
+ standard dwarf2/3 with no implementation-defined fields. */
t = aug_empty_string;
} else if (strcmp(ag_string, DW_DEBUG_FRAME_AUGMENTER_STRING) == 0) {
- /* The string is "mti v1". Used internally at SGI, probably
- never shipped. Replaced by "z". Treat like 'nothing
- special'. */
+ /* The string is "mti v1". Used internally at SGI, probably
+ never shipped. Replaced by "z". Treat like 'nothing
+ special'. */
t = aug_irix_mti_v1;
} else if (ag_string[0] == 'z') {
- /* If it's IRIX cc, z means aug_irix_exception_table. z1 z2
- were designed as for IRIX CC, but never implemented */
- /* If it's gcc, z may be any of several things. "z" or z
- followed optionally followed by one or more of L R P, each
- of which means a value may be present. Should be in eh_frame
- only, I think. */
+ /* If it's IRIX cc, z means aug_irix_exception_table. z1 z2
+ were designed as for IRIX CC, but never implemented */
+ /* If it's gcc, z may be any of several things. "z" or z
+ followed optionally followed by one or more of L R P, each
+ of which means a value may be present. Should be in eh_frame
+ only, I think. */
if (is_gcc_eh_frame) {
t = aug_gcc_eh_z;
} else if (ag_string[1] == 0) {
- /* This is the normal IRIX C++ case, where there is an
- offset into a table in each fde. The table being for
- IRIX CC exception handling. */
- /* DW_CIE_AUGMENTER_STRING_V0 "z" */
+ /* This is the normal IRIX C++ case, where there is an
+ offset into a table in each fde. The table being for
+ IRIX CC exception handling. */
+ /* DW_CIE_AUGMENTER_STRING_V0 "z" */
t = aug_irix_exception_table;
} /* Else unknown. */
} else if (strncmp(ag_string, "eh", 2) == 0) {
- /* gcc .eh_frame augmentation for egcs and gcc 2.x, at least
- for x86. */
+ /* gcc .eh_frame augmentation for egcs and gcc 2.x, at least
+ for x86. */
t = aug_eh;
} else if (strcmp(ag_string, "armcc+") == 0) {
- /* Arm uses this string to mean a bug in
- in Arm compilers was fixed, changing to the standard
- calculation of the CFA. See
- http://sourceware.org/ml/gdb-patches/2006-12/msg00249.html
- for details. */
+ /* Arm uses this string to mean a bug in
+ in Arm compilers was fixed, changing to the standard
+ calculation of the CFA. See
+ http://sourceware.org/ml/gdb-patches/2006-12/msg00249.html
+ for details. */
t = aug_armcc;
+ } else if (strcmp(ag_string, "HC") == 0) {
+ t = aug_metaware;
} else {
-
}
return t;
}
-/* Using augmentation, and version
- read in the augmentation data for GNU eh.
+/* Using augmentation, and version
+ read in the augmentation data for GNU eh.
+
+ Return DW_DLV_OK if we succeeded,
+ DW_DLV_ERR if we fail.
- Return DW_DLV_OK if we succeeded,
- DW_DLV_ERR if we fail.
+ On success, update 'size_of_augmentation_data' with
+ the length of the fields that are part of augmentation (so the
+ caller can increment frame_ptr appropriately).
- On success, update 'size_of_augmentation_data' with
- the length of the fields that are part of augmentation (so the
- caller can increment frame_ptr appropriately).
+ 'frame_ptr' points within section.
+ 'section_end' points to end of section area of interest.
- 'frame_ptr' points within section.
- 'section_pointer' points to section base address in memory.
*/
/* ARGSUSED */
static int
get_gcc_eh_augmentation(Dwarf_Debug dbg, Dwarf_Small * frame_ptr,
unsigned long *size_of_augmentation_data,
enum Dwarf_augmentation_type augtype,
- Dwarf_Small * section_pointer,
- Dwarf_Small * fde_eh_encoding_out,
- char *augmentation)
+ Dwarf_Small * section_ptr_end,
+ char *augmentation,
+ Dwarf_Error *error)
{
char *suffix = 0;
unsigned long augdata_size = 0;
if (augtype == aug_gcc_eh_z) {
/* Has leading 'z'. */
- Dwarf_Word leb128_length = 0;
+ UNUSEDARG Dwarf_Unsigned val = 0;
+ Dwarf_Unsigned leb128_length = 0;
/* Dwarf_Unsigned eh_value = */
- _dwarf_decode_u_leb128(frame_ptr, &leb128_length);
+ DECODE_LEB128_UWORD_LEN_CK(frame_ptr,val,leb128_length,
+ dbg,error,section_ptr_end);
augdata_size += leb128_length;
- frame_ptr += leb128_length;
suffix = augmentation + 1;
} else {
- /* Prefix is 'eh'. As in gcc 3.2. No suffix present
- apparently. */
+ /* Prefix is 'eh'. As in gcc 3.2. No suffix present
+ apparently. */
suffix = augmentation + 2;
}
- for (; *suffix; ++suffix) {
- /* We have no idea what this is as yet. Some extensions beyond
- dwarf exist which we do not yet handle. */
+ /* FIXME: This could run too far. */
+ /* for (; *suffix; ++suffix) if we think we can do something */
+ if (*suffix) {
+ /* We have no idea what this is as yet.
+ Some extensions beyond
+ dwarf exist which we do not yet handle. */
+ _dwarf_error(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
return DW_DLV_ERROR;
}
@@ -1480,33 +1799,6 @@ get_gcc_eh_augmentation(Dwarf_Debug dbg, Dwarf_Small * frame_ptr,
}
-/* Make the 'cie_id_addr' consistent across .debug_frame and .eh_frame.
- Calculate a pointer into section bytes given a cie_id, which is
- trivial for .debug_frame, but a bit more work for .eh_frame.
-*/
-static Dwarf_Small *
-get_cieptr_given_offset(Dwarf_Unsigned cie_id_value,
- int use_gnu_cie_calc,
- Dwarf_Small * section_ptr,
- Dwarf_Small * cie_id_addr)
-{
- Dwarf_Small *cieptr = 0;
-
- if (use_gnu_cie_calc) {
- /* cie_id value is offset, in section, of the cie_id itself, to
- use vm ptr of the value, less the value, to get to the cie
- itself. In addition, munge *cie_id_addr to look *as if* it
- was from real dwarf. */
- cieptr = (Dwarf_Small *)(uintptr_t)
- ((Dwarf_Unsigned)(uintptr_t)cie_id_addr) -
- ((Dwarf_Unsigned) cie_id_value);
- } else {
- /* Traditional dwarf section offset is in cie_id */
- cieptr = (section_ptr + cie_id_value);
- }
- return cieptr;
-}
-
/* To properly release all spaced used.
Earlier approaches (before July 15, 2005)
letting client do the dealloc directly left
@@ -1525,16 +1817,18 @@ dwarf_fde_cie_list_dealloc(Dwarf_Debug dbg,
for (i = 0; i < cie_element_count; ++i) {
Dwarf_Frame frame = cie_data[i]->ci_initial_table;
- if (frame)
+ if (frame) {
dwarf_dealloc(dbg, frame, DW_DLA_FRAME);
+ }
dwarf_dealloc(dbg, cie_data[i], DW_DLA_CIE);
}
for (i = 0; i < fde_element_count; ++i) {
dwarf_dealloc(dbg, fde_data[i], DW_DLA_FDE);
}
- if (cie_data)
+ if (cie_data) {
dwarf_dealloc(dbg, cie_data, DW_DLA_LIST);
- if (fde_data)
+ }
+ if (fde_data) {
dwarf_dealloc(dbg, fde_data, DW_DLA_LIST);
-
+ }
}