This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] 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.

Tested on x86-64 and s390x. No regressions.

Ok?

Bye,

-Andreas-

binutils/ChangeLog:

2016-09-29  Andreas Krebbel  <krebbel@linux.vnet.ibm.com>

	* dwarf.c (display_debug_frames):
---
 binutils/dwarf.c | 35 ++++++++++++++++++++++++-----------
 1 file changed, 24 insertions(+), 11 deletions(-)

diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index e07f661..231eec7 100644
--- a/binutils/dwarf.c
+++ b/binutils/dwarf.c
@@ -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')
 		{
-		  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;
+		  if ((do_debug_frames_interp
+		       && fc->col_type[opa] == DW_CFA_unreferenced)
+		      || opa >= (unsigned int) cie->ncols)
+		    {
+		      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];
+		    }
 		}
 	      break;
 
@@ -6430,16 +6436,23 @@ 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')
 		{
-		  fc->col_type[reg] = cie->col_type[reg];
-		  fc->col_offset[reg] = cie->col_offset[reg];
+		  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];
+		    }
 		}
 	      break;
 
-- 
2.9.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]