From patchwork Thu Feb 16 22:12:45 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 141707 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 7C97DB6FA9 for ; Fri, 17 Feb 2012 09:13:10 +1100 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1330035190; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Received:Message-ID:Date:From:User-Agent:MIME-Version:To:Subject: References:In-Reply-To:Content-Type:Mailing-List:Precedence: List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender: Delivered-To; bh=OJAQQxd17phWepI/oIfQRQDeuhE=; b=xqeJmiLfDYNOY1e ZVBOOLqHSVusIySVGKR1vxJ995prBm0jIvV4fDjXle+aEC4YIWKx3i4HIuDPQ2SH 4MJcY2xqP7ZAWPi02v2HlpqhOP7WttkFMy9DEDSOxWBICpuFWZdI7zWsUazvlHLp Ca7pm2RFLnib19lc3V0kbR/zc9wo= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Received:Received:Message-ID:Date:From:User-Agent:MIME-Version:To:Subject:References:In-Reply-To:Content-Type:X-IsSubscribed:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=DsFRPi5n/ttuTxuEJQ1P1P7Vnz53ykvhn/U6Sg8XcuO+1B/EWxbxQGUeQYlH+4 Ab8gLk8rwnwVnZb7IKIvrfoUGr9sbVu9D/Gq6BV/AuVddU/PgczgbZww8rRSJWaF INX8Wa8GL75pFBxsd7mtGsOdVVDuF739Gw3UDSQszv5y8=; Received: (qmail 15169 invoked by alias); 16 Feb 2012 22:13:06 -0000 Received: (qmail 15157 invoked by uid 22791); 16 Feb 2012 22:13:05 -0000 X-SWARE-Spam-Status: No, hits=-2.2 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, FREEMAIL_ENVFROM_END_DIGIT, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW X-Spam-Check-By: sourceware.org Received: from mail-qw0-f47.google.com (HELO mail-qw0-f47.google.com) (209.85.216.47) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 16 Feb 2012 22:12:48 +0000 Received: by qadz30 with SMTP id z30so217493qad.20 for ; Thu, 16 Feb 2012 14:12:47 -0800 (PST) Received: by 10.229.136.193 with SMTP id s1mr2864562qct.18.1329430367651; Thu, 16 Feb 2012 14:12:47 -0800 (PST) Received: from anchor.twiddle.home ([173.160.232.49]) by mx.google.com with ESMTPS id hk9sm20403947qab.20.2012.02.16.14.12.46 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 16 Feb 2012 14:12:47 -0800 (PST) Message-ID: <4F3D7F5D.1080605@redhat.com> Date: Thu, 16 Feb 2012 14:12:45 -0800 From: Richard Henderson User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20120131 Thunderbird/10.0 MIME-Version: 1.0 To: GCC Patches , rdsandiford@googlemail.com Subject: [RFC 4.8] use ip+cfa to identify unwind frames, if possible References: <878vk327rw.fsf@talisman.home> <4F3C1CDF.4080508@redhat.com> <87sjiar4fx.fsf@talisman.home> <4F3D53ED.1030502@redhat.com> <87ipj6r2yb.fsf@talisman.home> <4F3D5F09.8010405@redhat.com> In-Reply-To: <4F3D5F09.8010405@redhat.com> X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org On 02/16/2012 11:54 AM, Richard Henderson wrote: > I'll work on a proper fix to the unwinder; we can then decide > whether and when to apply it... Something like this. Not the best of solutions, but we've run out of bits in the exception structure, and thus we can't use this solution universally. It shouldn't matter for most CISC targets, like x86, which always push the return address onto the stack; one never winds up with the situation you saw on mips where the return address is held only in a (special) register. r~ diff --git a/gcc/config/alpha/alpha.h b/gcc/config/alpha/alpha.h index 07ffa9f..77e1ee5 100644 --- a/gcc/config/alpha/alpha.h +++ b/gcc/config/alpha/alpha.h @@ -1290,3 +1290,8 @@ do { \ /* The system headers under Alpha systems are generally C++-aware. */ #define NO_IMPLICIT_EXTERN_C + +/* Bits 0 and 1 are always zero in jump targets. */ +#ifdef IN_LIBGCC2 +# define UNWIND_FORCE_UNWIND_MASK 1 +#endif diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index 1c19f8b..59d4560 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -2920,3 +2920,15 @@ extern GTY(()) struct target_globals *mips16_globals; with arguments ARGS. */ #define PMODE_INSN(NAME, ARGS) \ (Pmode == SImode ? NAME ## _si ARGS : NAME ## _di ARGS) + +/* For mips32 mode we have bits 0 and 1 zero free, but for mips16 mode, + bit 0 indicates mips16 mode, and bit 1 is thence meaningful. Thus + the only "free" bits would be at the top of the address space. + Can we trust that we'll never try to unwind in kernel mode? */ +#ifdef IN_LIBGCC2 +# if TARGET_64BIT +# define UNWIND_FORCE_UNWIND_MASK 0x8000000000000000ull +# else +# define UNWIND_FORCE_UNWIND_MASK 0x80000000u +# endif +#endif diff --git a/libgcc/unwind-sjlj.c b/libgcc/unwind-sjlj.c index 1fc1c5d..4b32328 100644 --- a/libgcc/unwind-sjlj.c +++ b/libgcc/unwind-sjlj.c @@ -322,6 +322,9 @@ uw_identify_context (struct _Unwind_Context *context) #define _Unwind_Resume _Unwind_SjLj_Resume #define _Unwind_Resume_or_Rethrow _Unwind_SjLj_Resume_or_Rethrow +/* Always use uw_identify_context to identify frames. */ +#undef UNWIND_FORCE_UNWIND_MASK + #include "unwind.inc" #endif /* USING_SJLJ_EXCEPTIONS */ diff --git a/libgcc/unwind.inc b/libgcc/unwind.inc index 5e2ec29..1374f9d 100644 --- a/libgcc/unwind.inc +++ b/libgcc/unwind.inc @@ -1,5 +1,5 @@ /* Exception handling and frame unwind runtime interface routines. -*- C -*- - Copyright (C) 2001, 2003, 2008, 2009 Free Software Foundation, Inc. + Copyright (C) 2001, 2003, 2008, 2009, 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -27,6 +27,64 @@ This file is included from unwind-dw2.c, unwind-sjlj.c or unwind-ia64.c. */ +/* This is a bit value within a function pointer or function return address + that is never set. E.g. most RISC targets have instructions aligned to + four bytes, meaning bits 0 and 1 are "free" and thus either 1 or 2 would + be appropriate values to use here. + + If non-zero, we will use this bit to distinguish forced unwind from normal + unwind, and in addition use both the IP+CFA to identify the target context + during unwinding. + + If zero, i.e. there is no "free" bit, then we will only be able to use the + CFA to identify the target context during unwinding. The consequence of + this is that we cannot reliably propagate an exception through a sequence + of functions that do not have a stack frame. Normally this is not a + problem, in that most functions that do not have stack frames are leaf + functions, and thus do not throw exceptions. */ + +#include + +#ifndef UNWIND_FORCE_UNWIND_MASK +# define UNWIND_FORCE_UNWIND_MASK 0 +#endif + +static inline bool +is_forced_unwind (struct _Unwind_Exception *exc) +{ + if (UNWIND_FORCE_UNWIND_MASK != 0) + return (exc->private_1 & UNWIND_FORCE_UNWIND_MASK) != 0; + else + return exc->private_1 != 0; +} + +static inline bool +is_handler_match (struct _Unwind_Exception *exc, + struct _Unwind_Context *context) +{ + if (UNWIND_FORCE_UNWIND_MASK != 0) + return (_Unwind_GetIP (context) == exc->private_1 + && _Unwind_GetCFA (context) == exc->private_2); + else + return uw_identify_context (context) == exc->private_2; +} + +static inline void +record_handler_match (struct _Unwind_Exception *exc, + struct _Unwind_Context *context) +{ + if (UNWIND_FORCE_UNWIND_MASK != 0) + { + exc->private_1 = _Unwind_GetIP (context); + exc->private_2 = _Unwind_GetCFA (context); + } + else + { + exc->private_1 = 0; + exc->private_2 = uw_identify_context (context); + } +} + /* Subroutine of _Unwind_RaiseException also invoked from _Unwind_Resume. Unwind the stack calling the personality routine to find both the @@ -48,8 +106,7 @@ _Unwind_RaiseException_Phase2(struct _Unwind_Exception *exc, code = uw_frame_state_for (context, &fs); /* Identify when we've reached the designated handler context. */ - match_handler = (uw_identify_context (context) == exc->private_2 - ? _UA_HANDLER_FRAME : 0); + match_handler = is_handler_match (exc, context) ? _UA_HANDLER_FRAME : 0; if (code != _URC_NO_REASON) /* Some error encountered. Usually the unwinder doesn't @@ -124,8 +181,7 @@ _Unwind_RaiseException(struct _Unwind_Exception *exc) /* Indicate to _Unwind_Resume and associated subroutines that this is not a forced unwind. Further, note where we found a handler. */ - exc->private_1 = 0; - exc->private_2 = uw_identify_context (&cur_context); + record_handler_match (exc, &cur_context); cur_context = this_context; code = _Unwind_RaiseException_Phase2 (exc, &cur_context); @@ -142,7 +198,8 @@ static _Unwind_Reason_Code _Unwind_ForcedUnwind_Phase2 (struct _Unwind_Exception *exc, struct _Unwind_Context *context) { - _Unwind_Stop_Fn stop = (_Unwind_Stop_Fn) (_Unwind_Ptr) exc->private_1; + _Unwind_Stop_Fn stop = (_Unwind_Stop_Fn) + (_Unwind_Ptr) (exc->private_1 & ~UNWIND_FORCE_UNWIND_MASK); void *stop_argument = (void *) (_Unwind_Ptr) exc->private_2; _Unwind_Reason_Code code, stop_code; @@ -201,7 +258,7 @@ _Unwind_ForcedUnwind (struct _Unwind_Exception *exc, uw_init_context (&this_context); cur_context = this_context; - exc->private_1 = (_Unwind_Ptr) stop; + exc->private_1 = (_Unwind_Ptr) stop | UNWIND_FORCE_UNWIND_MASK; exc->private_2 = (_Unwind_Ptr) stop_argument; code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context); @@ -226,10 +283,10 @@ _Unwind_Resume (struct _Unwind_Exception *exc) /* Choose between continuing to process _Unwind_RaiseException or _Unwind_ForcedUnwind. */ - if (exc->private_1 == 0) - code = _Unwind_RaiseException_Phase2 (exc, &cur_context); - else + if (is_forced_unwind (exc)) code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context); + else + code = _Unwind_RaiseException_Phase2 (exc, &cur_context); gcc_assert (code == _URC_INSTALL_CONTEXT); @@ -248,7 +305,7 @@ _Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exc) /* Choose between continuing to process _Unwind_RaiseException or _Unwind_ForcedUnwind. */ - if (exc->private_1 == 0) + if (!is_forced_unwind (exc)) return _Unwind_RaiseException (exc); uw_init_context (&this_context);