2008-07-22 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 #if defined(__s390__) || defined(__ia64__)
949                                         /* 
950                                          * This is required in cases where a try block starts immediately after
951                                          * a call which causes an exception. Testcase: tests/exception8.cs.
952                                          * FIXME: Clean this up.
953                                          */
954                                         if (ei->try_start < MONO_CONTEXT_GET_IP (ctx) && 
955 #else
956                                         if (ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
957 #endif
958                                             MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) { 
959                                                 /* catch block */
960                                                 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
961
962                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)) {
963                                                         /* store the exception object in bp + ei->exvar_offset */
964                                                         *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = obj;
965                                                 }
966
967                                                 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
968                                                         // mono_debugger_handle_exception (ei->data.filter, MONO_CONTEXT_GET_SP (ctx), obj);
969                                                         if (test_only) {
970                                                                 filtered = call_filter (ctx, ei->data.filter);
971                                                                 if (filtered && out_filter_idx)
972                                                                         *out_filter_idx = filter_idx;
973                                                         }
974                                                         else {
975                                                                 /* 
976                                                                  * Filter clauses should only be run in the 
977                                                                  * first pass of exception handling.
978                                                                  */
979                                                                 filtered = (filter_idx == first_filter_idx);
980                                                         }
981                                                         filter_idx ++;
982                                                 }
983
984                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && 
985                                                      mono_object_isinst (obj, catch_class)) || filtered) {
986                                                         if (test_only) {
987                                                                 if (mono_ex && !initial_trace_ips) {
988                                                                         trace_ips = g_list_reverse (trace_ips);
989                                                                         MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class));
990                                                                         if (has_dynamic_methods)
991                                                                                 /* These methods could go away anytime, so compute the stack trace now */
992                                                                                 MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
993                                                                 }
994                                                                 g_list_free (trace_ips);
995
996                                                                 return TRUE;
997                                                         }
998                                                         if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
999                                                                 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1000                                                         mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1001                                                         mono_debugger_handle_exception (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
1002                                                         MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1003                                                         *(mono_get_lmf_addr ()) = lmf;
1004
1005                                                         return 0;
1006                                                 }
1007                                                 if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
1008                                                     MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
1009                                                     (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT)) {
1010                                                         if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1011                                                                 g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1012                                                         mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1013                                                         mono_debugger_handle_exception (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
1014                                                         call_filter (ctx, ei->handler_start);
1015                                                 }
1016                                                 if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
1017                                                     MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
1018                                                     (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)) {
1019                                                         if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
1020                                                                 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1021                                                         mono_profiler_exception_clause_handler (ji->method, ei->flags, i);
1022                                                         mono_debugger_handle_exception (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
1023                                                         call_filter (ctx, ei->handler_start);
1024                                                 }
1025                                                 
1026                                         }
1027                                 }
1028                         }
1029                         if (!test_only)
1030                                 mono_profiler_exception_method_leave (ji->method);
1031                 }
1032
1033                 *ctx = new_ctx;
1034
1035                 if (ji == (gpointer)-1) {
1036
1037                         if (!test_only) {
1038                                 *(mono_get_lmf_addr ()) = lmf;
1039
1040                                 jit_tls->abort_func (obj);
1041                                 g_assert_not_reached ();
1042                         } else {
1043                                 if (mono_ex && !initial_trace_ips) {
1044                                         trace_ips = g_list_reverse (trace_ips);
1045                                         MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class));
1046                                         if (has_dynamic_methods)
1047                                                 /* These methods could go away anytime, so compute the stack trace now */
1048                                                 MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
1049                                 }
1050                                 g_list_free (trace_ips);
1051                                 return FALSE;
1052                         }
1053                 }
1054         }
1055
1056         g_assert_not_reached ();
1057 }
1058
1059 /**
1060  * mono_debugger_run_finally:
1061  * @start_ctx: saved processor state
1062  *
1063  * This method is called by the Mono Debugger to call all `finally' clauses of the
1064  * current stack frame.  It's used when the user issues a `return' command to make
1065  * the current stack frame return.  After returning from this method, the debugger
1066  * unwinds the stack one frame and gives control back to the user.
1067  *
1068  * NOTE: This method is only used when running inside the Mono Debugger.
1069  */
1070 void
1071 mono_debugger_run_finally (MonoContext *start_ctx)
1072 {
1073         static int (*call_filter) (MonoContext *, gpointer) = NULL;
1074         MonoDomain *domain = mono_domain_get ();
1075         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1076         MonoLMF *lmf = mono_get_lmf ();
1077         MonoContext ctx, new_ctx;
1078         MonoJitInfo *ji, rji;
1079         int i;
1080
1081         ctx = *start_ctx;
1082
1083         ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
1084         if (!ji || ji == (gpointer)-1)
1085                 return;
1086
1087         if (!call_filter)
1088                 call_filter = mono_get_call_filter ();
1089
1090         for (i = 0; i < ji->num_clauses; i++) {
1091                 MonoJitExceptionInfo *ei = &ji->clauses [i];
1092
1093                 if ((ei->try_start <= MONO_CONTEXT_GET_IP (&ctx)) && 
1094                     (MONO_CONTEXT_GET_IP (&ctx) < ei->try_end) &&
1095                     (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
1096                         call_filter (&ctx, ei->handler_start);
1097                 }
1098         }
1099 }
1100
1101 /**
1102  * mono_handle_exception:
1103  * @ctx: saved processor state
1104  * @obj: the exception object
1105  * @test_only: only test if the exception is caught, but dont call handlers
1106  */
1107 gboolean
1108 mono_handle_exception (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean test_only)
1109 {
1110         return mono_handle_exception_internal (ctx, obj, original_ip, test_only, NULL);
1111 }
1112
1113 #endif /* CUSTOM_EXCEPTION_HANDLING */
1114
1115 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
1116
1117 #ifndef MONO_ARCH_USE_SIGACTION
1118 #error "Can't use sigaltstack without sigaction"
1119 #endif
1120
1121 void
1122 mono_setup_altstack (MonoJitTlsData *tls)
1123 {
1124         size_t stsize = 0;
1125         struct sigaltstack sa;
1126         guint8 *staddr = NULL;
1127
1128         if (mono_running_on_valgrind ())
1129                 return;
1130
1131         mono_thread_get_stack_bounds (&staddr, &stsize);
1132
1133         g_assert (staddr);
1134
1135         tls->end_of_stack = staddr + stsize;
1136
1137         /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
1138
1139         tls->stack_ovf_guard_base = staddr + mono_pagesize ();
1140         tls->stack_ovf_guard_size = mono_pagesize () * 8;
1141
1142         if (mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE)) {
1143                 /* mprotect can fail for the main thread stack */
1144                 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);
1145                 g_assert (gaddr == tls->stack_ovf_guard_base);
1146         }
1147
1148         /*
1149          * threads created by nptl does not seem to have a guard page, and
1150          * since the main thread is not created by us, we can't even set one.
1151          * Increasing stsize fools the SIGSEGV signal handler into thinking this
1152          * is a stack overflow exception.
1153          */
1154         tls->stack_size = stsize + mono_pagesize ();
1155
1156         /* Setup an alternate signal stack */
1157         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);
1158         tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1159
1160         g_assert (tls->signal_stack);
1161
1162         sa.ss_sp = tls->signal_stack;
1163         sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1164         sa.ss_flags = SS_ONSTACK;
1165         sigaltstack (&sa, NULL);
1166 }
1167
1168 void
1169 mono_free_altstack (MonoJitTlsData *tls)
1170 {
1171         struct sigaltstack sa;
1172         int err;
1173
1174         sa.ss_sp = tls->signal_stack;
1175         sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
1176         sa.ss_flags = SS_DISABLE;
1177         err = sigaltstack  (&sa, NULL);
1178         g_assert (err == 0);
1179
1180         if (tls->signal_stack)
1181                 mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE);
1182 }
1183
1184 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1185
1186 void
1187 mono_setup_altstack (MonoJitTlsData *tls)
1188 {
1189 }
1190
1191 void
1192 mono_free_altstack (MonoJitTlsData *tls)
1193 {
1194 }
1195
1196 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
1197
1198 static gboolean
1199 print_stack_frame (MonoMethod *method, gint32 native_offset, gint32 il_offset, gboolean managed, gpointer data)
1200 {
1201         FILE *stream = (FILE*)data;
1202
1203         if (method) {
1204                 gchar *location = mono_debug_print_stack_frame (method, native_offset, mono_domain_get ());
1205                 fprintf (stream, "  %s\n", location);
1206                 g_free (location);
1207         } else
1208                 fprintf (stream, "  at <unknown> <0x%05x>\n", native_offset);
1209
1210         return FALSE;
1211 }
1212
1213 static gboolean
1214 print_stack_frame_to_string (MonoMethod *method, gint32 native_offset, gint32 il_offset, gboolean managed,
1215                              gpointer data)
1216 {
1217         GString *p = (GString*)data;
1218
1219         if (method) {
1220                 gchar *location = mono_debug_print_stack_frame (method, native_offset, mono_domain_get ());
1221                 g_string_append_printf (p, "  %s\n", location);
1222                 g_free (location);
1223         } else
1224                 g_string_append_printf (p, "  at <unknown> <0x%05x>\n", native_offset);
1225
1226         return FALSE;
1227 }
1228
1229 static gboolean handling_sigsegv = FALSE;
1230
1231 /*
1232  * mono_handle_native_sigsegv:
1233  *
1234  *   Handle a SIGSEGV received while in native code by printing diagnostic 
1235  * information and aborting.
1236  */
1237 void
1238 mono_handle_native_sigsegv (int signal, void *ctx)
1239 {
1240 #ifndef PLATFORM_WIN32
1241         struct sigaction sa;
1242 #endif
1243         if (handling_sigsegv)
1244                 return;
1245
1246         /* To prevent infinite loops when the stack walk causes a crash */
1247         handling_sigsegv = TRUE;
1248
1249         fprintf (stderr, "Stacktrace:\n\n");
1250
1251         mono_jit_walk_stack (print_stack_frame, TRUE, stderr);
1252
1253         fflush (stderr);
1254
1255 #ifdef HAVE_BACKTRACE_SYMBOLS
1256  {
1257         void *array [256];
1258         char **names;
1259         int i, size;
1260         const char *signal_str = (signal == SIGSEGV) ? "SIGSEGV" : "SIGABRT";
1261
1262         fprintf (stderr, "\nNative stacktrace:\n\n");
1263
1264         size = backtrace (array, 256);
1265         names = backtrace_symbols (array, size);
1266         for (i =0; i < size; ++i) {
1267                 fprintf (stderr, "\t%s\n", names [i]);
1268         }
1269         free (names);
1270
1271         fflush (stderr);
1272
1273         /* Try to get more meaningful information using gdb */
1274
1275 #if !defined(PLATFORM_WIN32) && defined(HAVE_SYS_SYSCALL_H) && defined(SYS_fork)
1276         if (!mini_get_debug_options ()->no_gdb_backtrace) {
1277                 /* From g_spawn_command_line_sync () in eglib */
1278                 int res;
1279                 int stdout_pipe [2] = { -1, -1 };
1280                 pid_t pid;
1281                 const char *argv [16];
1282                 char buf1 [128];
1283                 int status;
1284                 char buffer [1024];
1285
1286                 res = pipe (stdout_pipe);
1287                 g_assert (res != -1);
1288                         
1289                 //pid = fork ();
1290                 /*
1291                  * glibc fork acquires some locks, so if the crash happened inside malloc/free,
1292                  * it will deadlock. Call the syscall directly instead.
1293                  */
1294                 pid = syscall (SYS_fork);
1295                 if (pid == 0) {
1296                         close (stdout_pipe [0]);
1297                         dup2 (stdout_pipe [1], STDOUT_FILENO);
1298
1299                         for (i = getdtablesize () - 1; i >= 3; i--)
1300                                 close (i);
1301
1302                         argv [0] = g_find_program_in_path ("gdb");
1303                         if (argv [0] == NULL) {
1304                                 close (STDOUT_FILENO);
1305                                 exit (1);
1306                         }
1307
1308                         argv [1] = "-ex";
1309                         sprintf (buf1, "attach %ld", (long)getpid ());
1310                         argv [2] = buf1;
1311                         argv [3] = "--ex";
1312                         argv [4] = "info threads";
1313                         argv [5] = "--ex";
1314                         argv [6] = "thread apply all bt";
1315                         argv [7] = "--batch";
1316                         argv [8] = 0;
1317
1318                         execv (argv [0], (char**)argv);
1319                         exit (1);
1320                 }
1321
1322                 close (stdout_pipe [1]);
1323
1324                 fprintf (stderr, "\nDebug info from gdb:\n\n");
1325
1326                 while (1) {
1327                         int nread = read (stdout_pipe [0], buffer, 1024);
1328
1329                         if (nread <= 0)
1330                                 break;
1331                         write (STDERR_FILENO, buffer, nread);
1332                 }               
1333
1334                 waitpid (pid, &status, WNOHANG);
1335         }
1336 #endif
1337         /*
1338          * A SIGSEGV indicates something went very wrong so we can no longer depend
1339          * on anything working. So try to print out lots of diagnostics, starting 
1340          * with ones which have a greater chance of working.
1341          */
1342         fprintf (stderr,
1343                          "\n"
1344                          "=================================================================\n"
1345                          "Got a %s while executing native code. This usually indicates\n"
1346                          "a fatal error in the mono runtime or one of the native libraries \n"
1347                          "used by your application.\n"
1348                          "=================================================================\n"
1349                          "\n", signal_str);
1350
1351  }
1352 #endif
1353
1354 #ifndef PLATFORM_WIN32
1355
1356         /* Remove our SIGABRT handler */
1357         sa.sa_handler = SIG_DFL;
1358         sigemptyset (&sa.sa_mask);
1359         sa.sa_flags = 0;
1360
1361         g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
1362
1363 #endif
1364
1365         abort ();
1366 }
1367
1368 /*
1369  * mono_print_thread_dump:
1370  *
1371  *   Print information about the current thread to stdout.
1372  * SIGCTX can be NULL, allowing this to be called from gdb.
1373  */
1374 void
1375 mono_print_thread_dump (void *sigctx)
1376 {
1377         MonoThread *thread = mono_thread_current ();
1378 #if defined(__i386__) || defined(__x86_64__)
1379         MonoContext ctx;
1380 #endif
1381         GString* text = g_string_new (0);
1382         char *name;
1383         GError *error = NULL;
1384
1385         if (thread->name) {
1386                 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
1387                 g_assert (!error);
1388                 g_string_append_printf (text, "\n\"%s\"", name);
1389                 g_free (name);
1390         }
1391         else
1392                 g_string_append (text, "\n\"\"");
1393
1394         g_string_append_printf (text, " tid=0x%p this=0x%p:\n", (gpointer)(gsize)thread->tid, thread);
1395
1396         /* FIXME: */
1397 #if defined(__i386__) || defined(__x86_64__)
1398         if (!sigctx)
1399                 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_print_thread_dump);
1400         else
1401                 mono_arch_sigctx_to_monoctx (sigctx, &ctx);
1402
1403         mono_jit_walk_stack_from_ctx (print_stack_frame_to_string, &ctx, TRUE, text);
1404 #else
1405         printf ("\t<Stack traces in thread dumps not supported on this platform>\n");
1406 #endif
1407
1408         fprintf (stdout, text->str);
1409         g_string_free (text, TRUE);
1410         fflush (stdout);
1411 }