aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.8/libgo/runtime/go-recover.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.8/libgo/runtime/go-recover.c')
-rw-r--r--gcc-4.8/libgo/runtime/go-recover.c77
1 files changed, 75 insertions, 2 deletions
diff --git a/gcc-4.8/libgo/runtime/go-recover.c b/gcc-4.8/libgo/runtime/go-recover.c
index d6403e00d..ceb9b5725 100644
--- a/gcc-4.8/libgo/runtime/go-recover.c
+++ b/gcc-4.8/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,78 @@ __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;
+
+ /* 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;
+
+ 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