Reuse __unwind_single_frame where appropriate

* exceptions.cc (__unwind_single_frame): Move up in file to be
        accessible from other places.  Move comment to getcontext.
        (stack_info::walk): Call __unwind_single_frame in 64 bit case.  Fix
        preceeding comment.
        (myfault_altstack_handler): Call __unwind_single_frame.
        (getcontext): Give comment from __unwind_single_frame a new home.
        (swapcontext): Fix comment.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2015-07-17 16:29:41 +02:00
parent 1020bb292a
commit b3ccf998cc
2 changed files with 43 additions and 59 deletions

View File

@ -1,3 +1,13 @@
2015-07-17 Corinna Vinschen <corinna@vinschen.de>
* exceptions.cc (__unwind_single_frame): Move up in file to be
accessible from other places. Move comment to getcontext.
(stack_info::walk): Call __unwind_single_frame in 64 bit case. Fix
preceeding comment.
(myfault_altstack_handler): Call __unwind_single_frame.
(getcontext): Give comment from __unwind_single_frame a new home.
(swapcontext): Fix comment.
2015-07-17 Corinna Vinschen <corinna@vinschen.de> 2015-07-17 Corinna Vinschen <corinna@vinschen.de>
* common.din (getcontext): Export. * common.din (getcontext): Export.

View File

@ -280,17 +280,36 @@ stack_info::init (PUINT_PTR framep, bool wantargs, PCONTEXT ctx)
extern "C" void _cygwin_exit_return (); extern "C" void _cygwin_exit_return ();
/* Walk the stack by looking at successive stored 'bp' frames. #ifdef __x86_64__
static inline void
__unwind_single_frame (PCONTEXT ctx)
{
PRUNTIME_FUNCTION f;
ULONG64 imagebase;
UNWIND_HISTORY_TABLE hist;
DWORD64 establisher;
PVOID hdl;
f = RtlLookupFunctionEntry (ctx->Rip, &imagebase, &hist);
if (f)
RtlVirtualUnwind (0, imagebase, ctx->Rip, f, ctx, &hdl, &establisher,
NULL);
else
{
ctx->Rip = *(ULONG_PTR *) ctx->Rsp;
ctx->Rsp += 8;
}
}
#endif
/* Walk the stack.
On 32 bit we're doing this by looking at successive stored 'ebp' frames.
This is not foolproof. */ This is not foolproof. */
int int
stack_info::walk () stack_info::walk ()
{ {
#ifdef __x86_64__ #ifdef __x86_64__
PRUNTIME_FUNCTION f;
ULONG64 imagebase;
DWORD64 establisher;
PVOID hdl;
if (!c.Rip) if (!c.Rip)
return 0; return 0;
@ -306,15 +325,7 @@ stack_info::walk ()
sigstackptr--; sigstackptr--;
return 1; return 1;
} }
__unwind_single_frame (&c);
f = RtlLookupFunctionEntry (c.Rip, &imagebase, &hist);
if (f)
RtlVirtualUnwind (0, imagebase, c.Rip, f, &c, &hdl, &establisher, NULL);
else
{
c.Rip = *(ULONG_PTR *) c.Rsp;
c.Rsp += 8;
}
if (needargs && c.Rip) if (needargs && c.Rip)
{ {
PULONG_PTR p = (PULONG_PTR) c.Rsp; PULONG_PTR p = (PULONG_PTR) c.Rsp;
@ -605,28 +616,13 @@ myfault_altstack_handler (EXCEPTION_POINTERS *exc)
if (me.andreas) if (me.andreas)
{ {
PRUNTIME_FUNCTION f;
ULONG64 imagebase;
UNWIND_HISTORY_TABLE hist;
DWORD64 establisher;
PVOID hdl;
CONTEXT *c = exc->ContextRecord; CONTEXT *c = exc->ContextRecord;
/* Unwind the stack manually and call RtlRestoreContext. This /* Unwind the stack manually and call RtlRestoreContext. This
is necessary because RtlUnwindEx checks the stack for validity, is necessary because RtlUnwindEx checks the stack for validity,
which, as outlined above, fails for the alternate stack. */ which, as outlined above, fails for the alternate stack. */
while (c->Rsp < me.andreas->frame) while (c->Rsp < me.andreas->frame)
{ __unwind_single_frame (c);
f = RtlLookupFunctionEntry (c->Rip, &imagebase, &hist);
if (f)
RtlVirtualUnwind (0, imagebase, c->Rip, f, c, &hdl, &establisher,
NULL);
else
{
c->Rip = *(ULONG_PTR *) c->Rsp;
c->Rsp += 8;
}
}
c->Rip = me.andreas->ret; c->Rip = me.andreas->ret;
RtlRestoreContext (c, NULL); RtlRestoreContext (c, NULL);
} }
@ -1865,33 +1861,6 @@ _cygtls::signal_debugger (siginfo_t& si)
} }
} }
#ifdef __x86_64__
static inline void
__unwind_single_frame (PCONTEXT ctx)
{
/* Amazing, but true: On 32 bit, RtlCaptureContext returns the context
matching the caller of getcontext, so all we have to do is call it.
On 64 bit, RtlCaptureContext returns the exact context of its own
caller, so we have to unwind virtually by a single frame to get the
context of the caller of getcontext. */
PRUNTIME_FUNCTION f;
ULONG64 imagebase;
UNWIND_HISTORY_TABLE hist;
DWORD64 establisher;
PVOID hdl;
f = RtlLookupFunctionEntry (ctx->Rip, &imagebase, &hist);
if (f)
RtlVirtualUnwind (0, imagebase, ctx->Rip, f, ctx, &hdl, &establisher,
NULL);
else
{
ctx->Rip = *(ULONG_PTR *) ctx->Rsp;
ctx->Rsp += 8;
}
}
#endif
extern "C" int extern "C" int
setcontext (const ucontext_t *ucp) setcontext (const ucontext_t *ucp)
{ {
@ -1917,6 +1886,11 @@ getcontext (ucontext_t *ucp)
PCONTEXT ctx = (PCONTEXT) &ucp->uc_mcontext; PCONTEXT ctx = (PCONTEXT) &ucp->uc_mcontext;
ctx->ContextFlags = CONTEXT_FULL; ctx->ContextFlags = CONTEXT_FULL;
RtlCaptureContext (ctx); RtlCaptureContext (ctx);
/* Amazing, but true: On 32 bit, RtlCaptureContext returns the context
matching the caller of getcontext, so all we have to do is call it.
On 64 bit, RtlCaptureContext returns the exact context of its own
caller, so we have to unwind virtually by a single frame to get the
context of the caller of getcontext. */
__unwind_single_frame (ctx); __unwind_single_frame (ctx);
/* Successful getcontext is supposed to return 0. If we don't set rax to 0 /* Successful getcontext is supposed to return 0. If we don't set rax to 0
here, there's a chance that code like this: here, there's a chance that code like this:
@ -1937,8 +1911,8 @@ swapcontext (ucontext_t *oucp, const ucontext_t *ucp)
PCONTEXT ctx = (PCONTEXT) &oucp->uc_mcontext; PCONTEXT ctx = (PCONTEXT) &oucp->uc_mcontext;
ctx->ContextFlags = CONTEXT_FULL; ctx->ContextFlags = CONTEXT_FULL;
RtlCaptureContext (ctx); RtlCaptureContext (ctx);
/* See comments in getcontext. */
__unwind_single_frame (ctx); __unwind_single_frame (ctx);
/* See above. */
oucp->uc_mcontext.rax = 0; oucp->uc_mcontext.rax = 0;
oucp->uc_sigmask = oucp->uc_mcontext.oldmask = _my_tls.sigmask; oucp->uc_sigmask = oucp->uc_mcontext.oldmask = _my_tls.sigmask;
return setcontext (ucp); return setcontext (ucp);