diff options
Diffstat (limited to 'gcc-4.8/libgo/runtime/go-recover.c')
-rw-r--r-- | gcc-4.8/libgo/runtime/go-recover.c | 77 |
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 |