2002-09-12 Dietmar Maurer <dietmar@ximian.com>
[mono.git] / mono / jit / exception.c
1 /*
2  * exception.c: exception support
3  *
4  * Authors:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <signal.h>
13
14 #include <mono/arch/x86/x86-codegen.h>
15 #include <mono/metadata/appdomain.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/threads.h>
18 #include <mono/metadata/debug-helpers.h>
19
20 #include "jit.h"
21 #include "codegen.h"
22 #include "debug.h"
23
24 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
25 # define SC_EAX sc_eax
26 # define SC_EBX sc_ebx
27 # define SC_ECX sc_ecx
28 # define SC_EDX sc_edx
29 # define SC_EBP sc_ebp
30 # define SC_EIP sc_eip
31 # define SC_ESP sc_esp
32 # define SC_EDI sc_edi
33 # define SC_ESI sc_esi
34 #else
35 # define SC_EAX eax
36 # define SC_EBX ebx
37 # define SC_ECX ecx
38 # define SC_EDX edx
39 # define SC_EBP ebp
40 # define SC_EIP eip
41 # define SC_ESP esp
42 # define SC_EDI edi
43 # define SC_ESI esi
44 #endif
45
46 /*
47  * arch_get_restore_context:
48  *
49  * Returns a pointer to a method which restores a previously saved sigcontext.
50  */
51 static gpointer
52 arch_get_restore_context (void)
53 {
54         static guint8 *start = NULL;
55         guint8 *code;
56
57         if (start)
58                 return start;
59
60         /* restore_contect (struct sigcontext *ctx) */
61         /* we do not restore X86_EAX, X86_EDX */
62
63         start = code = g_malloc (1024);
64         
65         /* load ctx */
66         x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
67
68         /* get return address, stored in EDX */
69         x86_mov_reg_membase (code, X86_EDX, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EIP), 4);
70         /* restore EBX */
71         x86_mov_reg_membase (code, X86_EBX, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EBX), 4);
72         /* restore EDI */
73         x86_mov_reg_membase (code, X86_EDI, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EDI), 4);
74         /* restore ESI */
75         x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_ESI), 4);
76         /* restore ESP */
77         x86_mov_reg_membase (code, X86_ESP, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_ESP), 4);
78         /* restore EBP */
79         x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EBP), 4);
80         /* restore ECX. the exception object is passed here to the catch handler */
81         x86_mov_reg_membase (code, X86_ECX, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_ECX), 4);
82
83         /* jump to the saved IP */
84         x86_jump_reg (code, X86_EDX);
85
86         return start;
87 }
88
89 /*
90  * arch_get_call_filter:
91  *
92  * Returns a pointer to a method which calls an exception filter.
93  */
94 static gpointer
95 arch_get_call_filter (void)
96 {
97         static guint8 start [64];
98         static int inited = 0;
99         guint8 *code;
100
101         if (inited)
102                 return start;
103
104         inited = 1;
105         /* call_finally (struct sigcontext *ctx, unsigned long eip, gpointer exc) */
106         code = start;
107
108         x86_push_reg (code, X86_EBP);
109         x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
110         x86_push_reg (code, X86_EBX);
111         x86_push_reg (code, X86_EDI);
112         x86_push_reg (code, X86_ESI);
113
114         /* load ctx */
115         x86_mov_reg_membase (code, X86_EAX, X86_EBP, 8, 4);
116         /* load eip */
117         x86_mov_reg_membase (code, X86_ECX, X86_EBP, 12, 4);
118         /* save EBP */
119         x86_push_reg (code, X86_EBP);
120         /* push exc */
121         x86_push_membase (code, X86_EBP, 16);
122         /* set new EBP */
123         x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EBP), 4);
124         /* restore registers used by global register allocation (EBX & ESI) */
125         x86_mov_reg_membase (code, X86_EBX, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EBX), 4);
126         x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_ESI), 4);
127         /* save the ESP - this is used by endfinally */
128         x86_mov_membase_reg (code, X86_EBP, mono_exc_esp_offset, X86_ESP, 4);
129         /* call the handler */
130         x86_call_reg (code, X86_ECX);
131         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
132         /* restore EBP */
133         x86_pop_reg (code, X86_EBP);
134         /* restore saved regs */
135         x86_pop_reg (code, X86_ESI);
136         x86_pop_reg (code, X86_EDI);
137         x86_pop_reg (code, X86_EBX);
138         x86_leave (code);
139         x86_ret (code);
140
141         g_assert ((code - start) < 64);
142         return start;
143 }
144
145 /*
146  * arch_get_call_finally:
147  *
148  * Returns a pointer to a method which calls a finally handler.
149  */
150 static gpointer
151 arch_get_call_finally (void)
152 {
153         static guint8 start [64];
154         static int inited = 0;
155         guint8 *code;
156
157         if (inited)
158                 return start;
159
160         inited = 1;
161         /* call_finally (struct sigcontext *ctx, unsigned long eip) */
162         code = start;
163
164         x86_push_reg (code, X86_EBP);
165         x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
166         x86_push_reg (code, X86_EBX);
167         x86_push_reg (code, X86_EDI);
168         x86_push_reg (code, X86_ESI);
169
170         /* load ctx */
171         x86_mov_reg_membase (code, X86_EAX, X86_EBP, 8, 4);
172         /* load eip */
173         x86_mov_reg_membase (code, X86_ECX, X86_EBP, 12, 4);
174         /* save EBP */
175         x86_push_reg (code, X86_EBP);
176         /* set new EBP */
177         x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EBP), 4);
178         /* restore registers used by global register allocation (EBX & ESI) */
179         x86_mov_reg_membase (code, X86_EBX, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EBX), 4);
180         x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_ESI), 4);
181         /* save the ESP - this is used by endfinally */
182         x86_mov_membase_reg (code, X86_EBP, mono_exc_esp_offset, X86_ESP, 4);
183         /* call the handler */
184         x86_call_reg (code, X86_ECX);
185         /* restore EBP */
186         x86_pop_reg (code, X86_EBP);
187         /* restore saved regs */
188         x86_pop_reg (code, X86_ESI);
189         x86_pop_reg (code, X86_EDI);
190         x86_pop_reg (code, X86_EBX);
191         x86_leave (code);
192         x86_ret (code);
193
194         g_assert ((code - start) < 64);
195         return start;
196 }
197
198 static MonoArray *
199 glist_to_array (GList *list) 
200 {
201         MonoDomain *domain = mono_domain_get ();
202         MonoArray *res;
203         int len, i;
204
205         if (!list)
206                 return NULL;
207
208         len = g_list_length (list);
209         res = mono_array_new (domain, mono_defaults.int_class, len);
210
211         for (i = 0; list; list = list->next, i++)
212                 mono_array_set (res, gpointer, i, list->data);
213
214         return res;
215 }
216
217 MonoArray *
218 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
219 {
220         MonoDomain *domain = mono_domain_get ();
221         MonoArray *res;
222         MonoArray *ta = exc->trace_ips;
223         int i, len;
224         
225         len = mono_array_length (ta);
226
227         res = mono_array_new (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0);
228
229         for (i = skip; i < len; i++) {
230                 MonoJitInfo *ji;
231                 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
232                 gpointer ip = mono_array_get (ta, gpointer, i);
233
234                 ji = mono_jit_info_table_find (domain, ip);
235                 g_assert (ji != NULL);
236
237                 sf->method = mono_method_get_object (domain, ji->method, NULL);
238                 sf->native_offset = (char *)ip - (char *)ji->code_start;
239                 sf->il_offset = mono_debug_il_offset_from_address (ji->method, sf->native_offset);
240
241                 if (need_file_info) {
242                         gchar *filename;
243
244                         filename = mono_debug_source_location_from_address (ji->method, sf->native_offset, &sf->line);
245
246                         sf->filename = mono_string_new (domain, filename ? filename : "<unknown>");
247                         sf->column = 0;
248
249                         g_free (filename);
250                 }
251
252                 mono_array_set (res, gpointer, i, sf);
253         }
254
255         return res;
256 }
257
258 void
259 mono_jit_walk_stack (MonoStackWalk func, gpointer user_data) {
260         MonoDomain *domain = mono_domain_get ();
261         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
262         MonoLMF *lmf = jit_tls->lmf;
263         MonoJitInfo *ji;
264         MonoMethod *m;
265         gpointer ip;
266         gpointer *bp;
267         gint native_offset, il_offset;
268
269         bp = (gpointer *)&func;
270         ip = bp [-1];
271         bp = &ip;
272
273         while ((unsigned)bp < (unsigned)jit_tls->end_of_stack) {
274                 if ((ji = mono_jit_info_table_find (domain, ip))) {
275                         m = ji->method;
276                         native_offset = (char *)ip - (char *)ji->code_start;
277                         ip = (gpointer)((char *)bp [1] - 5);
278                         bp = bp [0];
279                         il_offset = mono_debug_il_offset_from_address (m, native_offset);
280                 } else {
281                         if (!lmf)
282                                 break;
283                         m = lmf->method;
284
285                         bp = (gpointer)lmf->ebp;
286                         ip = (gpointer)lmf->eip;
287                         lmf = lmf->previous_lmf;
288
289                         native_offset = il_offset = -1;
290                 }
291                 if (func (m, native_offset, il_offset, user_data))
292                         return;
293         }
294 }
295
296 MonoBoolean
297 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, 
298                           MonoReflectionMethod **method, 
299                           gint32 *iloffset, gint32 *native_offset,
300                           MonoString **file, gint32 *line, gint32 *column)
301 {
302         MonoDomain *domain = mono_domain_get ();
303         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
304         MonoLMF *lmf = jit_tls->lmf;
305         gpointer *sf = (gpointer *)&skip;
306         gpointer ip = sf [-1];
307         int addr;
308         gpointer *bp = sf [-2];
309         MonoMethod *m = NULL;
310
311         do {
312                 MonoJitInfo *ji;
313                 addr = -1; /* unknown */
314
315                 if ((ji = mono_jit_info_table_find (domain, ip))) {
316                         m = ji->method;
317                         addr = (char *)ip - (char *)ji->code_start;
318                         ip = (gpointer)((char *)bp [1] - 5);
319                         bp = bp [0];
320                 } else {
321                         if (!lmf)
322                                 return FALSE;
323                         
324                         m = lmf->method;
325
326                         bp = (gpointer)lmf->ebp;
327                         ip = (gpointer)lmf->eip;
328
329                         lmf = lmf->previous_lmf;
330                 }
331
332                 if ((unsigned)bp >= (unsigned)jit_tls->end_of_stack)
333                         return FALSE;
334
335         } while (skip-- > 0);
336
337         g_assert (m);
338
339         *method = mono_method_get_object (domain, m, NULL);
340         *iloffset = mono_debug_il_offset_from_address (m, addr);
341         *native_offset = addr;
342
343         if (need_file_info) {
344                 gchar *filename;
345
346                 filename = mono_debug_source_location_from_address (m, addr, line);
347
348                 *file = mono_string_new (domain, filename ? filename : "<unknown>");
349                 *column = 0;
350
351                 g_free (filename);
352         }
353
354         return TRUE;
355 }
356
357 /**
358  * arch_handle_exception:
359  * @ctx: saved processor state
360  * @obj:
361  */
362 gboolean
363 arch_handle_exception (struct sigcontext *ctx, gpointer obj, gboolean test_only)
364 {
365         MonoDomain *domain = mono_domain_get ();
366         MonoJitInfo *ji;
367         static void (*restore_context) (struct sigcontext *);
368         static void (*call_finally) (struct sigcontext *, unsigned long);
369         static int (*call_filter) (struct sigcontext *, gpointer, gpointer);
370         void (*cleanup) (MonoObject *exc);
371         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
372         gpointer end_of_stack;
373         struct sigcontext ctx_cp;
374         MonoLMF *lmf = jit_tls->lmf;            
375         GList *trace_ips = NULL;
376         MonoMethod *m;
377
378         g_assert (ctx != NULL);
379         if (!obj) {
380                 MonoException *ex = mono_get_exception_null_reference ();
381                 ex->message = mono_string_new (domain, 
382                         "Object reference not set to an instance of an object");
383                 obj = (MonoObject *)ex;
384         } 
385
386         g_assert (mono_object_isinst (obj, mono_defaults.exception_class));
387
388         if (!restore_context)
389                 restore_context = arch_get_restore_context ();
390         
391         if (!call_finally)
392                 call_finally = arch_get_call_finally ();
393
394         if (!call_filter)
395                 call_filter = arch_get_call_filter ();
396
397         end_of_stack = jit_tls->end_of_stack;
398         g_assert (end_of_stack);
399
400         cleanup = jit_tls->abort_func;
401         g_assert (cleanup);
402         
403         if (!test_only) {
404                 ctx_cp = *ctx;
405                 if (!arch_handle_exception (&ctx_cp, obj, TRUE)) {
406                         if (mono_break_on_exc) {
407                                 if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
408                                         mono_debug_make_symbols ();
409                                 G_BREAKPOINT ();
410                         }
411                         mono_unhandled_exception (obj);
412                 }
413         }
414
415         while (1) {
416
417                 ji = mono_jit_info_table_find (domain, (gpointer)ctx->SC_EIP);
418         
419                 /* we are inside managed code if ji != NULL */
420                 if (ji != NULL) {
421                         int offset;
422                         m = ji->method;                 
423
424                         if (m == mono_start_method) {
425                                 if (!test_only) {
426                                         jit_tls->lmf = lmf;
427                                         cleanup (obj);
428                                         g_assert_not_reached ();
429                                 } else {
430                                         ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
431                                         g_list_free (trace_ips);
432                                         return FALSE;
433                                 }
434                         }
435                         
436                         if (test_only) {
437                                 char    *strace;
438                                 char    *tmp, *source_location, *tmpaddr, *fname;
439                                 gint32   address, iloffset;
440
441                                 trace_ips = g_list_append (trace_ips, (gpointer)ctx->SC_EIP);
442
443                                 if (!((MonoException*)obj)->stack_trace)
444                                         strace = g_strdup ("");
445                                 else
446                                         strace = mono_string_to_utf8 (((MonoException*)obj)->stack_trace);
447
448                                 address = (char *)ctx->SC_EIP - (char *)ji->code_start;
449
450                                 if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
451                                         mono_debug_make_symbols ();
452
453                                 source_location = mono_debug_source_location_from_address (m, address, NULL);
454                                 iloffset = mono_debug_il_offset_from_address (m, address);
455
456                                 if (iloffset < 0)
457                                         tmpaddr = g_strdup_printf ("<0x%05x>", address);
458                                 else
459                                         tmpaddr = g_strdup_printf ("[0x%05x]", iloffset);
460
461                                 fname = mono_method_full_name (m, TRUE);
462
463                                 if (source_location)
464                                         tmp = g_strdup_printf ("%sin %s (at %s) %s\n", strace, tmpaddr,
465                                                                source_location, fname);
466                                 else
467                                         tmp = g_strdup_printf ("%sin %s %s\n", strace, tmpaddr,
468                                                                fname);
469                                 g_free (fname);
470                                 g_free (source_location);
471                                 g_free (strace);
472                                 g_free (tmpaddr);
473
474                                 ((MonoException*)obj)->stack_trace = mono_string_new (domain, tmp);
475
476                                 g_free (tmp);
477                         }
478                         
479                         if (ji->num_clauses) {
480                                 int i;
481                                 
482                                 g_assert (ji->clauses);
483                         
484                                 for (i = 0; i < ji->num_clauses; i++) {
485                                         MonoJitExceptionInfo *ei = &ji->clauses [i];
486
487                                         if (ei->try_start <= (gpointer)ctx->SC_EIP && 
488                                             (gpointer)ctx->SC_EIP <= ei->try_end) { 
489                                                 /* catch block */
490                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && 
491                                                      mono_object_isinst (obj, mono_class_get (m->klass->image, ei->data.token))) ||
492                                                     ((ei->flags == MONO_EXCEPTION_CLAUSE_FILTER &&
493                                                       call_filter (ctx, ei->data.filter, obj)))) {
494                                                         if (test_only) {
495                                                                 ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
496                                                                 g_list_free (trace_ips);
497                                                                 return TRUE;
498                                                         }
499                                                         ctx->SC_EIP = (unsigned long)ei->handler_start;
500                                                         ctx->SC_ECX = (unsigned long)obj;
501                                                         jit_tls->lmf = lmf;
502 #if 1
503                                                         return 0;
504 #else
505                                                         restore_context (ctx);
506                                                         g_assert_not_reached ();
507 #endif
508                                                 }
509                                         }
510                                 }
511
512                                 /* no handler found - we need to call all finally handlers */
513                                 if (!test_only) {
514                                         for (i = 0; i < ji->num_clauses; i++) {
515                                                 MonoJitExceptionInfo *ei = &ji->clauses [i];
516
517                                                 if (ei->try_start <= (gpointer)ctx->SC_EIP && 
518                                                     (gpointer)ctx->SC_EIP < ei->try_end &&
519                                                     (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
520                                                         call_finally (ctx, (unsigned long)ei->handler_start);
521                                                 }
522                                         }
523                                 }
524                         }
525
526                         /* continue unwinding */
527
528                         offset = -1;
529                         /* restore caller saved registers */
530                         if (ji->used_regs & X86_EBX_MASK) {
531                                 ctx->SC_EBX = *((int *)ctx->SC_EBP + offset);
532                                 offset--;
533                         }
534                         if (ji->used_regs & X86_EDI_MASK) {
535                                 ctx->SC_EDI = *((int *)ctx->SC_EBP + offset);
536                                 offset--;
537                         }
538                         if (ji->used_regs & X86_ESI_MASK) {
539                                 ctx->SC_ESI = *((int *)ctx->SC_EBP + offset);
540                         }
541
542                         ctx->SC_ESP = ctx->SC_EBP;
543                         ctx->SC_EIP = *((int *)ctx->SC_EBP + 1) - 5;
544                         ctx->SC_EBP = *((int *)ctx->SC_EBP);
545
546                         if (ctx->SC_EBP > (unsigned)end_of_stack) {
547                                 if (!test_only) {
548                                         jit_tls->lmf = lmf;
549                                         cleanup (obj);
550                                         g_assert_not_reached ();
551                                 } else {
552                                         ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
553                                         g_list_free (trace_ips);
554                                         return FALSE;
555                                 }
556                         }
557         
558                 } else {
559                         if (!lmf) {
560                                 if (!test_only) {
561                                         jit_tls->lmf = lmf;
562                                         cleanup (obj);
563                                         g_assert_not_reached ();
564                                 } else {
565                                         ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
566                                         g_list_free (trace_ips);
567                                         return FALSE;
568                                 }
569                         }
570                         
571                         m = lmf->method;
572
573                         if (test_only) {
574                                 char  *strace; 
575                                 char  *tmp;
576
577                                 trace_ips = g_list_append (trace_ips, lmf->method->info);
578
579                                 if (!((MonoException*)obj)->stack_trace)
580                                         strace = g_strdup ("");
581                                 else
582                                         strace = mono_string_to_utf8 (((MonoException*)obj)->stack_trace);
583
584                                 tmp = g_strdup_printf ("%sin (unmanaged) %s\n", strace, mono_method_full_name (m, TRUE));
585
586                                 g_free (strace);
587
588                                 ((MonoException*)obj)->stack_trace = mono_string_new (domain, tmp);
589                                 g_free (tmp);
590                         }
591
592                         ctx->SC_ESI = lmf->esi;
593                         ctx->SC_EDI = lmf->edi;
594                         ctx->SC_EBX = lmf->ebx;
595                         ctx->SC_EBP = lmf->ebp;
596                         ctx->SC_EIP = lmf->eip;
597                         ctx->SC_ESP = (unsigned long)&lmf->eip;
598
599                         lmf = lmf->previous_lmf;
600
601                         if (ctx->SC_EBP >= (unsigned)end_of_stack) {
602                                 if (!test_only) {
603                                         jit_tls->lmf = lmf;
604                                         cleanup (obj);
605                                         g_assert_not_reached ();
606                                 } else {
607                                         ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
608                                         g_list_free (trace_ips);
609                                         return FALSE;
610                                 }
611                         }
612                 }
613         }
614
615         g_assert_not_reached ();
616 }
617
618 static void
619 throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsigned long ebx,
620                  unsigned long esi, unsigned long edi, unsigned long ebp, MonoObject *exc,
621                  unsigned long eip,  unsigned long esp)
622 {
623         static void (*restore_context) (struct sigcontext *);
624         struct sigcontext ctx;
625
626         if (!restore_context)
627                 restore_context = arch_get_restore_context ();
628
629         /* adjust eip so that it point to the call instruction */
630         eip -= 5;
631
632         ctx.SC_ESP = esp;
633         ctx.SC_EIP = eip;
634         ctx.SC_EBP = ebp;
635         ctx.SC_EDI = edi;
636         ctx.SC_ESI = esi;
637         ctx.SC_EBX = ebx;
638         ctx.SC_EDX = edx;
639         ctx.SC_ECX = ecx;
640         ctx.SC_EAX = eax;
641         
642         arch_handle_exception (&ctx, exc, FALSE);
643         restore_context (&ctx);
644
645         g_assert_not_reached ();
646 }
647
648 /**
649  * arch_get_throw_exception:
650  *
651  * Returns a function pointer which can be used to raise 
652  * exceptions. The returned function has the following 
653  * signature: void (*func) (MonoException *exc); 
654  * For example to raise an arithmetic exception you can use:
655  *
656  * x86_push_imm (code, mono_get_exception_arithmetic ()); 
657  * x86_call_code (code, arch_get_throw_exception ()); 
658  *
659  */
660 gpointer 
661 arch_get_throw_exception (void)
662 {
663         static guint8 start [24];
664         static int inited = 0;
665         guint8 *code;
666
667         if (inited)
668                 return start;
669
670         inited = 1;
671         code = start;
672
673         x86_push_reg (code, X86_ESP);
674         x86_push_membase (code, X86_ESP, 4); /* IP */
675         x86_push_membase (code, X86_ESP, 12); /* exception */
676         x86_push_reg (code, X86_EBP);
677         x86_push_reg (code, X86_EDI);
678         x86_push_reg (code, X86_ESI);
679         x86_push_reg (code, X86_EBX);
680         x86_push_reg (code, X86_EDX);
681         x86_push_reg (code, X86_ECX);
682         x86_push_reg (code, X86_EAX);
683         x86_call_code (code, throw_exception);
684         /* we should never reach this breakpoint */
685         x86_breakpoint (code);
686
687         g_assert ((code - start) < 24);
688         return start;
689 }
690
691 /**
692  * arch_get_throw_exception_by_name:
693  *
694  * Returns a function pointer which can be used to raise 
695  * corlib exceptions. The returned function has the following 
696  * signature: void (*func) (char *exc_name); 
697  * For example to raise an arithmetic exception you can use:
698  *
699  * x86_push_imm (code, "ArithmeticException"); 
700  * x86_call_code (code, arch_get_throw_exception ()); 
701  *
702  */
703 gpointer 
704 arch_get_throw_exception_by_name ()
705 {
706         static guint8 start [32];
707         static int inited = 0;
708         guint8 *code;
709
710         if (inited)
711                 return start;
712
713         inited = 1;
714         code = start;
715
716         /* fixme: we do not save EAX, EDX, ECD - unsure if we need that */
717
718         x86_push_membase (code, X86_ESP, 4); /* exception name */
719         x86_push_imm (code, "System");
720         x86_push_imm (code, mono_defaults.exception_class->image);
721         x86_call_code (code, mono_exception_from_name);
722         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
723         /* save the newly create object (overwrite exception name)*/
724         x86_mov_membase_reg (code, X86_ESP, 4, X86_EAX, 4);
725         x86_jump_code (code, arch_get_throw_exception ());
726
727         g_assert ((code - start) < 32);
728
729         return start;
730 }