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.
This commit is contained in:
parent
aa8f4d1e5e
commit
49727e4617
|
@ -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>
|
2014-09-16 Nick Clifton <nickc@redhat.com>
|
||||||
|
|
||||||
* readelf.c (display_arm_attribute): Use unsigned int type for
|
* readelf.c (display_arm_attribute): Use unsigned int type for
|
||||||
|
|
243
binutils/dwarf.c
243
binutils/dwarf.c
|
@ -5232,10 +5232,97 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, int *max_regs)
|
||||||
printf ("\n");
|
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 LEB() read_uleb128 (start, & length_return, end); start += length_return
|
||||||
#define SLEB() read_sleb128 (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
|
static int
|
||||||
display_debug_frames (struct dwarf_section *section,
|
display_debug_frames (struct dwarf_section *section,
|
||||||
void *file ATTRIBUTE_UNUSED)
|
void *file ATTRIBUTE_UNUSED)
|
||||||
|
@ -5243,7 +5330,7 @@ display_debug_frames (struct dwarf_section *section,
|
||||||
unsigned char *start = section->start;
|
unsigned char *start = section->start;
|
||||||
unsigned char *end = start + section->size;
|
unsigned char *end = start + section->size;
|
||||||
unsigned char *section_start = start;
|
unsigned char *section_start = start;
|
||||||
Frame_Chunk *chunks = 0;
|
Frame_Chunk *chunks = 0, *forward_refs = 0;
|
||||||
Frame_Chunk *remembered_state = 0;
|
Frame_Chunk *remembered_state = 0;
|
||||||
Frame_Chunk *rs;
|
Frame_Chunk *rs;
|
||||||
int is_eh = strcmp (section->name, ".eh_frame") == 0;
|
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)))
|
|| (offset_size == 8 && cie_id == DW64_CIE_ID)))
|
||||||
{
|
{
|
||||||
int version;
|
int version;
|
||||||
|
int mreg;
|
||||||
|
|
||||||
fc = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk));
|
start = read_cie (start, end, &cie, &version,
|
||||||
memset (fc, 0, sizeof (Frame_Chunk));
|
&augmentation_data_len, &augmentation_data);
|
||||||
|
fc = cie;
|
||||||
fc->next = chunks;
|
fc->next = chunks;
|
||||||
chunks = fc;
|
chunks = fc;
|
||||||
fc->chunk_start = saved_start;
|
fc->chunk_start = saved_start;
|
||||||
fc->ncols = 0;
|
mreg = max_regs - 1;
|
||||||
fc->col_type = (short int *) xmalloc (sizeof (short int));
|
if (mreg < fc->ra)
|
||||||
fc->col_offset = (int *) xmalloc (sizeof (int));
|
mreg = fc->ra;
|
||||||
frame_need_space (fc, max_regs - 1);
|
frame_need_space (fc, mreg);
|
||||||
|
if (fc->fde_encoding)
|
||||||
version = *start++;
|
encoded_ptr_size = size_of_encoded_value (fc->fde_encoding);
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
printf ("\n%08lx ", (unsigned long) (saved_start - section_start));
|
printf ("\n%08lx ", (unsigned long) (saved_start - section_start));
|
||||||
print_dwarf_vma (length, fc->ptr_size);
|
print_dwarf_vma (length, fc->ptr_size);
|
||||||
|
@ -5389,33 +5441,6 @@ display_debug_frames (struct dwarf_section *section,
|
||||||
}
|
}
|
||||||
putchar ('\n');
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -5423,15 +5448,71 @@ display_debug_frames (struct dwarf_section *section,
|
||||||
static Frame_Chunk fde_fc;
|
static Frame_Chunk fde_fc;
|
||||||
unsigned long segment_selector;
|
unsigned long segment_selector;
|
||||||
|
|
||||||
fc = & fde_fc;
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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));
|
memset (fc, 0, sizeof (Frame_Chunk));
|
||||||
|
|
||||||
look_for = is_eh ? start - 4 - cie_id : section_start + cie_id;
|
|
||||||
|
|
||||||
for (cie = chunks; cie ; cie = cie->next)
|
|
||||||
if (cie->chunk_start == look_for)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!cie)
|
if (!cie)
|
||||||
{
|
{
|
||||||
warn ("Invalid CIE pointer 0x%s in FDE at %#08lx\n",
|
warn ("Invalid CIE pointer 0x%s in FDE at %#08lx\n",
|
||||||
|
|
Loading…
Reference in New Issue