summaryrefslogtreecommitdiff
path: root/libgo
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2013-12-11 23:43:16 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2013-12-11 23:43:16 +0000
commitabec427db99904cf19e9750c9051778d90917eab (patch)
tree958f4d3468ed91fa20d17ed4c61877af6f98a89a /libgo
parent0bc896d704dc2c3e21f45e6b7d817c93a05c8912 (diff)
downloadgcc-abec427db99904cf19e9750c9051778d90917eab.tar.gz
reflect, runtime: Let reflect.MakeFunc functions call recover.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@205908 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo')
-rw-r--r--libgo/go/reflect/makefunc_386.S16
-rw-r--r--libgo/go/reflect/makefunc_amd64.S15
-rw-r--r--libgo/runtime/go-defer.c1
-rw-r--r--libgo/runtime/go-defer.h6
-rw-r--r--libgo/runtime/go-recover.c72
-rw-r--r--libgo/runtime/proc.c1
6 files changed, 109 insertions, 2 deletions
diff --git a/libgo/go/reflect/makefunc_386.S b/libgo/go/reflect/makefunc_386.S
index 3f10cba23b0..d51115bb127 100644
--- a/libgo/go/reflect/makefunc_386.S
+++ b/libgo/go/reflect/makefunc_386.S
@@ -48,6 +48,15 @@ reflect.makeFuncStub:
leal 8(%ebp), %eax /* Set esp field in struct. */
movl %eax, -24(%ebp)
+ /* For MakeFunc functions that call recover. */
+ movl 4(%ebp), %eax
+ movl %eax, (%esp)
+#ifdef __PIC__
+ call __go_makefunc_can_recover@PLT
+#else
+ call __go_makefunc_can_recover
+#endif
+
#ifdef __PIC__
call __go_get_closure@PLT
#else
@@ -65,6 +74,13 @@ reflect.makeFuncStub:
call reflect.MakeFuncStubGo
#endif
+ /* MakeFunc functions can no longer call recover. */
+#ifdef __PIC__
+ call __go_makefunc_returning@PLT
+#else
+ call __go_makefunc_returning
+#endif
+
/* Set return registers. */
movl -20(%ebp), %eax
diff --git a/libgo/go/reflect/makefunc_amd64.S b/libgo/go/reflect/makefunc_amd64.S
index 9d12f193f01..88302eee1b2 100644
--- a/libgo/go/reflect/makefunc_amd64.S
+++ b/libgo/go/reflect/makefunc_amd64.S
@@ -61,6 +61,14 @@ reflect.makeFuncStub:
movdqa %xmm6, 0xa0(%rsp)
movdqa %xmm7, 0xb0(%rsp)
+ /* For MakeFunc functions that call recover. */
+ movq 8(%rbp), %rdi
+#ifdef __PIC__
+ call __go_makefunc_can_recover@PLT
+#else
+ call __go_makefunc_can_recover
+#endif
+
# Get function type.
#ifdef __PIC__
call __go_get_closure@PLT
@@ -77,6 +85,13 @@ reflect.makeFuncStub:
call reflect.MakeFuncStubGo
#endif
+ /* MakeFunc functions can no longer call recover. */
+#ifdef __PIC__
+ call __go_makefunc_returning@PLT
+#else
+ call __go_makefunc_returning
+#endif
+
# The structure will be updated with any return values. Load
# all possible return registers before returning to the caller.
diff --git a/libgo/runtime/go-defer.c b/libgo/runtime/go-defer.c
index 3955e0f5cee..fed8db385ae 100644
--- a/libgo/runtime/go-defer.c
+++ b/libgo/runtime/go-defer.c
@@ -27,6 +27,7 @@ __go_defer (_Bool *frame, void (*pfn) (void *), void *arg)
n->__pfn = pfn;
n->__arg = arg;
n->__retaddr = NULL;
+ n->__makefunc_can_recover = 0;
g->defer = n;
}
diff --git a/libgo/runtime/go-defer.h b/libgo/runtime/go-defer.h
index 0b20e8f6e78..3298ce95059 100644
--- a/libgo/runtime/go-defer.h
+++ b/libgo/runtime/go-defer.h
@@ -34,4 +34,10 @@ struct __go_defer_stack
set by __go_set_defer_retaddr which is called by the thunks
created by defer statements. */
const void *__retaddr;
+
+ /* Set to true if a function created by reflect.MakeFunc is
+ permitted to recover. The return address of such a function
+ function will be somewhere in libffi, so __retaddr is not
+ useful. */
+ _Bool __makefunc_can_recover;
};
diff --git a/libgo/runtime/go-recover.c b/libgo/runtime/go-recover.c
index d6403e00d39..6cef2660ea4 100644
--- a/libgo/runtime/go-recover.c
+++ b/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,73 @@ __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;
+
+ 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
diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c
index 19afee3cd7a..0d0127b6c75 100644
--- a/libgo/runtime/proc.c
+++ b/libgo/runtime/proc.c
@@ -539,6 +539,7 @@ runtime_main(void* dummy __attribute__((unused)))
d.__arg = (void*)-1;
d.__panic = g->panic;
d.__retaddr = nil;
+ d.__makefunc_can_recover = 0;
d.__frame = &frame;
g->defer = &d;