From: ian Date: Wed, 11 Dec 2013 23:43:16 +0000 (+0000) Subject: reflect, runtime: Let reflect.MakeFunc functions call recover. X-Git-Tag: upstream/4.9.2~2309 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=abec427db99904cf19e9750c9051778d90917eab;p=platform%2Fupstream%2Flinaro-gcc.git reflect, runtime: Let reflect.MakeFunc functions call recover. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@205908 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/libgo/go/reflect/makefunc_386.S b/libgo/go/reflect/makefunc_386.S index 3f10cba..d51115b 100644 --- a/libgo/go/reflect/makefunc_386.S +++ b/libgo/go/reflect/makefunc_386.S @@ -48,6 +48,15 @@ reflect.makeFuncStub: leal 8(%ebp), %eax /* Set esp field in struct. */ movl %eax, -24(%ebp) + /* For MakeFunc functions that call recover. */ + movl 4(%ebp), %eax + movl %eax, (%esp) +#ifdef __PIC__ + call __go_makefunc_can_recover@PLT +#else + call __go_makefunc_can_recover +#endif + #ifdef __PIC__ call __go_get_closure@PLT #else @@ -65,6 +74,13 @@ reflect.makeFuncStub: call reflect.MakeFuncStubGo #endif + /* MakeFunc functions can no longer call recover. */ +#ifdef __PIC__ + call __go_makefunc_returning@PLT +#else + call __go_makefunc_returning +#endif + /* Set return registers. */ movl -20(%ebp), %eax diff --git a/libgo/go/reflect/makefunc_amd64.S b/libgo/go/reflect/makefunc_amd64.S index 9d12f19..88302ee 100644 --- a/libgo/go/reflect/makefunc_amd64.S +++ b/libgo/go/reflect/makefunc_amd64.S @@ -61,6 +61,14 @@ reflect.makeFuncStub: movdqa %xmm6, 0xa0(%rsp) movdqa %xmm7, 0xb0(%rsp) + /* For MakeFunc functions that call recover. */ + movq 8(%rbp), %rdi +#ifdef __PIC__ + call __go_makefunc_can_recover@PLT +#else + call __go_makefunc_can_recover +#endif + # Get function type. #ifdef __PIC__ call __go_get_closure@PLT @@ -77,6 +85,13 @@ reflect.makeFuncStub: call reflect.MakeFuncStubGo #endif + /* MakeFunc functions can no longer call recover. */ +#ifdef __PIC__ + call __go_makefunc_returning@PLT +#else + call __go_makefunc_returning +#endif + # The structure will be updated with any return values. Load # all possible return registers before returning to the caller. diff --git a/libgo/runtime/go-defer.c b/libgo/runtime/go-defer.c index 3955e0f..fed8db3 100644 --- a/libgo/runtime/go-defer.c +++ b/libgo/runtime/go-defer.c @@ -27,6 +27,7 @@ __go_defer (_Bool *frame, void (*pfn) (void *), void *arg) n->__pfn = pfn; n->__arg = arg; n->__retaddr = NULL; + n->__makefunc_can_recover = 0; g->defer = n; } diff --git a/libgo/runtime/go-defer.h b/libgo/runtime/go-defer.h index 0b20e8f..3298ce9 100644 --- a/libgo/runtime/go-defer.h +++ b/libgo/runtime/go-defer.h @@ -34,4 +34,10 @@ struct __go_defer_stack set by __go_set_defer_retaddr which is called by the thunks created by defer statements. */ const void *__retaddr; + + /* Set to true if a function created by reflect.MakeFunc is + permitted to recover. The return address of such a function + function will be somewhere in libffi, so __retaddr is not + useful. */ + _Bool __makefunc_can_recover; }; diff --git a/libgo/runtime/go-recover.c b/libgo/runtime/go-recover.c index d6403e0..6cef266 100644 --- a/libgo/runtime/go-recover.c +++ b/libgo/runtime/go-recover.c @@ -16,12 +16,14 @@ __go_can_recover--this is, the thunk. */ _Bool -__go_can_recover (const void* retaddr) +__go_can_recover (const void *retaddr) { G *g; struct __go_defer_stack *d; const char* ret; const char* dret; + Location loc; + const byte *name; g = runtime_g (); @@ -52,7 +54,73 @@ __go_can_recover (const void* retaddr) #endif dret = (const char *) d->__retaddr; - return ret <= dret && ret + 16 >= dret; + 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; + + if (runtime_callers (2, &loc, 1) < 1) + 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) + return 1; + + if (loc.function.len < 4) + return 0; + name = loc.function.str; + if (*name == '_') + { + if (loc.function.len < 5) + return 0; + ++name; + } + + if (name[0] == 'f' && name[1] == 'f' && name[2] == 'i' && name[3] == '_') + return 1; + + return 0; +} + +/* This function is called when code is about to enter a function + created by reflect.MakeFunc. It is called by the function stub + used by MakeFunc. If the stub is permitted to call recover, then a + real MakeFunc function is permitted to call recover. */ + +void +__go_makefunc_can_recover (const void *retaddr) +{ + struct __go_defer_stack *d; + + d = runtime_g ()->defer; + if (d != NULL + && !d->__makefunc_can_recover + && __go_can_recover (retaddr)) + d->__makefunc_can_recover = 1; +} + +/* This function is called when code is about to exit a function + created by reflect.MakeFunc. It is called by the function stub + used by MakeFunc. It clears the __makefunc_can_recover field. + It's OK to always clear this field, because __go_can_recover will + only be called by a stub created for a function that calls recover. + That stub will not call a function created by reflect.MakeFunc, so + by the time we get here any caller higher up on the call stack no + longer needs the information. */ + +void +__go_makefunc_returning (void) +{ + struct __go_defer_stack *d; + + d = runtime_g ()->defer; + if (d != NULL) + d->__makefunc_can_recover = 0; } /* This is only called when it is valid for the caller to recover the diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c index 19afee3..0d0127b 100644 --- a/libgo/runtime/proc.c +++ b/libgo/runtime/proc.c @@ -539,6 +539,7 @@ runtime_main(void* dummy __attribute__((unused))) d.__arg = (void*)-1; d.__panic = g->panic; d.__retaddr = nil; + d.__makefunc_can_recover = 0; d.__frame = &frame; g->defer = &d;