Fix an issue with fb_intercept

After my rewrite to use the FunctionnEnter hook to implement
intercept, there was a potential problem.

If an intercept handler was intercepted, and we hadn't yet jitted
the prolog for the intercept handler, and we lost the race to jit it,
and the intercept handler threw an exception, the unwinder could skip
some c++ frames, and fail to unwind a re-entry.

This was caused by attempting to emulate the previous intercept
behavior, where the original function is not included in the backtrace.
I don't think thats necessary; for one thing, the intercept handler
has always appeared in the backtrace, even though its (generally) not the
replacement function, but a function that forwards to the replacement
function. So this diff just leaves the original function's fraem in place.
If the backtraces *do* turn out to be problematic, I'll fix it later in
debugBacktrace.
Esse commit está contido em:
mwilliams
2013-06-02 14:00:23 -07:00
commit de Sara Golemon
commit 99f3924872
2 arquivos alterados com 38 adições e 37 exclusões
+32 -37
Ver Arquivo
@@ -139,45 +139,40 @@ bool EventHook::RunInterceptHandler(ActRec* ar) {
PC savePc = g_vmContext->m_pc;
Offset pcOff;
ActRec* outer = g_vmContext->getPrevVMState(ar, &pcOff);
assert(outer);
g_vmContext->m_fp = outer;
g_vmContext->m_pc = outer->m_func->unit()->at(pcOff);
Variant doneFlag = true;
Variant called_on;
try {
Variant doneFlag = true;
Variant called_on;
if (ar->hasThis()) {
called_on = Variant(ar->getThis());
} else if (ar->hasClass()) {
// For static methods, give handler the name of called class
called_on = Variant(const_cast<StringData*>(ar->getClass()->name()));
}
Array intArgs =
CREATE_VECTOR5(ar->m_func->fullNameRef(),
called_on,
get_frame_args_with_ref(ar),
h->asCArrRef()[1],
ref(doneFlag));
Variant ret = vm_call_user_func(h->asCArrRef()[0], intArgs);
if (doneFlag.toBoolean()) {
frame_free_locals_inl_no_hook<true>(ar, ar->m_func->numLocals());
Stack& stack = g_vmContext->getStack();
stack.top() = (Cell*)(ar + 1);
tvDup(ret.asTypedValue(), stack.allocTV());
return false;
}
g_vmContext->m_fp = ar;
g_vmContext->m_pc = savePc;
} catch (...) {
g_vmContext->m_fp = ar;
g_vmContext->m_pc = savePc;
g_vmContext->m_stack.top() = Stack::frameStackBase(ar);
throw;
if (ar->hasThis()) {
called_on = Variant(ar->getThis());
} else if (ar->hasClass()) {
// For static methods, give handler the name of called class
called_on = Variant(const_cast<StringData*>(ar->getClass()->name()));
}
Array intArgs =
CREATE_VECTOR5(ar->m_func->fullNameRef(),
called_on,
get_frame_args_with_ref(ar),
h->asCArrRef()[1],
ref(doneFlag));
Variant ret = vm_call_user_func(h->asCArrRef()[0], intArgs);
if (doneFlag.toBoolean()) {
Offset pcOff;
ActRec* outer = g_vmContext->getPrevVMState(ar, &pcOff);
assert(outer);
frame_free_locals_inl_no_hook<true>(ar, ar->m_func->numLocals());
Stack& stack = g_vmContext->getStack();
stack.top() = (Cell*)(ar + 1);
tvDup(ret.asTypedValue(), stack.allocTV());
g_vmContext->m_fp = outer;
g_vmContext->m_pc = outer->m_func->unit()->at(pcOff);
return false;
}
g_vmContext->m_fp = ar;
g_vmContext->m_pc = savePc;
return true;
}
@@ -149,7 +149,13 @@ asm(
// fcallHelper, and then push it back from r15 + m_savedRip after
// fcallHelper returns in case it has changed it.
"1: pop 0x8(%r15)\n"
// There is a brief span from enterTCAtProlog until the function
// is entered where rbp is *below* the new actrec, and is missing
// a number of c++ frames. The new actrec is linked onto the c++
// frames, however, so switch it into rbp in case fcallHelper throws.
"xchg %r15,%rbp\n"
"call fcallHelper\n"
"xchg %r15,%rbp\n"
"push 0x8(%r15)\n"
"jmp *%rax\n"
"ud2\n"