PATCH: dwarf.c: Check invalid registers

H.J. Lu hongjiu.lu@intel.com
Thu Mar 19 17:38:00 GMT 2009


Hi,

I have an x86-64 binary with corrupt DWARF sections.  Many registers are
either never really used or simply bad:

  DW_CFA_restore: bad register: r63 (ldtr) 

DW_CFA_restore points to r63, which is never used.  

 DW_CFA_undefined: bad register: r-104

DW_CFA_undefined points to register -104, which doesn't exist.  We are
reading/writing on invalid memory.  This patch checks them.  OK to
install?

Thanks.


H.J.
---
2009-03-19  H.J. Lu  <hongjiu.lu@intel.com>

	* dwarf.c (dwarf_regnames): Moved before frame_need_space.
	(dwarf_regnames_count): Likewise.
	(frame_need_space): Return int.
	(display_debug_frames): Check invalid registers.

--- binutils/dwarf.c.check	2009-02-09 16:16:35.000000000 -0800
+++ binutils/dwarf.c	2009-03-19 10:24:10.000000000 -0700
@@ -3621,17 +3621,27 @@ typedef struct Frame_Chunk
 }
 Frame_Chunk;
 
+static const char *const *dwarf_regnames;
+static unsigned int dwarf_regnames_count;
+
 /* A marker for a col_type that means this column was never referenced
    in the frame info.  */
 #define DW_CFA_unreferenced (-1)
 
-static void
-frame_need_space (Frame_Chunk *fc, int reg)
+/* Return 0 if not more space is needed, 1 if more space is needed,
+   -1 for invalid reg.  */
+
+static int
+frame_need_space (Frame_Chunk *fc, unsigned int reg)
 {
   int prev = fc->ncols;
 
-  if (reg < fc->ncols)
-    return;
+  if (reg < (unsigned int) fc->ncols)
+    return 0;
+
+  if (dwarf_regnames_count
+      && reg > dwarf_regnames_count)
+    return -1;
 
   fc->ncols = reg + 1;
   fc->col_type = xcrealloc (fc->col_type, fc->ncols, sizeof (short int));
@@ -3643,6 +3653,7 @@ frame_need_space (Frame_Chunk *fc, int r
       fc->col_offset[prev] = 0;
       prev++;
     }
+  return 1;
 }
 
 static const char *const dwarf_regnames_i386[] =
@@ -3684,9 +3695,6 @@ static const char *const dwarf_regnames_
   "mxcsr", "fcw", "fsw"
 };
 
-static const char *const *dwarf_regnames;
-static unsigned int dwarf_regnames_count;
-
 void
 init_dwarf_regnames (unsigned int e_machine)
 {
@@ -3816,6 +3824,7 @@ display_debug_frames (struct dwarf_secti
   int is_eh = strcmp (section->name, ".eh_frame") == 0;
   unsigned int length_return;
   int max_regs = 0;
+  const char *bad_reg = _("bad register: ");
 
   printf (_("Contents of the %s section:\n"), section->name);
 
@@ -4089,12 +4098,12 @@ display_debug_frames (struct dwarf_secti
 		  break;
 		case DW_CFA_offset:
 		  LEB ();
-		  frame_need_space (fc, opa);
-		  fc->col_type[opa] = DW_CFA_undefined;
+		  if (frame_need_space (fc, opa) >= 0)
+		    fc->col_type[opa] = DW_CFA_undefined;
 		  break;
 		case DW_CFA_restore:
-		  frame_need_space (fc, opa);
-		  fc->col_type[opa] = DW_CFA_undefined;
+		  if (frame_need_space (fc, opa) >= 0)
+		    fc->col_type[opa] = DW_CFA_undefined;
 		  break;
 		case DW_CFA_set_loc:
 		  start += encoded_ptr_size;
@@ -4111,28 +4120,29 @@ display_debug_frames (struct dwarf_secti
 		case DW_CFA_offset_extended:
 		case DW_CFA_val_offset:
 		  reg = LEB (); LEB ();
-		  frame_need_space (fc, reg);
-		  fc->col_type[reg] = DW_CFA_undefined;
+		  if (frame_need_space (fc, reg) >= 0)
+		    fc->col_type[reg] = DW_CFA_undefined;
 		  break;
 		case DW_CFA_restore_extended:
 		  reg = LEB ();
 		  frame_need_space (fc, reg);
-		  fc->col_type[reg] = DW_CFA_undefined;
+		  if (frame_need_space (fc, reg) >= 0)
+		    fc->col_type[reg] = DW_CFA_undefined;
 		  break;
 		case DW_CFA_undefined:
 		  reg = LEB ();
-		  frame_need_space (fc, reg);
-		  fc->col_type[reg] = DW_CFA_undefined;
+		  if (frame_need_space (fc, reg) >= 0)
+		    fc->col_type[reg] = DW_CFA_undefined;
 		  break;
 		case DW_CFA_same_value:
 		  reg = LEB ();
-		  frame_need_space (fc, reg);
-		  fc->col_type[reg] = DW_CFA_undefined;
+		  if (frame_need_space (fc, reg) >= 0)
+		    fc->col_type[reg] = DW_CFA_undefined;
 		  break;
 		case DW_CFA_register:
 		  reg = LEB (); LEB ();
-		  frame_need_space (fc, reg);
-		  fc->col_type[reg] = DW_CFA_undefined;
+		  if (frame_need_space (fc, reg) >= 0)
+		    fc->col_type[reg] = DW_CFA_undefined;
 		  break;
 		case DW_CFA_def_cfa:
 		  LEB (); LEB ();
@@ -4152,14 +4162,14 @@ display_debug_frames (struct dwarf_secti
 		  reg = LEB ();
 		  tmp = LEB ();
 		  start += tmp;
-		  frame_need_space (fc, reg);
-		  fc->col_type[reg] = DW_CFA_undefined;
+		  if (frame_need_space (fc, reg) >= 0)
+		    fc->col_type[reg] = DW_CFA_undefined;
 		  break;
 		case DW_CFA_offset_extended_sf:
 		case DW_CFA_val_offset_sf:
 		  reg = LEB (); SLEB ();
-		  frame_need_space (fc, reg);
-		  fc->col_type[reg] = DW_CFA_undefined;
+		  if (frame_need_space (fc, reg) >= 0)
+		    fc->col_type[reg] = DW_CFA_undefined;
 		  break;
 		case DW_CFA_def_cfa_sf:
 		  LEB (); SLEB ();
@@ -4175,9 +4185,9 @@ display_debug_frames (struct dwarf_secti
 		  break;
 		case DW_CFA_GNU_negative_offset_extended:
 		  reg = LEB (); LEB ();
-		  frame_need_space (fc, reg);
-		  fc->col_type[reg] = DW_CFA_undefined;
-
+		  if (frame_need_space (fc, reg) >= 0)
+		    fc->col_type[reg] = DW_CFA_undefined;
+		  break;
 		default:
 		  break;
 		}
@@ -4194,6 +4204,7 @@ display_debug_frames (struct dwarf_secti
 	  unsigned long ul, reg, roffs;
 	  long l, ofs;
 	  dwarf_vma vma;
+	  const char *reg_prefix = "";
 
 	  op = *start++;
 	  opa = op & 0x3f;
@@ -4216,18 +4227,31 @@ display_debug_frames (struct dwarf_secti
 
 	    case DW_CFA_offset:
 	      roffs = LEB ();
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_offset: %s at cfa%+ld\n",
-			regname (opa, 0), roffs * fc->data_factor);
-	      fc->col_type[opa] = DW_CFA_offset;
-	      fc->col_offset[opa] = roffs * fc->data_factor;
+	      if (opa >= (unsigned int) fc->ncols)
+		reg_prefix = bad_reg;
+	      if (! do_debug_frames_interp || *reg_prefix != '\0')
+		printf ("  DW_CFA_offset: %s%s at cfa%+ld\n",
+			reg_prefix, regname (opa, 0),
+			roffs * fc->data_factor);
+	      if (*reg_prefix == '\0')
+		{
+		  fc->col_type[opa] = DW_CFA_offset;
+		  fc->col_offset[opa] = roffs * fc->data_factor;
+		}
 	      break;
 
 	    case DW_CFA_restore:
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_restore: %s\n", regname (opa, 0));
-	      fc->col_type[opa] = cie->col_type[opa];
-	      fc->col_offset[opa] = cie->col_offset[opa];
+	      if (opa >= (unsigned int) cie->ncols
+		  || 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];
+		}
 	      break;
 
 	    case DW_CFA_set_loc:
@@ -4278,59 +4302,94 @@ display_debug_frames (struct dwarf_secti
 	    case DW_CFA_offset_extended:
 	      reg = LEB ();
 	      roffs = LEB ();
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_offset_extended: %s at cfa%+ld\n",
-			regname (reg, 0), roffs * fc->data_factor);
-	      fc->col_type[reg] = DW_CFA_offset;
-	      fc->col_offset[reg] = roffs * fc->data_factor;
+	      if (reg >= (unsigned int) fc->ncols)
+		reg_prefix = bad_reg;
+	      if (! do_debug_frames_interp || *reg_prefix != '\0')
+		printf ("  DW_CFA_offset_extended: %s%s at cfa%+ld\n",
+			reg_prefix, regname (reg, 0),
+			roffs * fc->data_factor);
+	      if (*reg_prefix == '\0')
+		{
+		  fc->col_type[reg] = DW_CFA_offset;
+		  fc->col_offset[reg] = roffs * fc->data_factor;
+		}
 	      break;
 
 	    case DW_CFA_val_offset:
 	      reg = LEB ();
 	      roffs = LEB ();
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_val_offset: %s at cfa%+ld\n",
-			regname (reg, 0), roffs * fc->data_factor);
-	      fc->col_type[reg] = DW_CFA_val_offset;
-	      fc->col_offset[reg] = roffs * fc->data_factor;
+	      if (reg >= (unsigned int) fc->ncols)
+		reg_prefix = bad_reg;
+	      if (! do_debug_frames_interp || *reg_prefix != '\0')
+		printf ("  DW_CFA_val_offset: %s%s at cfa%+ld\n",
+			reg_prefix, regname (reg, 0),
+			roffs * fc->data_factor);
+	      if (*reg_prefix == '\0')
+		{
+		  fc->col_type[reg] = DW_CFA_val_offset;
+		  fc->col_offset[reg] = roffs * fc->data_factor;
+		}
 	      break;
 
 	    case DW_CFA_restore_extended:
 	      reg = LEB ();
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_restore_extended: %s\n",
-			regname (reg, 0));
-	      fc->col_type[reg] = cie->col_type[reg];
-	      fc->col_offset[reg] = cie->col_offset[reg];
+	      if (reg >= (unsigned int) cie->ncols
+		  || 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];
+		}
 	      break;
 
 	    case DW_CFA_undefined:
 	      reg = LEB ();
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_undefined: %s\n", regname (reg, 0));
-	      fc->col_type[reg] = DW_CFA_undefined;
-	      fc->col_offset[reg] = 0;
+	      if (reg >= (unsigned int) fc->ncols)
+		reg_prefix = bad_reg;
+	      if (! do_debug_frames_interp || *reg_prefix != '\0')
+		printf ("  DW_CFA_undefined: %s%s\n",
+			reg_prefix, regname (reg, 0));
+	      if (*reg_prefix == '\0')
+		{
+		  fc->col_type[reg] = DW_CFA_undefined;
+		  fc->col_offset[reg] = 0;
+		}
 	      break;
 
 	    case DW_CFA_same_value:
 	      reg = LEB ();
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_same_value: %s\n", regname (reg, 0));
-	      fc->col_type[reg] = DW_CFA_same_value;
-	      fc->col_offset[reg] = 0;
+	      if (reg >= (unsigned int) fc->ncols)
+		reg_prefix = bad_reg;
+	      if (! do_debug_frames_interp || *reg_prefix != '\0')
+		printf ("  DW_CFA_same_value: %s%s\n",
+			reg_prefix, regname (reg, 0));
+	      if (*reg_prefix == '\0')
+		{
+		  fc->col_type[reg] = DW_CFA_same_value;
+		  fc->col_offset[reg] = 0;
+		}
 	      break;
 
 	    case DW_CFA_register:
 	      reg = LEB ();
 	      roffs = LEB ();
-	      if (! do_debug_frames_interp)
+	      if (reg >= (unsigned int) fc->ncols)
+		reg_prefix = bad_reg;
+	      if (! do_debug_frames_interp || *reg_prefix != '\0')
 		{
-		  printf ("  DW_CFA_register: %s in ",
-			  regname (reg, 0));
+		  printf ("  DW_CFA_register: %s%s in ",
+			  reg_prefix, regname (reg, 0));
 		  puts (regname (roffs, 0));
 		}
-	      fc->col_type[reg] = DW_CFA_register;
-	      fc->col_offset[reg] = roffs;
+	      if (*reg_prefix == '\0')
+		{
+		  fc->col_type[reg] = DW_CFA_register;
+		  fc->col_offset[reg] = roffs;
+		}
 	      break;
 
 	    case DW_CFA_remember_state:
@@ -4409,53 +4468,69 @@ display_debug_frames (struct dwarf_secti
 	    case DW_CFA_expression:
 	      reg = LEB ();
 	      ul = LEB ();
-	      if (! do_debug_frames_interp)
+	      if (reg >= (unsigned int) fc->ncols)
+		reg_prefix = bad_reg;
+	      if (! do_debug_frames_interp || *reg_prefix != '\0')
 		{
-		  printf ("  DW_CFA_expression: %s (",
-			  regname (reg, 0));
+		  printf ("  DW_CFA_expression: %s%s (",
+			  reg_prefix, regname (reg, 0));
 		  decode_location_expression (start, eh_addr_size,
 					      ul, 0, section);
 		  printf (")\n");
 		}
-	      fc->col_type[reg] = DW_CFA_expression;
+	      if (*reg_prefix == '\0')
+		fc->col_type[reg] = DW_CFA_expression;
 	      start += ul;
 	      break;
 
 	    case DW_CFA_val_expression:
 	      reg = LEB ();
 	      ul = LEB ();
-	      if (! do_debug_frames_interp)
+	      if (reg >= (unsigned int) fc->ncols)
+		reg_prefix = bad_reg;
+	      if (! do_debug_frames_interp || *reg_prefix != '\0')
 		{
-		  printf ("  DW_CFA_val_expression: %s (",
-			  regname (reg, 0));
+		  printf ("  DW_CFA_val_expression: %s%s (",
+			  reg_prefix, regname (reg, 0));
 		  decode_location_expression (start, eh_addr_size, ul, 0,
 					      section);
 		  printf (")\n");
 		}
-	      fc->col_type[reg] = DW_CFA_val_expression;
+	      if (*reg_prefix == '\0')
+		fc->col_type[reg] = DW_CFA_val_expression;
 	      start += ul;
 	      break;
 
 	    case DW_CFA_offset_extended_sf:
 	      reg = LEB ();
 	      l = SLEB ();
-	      frame_need_space (fc, reg);
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_offset_extended_sf: %s at cfa%+ld\n",
-			regname (reg, 0), l * fc->data_factor);
-	      fc->col_type[reg] = DW_CFA_offset;
-	      fc->col_offset[reg] = l * fc->data_factor;
+	      if (frame_need_space (fc, reg) < 0)
+		reg_prefix = bad_reg;
+	      if (! do_debug_frames_interp || *reg_prefix != '\0')
+		printf ("  DW_CFA_offset_extended_sf: %s%s at cfa%+ld\n",
+			reg_prefix, regname (reg, 0),
+			l * fc->data_factor);
+	      if (*reg_prefix == '\0')
+		{
+		  fc->col_type[reg] = DW_CFA_offset;
+		  fc->col_offset[reg] = l * fc->data_factor;
+		}
 	      break;
 
 	    case DW_CFA_val_offset_sf:
 	      reg = LEB ();
 	      l = SLEB ();
-	      frame_need_space (fc, reg);
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_val_offset_sf: %s at cfa%+ld\n",
-			regname (reg, 0), l * fc->data_factor);
-	      fc->col_type[reg] = DW_CFA_val_offset;
-	      fc->col_offset[reg] = l * fc->data_factor;
+	      if (frame_need_space (fc, reg) < 0)
+		reg_prefix = bad_reg;
+	      if (! do_debug_frames_interp || *reg_prefix != '\0')
+		printf ("  DW_CFA_val_offset_sf: %s%s at cfa%+ld\n",
+			reg_prefix, regname (reg, 0),
+			l * fc->data_factor);
+	      if (*reg_prefix == '\0')
+		{
+		  fc->col_type[reg] = DW_CFA_val_offset;
+		  fc->col_offset[reg] = l * fc->data_factor;
+		}
 	      break;
 
 	    case DW_CFA_def_cfa_sf:
@@ -4500,12 +4575,17 @@ display_debug_frames (struct dwarf_secti
 	    case DW_CFA_GNU_negative_offset_extended:
 	      reg = LEB ();
 	      l = - LEB ();
-	      frame_need_space (fc, reg);
-	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_GNU_negative_offset_extended: %s at cfa%+ld\n",
-			regname (reg, 0), l * fc->data_factor);
-	      fc->col_type[reg] = DW_CFA_offset;
-	      fc->col_offset[reg] = l * fc->data_factor;
+	      if (frame_need_space (fc, reg) < 0)
+		reg_prefix = bad_reg;
+	      if (! do_debug_frames_interp || *reg_prefix != '\0')
+		printf ("  DW_CFA_GNU_negative_offset_extended: %s%s at cfa%+ld\n",
+			reg_prefix, regname (reg, 0),
+			l * fc->data_factor);
+	      if (*reg_prefix == '\0')
+		{
+		  fc->col_type[reg] = DW_CFA_offset;
+		  fc->col_offset[reg] = l * fc->data_factor;
+		}
 	      break;
 
 	    default:



More information about the Binutils mailing list