2014-07-11 Edward Smith-Rowland <3dw4rd@verizon.net>
[official-gcc.git] / libgo / runtime / go-recover.c
blobceb9b572582d9680d660f7906fdc72e406130eb8
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) < 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, for a
88 function created by reflect.MakeFunc. */
89 if (__builtin_strstr ((const char *) name, "makeFuncImpl") != NULL)
90 return 1;
92 return 0;
95 /* This function is called when code is about to enter a function
96 created by reflect.MakeFunc. It is called by the function stub
97 used by MakeFunc. If the stub is permitted to call recover, then a
98 real MakeFunc function is permitted to call recover. */
100 void
101 __go_makefunc_can_recover (const void *retaddr)
103 struct __go_defer_stack *d;
105 d = runtime_g ()->defer;
106 if (d != NULL
107 && !d->__makefunc_can_recover
108 && __go_can_recover (retaddr))
109 d->__makefunc_can_recover = 1;
112 /* This function is called when code is about to exit a function
113 created by reflect.MakeFunc. It is called by the function stub
114 used by MakeFunc. It clears the __makefunc_can_recover field.
115 It's OK to always clear this field, because __go_can_recover will
116 only be called by a stub created for a function that calls recover.
117 That stub will not call a function created by reflect.MakeFunc, so
118 by the time we get here any caller higher up on the call stack no
119 longer needs the information. */
121 void
122 __go_makefunc_returning (void)
124 struct __go_defer_stack *d;
126 d = runtime_g ()->defer;
127 if (d != NULL)
128 d->__makefunc_can_recover = 0;
131 /* This is only called when it is valid for the caller to recover the
132 value on top of the panic stack, if there is one. */
134 struct __go_empty_interface
135 __go_recover ()
137 G *g;
138 struct __go_panic_stack *p;
140 g = runtime_g ();
142 if (g->panic == NULL || g->panic->__was_recovered)
144 struct __go_empty_interface ret;
146 ret.__type_descriptor = NULL;
147 ret.__object = NULL;
148 return ret;
150 p = g->panic;
151 p->__was_recovered = 1;
152 return p->__arg;