This is the mail archive of the binutils-cvs@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]

[binutils-gdb] Frame info dump: Fix bad register marks.


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=50751e18f3f2fc47959a577a5754f1a2d80baf18

commit 50751e18f3f2fc47959a577a5754f1a2d80baf18
Author: Andreas Krebbel <krebbel@linux.vnet.ibm.com>
Date:   Thu Sep 29 10:04:44 2016 +0200

    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.

Diff:
---
 binutils/dwarf.c | 33 +++++++++++++++++++++++----------
 1 file changed, 23 insertions(+), 10 deletions(-)

diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index 95b33a8..b4687e9 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];


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