3 * Support for verbose unmanaged crash dumps
6 * Alexander Kyte (alkyte@microsoft.com)
8 * (C) 2018 Microsoft, Inc.
13 #include <mono/utils/mono-state.h>
14 #include <mono/utils/atomic.h>
16 #ifndef DISABLE_CRASH_REPORTING
18 #include <mono/utils/mono-threads-coop.h>
19 #include <mono/metadata/object-internals.h>
20 #include <mono/metadata/mono-config-dirs.h>
22 #include <sys/param.h>
24 #ifdef HAVE_SYS_STAT_H
27 #include <utils/mono-threads-debug.h>
29 extern GCStats mono_gc_stats
;
32 #include <mono/mini/mini-runtime.h>
33 #include <mono/utils/mono-threads-debug.h>
34 #include <mono/utils/mono-merp.h>
37 #include <mach/mach.h>
38 #include <mach/task_info.h>
41 #ifdef HAVE_SYS_SYSCTL_H
42 #include <sys/sysctl.h>
45 #ifdef HAVE_SYS_MMAN_H
50 // OSX 10.9 does not have MAP_ANONYMOUS
51 #if !defined(MAP_ANONYMOUS)
52 #define NO_MAP_ANONYMOUS
54 #define MAP_ANONYMOUS MAP_ANON
56 #define MAP_ANONYMOUS 0
61 #ifdef HAVE_EXECINFO_H
65 #if defined(ENABLE_CHECKED_BUILD_CRASH_REPORTING) && defined (ENABLE_OVERRIDABLE_ALLOCATORS)
66 // Fixme: put behind preprocessor symbol?
68 assert_not_reached_mem (const char *msg
)
70 g_async_safe_printf ("%s\n", msg
);
73 pid_t crashed_pid
= getpid ();
75 g_async_safe_printf ("Attach to PID %d. Supervisor thread will signal us shortly.\n", crashed_pid
);
77 // Sleep for 1 second.
78 g_usleep (1000 * 1000);
86 assert_not_reached_fn_ptr_free (gpointer ptr
)
88 // Wrap the macro to provide as a function pointer
89 assert_not_reached_mem ("Attempted to call free during merp dump");
93 assert_not_reached_fn_ptr_malloc (gsize size
)
95 // Wrap the macro to provide as a function pointer
96 assert_not_reached_mem ("Attempted to call malloc during merp dump");
101 assert_not_reached_fn_ptr_realloc (gpointer obj
, gsize size
)
103 // Wrap the macro to provide as a function pointer
104 assert_not_reached_mem ("Attempted to call realloc during merp dump");
109 assert_not_reached_fn_ptr_calloc (gsize n
, gsize x
)
111 // Wrap the macro to provide as a function pointer
112 assert_not_reached_mem ("Attempted to call calloc during merp dump");
115 #endif /* defined(ENABLE_CHECKED_BUILD_CRASH_REPORTING) && defined (ENABLE_OVERRIDABLE_ALLOCATORS) */
118 mono_summarize_toggle_assertions (gboolean enable
)
120 #if defined(ENABLE_CHECKED_BUILD_CRASH_REPORTING) && defined (ENABLE_OVERRIDABLE_ALLOCATORS)
121 static GMemVTable g_mem_vtable_backup
;
122 static gboolean saved
;
125 g_mem_get_vtable (&g_mem_vtable_backup
);
128 GMemVTable g_mem_vtable_assert
= { assert_not_reached_fn_ptr_malloc
, assert_not_reached_fn_ptr_realloc
, assert_not_reached_fn_ptr_free
, assert_not_reached_fn_ptr_calloc
};
129 g_mem_set_vtable (&g_mem_vtable_assert
);
131 g_mem_set_vtable (&g_mem_vtable_backup
);
135 mono_memory_barrier ();
140 const char *directory
;
141 MonoSummaryStage level
;
142 } MonoSummaryTimeline
;
144 static const char *configured_timeline_dir
;
145 static MonoSummaryTimeline log
;
148 file_for_summary_stage (const char *directory
, MonoSummaryStage stage
, gchar
*buff
, size_t sizeof_buff
)
150 g_snprintf (buff
, sizeof_buff
, "%s%scrash_stage_%d", directory
, G_DIR_SEPARATOR_S
, stage
);
154 create_stage_mark_file (void)
157 file_for_summary_stage (log
.directory
, log
.level
, out_file
, sizeof(out_file
));
158 int handle
= g_open (out_file
, O_WRONLY
| O_CREAT
, S_IWUSR
| S_IRUSR
| S_IRGRP
| S_IROTH
);
163 mono_summarize_set_timeline_dir (const char *directory
)
166 configured_timeline_dir
= strdup (directory
);
167 return g_ensure_directory_exists (directory
);
169 configured_timeline_dir
= NULL
;
175 mono_summarize_timeline_start (void)
177 memset (&log
, 0, sizeof (log
));
179 if (!configured_timeline_dir
)
182 log
.directory
= configured_timeline_dir
;
183 mono_summarize_timeline_phase_log (MonoSummarySetup
);
187 mono_summarize_double_fault_log (void)
189 mono_summarize_timeline_phase_log (MonoSummaryDoubleFault
);
193 mono_summarize_timeline_phase_log (MonoSummaryStage next
)
198 MonoSummaryStage out_level
;
200 case MonoSummaryNone
:
201 out_level
= MonoSummarySetup
;
203 case MonoSummarySetup
:
204 out_level
= MonoSummarySuspendHandshake
;
206 case MonoSummarySuspendHandshake
:
207 out_level
= MonoSummaryUnmanagedStacks
;
209 case MonoSummaryUnmanagedStacks
:
210 out_level
= MonoSummaryManagedStacks
;
212 case MonoSummaryManagedStacks
:
213 out_level
= MonoSummaryStateWriter
;
215 case MonoSummaryStateWriter
:
216 out_level
= MonoSummaryStateWriterDone
;
218 case MonoSummaryStateWriterDone
:
220 if (mono_merp_enabled ()) {
221 out_level
= MonoSummaryMerpWriter
;
225 out_level
= MonoSummaryCleanup
;
228 case MonoSummaryMerpWriter
:
229 out_level
= MonoSummaryMerpInvoke
;
231 case MonoSummaryMerpInvoke
:
232 out_level
= MonoSummaryCleanup
;
234 case MonoSummaryCleanup
:
235 out_level
= MonoSummaryDone
;
238 case MonoSummaryDone
:
239 g_async_safe_printf ("Trying to log crash reporter timeline, already at done %d\n", log
.level
);
242 g_async_safe_printf ("Trying to log crash reporter timeline, illegal state %d\n", log
.level
);
246 g_assertf(out_level
== next
|| next
== MonoSummaryDoubleFault
, "Log Error: Log transition to %d, actual expected next step is %d\n", next
, out_level
);
248 log
.level
= out_level
;
249 create_stage_mark_file ();
250 // To check, comment out normally
251 // DO NOT MERGE UNCOMMENTED
252 // As this does a lot of FILE io
254 // g_assert (out_level == mono_summarize_timeline_read_level (log.directory, FALSE));
256 if (out_level
== MonoSummaryDone
)
257 memset (&log
, 0, sizeof (log
));
263 mem_file_name (long tag
, char *name
, size_t limit
)
266 pid_t pid
= getpid ();
267 g_snprintf (name
, limit
, "mono_crash.mem.%d.%lx.blob", pid
, tag
);
271 mono_state_alloc_mem (MonoStateMem
*mem
, long tag
, size_t size
)
274 mem_file_name (tag
, name
, sizeof (name
));
276 memset (mem
, 0, sizeof (*mem
));
281 if (!g_hasenv ("MONO_CRASH_NOFILE"))
282 mem
->handle
= g_open (name
, O_RDWR
| O_CREAT
| O_EXCL
, S_IWUSR
| S_IRUSR
| S_IRGRP
| S_IROTH
);
284 if (mem
->handle
< 1) {
285 mem
->mem
= (gpointer
*) mmap (0, mem
->size
, PROT_READ
| PROT_WRITE
, MAP_PRIVATE
| MAP_ANONYMOUS
, -1, 0);
287 lseek (mem
->handle
, mem
->size
, SEEK_SET
);
288 g_write (mem
->handle
, "", 1);
290 mem
->mem
= (gpointer
*) mmap (0, mem
->size
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, mem
->handle
, 0);
292 if (mem
->mem
== GINT_TO_POINTER (-1))
299 mono_state_free_mem (MonoStateMem
*mem
)
304 msync(mem
->mem
, mem
->size
, MS_SYNC
);
305 munmap (mem
->mem
, mem
->size
);
307 // Note: We aren't calling msync on this file.
308 // There is no guarantee that we're going to persist
309 // changes to it at all, in the case that we fail before
310 // removing it. Don't try to debug where in the crash we were
311 // by the file contents.
315 g_async_safe_printf ("NULL handle mono-state mem on freeing\n");
318 mem_file_name (mem
->tag
, name
, sizeof (name
));
323 timeline_has_level (const char *directory
, char *log_file
, size_t log_file_size
, gboolean clear
, MonoSummaryStage stage
)
325 memset (log_file
, 0, log_file_size
);
326 file_for_summary_stage (directory
, stage
, log_file
, log_file_size
);
327 gboolean exists
= g_file_test (log_file
, G_FILE_TEST_EXISTS
);
335 mono_summarize_timeline_read_level (const char *directory
, gboolean clear
)
340 directory
= log
.directory
;
343 return MonoSummaryNone
;
345 // Make sure that clear gets to erase all of these files if they exist
346 gboolean has_level_done
= timeline_has_level (directory
, out_file
, sizeof(out_file
), clear
, MonoSummaryDone
);
347 gboolean has_level_cleanup
= timeline_has_level (directory
, out_file
, sizeof(out_file
), clear
, MonoSummaryCleanup
);
348 gboolean has_level_merp_invoke
= timeline_has_level (directory
, out_file
, sizeof(out_file
), clear
, MonoSummaryMerpInvoke
);
349 gboolean has_level_merp_writer
= timeline_has_level (directory
, out_file
, sizeof(out_file
), clear
, MonoSummaryMerpWriter
);
350 gboolean has_level_state_writer
= timeline_has_level (directory
, out_file
, sizeof(out_file
), clear
, MonoSummaryStateWriter
);
351 gboolean has_level_state_writer_done
= timeline_has_level (directory
, out_file
, sizeof(out_file
), clear
, MonoSummaryStateWriterDone
);
352 gboolean has_level_managed_stacks
= timeline_has_level (directory
, out_file
, sizeof(out_file
), clear
, MonoSummaryManagedStacks
);
353 gboolean has_level_unmanaged_stacks
= timeline_has_level (directory
, out_file
, sizeof(out_file
), clear
, MonoSummaryUnmanagedStacks
);
354 gboolean has_level_suspend_handshake
= timeline_has_level (directory
, out_file
, sizeof(out_file
), clear
, MonoSummarySuspendHandshake
);
355 gboolean has_level_setup
= timeline_has_level (directory
, out_file
, sizeof(out_file
), clear
, MonoSummarySetup
);
358 return MonoSummaryDone
;
359 else if (has_level_cleanup
)
360 return MonoSummaryCleanup
;
361 else if (has_level_merp_invoke
)
362 return MonoSummaryMerpInvoke
;
363 else if (has_level_merp_writer
)
364 return MonoSummaryMerpWriter
;
365 else if (has_level_state_writer_done
)
366 return MonoSummaryStateWriterDone
;
367 else if (has_level_state_writer
)
368 return MonoSummaryStateWriter
;
369 else if (has_level_managed_stacks
)
370 return MonoSummaryManagedStacks
;
371 else if (has_level_unmanaged_stacks
)
372 return MonoSummaryUnmanagedStacks
;
373 else if (has_level_suspend_handshake
)
374 return MonoSummarySuspendHandshake
;
375 else if (has_level_setup
)
376 return MonoSummarySetup
;
378 return MonoSummaryNone
;
382 assert_has_space (MonoStateWriter
*writer
)
384 // Each individual key/value append should be roughly less than this many characters
385 const int margin
= 35;
387 // Not using static, exit
388 if (writer
->allocated_len
== 0)
391 g_assertf (writer
->allocated_len
- writer
->len
>= margin
, "Ran out of memory to create crash dump json blob. Current state:\n%s\n", writer
->output_str
);
395 mono_state_writer_printf (MonoStateWriter
*writer
, const gchar
*format
, ...)
397 g_assert (writer
->len
== strlen(writer
->output_str
));
400 va_start (args
, format
);
401 int written
= vsnprintf (&writer
->output_str
[writer
->len
], writer
->allocated_len
- writer
->len
, format
, args
);
404 if (written
> 0) writer
->len
+= written
;
405 g_assert (writer
->len
== strlen (writer
->output_str
));
409 mono_state_writer_indent (MonoStateWriter
*writer
)
411 for (int i
= 0; i
< writer
->indent
; ++i
)
412 mono_state_writer_printf(writer
, " ");
416 mono_state_writer_object_key (MonoStateWriter
*writer
, const char *key
)
418 mono_state_writer_indent (writer
);
419 mono_state_writer_printf(writer
, "\"%s\" : ", key
);
423 mono_native_state_add_ctx (MonoStateWriter
*writer
, MonoContext
*ctx
)
426 mono_state_writer_indent (writer
);
427 mono_state_writer_object_key (writer
, "ctx");
428 mono_state_writer_printf(writer
, "{\n");
431 assert_has_space (writer
);
432 mono_state_writer_indent (writer
);
433 mono_state_writer_object_key (writer
, "IP");
434 mono_state_writer_printf(writer
, "\"%p\",\n", (gpointer
) MONO_CONTEXT_GET_IP (ctx
));
436 assert_has_space (writer
);
437 mono_state_writer_indent (writer
);
438 mono_state_writer_object_key (writer
, "SP");
439 mono_state_writer_printf(writer
, "\"%p\",\n", (gpointer
) MONO_CONTEXT_GET_SP (ctx
));
441 assert_has_space (writer
);
442 mono_state_writer_indent (writer
);
443 mono_state_writer_object_key (writer
, "BP");
444 mono_state_writer_printf(writer
, "\"%p\"\n", (gpointer
) MONO_CONTEXT_GET_BP (ctx
));
447 mono_state_writer_indent (writer
);
448 mono_state_writer_printf(writer
, "}");
452 mono_native_state_add_frame (MonoStateWriter
*writer
, MonoFrameSummary
*frame
)
454 mono_state_writer_indent (writer
);
455 mono_state_writer_printf(writer
, "{\n");
458 assert_has_space (writer
);
459 mono_state_writer_indent (writer
);
460 mono_state_writer_object_key (writer
, "is_managed");
461 mono_state_writer_printf(writer
, "\"%s\",", frame
->is_managed
? "true" : "false");
463 if (frame
->unmanaged_data
.is_trampoline
) {
464 mono_state_writer_printf(writer
, "\n");
465 assert_has_space (writer
);
466 mono_state_writer_indent (writer
);
467 mono_state_writer_object_key (writer
, "is_trampoline");
468 mono_state_writer_printf(writer
, "\"true\",");
471 if (frame
->is_managed
) {
472 mono_state_writer_printf(writer
, "\n");
473 assert_has_space (writer
);
474 mono_state_writer_indent (writer
);
475 mono_state_writer_object_key (writer
, "guid");
476 mono_state_writer_printf(writer
, "\"%s\",\n", frame
->managed_data
.guid
);
478 assert_has_space (writer
);
479 mono_state_writer_indent (writer
);
480 mono_state_writer_object_key (writer
, "token");
481 mono_state_writer_printf(writer
, "\"0x%05x\",\n", frame
->managed_data
.token
);
483 assert_has_space (writer
);
484 mono_state_writer_indent (writer
);
485 mono_state_writer_object_key (writer
, "native_offset");
486 mono_state_writer_printf(writer
, "\"0x%x\",\n", frame
->managed_data
.native_offset
);
488 #ifndef MONO_PRIVATE_CRASHES
489 if (frame
->managed_data
.name
!= NULL
) {
490 assert_has_space (writer
);
491 mono_state_writer_indent (writer
);
492 mono_state_writer_object_key (writer
, "method_name");
493 mono_state_writer_printf(writer
, "\"%s\",\n", frame
->managed_data
.name
);
497 assert_has_space (writer
);
498 mono_state_writer_indent (writer
);
499 mono_state_writer_object_key (writer
, "filename");
500 mono_state_writer_printf(writer
, "\"%s\",\n", frame
->managed_data
.filename
);
502 assert_has_space (writer
);
503 mono_state_writer_indent (writer
);
504 mono_state_writer_object_key (writer
, "sizeofimage");
505 mono_state_writer_printf(writer
, "\"0x%x\",\n", frame
->managed_data
.image_size
);
507 assert_has_space (writer
);
508 mono_state_writer_indent (writer
);
509 mono_state_writer_object_key (writer
, "timestamp");
510 mono_state_writer_printf(writer
, "\"0x%x\",\n", frame
->managed_data
.time_date_stamp
);
512 assert_has_space (writer
);
513 mono_state_writer_indent (writer
);
514 mono_state_writer_object_key (writer
, "il_offset");
515 mono_state_writer_printf(writer
, "\"0x%05x\"\n", frame
->managed_data
.il_offset
);
518 mono_state_writer_printf(writer
, "\n");
519 assert_has_space (writer
);
520 mono_state_writer_indent (writer
);
521 mono_state_writer_object_key (writer
, "native_address");
522 if (frame
->unmanaged_data
.ip
) {
523 mono_state_writer_printf(writer
, "\"0x%" PRIx64
"\"", (guint64
) frame
->unmanaged_data
.ip
);
525 mono_state_writer_printf(writer
, "\"unregistered\"");
527 if (frame
->unmanaged_data
.ip
) {
528 mono_state_writer_printf(writer
, ",\n");
530 assert_has_space (writer
);
531 mono_state_writer_indent (writer
);
532 mono_state_writer_object_key (writer
, "native_offset");
533 mono_state_writer_printf(writer
, "\"0x%05x\"", frame
->unmanaged_data
.offset
);
536 if (frame
->unmanaged_data
.module
[0] != '\0') {
537 mono_state_writer_printf(writer
, ",\n");
539 assert_has_space (writer
);
540 mono_state_writer_indent (writer
);
541 mono_state_writer_object_key (writer
, "native_module");
542 mono_state_writer_printf(writer
, "\"%s\"", frame
->unmanaged_data
.module
);
545 if (frame
->unmanaged_data
.has_name
) {
546 mono_state_writer_printf(writer
, ",\n");
548 assert_has_space (writer
);
549 mono_state_writer_indent (writer
);
550 mono_state_writer_object_key (writer
, "unmanaged_name");
551 mono_state_writer_printf(writer
, "\"%s\"\n", frame
->str_descr
);
553 mono_state_writer_printf(writer
, "\n");
557 mono_state_writer_indent (writer
);
559 mono_state_writer_printf(writer
, "}\n");
563 mono_native_state_add_frames (MonoStateWriter
*writer
, int num_frames
, MonoFrameSummary
*frames
, const char *label
)
565 mono_state_writer_indent (writer
);
566 mono_state_writer_object_key (writer
, label
);
568 mono_state_writer_printf(writer
, "[\n");
570 for (int i
= 0; i
< num_frames
; ++i
) {
572 mono_state_writer_printf(writer
, ",\n");
573 mono_native_state_add_frame (writer
, &frames
[i
]);
575 mono_state_writer_printf(writer
, "\n");
577 mono_state_writer_indent (writer
);
579 mono_state_writer_printf(writer
, "]");
583 mono_native_state_add_managed_exc (MonoStateWriter
*writer
, MonoExcSummary
*exc
)
585 mono_state_writer_indent (writer
);
586 mono_state_writer_printf(writer
, "{\n");
589 assert_has_space (writer
);
590 mono_state_writer_indent (writer
);
591 mono_state_writer_object_key (writer
, "type");
592 mono_state_writer_printf(writer
, "\"%s.%s\",\n", m_class_get_name_space (exc
->managed_exc_type
), m_class_get_name (exc
->managed_exc_type
));
594 mono_native_state_add_frames (writer
, exc
->num_managed_frames
, exc
->managed_frames
, "managed_frames");
596 mono_state_writer_indent (writer
);
598 mono_state_writer_printf(writer
, "}\n");
602 mono_native_state_add_managed_excs (MonoStateWriter
*writer
, int num_excs
, MonoExcSummary
*excs
)
604 mono_state_writer_indent (writer
);
605 mono_state_writer_object_key (writer
, "exceptions");
607 mono_state_writer_printf(writer
, "[\n");
609 for (int i
= 0; i
< num_excs
; ++i
) {
611 mono_state_writer_printf(writer
, ",\n");
612 mono_native_state_add_managed_exc (writer
, &excs
[i
]);
615 mono_state_writer_indent (writer
);
617 mono_state_writer_printf(writer
, "]");
622 mono_native_state_add_thread (MonoStateWriter
*writer
, MonoThreadSummary
*thread
, MonoContext
*ctx
, gboolean first_thread
, gboolean crashing_thread
)
624 assert_has_space (writer
);
627 mono_state_writer_printf(writer
, ",\n");
630 mono_state_writer_indent (writer
);
631 mono_state_writer_printf(writer
, "{\n");
634 assert_has_space (writer
);
635 mono_state_writer_indent (writer
);
636 mono_state_writer_object_key (writer
, "is_managed");
637 mono_state_writer_printf(writer
, "%s,\n", thread
->is_managed
? "true" : "false");
639 assert_has_space (writer
);
640 mono_state_writer_indent (writer
);
641 mono_state_writer_object_key (writer
, "offset_free_hash");
642 mono_state_writer_printf(writer
, "\"0x%" PRIx64
"\",\n", thread
->hashes
.offset_free_hash
);
644 assert_has_space (writer
);
645 mono_state_writer_indent (writer
);
646 mono_state_writer_object_key (writer
, "offset_rich_hash");
647 mono_state_writer_printf(writer
, "\"0x%" PRIx64
"\",\n", thread
->hashes
.offset_rich_hash
);
649 assert_has_space (writer
);
650 mono_state_writer_indent (writer
);
651 mono_state_writer_object_key (writer
, "crashed");
652 mono_state_writer_printf(writer
, "%s,\n", crashing_thread
? "true" : "false");
654 assert_has_space (writer
);
655 mono_state_writer_indent (writer
);
656 mono_state_writer_object_key (writer
, "native_thread_id");
657 mono_state_writer_printf(writer
, "\"0x%" PRIx64
"\",\n", (guint64
) thread
->native_thread_id
);
659 assert_has_space (writer
);
660 mono_state_writer_indent (writer
);
661 mono_state_writer_object_key (writer
, "thread_info_addr");
662 mono_state_writer_printf(writer
, "\"0x%" PRIx64
"\"", (guint64
) thread
->info_addr
);
664 if (thread
->error_msg
!= NULL
) {
665 mono_state_writer_printf(writer
, ",\n");
666 assert_has_space (writer
);
667 mono_state_writer_indent (writer
);
668 mono_state_writer_object_key (writer
, "dumping_error");
669 mono_state_writer_printf(writer
, "\"%s\"", thread
->error_msg
);
672 if (thread
->name
[0] != '\0') {
673 mono_state_writer_printf(writer
, ",\n");
674 assert_has_space (writer
);
675 mono_state_writer_indent (writer
);
676 mono_state_writer_object_key (writer
, "thread_name");
677 mono_state_writer_printf(writer
, "\"%s\"", thread
->name
);
681 mono_state_writer_printf(writer
, ",\n");
682 mono_native_state_add_ctx (writer
, ctx
);
685 if (thread
->num_exceptions
> 0) {
686 mono_state_writer_printf(writer
, ",\n");
687 mono_native_state_add_managed_excs (writer
, thread
->num_exceptions
, thread
->exceptions
);
690 if (thread
->num_managed_frames
> 0) {
691 mono_state_writer_printf(writer
, ",\n");
692 mono_native_state_add_frames (writer
, thread
->num_managed_frames
, thread
->managed_frames
, "managed_frames");
695 if (thread
->num_unmanaged_frames
> 0) {
696 mono_state_writer_printf(writer
, ",\n");
697 mono_native_state_add_frames (writer
, thread
->num_unmanaged_frames
, thread
->unmanaged_frames
, "unmanaged_frames");
700 mono_state_writer_printf(writer
, "\n");
702 mono_state_writer_indent (writer
);
703 mono_state_writer_printf(writer
, "}");
707 mono_native_state_add_ee_info (MonoStateWriter
*writer
)
709 #ifndef MONO_PRIVATE_CRASHES
710 // FIXME: setup callbacks to enable
711 /*const char *aot_mode;*/
712 /*MonoAotMode mono_aot_mode = mono_jit_get_aot_mode ();*/
713 /*switch (mono_aot_mode) {*/
714 /*case MONO_AOT_MODE_NONE:*/
715 /*aot_mode = "none";*/
717 /*case MONO_AOT_MODE_NORMAL:*/
718 /*aot_mode = "normal";*/
720 /*case MONO_AOT_MODE_HYBRID:*/
721 /*aot_mode = "hybrid";*/
723 /*case MONO_AOT_MODE_FULL:*/
724 /*aot_mode = "full";*/
726 /*case MONO_AOT_MODE_LLVMONLY:*/
727 /*aot_mode = "llvmonly";*/
729 /*case MONO_AOT_MODE_INTERP:*/
730 /*aot_mode = "interp";*/
732 /*case MONO_AOT_MODE_INTERP_LLVMONLY:*/
733 /*aot_mode = "interp_llvmonly";*/
736 /*aot_mode = "error";*/
739 assert_has_space (writer
);
740 mono_state_writer_indent (writer
);
741 mono_state_writer_object_key (writer
, "execution_context");
742 mono_state_writer_printf(writer
, "{\n");
745 /*mono_state_writer_indent (writer);*/
746 /*mono_state_writer_object_key (writer, "aot_mode");*/
747 /*mono_state_writer_printf(writer, "\"%s\",\n", aot_mode);*/
749 /*mono_state_writer_indent (writer);*/
750 /*mono_state_writer_object_key (writer, "mono_use_llvm");*/
751 /*mono_state_writer_printf(writer, "\"%s\",\n", mono_use_llvm ? "true" : "false");*/
753 assert_has_space (writer
);
754 mono_state_writer_indent (writer
);
755 mono_state_writer_object_key (writer
, "coop-enabled");
756 mono_state_writer_printf(writer
, "\"%s\"\n", mono_threads_is_cooperative_suspension_enabled () ? "true" : "false");
759 mono_state_writer_indent (writer
);
760 mono_state_writer_printf(writer
, "},\n");
764 // Taken from driver.c
765 #if defined(MONO_ARCH_ARCHITECTURE)
766 /* Redefine MONO_ARCHITECTURE to include more information */
767 #undef MONO_ARCHITECTURE
768 #define MONO_ARCHITECTURE MONO_ARCH_ARCHITECTURE
772 mono_native_state_add_version (MonoStateWriter
*writer
)
774 assert_has_space (writer
);
775 mono_state_writer_indent (writer
);
776 mono_state_writer_object_key (writer
, "configuration");
777 mono_state_writer_printf(writer
, "{\n");
780 assert_has_space (writer
);
781 mono_state_writer_indent (writer
);
782 mono_state_writer_object_key (writer
, "version");
783 mono_state_writer_printf(writer
, "\"(%s) (%s)\",\n", VERSION
, mono_get_runtime_callbacks ()->get_runtime_build_version ());
785 assert_has_space (writer
);
786 mono_state_writer_indent (writer
);
787 mono_state_writer_object_key (writer
, "tlc");
788 #ifdef MONO_KEYWORD_THREAD
789 mono_state_writer_printf(writer
, "\"__thread\",\n");
791 mono_state_writer_printf(writer
, "\"normal\",\n");
792 #endif /* MONO_KEYWORD_THREAD */
794 assert_has_space (writer
);
795 mono_state_writer_indent (writer
);
796 mono_state_writer_object_key (writer
, "sigsgev");
797 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
798 mono_state_writer_printf(writer
, "\"altstack\",\n");
800 mono_state_writer_printf(writer
, "\"normal\",\n");
803 assert_has_space (writer
);
804 mono_state_writer_indent (writer
);
805 mono_state_writer_object_key (writer
, "notifications");
807 mono_state_writer_printf(writer
, "\"epoll\",\n");
808 #elif defined(HAVE_KQUEUE)
809 mono_state_writer_printf(writer
, "\"kqueue\",\n");
811 mono_state_writer_printf(writer
, "\"thread+polling\",\n");
814 assert_has_space (writer
);
815 mono_state_writer_indent (writer
);
816 mono_state_writer_object_key (writer
, "architecture");
817 mono_state_writer_printf(writer
, "\"%s\",\n", MONO_ARCHITECTURE
);
819 assert_has_space (writer
);
820 mono_state_writer_indent (writer
);
821 mono_state_writer_object_key (writer
, "disabled_features");
822 mono_state_writer_printf(writer
, "\"%s\",\n", DISABLED_FEATURES
);
824 assert_has_space (writer
);
825 mono_state_writer_indent (writer
);
826 mono_state_writer_object_key (writer
, "smallconfig");
827 #ifdef MONO_SMALL_CONFIG
828 mono_state_writer_printf(writer
, "\"enabled\",\n");
830 mono_state_writer_printf(writer
, "\"disabled\",\n");
833 assert_has_space (writer
);
834 mono_state_writer_indent (writer
);
835 mono_state_writer_object_key (writer
, "bigarrays");
836 #ifdef MONO_BIG_ARRAYS
837 mono_state_writer_printf(writer
, "\"enabled\",\n");
839 mono_state_writer_printf(writer
, "\"disabled\",\n");
842 assert_has_space (writer
);
843 mono_state_writer_indent (writer
);
844 mono_state_writer_object_key (writer
, "softdebug");
845 #if !defined(DISABLE_SDB)
846 mono_state_writer_printf(writer
, "\"enabled\",\n");
848 mono_state_writer_printf(writer
, "\"disabled\",\n");
851 assert_has_space (writer
);
852 mono_state_writer_indent (writer
);
853 mono_state_writer_object_key (writer
, "interpreter");
854 #ifndef DISABLE_INTERPRETER
855 mono_state_writer_printf(writer
, "\"enabled\",\n");
857 mono_state_writer_printf(writer
, "\"disabled\",\n");
860 assert_has_space (writer
);
861 mono_state_writer_indent (writer
);
862 mono_state_writer_object_key (writer
, "llvm_support");
863 #ifdef MONO_ARCH_LLVM_SUPPORTED
865 mono_state_writer_printf(writer
, "\"%d\",\n", LLVM_API_VERSION
);
867 mono_state_writer_printf(writer
, "\"disabled\",\n");
871 const char *susp_policy
= mono_threads_suspend_policy_name (mono_threads_suspend_policy ());
872 assert_has_space (writer
);
873 mono_state_writer_indent (writer
);
874 mono_state_writer_object_key (writer
, "suspend");
875 mono_state_writer_printf(writer
, "\"%s\"\n", susp_policy
);
877 assert_has_space (writer
);
878 mono_state_writer_indent (writer
);
879 mono_state_writer_printf(writer
, "},\n");
884 mono_native_state_add_memory (MonoStateWriter
*writer
)
886 assert_has_space (writer
);
887 mono_state_writer_indent (writer
);
888 mono_state_writer_object_key (writer
, "memory");
889 mono_state_writer_printf(writer
, "{\n");
893 struct task_basic_info t_info
;
894 memset (&t_info
, 0, sizeof (t_info
));
895 mach_msg_type_number_t t_info_count
= TASK_BASIC_INFO_COUNT
;
896 task_name_t task
= mach_task_self ();
897 task_info(task
, TASK_BASIC_INFO
, (task_info_t
) &t_info
, &t_info_count
);
899 assert_has_space (writer
);
900 mono_state_writer_indent (writer
);
901 mono_state_writer_object_key (writer
, "Resident Size");
902 mono_state_writer_printf(writer
, "\"%lu\",\n", t_info
.resident_size
);
904 assert_has_space (writer
);
905 mono_state_writer_indent (writer
);
906 mono_state_writer_object_key (writer
, "Virtual Size");
907 mono_state_writer_printf(writer
, "\"%lu\",\n", t_info
.virtual_size
);
911 memcpy (&stats
, &mono_gc_stats
, sizeof (GCStats
));
913 assert_has_space (writer
);
914 mono_state_writer_indent (writer
);
915 mono_state_writer_object_key (writer
, "minor_gc_time");
916 mono_state_writer_printf(writer
, "\"%lld\",\n", stats
.minor_gc_time
);
918 assert_has_space (writer
);
919 mono_state_writer_indent (writer
);
920 mono_state_writer_object_key (writer
, "major_gc_time");
921 mono_state_writer_printf(writer
, "\"%lld\",\n", stats
.major_gc_time
);
923 assert_has_space (writer
);
924 mono_state_writer_indent (writer
);
925 mono_state_writer_object_key (writer
, "minor_gc_count");
926 mono_state_writer_printf(writer
, "\"%d\",\n", stats
.minor_gc_count
);
928 assert_has_space (writer
);
929 mono_state_writer_indent (writer
);
930 mono_state_writer_object_key (writer
, "major_gc_count");
931 mono_state_writer_printf(writer
, "\"%d\",\n", stats
.major_gc_count
);
933 assert_has_space (writer
);
934 mono_state_writer_indent (writer
);
935 mono_state_writer_object_key (writer
, "major_gc_time_concurrent");
936 mono_state_writer_printf(writer
, "\"%lld\"\n", stats
.major_gc_time_concurrent
);
939 mono_state_writer_indent (writer
);
940 mono_state_writer_printf(writer
, "},\n");
943 #define MONO_CRASH_REPORTING_MAPPING_LINE_LIMIT 30
945 #if !MONO_PRIVATE_CRASHES
948 mono_native_state_add_process_map (MonoStateWriter
*writer
)
950 #if defined(__linux__) && !defined(HOST_ANDROID)
951 int handle
= g_open ("/proc/self/maps", O_RDONLY
, S_IWUSR
| S_IRUSR
| S_IRGRP
| S_IROTH
);
953 g_async_safe_printf ("Couldn't find /proc/self/maps on Linux system. Continuing.");
957 assert_has_space (writer
);
958 mono_state_writer_indent (writer
);
959 mono_state_writer_object_key (writer
, "process_map");
960 mono_state_writer_printf(writer
, "[\n");
963 while (mapping
< MONO_CRASH_REPORTING_MAPPING_LINE_LIMIT
) {
965 mono_state_writer_printf (writer
, "\",\n");
967 mono_state_writer_printf (writer
, "\t\"");
971 gboolean newline
= FALSE
;
972 int charsCopied
= g_async_safe_fgets (line
, sizeof (line
), handle
, &newline
);
974 if (charsCopied
== 0)
977 for (int i
=0; i
< charsCopied
; i
++)
978 g_assert (isprint (line
[i
]));
980 g_assert (line
[charsCopied
] == '\0');
982 mono_state_writer_printf (writer
, "%s", line
);
992 mono_state_writer_printf (writer
, "\"");
994 mono_state_writer_indent (writer
);
996 mono_state_writer_printf(writer
, "],\n");
1005 mono_native_state_add_logged_message (MonoStateWriter
*writer
, const char *object_key
, const char *msg
)
1008 assert_has_space (writer
);
1009 mono_state_writer_indent (writer
);
1010 mono_state_writer_object_key (writer
, object_key
);
1014 if ((pos
= strchr (msg
, '\n')) != NULL
)
1015 length
= (size_t)(pos
- msg
);
1017 length
= strlen (msg
);
1018 length
= MIN (length
, INT_MAX
);
1020 mono_state_writer_printf(writer
, "\"%.*s\",\n", (int)length
, msg
);
1025 mono_native_state_add_prologue (MonoStateWriter
*writer
)
1027 mono_state_writer_printf(writer
, "{\n");
1030 assert_has_space (writer
);
1031 mono_state_writer_indent (writer
);
1032 mono_state_writer_object_key (writer
, "protocol_version");
1033 mono_state_writer_printf(writer
, "\"%s\",\n", MONO_NATIVE_STATE_PROTOCOL_VERSION
);
1035 mono_native_state_add_version (writer
);
1037 mono_native_state_add_ee_info (writer
);
1039 mono_native_state_add_memory (writer
);
1041 const char *assertion_msg
= g_get_assertion_message ();
1042 mono_native_state_add_logged_message (writer
, "assertion_message", assertion_msg
);
1044 const char *failfast_msg
= mono_crash_get_failfast_msg ();
1045 mono_native_state_add_logged_message (writer
, "failfast_message", failfast_msg
);
1048 #ifndef MONO_PRIVATE_CRASHES
1049 mono_native_state_add_process_map (writer
);
1052 // Start threads array
1053 assert_has_space (writer
);
1054 mono_state_writer_indent (writer
);
1055 mono_state_writer_object_key (writer
, "threads");
1056 mono_state_writer_printf(writer
, "[\n");
1060 mono_native_state_add_epilogue (MonoStateWriter
*writer
)
1062 mono_state_writer_printf(writer
, "\n");
1063 mono_state_writer_indent (writer
);
1064 mono_state_writer_printf(writer
, "]\n");
1068 mono_state_writer_indent (writer
);
1069 mono_state_writer_printf(writer
, "}");
1073 mono_native_state_init (MonoStateWriter
*writer
)
1075 mono_native_state_add_prologue (writer
);
1079 mono_native_state_emit (MonoStateWriter
*writer
)
1081 mono_native_state_add_epilogue (writer
);
1082 return writer
->output_str
;
1086 mono_native_state_free (MonoStateWriter
*writer
, gboolean free_data
)
1088 mono_native_state_add_epilogue (writer
);
1089 char *output
= NULL
;
1091 // Make this interface work like the g_string free does
1093 output
= g_strdup (writer
->output_str
);
1099 mono_state_writer_init (MonoStateWriter
*writer
, gchar
*output_str
, int len
)
1101 memset(writer
, 0, sizeof(*writer
));
1102 memset(output_str
, 0, len
* sizeof(gchar
));
1104 writer
->output_str
= output_str
;
1105 writer
->allocated_len
= len
;
1111 mono_summarize_native_state_begin (MonoStateWriter
*writer
, gchar
*mem
, int size
)
1114 mono_state_writer_init (writer
, mem
, size
);
1115 mono_native_state_init (writer
);
1119 mono_summarize_native_state_end (MonoStateWriter
*writer
)
1121 return mono_native_state_emit (writer
);
1125 mono_summarize_native_state_add_thread (MonoStateWriter
*writer
, MonoThreadSummary
*thread
, MonoContext
*ctx
, gboolean crashing_thread
)
1127 static gboolean not_first_thread
= FALSE
;
1128 mono_native_state_add_thread (writer
, thread
, ctx
, !not_first_thread
, crashing_thread
);
1129 not_first_thread
= TRUE
;
1133 mono_crash_dump (const char *jsonFile
, MonoStackHash
*hashes
)
1135 if (g_hasenv ("MONO_CRASH_NOFILE"))
1138 size_t size
= strlen (jsonFile
);
1140 gboolean success
= FALSE
;
1142 // Save up to 100 dump files for a given stacktrace hash
1143 for (int increment
= 0; increment
< 100; increment
++) {
1146 g_snprintf (name
, sizeof (name
), "mono_crash.%" PRIx64
".%d.json", hashes
->offset_free_hash
, increment
);
1148 int handle
= g_open (name
, O_WRONLY
| O_CREAT
| O_EXCL
, S_IWUSR
| S_IRUSR
| S_IRGRP
| S_IROTH
);
1150 g_write (handle
, jsonFile
, (guint32
) size
);
1162 g_assertf (!success
, "Couldn't create any of (many) attempted crash files\n");
1166 #endif // DISABLE_CRASH_REPORTING
1168 static volatile int32_t dump_status
;
1171 mono_dump_start (void)
1173 return (mono_atomic_xchg_i32(&dump_status
, 1) == 0); // return true if we started the dump
1177 mono_dump_complete (void)
1179 return (mono_atomic_xchg_i32(&dump_status
, 0) == 1); // return true if we completed the dump
1182 static char *saved_failfast_msg
;
1185 * mono_crash_save_failfast_msg:
1186 * \param msg the message to save. Takes ownership, caller shouldn't free
1188 * \returns the previous message - caller is responsible for freeing.
1191 mono_crash_save_failfast_msg (char *msg
)
1193 return (char*) mono_atomic_xchg_ptr ((gpointer
*)&saved_failfast_msg
, (void*)msg
);
1197 mono_crash_get_failfast_msg (void)
1199 return saved_failfast_msg
;