mirror of git://gcc.gnu.org/git/gcc.git
reflect, runtime: Let reflect.MakeFunc functions call recover.
From-SVN: r205908
This commit is contained in:
parent
de04d95e64
commit
b1d137cf58
|
|
@ -48,6 +48,15 @@ reflect.makeFuncStub:
|
||||||
leal 8(%ebp), %eax /* Set esp field in struct. */
|
leal 8(%ebp), %eax /* Set esp field in struct. */
|
||||||
movl %eax, -24(%ebp)
|
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__
|
#ifdef __PIC__
|
||||||
call __go_get_closure@PLT
|
call __go_get_closure@PLT
|
||||||
#else
|
#else
|
||||||
|
|
@ -65,6 +74,13 @@ reflect.makeFuncStub:
|
||||||
call reflect.MakeFuncStubGo
|
call reflect.MakeFuncStubGo
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* MakeFunc functions can no longer call recover. */
|
||||||
|
#ifdef __PIC__
|
||||||
|
call __go_makefunc_returning@PLT
|
||||||
|
#else
|
||||||
|
call __go_makefunc_returning
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Set return registers. */
|
/* Set return registers. */
|
||||||
|
|
||||||
movl -20(%ebp), %eax
|
movl -20(%ebp), %eax
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,14 @@ reflect.makeFuncStub:
|
||||||
movdqa %xmm6, 0xa0(%rsp)
|
movdqa %xmm6, 0xa0(%rsp)
|
||||||
movdqa %xmm7, 0xb0(%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.
|
# Get function type.
|
||||||
#ifdef __PIC__
|
#ifdef __PIC__
|
||||||
call __go_get_closure@PLT
|
call __go_get_closure@PLT
|
||||||
|
|
@ -77,6 +85,13 @@ reflect.makeFuncStub:
|
||||||
call reflect.MakeFuncStubGo
|
call reflect.MakeFuncStubGo
|
||||||
#endif
|
#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
|
# The structure will be updated with any return values. Load
|
||||||
# all possible return registers before returning to the caller.
|
# all possible return registers before returning to the caller.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ __go_defer (_Bool *frame, void (*pfn) (void *), void *arg)
|
||||||
n->__pfn = pfn;
|
n->__pfn = pfn;
|
||||||
n->__arg = arg;
|
n->__arg = arg;
|
||||||
n->__retaddr = NULL;
|
n->__retaddr = NULL;
|
||||||
|
n->__makefunc_can_recover = 0;
|
||||||
g->defer = n;
|
g->defer = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,4 +34,10 @@ struct __go_defer_stack
|
||||||
set by __go_set_defer_retaddr which is called by the thunks
|
set by __go_set_defer_retaddr which is called by the thunks
|
||||||
created by defer statements. */
|
created by defer statements. */
|
||||||
const void *__retaddr;
|
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;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,14 @@
|
||||||
__go_can_recover--this is, the thunk. */
|
__go_can_recover--this is, the thunk. */
|
||||||
|
|
||||||
_Bool
|
_Bool
|
||||||
__go_can_recover (const void* retaddr)
|
__go_can_recover (const void *retaddr)
|
||||||
{
|
{
|
||||||
G *g;
|
G *g;
|
||||||
struct __go_defer_stack *d;
|
struct __go_defer_stack *d;
|
||||||
const char* ret;
|
const char* ret;
|
||||||
const char* dret;
|
const char* dret;
|
||||||
|
Location loc;
|
||||||
|
const byte *name;
|
||||||
|
|
||||||
g = runtime_g ();
|
g = runtime_g ();
|
||||||
|
|
||||||
|
|
@ -52,7 +54,73 @@ __go_can_recover (const void* retaddr)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
dret = (const char *) d->__retaddr;
|
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
|
/* This is only called when it is valid for the caller to recover the
|
||||||
|
|
|
||||||
|
|
@ -539,6 +539,7 @@ runtime_main(void* dummy __attribute__((unused)))
|
||||||
d.__arg = (void*)-1;
|
d.__arg = (void*)-1;
|
||||||
d.__panic = g->panic;
|
d.__panic = g->panic;
|
||||||
d.__retaddr = nil;
|
d.__retaddr = nil;
|
||||||
|
d.__makefunc_can_recover = 0;
|
||||||
d.__frame = &frame;
|
d.__frame = &frame;
|
||||||
g->defer = &d;
|
g->defer = &d;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue