This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
PATCH: dwarf.c: Check invalid registers
- From: "H.J. Lu" <hongjiu dot lu at intel dot com>
- To: binutils at sources dot redhat dot com
- Date: Thu, 19 Mar 2009 10:37:56 -0700
- Subject: PATCH: dwarf.c: Check invalid registers
- Reply-to: "H.J. Lu" <hjl dot tools at gmail dot com>
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: