2008-07-12 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini-exceptions.c
1 /*
2  * mini-exceptions.c: generic 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 #include <string.h>
14
15 #ifdef HAVE_EXECINFO_H
16 #include <execinfo.h>
17 #endif
18
19 #ifndef PLATFORM_WIN32
20 #include <sys/types.h>
21 #include <sys/wait.h>
22 #include <unistd.h>
23 #endif
24
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28
29 #ifdef HAVE_SYS_SYSCALL_H
30 #include <sys/syscall.h>
31 #endif
32
33 #include <mono/metadata/appdomain.h>
34 #include <mono/metadata/tabledefs.h>
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/threads-types.h>
37 #include <mono/metadata/debug-helpers.h>
38 #include <mono/metadata/exception.h>
39 #include <mono/metadata/gc-internal.h>
40 #include <mono/metadata/mono-debug.h>
41 #include <mono/metadata/profiler.h>
42 #include <mono/utils/mono-mmap.h>
43
44 #include "mini.h"
45 #include "trace.h"
46
47 #ifndef MONO_ARCH_CONTEXT_DEF
48 #define MONO_ARCH_CONTEXT_DEF
49 #endif
50
51 static gpointer restore_context_func, call_filter_func;
52 static gpointer throw_exception_func, rethrow_exception_func;
53 static gpointer throw_exception_by_name_func, throw_corlib_exception_func;
54
55 void
56 mono_exceptions_init (void)
57 {
58 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
59         guint32 code_size;
60         MonoJumpInfo *ji;
61
62         if (mono_aot_only) {
63                 restore_context_func = mono_aot_get_named_code ("restore_context");
64                 call_filter_func = mono_aot_get_named_code ("call_filter");
65                 throw_exception_func = mono_aot_get_named_code ("throw_exception");
66                 rethrow_exception_func = mono_aot_get_named_code ("rethrow_exception");
67         } else {
68                 restore_context_func = mono_arch_get_restore_context_full (&code_size, &ji, FALSE);
69                 call_filter_func = mono_arch_get_call_filter_full (&code_size, &ji, FALSE);
70                 throw_exception_func = mono_arch_get_throw_exception_full (&code_size, &ji, FALSE);
71                 rethrow_exception_func = mono_arch_get_rethrow_exception_full (&code_size, &ji, FALSE);
72         }
73 #else
74 #ifndef CUSTOM_EXCEPTION_HANDLING
75         restore_context_func = mono_arch_get_restore_context ();
76         call_filter_func = mono_arch_get_call_filter ();
77 #endif
78         throw_exception_func = mono_arch_get_throw_exception ();
79         rethrow_exception_func = mono_arch_get_rethrow_exception ();
80 #endif
81 }
82
83 gpointer
84 mono_get_throw_exception (void)
85 {
86         g_assert (throw_exception_func);
87         return throw_exception_func;
88 }
89
90 gpointer
91 mono_get_rethrow_exception (void)
92 {
93         g_assert (rethrow_exception_func);
94         return rethrow_exception_func;
95 }
96
97 gpointer
98 mono_get_call_filter (void)
99 {
100         g_assert (call_filter_func);
101         return call_filter_func;
102 }
103
104 gpointer
105 mono_get_restore_context (void)
106 {
107         g_assert (restore_context_func);
108         return restore_context_func;
109 }
110
111 gpointer
112 mono_get_throw_exception_by_name (void)
113 {
114         gpointer code = NULL;
115 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
116         guint32 code_size;
117         MonoJumpInfo *ji;
118 #endif
119
120         /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
121         if (throw_exception_by_name_func)
122                 return throw_exception_by_name_func;
123
124 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
125         if (mono_aot_only)
126                 code = mono_aot_get_named_code ("throw_exception_by_name");
127         else
128                 code = mono_arch_get_throw_exception_by_name_full (&code_size, &ji, FALSE);
129 #else
130                 code = mono_arch_get_throw_exception_by_name ();
131 #endif
132
133         mono_memory_barrier ();
134
135         throw_exception_by_name_func = code;
136
137         return throw_exception_by_name_func;
138 }
139
140 gpointer
141 mono_get_throw_corlib_exception (void)
142 {
143         gpointer code = NULL;
144 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
145         guint32 code_size;
146         MonoJumpInfo *ji;
147 #endif
148
149         /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
150         if (throw_corlib_exception_func)
151                 return throw_corlib_exception_func;
152
153 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
154 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
155         if (mono_aot_only)
156                 code = mono_aot_get_named_code ("throw_corlib_exception");
157         else
158                 code = mono_arch_get_throw_corlib_exception_full (&code_size, &ji, FALSE);
159 #else
160                 code = mono_arch_get_throw_corlib_exception ();
161 #endif
162 #else
163         g_assert_not_reached ();
164 #endif
165
166         mono_memory_barrier ();
167
168         throw_corlib_exception_func = code;
169
170         return throw_corlib_exception_func;
171 }
172
173 #ifndef mono_find_jit_info
174
175 /* mono_find_jit_info:
176  *
177  * This function is used to gather information from @ctx. It return the 
178  * MonoJitInfo of the corresponding function, unwinds one stack frame and
179  * stores the resulting context into @new_ctx. It also stores a string 
180  * describing the stack location into @trace (if not NULL), and modifies
181  * the @lmf if necessary. @native_offset return the IP offset from the 
182  * start of the function or -1 if that info is not available.
183  */
184 static MonoJitInfo *
185 mono_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx, 
186                     MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
187                     gboolean *managed)
188 {
189         gboolean managed2;
190         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
191         MonoJitInfo *ji;
192
193         if (trace)
194                 *trace = NULL;
195
196         if (native_offset)
197                 *native_offset = -1;
198
199         if (managed)
200                 *managed = FALSE;
201
202         ji = mono_arch_find_jit_info (domain, jit_tls, res, prev_ji, ctx, new_ctx, NULL, lmf, NULL, &managed2);
203
204         if (ji == (gpointer)-1)
205                 return ji;
206
207         if (managed2 || ji->method->wrapper_type) {
208                 const char *real_ip, *start;
209                 gint32 offset;
210
211                 start = (const char *)ji->code_start;
212                 if (!managed2)
213                         /* ctx->ip points into native code */
214                         real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
215                 else
216                         real_ip = (const char*)ip;
217
218                 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
219                         offset = real_ip - start;
220                 else
221                         offset = -1;
222
223                 if (native_offset)
224                         *native_offset = offset;
225
226                 if (managed)
227                         if (!ji->method->wrapper_type)
228                                 *managed = TRUE;
229
230                 if (trace)
231                         *trace = mono_debug_print_stack_frame (ji->method, offset, domain);
232         } else {
233                 if (trace) {
234                         char *fname = mono_method_full_name (res->method, TRUE);
235                         *trace = g_strdup_printf ("in (unmanaged) %s", fname);
236                         g_free (fname);
237                 }
238         }
239
240         return ji;
241 }
242
243 #endif /* mono_find_jit_info */
244
245 MonoString *
246 ves_icall_System_Exception_get_trace (MonoException *ex)
247 {
248         MonoDomain *domain = mono_domain_get ();
249         MonoString *res;
250         MonoArray *ta = ex->trace_ips;
251         int i, len;
252         GString *trace_str;
253
254         if (ta == NULL)
255                 /* Exception is not thrown yet */
256                 return NULL;
257
258         len = mono_array_length (ta);
259         trace_str = g_string_new ("");
260         for (i = 0; i < len; i++) {
261                 MonoJitInfo *ji;
262                 gpointer ip = mono_array_get (ta, gpointer, i);
263
264                 ji = mono_jit_info_table_find (domain, ip);
265                 if (ji == NULL) {
266                         /* Unmanaged frame */
267                         g_string_append_printf (trace_str, "in (unmanaged) %p\n", ip);
268                 } else {
269                         gchar *location;
270                         gint32 address;
271
272                         address = (char *)ip - (char *)ji->code_start;
273                         location = mono_debug_print_stack_frame (
274                                 ji->method, address, ex->object.vtable->domain);
275
276                         g_string_append_printf (trace_str, "%s\n", location);
277                         g_free (location);
278                 }
279         }
280
281         res = mono_string_new (ex->object.vtable->domain, trace_str->str);
282         g_string_free (trace_str, TRUE);
283
284         return res;
285 }
286
287 MonoArray *
288 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
289 {
290         MonoDomain *domain = mono_domain_get ();
291         MonoArray *res;
292         MonoArray *ta = exc->trace_ips;
293         MonoDebugSourceLocation *location;
294         int i, len;
295
296         if (ta == NULL) {
297                 /* Exception is not thrown yet */
298                 return mono_array_new (domain, mono_defaults.stack_frame_class, 0);
299         }
300         
301         len = mono_array_length (ta);
302
303         res = mono_array_new (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0);
304
305         for (i = skip; i < len; i++) {
306                 MonoJitInfo *ji;
307                 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
308                 gpointer ip = mono_array_get (ta, gpointer, i);
309
310                 ji = mono_jit_info_table_find (domain, ip);
311                 if (ji == NULL) {
312                         /* Unmanaged frame */
313                         mono_array_setref (res, i, sf);
314                         continue;
315                 }
316
317                 g_assert (ji != NULL);
318
319                 if (ji->method->wrapper_type) {
320                         char *s;
321
322                         sf->method = NULL;
323                         s = mono_method_full_name (ji->method, TRUE);
324                         MONO_OBJECT_SETREF (sf, internal_method_name, mono_string_new (domain, s));
325                         g_free (s);
326                 }
327                 else
328                         MONO_OBJECT_SETREF (sf, method, mono_method_get_object (domain, ji->method, NULL));
329                 sf->native_offset = (char *)ip - (char *)ji->code_start;
330
331                 /*
332                  * mono_debug_lookup_source_location() returns both the file / line number information
333                  * and the IL offset.  Note that computing the IL offset is already an expensive
334                  * operation, so we shouldn't call this method twice.
335                  */
336                 location = mono_debug_lookup_source_location (ji->method, sf->native_offset, domain);
337                 if (location)
338                         sf->il_offset = location->il_offset;
339                 else
340                         sf->il_offset = 0;
341
342                 if (need_file_info) {
343                         if (location && location->source_file) {
344                                 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
345                                 sf->line = location->row;
346                                 sf->column = location->column;
347                         } else {
348                                 sf->line = sf->column = 0;
349                                 sf->filename = NULL;
350                         }
351                 }
352
353                 mono_debug_free_source_location (location);
354                 mono_array_setref (res, i, sf);
355         }
356
357         return res;
358 }
359
360 /**
361  * mono_walk_stack:
362  * @domain: starting appdomain
363  * @jit_tls: JIT data for the thread
364  * @start_ctx: starting state of the stack frame
365  * @func: callback to call for each stack frame
366  * @user_data: data passed to the callback
367  *
368  * This function walks the stack of a thread, starting from the state
369  * represented by jit_tls and start_ctx. For each frame the callback
370  * function is called with the relevant info. The walk ends when no more
371  * managed stack frames are found or when the callback returns a TRUE value.
372  * Note that the function can be used to walk the stack of a thread 
373  * different from the current.
374  */
375 void
376 mono_walk_stack (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoContext *start_ctx, MonoStackFrameWalk func, gpointer user_data)
377 {
378         MonoLMF *lmf = mono_get_lmf ();
379         MonoJitInfo *ji, rji;
380         gint native_offset;
381         gboolean managed;
382         MonoContext ctx, new_ctx;
383
384         ctx = *start_ctx;
385
386         while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
387                 /* 
388                  * FIXME: mono_find_jit_info () will need to be able to return a different
389                  * MonoDomain when apddomain transitions are found on the stack.
390                  */
391                 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
392                 if (!ji || ji == (gpointer)-1)
393                         return;
394
395                 if (func (domain, &new_ctx, ji, user_data))
396                         return;
397
398                 ctx = new_ctx;
399         }
400 }
401
402 #ifndef CUSTOM_STACK_WALK
403
404 void
405 mono_jit_walk_stack_from_ctx (MonoStackWalk func, MonoContext *start_ctx, gboolean do_il_offset, gpointer user_data)
406 {
407         MonoDomain *domain = mono_domain_get ();
408         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
409         MonoLMF *lmf = mono_get_lmf ();
410         MonoJitInfo *ji, rji;
411         gint native_offset, il_offset;
412         gboolean managed;
413         MonoContext ctx, new_ctx;
414
415         MONO_ARCH_CONTEXT_DEF
416
417         mono_arch_flush_register_windows ();
418
419         if (start_ctx) {
420                 memcpy (&ctx, start_ctx, sizeof (MonoContext));
421         } else {
422 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
423         MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
424 #else
425     MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_jit_walk_stack_from_ctx);
426 #endif
427         }
428
429         while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
430                 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
431                 g_assert (ji);
432
433                 if (ji == (gpointer)-1)
434                         return;
435
436                 if (do_il_offset) {
437                         MonoDebugSourceLocation *source;
438
439                         source = mono_debug_lookup_source_location (ji->method, native_offset, domain);
440                         il_offset = source ? source->il_offset : -1;
441                         mono_debug_free_source_location (source);
442                 } else
443                         il_offset = -1;
444
445                 if (func (ji->method, native_offset, il_offset, managed, user_data))
446                         return;
447                 
448                 ctx = new_ctx;
449         }
450 }
451
452 void
453 mono_jit_walk_stack (MonoStackWalk func, gboolean do_il_offset, gpointer user_data)
454 {
455         mono_jit_walk_stack_from_ctx (func, NULL, do_il_offset, user_data);
456 }
457
458 MonoBoolean
459 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, 
460                           MonoReflectionMethod **method, 
461                           gint32 *iloffset, gint32 *native_offset,
462                           MonoString **file, gint32 *line, gint32 *column)
463 {
464         MonoDomain *domain = mono_domain_get ();
465         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
466         MonoLMF *lmf = mono_get_lmf ();
467         MonoJitInfo *ji, rji;
468         MonoContext ctx, new_ctx;
469         MonoDebugSourceLocation *location;
470         MonoMethod *last_method = NULL;
471
472         MONO_ARCH_CONTEXT_DEF;
473
474         mono_arch_flush_register_windows ();
475
476 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
477         MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
478 #else
479         MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_get_frame_info);
480 #endif
481
482         do {
483                 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, native_offset, NULL);
484                 
485                 ctx = new_ctx;
486                 
487                 if (!ji || ji == (gpointer)-1 || MONO_CONTEXT_GET_SP (&ctx) >= jit_tls->end_of_stack)
488                         return FALSE;
489
490                 /* skip all wrappers ??*/
491                 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
492                     ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
493                     ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
494                     ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
495                     ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE ||
496                         ji->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
497                         continue;
498
499                 if (ji->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE && ji->method == last_method) {
500                         /*
501                          * FIXME: Native-to-managed wrappers sometimes show up twice.
502                          * Probably the whole mono_find_jit_info () stuff needs to be fixed so this 
503                          * isn't needed.
504                          */
505                         continue;
506                 }
507
508                 last_method = ji->method;
509
510                 skip--;
511
512         } while (skip >= 0);
513
514         *method = mono_method_get_object (domain, ji->method, NULL);
515
516         location = mono_debug_lookup_source_location (ji->method, *native_offset, domain);
517         if (location)
518                 *iloffset = location->il_offset;
519         else
520                 *iloffset = 0;
521
522         if (need_file_info) {
523                 if (location) {
524                         *file = mono_string_new (domain, location->source_file);
525                         *line = location->row;
526                         *column = location->column;
527                 } else {
528                         *file = NULL;
529                         *line = *column = 0;
530                 }
531         }
532
533         mono_debug_free_source_location (location);
534
535         return TRUE;
536 }
537
538 #endif /* CUSTOM_STACK_WALK */
539
540 typedef struct {
541         guint32 skips;
542         MonoSecurityFrame *frame;
543 } MonoFrameSecurityInfo;
544
545 static gboolean
546 callback_get_first_frame_security_info (MonoDomain *domain, MonoContext *ctx, MonoJitInfo *ji, gpointer data)
547 {
548         MonoFrameSecurityInfo *si = (MonoFrameSecurityInfo*) data;
549
550         /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
551         if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
552             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
553             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
554             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
555             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
556                 return FALSE;
557         }
558
559         if (si->skips > 0) {
560                 si->skips--;
561                 return FALSE;
562         }
563
564         si->frame = mono_declsec_create_frame (domain, ji);
565
566         /* Stop - we only want the first frame (e.g. LinkDemand and InheritanceDemand) */
567         return TRUE;
568 }
569
570 /**
571  * ves_icall_System_Security_SecurityFrame_GetSecurityFrame:
572  * @skip: the number of stack frames to skip
573  *
574  * This function returns a the security informations of a single stack frame 
575  * (after the skipped ones). This is required for [NonCas]LinkDemand[Choice]
576  * and [NonCas]InheritanceDemand[Choice] as only the caller security is 
577  * evaluated.
578  */
579 MonoSecurityFrame*
580 ves_icall_System_Security_SecurityFrame_GetSecurityFrame (gint32 skip)
581 {
582         MonoDomain *domain = mono_domain_get ();
583         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
584         MonoFrameSecurityInfo si;
585         MonoContext ctx;
586
587         MONO_ARCH_CONTEXT_DEF
588
589 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
590         MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
591 #else
592         MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
593 #endif
594
595 #if     defined(__ia64__) || defined(__s390__) || defined(__s390x__)
596         skip--;
597 #endif
598
599         si.skips = skip;
600         si.frame = NULL;
601         mono_walk_stack (domain, jit_tls, &ctx, callback_get_first_frame_security_info, (gpointer)&si);
602
603         return (si.skips == 0) ? si.frame : NULL;
604 }
605
606
607 typedef struct {
608         guint32 skips;
609         MonoArray *stack;
610         guint32 count;
611         guint32 maximum;
612 } MonoSecurityStack;
613
614 static void
615 grow_array (MonoSecurityStack *stack)
616 {
617         MonoDomain *domain = mono_domain_get ();
618         guint32 newsize = (stack->maximum << 1);
619         MonoArray *newstack = mono_array_new (domain, mono_defaults.runtimesecurityframe_class, newsize);
620         int i;
621         for (i=0; i < stack->maximum; i++) {
622                 gpointer frame = mono_array_get (stack->stack, gpointer, i);
623                 mono_array_setref (newstack, i, frame);
624         }
625         stack->maximum = newsize;
626         stack->stack = newstack;
627 }
628
629 static gboolean
630 callback_get_stack_frames_security_info (MonoDomain *domain, MonoContext *ctx, MonoJitInfo *ji, gpointer data)
631 {
632         MonoSecurityStack *ss = (MonoSecurityStack*) data;
633
634         /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
635         if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
636             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
637             ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
638             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
639             ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
640                 return FALSE;
641         }
642
643         if (ss->skips > 0) {
644                 ss->skips--;
645                 return FALSE;
646         }
647
648         if (ss->count == ss->maximum)
649                 grow_array (ss);
650
651         mono_array_setref (ss->stack, ss->count++, mono_declsec_create_frame (domain, ji));
652
653         /* continue down the stack */
654         return FALSE;
655 }
656
657 static MonoArray *
658 glist_to_array (GList *list, MonoClass *eclass) 
659 {
660         MonoDomain *domain = mono_domain_get ();
661         MonoArray *res;
662         int len, i;
663
664         if (!list)
665                 return NULL;
666
667         len = g_list_length (list);
668         res = mono_array_new (domain, eclass, len);
669
670         for (i = 0; list; list = list->next, i++)
671                 mono_array_set (res, gpointer, i, list->data);
672
673         return res;
674 }
675
676 /**
677  * ves_icall_System_Security_SecurityFrame_GetSecurityStack:
678  * @skip: the number of stack frames to skip
679  *
680  * This function returns an managed array of containing the security
681  * informations for each frame (after the skipped ones). This is used for
682  * [NonCas]Demand[Choice] where the complete evaluation of the stack is 
683  * required.
684  */
685 MonoArray*
686 ves_icall_System_Security_SecurityFrame_GetSecurityStack (gint32 skip)
687 {
688         MonoDomain *domain = mono_domain_get ();
689         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
690         MonoSecurityStack ss;
691         MonoContext ctx;
692
693         MONO_ARCH_CONTEXT_DEF
694
695 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
696         MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
697 #else
698         MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_System_Security_SecurityFrame_GetSecurityStack);
699 #endif
700
701 #if     defined(__ia64__) || defined(__s390__) || defined(__s390x__)
702         skip--;
703 #endif
704
705         ss.skips = skip;
706         ss.count = 0;
707         ss.maximum = MONO_CAS_INITIAL_STACK_SIZE;
708         ss.stack = mono_array_new (domain, mono_defaults.runtimesecurityframe_class, ss.maximum);
709         mono_walk_stack (domain, jit_tls, &ctx, callback_get_stack_frames_security_info, (gpointer)&ss);
710         /* g_warning ("STACK RESULT: %d out of %d", ss.count, ss.maximum); */
711         return ss.stack;
712 }
713
714 #ifndef CUSTOM_EXCEPTION_HANDLING
715
716 static MonoClass*
717 get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContext *ctx)
718 {
719         MonoClass *catch_class = ei->data.catch_class;
720         MonoGenericJitInfo *gi;
721         gpointer info;
722         MonoClass *class, *method_container_class;
723         MonoType *inflated_type;
724         MonoGenericContext context = { NULL, NULL };
725
726         if (!catch_class)
727                 return NULL;
728
729         if (!ji->has_generic_jit_info)
730                 return catch_class;
731
732         gi = mono_jit_info_get_generic_jit_info (ji);
733         if (!gi->has_this)
734                 return catch_class;
735
736         if (gi->this_in_reg)
737                 info = mono_arch_context_get_int_reg (ctx, gi->this_reg);
738         else
739                 info = *(gpointer*)((char*)mono_arch_context_get_int_reg (ctx, gi->this_reg) +
740                                 gi->this_offset);
741
742         g_assert (ji->method->is_inflated);
743
744         if (mono_method_get_context (ji->method)->method_inst) {
745                 MonoMethodRuntimeGenericContext *mrgctx = info;
746
747                 class = mrgctx->class_vtable->klass;
748                 context.method_inst = mrgctx->method_inst;
749                 g_assert (context.method_inst);
750         } else if (ji->method->flags & METHOD_ATTRIBUTE_STATIC) {
751                 MonoVTable *vtable = info;
752
753                 class = vtable->klass;
754         } else {
755                 MonoObject *this = info;
756
757                 class = this->vtable->klass;
758         }
759
760         if (class->generic_class || class->generic_container)
761                 context.class_inst = mini_class_get_context (class)->class_inst;
762
763         g_assert (!ji->method->klass->generic_container);
764         if (ji->method->klass->generic_class)
765                 method_container_class = ji->method->klass->generic_class->container_class;
766         else
767                 method_container_class = ji->method->klass;
768
769         if (class->generic_class)
770                 g_assert (class->generic_class->container_class == method_container_class);
771         else
772                 g_assert (!class->generic_container && class == method_container_class);
773
774         /* FIXME: we shouldn't inflate but instead put the
775            type in the rgctx and fetch it from there.  It
776            might be a good idea to do this lazily, i.e. only
777            when the exception is actually thrown, so as not to
778            waste space for exception clauses which might never
779            be encountered. */
780         inflated_type = mono_class_inflate_generic_type (&catch_class->byval_arg, &context);
781         catch_class = mono_class_from_mono_type (inflated_type);
782         g_free (inflated_type);
783
784         return catch_class;
785 }
786
787 /**
788  * mono_handle_exception_internal:
789  * @ctx: saved processor state
790  * @obj: the exception object
791  * @test_only: only test if the exception is caught, but dont call handlers
792  * @out_filter_idx: out parameter. if test_only is true, set to the index of 
793  * the first filter clause which caught the exception.
794  */
795 static gboolean
796 mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean test_only, gint32 *out_filter_idx)
797 {
798         MonoDomain *domain = mono_domain_get ();
799         MonoJitInfo *ji, rji;
800         static int (*call_filter) (MonoContext *, gpointer) = NULL;
801         static void (*restore_context) (void *);
802         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
803         MonoLMF *lmf = mono_get_lmf ();
804         MonoArray *initial_trace_ips = NULL;
805         GList *trace_ips = NULL;
806         MonoException *mono_ex;
807         gboolean stack_overflow = FALSE;
808         MonoContext initial_ctx;
809         int frame_count = 0;
810         gboolean has_dynamic_methods = FALSE;
811         gint32 filter_idx, first_filter_idx;
812
813         g_assert (ctx != NULL);
814         if (!obj) {
815                 MonoException *ex = mono_get_exception_null_reference ();
816                 MONO_OBJECT_SETREF (ex, message, mono_string_new (domain, "Object reference not set to an instance of an object"));
817                 obj = (MonoObject *)ex;
818         } 
819
820         /*
821          * Allocate a new exception object instead of the preconstructed ones.
822          */
823         if (obj == domain->stack_overflow_ex) {
824                 obj = mono_get_exception_stack_overflow ();
825                 stack_overflow = TRUE;
826         }
827         else if (obj == domain->null_reference_ex) {
828                 obj = mono_get_exception_null_reference ();
829         }
830
831         if (mono_object_isinst (obj, mono_defaults.exception_class)) {
832                 mono_ex = (MonoException*)obj;
833                 initial_trace_ips = mono_ex->trace_ips;
834         } else {
835                 mono_ex = NULL;
836         }
837
838         if (mono_ex && jit_tls->class_cast_to && !strcmp (mono_ex->object.vtable->klass->name, "InvalidCastException")) {
839                 char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
840                 char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
841                 char *msg = g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name, to_name);
842                 mono_ex->message = mono_string_new (domain, msg);
843                 g_free (from_name);
844                 g_free (to_name);
845                 g_free (msg);
846         }
847
848         if (!call_filter)
849                 call_filter = mono_get_call_filter ();
850
851         if (!restore_context)
852                 restore_context = mono_get_restore_context ();
853
854         g_assert (jit_tls->end_of_stack);
855         g_assert (jit_tls->abort_func);
856
857         if (!test_only) {
858                 MonoContext ctx_cp = *ctx;
859                 if (mono_trace_is_enabled ())
860                         g_print ("EXCEPTION handling: %s\n", mono_object_class (obj)->name);
861                 mono_profiler_exception_thrown (obj);
862                 if (!mono_handle_exception_internal (&ctx_cp, obj, original_ip, TRUE, &first_filter_idx)) {
863                         if (mono_break_on_exc)
864                                 G_BREAKPOINT ();
865                         // FIXME: This runs managed code so it might cause another stack overflow when
866                         // we are handling a stack overflow
867                         mono_unhandled_exception (obj);
868
869                         if (mono_debugger_unhandled_exception (original_ip, MONO_CONTEXT_GET_SP (ctx), obj)) {
870                                 /*
871                                  * If this returns true, then we're running inside the
872                                  * Mono Debugger and the debugger wants us to restore the
873                                  * context and continue (normally, the debugger inserts
874                                  * a breakpoint on the `original_ip', so it regains control
875                                  * immediately after restoring the context).
876                                  */
877                                 MONO_CONTEXT_SET_IP (ctx, original_ip);
878                                 restore_context (ctx);
879                                 g_assert_not_reached ();
880                         }
881                 }
882         }
883
884         if (out_filter_idx)
885                 *out_filter_idx = -1;
886         filter_idx = 0;
887         initial_ctx = *ctx;
888         memset (&rji, 0, sizeof (rji));
889
890         while (1) {
891                 MonoContext new_ctx;
892                 guint32 free_stack;
893
894                 ji = mono_find_jit_info (domain, jit_tls, &rji, &rji, ctx, &new_ctx, 
895                                                                  NULL, &lmf, NULL, NULL);
896                 if (!ji) {
897                         g_warning ("Exception inside function without unwind info");
898                         g_assert_not_reached ();
899                 }
900
901                 if (ji != (gpointer)-1 && !(ji->code_start <= MONO_CONTEXT_GET_IP (ctx) && (((guint8*)ji->code_start + ji->code_size >= (guint8*)MONO_CONTEXT_GET_IP (ctx))))) {
902                         /*
903                          * The exception was raised in native code and we got back to managed code 
904                          * using the LMF.
905                          */
906                         *ctx = new_ctx;
907                         continue;
908                 }
909
910                 if (ji != (gpointer)-1) {
911                         frame_count ++;
912                         //printf ("M: %s %d %d.\n", mono_method_full_name (ji->method, TRUE), frame_count, test_only);
913
914                         if (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
915                                 /* 
916                                  * Avoid overwriting the stack trace if the exception is
917                                  * rethrown. Also avoid giant stack traces during a stack
918                                  * overflow.
919                                  */
920                                 if (!initial_trace_ips && (frame_count < 1000)) {
921                                         trace_ips = g_list_prepend (trace_ips, MONO_CONTEXT_GET_IP (ctx));
922                                 }
923                         }
924
925                         if (ji->method->dynamic)
926                                 has_dynamic_methods = TRUE;
927
928                         if (stack_overflow)
929 #ifndef MONO_ARCH_STACK_GROWS_UP
930                                 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
931 #else
932                                 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (ctx));
933 #endif
934                         else
935                                 free_stack = 0xffffff;
936
937                         /* 
938                          * During stack overflow, wait till the unwinding frees some stack
939                          * space before running handlers/finalizers.
940                          */
941                         if ((free_stack > (64 * 1024)) && ji->num_clauses) {
942                                 int i;
943                                 
944                                 for (i = 0; i < ji->num_clauses; i++) {
945                                         MonoJitExceptionInfo *ei = &ji->clauses [i];
946                                         gboolean filtered = FALSE;
947
948 #ifdef __s390__
949                                         if (ei->try_start < MONO_CONTEXT_GET_IP (ctx) && 
950 #else
951                                         if (ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
952 #endif
953                                             MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) { 
954                                                 /* catch block */
955                                                 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
956
957                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)) {
958                                                         /* store the exception object in bp + ei->exvar_offset */
959                                                         *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = obj;
960                                                 }
961
962                                                 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
963                                                         // mono_debugger_handle_exception (ei->data.filter, MONO_CONTEXT_GET_SP (ctx), obj);
964                                                         if (test_only) {
965                                                                 filtered = call_filter (ctx, ei->data.filter);
966                                                                 if (filtered && out_filter_idx)
967                                                                         *out_filter_idx = filter_idx;
968                                                         }
969                                                         else {
970                                                                 /* 
971                                                                  * Filter clauses should only be run in the 
972                                                                  * first pass of exception handling.
973                                                                  */
974                                                                 filtered = (filter_idx == first_filter_idx);
975                                                         }
976                                                         filter_idx ++;
977                                                 }
978
979                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && 
980                                                      mono_object_isinst (obj, catch_class)) || filtered) {
981                                                         if (test_only) {
982                                                                 if (mono_ex && !initial_trace_ips) {
983                                                                         trace_ips = g_list_reverse (trace_ips);
984                                                                         MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class));
985                                                                         if (has_dynamic_methods)
986                                                                                 /* These methods could go away anytime, so compute the stack trace now */
987                                                                                 MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
988                                                                 }
989                                                                 g_list_free (trace_ips);
990
991                                                                 return TRUE;
992                                                         }
993                                                         if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
994                                                                 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
995                                                         mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
996                                                         mono_debugger_handle_exception (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
997                                                         MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
998                                                         *(mono_get_lmf_addr ()) = lmf;
999
1000                                                         return 0;
1001                                                 }
1002                                                 if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
1003                                                     MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
1004                                                     (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT)) {
1005                                                         if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1006                                                                 g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1007                                                         mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1008                                                         mono_debugger_handle_exception (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
1009                                                         call_filter (ctx, ei->handler_start);
1010                                                 }
1011                                                 if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
1012                                                     MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
1013                                                     (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)) {
1014                                                         if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1015                                                                 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1016                                                         mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1017                                                         mono_debugger_handle_exception (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
1018                                                         call_filter (ctx, ei->handler_start);
1019                                                 }
1020                                                 
1021                                         }
1022                                 }
1023                         }
1024                         if (!test_only)
1025                                 mono_profiler_exception_method_leave (ji->method);
1026                 }
1027
1028                 *ctx = new_ctx;
1029
1030                 if (ji == (gpointer)-1) {
1031
1032                         if (!test_only) {
1033                                 *(mono_get_lmf_addr ()) = lmf;
1034
1035                                 jit_tls->abort_func (obj);
1036                                 g_assert_not_reached ();
1037                         } else {
1038                                 if (mono_ex && !initial_trace_ips) {
1039                                         trace_ips = g_list_reverse (trace_ips);
1040                                         MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class));
1041                                         if (has_dynamic_methods)
1042                                                 /* These methods could go away anytime, so compute the stack trace now */
1043                                                 MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
1044                                 }
1045                                 g_list_free (trace_ips);
1046                                 return FALSE;
1047                         }
1048                 }
1049         }
1050
1051         g_assert_not_reached ();
1052 }
1053
1054 /**
1055  * mono_debugger_run_finally:
1056  * @start_ctx: saved processor state
1057  *
1058  * This method is called by the Mono Debugger to call all `finally' clauses of the
1059  * current stack frame.  It's used when the user issues a `return' command to make
1060  * the current stack frame return.  After returning from this method, the debugger
1061  * unwinds the stack one frame and gives control back to the user.
1062  *
1063  * NOTE: This method is only used when running inside the Mono Debugger.
1064  */
1065 void
1066 mono_debugger_run_finally (MonoContext *start_ctx)
1067 {
1068         static int (*call_filter) (MonoContext *, gpointer) = NULL;
1069         MonoDomain *domain = mono_domain_get ();
1070         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1071         MonoLMF *lmf = mono_get_lmf ();
1072         MonoContext ctx, new_ctx;
1073         MonoJitInfo *ji, rji;
1074         int i;
1075
1076         ctx = *start_ctx;
1077
1078         ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
1079         if (!ji || ji == (gpointer)-1)
1080                 return;
1081
1082         if (!call_filter)
1083                 call_filter = mono_get_call_filter ();
1084
1085         for (i = 0; i < ji->num_clauses; i++) {
1086                 MonoJitExceptionInfo *ei = &ji->clauses [i];
1087
1088                 if ((ei->try_start <= MONO_CONTEXT_GET_IP (&ctx)) && 
1089                     (MONO_CONTEXT_GET_IP (&ctx) < ei->try_end) &&
1090                     (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
1091                         call_filter (&ctx, ei->handler_start);
1092                 }
1093         }
1094 }
1095
1096 /**
1097  * mono_handle_exception:
1098  * @ctx: saved processor state
1099  * @obj: the exception object
1100  * @test_only: only test if the exception is caught, but dont call handlers
1101  */
1102 gboolean
1103 mono_handle_exception (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean test_only)
1104 {
1105         return mono_handle_exception_internal (ctx, obj, original_ip, test_only, NULL);
1106 }
1107
1108 #endif /* CUSTOM_EXCEPTION_HANDLING */
1109
1110 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1111
1112 #ifndef MONO_ARCH_USE_SIGACTION
1113 #error "Can't use sigaltstack without sigaction"
1114 #endif
1115
1116 void
1117 mono_setup_altstack (MonoJitTlsData *tls)
1118 {
1119         size_t stsize = 0;
1120         struct sigaltstack sa;
1121         guint8 *staddr = NULL;
1122
1123         if (mono_running_on_valgrind ())
1124                 return;
1125
1126         mono_thread_get_stack_bounds (&staddr, &stsize);
1127
1128         g_assert (staddr);
1129
1130         tls->end_of_stack = staddr + stsize;
1131
1132         /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
1133
1134         tls->stack_ovf_guard_base = staddr + mono_pagesize ();
1135         tls->stack_ovf_guard_size = mono_pagesize () * 8;
1136
1137         if (mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE)) {
1138                 /* mprotect can fail for the main thread stack */
1139                 gpointer gaddr = mono_valloc (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON|MONO_MMAP_FIXED);
1140                 g_assert (gaddr == tls->stack_ovf_guard_base);
1141         }
1142
1143         /*
1144          * threads created by nptl does not seem to have a guard page, and
1145          * since the main thread is not created by us, we can't even set one.
1146          * Increasing stsize fools the SIGSEGV signal handler into thinking this
1147          * is a stack overflow exception.
1148          */
1149         tls->stack_size = stsize + mono_pagesize ();
1150
1151         /* Setup an alternate signal stack */
1152         tls->signal_stack = mono_valloc (0, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC|MONO_MMAP_PRIVATE|MONO_MMAP_ANON);
1153         tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1154
1155         g_assert (tls->signal_stack);
1156
1157         sa.ss_sp = tls->signal_stack;
1158         sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1159         sa.ss_flags = SS_ONSTACK;
1160         sigaltstack (&sa, NULL);
1161 }
1162
1163 void
1164 mono_free_altstack (MonoJitTlsData *tls)
1165 {
1166         struct sigaltstack sa;
1167         int err;
1168
1169         sa.ss_sp = tls->signal_stack;
1170         sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1171         sa.ss_flags = SS_DISABLE;
1172         err = sigaltstack  (&sa, NULL);
1173         g_assert (err == 0);
1174
1175         if (tls->signal_stack)
1176                 mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE);
1177 }
1178
1179 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1180
1181 void
1182 mono_setup_altstack (MonoJitTlsData *tls)
1183 {
1184 }
1185
1186 void
1187 mono_free_altstack (MonoJitTlsData *tls)
1188 {
1189 }
1190
1191 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1192
1193 static gboolean
1194 print_stack_frame (MonoMethod *method, gint32 native_offset, gint32 il_offset, gboolean managed, gpointer data)
1195 {
1196         FILE *stream = (FILE*)data;
1197
1198         if (method) {
1199                 gchar *location = mono_debug_print_stack_frame (method, native_offset, mono_domain_get ());
1200                 fprintf (stream, "  %s\n", location);
1201                 g_free (location);
1202         } else
1203                 fprintf (stream, "  at <unknown> <0x%05x>\n", native_offset);
1204
1205         return FALSE;
1206 }
1207
1208 static gboolean
1209 print_stack_frame_to_string (MonoMethod *method, gint32 native_offset, gint32 il_offset, gboolean managed,
1210                              gpointer data)
1211 {
1212         GString *p = (GString*)data;
1213
1214         if (method) {
1215                 gchar *location = mono_debug_print_stack_frame (method, native_offset, mono_domain_get ());
1216                 g_string_append_printf (p, "  %s\n", location);
1217                 g_free (location);
1218         } else
1219                 g_string_append_printf (p, "  at <unknown> <0x%05x>\n", native_offset);
1220
1221         return FALSE;
1222 }
1223
1224 static gboolean handling_sigsegv = FALSE;
1225
1226 /*
1227  * mono_handle_native_sigsegv:
1228  *
1229  *   Handle a SIGSEGV received while in native code by printing diagnostic 
1230  * information and aborting.
1231  */
1232 void
1233 mono_handle_native_sigsegv (int signal, void *ctx)
1234 {
1235 #ifndef PLATFORM_WIN32
1236         struct sigaction sa;
1237 #endif
1238         if (handling_sigsegv)
1239                 return;
1240
1241         /* To prevent infinite loops when the stack walk causes a crash */
1242         handling_sigsegv = TRUE;
1243
1244         fprintf (stderr, "Stacktrace:\n\n");
1245
1246         mono_jit_walk_stack (print_stack_frame, TRUE, stderr);
1247
1248         fflush (stderr);
1249
1250 #ifdef HAVE_BACKTRACE_SYMBOLS
1251  {
1252         void *array [256];
1253         char **names;
1254         int i, size;
1255         const char *signal_str = (signal == SIGSEGV) ? "SIGSEGV" : "SIGABRT";
1256
1257         fprintf (stderr, "\nNative stacktrace:\n\n");
1258
1259         size = backtrace (array, 256);
1260         names = backtrace_symbols (array, size);
1261         for (i =0; i < size; ++i) {
1262                 fprintf (stderr, "\t%s\n", names [i]);
1263         }
1264         free (names);
1265
1266         fflush (stderr);
1267
1268         /* Try to get more meaningful information using gdb */
1269
1270 #if !defined(PLATFORM_WIN32) && defined(HAVE_SYS_SYSCALL_H) && defined(SYS_fork)
1271         if (!mini_get_debug_options ()->no_gdb_backtrace) {
1272                 /* From g_spawn_command_line_sync () in eglib */
1273                 int res;
1274                 int stdout_pipe [2] = { -1, -1 };
1275                 pid_t pid;
1276                 const char *argv [16];
1277                 char buf1 [128];
1278                 int status;
1279                 char buffer [1024];
1280
1281                 res = pipe (stdout_pipe);
1282                 g_assert (res != -1);
1283                         
1284                 //pid = fork ();
1285                 /*
1286                  * glibc fork acquires some locks, so if the crash happened inside malloc/free,
1287                  * it will deadlock. Call the syscall directly instead.
1288                  */
1289                 pid = syscall (SYS_fork);
1290                 if (pid == 0) {
1291                         close (stdout_pipe [0]);
1292                         dup2 (stdout_pipe [1], STDOUT_FILENO);
1293
1294                         for (i = getdtablesize () - 1; i >= 3; i--)
1295                                 close (i);
1296
1297                         argv [0] = g_find_program_in_path ("gdb");
1298                         if (argv [0] == NULL) {
1299                                 close (STDOUT_FILENO);
1300                                 exit (1);
1301                         }
1302
1303                         argv [1] = "-ex";
1304                         sprintf (buf1, "attach %ld", (long)getpid ());
1305                         argv [2] = buf1;
1306                         argv [3] = "--ex";
1307                         argv [4] = "info threads";
1308                         argv [5] = "--ex";
1309                         argv [6] = "thread apply all bt";
1310                         argv [7] = "--batch";
1311                         argv [8] = 0;
1312
1313                         execv (argv [0], (char**)argv);
1314                         exit (1);
1315                 }
1316
1317                 close (stdout_pipe [1]);
1318
1319                 fprintf (stderr, "\nDebug info from gdb:\n\n");
1320
1321                 while (1) {
1322                         int nread = read (stdout_pipe [0], buffer, 1024);
1323
1324                         if (nread <= 0)
1325                                 break;
1326                         write (STDERR_FILENO, buffer, nread);
1327                 }               
1328
1329                 waitpid (pid, &status, WNOHANG);
1330         }
1331 #endif
1332         /*
1333          * A SIGSEGV indicates something went very wrong so we can no longer depend
1334          * on anything working. So try to print out lots of diagnostics, starting 
1335          * with ones which have a greater chance of working.
1336          */
1337         fprintf (stderr,
1338                          "\n"
1339                          "=================================================================\n"
1340                          "Got a %s while executing native code. This usually indicates\n"
1341                          "a fatal error in the mono runtime or one of the native libraries \n"
1342                          "used by your application.\n"
1343                          "=================================================================\n"
1344                          "\n", signal_str);
1345
1346  }
1347 #endif
1348
1349 #ifndef PLATFORM_WIN32
1350
1351         /* Remove our SIGABRT handler */
1352         sa.sa_handler = SIG_DFL;
1353         sigemptyset (&sa.sa_mask);
1354         sa.sa_flags = 0;
1355
1356         g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
1357
1358 #endif
1359
1360         abort ();
1361 }
1362
1363 /*
1364  * mono_print_thread_dump:
1365  *
1366  *   Print information about the current thread to stdout.
1367  * SIGCTX can be NULL, allowing this to be called from gdb.
1368  */
1369 void
1370 mono_print_thread_dump (void *sigctx)
1371 {
1372         MonoThread *thread = mono_thread_current ();
1373 #if defined(__i386__) || defined(__x86_64__)
1374         MonoContext ctx;
1375 #endif
1376         GString* text = g_string_new (0);
1377         char *name;
1378         GError *error = NULL;
1379
1380         if (thread->name) {
1381                 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
1382                 g_assert (!error);
1383                 g_string_append_printf (text, "\n\"%s\"", name);
1384                 g_free (name);
1385         }
1386         else
1387                 g_string_append (text, "\n\"\"");
1388
1389         g_string_append_printf (text, " tid=0x%p this=0x%p:\n", (gpointer)(gsize)thread->tid, thread);
1390
1391         /* FIXME: */
1392 #if defined(__i386__) || defined(__x86_64__)
1393         if (!sigctx)
1394                 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_print_thread_dump);
1395         else
1396                 mono_arch_sigctx_to_monoctx (sigctx, &ctx);
1397
1398         mono_jit_walk_stack_from_ctx (print_stack_frame_to_string, &ctx, TRUE, text);
1399 #else
1400         printf ("\t<Stack traces in thread dumps not supported on this platform>\n");
1401 #endif
1402
1403         fprintf (stdout, text->str);
1404         g_string_free (text, TRUE);
1405         fflush (stdout);
1406 }