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