Wed Aug 14 17:31:37 CEST 2002 Paolo Molaro <lupus@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 #ifdef __FreeBSD__
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         ((MonoException *)obj)->stack_trace = NULL;
389
390         if (!restore_context)
391                 restore_context = arch_get_restore_context ();
392         
393         if (!call_finally)
394                 call_finally = arch_get_call_finally ();
395
396         if (!call_filter)
397                 call_filter = arch_get_call_filter ();
398
399         end_of_stack = jit_tls->end_of_stack;
400         g_assert (end_of_stack);
401
402         cleanup = jit_tls->abort_func;
403         g_assert (cleanup);
404         
405         if (!test_only) {
406                 ctx_cp = *ctx;
407                 if (!arch_handle_exception (&ctx_cp, obj, TRUE)) {
408                         if (mono_break_on_exc) {
409                                 if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
410                                         mono_debug_make_symbols ();
411                                 G_BREAKPOINT ();
412                         }
413                         mono_unhandled_exception (obj);
414                 }
415         }
416
417         while (1) {
418
419                 ji = mono_jit_info_table_find (domain, (gpointer)ctx->SC_EIP);
420         
421                 /* we are inside managed code if ji != NULL */
422                 if (ji != NULL) {
423                         int offset;
424                         m = ji->method;
425
426                         if (m == mono_start_method) {
427                                 if (!test_only) {
428                                         jit_tls->lmf = lmf;
429                                         cleanup (obj);
430                                         g_assert_not_reached ();
431                                 } else {
432                                         ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
433                                         g_list_free (trace_ips);
434                                         return FALSE;
435                                 }
436                         }
437                         
438                         if (test_only) {
439                                 char    *strace;
440                                 char    *tmp, *source_location, *tmpaddr, *fname;
441                                 gint32   address, iloffset;
442
443                                 trace_ips = g_list_append (trace_ips, (gpointer)ctx->SC_EIP);
444
445                                 if (!((MonoException*)obj)->stack_trace)
446                                         strace = g_strdup ("");
447                                 else
448                                         strace = mono_string_to_utf8 (((MonoException*)obj)->stack_trace);
449
450                                 address = (char *)ctx->SC_EIP - (char *)ji->code_start;
451
452                                 source_location = mono_debug_source_location_from_address (m, address, NULL);
453                                 iloffset = mono_debug_il_offset_from_address (m, address);
454
455                                 if (iloffset < 0)
456                                         tmpaddr = g_strdup_printf ("<0x%05x>", address);
457                                 else
458                                         tmpaddr = g_strdup_printf ("[0x%05x]", iloffset);
459
460                                 fname = mono_method_full_name (m, TRUE);
461
462                                 if (source_location)
463                                         tmp = g_strdup_printf ("%sin %s (at %s) %s\n", strace, tmpaddr,
464                                                                source_location, fname);
465                                 else
466                                         tmp = g_strdup_printf ("%sin %s %s\n", strace, tmpaddr,
467                                                                fname);
468                                 g_free (fname);
469                                 g_free (source_location);
470                                 g_free (strace);
471                                 g_free (tmpaddr);
472
473                                 ((MonoException*)obj)->stack_trace = mono_string_new (domain, tmp);
474
475                                 g_free (tmp);
476                         }
477                         
478                         if (ji->num_clauses) {
479                                 int i;
480                                 
481                                 g_assert (ji->clauses);
482                         
483                                 for (i = 0; i < ji->num_clauses; i++) {
484                                         MonoJitExceptionInfo *ei = &ji->clauses [i];
485
486                                         if (ei->try_start <= (gpointer)ctx->SC_EIP && 
487                                             (gpointer)ctx->SC_EIP <= ei->try_end) { 
488                                                 /* catch block */
489                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && 
490                                                      mono_object_isinst (obj, mono_class_get (m->klass->image, ei->data.token))) ||
491                                                     ((ei->flags == MONO_EXCEPTION_CLAUSE_FILTER &&
492                                                       call_filter (ctx, ei->data.filter, obj)))) {
493                                                         if (test_only) {
494                                                                 ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
495                                                                 g_list_free (trace_ips);
496                                                                 return TRUE;
497                                                         }
498                                                         ctx->SC_EIP = (unsigned long)ei->handler_start;
499                                                         ctx->SC_ECX = (unsigned long)obj;
500                                                         jit_tls->lmf = lmf;
501 #if 1
502                                                         return 0;
503 #else
504                                                         restore_context (ctx);
505                                                         g_assert_not_reached ();
506 #endif
507                                                 }
508                                         }
509                                 }
510
511                                 /* no handler found - we need to call all finally handlers */
512                                 if (!test_only) {
513                                         for (i = 0; i < ji->num_clauses; i++) {
514                                                 MonoJitExceptionInfo *ei = &ji->clauses [i];
515
516                                                 if (ei->try_start <= (gpointer)ctx->SC_EIP && 
517                                                     (gpointer)ctx->SC_EIP < ei->try_end &&
518                                                     (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
519                                                         call_finally (ctx, (unsigned long)ei->handler_start);
520                                                 }
521                                         }
522                                 }
523                         }
524
525                         /* continue unwinding */
526
527                         offset = -1;
528                         /* restore caller saved registers */
529                         if (ji->used_regs & X86_EBX_MASK) {
530                                 ctx->SC_EBX = *((int *)ctx->SC_EBP + offset);
531                                 offset--;
532                         }
533                         if (ji->used_regs & X86_EDI_MASK) {
534                                 ctx->SC_EDI = *((int *)ctx->SC_EBP + offset);
535                                 offset--;
536                         }
537                         if (ji->used_regs & X86_ESI_MASK) {
538                                 ctx->SC_ESI = *((int *)ctx->SC_EBP + offset);
539                         }
540
541                         ctx->SC_ESP = ctx->SC_EBP;
542                         ctx->SC_EIP = *((int *)ctx->SC_EBP + 1) - 5;
543                         ctx->SC_EBP = *((int *)ctx->SC_EBP);
544
545                         if (ctx->SC_EBP > (unsigned)end_of_stack) {
546                                 if (!test_only) {
547                                         jit_tls->lmf = lmf;
548                                         cleanup (obj);
549                                         g_assert_not_reached ();
550                                 } else {
551                                         ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
552                                         g_list_free (trace_ips);
553                                         return FALSE;
554                                 }
555                         }
556         
557                 } else {
558                         if (!lmf) {
559                                 if (!test_only) {
560                                         jit_tls->lmf = lmf;
561                                         cleanup (obj);
562                                         g_assert_not_reached ();
563                                 } else {
564                                         ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
565                                         g_list_free (trace_ips);
566                                         return FALSE;
567                                 }
568                         }
569                         
570                         m = lmf->method;
571
572                         if (test_only) {
573                                 char  *strace; 
574                                 char  *tmp;
575
576                                 trace_ips = g_list_append (trace_ips, lmf->method->info);
577
578                                 if (!((MonoException*)obj)->stack_trace)
579                                         strace = g_strdup ("");
580                                 else
581                                         strace = mono_string_to_utf8 (((MonoException*)obj)->stack_trace);
582
583                                 tmp = g_strdup_printf ("%sin (unmanaged) %s\n", strace, mono_method_full_name (m, TRUE));
584
585                                 g_free (strace);
586
587                                 ((MonoException*)obj)->stack_trace = mono_string_new (domain, tmp);
588                                 g_free (tmp);
589                         }
590
591                         ctx->SC_ESI = lmf->esi;
592                         ctx->SC_EDI = lmf->edi;
593                         ctx->SC_EBX = lmf->ebx;
594                         ctx->SC_EBP = lmf->ebp;
595                         ctx->SC_EIP = lmf->eip;
596                         ctx->SC_ESP = (unsigned long)&lmf->eip;
597
598                         lmf = lmf->previous_lmf;
599
600                         if (ctx->SC_EBP >= (unsigned)end_of_stack) {
601                                 if (!test_only) {
602                                         jit_tls->lmf = lmf;
603                                         cleanup (obj);
604                                         g_assert_not_reached ();
605                                 } else {
606                                         ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
607                                         g_list_free (trace_ips);
608                                         return FALSE;
609                                 }
610                         }
611                 }
612         }
613
614         g_assert_not_reached ();
615 }
616
617 static void
618 throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsigned long ebx,
619                  unsigned long esi, unsigned long edi, unsigned long ebp, MonoObject *exc,
620                  unsigned long eip,  unsigned long esp)
621 {
622         static void (*restore_context) (struct sigcontext *);
623         struct sigcontext ctx;
624
625         if (!restore_context)
626                 restore_context = arch_get_restore_context ();
627
628         /* adjust eip so that it point to the call instruction */
629         eip -= 5;
630
631         ctx.SC_ESP = esp;
632         ctx.SC_EIP = eip;
633         ctx.SC_EBP = ebp;
634         ctx.SC_EDI = edi;
635         ctx.SC_ESI = esi;
636         ctx.SC_EBX = ebx;
637         ctx.SC_EDX = edx;
638         ctx.SC_ECX = ecx;
639         ctx.SC_EAX = eax;
640         
641         arch_handle_exception (&ctx, exc, FALSE);
642         restore_context (&ctx);
643
644         g_assert_not_reached ();
645 }
646
647 /**
648  * arch_get_throw_exception:
649  *
650  * Returns a function pointer which can be used to raise 
651  * exceptions. The returned function has the following 
652  * signature: void (*func) (MonoException *exc); 
653  * For example to raise an arithmetic exception you can use:
654  *
655  * x86_push_imm (code, mono_get_exception_arithmetic ()); 
656  * x86_call_code (code, arch_get_throw_exception ()); 
657  *
658  */
659 gpointer 
660 arch_get_throw_exception (void)
661 {
662         static guint8 start [24];
663         static int inited = 0;
664         guint8 *code;
665
666         if (inited)
667                 return start;
668
669         inited = 1;
670         code = start;
671
672         x86_push_reg (code, X86_ESP);
673         x86_push_membase (code, X86_ESP, 4); /* IP */
674         x86_push_membase (code, X86_ESP, 12); /* exception */
675         x86_push_reg (code, X86_EBP);
676         x86_push_reg (code, X86_EDI);
677         x86_push_reg (code, X86_ESI);
678         x86_push_reg (code, X86_EBX);
679         x86_push_reg (code, X86_EDX);
680         x86_push_reg (code, X86_ECX);
681         x86_push_reg (code, X86_EAX);
682         x86_call_code (code, throw_exception);
683         /* we should never reach this breakpoint */
684         x86_breakpoint (code);
685
686         g_assert ((code - start) < 24);
687         return start;
688 }
689
690 /**
691  * arch_get_throw_exception_by_name:
692  *
693  * Returns a function pointer which can be used to raise 
694  * corlib exceptions. The returned function has the following 
695  * signature: void (*func) (char *exc_name); 
696  * For example to raise an arithmetic exception you can use:
697  *
698  * x86_push_imm (code, "ArithmeticException"); 
699  * x86_call_code (code, arch_get_throw_exception ()); 
700  *
701  */
702 gpointer 
703 arch_get_throw_exception_by_name ()
704 {
705         static guint8 start [32];
706         static int inited = 0;
707         guint8 *code;
708
709         if (inited)
710                 return start;
711
712         inited = 1;
713         code = start;
714
715         /* fixme: we do not save EAX, EDX, ECD - unsure if we need that */
716
717         x86_push_membase (code, X86_ESP, 4); /* exception name */
718         x86_push_imm (code, "System");
719         x86_push_imm (code, mono_defaults.exception_class->image);
720         x86_call_code (code, mono_exception_from_name);
721         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
722         /* save the newly create object (overwrite exception name)*/
723         x86_mov_membase_reg (code, X86_ESP, 4, X86_EAX, 4);
724         x86_jump_code (code, arch_get_throw_exception ());
725
726         g_assert ((code - start) < 32);
727
728         return start;
729 }