summaryrefslogtreecommitdiff
path: root/binutils
diff options
context:
space:
mode:
authorAndreas Krebbel <krebbel@linux.vnet.ibm.com>2016-09-29 10:04:44 +0200
committerAndreas Krebbel <krebbel@linux.vnet.ibm.com>2016-09-29 16:34:57 +0200
commit50751e18f3f2fc47959a577a5754f1a2d80baf18 (patch)
treed345d503eab9c8b47adedc4b9312233069771ee8 /binutils
parent084303b8c636944564d7be3b85dde55e8c371e91 (diff)
downloadbinutils-gdb-50751e18f3f2fc47959a577a5754f1a2d80baf18.tar.gz
Frame info dump: Fix bad register marks.
On S/390 we see quite often registers marked as "bad register" in the readelf --debug-dump=frames or objdump -Wf output. 00000000 0000000000000014 00000000 CIE Version: 1 Augmentation: "zR" Code alignment factor: 1 Data alignment factor: -8 Return address column: 14 Augmentation data: 1b DW_CFA_def_cfa: r15 ofs 160 DW_CFA_nop DW_CFA_nop DW_CFA_nop ... 00000050 000000000000001c 00000054 FDE cie=00000000 pc=0000000080000e58..0000000080000e84 DW_CFA_advance_loc: 6 to 0000000080000e5e DW_CFA_offset: r14 at cfa-48 DW_CFA_offset: r15 at cfa-40 DW_CFA_advance_loc: 6 to 0000000080000e64 DW_CFA_def_cfa_offset: 320 DW_CFA_advance_loc: 18 to 0000000080000e76 DW_CFA_restore: bad register: r15 <------ DW_CFA_restore: r14 DW_CFA_def_cfa_offset: 160 This is triggered by this check in display_debug_frames (dwarf.c): case DW_CFA_restore: if (opa >= (unsigned int) cie->ncols || opa >= (unsigned int) fc->ncols) reg_prefix = bad_reg; cie->ncols is number of registers referenced in the CIE which is 15 due to r14 being given as return address column. So for the CFA_restore of r15 a "bad register" is being printed while the same rule on r14 is ok. The reason for this check is to prevent wild memory accesses when reading input with corrupted register values while accessing the col_type/col_offset arrays. However in that case r15 is a perfectly valid register. It just happens not to be mentioned in the CIE. Hence restoring the CIE rule for r15 should end up with the default rule which is DW_CFA_undefined. This probably wasn't observed on other platforms because they either do not use CFA_restore (x86-64) or do not issue CFA_restore on registers with a higher number than the return address column. binutils/ChangeLog: 2016-09-29 Andreas Krebbel <krebbel@linux.vnet.ibm.com> * dwarf.c (frame_display_row): Fix formatting of return address register column. (display_debug_frames): Ignore invalid indices into cie->col_type/cie->col_offset arrays and default to DW_CF_undefined instead.
Diffstat (limited to 'binutils')
-rw-r--r--binutils/dwarf.c33
1 files changed, 23 insertions, 10 deletions
diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index 95b33a8723e..b4687e97c90 100644
--- a/binutils/dwarf.c
+++ b/binutils/dwarf.c
@@ -5620,7 +5620,7 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, unsigned int *max_reg
if (fc->col_type[r] != DW_CFA_unreferenced)
{
if (r == fc->ra)
- printf ("ra ");
+ printf ("ra ");
else
printf ("%-5s ", regname (r, 1));
}
@@ -6331,19 +6331,25 @@ display_debug_frames (struct dwarf_section *section,
break;
case DW_CFA_restore:
- if (opa >= (unsigned int) cie->ncols
- || opa >= (unsigned int) fc->ncols)
+ if (opa >= (unsigned int) fc->ncols)
reg_prefix = bad_reg;
if (! do_debug_frames_interp || *reg_prefix != '\0')
printf (" DW_CFA_restore: %s%s\n",
reg_prefix, regname (opa, 0));
- if (*reg_prefix == '\0')
+ if (*reg_prefix != '\0')
+ break;
+
+ if (opa >= (unsigned int) cie->ncols
+ || (do_debug_frames_interp
+ && cie->col_type[opa] == DW_CFA_unreferenced))
+ {
+ fc->col_type[opa] = DW_CFA_undefined;
+ fc->col_offset[opa] = 0;
+ }
+ else
{
fc->col_type[opa] = cie->col_type[opa];
fc->col_offset[opa] = cie->col_offset[opa];
- if (do_debug_frames_interp
- && fc->col_type[opa] == DW_CFA_unreferenced)
- fc->col_type[opa] = DW_CFA_undefined;
}
break;
@@ -6430,13 +6436,20 @@ display_debug_frames (struct dwarf_section *section,
case DW_CFA_restore_extended:
reg = LEB ();
- if (reg >= (unsigned int) cie->ncols
- || reg >= (unsigned int) fc->ncols)
+ if (reg >= (unsigned int) fc->ncols)
reg_prefix = bad_reg;
if (! do_debug_frames_interp || *reg_prefix != '\0')
printf (" DW_CFA_restore_extended: %s%s\n",
reg_prefix, regname (reg, 0));
- if (*reg_prefix == '\0')
+ if (*reg_prefix != '\0')
+ break;
+
+ if (reg >= (unsigned int) cie->ncols)
+ {
+ fc->col_type[reg] = DW_CFA_undefined;
+ fc->col_offset[reg] = 0;
+ }
+ else
{
fc->col_type[reg] = cie->col_type[reg];
fc->col_offset[reg] = cie->col_offset[reg];