/*
- * exception.c: exception support
+ * exceptions-x86.c: exception support for x86
*
* Authors:
* Dietmar Maurer (dietmar@ximian.com)
static LPTOP_LEVEL_EXCEPTION_FILTER old_handler;
-#define W32_SEH_COPY_CONTEXT \
- sctx->eax = ctx->Eax;\
- sctx->ebx = ctx->Ebx;\
- sctx->ecx = ctx->Ecx;\
- sctx->edx = ctx->Edx;\
- sctx->ebp = ctx->Ebp;\
- sctx->esp = ctx->Esp;\
- sctx->esi = ctx->Esi;\
- sctx->edi = ctx->Edi;\
- sctx->eip = ctx->Eip;
-
#define W32_SEH_HANDLE_EX(_ex) \
if (_ex##_handler) _ex##_handler((int)sctx)
struct sigcontext* sctx;
LONG res;
- res = EXCEPTION_CONTINUE_SEARCH;
+ res = EXCEPTION_CONTINUE_EXECUTION;
er = ep->ExceptionRecord;
ctx = ep->ContextRecord;
sctx = g_malloc(sizeof(struct sigcontext));
- W32_SEH_COPY_CONTEXT
+
+ /* Copy Win32 context to UNIX style context */
+ sctx->eax = ctx->Eax;
+ sctx->ebx = ctx->Ebx;
+ sctx->ecx = ctx->Ecx;
+ sctx->edx = ctx->Edx;
+ sctx->ebp = ctx->Ebp;
+ sctx->esp = ctx->Esp;
+ sctx->esi = ctx->Esi;
+ sctx->edi = ctx->Edi;
+ sctx->eip = ctx->Eip;
switch (er->ExceptionCode) {
case EXCEPTION_ACCESS_VIOLATION:
break;
}
+ /* Copy context back */
+ ctx->Eax = sctx->eax;
+ ctx->Ebx = sctx->ebx;
+ ctx->Ecx = sctx->ecx;
+ ctx->Edx = sctx->edx;
+ ctx->Ebp = sctx->ebp;
+ ctx->Esp = sctx->esp;
+ ctx->Esi = sctx->esi;
+ ctx->Edi = sctx->edi;
+ ctx->Eip = sctx->eip;
+
return res;
}
/* offset 10 is just a guess, but it works for all methods tested */
if ((res = frame_state_for ((char *)addr + 10, &state_in))) {
- if (res->saved [X86_EBX] != 1 ||
- res->saved [X86_EDI] != 1 ||
- res->saved [X86_EBP] != 1 ||
- res->saved [X86_ESI] != 1) {
- return FALSE;
- }
- return TRUE;
- } else {
- return FALSE;
+ if (res->saved [X86_EBX] == 1 &&
+ res->saved [X86_EDI] == 1 &&
+ res->saved [X86_EBP] == 1 &&
+ res->saved [X86_ESI] == 1)
+ return TRUE;
}
+
+ return FALSE;
}
struct stack_frame
return start;
inited = 1;
- /* call_filter (struct sigcontext *ctx, unsigned long eip, gpointer exc) */
+ /* call_filter (struct sigcontext *ctx, unsigned long eip) */
code = start;
x86_push_reg (code, X86_EBP);
x86_mov_reg_membase (code, X86_ECX, X86_EBP, 12, 4);
/* save EBP */
x86_push_reg (code, X86_EBP);
- /* push exc */
- x86_push_membase (code, X86_EBP, 16);
+
/* set new EBP */
x86_mov_reg_membase (code, X86_EBP, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EBP), 4);
/* restore registers used by global register allocation (EBX & ESI) */
/* call the handler */
x86_call_reg (code, X86_ECX);
- x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
/* restore EBP */
x86_pop_reg (code, X86_EBP);
/* adjust eip so that it point into the call instruction */
eip -= 1;
- ctx.SC_ESP = esp;
+ /* Pop argument and return address */
+ ctx.SC_ESP = esp + (2 * sizeof (gpointer));
ctx.SC_EIP = eip;
ctx.SC_EBP = ebp;
ctx.SC_EDI = edi;
*new_ctx = *ctx;
- if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
- /* remove any unused lmf */
- *lmf = (*lmf)->previous_lmf;
- }
-
address = (char *)ip - (char *)ji->code_start;
if (native_offset)
g_free (source_location);
g_free (tmpaddr);
}
-
- offset = -1;
- /* restore caller saved registers */
- if (ji->used_regs & X86_EBX_MASK) {
- new_ctx->SC_EBX = *((int *)ctx->SC_EBP + offset);
- offset--;
+
+ /*
+ * Some managed methods like pinvoke wrappers might have save_lmf set.
+ * In this case, register save/restore code is not generated by the
+ * JIT, so we have to restore callee saved registers from the lmf.
+ */
+ if (ji->method->save_lmf) {
+ /*
+ * 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)) {
+ new_ctx->SC_ESI = (*lmf)->esi;
+ new_ctx->SC_EDI = (*lmf)->edi;
+ new_ctx->SC_EBX = (*lmf)->ebx;
+ }
}
- if (ji->used_regs & X86_EDI_MASK) {
- new_ctx->SC_EDI = *((int *)ctx->SC_EBP + offset);
- offset--;
+ else {
+ offset = -1;
+ /* restore caller saved registers */
+ if (ji->used_regs & X86_EBX_MASK) {
+ new_ctx->SC_EBX = *((int *)ctx->SC_EBP + offset);
+ offset--;
+ }
+ if (ji->used_regs & X86_EDI_MASK) {
+ new_ctx->SC_EDI = *((int *)ctx->SC_EBP + offset);
+ offset--;
+ }
+ if (ji->used_regs & X86_ESI_MASK) {
+ new_ctx->SC_ESI = *((int *)ctx->SC_EBP + offset);
+ }
}
- if (ji->used_regs & X86_ESI_MASK) {
- new_ctx->SC_ESI = *((int *)ctx->SC_EBP + offset);
+
+ if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
+ /* remove any unused lmf */
+ *lmf = (*lmf)->previous_lmf;
}
- new_ctx->SC_ESP = ctx->SC_EBP;
+ /* 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 = *((int *)ctx->SC_EBP + 1) - 1;
new_ctx->SC_EBP = *((int *)ctx->SC_EBP);
{
MonoDomain *domain = mono_domain_get ();
MonoJitInfo *ji, rji;
- static int (*call_filter) (MonoContext *, gpointer, gpointer) = NULL;
+ static int (*call_filter) (MonoContext *, gpointer) = NULL;
MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
MonoLMF *lmf = jit_tls->lmf;
GList *trace_ips = NULL;
+ MonoException *mono_ex;
g_assert (ctx != NULL);
if (!obj) {
obj = (MonoObject *)ex;
}
- g_assert (mono_object_isinst (obj, mono_defaults.exception_class));
+ if (mono_object_isinst (obj, mono_defaults.exception_class)) {
+ mono_ex = (MonoException*)obj;
+ mono_ex->stack_trace = NULL;
+ } else {
+ mono_ex = NULL;
+ }
if (!call_filter)
call_filter = arch_get_call_filter ();
if (!test_only) {
MonoContext ctx_cp = *ctx;
- if (mono_jit_trace_calls)
+ if (mono_jit_trace_calls != NULL)
g_print ("EXCEPTION handling: %s\n", mono_object_class (obj)->name);
if (!mono_arch_handle_exception (&ctx_cp, obj, TRUE)) {
if (mono_break_on_exc)
if (ji != (gpointer)-1) {
- if (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
+ if (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
char *tmp, *strace;
trace_ips = g_list_append (trace_ips, MONO_CONTEXT_GET_IP (ctx));
- if (!((MonoException*)obj)->stack_trace)
+ if (!mono_ex->stack_trace)
strace = g_strdup ("");
else
- strace = mono_string_to_utf8 (((MonoException*)obj)->stack_trace);
+ strace = mono_string_to_utf8 (mono_ex->stack_trace);
tmp = g_strdup_printf ("%s%s\n", strace, trace);
g_free (strace);
- ((MonoException*)obj)->stack_trace = mono_string_new (domain, tmp);
+ mono_ex->stack_trace = mono_string_new (domain, tmp);
g_free (tmp);
}
if (ei->try_start <= MONO_CONTEXT_GET_IP (ctx) &&
MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) {
/* catch block */
+
+ if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)) {
+ /* store the exception object int cfg->excvar */
+ g_assert (ji->exvar_offset);
+ *((gpointer *)((char *)MONO_CONTEXT_GET_BP (ctx) + ji->exvar_offset)) = obj;
+ }
+
if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE &&
mono_object_isinst (obj, mono_class_get (ji->method->klass->image, ei->data.token))) ||
((ei->flags == MONO_EXCEPTION_CLAUSE_FILTER &&
- call_filter (ctx, ei->data.filter, obj)))) {
+ call_filter (ctx, ei->data.filter)))) {
if (test_only) {
- ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
+ if (mono_ex)
+ mono_ex->trace_ips = glist_to_array (trace_ips);
g_list_free (trace_ips);
g_free (trace);
return TRUE;
}
- if (mono_jit_trace_calls)
+ if (mono_jit_trace_calls != NULL && mono_trace_eval (ji->method))
g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
- *((gpointer *)((char *)MONO_CONTEXT_GET_BP (ctx) + ji->exvar_offset)) = obj;
jit_tls->lmf = lmf;
g_free (trace);
return 0;
if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) &&
MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
(ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
- if (mono_jit_trace_calls)
+ if (mono_jit_trace_calls != NULL && mono_trace_eval (ji->method))
g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
- call_filter (ctx, ei->handler_start, NULL);
+ call_filter (ctx, ei->handler_start);
}
}
jit_tls->abort_func (obj);
g_assert_not_reached ();
} else {
- ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
+ if (mono_ex)
+ mono_ex->trace_ips = glist_to_array (trace_ips);
g_list_free (trace_ips);
return FALSE;
}