From patchwork Tue Jan 6 15:46:45 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Lynn A. Boger" X-Patchwork-Id: 425709 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]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 992151400DE for ; Wed, 7 Jan 2015 02:47:03 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:subject:content-type; q= dns; s=default; b=UAWCG1KMyhXpzwA2hF3AQjGZ/T5FYUDb5Tj09wgXHi3S8S PKEAM5Aswl1gV+hU92tKybrOb/3rXi0OPdwUSNL/p3tY6708ekgYyQ3KX9KZyleO Pj4945E/MeFr7hNsG3Mn8zjfbY7XGKW+X+U0yBRjVkb8lfYlV57sWYBj6uY7k= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:subject:content-type; s= default; bh=8hSrEXIuZhKMfqmpVHsIy0VYrFg=; b=uDdZNvNBlvFufSEDdEbt NcsoIbDuQkfOwLrYDKNwIGu09yKhci4lMgLfcyitIk3CVTmKpHP82dIzs+udHH8O cPNp+7tdtvNIUUSgpZGBYGK+YtOR+Tb/PVPV+FTir61Q3k9hTT1w/RwCLW4wqGJW Tuc9eVqYEKp8ba23mm5kmLc= Received: (qmail 29456 invoked by alias); 6 Jan 2015 15:46:56 -0000 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 Received: (qmail 29445 invoked by uid 89); 6 Jan 2015 15:46:55 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=AWL, BAYES_00, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: e39.co.us.ibm.com Received: from e39.co.us.ibm.com (HELO e39.co.us.ibm.com) (32.97.110.160) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Tue, 06 Jan 2015 15:46:52 +0000 Received: from /spool/local by e39.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 6 Jan 2015 08:46:50 -0700 Received: from d01dlp01.pok.ibm.com (9.56.250.166) by e39.co.us.ibm.com (192.168.1.139) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Tue, 6 Jan 2015 08:46:48 -0700 Received: from b01cxnp22034.gho.pok.ibm.com (b01cxnp22034.gho.pok.ibm.com [9.57.198.24]) by d01dlp01.pok.ibm.com (Postfix) with ESMTP id 7B1A638C8054 for ; Tue, 6 Jan 2015 10:46:46 -0500 (EST) Received: from d01av03.pok.ibm.com (d01av03.pok.ibm.com [9.56.224.217]) by b01cxnp22034.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id t06FkjEH29032458 for ; Tue, 6 Jan 2015 15:46:45 GMT Received: from d01av03.pok.ibm.com (localhost [127.0.0.1]) by d01av03.pok.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id t06Fkjco031375 for ; Tue, 6 Jan 2015 10:46:45 -0500 Received: from oc2602623110.ibm.com (oc2602623110.ibm.com.rchland.ibm.com [9.10.86.28]) by d01av03.pok.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id t06FkjFF031354; Tue, 6 Jan 2015 10:46:45 -0500 Message-ID: <54AC0365.1030402@linux.vnet.ibm.com> Date: Tue, 06 Jan 2015 09:46:45 -0600 From: "Lynn A. Boger" User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.3.0 MIME-Version: 1.0 To: gcc-patches , "gofrontend-dev@googlegroups.com" Subject: [PATCH 2/2, libgo] Backport recover fix for gccgo to gcc 4.9 X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 15010615-0033-0000-0000-000003391F20 X-IsSubscribed: yes This is a backport to gcc 4.9 of the following change: https://gcc.gnu.org/ml/gcc-patches/2014-10/msg00660.html. The original patch had changes required for use with the FFI reflection support. Since FFI is not used for reflection in gcc 4.9 those changes were omitted. 2015-01-06 Lynn Boger * libgo/runtime/go-defer.c * libgo/runtime/go-panic.h * libgo/go-recover.c Thanks Index: libgo/runtime/go-defer.c =================================================================== --- libgo/runtime/go-defer.c (revision 218817) +++ libgo/runtime/go-defer.c (working copy) @@ -82,6 +82,6 @@ __go_set_defer_retaddr (void *retaddr) g = runtime_g (); if (g->defer != NULL) - g->defer->__retaddr = retaddr; + g->defer->__retaddr = __builtin_extract_return_addr (retaddr); return 0; } Index: libgo/runtime/go-panic.h =================================================================== --- libgo/runtime/go-panic.h (revision 218817) +++ libgo/runtime/go-panic.h (working copy) @@ -38,6 +38,12 @@ extern void __go_print_string (struct String); extern struct __go_empty_interface __go_recover (void); +extern _Bool __go_can_recover (void *); + +extern void __go_makefunc_can_recover (void *retaddr); + +extern void __go_makefunc_returning (void); + extern void __go_unwind_stack (void); #endif /* !defined(LIBGO_GO_PANIC_H) */ Index: libgo/runtime/go-recover.c =================================================================== --- libgo/runtime/go-recover.c (revision 218817) +++ libgo/runtime/go-recover.c (working copy) @@ -9,6 +9,36 @@ #include "go-panic.h" #include "go-defer.h" +/* If the top of the defer stack can be recovered, then return it. + Otherwise return NULL. */ + +static struct __go_defer_stack * +current_defer () +{ + G *g; + struct __go_defer_stack *d; + + g = runtime_g (); + + d = g->defer; + if (d == NULL) + return NULL; + + /* The panic which would be recovered is the one on the top of the + panic stack. We do not want to recover it if that panic was on + the top of the panic stack when this function was deferred. */ + if (d->__panic == g->panic) + return NULL; + + /* The deferred thunk will call _go_set_defer_retaddr. If this has + not happened, then we have not been called via defer, and we can + not recover. */ + if (d->__retaddr == NULL) + return NULL; + + return d; +} + /* This is called by a thunk to see if the real function should be permitted to recover a panic value. Recovering a value is permitted if the thunk was called directly by defer. RETADDR is @@ -16,79 +46,127 @@ __go_can_recover--this is, the thunk. */ _Bool -__go_can_recover (const void *retaddr) +__go_can_recover (void *retaddr) { - G *g; struct __go_defer_stack *d; const char* ret; const char* dret; - Location loc; + Location locs[16]; const byte *name; + intgo len; + int n; + int i; + _Bool found_ffi_callback; - g = runtime_g (); - - d = g->defer; + d = current_defer (); if (d == NULL) return 0; - /* The panic which this function would recover is the one on the top - of the panic stack. We do not want to recover it if that panic - was on the top of the panic stack when this function was - deferred. */ - if (d->__panic == g->panic) - return 0; + ret = (const char *) __builtin_extract_return_addr (retaddr); - /* D->__RETADDR is the address of a label immediately following the - call to the thunk. We can recover a panic if that is the same as - the return address of the thunk. We permit a bit of slack in - case there is any code between the function return and the label, - such as an instruction to adjust the stack pointer. */ - - ret = (const char *) retaddr; - -#ifdef __sparc__ - /* On SPARC the address we get, from __builtin_return_address, is - the address of the call instruction. Adjust forward, also - skipping the delayed instruction following the call. */ - ret += 8; -#endif - dret = (const char *) d->__retaddr; if (ret <= dret && ret + 16 >= dret) return 1; - /* If the function calling recover was created by reflect.MakeFunc, - then RETADDR will be somewhere in libffi. Our caller is - permitted to recover if it was called from libffi. */ - if (!d->__makefunc_can_recover) - return 0; + /* On some systems, in some cases, the return address does not work + reliably. See http://gcc.gnu.org/PR60406. If we are permitted + to call recover, the call stack will look like this: + __go_panic, __go_undefer, etc. + thunk to call deferred function (calls __go_set_defer_retaddr) + function that calls __go_can_recover (passing return address) + __go_can_recover + Calling runtime_callers will skip the thunks. So if our caller's + caller starts with __go, then we are permitted to call + recover. */ - if (runtime_callers (2, &loc, 1) < 1) + if (runtime_callers (1, &locs[0], 2) < 2) return 0; - /* If we have no function name, then we weren't called by Go code. - Guess that we were called by libffi. */ - if (loc.function.len == 0) + name = locs[1].function.str; + len = locs[1].function.len; + + /* Although locs[1].function is a Go string, we know it is + NUL-terminated. */ + if (len > 4 + && __builtin_strchr ((const char *) name, '.') == NULL + && __builtin_strncmp ((const char *) name, "__go_", 4) == 0) return 1; - if (loc.function.len < 4) - return 0; - name = loc.function.str; - if (*name == '_') + /* If we are called from __go_makefunc_can_recover, then we need to + look one level higher. */ + if (locs[0].function.len > 0 + && __builtin_strcmp ((const char *) locs[0].function.str, + "__go_makefunc_can_recover") == 0) { - if (loc.function.len < 5) + if (runtime_callers (3, &locs[0], 1) < 1) return 0; - ++name; + name = locs[0].function.str; + len = locs[0].function.len; + if (len > 4 + && __builtin_strchr ((const char *) name, '.') == NULL + && __builtin_strncmp ((const char *) name, "__go_", 4) == 0) + return 1; } - if (name[0] == 'f' && name[1] == 'f' && name[2] == 'i' && name[3] == '_') - return 1; + /* If the function calling recover was created by reflect.MakeFunc, + then __go_makefunc_can_recover or __go_makefunc_ffi_can_recover + will have set the __makefunc_can_recover field. */ + if (!d->__makefunc_can_recover) + return 0; - /* We may also be called by reflect.makeFuncImpl.call, for a - function created by reflect.MakeFunc. */ - if (__builtin_strstr ((const char *) name, "makeFuncImpl") != NULL) - return 1; + /* We look up the stack, ignoring libffi functions and functions in + the reflect package, until we find reflect.makeFuncStub or + reflect.ffi_callback called by FFI functions. Then we check the + caller of that function. */ + n = runtime_callers (2, &locs[0], sizeof locs / sizeof locs[0]); + found_ffi_callback = 0; + for (i = 0; i < n; i++) + { + const byte *name; + + if (locs[i].function.len == 0) + { + /* No function name means this caller isn't Go code. Assume + that this is libffi. */ + continue; + } + + /* Ignore functions in libffi. */ + name = locs[i].function.str; + if (__builtin_strncmp ((const char *) name, "ffi_", 4) == 0) + continue; + + if (found_ffi_callback) + break; + + if (__builtin_strcmp ((const char *) name, "reflect.ffi_callback") == 0) + { + found_ffi_callback = 1; + continue; + } + + if (__builtin_strcmp ((const char *) name, "reflect.makeFuncStub") == 0) + { + i++; + break; + } + + /* Ignore other functions in the reflect package. */ + if (__builtin_strncmp ((const char *) name, "reflect.", 8) == 0) + continue; + + /* We should now be looking at the real caller. */ + break; + } + + if (i < n && locs[i].function.len > 0) + { + name = locs[i].function.str; + if (__builtin_strncmp ((const char *) name, "__go_", 4) == 0) + return 1; + } + return 0; } @@ -98,14 +176,20 @@ _Bool real MakeFunc function is permitted to call recover. */ void -__go_makefunc_can_recover (const void *retaddr) +__go_makefunc_can_recover (void *retaddr) { struct __go_defer_stack *d; - d = runtime_g ()->defer; - if (d != NULL - && !d->__makefunc_can_recover - && __go_can_recover (retaddr)) + d = current_defer (); + if (d == NULL) + return; + + /* If we are already in a call stack of MakeFunc functions, there is + nothing we can usefully check here. */ + if (d->__makefunc_can_recover) + return; + + if (__go_can_recover (retaddr)) d->__makefunc_can_recover = 1; }