aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2014-09-22 17:53:15 +0930
committerAlan Modra <amodra@gmail.com>2014-09-22 18:57:16 +0930
commit49727e46175419c638251b39091f24c575568bee (patch)
tree772cb54ac720f72790ab013236f2b5c3cdc63c79
parentaa8f4d1e5e6c01420489a2dfba72495bbd8489be (diff)
downloadgdb-49727e46175419c638251b39091f24c575568bee.zip
gdb-49727e46175419c638251b39091f24c575568bee.tar.gz
gdb-49727e46175419c638251b39091f24c575568bee.tar.bz2
Readelf: Handle forward references to CIEs
The linker side of pr16563 was fixed with commit 18cd5bce, but unfortunately people continue to use older linkers with -flto. This means we have binaries with working .eh_frame that can't be dumped by readelf, and I'm seeing internal IBM bug reports about this fact. PR 16563 * dwarf.c (GET): Remove semicolon. (read_cie): New function, extracted from.. (display_debug_frames): ..here. Correctly handle signed offset from FDE to CIE in .eh_frame. Decode forward referenced CIEs too.
-rw-r--r--binutils/ChangeLog8
-rw-r--r--binutils/dwarf.c241
2 files changed, 169 insertions, 80 deletions
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 223bf11..e8b2daf 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,11 @@
+2014-09-22 Alan Modra <amodra@gmail.com>
+
+ PR 16563
+ * dwarf.c (GET): Remove semicolon.
+ (read_cie): New function, extracted from..
+ (display_debug_frames): ..here. Correctly handle signed offset
+ from FDE to CIE in .eh_frame. Decode forward referenced CIEs too.
+
2014-09-16 Nick Clifton <nickc@redhat.com>
* readelf.c (display_arm_attribute): Use unsigned int type for
diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index 348e20f..3f4095a 100644
--- a/binutils/dwarf.c
+++ b/binutils/dwarf.c
@@ -5232,10 +5232,97 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, int *max_regs)
printf ("\n");
}
-#define GET(VAR, N) SAFE_BYTE_GET_AND_INC (VAR, start, N, end);
+#define GET(VAR, N) SAFE_BYTE_GET_AND_INC (VAR, start, N, end)
#define LEB() read_uleb128 (start, & length_return, end); start += length_return
#define SLEB() read_sleb128 (start, & length_return, end); start += length_return
+static unsigned char *
+read_cie (unsigned char *start, unsigned char *end,
+ Frame_Chunk **p_cie, int *p_version,
+ unsigned long *p_aug_len, unsigned char **p_aug)
+{
+ int version;
+ Frame_Chunk *fc;
+ unsigned int length_return;
+ unsigned char *augmentation_data = NULL;
+ unsigned long augmentation_data_len = 0;
+
+ fc = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk));
+ memset (fc, 0, sizeof (Frame_Chunk));
+
+ fc->col_type = (short int *) xmalloc (sizeof (short int));
+ fc->col_offset = (int *) xmalloc (sizeof (int));
+
+ version = *start++;
+
+ fc->augmentation = (char *) start;
+ start = (unsigned char *) strchr ((char *) start, '\0') + 1;
+
+ if (strcmp (fc->augmentation, "eh") == 0)
+ start += eh_addr_size;
+
+ if (version >= 4)
+ {
+ GET (fc->ptr_size, 1);
+ GET (fc->segment_size, 1);
+ eh_addr_size = fc->ptr_size;
+ }
+ else
+ {
+ fc->ptr_size = eh_addr_size;
+ fc->segment_size = 0;
+ }
+ fc->code_factor = LEB ();
+ fc->data_factor = SLEB ();
+ if (version == 1)
+ {
+ GET (fc->ra, 1);
+ }
+ else
+ {
+ fc->ra = LEB ();
+ }
+
+ if (fc->augmentation[0] == 'z')
+ {
+ augmentation_data_len = LEB ();
+ augmentation_data = start;
+ start += augmentation_data_len;
+ }
+
+ if (augmentation_data_len)
+ {
+ unsigned char *p, *q;
+ p = (unsigned char *) fc->augmentation + 1;
+ q = augmentation_data;
+
+ while (1)
+ {
+ if (*p == 'L')
+ q++;
+ else if (*p == 'P')
+ q += 1 + size_of_encoded_value (*q);
+ else if (*p == 'R')
+ fc->fde_encoding = *q++;
+ else if (*p == 'S')
+ ;
+ else
+ break;
+ p++;
+ }
+ }
+
+ *p_cie = fc;
+ if (p_version)
+ *p_version = version;
+ if (p_aug_len)
+ {
+ *p_aug_len = augmentation_data_len;
+ *p_aug = augmentation_data;
+ }
+ return start;
+}
+
static int
display_debug_frames (struct dwarf_section *section,
void *file ATTRIBUTE_UNUSED)
@@ -5243,7 +5330,7 @@ display_debug_frames (struct dwarf_section *section,
unsigned char *start = section->start;
unsigned char *end = start + section->size;
unsigned char *section_start = start;
- Frame_Chunk *chunks = 0;
+ Frame_Chunk *chunks = 0, *forward_refs = 0;
Frame_Chunk *remembered_state = 0;
Frame_Chunk *rs;
int is_eh = strcmp (section->name, ".eh_frame") == 0;
@@ -5306,55 +5393,20 @@ display_debug_frames (struct dwarf_section *section,
|| (offset_size == 8 && cie_id == DW64_CIE_ID)))
{
int version;
+ int mreg;
- fc = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk));
- memset (fc, 0, sizeof (Frame_Chunk));
-
+ start = read_cie (start, end, &cie, &version,
+ &augmentation_data_len, &augmentation_data);
+ fc = cie;
fc->next = chunks;
chunks = fc;
fc->chunk_start = saved_start;
- fc->ncols = 0;
- fc->col_type = (short int *) xmalloc (sizeof (short int));
- fc->col_offset = (int *) xmalloc (sizeof (int));
- frame_need_space (fc, max_regs - 1);
-
- version = *start++;
-
- fc->augmentation = (char *) start;
- start = (unsigned char *) strchr ((char *) start, '\0') + 1;
-
- if (strcmp (fc->augmentation, "eh") == 0)
- start += eh_addr_size;
-
- if (version >= 4)
- {
- GET (fc->ptr_size, 1);
- GET (fc->segment_size, 1);
- eh_addr_size = fc->ptr_size;
- }
- else
- {
- fc->ptr_size = eh_addr_size;
- fc->segment_size = 0;
- }
- fc->code_factor = LEB ();
- fc->data_factor = SLEB ();
- if (version == 1)
- {
- GET (fc->ra, 1);
- }
- else
- {
- fc->ra = LEB ();
- }
-
- if (fc->augmentation[0] == 'z')
- {
- augmentation_data_len = LEB ();
- augmentation_data = start;
- start += augmentation_data_len;
- }
- cie = fc;
+ mreg = max_regs - 1;
+ if (mreg < fc->ra)
+ mreg = fc->ra;
+ frame_need_space (fc, mreg);
+ if (fc->fde_encoding)
+ encoded_ptr_size = size_of_encoded_value (fc->fde_encoding);
printf ("\n%08lx ", (unsigned long) (saved_start - section_start));
print_dwarf_vma (length, fc->ptr_size);
@@ -5389,33 +5441,6 @@ display_debug_frames (struct dwarf_section *section,
}
putchar ('\n');
}
-
- if (augmentation_data_len)
- {
- unsigned char *p, *q;
- p = (unsigned char *) fc->augmentation + 1;
- q = augmentation_data;
-
- while (1)
- {
- if (*p == 'L')
- q++;
- else if (*p == 'P')
- q += 1 + size_of_encoded_value (*q);
- else if (*p == 'R')
- fc->fde_encoding = *q++;
- else if (*p == 'S')
- ;
- else
- break;
- p++;
- }
-
- if (fc->fde_encoding)
- encoded_ptr_size = size_of_encoded_value (fc->fde_encoding);
- }
-
- frame_need_space (fc, fc->ra);
}
else
{
@@ -5423,14 +5448,70 @@ display_debug_frames (struct dwarf_section *section,
static Frame_Chunk fde_fc;
unsigned long segment_selector;
- fc = & fde_fc;
- memset (fc, 0, sizeof (Frame_Chunk));
+ if (is_eh)
+ {
+ dwarf_vma sign = (dwarf_vma) 1 << (offset_size * 8 - 1);
+ look_for = start - 4 - ((cie_id ^ sign) - sign);
+ }
+ else
+ look_for = section_start + cie_id;
+
+ if (look_for <= saved_start)
+ {
+ for (cie = chunks; cie ; cie = cie->next)
+ if (cie->chunk_start == look_for)
+ break;
+ }
+ else
+ {
+ for (cie = forward_refs; cie ; cie = cie->next)
+ if (cie->chunk_start == look_for)
+ break;
+ if (!cie)
+ {
+ unsigned int off_size;
+ unsigned char *cie_scan;
- look_for = is_eh ? start - 4 - cie_id : section_start + cie_id;
+ cie_scan = look_for;
+ off_size = 4;
+ SAFE_BYTE_GET_AND_INC (length, cie_scan, 4, end);
+ if (length == 0xffffffff)
+ {
+ SAFE_BYTE_GET_AND_INC (length, cie_scan, 8, end);
+ off_size = 8;
+ }
+ if (length != 0)
+ {
+ dwarf_vma c_id;
- for (cie = chunks; cie ; cie = cie->next)
- if (cie->chunk_start == look_for)
- break;
+ SAFE_BYTE_GET_AND_INC (c_id, cie_scan, off_size, end);
+ if (is_eh
+ ? c_id == 0
+ : ((off_size == 4 && c_id == DW_CIE_ID)
+ || (off_size == 8 && c_id == DW64_CIE_ID)))
+ {
+ int version;
+ int mreg;
+
+ read_cie (cie_scan, end, &cie, &version,
+ &augmentation_data_len, &augmentation_data);
+ cie->next = forward_refs;
+ forward_refs = cie;
+ cie->chunk_start = look_for;
+ mreg = max_regs - 1;
+ if (mreg < cie->ra)
+ mreg = cie->ra;
+ frame_need_space (cie, mreg);
+ if (cie->fde_encoding)
+ encoded_ptr_size
+ = size_of_encoded_value (cie->fde_encoding);
+ }
+ }
+ }
+ }
+
+ fc = &fde_fc;
+ memset (fc, 0, sizeof (Frame_Chunk));
if (!cie)
{