| /* go-recover.c -- support for the go recover function. |
| |
| Copyright 2010 The Go Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style |
| license that can be found in the LICENSE file. */ |
| |
| #include "runtime.h" |
| #include "interface.h" |
| #include "go-panic.h" |
| #include "go-defer.h" |
| |
| /* 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 |
| the return address of the function which is calling |
| __go_can_recover--this is, the thunk. */ |
| |
| _Bool |
| __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 (); |
| |
| d = g->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; |
| |
| /* 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; |
| |
| 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 |
| value on top of the panic stack, if there is one. */ |
| |
| struct __go_empty_interface |
| __go_recover () |
| { |
| G *g; |
| struct __go_panic_stack *p; |
| |
| g = runtime_g (); |
| |
| if (g->panic == NULL || g->panic->__was_recovered) |
| { |
| struct __go_empty_interface ret; |
| |
| ret.__type_descriptor = NULL; |
| ret.__object = NULL; |
| return ret; |
| } |
| p = g->panic; |
| p->__was_recovered = 1; |
| return p->__arg; |
| } |