summaryrefslogtreecommitdiff
path: root/libgcc
diff options
context:
space:
mode:
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>2013-05-17 15:27:37 +0000
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>2013-05-17 15:27:37 +0000
commitbe82f7a8fca57f05dcde4bb98b10aef2605486b8 (patch)
tree545aebc5456658d87774829e39cd3651a5e27df8 /libgcc
parent6150dc358dc5c859a6ee08dd921908c4fbf725a5 (diff)
downloadgcc-be82f7a8fca57f05dcde4bb98b10aef2605486b8.tar.gz
PR target/49146
* unwind-dw2.c (UNWIND_COLUMN_IN_RANGE): New macro. (execute_cfa_program): Use it when storing to fs->regs. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@199019 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgcc')
-rw-r--r--libgcc/ChangeLog6
-rw-r--r--libgcc/unwind-dw2.c125
2 files changed, 101 insertions, 30 deletions
diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog
index a04c4ffb37d..2617c7e0607 100644
--- a/libgcc/ChangeLog
+++ b/libgcc/ChangeLog
@@ -1,3 +1,9 @@
+2013-05-17 Richard Henderson <rth@redhat.com>
+
+ PR target/49146
+ * unwind-dw2.c (UNWIND_COLUMN_IN_RANGE): New macro.
+ (execute_cfa_program): Use it when storing to fs->regs.
+
2013-05-08 Kai Tietz <ktietz@redhat.com>
* config/i386/cygming-crtbegin.c (__register_frame_info): Make weak.
diff --git a/libgcc/unwind-dw2.c b/libgcc/unwind-dw2.c
index 80de5ab1894..041f9d5c3f0 100644
--- a/libgcc/unwind-dw2.c
+++ b/libgcc/unwind-dw2.c
@@ -59,6 +59,35 @@
#define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO)
#endif
+/* ??? For the public function interfaces, we tend to gcc_assert that the
+ column numbers are in range. For the dwarf2 unwind info this does happen,
+ although so far in a case that doesn't actually matter.
+
+ See PR49146, in which a call from x86_64 ms abi to x86_64 unix abi stores
+ the call-saved xmm registers and annotates them. We havn't bothered
+ providing support for the xmm registers for the x86_64 port primarily
+ because the 64-bit windows targets don't use dwarf2 unwind, using sjlj or
+ SEH instead. Adding the support for unix targets would generally be a
+ waste. However, some runtime libraries supplied with ICC do contain such
+ an unorthodox transition, as well as the unwind info to match. This loss
+ of register restoration doesn't matter in practice, because the exception
+ is caught in the native unix abi, where all of the xmm registers are
+ call clobbered.
+
+ Ideally, we'd record some bit to notice when we're failing to restore some
+ register recorded in the unwind info, but to do that we need annotation on
+ the unix->ms abi edge, so that we know when the register data may be
+ discarded. And since this edge is also within the ICC library, we're
+ unlikely to be able to get the new annotation.
+
+ Barring a magic solution to restore the ms abi defined 128-bit xmm registers
+ (as distictly opposed to the full runtime width) without causing extra
+ overhead for normal unix abis, the best solution seems to be to simply
+ ignore unwind data for unknown columns. */
+
+#define UNWIND_COLUMN_IN_RANGE(x) \
+ __builtin_expect((x) <= DWARF_FRAME_REGISTERS, 1)
+
#ifdef REG_VALUE_IN_UNWIND_CONTEXT
typedef _Unwind_Word _Unwind_Context_Reg_Val;
@@ -939,14 +968,19 @@ execute_cfa_program (const unsigned char *insn_ptr,
reg = insn & 0x3f;
insn_ptr = read_uleb128 (insn_ptr, &utmp);
offset = (_Unwind_Sword) utmp * fs->data_align;
- fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
- = REG_SAVED_OFFSET;
- fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset;
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+ if (UNWIND_COLUMN_IN_RANGE (reg))
+ {
+ fs->regs.reg[reg].how = REG_SAVED_OFFSET;
+ fs->regs.reg[reg].loc.offset = offset;
+ }
}
else if ((insn & 0xc0) == DW_CFA_restore)
{
reg = insn & 0x3f;
- fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how = REG_UNSAVED;
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+ if (UNWIND_COLUMN_IN_RANGE (reg))
+ fs->regs.reg[reg].how = REG_UNSAVED;
}
else switch (insn)
{
@@ -977,26 +1011,35 @@ execute_cfa_program (const unsigned char *insn_ptr,
insn_ptr = read_uleb128 (insn_ptr, &reg);
insn_ptr = read_uleb128 (insn_ptr, &utmp);
offset = (_Unwind_Sword) utmp * fs->data_align;
- fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
- = REG_SAVED_OFFSET;
- fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset;
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+ if (UNWIND_COLUMN_IN_RANGE (reg))
+ {
+ fs->regs.reg[reg].how = REG_SAVED_OFFSET;
+ fs->regs.reg[reg].loc.offset = offset;
+ }
break;
case DW_CFA_restore_extended:
insn_ptr = read_uleb128 (insn_ptr, &reg);
/* FIXME, this is wrong; the CIE might have said that the
register was saved somewhere. */
- fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN(reg)].how = REG_UNSAVED;
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+ if (UNWIND_COLUMN_IN_RANGE (reg))
+ fs->regs.reg[reg].how = REG_UNSAVED;
break;
case DW_CFA_same_value:
insn_ptr = read_uleb128 (insn_ptr, &reg);
- fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN(reg)].how = REG_UNSAVED;
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+ if (UNWIND_COLUMN_IN_RANGE (reg))
+ fs->regs.reg[reg].how = REG_UNSAVED;
break;
case DW_CFA_undefined:
insn_ptr = read_uleb128 (insn_ptr, &reg);
- fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN(reg)].how = REG_UNDEFINED;
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+ if (UNWIND_COLUMN_IN_RANGE (reg))
+ fs->regs.reg[reg].how = REG_UNDEFINED;
break;
case DW_CFA_nop:
@@ -1007,9 +1050,12 @@ execute_cfa_program (const unsigned char *insn_ptr,
_uleb128_t reg2;
insn_ptr = read_uleb128 (insn_ptr, &reg);
insn_ptr = read_uleb128 (insn_ptr, &reg2);
- fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how = REG_SAVED_REG;
- fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.reg =
- (_Unwind_Word)reg2;
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+ if (UNWIND_COLUMN_IN_RANGE (reg))
+ {
+ fs->regs.reg[reg].how = REG_SAVED_REG;
+ fs->regs.reg[reg].loc.reg = (_Unwind_Word)reg2;
+ }
}
break;
@@ -1067,8 +1113,12 @@ execute_cfa_program (const unsigned char *insn_ptr,
case DW_CFA_expression:
insn_ptr = read_uleb128 (insn_ptr, &reg);
- fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how = REG_SAVED_EXP;
- fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.exp = insn_ptr;
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+ if (UNWIND_COLUMN_IN_RANGE (reg))
+ {
+ fs->regs.reg[reg].how = REG_SAVED_EXP;
+ fs->regs.reg[reg].loc.exp = insn_ptr;
+ }
insn_ptr = read_uleb128 (insn_ptr, &utmp);
insn_ptr += utmp;
break;
@@ -1078,9 +1128,12 @@ execute_cfa_program (const unsigned char *insn_ptr,
insn_ptr = read_uleb128 (insn_ptr, &reg);
insn_ptr = read_sleb128 (insn_ptr, &stmp);
offset = stmp * fs->data_align;
- fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
- = REG_SAVED_OFFSET;
- fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset;
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+ if (UNWIND_COLUMN_IN_RANGE (reg))
+ {
+ fs->regs.reg[reg].how = REG_SAVED_OFFSET;
+ fs->regs.reg[reg].loc.offset = offset;
+ }
break;
case DW_CFA_def_cfa_sf:
@@ -1103,25 +1156,34 @@ execute_cfa_program (const unsigned char *insn_ptr,
insn_ptr = read_uleb128 (insn_ptr, &reg);
insn_ptr = read_uleb128 (insn_ptr, &utmp);
offset = (_Unwind_Sword) utmp * fs->data_align;
- fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
- = REG_SAVED_VAL_OFFSET;
- fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset;
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+ if (UNWIND_COLUMN_IN_RANGE (reg))
+ {
+ fs->regs.reg[reg].how = REG_SAVED_VAL_OFFSET;
+ fs->regs.reg[reg].loc.offset = offset;
+ }
break;
case DW_CFA_val_offset_sf:
insn_ptr = read_uleb128 (insn_ptr, &reg);
insn_ptr = read_sleb128 (insn_ptr, &stmp);
offset = stmp * fs->data_align;
- fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
- = REG_SAVED_VAL_OFFSET;
- fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset;
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+ if (UNWIND_COLUMN_IN_RANGE (reg))
+ {
+ fs->regs.reg[reg].how = REG_SAVED_VAL_OFFSET;
+ fs->regs.reg[reg].loc.offset = offset;
+ }
break;
case DW_CFA_val_expression:
insn_ptr = read_uleb128 (insn_ptr, &reg);
- fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
- = REG_SAVED_VAL_EXP;
- fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.exp = insn_ptr;
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+ if (UNWIND_COLUMN_IN_RANGE (reg))
+ {
+ fs->regs.reg[reg].how = REG_SAVED_VAL_EXP;
+ fs->regs.reg[reg].loc.exp = insn_ptr;
+ }
insn_ptr = read_uleb128 (insn_ptr, &utmp);
insn_ptr += utmp;
break;
@@ -1147,9 +1209,12 @@ execute_cfa_program (const unsigned char *insn_ptr,
insn_ptr = read_uleb128 (insn_ptr, &reg);
insn_ptr = read_uleb128 (insn_ptr, &utmp);
offset = (_Unwind_Word) utmp * fs->data_align;
- fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
- = REG_SAVED_OFFSET;
- fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = -offset;
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+ if (UNWIND_COLUMN_IN_RANGE (reg))
+ {
+ fs->regs.reg[reg].how = REG_SAVED_OFFSET;
+ fs->regs.reg[reg].loc.offset = -offset;
+ }
break;
default: