2 * exception.c: exception support
5 * Dietmar Maurer (dietmar@ximian.com)
7 * (C) 2001 Ximian, Inc.
13 #include <mono/arch/x86/x86-codegen.h>
14 #include <mono/metadata/appdomain.h>
15 #include <mono/metadata/tabledefs.h>
21 # define SC_EAX sc_eax
22 # define SC_EBX sc_ebx
23 # define SC_ECX sc_ecx
24 # define SC_EDX sc_edx
25 # define SC_EBP sc_ebp
26 # define SC_EIP sc_eip
27 # define SC_ESP sc_esp
28 # define SC_EDI sc_edi
29 # define SC_ESI sc_esi
43 * arch_get_restore_context:
45 * Returns a pointer to a method which restores a previously saved sigcontext.
48 arch_get_restore_context (void)
50 static guint8 *start = NULL;
56 /* restore_contect (struct sigcontext *ctx) */
57 /* we do not restore X86_EAX, X86_EDX */
59 start = code = g_malloc (1024);
62 x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
64 /* get return address, stored in EDX */
65 x86_mov_reg_membase (code, X86_EDX, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EIP), 4);
67 x86_mov_reg_membase (code, X86_EBX, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EBX), 4);
69 x86_mov_reg_membase (code, X86_EDI, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EDI), 4);
71 x86_mov_reg_membase (code, X86_ESI, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_ESI), 4);
73 x86_mov_reg_membase (code, X86_ESP, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_ESP), 4);
75 x86_mov_reg_membase (code, X86_EBP, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EBP), 4);
76 /* restore ECX. the exception object is passed here to the catch handler */
77 x86_mov_reg_membase (code, X86_ECX, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_ECX), 4);
79 /* jump to the saved IP */
80 x86_jump_reg (code, X86_EDX);
86 * arch_get_call_finally:
88 * Returns a pointer to a method which calls a finally handler.
91 arch_get_call_finally (void)
93 static guint8 start [28];
94 static int inited = 0;
101 /* call_finally (struct sigcontext *ctx, unsigned long eip) */
104 x86_push_reg (code, X86_EBP);
105 x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
106 x86_push_reg (code, X86_EBX);
107 x86_push_reg (code, X86_EDI);
108 x86_push_reg (code, X86_ESI);
111 x86_mov_reg_membase (code, X86_EAX, X86_EBP, 8, 4);
113 x86_mov_reg_membase (code, X86_ECX, X86_EBP, 12, 4);
115 x86_push_reg (code, X86_EBP);
117 x86_mov_reg_membase (code, X86_EBP, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EBP), 4);
118 /* call the handler */
119 x86_call_reg (code, X86_ECX);
121 x86_pop_reg (code, X86_EBP);
122 /* restore saved regs */
123 x86_pop_reg (code, X86_ESI);
124 x86_pop_reg (code, X86_EDI);
125 x86_pop_reg (code, X86_EBX);
129 g_assert ((code - start) < 28);
135 * arch_handle_exception:
136 * @ctx: saved processor state
140 arch_handle_exception (struct sigcontext *ctx, gpointer obj)
142 MonoDomain *domain = mono_domain_get ();
144 gpointer ip = (gpointer)ctx->SC_EIP;
145 static void (*restore_context) (struct sigcontext *);
146 static void (*call_finally) (struct sigcontext *, unsigned long);
147 void (*cleanup) (MonoObject *exc);
149 g_assert (ctx != NULL);
150 g_assert (obj != NULL);
152 ji = mono_jit_info_table_find (domain, ip);
154 if (!restore_context)
155 restore_context = arch_get_restore_context ();
158 call_finally = arch_get_call_finally ();
160 cleanup = TlsGetValue (exc_cleanup_id);
162 if (ji) { /* we are inside managed code */
163 MonoMethod *m = ji->method;
166 if (ji->num_clauses) {
169 g_assert (ji->clauses);
171 for (i = 0; i < ji->num_clauses; i++) {
172 MonoJitExceptionInfo *ei = &ji->clauses [i];
174 if (ei->try_start <= ip && ip <= (ei->try_end)) {
176 if (ei->flags == 0 && mono_object_isinst (obj,
177 mono_class_get (m->klass->image, ei->token_or_filter))) {
179 ctx->SC_EIP = (unsigned long)ei->handler_start;
180 ctx->SC_ECX = (unsigned long)obj;
181 restore_context (ctx);
182 g_assert_not_reached ();
187 /* no handler found - we need to call all finally handlers */
188 for (i = 0; i < ji->num_clauses; i++) {
189 MonoJitExceptionInfo *ei = &ji->clauses [i];
191 if (ei->try_start <= ip && ip < (ei->try_end) &&
192 (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
193 call_finally (ctx, (unsigned long)ei->handler_start);
198 if (mono_object_isinst (obj, mono_defaults.exception_class)) {
199 char *strace = mono_string_to_utf8 (((MonoException*)obj)->stack_trace);
202 if (!strcmp (strace, "TODO: implement stack traces")){
204 strace = g_strdup ("");
207 tmp = g_strdup_printf ("%sin %03x %s.%s:%s ()\n", strace, ip - ji->code_start,
208 m->klass->name_space, m->klass->name, m->name);
212 ((MonoException*)obj)->stack_trace = mono_string_new (domain, tmp);
216 /* continue unwinding */
218 /* restore caller saved registers */
219 if (ji->used_regs & X86_ESI_MASK) {
220 ctx->SC_ESI = *((int *)ctx->SC_EBP + offset);
223 if (ji->used_regs & X86_EDI_MASK) {
224 ctx->SC_EDI = *((int *)ctx->SC_EBP + offset);
227 if (ji->used_regs & X86_EBX_MASK) {
228 ctx->SC_EBX = *((int *)ctx->SC_EBP + offset);
231 ctx->SC_ESP = ctx->SC_EBP;
232 ctx->SC_EIP = *((int *)ctx->SC_EBP + 1);
233 ctx->SC_EBP = *((int *)ctx->SC_EBP);
235 if (ctx->SC_EBP < (unsigned)mono_end_of_stack)
236 arch_handle_exception (ctx, obj);
243 gpointer *lmf_addr = TlsGetValue (lmf_thread_id);
248 lmf = *((MonoLMF **)lmf_addr);
256 *lmf_addr = lmf->previous_lmf;
258 ctx->SC_ESI = lmf->esi;
259 ctx->SC_EDI = lmf->edi;
260 ctx->SC_EBX = lmf->ebx;
261 ctx->SC_EBP = lmf->ebp;
262 ctx->SC_EIP = lmf->eip;
263 ctx->SC_ESP = (unsigned long)&lmf->eip;
265 if (mono_object_isinst (obj, mono_defaults.exception_class)) {
266 char *strace = mono_string_to_utf8 (((MonoException*)obj)->stack_trace);
269 if (!strcmp (strace, "TODO: implement stack traces"))
270 strace = g_strdup ("");
272 tmp = g_strdup_printf ("%sin (unmanaged) %s.%s:%s ()\n", strace, m->klass->name_space,
273 m->klass->name, m->name);
277 ((MonoException*)obj)->stack_trace = mono_string_new (domain, tmp);
281 if (ctx->SC_EBP < (unsigned)mono_end_of_stack)
282 arch_handle_exception (ctx, obj);
289 g_assert_not_reached ();
293 throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsigned long ebx,
294 unsigned long esi, unsigned long edi, unsigned long ebp, MonoObject *exc,
295 unsigned long eip, unsigned long esp)
297 struct sigcontext ctx;
309 arch_handle_exception (&ctx, exc);
311 g_assert_not_reached ();
315 * arch_get_throw_exception:
317 * Returns a function pointer which can be used to raise
318 * exceptions. The returned function has the following
319 * signature: void (*func) (MonoException *exc);
320 * For example to raise an arithmetic exception you can use:
322 * x86_push_imm (code, mono_get_exception_arithmetic ());
323 * x86_call_code (code, arch_get_throw_exception ());
327 arch_get_throw_exception (void)
329 static guint8 start [24];
330 static int inited = 0;
339 x86_push_reg (code, X86_ESP);
340 x86_push_membase (code, X86_ESP, 4); /* IP */
341 x86_push_membase (code, X86_ESP, 12); /* exception */
342 x86_push_reg (code, X86_EBP);
343 x86_push_reg (code, X86_EDI);
344 x86_push_reg (code, X86_ESI);
345 x86_push_reg (code, X86_EBX);
346 x86_push_reg (code, X86_EDX);
347 x86_push_reg (code, X86_ECX);
348 x86_push_reg (code, X86_EAX);
349 x86_call_code (code, throw_exception);
350 /* we should never reach this breakpoint */
351 x86_breakpoint (code);
353 g_assert ((code - start) < 24);
358 * arch_get_throw_exception_by_name:
360 * Returns a function pointer which can be used to raise
361 * corlib exceptions. The returned function has the following
362 * signature: void (*func) (char *exc_name);
363 * For example to raise an arithmetic exception you can use:
365 * x86_push_imm (code, "ArithmeticException");
366 * x86_call_code (code, arch_get_throw_exception ());
370 arch_get_throw_exception_by_name ()
372 static guint8 start [32];
373 static int inited = 0;
382 /* fixme: we do not save EAX, EDX, ECD - unsure if we need that */
384 x86_push_membase (code, X86_ESP, 4); /* exception name */
385 x86_push_imm (code, "System");
386 x86_push_imm (code, mono_defaults.exception_class->image);
387 x86_call_code (code, mono_exception_from_name);
388 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
389 /* save the newly create object (overwrite exception name)*/
390 x86_mov_membase_reg (code, X86_ESP, 4, X86_EAX, 4);
391 x86_jump_code (code, arch_get_throw_exception ());
393 g_assert ((code - start) < 32);