2014-07-29 Ed Smith-Rowland <3dw4rd@verizon.net>
[official-gcc.git] / libgo / runtime / go-recover.c
blob2d3db55cbc95878b1d98b6291f46875eee2504d4
1 /* go-recover.c -- support for the go recover function.
3 Copyright 2010 The Go Authors. All rights reserved.
4 Use of this source code is governed by a BSD-style
5 license that can be found in the LICENSE file. */
7 #include "runtime.h"
8 #include "interface.h"
9 #include "go-panic.h"
10 #include "go-defer.h"
12 /* This is called by a thunk to see if the real function should be
13 permitted to recover a panic value. Recovering a value is
14 permitted if the thunk was called directly by defer. RETADDR is
15 the return address of the function which is calling
16 __go_can_recover--this is, the thunk. */
18 _Bool
19 __go_can_recover (const void *retaddr)
21 G *g;
22 struct __go_defer_stack *d;
23 const char* ret;
24 const char* dret;
25 Location loc;
26 const byte *name;
28 g = runtime_g ();
30 d = g->defer;
31 if (d == NULL)
32 return 0;
34 /* The panic which this function would recover is the one on the top
35 of the panic stack. We do not want to recover it if that panic
36 was on the top of the panic stack when this function was
37 deferred. */
38 if (d->__panic == g->panic)
39 return 0;
41 /* D->__RETADDR is the address of a label immediately following the
42 call to the thunk. We can recover a panic if that is the same as
43 the return address of the thunk. We permit a bit of slack in
44 case there is any code between the function return and the label,
45 such as an instruction to adjust the stack pointer. */
47 ret = (const char *) retaddr;
49 #ifdef __sparc__
50 /* On SPARC the address we get, from __builtin_return_address, is
51 the address of the call instruction. Adjust forward, also
52 skipping the delayed instruction following the call. */
53 ret += 8;
54 #endif
56 dret = (const char *) d->__retaddr;
57 if (ret <= dret && ret + 16 >= dret)
58 return 1;
60 /* If the function calling recover was created by reflect.MakeFunc,
61 then RETADDR will be somewhere in libffi. Our caller is
62 permitted to recover if it was called from libffi. */
63 if (!d->__makefunc_can_recover)
64 return 0;
66 if (runtime_callers (2, &loc, 1, false) < 1)
67 return 0;
69 /* If we have no function name, then we weren't called by Go code.
70 Guess that we were called by libffi. */
71 if (loc.function.len == 0)
72 return 1;
74 if (loc.function.len < 4)
75 return 0;
76 name = loc.function.str;
77 if (*name == '_')
79 if (loc.function.len < 5)
80 return 0;
81 ++name;
84 if (name[0] == 'f' && name[1] == 'f' && name[2] == 'i' && name[3] == '_')
85 return 1;
87 /* We may also be called by reflect.makeFuncImpl.call or
88 reflect.ffiCall, for a function created by reflect.MakeFunc. */
89 if (__builtin_strstr ((const char *) name, "makeFuncImpl") != NULL
90 || __builtin_strcmp ((const char *) name, "reflect.ffiCall") == 0)
91 return 1;
93 return 0;
96 /* This function is called when code is about to enter a function
97 created by reflect.MakeFunc. It is called by the function stub
98 used by MakeFunc. If the stub is permitted to call recover, then a
99 real MakeFunc function is permitted to call recover. */
101 void
102 __go_makefunc_can_recover (const void *retaddr)
104 struct __go_defer_stack *d;
106 d = runtime_g ()->defer;
107 if (d != NULL
108 && !d->__makefunc_can_recover
109 && __go_can_recover (retaddr))
110 d->__makefunc_can_recover = 1;
113 /* This function is called when code is about to exit a function
114 created by reflect.MakeFunc. It is called by the function stub
115 used by MakeFunc. It clears the __makefunc_can_recover field.
116 It's OK to always clear this field, because __go_can_recover will
117 only be called by a stub created for a function that calls recover.
118 That stub will not call a function created by reflect.MakeFunc, so
119 by the time we get here any caller higher up on the call stack no
120 longer needs the information. */
122 void
123 __go_makefunc_returning (void)
125 struct __go_defer_stack *d;
127 d = runtime_g ()->defer;
128 if (d != NULL)
129 d->__makefunc_can_recover = 0;
132 /* This is only called when it is valid for the caller to recover the
133 value on top of the panic stack, if there is one. */
135 struct __go_empty_interface
136 __go_recover ()
138 G *g;
139 struct __go_panic_stack *p;
141 g = runtime_g ();
143 if (g->panic == NULL || g->panic->__was_recovered)
145 struct __go_empty_interface ret;
147 ret.__type_descriptor = NULL;
148 ret.__object = NULL;
149 return ret;
151 p = g->panic;
152 p->__was_recovered = 1;
153 return p->__arg;