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 * arch_get_restore_context:
23 * Returns a pointer to a method which restores a previously saved sigcontext.
26 arch_get_restore_context ()
28 static guint8 *start = NULL;
34 /* restore_contect (struct sigcontext *ctx) */
35 /* we do not restore X86_EAX, X86_EDX */
37 start = code = g_malloc (1024);
40 x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
42 /* get return address, stored in EDX */
43 x86_mov_reg_membase (code, X86_EDX, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, eip), 4);
45 x86_mov_reg_membase (code, X86_EBX, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, ebx), 4);
47 x86_mov_reg_membase (code, X86_EDI, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, edi), 4);
49 x86_mov_reg_membase (code, X86_ESI, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, esi), 4);
51 x86_mov_reg_membase (code, X86_ESP, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, esp), 4);
53 x86_mov_reg_membase (code, X86_EBP, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, ebp), 4);
54 /* restore ECX. the exception object is passed here to the catch handler */
55 x86_mov_reg_membase (code, X86_ECX, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, ecx), 4);
57 /* jump to the saved IP */
58 x86_jump_reg (code, X86_EDX);
64 * arch_get_call_finally:
66 * Returns a pointer to a method which calls a finally handler.
69 arch_get_call_finally ()
71 static guint8 start [28];
72 static int inited = 0;
79 /* call_finally (struct sigcontext *ctx, unsigned long eip) */
82 x86_push_reg (code, X86_EBP);
83 x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
84 x86_push_reg (code, X86_EBX);
85 x86_push_reg (code, X86_EDI);
86 x86_push_reg (code, X86_ESI);
89 x86_mov_reg_membase (code, X86_EAX, X86_EBP, 8, 4);
91 x86_mov_reg_membase (code, X86_ECX, X86_EBP, 12, 4);
93 x86_push_reg (code, X86_EBP);
95 x86_mov_reg_membase (code, X86_EBP, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, ebp), 4);
96 /* call the handler */
97 x86_call_reg (code, X86_ECX);
99 x86_pop_reg (code, X86_EBP);
100 /* restore saved regs */
101 x86_pop_reg (code, X86_ESI);
102 x86_pop_reg (code, X86_EDI);
103 x86_pop_reg (code, X86_EBX);
107 g_assert ((code - start) < 28);
112 * arch_handle_exception:
113 * @ctx: saved processor state
117 arch_handle_exception (struct sigcontext *ctx, gpointer obj)
119 MonoDomain *domain = mono_domain_get ();
121 gpointer ip = (gpointer)ctx->eip;
122 static void (*restore_context) (struct sigcontext *);
123 static void (*call_finally) (struct sigcontext *, unsigned long);
125 g_assert (ctx != NULL);
126 g_assert (obj != NULL);
128 ji = mono_jit_info_table_find (domain, ip);
130 if (!restore_context)
131 restore_context = arch_get_restore_context ();
134 call_finally = arch_get_call_finally ();
136 if (ji) { /* we are inside managed code */
137 MonoMethod *m = ji->method;
140 if (ji->num_clauses) {
143 g_assert (ji->clauses);
145 for (i = 0; i < ji->num_clauses; i++) {
146 MonoJitExceptionInfo *ei = &ji->clauses [i];
148 if (ei->try_start <= ip && ip <= (ei->try_end)) {
150 if (ei->flags == 0 && mono_object_isinst (obj,
151 mono_class_get (m->klass->image, ei->token_or_filter))) {
153 ctx->eip = (unsigned long)ei->handler_start;
154 ctx->ecx = (unsigned long)obj;
155 restore_context (ctx);
156 g_assert_not_reached ();
161 /* no handler found - we need to call all finally handlers */
162 for (i = 0; i < ji->num_clauses; i++) {
163 MonoJitExceptionInfo *ei = &ji->clauses [i];
165 if (ei->try_start <= ip && ip < (ei->try_end) &&
166 (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
167 call_finally (ctx, (unsigned long)ei->handler_start);
172 if (mono_object_isinst (obj, mono_defaults.exception_class)) {
173 char *strace = mono_string_to_utf8 (((MonoException*)obj)->stack_trace);
176 if (!strcmp (strace, "TODO: implement stack traces")){
178 strace = g_strdup ("");
181 tmp = g_strdup_printf ("%sin %s.%s:%s ()\n", strace, m->klass->name_space,
182 m->klass->name, m->name);
186 ((MonoException*)obj)->stack_trace = mono_string_new (domain, tmp);
190 /* continue unwinding */
192 /* restore caller saved registers */
193 if (ji->used_regs & X86_ESI_MASK) {
194 ctx->esi = *((int *)ctx->ebp + offset);
197 if (ji->used_regs & X86_EDI_MASK) {
198 ctx->edi = *((int *)ctx->ebp + offset);
201 if (ji->used_regs & X86_EBX_MASK) {
202 ctx->ebx = *((int *)ctx->ebp + offset);
206 ctx->eip = *((int *)ctx->ebp + 1);
207 ctx->ebp = *((int *)ctx->ebp);
209 if (ctx->ebp < (unsigned)mono_end_of_stack)
210 arch_handle_exception (ctx, obj);
212 mono_jit_abort (obj);
214 gpointer *lmf_addr = TlsGetValue (lmf_thread_id);
219 lmf = *((MonoLMF **)lmf_addr);
222 mono_jit_abort (obj);
226 *lmf_addr = lmf->previous_lmf;
233 ctx->esp = (unsigned long)&lmf->eip;
235 if (mono_object_isinst (obj, mono_defaults.exception_class)) {
236 char *strace = mono_string_to_utf8 (((MonoException*)obj)->stack_trace);
239 if (!strcmp (strace, "TODO: implement stack traces"))
240 strace = g_strdup ("");
242 tmp = g_strdup_printf ("%sin (unmanaged) %s.%s:%s ()\n", strace, m->klass->name_space,
243 m->klass->name, m->name);
247 ((MonoException*)obj)->stack_trace = mono_string_new (domain, tmp);
251 if (ctx->eip < (unsigned)mono_end_of_stack)
252 arch_handle_exception (ctx, obj);
254 mono_jit_abort (obj);
257 g_assert_not_reached ();
261 throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsigned long ebx,
262 unsigned long esi, unsigned long edi, unsigned long ebp, MonoObject *exc,
263 unsigned long eip, unsigned long esp)
265 struct sigcontext ctx;
277 arch_handle_exception (&ctx, exc);
279 g_assert_not_reached ();
283 * arch_get_throw_exception:
285 * Returns a function pointer which can be used to raise
286 * exceptions. The returned function has the following
287 * signature: void (*func) (MonoException *exc);
288 * For example to raise an arithmetic exception you can use:
290 * x86_push_imm (code, mono_get_exception_arithmetic ());
291 * x86_call_code (code, arch_get_throw_exception ());
295 arch_get_throw_exception (void)
297 static guint8 start [24];
298 static int inited = 0;
307 x86_push_reg (code, X86_ESP);
308 x86_push_membase (code, X86_ESP, 4); /* IP */
309 x86_push_membase (code, X86_ESP, 12); /* exception */
310 x86_push_reg (code, X86_EBP);
311 x86_push_reg (code, X86_EDI);
312 x86_push_reg (code, X86_ESI);
313 x86_push_reg (code, X86_EBX);
314 x86_push_reg (code, X86_EDX);
315 x86_push_reg (code, X86_ECX);
316 x86_push_reg (code, X86_EAX);
317 x86_call_code (code, throw_exception);
318 /* we should never reach this breakpoint */
319 x86_breakpoint (code);
321 g_assert ((code - start) < 24);
326 * arch_get_throw_exception_by_name:
328 * Returns a function pointer which can be used to raise
329 * corlib exceptions. The returned function has the following
330 * signature: void (*func) (char *exc_name);
331 * For example to raise an arithmetic exception you can use:
333 * x86_push_imm (code, "ArithmeticException");
334 * x86_call_code (code, arch_get_throw_exception ());
338 arch_get_throw_exception_by_name ()
340 static guint8 start [32];
341 static int inited = 0;
350 /* fixme: we do not save EAX, EDX, ECD - unsure if we need that */
352 x86_push_membase (code, X86_ESP, 4); /* exception name */
353 x86_push_imm (code, "System");
354 x86_push_imm (code, mono_defaults.exception_class->image);
355 x86_call_code (code, mono_exception_from_name);
356 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
357 /* save the newly create object (overwrite exception name)*/
358 x86_mov_membase_reg (code, X86_ESP, 4, X86_EAX, 4);
359 x86_jump_code (code, arch_get_throw_exception ());
361 g_assert ((code - start) < 32);