2 * exceptions-s390.c: exception support for S/390
5 * Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com)
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Paolo Molaro (lupus@ximian.com)
9 * (C) 2001 Ximian, Inc.
17 #include <mono/arch/s390/s390-codegen.h>
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/tabledefs.h>
20 #include <mono/metadata/threads.h>
21 #include <mono/metadata/debug-helpers.h>
22 #include <mono/metadata/exception.h>
23 #include <mono/metadata/mono-debug.h>
26 #include "mini-s390.h"
28 typedef struct sigcontext MonoContext;
33 int sc_onstack; // sigstack state to restore
34 int sc_mask; // signal mask to restore
36 int sc_psw; // processor status word
37 int sc_sp; // stack pointer if sc_regs == NULL
38 void *sc_regs; // (kernel private) saved state
43 sigset_t uc_sigmask; // signal mask used by this context
44 stack_t uc_stack; // stack used by this context
45 struct ucontext *uc_link; // pointer to resuming context
46 size_t uc_mcsize; // size of the machine context passed in
47 mcontext_t uc_mcontext; // machine specific context
50 typedef struct s390_exception_state {
51 unsigned long dar; // Fault registers for coredump
53 unsigned long exception;// number of s390 exception taken
54 unsigned long pad0; // align to 16 bytes
56 unsigned long pad1[4]; // space in PCB "just in case"
57 } s390_exception_state_t;
59 typedef struct s390_float_state {
62 unsigned int fpc; // floating point status register
65 typedef struct s390_thread_state {
66 unsigned int ip; // Instruction address register (PC)
68 } s390_thread_state_t;
71 s390_exception_state_t es;
72 s390_thread_state_t ss;
73 s390_float_state_t fs;
76 typedef struct mcontext * mcontext_t;
80 #define MONO_CONTEXT_SET_IP(ctx,ip) do { \
81 (ctx)->sregs->regs.psw.addr = (unsigned long)ip;\
83 #define MONO_CONTEXT_SET_BP(ctx,bp) do { (ctx)->sregs->regs.gprs[15] = (unsigned long)bp; } while (0);
85 #define MONO_CONTEXT_GET_IP(ctx) ((gpointer)((ctx)->sregs->regs.psw.addr))
86 #define MONO_CONTEXT_GET_BP(ctx) ((gpointer)((ctx)->sregs->regs.gprs[15]))
93 /* disbale this for now */
94 #undef MONO_USE_EXC_TABLES
96 #ifdef MONO_USE_EXC_TABLES
98 /*************************************/
99 /* STACK UNWINDING STUFF */
100 /*************************************/
102 /* These definitions are from unwind-dw2.c in glibc 2.2.5 */
105 #define DWARF_FRAME_REGISTERS 17
107 typedef struct frame_state
113 long reg_or_offset[DWARF_FRAME_REGISTERS+1];
114 unsigned short cfa_reg;
115 unsigned short retaddr_column;
116 char saved[DWARF_FRAME_REGISTERS+1];
122 get_sigcontext_reg (struct sigcontext *ctx, int dwarf_regnum)
124 switch (dwarf_regnum) {
142 g_assert_not_reached ();
149 set_sigcontext_reg (struct sigcontext *ctx, int dwarf_regnum, long value)
151 switch (dwarf_regnum) {
180 g_assert_not_reached ();
184 typedef struct frame_state * (*framesf) (void *, struct frame_state *);
186 static framesf frame_state_for = NULL;
188 static gboolean inited = FALSE;
190 typedef char ** (*get_backtrace_symbols_type) (void *__const *__array, int __size);
192 static get_backtrace_symbols_type get_backtrace_symbols = NULL;
195 init_frame_state_for (void)
200 * There are two versions of __frame_state_for: one in libgcc.a and the
201 * other in glibc.so. We need the version from glibc.
202 * For more info, see this:
203 * http://gcc.gnu.org/ml/gcc/2002-08/msg00192.html
205 if ((module = g_module_open ("libc.so.6", G_MODULE_BIND_LAZY))) {
207 if (!g_module_symbol (module, "__frame_state_for", (gpointer*)&frame_state_for))
208 frame_state_for = NULL;
210 if (!g_module_symbol (module, "backtrace_symbols", (gpointer*)&get_backtrace_symbols)) {
211 get_backtrace_symbols = NULL;
212 frame_state_for = NULL;
215 g_module_close (module);
223 gboolean mono_arch_handle_exception (struct sigcontext *ctx, gpointer obj, gboolean test_only);
225 /* mono_arch_has_unwind_info:
227 * Tests if a function has an DWARF exception table able to restore
228 * all caller saved registers.
231 mono_arch_has_unwind_info (MonoMethod *method)
234 struct frame_state state_in;
235 struct frame_state *res;
238 init_frame_state_for ();
240 if (!frame_state_for)
243 g_assert (method->addr);
245 memset (&state_in, 0, sizeof (state_in));
247 /* offset 10 is just a guess, but it works for all methods tested */
248 if ((res = frame_state_for ((char *)method->addr + 10, &state_in))) {
250 if (res->saved [X86_EBX] != 1 ||
251 res->saved [X86_EDI] != 1 ||
252 res->saved [X86_EBP] != 1 ||
253 res->saved [X86_ESI] != 1) {
268 void *return_address;
272 s390_unwind_native_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, struct sigcontext *ctx,
273 struct sigcontext *new_ctx, MonoLMF *lmf, char **trace)
276 struct stack_frame *frame;
279 struct frame_state state_in;
280 struct frame_state *res;
286 init_frame_state_for ();
288 if (!frame_state_for)
291 frame = MONO_CONTEXT_GET_BP (ctx);
293 max_stack = lmf && lmf->method ? lmf : jit_tls->end_of_stack;
297 memset (&state_in, 0, sizeof (state_in));
299 while ((gpointer)frame->next < (gpointer)max_stack) {
300 gpointer ip, addr = frame->return_address;
302 char *tmp, **symbols;
305 ip = MONO_CONTEXT_GET_IP (new_ctx);
306 symbols = get_backtrace_symbols (&ip, 1);
308 tmp = g_strdup_printf ("%s\nin (unmanaged) %s", *trace, symbols [0]);
310 tmp = g_strdup_printf ("in (unmanaged) %s", symbols [0]);
317 if ((res = frame_state_for (addr, &state_in))) {
320 cfa = (gint8*) (get_sigcontext_reg (new_ctx, res->cfa_reg) + res->cfa_offset);
321 frame = (struct stack_frame *)((gint8*)cfa - 8);
322 for (i = 0; i < DWARF_FRAME_REGISTERS + 1; i++) {
323 int how = res->saved[i];
325 g_assert ((how == 0) || (how == 1));
328 val = * (long*) ((gint8*)cfa + res->reg_or_offset[i]);
329 set_sigcontext_reg (new_ctx, i, val);
332 new_ctx->SC_ESP = (long)cfa;
334 if (res->saved [X86_EBX] == 1 &&
335 res->saved [X86_EDI] == 1 &&
336 res->saved [X86_EBP] == 1 &&
337 res->saved [X86_ESI] == 1 &&
338 (ji = mono_jit_info_table_find (domain, frame->return_address))) {
339 //printf ("FRAME CFA %s\n", mono_method_full_name (ji->method, TRUE));
344 //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)));
346 MONO_CONTEXT_SET_IP (new_ctx, frame->return_address);
348 MONO_CONTEXT_SET_BP (new_ctx, frame);
350 /* stop if !frame or when we detect an unexpected managed frame */
351 if (!frame || mono_jit_info_table_find (domain, frame->return_address)) {
362 //g_assert_not_reached ();
375 * arch_get_restore_context:
377 * Returns a pointer to a method which restores a previously saved sigcontext.
380 arch_get_restore_context (void)
382 static guint8 *start = NULL;
389 /* restore_contect (struct sigcontext *ctx) */
390 /* we do not restore X86_EAX, X86_EDX */
392 start = code = g_malloc (1024);
395 x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
397 /* get return address, stored in EDX */
398 x86_mov_reg_membase (code, X86_EDX, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EIP), 4);
400 x86_mov_reg_membase (code, X86_EBX, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EBX), 4);
402 x86_mov_reg_membase (code, X86_EDI, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EDI), 4);
404 x86_mov_reg_membase (code, X86_ESI, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_ESI), 4);
406 x86_mov_reg_membase (code, X86_ESP, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_ESP), 4);
408 x86_mov_reg_membase (code, X86_EBP, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EBP), 4);
410 /* jump to the saved IP */
411 x86_jump_reg (code, X86_EDX);
418 * arch_get_call_filter:
420 * Returns a pointer to a method which calls an exception filter. We
421 * also use this function to call finally handlers (we pass NULL as
422 * @exc object in this case).
425 arch_get_call_filter (void)
427 static guint8 start [196];
428 static int inited = 0;
430 int alloc_size, pos, i;
436 /* call_filter (struct sigcontext *ctx, unsigned long eip, gpointer exc) */
439 s390_lr (code, s390_r0, s390_r14);
440 s390_st (code, s390_r0, 0, STK_BASE, S390_RET_ADDR_OFFSET);
441 alloc_size = S390_MINIMAL_STACK_SIZE + (sizeof (gulong) * 16 + sizeof (gdouble) * 14);
442 // align to S390_STACK_ALIGNMENT bytes
443 if (alloc_size & (S390_STACK_ALIGNMENT - 1))
444 alloc_size += S390_STACK_ALIGNMENT - (alloc_size & (S390_STACK_ALIGNMENT - 1));
445 s390_st (code, STK_BASE, 0, STK_BASE, 0);
446 s390_ahi (code, STK_BASE, -alloc_size);
447 /* save all the regs on the stack */
448 pos = S390_MINIMAL_STACK_SIZE;
449 s390_stm (code, s390_r6, s390_r14, STK_BASE, pos);
450 pos += sizeof (gulong) * 9;
451 for (i = 0; i < 16; ++i) {
452 s390_std (code, i, 0, STK_BASE, pos);
453 pos += sizeof (gdouble);
455 /* FIXME: restore all the regs from ctx (in r3) */
456 /* call handler at eip (r4) and set the first arg with the exception (r5) */
458 /* restore all the regs from the stack */
459 pos = S390_MINIMAL_STACK_SIZE;
460 s390_lm (code, s390_r6, s390_r14, STK_BASE, pos);
461 pos += sizeof (gulong) * 9;
462 for (i = 0; i < 16; ++i) {
463 s390_ld (code, i, 0,STK_BASE, pos);
464 pos += sizeof (gdouble);
466 s390_l (code, s390_r14, 0, STK_BASE, alloc_size + S390_RET_ADDR_OFFSET);
467 s390_ahi (code, STK_BASE, alloc_size);
469 g_assert ((code - start) < sizeof(start));
474 throw_exception (MonoObject *exc, unsigned long eip, unsigned long esp, gulong *int_regs, gdouble *fp_regs)
476 static void (*restore_context) (struct sigcontext *);
477 struct sigcontext ctx;
481 ctx.sregs = &ctxRegs;
483 if (!restore_context)
484 restore_context = arch_get_restore_context ();
486 /* adjust eip so that it point into the call instruction */
489 for (iReg = 0; iReg < 16; iReg++) {
490 ctx.sregs->regs.gprs[iReg] = int_regs[iReg];
491 ctx.sregs->fpregs.fprs[iReg] = fp_regs[iReg];
492 ctx.sregs->regs.acrs[iReg] = 0;
495 MONO_CONTEXT_SET_BP (&ctx, esp);
496 MONO_CONTEXT_SET_IP (&ctx, eip);
498 mono_arch_handle_exception (&ctx, exc, FALSE);
499 restore_context (&ctx);
501 g_assert_not_reached ();
505 * arch_get_throw_exception_generic:
507 * Returns a function pointer which can be used to raise
508 * exceptions. The returned function has the following
509 * signature: void (*func) (MonoException *exc); or
510 * void (*func) (char *exc_name);
514 mono_arch_get_throw_exception_generic (guint8 *start, int size, int by_name)
517 int alloc_size, pos, i, offset;
521 s390_stm (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
522 alloc_size = S390_MINIMAL_STACK_SIZE + (sizeof (gulong) * 16 + sizeof (gdouble) * 16);
523 // align to S390_STACK_ALIGNMENT bytes
524 if (alloc_size & (S390_STACK_ALIGNMENT - 1))
525 alloc_size += S390_STACK_ALIGNMENT - (alloc_size & (S390_STACK_ALIGNMENT - 1));
526 s390_lr (code, s390_r14, STK_BASE);
527 s390_ahi (code, STK_BASE, -alloc_size);
528 s390_st (code, s390_r14, 0, STK_BASE, 0);
531 s390_lr (code, s390_r4, s390_r2);
532 s390_bras (code, s390_r13, 6);
533 s390_word (code, mono_defaults.corlib);
534 s390_word (code, "System");
535 s390_l (code, s390_r2, 0, s390_r13, 0);
536 s390_l (code, s390_r3, 0, s390_r13, 4);
537 offset = (guint32) S390_RELATIVE(mono_exception_from_name, code);
538 s390_brasl(code, s390_r14, offset);
540 /* save the general registers on the stack */
541 pos = S390_MINIMAL_STACK_SIZE;
542 s390_stm (code, s390_r0, s390_r13, STK_BASE, pos);
543 s390_l (code, s390_r1, 0, STK_BASE, 0);
544 s390_lm (code, s390_r6, s390_r7, s390_r1, S390_RET_ADDR_OFFSET);
545 s390_stm (code, s390_r6, s390_r7, STK_BASE, pos+(14*sizeof(gulong)));
546 /* save the floating point registers */
547 pos += sizeof (gulong) * 9;
548 for (i = 0; i < 16; ++i) {
549 s390_std (code, i, 0,STK_BASE, pos);
550 pos += sizeof (gdouble);
552 /* call throw_exception (exc, ip, sp, int_regs, fp_regs) */
553 /* exc is already in place in r2 */
554 s390_lr (code, s390_r3, s390_r6); /* caller ip */
555 s390_lr (code, s390_r4, s390_r1); /* caller sp */
556 /* pointer to the saved int regs */
557 pos = S390_MINIMAL_STACK_SIZE;
558 s390_la (code, s390_r5, 0, STK_BASE, S390_MINIMAL_STACK_SIZE);
559 s390_la (code, s390_r6, 0, s390_r5, (sizeof(gulong) * 14));
560 offset = (guint32) S390_RELATIVE(throw_exception, code);
561 s390_brasl(code, s390_r14, offset);
562 /* we should never reach this breakpoint */
564 g_assert ((code - start) < size);
569 * arch_get_throw_exception:
571 * Returns a function pointer which can be used to raise
572 * exceptions. The returned function has the following
573 * signature: void (*func) (MonoException *exc);
574 * For example to raise an arithmetic exception you can use:
576 * x86_push_imm (code, mono_get_exception_arithmetic ());
577 * x86_call_code (code, arch_get_throw_exception ());
581 mono_arch_get_throw_exception (void)
583 static guint8 start [128];
584 static int inited = 0;
588 mono_arch_get_throw_exception_generic (start, sizeof (start), FALSE);
594 * arch_get_throw_exception_by_name:
596 * Returns a function pointer which can be used to raise
597 * corlib exceptions. The returned function has the following
598 * signature: void (*func) (char *exc_name);
599 * For example to raise an arithmetic exception you can use:
601 * x86_push_imm (code, "ArithmeticException");
602 * x86_call_code (code, arch_get_throw_exception_by_name ());
606 mono_arch_get_throw_exception_by_name (void)
608 static guint8 start [160];
609 static int inited = 0;
613 mono_arch_get_throw_exception_generic (start, sizeof (start), TRUE);
619 glist_to_array (GList *list)
621 MonoDomain *domain = mono_domain_get ();
628 len = g_list_length (list);
629 res = mono_array_new (domain, mono_defaults.int_class, len);
631 for (i = 0; list; list = list->next, i++)
632 mono_array_set (res, gpointer, i, list->data);
637 /* mono_arch_find_jit_info:
639 * This function is used to gather information from @ctx. It return the
640 * MonoJitInfo of the corresponding function, unwinds one stack frame and
641 * stores the resulting context into @new_ctx. It also stores a string
642 * describing the stack location into @trace (if not NULL), and modifies
643 * the @lmf if necessary. @native_offset return the IP offset from the
644 * start of the function or -1 if that info is not available.
647 mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoContext *ctx,
648 MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
652 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
655 MonoS390StackFrame *sframe;
657 ji = mono_jit_info_table_find (domain, ip);
669 char *source_location, *tmpaddr, *fname;
670 gint32 address, iloffset;
675 if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
676 /* remove any unused lmf */
677 *lmf = (*lmf)->previous_lmf;
680 address = (char *)ip - (char *)ji->code_start;
683 *native_offset = address;
686 if (!ji->method->wrapper_type)
690 source_location = mono_debug_source_location_from_address (ji->method, address, NULL, domain);
691 iloffset = mono_debug_il_offset_from_address (ji->method, address, domain);
694 tmpaddr = g_strdup_printf ("<0x%05x>", address);
696 tmpaddr = g_strdup_printf ("[0x%05x]", iloffset);
698 fname = mono_method_full_name (ji->method, TRUE);
701 *trace = g_strdup_printf ("in %s (at %s) %s", tmpaddr, source_location, fname);
703 *trace = g_strdup_printf ("in %s %s", tmpaddr, fname);
706 g_free (source_location);
711 /* restore caller saved registers */
712 if (ji->used_regs & X86_EBX_MASK) {
713 new_ctx->SC_EBX = *((int *)ctx->SC_EBP + offset);
716 if (ji->used_regs & X86_EDI_MASK) {
717 new_ctx->SC_EDI = *((int *)ctx->SC_EBP + offset);
720 if (ji->used_regs & X86_ESI_MASK) {
721 new_ctx->SC_ESI = *((int *)ctx->SC_EBP + offset);
724 new_ctx->SC_ESP = ctx->SC_EBP;
725 /* we substract 1, so that the IP points into the call instruction */
726 new_ctx->SC_EIP = *((int *)ctx->SC_EBP + 1) - 1;
727 new_ctx->SC_EBP = *((int *)ctx->SC_EBP);
729 sframe = (MonoS390StackFrame*)MONO_CONTEXT_GET_BP (ctx);
730 MONO_CONTEXT_SET_BP (new_ctx, sframe->sp);
731 MONO_CONTEXT_SET_IP (new_ctx, sframe->lr);
734 #ifdef MONO_USE_EXC_TABLES
735 } else if ((ji = s390_unwind_native_frame (domain, jit_tls, ctx, new_ctx, *lmf, trace))) {
747 *trace = g_strdup_printf ("in (unmanaged) %s", mono_method_full_name ((*lmf)->method, TRUE));
749 if ((ji = mono_jit_info_table_find (domain, (gpointer)(*lmf)->eip))) {
752 memset (res, 0, sizeof (MonoJitInfo));
753 res->method = (*lmf)->method;
757 new_ctx->SC_ESI = (*lmf)->esi;
758 new_ctx->SC_EDI = (*lmf)->edi;
759 new_ctx->SC_EBX = (*lmf)->ebx;
760 new_ctx->SC_EBP = (*lmf)->ebp;
761 new_ctx->SC_EIP = (*lmf)->eip;
762 /* the lmf is always stored on the stack, so the following
763 * expression points to a stack location which can be used as ESP */
764 new_ctx->SC_ESP = (unsigned long)&((*lmf)->eip);
766 sframe = (MonoS390StackFrame*)MONO_CONTEXT_GET_BP (ctx);
767 MONO_CONTEXT_SET_BP (new_ctx, sframe->sp);
768 MONO_CONTEXT_SET_IP (new_ctx, sframe->lr);
769 *lmf = (*lmf)->previous_lmf;
779 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
781 MonoDomain *domain = mono_domain_get ();
783 MonoArray *ta = exc->trace_ips;
786 len = mono_array_length (ta);
788 res = mono_array_new (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0);
790 for (i = skip; i < len; i++) {
792 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
793 gpointer ip = mono_array_get (ta, gpointer, i);
795 ji = mono_jit_info_table_find (domain, ip);
796 g_assert (ji != NULL);
798 sf->method = mono_method_get_object (domain, ji->method, NULL);
799 sf->native_offset = (char *)ip - (char *)ji->code_start;
801 sf->il_offset = mono_debug_il_offset_from_address (ji->method, sf->native_offset, domain);
803 if (need_file_info) {
806 filename = mono_debug_source_location_from_address (ji->method, sf->native_offset, &sf->line, domain);
808 sf->filename = filename? mono_string_new (domain, filename): NULL;
814 mono_array_set (res, gpointer, i, sf);
821 mono_jit_walk_stack (MonoStackWalk func, gpointer user_data) {
822 MonoDomain *domain = mono_domain_get ();
823 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
824 MonoLMF *lmf = jit_tls->lmf;
825 MonoJitInfo *ji, rji;
826 gint native_offset, il_offset;
828 MonoS390StackFrame *sframe;
830 MonoContext ctx, new_ctx;
832 __asm__ volatile("l %0,0(15)" : "=r" (sframe));
834 MONO_CONTEXT_SET_IP (&ctx, sframe->lr);
835 MONO_CONTEXT_SET_BP (&ctx, sframe->sp);
837 while (MONO_CONTEXT_GET_BP (&ctx) < jit_tls->end_of_stack) {
839 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
842 if (ji == (gpointer)-1)
845 il_offset = mono_debug_il_offset_from_address (ji->method, native_offset, domain);
847 if (func (ji->method, native_offset, il_offset, managed, user_data))
855 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
856 MonoReflectionMethod **method,
857 gint32 *iloffset, gint32 *native_offset,
858 MonoString **file, gint32 *line, gint32 *column)
860 MonoDomain *domain = mono_domain_get ();
861 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
862 MonoLMF *lmf = jit_tls->lmf;
863 MonoJitInfo *ji, rji;
864 MonoContext ctx, new_ctx;
866 MONO_CONTEXT_SET_IP (&ctx, ves_icall_get_frame_info);
867 MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (0));
872 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &ctx, &new_ctx, NULL, &lmf, native_offset, NULL);
876 if (!ji || ji == (gpointer)-1 || MONO_CONTEXT_GET_BP (&ctx) >= jit_tls->end_of_stack)
879 /* skip all wrappers ??*/
880 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
881 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
882 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE)
889 *method = mono_method_get_object (domain, ji->method, NULL);
890 *iloffset = mono_debug_il_offset_from_address (ji->method, *native_offset, domain);
892 if (need_file_info) {
895 filename = mono_debug_source_location_from_address (ji->method, *native_offset, line, domain);
897 *file = filename? mono_string_new (domain, filename): NULL;
907 * arch_handle_exception:
908 * @ctx: saved processor state
909 * @obj: the exception object
910 * @test_only: only test if the exception is caught, but dont call handlers
915 mono_arch_handle_exception (MonoContext *ctx, gpointer obj, gboolean test_only)
917 MonoDomain *domain = mono_domain_get ();
918 MonoJitInfo *ji, rji;
919 static int (*call_filter) (MonoContext *, gpointer, gpointer) = NULL;
920 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
921 MonoLMF *lmf = jit_tls->lmf;
922 GList *trace_ips = NULL;
923 MonoException *mono_ex;
925 g_assert (ctx != NULL);
927 MonoException *ex = mono_get_exception_null_reference ();
928 ex->message = mono_string_new (domain,
929 "Object reference not set to an instance of an object");
930 obj = (MonoObject *)ex;
933 if (mono_object_isinst (obj, mono_defaults.exception_class)) {
934 mono_ex = (MonoException*)obj;
935 mono_ex->stack_trace = NULL;
942 call_filter = arch_get_call_filter ();
944 g_assert (jit_tls->end_of_stack);
945 g_assert (jit_tls->abort_func);
948 MonoContext ctx_cp = *ctx;
949 if (mono_jit_trace_calls != NULL)
950 g_print ("EXCEPTION handling: %s\n", mono_object_class (obj)->name);
951 if (!mono_arch_handle_exception (&ctx_cp, obj, TRUE)) {
952 if (mono_break_on_exc)
954 mono_unhandled_exception (obj);
962 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, ctx, &new_ctx,
963 test_only ? &trace : NULL, &lmf, NULL, NULL);
965 g_warning ("Exception inside function without unwind info");
966 g_assert_not_reached ();
969 if (ji != (gpointer)-1) {
971 if (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
974 trace_ips = g_list_append (trace_ips, MONO_CONTEXT_GET_IP (ctx));
976 if (!mono_ex->stack_trace)
977 strace = g_strdup ("");
979 strace = mono_string_to_utf8 (mono_ex->stack_trace);
981 tmp = g_strdup_printf ("%s%s\n", strace, trace);
984 mono_ex->stack_trace = mono_string_new (domain, tmp);
989 if (ji->num_clauses) {
992 g_assert (ji->clauses);
994 for (i = 0; i < ji->num_clauses; i++) {
995 MonoJitExceptionInfo *ei = &ji->clauses [i];
997 if (ei->try_start <= MONO_CONTEXT_GET_IP (ctx) &&
998 MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) {
1000 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE &&
1001 mono_object_isinst (obj, mono_class_get (ji->method->klass->image, ei->data.token))) ||
1002 ((ei->flags == MONO_EXCEPTION_CLAUSE_FILTER &&
1003 call_filter (ctx, ei->data.filter, obj)))) {
1006 mono_ex->trace_ips = glist_to_array (trace_ips);
1007 g_list_free (trace_ips);
1011 if (mono_jit_trace_calls != NULL)
1012 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1013 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1014 *((gpointer *)((char *)MONO_CONTEXT_GET_BP (ctx) + ji->exvar_offset)) = obj;
1019 if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) &&
1020 MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
1021 (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
1022 if (mono_jit_trace_calls != NULL)
1023 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1024 call_filter (ctx, ei->handler_start, NULL);
1036 if ((ji == (gpointer)-1) || MONO_CONTEXT_GET_BP (ctx) >= jit_tls->end_of_stack) {
1039 jit_tls->abort_func (obj);
1040 g_assert_not_reached ();
1043 mono_ex->trace_ips = glist_to_array (trace_ips);
1044 g_list_free (trace_ips);
1050 g_assert_not_reached ();
1054 mono_arch_has_unwind_info (gconstpointer addr)