2004-04-29 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mono / mini / exceptions-x86.c
1 /*
2  * exceptions-x86.c: exception support for x86
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 #include <string.h>
14
15 #include <mono/arch/x86/x86-codegen.h>
16 #include <mono/metadata/appdomain.h>
17 #include <mono/metadata/tabledefs.h>
18 #include <mono/metadata/threads.h>
19 #include <mono/metadata/debug-helpers.h>
20 #include <mono/metadata/exception.h>
21 #include <mono/metadata/gc-internal.h>
22 #include <mono/metadata/mono-debug.h>
23
24 #include "mini.h"
25 #include "mini-x86.h"
26
27 #ifdef PLATFORM_WIN32
28
29 #include <windows.h>
30
31 /* use SIG* defines if possible */
32 #ifdef HAVE_SIGNAL_H
33 #include <signal.h>
34 #endif
35
36 /* sigcontext surrogate */
37 struct sigcontext {
38         unsigned int eax;
39         unsigned int ebx;
40         unsigned int ecx;
41         unsigned int edx;
42         unsigned int ebp;
43         unsigned int esp;
44         unsigned int esi;
45         unsigned int edi;
46         unsigned int eip;
47 };
48
49
50 typedef void (* MonoW32ExceptionHandler) (int);
51 void win32_seh_init(void);
52 void win32_seh_cleanup(void);
53 void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler);
54
55 #ifndef SIGFPE
56 #define SIGFPE 4
57 #endif
58
59 #ifndef SIGILL
60 #define SIGILL 8
61 #endif
62
63 #ifndef SIGSEGV
64 #define SIGSEGV 11
65 #endif
66
67 LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep);
68
69 static MonoW32ExceptionHandler fpe_handler;
70 static MonoW32ExceptionHandler ill_handler;
71 static MonoW32ExceptionHandler segv_handler;
72
73 static LPTOP_LEVEL_EXCEPTION_FILTER old_handler;
74
75 #define W32_SEH_HANDLE_EX(_ex) \
76         if (_ex##_handler) _ex##_handler((int)sctx)
77
78 /*
79  * Unhandled Exception Filter
80  * Top-level per-process exception handler.
81  */
82 LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep)
83 {
84         EXCEPTION_RECORD* er;
85         CONTEXT* ctx;
86         struct sigcontext* sctx;
87         LONG res;
88
89         res = EXCEPTION_CONTINUE_EXECUTION;
90
91         er = ep->ExceptionRecord;
92         ctx = ep->ContextRecord;
93         sctx = g_malloc(sizeof(struct sigcontext));
94
95         /* Copy Win32 context to UNIX style context */
96         sctx->eax = ctx->Eax;
97         sctx->ebx = ctx->Ebx;
98         sctx->ecx = ctx->Ecx;
99         sctx->edx = ctx->Edx;
100         sctx->ebp = ctx->Ebp;
101         sctx->esp = ctx->Esp;
102         sctx->esi = ctx->Esi;
103         sctx->edi = ctx->Edi;
104         sctx->eip = ctx->Eip;
105
106         switch (er->ExceptionCode) {
107         case EXCEPTION_ACCESS_VIOLATION:
108                 W32_SEH_HANDLE_EX(segv);
109                 break;
110         case EXCEPTION_ILLEGAL_INSTRUCTION:
111                 W32_SEH_HANDLE_EX(ill);
112                 break;
113         case EXCEPTION_INT_DIVIDE_BY_ZERO:
114         case EXCEPTION_INT_OVERFLOW:
115         case EXCEPTION_FLT_DIVIDE_BY_ZERO:
116         case EXCEPTION_FLT_OVERFLOW:
117         case EXCEPTION_FLT_UNDERFLOW:
118         case EXCEPTION_FLT_INEXACT_RESULT:
119                 W32_SEH_HANDLE_EX(fpe);
120                 break;
121         default:
122                 break;
123         }
124
125         /* Copy context back */
126         ctx->Eax = sctx->eax;
127         ctx->Ebx = sctx->ebx;
128         ctx->Ecx = sctx->ecx;
129         ctx->Edx = sctx->edx;
130         ctx->Ebp = sctx->ebp;
131         ctx->Esp = sctx->esp;
132         ctx->Esi = sctx->esi;
133         ctx->Edi = sctx->edi;
134         ctx->Eip = sctx->eip;
135
136         return res;
137 }
138
139 void win32_seh_init()
140 {
141         old_handler = SetUnhandledExceptionFilter(seh_handler);
142 }
143
144 void win32_seh_cleanup()
145 {
146         if (old_handler) SetUnhandledExceptionFilter(old_handler);
147 }
148
149 void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler)
150 {
151         switch (type) {
152         case SIGFPE:
153                 fpe_handler = handler;
154                 break;
155         case SIGILL:
156                 ill_handler = handler;
157                 break;
158         case SIGSEGV:
159                 segv_handler = handler;
160                 break;
161         default:
162                 break;
163         }
164 }
165
166 #endif /* PLATFORM_WIN32 */
167
168
169 #ifdef MONO_USE_EXC_TABLES
170
171 /*************************************/
172 /*    STACK UNWINDING STUFF          */
173 /*************************************/
174
175 /* These definitions are from unwind-dw2.c in glibc 2.2.5 */
176
177 /* For x86 */
178 #define DWARF_FRAME_REGISTERS 17
179
180 typedef struct frame_state
181 {
182   void *cfa;
183   void *eh_ptr;
184   long cfa_offset;
185   long args_size;
186   long reg_or_offset[DWARF_FRAME_REGISTERS+1];
187   unsigned short cfa_reg;
188   unsigned short retaddr_column;
189   char saved[DWARF_FRAME_REGISTERS+1];
190 } frame_state;
191
192 static long
193 get_sigcontext_reg (struct sigcontext *ctx, int dwarf_regnum)
194 {
195         switch (dwarf_regnum) {
196         case X86_EAX:
197                 return ctx->SC_EAX;
198         case X86_EBX:
199                 return ctx->SC_EBX;
200         case X86_ECX:
201                 return ctx->SC_ECX;
202         case X86_EDX:
203                 return ctx->SC_EDX;
204         case X86_ESI:
205                 return ctx->SC_ESI;
206         case X86_EDI:
207                 return ctx->SC_EDI;
208         case X86_EBP:
209                 return ctx->SC_EBP;
210         case X86_ESP:
211                 return ctx->SC_ESP;
212         default:
213                 g_assert_not_reached ();
214         }
215
216         return 0;
217 }
218
219 static void
220 set_sigcontext_reg (struct sigcontext *ctx, int dwarf_regnum, long value)
221 {
222         switch (dwarf_regnum) {
223         case X86_EAX:
224                 ctx->SC_EAX = value;
225                 break;
226         case X86_EBX:
227                 ctx->SC_EBX = value;
228                 break;
229         case X86_ECX:
230                 ctx->SC_ECX = value;
231                 break;
232         case X86_EDX:
233                 ctx->SC_EDX = value;
234                 break;
235         case X86_ESI:
236                 ctx->SC_ESI = value;
237                 break;
238         case X86_EDI:
239                 ctx->SC_EDI = value;
240                 break;
241         case X86_EBP:
242                 ctx->SC_EBP = value;
243                 break;
244         case X86_ESP:
245                 ctx->SC_ESP = value;
246                 break;
247         case 8:
248                 ctx->SC_EIP = value;
249                 break;
250         default:
251                 g_assert_not_reached ();
252         }
253 }
254
255 typedef struct frame_state * (*framesf) (void *, struct frame_state *);
256
257 static framesf frame_state_for = NULL;
258
259 static gboolean inited = FALSE;
260
261 typedef char ** (*get_backtrace_symbols_type) (void *__const *__array, int __size);
262
263 static get_backtrace_symbols_type get_backtrace_symbols = NULL;
264
265 static void
266 init_frame_state_for (void)
267 {
268         GModule *module;
269
270         /*
271          * There are two versions of __frame_state_for: one in libgcc.a and the
272          * other in glibc.so. We need the version from glibc.
273          * For more info, see this:
274          * http://gcc.gnu.org/ml/gcc/2002-08/msg00192.html
275          */
276         if ((module = g_module_open ("libc.so.6", G_MODULE_BIND_LAZY))) {
277         
278                 if (!g_module_symbol (module, "__frame_state_for", (gpointer*)&frame_state_for))
279                         frame_state_for = NULL;
280
281                 if (!g_module_symbol (module, "backtrace_symbols", (gpointer*)&get_backtrace_symbols)) {
282                         get_backtrace_symbols = NULL;
283                         frame_state_for = NULL;
284                 }
285
286                 g_module_close (module);
287         }
288
289         inited = TRUE;
290 }
291
292 /* mono_arch_has_unwind_info:
293  *
294  * Tests if a function has an DWARF exception table able to restore
295  * all caller saved registers. 
296  */
297 gboolean
298 mono_arch_has_unwind_info (gconstpointer addr)
299 {
300         struct frame_state state_in;
301         struct frame_state *res;
302
303         if (!inited) 
304                 init_frame_state_for ();
305         
306         if (!frame_state_for)
307                 return FALSE;
308
309         g_assert (addr);
310
311         memset (&state_in, 0, sizeof (state_in));
312
313         /* offset 10 is just a guess, but it works for all methods tested */
314         if ((res = frame_state_for ((char *)addr + 10, &state_in))) {
315
316                 if (res->saved [X86_EBX] == 1 &&
317                     res->saved [X86_EDI] == 1 &&
318                     res->saved [X86_EBP] == 1 &&
319                     res->saved [X86_ESI] == 1)
320                         return TRUE;
321         }
322
323         return FALSE;
324 }
325
326 struct stack_frame
327 {
328   void *next;
329   void *return_address;
330 };
331
332 static MonoJitInfo *
333 x86_unwind_native_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, struct sigcontext *ctx, 
334                          struct sigcontext *new_ctx, MonoLMF *lmf, char **trace)
335 {
336         struct stack_frame *frame;
337         gpointer max_stack;
338         MonoJitInfo *ji;
339         struct frame_state state_in;
340         struct frame_state *res;
341
342         if (trace)
343                 *trace = NULL;
344
345         if (!inited) 
346                 init_frame_state_for ();
347
348         if (!frame_state_for)
349                 return FALSE;
350
351         frame = MONO_CONTEXT_GET_BP (ctx);
352
353         max_stack = lmf && lmf->method ? lmf : jit_tls->end_of_stack;
354
355         *new_ctx = *ctx;
356
357         memset (&state_in, 0, sizeof (state_in));
358
359         while ((gpointer)frame->next < (gpointer)max_stack) {
360                 gpointer ip, addr = frame->return_address;
361                 void *cfa;
362                 char *tmp, **symbols;
363
364                 if (trace) {
365                         ip = MONO_CONTEXT_GET_IP (new_ctx);
366                         symbols = get_backtrace_symbols (&ip, 1);
367                         if (*trace)
368                                 tmp = g_strdup_printf ("%s\nin (unmanaged) %s", *trace, symbols [0]);
369                         else
370                                 tmp = g_strdup_printf ("in (unmanaged) %s", symbols [0]);
371
372                         free (symbols);
373                         g_free (*trace);
374                         *trace = tmp;
375                 }
376
377                 if ((res = frame_state_for (addr, &state_in))) {        
378                         int i;
379
380                         cfa = (gint8*) (get_sigcontext_reg (new_ctx, res->cfa_reg) + res->cfa_offset);
381                         frame = (struct stack_frame *)((gint8*)cfa - 8);
382                         for (i = 0; i < DWARF_FRAME_REGISTERS + 1; i++) {
383                                 int how = res->saved[i];
384                                 long val;
385                                 g_assert ((how == 0) || (how == 1));
386                         
387                                 if (how == 1) {
388                                         val = * (long*) ((gint8*)cfa + res->reg_or_offset[i]);
389                                         set_sigcontext_reg (new_ctx, i, val);
390                                 }
391                         }
392                         new_ctx->SC_ESP = (long)cfa;
393
394                         if (res->saved [X86_EBX] == 1 &&
395                             res->saved [X86_EDI] == 1 &&
396                             res->saved [X86_EBP] == 1 &&
397                             res->saved [X86_ESI] == 1 &&
398                             (ji = mono_jit_info_table_find (domain, frame->return_address))) {
399                                 //printf ("FRAME CFA %s\n", mono_method_full_name (ji->method, TRUE));
400                                 return ji;
401                         }
402
403                 } else {
404                         //printf ("FRAME %p %p %p\n", frame, MONO_CONTEXT_GET_IP (new_ctx), mono_jit_info_table_find (domain, MONO_CONTEXT_GET_IP (new_ctx)));
405
406                         MONO_CONTEXT_SET_IP (new_ctx, frame->return_address);
407                         frame = frame->next;
408                         MONO_CONTEXT_SET_BP (new_ctx, frame);
409
410                         /* stop if !frame or when we detect an unexpected managed frame */
411                         if (!frame || mono_jit_info_table_find (domain, frame->return_address)) {
412                                 if (trace) {
413                                         g_free (*trace);
414                                         *trace = NULL;
415                                 }
416                                 return NULL;
417                         }
418                 }
419         }
420
421         //if (!lmf)
422         //g_assert_not_reached ();
423
424         if (trace) {
425                 g_free (*trace);
426                 *trace = NULL;
427         }
428         return NULL;
429 }
430
431 #endif
432
433 /*
434  * mono_arch_get_restore_context:
435  *
436  * Returns a pointer to a method which restores a previously saved sigcontext.
437  */
438 gpointer
439 mono_arch_get_restore_context (void)
440 {
441         static guint8 *start = NULL;
442         guint8 *code;
443
444         if (start)
445                 return start;
446
447         /* restore_contect (struct sigcontext *ctx) */
448         /* we do not restore X86_EAX, X86_EDX */
449
450         start = code = g_malloc (1024);
451         
452         /* load ctx */
453         x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
454
455         /* get return address, stored in EDX */
456         x86_mov_reg_membase (code, X86_EDX, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EIP), 4);
457         /* restore EBX */
458         x86_mov_reg_membase (code, X86_EBX, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EBX), 4);
459         /* restore EDI */
460         x86_mov_reg_membase (code, X86_EDI, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EDI), 4);
461         /* restore ESI */
462         x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_ESI), 4);
463         /* restore ESP */
464         x86_mov_reg_membase (code, X86_ESP, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_ESP), 4);
465         /* restore EBP */
466         x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EBP), 4);
467
468         /* jump to the saved IP */
469         x86_jump_reg (code, X86_EDX);
470
471         return start;
472 }
473
474 /*
475  * mono_arch_get_call_filter:
476  *
477  * Returns a pointer to a method which calls an exception filter. We
478  * also use this function to call finally handlers (we pass NULL as 
479  * @exc object in this case).
480  */
481 gpointer
482 mono_arch_get_call_filter (void)
483 {
484         static guint8 start [64];
485         static int inited = 0;
486         guint8 *code;
487
488         if (inited)
489                 return start;
490
491         inited = 1;
492         /* call_filter (struct sigcontext *ctx, unsigned long eip) */
493         code = start;
494
495         x86_push_reg (code, X86_EBP);
496         x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
497         x86_push_reg (code, X86_EBX);
498         x86_push_reg (code, X86_EDI);
499         x86_push_reg (code, X86_ESI);
500
501         /* load ctx */
502         x86_mov_reg_membase (code, X86_EAX, X86_EBP, 8, 4);
503         /* load eip */
504         x86_mov_reg_membase (code, X86_ECX, X86_EBP, 12, 4);
505         /* save EBP */
506         x86_push_reg (code, X86_EBP);
507
508         /* set new EBP */
509         x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EBP), 4);
510         /* restore registers used by global register allocation (EBX & ESI) */
511         x86_mov_reg_membase (code, X86_EBX, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EBX), 4);
512         x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_ESI), 4);
513         x86_mov_reg_membase (code, X86_EDI, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EDI), 4);
514
515         /* call the handler */
516         x86_call_reg (code, X86_ECX);
517
518         /* restore EBP */
519         x86_pop_reg (code, X86_EBP);
520
521         /* restore saved regs */
522         x86_pop_reg (code, X86_ESI);
523         x86_pop_reg (code, X86_EDI);
524         x86_pop_reg (code, X86_EBX);
525         x86_leave (code);
526         x86_ret (code);
527
528         g_assert ((code - start) < 64);
529         return start;
530 }
531
532 static void
533 throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsigned long ebx,
534                  unsigned long esi, unsigned long edi, unsigned long ebp, MonoObject *exc,
535                  unsigned long eip,  unsigned long esp)
536 {
537         static void (*restore_context) (struct sigcontext *);
538         struct sigcontext ctx;
539
540         if (!restore_context)
541                 restore_context = mono_arch_get_restore_context ();
542
543         /* adjust eip so that it point into the call instruction */
544         eip -= 1;
545
546         /* Pop argument and return address */
547         ctx.SC_ESP = esp + (2 * sizeof (gpointer));
548         ctx.SC_EIP = eip;
549         ctx.SC_EBP = ebp;
550         ctx.SC_EDI = edi;
551         ctx.SC_ESI = esi;
552         ctx.SC_EBX = ebx;
553         ctx.SC_EDX = edx;
554         ctx.SC_ECX = ecx;
555         ctx.SC_EAX = eax;
556         
557         mono_arch_handle_exception (&ctx, exc, FALSE);
558         restore_context (&ctx);
559
560         g_assert_not_reached ();
561 }
562
563 /**
564  * mono_arch_get_throw_exception:
565  *
566  * Returns a function pointer which can be used to raise 
567  * exceptions. The returned function has the following 
568  * signature: void (*func) (MonoException *exc); 
569  * For example to raise an arithmetic exception you can use:
570  *
571  * x86_push_imm (code, mono_get_exception_arithmetic ()); 
572  * x86_call_code (code, arch_get_throw_exception ()); 
573  *
574  */
575 gpointer 
576 mono_arch_get_throw_exception (void)
577 {
578         static guint8 start [24];
579         static int inited = 0;
580         guint8 *code;
581
582         if (inited)
583                 return start;
584
585         inited = 1;
586         code = start;
587
588         x86_push_reg (code, X86_ESP);
589         x86_push_membase (code, X86_ESP, 4); /* IP */
590         x86_push_membase (code, X86_ESP, 12); /* exception */
591         x86_push_reg (code, X86_EBP);
592         x86_push_reg (code, X86_EDI);
593         x86_push_reg (code, X86_ESI);
594         x86_push_reg (code, X86_EBX);
595         x86_push_reg (code, X86_EDX);
596         x86_push_reg (code, X86_ECX);
597         x86_push_reg (code, X86_EAX);
598         x86_call_code (code, throw_exception);
599         /* we should never reach this breakpoint */
600         x86_breakpoint (code);
601
602         g_assert ((code - start) < 24);
603         return start;
604 }
605
606 /**
607  * mono_arch_get_throw_exception_by_name:
608  *
609  * Returns a function pointer which can be used to raise 
610  * corlib exceptions. The returned function has the following 
611  * signature: void (*func) (char *exc_name); 
612  * For example to raise an arithmetic exception you can use:
613  *
614  * x86_push_imm (code, "ArithmeticException"); 
615  * x86_call_code (code, arch_get_throw_exception_by_name ()); 
616  *
617  */
618 gpointer 
619 mono_arch_get_throw_exception_by_name (void)
620 {
621         static guint8 start [32];
622         static int inited = 0;
623         guint8 *code;
624
625         if (inited)
626                 return start;
627
628         inited = 1;
629         code = start;
630
631         x86_push_membase (code, X86_ESP, 4); /* exception name */
632         x86_push_imm (code, "System");
633         x86_push_imm (code, mono_defaults.exception_class->image);
634         x86_call_code (code, mono_exception_from_name);
635         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
636         /* save the newly create object (overwrite exception name)*/
637         x86_mov_membase_reg (code, X86_ESP, 4, X86_EAX, 4);
638         x86_jump_code (code, mono_arch_get_throw_exception ());
639
640         g_assert ((code - start) < 32);
641
642         return start;
643 }
644
645 /* mono_arch_find_jit_info:
646  *
647  * This function is used to gather information from @ctx. It return the 
648  * MonoJitInfo of the corresponding function, unwinds one stack frame and
649  * stores the resulting context into @new_ctx. It also stores a string 
650  * describing the stack location into @trace (if not NULL), and modifies
651  * the @lmf if necessary. @native_offset return the IP offset from the 
652  * start of the function or -1 if that info is not available.
653  */
654 MonoJitInfo *
655 mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx, 
656                          MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
657                          gboolean *managed)
658 {
659         MonoJitInfo *ji;
660         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
661
662         /* Avoid costly table lookup during stack overflow */
663         if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
664                 ji = prev_ji;
665         else
666                 ji = mono_jit_info_table_find (domain, ip);
667
668         if (trace)
669                 *trace = NULL;
670
671         if (native_offset)
672                 *native_offset = -1;
673
674         if (managed)
675                 *managed = FALSE;
676
677         if (ji != NULL) {
678                 char *source_location, *tmpaddr, *fname;
679                 gint32 address, iloffset;
680                 int offset;
681
682                 *new_ctx = *ctx;
683
684                 address = (char *)ip - (char *)ji->code_start;
685
686                 if (native_offset)
687                         *native_offset = address;
688
689                 if (managed)
690                         if (!ji->method->wrapper_type)
691                                 *managed = TRUE;
692
693                 if (trace) {
694                         source_location = mono_debug_source_location_from_address (ji->method, address, NULL, domain);
695                         iloffset = mono_debug_il_offset_from_address (ji->method, address, domain);
696
697                         if (iloffset < 0)
698                                 tmpaddr = g_strdup_printf ("<0x%05x>", address);
699                         else
700                                 tmpaddr = g_strdup_printf ("[0x%05x]", iloffset);
701                 
702                         fname = mono_method_full_name (ji->method, TRUE);
703
704                         if (source_location)
705                                 *trace = g_strdup_printf ("in %s (at %s) %s", tmpaddr, source_location, fname);
706                         else
707                                 *trace = g_strdup_printf ("in %s %s", tmpaddr, fname);
708
709                         g_free (fname);
710                         g_free (source_location);
711                         g_free (tmpaddr);
712                 }
713
714                 /*
715                  * Some managed methods like pinvoke wrappers might have save_lmf set.
716                  * In this case, register save/restore code is not generated by the 
717                  * JIT, so we have to restore callee saved registers from the lmf.
718                  */
719                 if (ji->method->save_lmf) {
720                         /* 
721                          * We only need to do this if the exception was raised in managed
722                          * code, since otherwise the lmf was already popped of the stack.
723                          */
724                         if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
725                                 new_ctx->SC_ESI = (*lmf)->esi;
726                                 new_ctx->SC_EDI = (*lmf)->edi;
727                                 new_ctx->SC_EBX = (*lmf)->ebx;
728                         }
729                 }
730                 else {
731                         offset = -1;
732                         /* restore caller saved registers */
733                         if (ji->used_regs & X86_EBX_MASK) {
734                                 new_ctx->SC_EBX = *((int *)ctx->SC_EBP + offset);
735                                 offset--;
736                         }
737                         if (ji->used_regs & X86_EDI_MASK) {
738                                 new_ctx->SC_EDI = *((int *)ctx->SC_EBP + offset);
739                                 offset--;
740                         }
741                         if (ji->used_regs & X86_ESI_MASK) {
742                                 new_ctx->SC_ESI = *((int *)ctx->SC_EBP + offset);
743                         }
744                 }
745
746                 if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
747                         /* remove any unused lmf */
748                         *lmf = (*lmf)->previous_lmf;
749                 }
750
751                 /* Pop EBP and the return address */
752                 new_ctx->SC_ESP = ctx->SC_EBP + (2 * sizeof (gpointer));
753                 /* we substract 1, so that the IP points into the call instruction */
754                 new_ctx->SC_EIP = *((int *)ctx->SC_EBP + 1) - 1;
755                 new_ctx->SC_EBP = *((int *)ctx->SC_EBP);
756
757                 *res = *ji;
758                 return res;
759 #ifdef MONO_USE_EXC_TABLES
760         } else if ((ji = x86_unwind_native_frame (domain, jit_tls, ctx, new_ctx, *lmf, trace))) {
761                 *res = *ji;             
762                 return res;
763 #endif
764         } else if (*lmf) {
765                 
766                 *new_ctx = *ctx;
767
768                 if (!(*lmf)->method)
769                         return (gpointer)-1;
770
771                 if (trace)
772                         *trace = g_strdup_printf ("in (unmanaged) %s", mono_method_full_name ((*lmf)->method, TRUE));
773                 
774                 if ((ji = mono_jit_info_table_find (domain, (gpointer)(*lmf)->eip))) {
775                         *res = *ji;
776                 } else {
777                         memset (res, 0, sizeof (MonoJitInfo));
778                         res->method = (*lmf)->method;
779                 }
780
781                 new_ctx->SC_ESI = (*lmf)->esi;
782                 new_ctx->SC_EDI = (*lmf)->edi;
783                 new_ctx->SC_EBX = (*lmf)->ebx;
784                 new_ctx->SC_EBP = (*lmf)->ebp;
785                 new_ctx->SC_EIP = (*lmf)->eip;
786                 /* the lmf is always stored on the stack, so the following
787                  * expression points to a stack location which can be used as ESP */
788                 new_ctx->SC_ESP = (unsigned long)&((*lmf)->eip);
789
790                 *lmf = (*lmf)->previous_lmf;
791
792                 return res;
793                 
794         }
795
796         return NULL;
797 }
798
799 /**
800  * mono_arch_handle_exception:
801  *
802  * @ctx: saved processor state
803  * @obj: the exception object
804  */
805 gboolean
806 mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only)
807 {
808         return mono_handle_exception (sigctx, obj, test_only);
809 }