ctx.r14 = r14;
ctx.r15 = r15;
- if (mono_debugger_throw_exception ((gpointer)(rip - 8), (gpointer)rsp, exc)) {
+ if (!rethrow && mono_debugger_throw_exception ((gpointer)(rip - 8), (gpointer)rsp, exc)) {
/*
* The debugger wants us to stop on the `throw' instruction.
* By the time we get here, it already inserted a breakpoint on
* eip - 8 (which is the address of the `mov %r15,%rdi ; callq throw').
*/
+
+ /* FIXME FIXME
+ *
+ * In case of a rethrow, the JIT is emitting code like this:
+ *
+ * mov 0xffffffffffffffd0(%rbp),%rax'
+ * mov %rax,%rdi
+ * callq throw
+ *
+ * Here, restore_context() wouldn't restore the %rax register correctly.
+ */
ctx.rip = rip - 8;
ctx.rsp = rsp + 8;
restore_context (&ctx);
if (ji != NULL) {
int offset;
+ gboolean omit_fp = (ji->used_regs & (1 << 31)) > 0;
*new_ctx = *ctx;
* We only need to do this if the exception was raised in managed
* code, since otherwise the lmf was already popped of the stack.
*/
- if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
+ if (*lmf && ((*lmf) != jit_tls->first_lmf) && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->rsp)) {
+ new_ctx->rbp = (*lmf)->ebp;
new_ctx->rbx = (*lmf)->rbx;
+ new_ctx->rsp = (*lmf)->rsp;
new_ctx->r12 = (*lmf)->r12;
new_ctx->r13 = (*lmf)->r13;
new_ctx->r14 = (*lmf)->r14;
}
}
else {
- offset = -1;
+ offset = omit_fp ? 0 : -1;
/* restore caller saved registers */
for (i = 0; i < AMD64_NREG; i ++)
if (AMD64_IS_CALLEE_SAVED_REG (i) && (ji->used_regs & (1 << i))) {
- guint64 reg = *((guint64 *)ctx->SC_EBP + offset);
- offset --;
+ guint64 reg;
+
+ if (omit_fp) {
+ reg = *((guint64*)ctx->rsp + offset);
+ offset ++;
+ }
+ else {
+ reg = *((guint64 *)ctx->SC_EBP + offset);
+ offset --;
+ }
+
switch (i) {
case AMD64_RBX:
new_ctx->rbx = reg;
case AMD64_R15:
new_ctx->r15 = reg;
break;
+ case AMD64_RBP:
+ new_ctx->rbp = reg;
+ break;
default:
g_assert_not_reached ();
}
}
}
- if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
+ if (*lmf && ((*lmf) != jit_tls->first_lmf) && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->rsp)) {
/* remove any unused lmf */
*lmf = (*lmf)->previous_lmf;
}
- /* Pop EBP and the return address */
- new_ctx->SC_ESP = ctx->SC_EBP + (2 * sizeof (gpointer));
- /* we substract 1, so that the IP points into the call instruction */
- new_ctx->SC_EIP = *((guint64 *)ctx->SC_EBP + 1) - 1;
- new_ctx->SC_EBP = *((guint64 *)ctx->SC_EBP);
+ if (omit_fp) {
+ /* Pop frame */
+ new_ctx->rsp += (ji->used_regs >> 16) & (0x7fff);
+ new_ctx->SC_EIP = *((guint64 *)new_ctx->rsp) - 1;
+ /* Pop return address */
+ new_ctx->rsp += 8;
+ }
+ else {
+ /* Pop EBP and the return address */
+ new_ctx->SC_ESP = ctx->SC_EBP + (2 * sizeof (gpointer));
+ /* we substract 1, so that the IP points into the call instruction */
+ new_ctx->SC_EIP = *((guint64 *)ctx->SC_EBP + 1) - 1;
+ new_ctx->SC_EBP = *((guint64 *)ctx->SC_EBP);
+ }
/* Pop arguments off the stack */
{
new_ctx->SC_RIP = (*lmf)->rip;
new_ctx->SC_RBP = (*lmf)->ebp;
+ new_ctx->SC_ESP = (*lmf)->rsp;
new_ctx->SC_RBX = (*lmf)->rbx;
new_ctx->SC_R12 = (*lmf)->r12;
new_ctx->SC_R14 = (*lmf)->r14;
new_ctx->SC_R15 = (*lmf)->r15;
- /* the lmf is always stored on the stack, so the following
- * expression points to a stack location which can be used as ESP */
- new_ctx->SC_ESP = ALIGN_TO ((guint64)&((*lmf)->rip), 16);
-
*lmf = (*lmf)->previous_lmf;
return ji ? ji : res;