summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2006-02-27 17:26:26 +0000
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2006-02-27 17:26:26 +0000
commit15c73eb7f6ae9d0be39182f797df10d573be4199 (patch)
tree6984337363ffe60556818a17e48ceaa2283110bb /gcc
parent5f506404644a3986acc8986f3c980a488c2c27b7 (diff)
downloadgcc-15c73eb7f6ae9d0be39182f797df10d573be4199.tar.gz
PR other/26208
* unwind-dw2.c (struct _Unwind_Context): Add signal_frame field. (extract_cie_info): Handle S flag in augmentation string. (execute_cfa_program): If context->signal_frame, execute also fs->pc == context->ra instructions. (uw_frame_state_for): If context->signal_frame, don't subtract one from context->ra to find FDE. (uw_update_context_1): Set context->signal_frame to fs->signal_frame. (_Unwind_GetIPInfo): New function. * unwind-dw2.h (_Unwind_FrameState): Add signal_frame field. * unwind-c.c (PERSONALITY_FUNCTION): Use _Unwind_GetIPInfo instead of _Unwind_GetIP. * unwind-sjlj.c (_Unwind_GetIPInfo): New function. * unwind-generic.h (_Unwind_GetIPInfo): New prototype. * unwind-compat.c (_Unwind_GetIPInfo): New function. * libgcc-std.ver (_Unwind_GetIPInfo): Export @@GCC_4.2.0. * config/ia64/unwind-ia64.c (_Unwind_GetIPInfo): New function. * config/arm/unwind-arm.h (_Unwind_GetIPInfo): Define. * config/i386/linux-unwind.h (x86_fallback_frame_state, x86_64_fallback_frame_state): Set fs->signal_frame. * config/rs6000/linux-unwind.h (ppc_fallback_frame_state): Likewise. (MD_FROB_UPDATE_CONTEXT): Define unconditionally. (frob_update_context): Likewise. Workaround missing S flag in Linux 2.6.12 - 2.6.16 kernel vDSOs. * config/s390/linux-unwind.h (s390_fallback_frame_state): Likewise. Remove the psw_addr + 1 hack. libjava/ * exception.cc (PERSONALITY_FUNCTION): Use _Unwind_GetIPInfo instead of _Unwind_GetIP. * include/i386-signal.h (MAKE_THROW_FRAME): Change into empty macro. (HANDLE_DIVIDE_OVERFLOW): Don't adjust _res->eip if falling through to throw. * include/x86_64-signal.h (MAKE_THROW_FRAME): Change into empty macro. * include/powerpc-signal.h (MAKE_THROW_FRAME): Change into empty macro. libstdc++-v3/ * libsupc++/eh_personality.cc (PERSONALITY_FUNCTION): Use _Unwind_GetIPInfo instead of _Unwind_GetIP. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@111488 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog30
-rw-r--r--gcc/config/arm/unwind-arm.h5
-rw-r--r--gcc/config/i386/linux-unwind.h4
-rw-r--r--gcc/config/ia64/unwind-ia64.c7
-rw-r--r--gcc/config/rs6000/linux-unwind.h66
-rw-r--r--gcc/config/s390/linux-unwind.h28
-rw-r--r--gcc/libgcc-std.ver1
-rw-r--r--gcc/unwind-c.c5
-rw-r--r--gcc/unwind-compat.c9
-rw-r--r--gcc/unwind-dw2.c31
-rw-r--r--gcc/unwind-dw2.h1
-rw-r--r--gcc/unwind-generic.h3
-rw-r--r--gcc/unwind-sjlj.c7
13 files changed, 145 insertions, 52 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index ca154bdd1fe..baabf6a5f1a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,33 @@
+2006-02-27 Jakub Jelinek <jakub@redhat.com>
+
+ PR other/26208
+ * unwind-dw2.c (struct _Unwind_Context): Add signal_frame field.
+ (extract_cie_info): Handle S flag in augmentation string.
+ (execute_cfa_program): If context->signal_frame, execute also
+ fs->pc == context->ra instructions.
+ (uw_frame_state_for): If context->signal_frame, don't subtract one
+ from context->ra to find FDE.
+ (uw_update_context_1): Set context->signal_frame to
+ fs->signal_frame.
+ (_Unwind_GetIPInfo): New function.
+ * unwind-dw2.h (_Unwind_FrameState): Add signal_frame field.
+ * unwind-c.c (PERSONALITY_FUNCTION): Use _Unwind_GetIPInfo instead
+ of _Unwind_GetIP.
+ * unwind-sjlj.c (_Unwind_GetIPInfo): New function.
+ * unwind-generic.h (_Unwind_GetIPInfo): New prototype.
+ * unwind-compat.c (_Unwind_GetIPInfo): New function.
+ * libgcc-std.ver (_Unwind_GetIPInfo): Export @@GCC_4.2.0.
+ * config/ia64/unwind-ia64.c (_Unwind_GetIPInfo): New function.
+ * config/arm/unwind-arm.h (_Unwind_GetIPInfo): Define.
+ * config/i386/linux-unwind.h (x86_fallback_frame_state,
+ x86_64_fallback_frame_state): Set fs->signal_frame.
+ * config/rs6000/linux-unwind.h (ppc_fallback_frame_state): Likewise.
+ (MD_FROB_UPDATE_CONTEXT): Define unconditionally.
+ (frob_update_context): Likewise. Workaround missing S flag in
+ Linux 2.6.12 - 2.6.16 kernel vDSOs.
+ * config/s390/linux-unwind.h (s390_fallback_frame_state): Likewise.
+ Remove the psw_addr + 1 hack.
+
2006-02-27 Daniel Berlin <dberlin@dberlin.org>
* tree-ssa-structalias.c (get_constraint_for): Move code to deal
diff --git a/gcc/config/arm/unwind-arm.h b/gcc/config/arm/unwind-arm.h
index dd8d2affe39..f7cfcab8890 100644
--- a/gcc/config/arm/unwind-arm.h
+++ b/gcc/config/arm/unwind-arm.h
@@ -1,5 +1,5 @@
/* Header file for the ARM EABI unwinder
- Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
Contributed by Paul Brook
This file is free software; you can redistribute it and/or modify it
@@ -250,6 +250,9 @@ extern "C" {
#define _Unwind_GetIP(context) \
(_Unwind_GetGR (context, 15) & ~(_Unwind_Word)1)
+#define _Unwind_GetIP(context, ip_before_insn) \
+ (*ip_before_insn = 0, _Unwind_GetGR (context, 15) & ~(_Unwind_Word)1)
+
static inline void
_Unwind_SetGR (_Unwind_Context *context, int regno, _Unwind_Word val)
{
diff --git a/gcc/config/i386/linux-unwind.h b/gcc/config/i386/linux-unwind.h
index 6ca1309c73c..07979d319b6 100644
--- a/gcc/config/i386/linux-unwind.h
+++ b/gcc/config/i386/linux-unwind.h
@@ -1,5 +1,5 @@
/* DWARF2 EH unwinding support for AMD x86-64 and x86.
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GCC.
@@ -100,6 +100,7 @@ x86_64_fallback_frame_state (struct _Unwind_Context *context,
fs->regs.reg[16].how = REG_SAVED_OFFSET;
fs->regs.reg[16].loc.offset = (long)&sc->rip - new_cfa;
fs->retaddr_column = 16;
+ fs->signal_frame = 1;
return _URC_NO_REASON;
}
@@ -172,6 +173,7 @@ x86_fallback_frame_state (struct _Unwind_Context *context,
fs->regs.reg[8].how = REG_SAVED_OFFSET;
fs->regs.reg[8].loc.offset = (long)&sc->REG_NAME(eip) - new_cfa;
fs->retaddr_column = 8;
+ fs->signal_frame = 1;
return _URC_NO_REASON;
}
#endif /* not glibc 2.0 */
diff --git a/gcc/config/ia64/unwind-ia64.c b/gcc/config/ia64/unwind-ia64.c
index 302f0d14927..fc7b20701cd 100644
--- a/gcc/config/ia64/unwind-ia64.c
+++ b/gcc/config/ia64/unwind-ia64.c
@@ -1704,6 +1704,13 @@ _Unwind_GetIP (struct _Unwind_Context *context)
return context->rp;
}
+inline _Unwind_Ptr
+_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn)
+{
+ *ip_before_insn = 0;
+ return context->rp;
+}
+
/* Overwrite the return address for CONTEXT with VAL. */
inline void
diff --git a/gcc/config/rs6000/linux-unwind.h b/gcc/config/rs6000/linux-unwind.h
index 6e822bde0e2..d01e6b1fb32 100644
--- a/gcc/config/rs6000/linux-unwind.h
+++ b/gcc/config/rs6000/linux-unwind.h
@@ -1,5 +1,5 @@
/* DWARF2 EH unwinding support for PowerPC and PowerPC64 Linux.
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GCC.
@@ -89,26 +89,6 @@ struct gcc_ucontext
enum { SIGNAL_FRAMESIZE = 128 };
-/* If the current unwind info (FS) does not contain explicit info
- saving R2, then we have to do a minor amount of code reading to
- figure out if it was saved. The big problem here is that the
- code that does the save/restore is generated by the linker, so
- we have no good way to determine at compile time what to do. */
-
-#define MD_FROB_UPDATE_CONTEXT frob_update_context
-
-static void
-frob_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
-{
- if (fs->regs.reg[2].how == REG_UNSAVED)
- {
- unsigned int *insn
- = (unsigned int *) _Unwind_GetGR (context, LINK_REGISTER_REGNUM);
- if (*insn == 0xE8410028)
- _Unwind_SetGRPtr (context, 2, context->cfa + 40);
- }
-}
-
/* If PC is at a sigreturn trampoline, return a pointer to the
regs. Otherwise return NULL. */
@@ -272,6 +252,7 @@ ppc_fallback_frame_state (struct _Unwind_Context *context,
fs->regs.reg[ARG_POINTER_REGNUM].how = REG_SAVED_OFFSET;
fs->regs.reg[ARG_POINTER_REGNUM].loc.offset = (long) &regs->nip - new_cfa;
fs->retaddr_column = ARG_POINTER_REGNUM;
+ fs->signal_frame = 1;
if (hwcap == 0)
{
@@ -322,3 +303,46 @@ ppc_fallback_frame_state (struct _Unwind_Context *context,
return _URC_NO_REASON;
}
+
+#define MD_FROB_UPDATE_CONTEXT frob_update_context
+
+static void
+frob_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
+{
+ const unsigned int *pc = (const unsigned int *) context->ra;
+
+ /* Fix up for 2.6.12 - 2.6.16 Linux kernels that have vDSO, but don't
+ have S flag in it. */
+#ifdef __powerpc64__
+ /* addi r1, r1, 128; li r0, 0x0077; sc (sigreturn) */
+ /* addi r1, r1, 128; li r0, 0x00AC; sc (rt_sigreturn) */
+ if (pc[0] == 0x38210000 + SIGNAL_FRAMESIZE
+ && (pc[1] == 0x38000077 || pc[1] == 0x380000AC)
+ && pc[2] == 0x44000002)
+ context->signal_frame = 1;
+#else
+ /* li r0, 0x7777; sc (sigreturn old) */
+ /* li r0, 0x0077; sc (sigreturn new) */
+ /* li r0, 0x6666; sc (rt_sigreturn old) */
+ /* li r0, 0x00AC; sc (rt_sigreturn new) */
+ if ((pc[0] == 0x38007777 || pc[0] == 0x38000077
+ || pc[0] == 0x38006666 || pc[0] == 0x380000AC)
+ && pc[1] == 0x44000002)
+ context->signal_frame = 1;
+#endif
+
+#ifdef __powerpc64__
+ if (fs->regs.reg[2].how == REG_UNSAVED)
+ {
+ /* If the current unwind info (FS) does not contain explicit info
+ saving R2, then we have to do a minor amount of code reading to
+ figure out if it was saved. The big problem here is that the
+ code that does the save/restore is generated by the linker, so
+ we have no good way to determine at compile time what to do. */
+ unsigned int *insn
+ = (unsigned int *) _Unwind_GetGR (context, LINK_REGISTER_REGNUM);
+ if (*insn == 0xE8410028)
+ _Unwind_SetGRPtr (context, 2, context->cfa + 40);
+ }
+#endif
+}
diff --git a/gcc/config/s390/linux-unwind.h b/gcc/config/s390/linux-unwind.h
index 5f22dfc1bff..d1e9b735edb 100644
--- a/gcc/config/s390/linux-unwind.h
+++ b/gcc/config/s390/linux-unwind.h
@@ -1,5 +1,5 @@
/* DWARF2 EH unwinding support for S/390 Linux.
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GCC.
@@ -113,27 +113,11 @@ s390_fallback_frame_state (struct _Unwind_Context *context,
fs->regs.reg[32].how = REG_SAVED_OFFSET;
fs->regs.reg[32].loc.offset = (long)&regs->psw_addr - new_cfa;
fs->retaddr_column = 32;
-
- /* If we got a SIGSEGV or a SIGBUS, the PSW address points *to*
- the faulting instruction, not after it. This causes the logic
- in unwind-dw2.c that decrements the RA to determine the correct
- CFI region to get confused. To fix that, we *increment* the RA
- here in that case. Note that we cannot modify the RA in place,
- and the frame state wants a *pointer*, not a value; thus we put
- the modified RA value into the unused register 33 slot of FS and
- have the register 32 save address point to that slot.
-
- Unfortunately, for regular signals on old kernels, we don't know
- the signal number. We default to not fiddling with the RA;
- that can fail in rare cases. Upgrade your kernel. */
-
- if (signo && (*signo == 11 || *signo == 7))
- {
- fs->regs.reg[33].loc.exp =
- (unsigned char *)regs->psw_addr + 1;
- fs->regs.reg[32].loc.offset =
- (long)&fs->regs.reg[33].loc.exp - new_cfa;
- }
+ /* SIGILL, SIGFPE and SIGTRAP are delivered with psw_addr
+ after the faulting instruction rather than before it.
+ Don't set FS->signal_frame in that case. */
+ if (!signo || (*signo != 4 && *signo != 5 && *signo != 8))
+ fs->signal_frame = 1;
return _URC_NO_REASON;
}
diff --git a/gcc/libgcc-std.ver b/gcc/libgcc-std.ver
index cb2e7fe40d8..f8e9e52d082 100644
--- a/gcc/libgcc-std.ver
+++ b/gcc/libgcc-std.ver
@@ -272,4 +272,5 @@ GCC_4.2.0 {
__floatuntisf
__floatuntixf
__floatuntitf
+ _Unwind_GetIPInfo
}
diff --git a/gcc/unwind-c.c b/gcc/unwind-c.c
index e3e2eca1804..cf17b6174d2 100644
--- a/gcc/unwind-c.c
+++ b/gcc/unwind-c.c
@@ -127,6 +127,7 @@ PERSONALITY_FUNCTION (int version,
lsda_header_info info;
const unsigned char *language_specific_data, *p, *action_record;
_Unwind_Ptr landing_pad, ip;
+ int ip_before_insn = 0;
#ifdef __ARM_EABI_UNWINDER__
if ((state & _US_ACTION_MASK) != _US_UNWIND_FRAME_STARTING)
@@ -156,7 +157,9 @@ PERSONALITY_FUNCTION (int version,
/* Parse the LSDA header. */
p = parse_lsda_header (context, language_specific_data, &info);
- ip = _Unwind_GetIP (context) - 1;
+ ip = _Unwind_GetIPInfo (context, &ip_before_insn);
+ if (! ip_before_insn)
+ --ip;
landing_pad = 0;
#ifdef __USING_SJLJ_EXCEPTIONS__
diff --git a/gcc/unwind-compat.c b/gcc/unwind-compat.c
index f5316f0b6cb..fa40ab27cba 100644
--- a/gcc/unwind-compat.c
+++ b/gcc/unwind-compat.c
@@ -1,5 +1,5 @@
/* Backward compatibility unwind routines.
- Copyright (C) 2004, 2005
+ Copyright (C) 2004, 2005, 2006
Free Software Foundation, Inc.
This file is part of GCC.
@@ -136,6 +136,13 @@ _Unwind_GetIP (struct _Unwind_Context *context)
}
symver (_Unwind_GetIP, GCC_3.0);
+_Unwind_Ptr
+_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn)
+{
+ *ip_before_insn = 0;
+ return __libunwind_Unwind_GetIP (context);
+}
+
extern void *__libunwind_Unwind_GetLanguageSpecificData
(struct _Unwind_Context *);
diff --git a/gcc/unwind-dw2.c b/gcc/unwind-dw2.c
index 930f02f3799..8707391a86b 100644
--- a/gcc/unwind-dw2.c
+++ b/gcc/unwind-dw2.c
@@ -1,5 +1,5 @@
/* DWARF2 exception handling and frame unwind runtime interface routines.
- Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This file is part of GCC.
@@ -71,6 +71,7 @@ struct _Unwind_Context
void *lsda;
struct dwarf_eh_bases bases;
_Unwind_Word args_size;
+ char signal_frame;
};
/* Byte size of every register managed by these routines. */
@@ -207,6 +208,16 @@ _Unwind_GetIP (struct _Unwind_Context *context)
return (_Unwind_Ptr) context->ra;
}
+/* Retrieve the return address and flag whether that IP is before
+ or after first not yet fully executed instruction. */
+
+inline _Unwind_Ptr
+_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn)
+{
+ *ip_before_insn = context->signal_frame != 0;
+ return (_Unwind_Ptr) context->ra;
+}
+
/* Overwrite the return address for CONTEXT with VAL. */
inline void
@@ -327,6 +338,13 @@ extract_cie_info (const struct dwarf_cie *cie, struct _Unwind_Context *context,
aug += 1;
}
+ /* "S" indicates a signal frame. */
+ else if (aug[0] == 'S')
+ {
+ fs->signal_frame = 1;
+ aug += 1;
+ }
+
/* Otherwise we have an unknown augmentation string.
Bail unless we saw a 'z' prefix. */
else
@@ -761,8 +779,10 @@ execute_cfa_program (const unsigned char *insn_ptr,
a different stack configuration that we are not interested in. We
assume that the call itself is unwind info-neutral; if not, or if
there are delay instructions that adjust the stack, these must be
- reflected at the point immediately before the call insn. */
- while (insn_ptr < insn_end && fs->pc < context->ra)
+ reflected at the point immediately before the call insn.
+ In signal frames, return address is after last completed instruction,
+ so we add 1 to return address to make the comparison <=. */
+ while (insn_ptr < insn_end && fs->pc < context->ra + context->signal_frame)
{
unsigned char insn = *insn_ptr++;
_Unwind_Word reg, utmp;
@@ -974,7 +994,8 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
if (context->ra == 0)
return _URC_END_OF_STACK;
- fde = _Unwind_Find_FDE (context->ra - 1, &context->bases);
+ fde = _Unwind_Find_FDE (context->ra + context->signal_frame - 1,
+ &context->bases);
if (fde == NULL)
{
#ifdef MD_FALLBACK_FRAME_STATE_FOR
@@ -1192,6 +1213,8 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
break;
}
+ context->signal_frame = fs->signal_frame;
+
#ifdef MD_FROB_UPDATE_CONTEXT
MD_FROB_UPDATE_CONTEXT (context, fs);
#endif
diff --git a/gcc/unwind-dw2.h b/gcc/unwind-dw2.h
index e894dd913dc..4851067fdfb 100644
--- a/gcc/unwind-dw2.h
+++ b/gcc/unwind-dw2.h
@@ -83,6 +83,7 @@ typedef struct
unsigned char fde_encoding;
unsigned char lsda_encoding;
unsigned char saw_z;
+ unsigned char signal_frame;
void *eh_ptr;
} _Unwind_FrameState;
diff --git a/gcc/unwind-generic.h b/gcc/unwind-generic.h
index 9c0c7da07ad..3f4c06530ce 100644
--- a/gcc/unwind-generic.h
+++ b/gcc/unwind-generic.h
@@ -1,5 +1,5 @@
/* Exception handling and frame unwind runtime interface routines.
- Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2001, 2003, 2004, 2006 Free Software Foundation, Inc.
This file is part of GCC.
@@ -155,6 +155,7 @@ extern _Unwind_Word _Unwind_GetGR (struct _Unwind_Context *, int);
extern void _Unwind_SetGR (struct _Unwind_Context *, int, _Unwind_Word);
extern _Unwind_Ptr _Unwind_GetIP (struct _Unwind_Context *);
+extern _Unwind_Ptr _Unwind_GetIPInfo (struct _Unwind_Context *, int *);
extern void _Unwind_SetIP (struct _Unwind_Context *, _Unwind_Ptr);
/* @@@ Retrieve the CFA of the given context. */
diff --git a/gcc/unwind-sjlj.c b/gcc/unwind-sjlj.c
index 4c06aa1f894..72c363c7af1 100644
--- a/gcc/unwind-sjlj.c
+++ b/gcc/unwind-sjlj.c
@@ -214,6 +214,13 @@ _Unwind_GetIP (struct _Unwind_Context *context)
return context->fc->call_site + 1;
}
+_Unwind_Ptr
+_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn)
+{
+ *ip_before_insn = 0;
+ return context->fc->call_site + 1;
+}
+
/* Set the return landing pad index in CONTEXT. */
void