3 * Support for verbose unmanaged crash dumps
6 * Alexander Kyte (alkyte@microsoft.com)
8 * (C) 2018 Microsoft, Inc.
13 #include <mono/utils/json.h>
14 #include <mono/utils/mono-state.h>
15 #include <mono/metadata/object-internals.h>
19 extern GCStats mono_gc_stats
;
22 #include <mono/mini/mini-runtime.h>
25 #include <mach/mach.h>
26 #include <mach/task_info.h>
29 #define MONO_MAX_SUMMARY_LEN 900
30 static JsonWriter writer
;
31 static GString static_gstr
;
32 static char output_dump_str
[MONO_MAX_SUMMARY_LEN
];
34 static void mono_json_writer_init_static (void) {
36 static_gstr
.allocated_len
= MONO_MAX_SUMMARY_LEN
;
37 static_gstr
.str
= output_dump_str
;
38 memset (output_dump_str
, 0, sizeof (output_dump_str
));
41 writer
.text
= &static_gstr
;
45 mono_native_state_add_ctx (JsonWriter
*writer
, MonoContext
*ctx
)
48 mono_json_writer_indent (writer
);
49 mono_json_writer_object_key(writer
, "ctx");
50 mono_json_writer_object_begin(writer
);
52 mono_json_writer_indent (writer
);
53 mono_json_writer_object_key(writer
, "IP");
54 mono_json_writer_printf (writer
, "\"%p\",\n", (gpointer
) MONO_CONTEXT_GET_IP (ctx
));
56 mono_json_writer_indent (writer
);
57 mono_json_writer_object_key(writer
, "SP");
58 mono_json_writer_printf (writer
, "\"%p\",\n", (gpointer
) MONO_CONTEXT_GET_SP (ctx
));
60 mono_json_writer_indent (writer
);
61 mono_json_writer_object_key(writer
, "BP");
62 mono_json_writer_printf (writer
, "\"%p\"\n", (gpointer
) MONO_CONTEXT_GET_BP (ctx
));
64 mono_json_writer_indent_pop (writer
);
65 mono_json_writer_indent (writer
);
66 mono_json_writer_object_end (writer
);
67 mono_json_writer_printf (writer
, ",\n");
71 mono_native_state_add_frame (JsonWriter
*writer
, MonoFrameSummary
*frame
)
73 mono_json_writer_indent (writer
);
74 mono_json_writer_object_begin(writer
);
76 if (frame
->is_managed
) {
77 mono_json_writer_indent (writer
);
78 mono_json_writer_object_key(writer
, "is_managed");
79 mono_json_writer_printf (writer
, "\"%s\",\n", frame
->is_managed
? "true" : "false");
82 if (frame
->unmanaged_data
.is_trampoline
) {
83 mono_json_writer_indent (writer
);
84 mono_json_writer_object_key(writer
, "is_trampoline");
85 mono_json_writer_printf (writer
, "\"true\",");
88 if (frame
->is_managed
) {
89 mono_json_writer_indent (writer
);
90 mono_json_writer_object_key(writer
, "guid");
91 mono_json_writer_printf (writer
, "\"%s\",\n", frame
->managed_data
.guid
);
93 mono_json_writer_indent (writer
);
94 mono_json_writer_object_key(writer
, "token");
95 mono_json_writer_printf (writer
, "\"0x%05x\",\n", frame
->managed_data
.token
);
97 mono_json_writer_indent (writer
);
98 mono_json_writer_object_key(writer
, "native_offset");
99 mono_json_writer_printf (writer
, "\"0x%x\",\n", frame
->managed_data
.native_offset
);
101 mono_json_writer_indent (writer
);
102 mono_json_writer_object_key(writer
, "il_offset");
103 mono_json_writer_printf (writer
, "\"0x%05x\"\n", frame
->managed_data
.il_offset
);
106 mono_json_writer_indent (writer
);
107 mono_json_writer_object_key(writer
, "native_address");
108 if (frame
->unmanaged_data
.ip
)
109 mono_json_writer_printf (writer
, "\"%p\"", (void *) frame
->unmanaged_data
.ip
);
111 mono_json_writer_printf (writer
, "\"outside mono-sgen\"");
113 if (frame
->unmanaged_data
.has_name
) {
114 mono_json_writer_printf (writer
, ",\n");
116 mono_json_writer_indent (writer
);
117 mono_json_writer_object_key(writer
, "unmanaged_name");
118 mono_json_writer_printf (writer
, "\"%s\"\n", frame
->str_descr
);
120 mono_json_writer_printf (writer
, "\n");
124 mono_json_writer_indent_pop (writer
);
125 mono_json_writer_indent (writer
);
126 mono_json_writer_object_end (writer
);
130 mono_native_state_add_frames (JsonWriter
*writer
, int num_frames
, MonoFrameSummary
*frames
, const char *label
)
132 mono_json_writer_indent (writer
);
133 mono_json_writer_object_key(writer
, label
);
135 mono_json_writer_array_begin (writer
);
137 mono_native_state_add_frame (writer
, &frames
[0]);
138 for (int i
= 1; i
< num_frames
; ++i
) {
139 mono_json_writer_printf (writer
, ",\n");
140 mono_native_state_add_frame (writer
, &frames
[i
]);
142 mono_json_writer_printf (writer
, "\n");
144 mono_json_writer_indent_pop (writer
);
145 mono_json_writer_indent (writer
);
146 mono_json_writer_array_end (writer
);
151 mono_native_state_add_thread (JsonWriter
*writer
, MonoThreadSummary
*thread
, MonoContext
*ctx
)
153 static gboolean not_first_thread
;
155 if (not_first_thread
) {
156 mono_json_writer_printf (writer
, ",\n");
158 not_first_thread
= TRUE
;
161 mono_json_writer_indent (writer
);
162 mono_json_writer_object_begin(writer
);
164 mono_json_writer_indent (writer
);
165 mono_json_writer_object_key(writer
, "is_managed");
166 mono_json_writer_printf (writer
, "%s,\n", thread
->is_managed
? "true" : "false");
168 mono_json_writer_indent (writer
);
169 mono_json_writer_object_key(writer
, "managed_thread_ptr");
170 mono_json_writer_printf (writer
, "\"0x%x\",\n", (gpointer
) thread
->managed_thread_ptr
);
172 mono_json_writer_indent (writer
);
173 mono_json_writer_object_key(writer
, "thread_info_addr");
174 mono_json_writer_printf (writer
, "\"0x%x\",\n", (gpointer
) thread
->info_addr
);
177 mono_json_writer_indent (writer
);
178 mono_json_writer_object_key(writer
, "thread_name");
179 mono_json_writer_printf (writer
, "\"%s\",\n", thread
->name
);
182 mono_json_writer_indent (writer
);
183 mono_json_writer_object_key(writer
, "native_thread_id");
184 mono_json_writer_printf (writer
, "\"0x%x\",\n", (gpointer
) thread
->native_thread_id
);
186 mono_native_state_add_ctx (writer
, ctx
);
188 if (thread
->num_managed_frames
> 0) {
189 mono_native_state_add_frames (writer
, thread
->num_managed_frames
, thread
->managed_frames
, "managed_frames");
191 if (thread
->num_unmanaged_frames
> 0) {
192 if (thread
->num_managed_frames
> 0)
193 mono_json_writer_printf (writer
, ",\n");
194 mono_native_state_add_frames (writer
, thread
->num_unmanaged_frames
, thread
->unmanaged_frames
, "unmanaged_frames");
196 mono_json_writer_printf (writer
, "\n");
198 mono_json_writer_indent (writer
);
199 mono_json_writer_object_end (writer
);
203 mono_native_state_add_ee_info (JsonWriter
*writer
)
205 // FIXME: setup callbacks to enable
206 /*const char *aot_mode;*/
207 /*MonoAotMode mono_aot_mode = mono_jit_get_aot_mode ();*/
208 /*switch (mono_aot_mode) {*/
209 /*case MONO_AOT_MODE_NONE:*/
210 /*aot_mode = "none";*/
212 /*case MONO_AOT_MODE_NORMAL:*/
213 /*aot_mode = "normal";*/
215 /*case MONO_AOT_MODE_HYBRID:*/
216 /*aot_mode = "hybrid";*/
218 /*case MONO_AOT_MODE_FULL:*/
219 /*aot_mode = "full";*/
221 /*case MONO_AOT_MODE_LLVMONLY:*/
222 /*aot_mode = "llvmonly";*/
224 /*case MONO_AOT_MODE_INTERP:*/
225 /*aot_mode = "interp";*/
227 /*case MONO_AOT_MODE_INTERP_LLVMONLY:*/
228 /*aot_mode = "interp_llvmonly";*/
231 /*aot_mode = "error";*/
234 mono_json_writer_indent (writer
);
235 mono_json_writer_object_key(writer
, "execution_context");
236 mono_json_writer_object_begin(writer
);
238 /*mono_json_writer_indent (writer);*/
239 /*mono_json_writer_object_key(writer, "aot_mode");*/
240 /*mono_json_writer_printf (writer, "\"%s\",\n", aot_mode);*/
242 /*mono_json_writer_indent (writer);*/
243 /*mono_json_writer_object_key(writer, "mono_use_llvm");*/
244 /*mono_json_writer_printf (writer, "\"%s\",\n", mono_use_llvm ? "true" : "false");*/
246 mono_json_writer_indent (writer
);
247 mono_json_writer_object_key(writer
, "coop-enabled");
248 mono_json_writer_printf (writer
, "\"%s\"\n", mono_threads_is_cooperative_suspension_enabled () ? "true" : "false");
250 mono_json_writer_indent_pop (writer
);
251 mono_json_writer_indent (writer
);
252 mono_json_writer_object_end (writer
);
253 mono_json_writer_printf (writer
, ",\n");
256 // Taken from driver.c
257 #if defined(MONO_ARCH_ARCHITECTURE)
258 /* Redefine MONO_ARCHITECTURE to include more information */
259 #undef MONO_ARCHITECTURE
260 #define MONO_ARCHITECTURE MONO_ARCH_ARCHITECTURE
264 mono_native_state_add_version (JsonWriter
*writer
)
266 mono_json_writer_indent (writer
);
267 mono_json_writer_object_key(writer
, "configuration");
268 mono_json_writer_object_begin(writer
);
270 char *build
= mono_get_runtime_callbacks ()->get_runtime_build_info ();
271 mono_json_writer_indent (writer
);
272 mono_json_writer_object_key(writer
, "version");
273 mono_json_writer_printf (writer
, "\"%s\",\n", build
);
275 mono_json_writer_indent (writer
);
276 mono_json_writer_object_key(writer
, "tlc");
277 #ifdef HAVE_KW_THREAD
278 mono_json_writer_printf (writer
, "\"__thread\",\n");
280 mono_json_writer_printf (writer
, "\"normal\",\n");
281 #endif /* HAVE_KW_THREAD */
283 mono_json_writer_indent (writer
);
284 mono_json_writer_object_key(writer
, "sigsgev");
285 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
286 mono_json_writer_printf (writer
, "\"altstack\",\n");
288 mono_json_writer_printf (writer
, "\"normal\",\n");
291 mono_json_writer_indent (writer
);
292 mono_json_writer_object_key(writer
, "notifications");
294 mono_json_writer_printf (writer
, "\"epoll\",\n");
295 #elif defined(HAVE_KQUEUE)
296 mono_json_writer_printf (writer
, "\"kqueue\",\n");
298 mono_json_writer_printf (writer
, "\"thread+polling\",\n");
301 mono_json_writer_indent (writer
);
302 mono_json_writer_object_key(writer
, "architecture");
303 mono_json_writer_printf (writer
, "\"%s\",\n", MONO_ARCHITECTURE
);
305 mono_json_writer_indent (writer
);
306 mono_json_writer_object_key(writer
, "disabled_features");
307 mono_json_writer_printf (writer
, "\"%s\",\n", DISABLED_FEATURES
);
309 mono_json_writer_indent (writer
);
310 mono_json_writer_object_key(writer
, "smallconfig");
311 #ifdef MONO_SMALL_CONFIG
312 mono_json_writer_printf (writer
, "\"enabled\",\n");
314 mono_json_writer_printf (writer
, "\"disabled\",\n");
317 mono_json_writer_indent (writer
);
318 mono_json_writer_object_key(writer
, "bigarrays");
319 #ifdef MONO_BIG_ARRAYS
320 mono_json_writer_printf (writer
, "\"enabled\",\n");
322 mono_json_writer_printf (writer
, "\"disabled\",\n");
325 mono_json_writer_indent (writer
);
326 mono_json_writer_object_key(writer
, "softdebug");
327 #if !defined(DISABLE_SDB)
328 mono_json_writer_printf (writer
, "\"enabled\",\n");
330 mono_json_writer_printf (writer
, "\"disabled\",\n");
333 mono_json_writer_indent (writer
);
334 mono_json_writer_object_key(writer
, "interpreter");
335 #ifndef DISABLE_INTERPRETER
336 mono_json_writer_printf (writer
, "\"enabled\",\n");
338 mono_json_writer_printf (writer
, "\"disabled\",\n");
341 mono_json_writer_indent (writer
);
342 mono_json_writer_object_key(writer
, "llvm_support");
343 #ifdef MONO_ARCH_LLVM_SUPPORTED
345 mono_json_writer_printf (writer
, "\"%s\"\n", LLVM_VERSION
);
347 mono_json_writer_printf (writer
, "\"disabled\"\n");
351 mono_json_writer_indent_pop (writer
);
352 mono_json_writer_indent (writer
);
353 mono_json_writer_object_end (writer
);
354 mono_json_writer_printf (writer
, ",\n");
358 mono_native_state_add_memory (JsonWriter
*writer
)
360 mono_json_writer_indent (writer
);
361 mono_json_writer_object_key(writer
, "memory");
362 mono_json_writer_object_begin(writer
);
365 struct task_basic_info t_info
;
366 memset (&t_info
, 0, sizeof (t_info
));
367 mach_msg_type_number_t t_info_count
= TASK_BASIC_INFO_COUNT
;
368 task_name_t task
= mach_task_self ();
369 task_info(task
, TASK_BASIC_INFO
, (task_info_t
) &t_info
, &t_info_count
);
371 mono_json_writer_indent (writer
);
372 mono_json_writer_object_key(writer
, "Resident Size");
373 mono_json_writer_printf (writer
, "\"%lu\",\n", t_info
.resident_size
);
375 mono_json_writer_indent (writer
);
376 mono_json_writer_object_key(writer
, "Virtual Size");
377 mono_json_writer_printf (writer
, "\"%lu\",\n", t_info
.virtual_size
);
381 memcpy (&stats
, &mono_gc_stats
, sizeof (GCStats
));
383 mono_json_writer_indent (writer
);
384 mono_json_writer_object_key(writer
, "minor_gc_time");
385 mono_json_writer_printf (writer
, "\"%lu\",\n", stats
.minor_gc_time
);
387 mono_json_writer_indent (writer
);
388 mono_json_writer_object_key(writer
, "major_gc_time");
389 mono_json_writer_printf (writer
, "\"%lu\",\n", stats
.major_gc_time
);
391 mono_json_writer_indent (writer
);
392 mono_json_writer_object_key(writer
, "minor_gc_count");
393 mono_json_writer_printf (writer
, "\"%lu\",\n", stats
.minor_gc_count
);
395 mono_json_writer_indent (writer
);
396 mono_json_writer_object_key(writer
, "major_gc_count");
397 mono_json_writer_printf (writer
, "\"%lu\",\n", stats
.major_gc_count
);
399 mono_json_writer_indent (writer
);
400 mono_json_writer_object_key(writer
, "major_gc_time_concurrent");
401 mono_json_writer_printf (writer
, "\"%lu\"\n", stats
.major_gc_time_concurrent
);
403 mono_json_writer_indent_pop (writer
);
404 mono_json_writer_indent (writer
);
405 mono_json_writer_object_end (writer
);
406 mono_json_writer_printf (writer
, ",\n");
410 mono_native_state_add_prologue (JsonWriter
*writer
)
412 mono_json_writer_init (writer
);
413 mono_json_writer_object_begin(writer
);
415 mono_json_writer_indent (writer
);
416 mono_json_writer_object_key(writer
, "protocol_version");
417 mono_json_writer_printf (writer
, "\"%s\",\n", MONO_NATIVE_STATE_PROTOCOL_VERSION
);
419 mono_native_state_add_version (writer
);
421 #ifndef MONO_PRIVATE_CRASHES
422 mono_native_state_add_ee_info (writer
);
425 mono_native_state_add_memory (writer
);
427 const char *assertion_msg
= g_get_assertion_message ();
428 if (assertion_msg
!= NULL
) {
429 mono_json_writer_indent (writer
);
430 mono_json_writer_object_key(writer
, "assertion_message");
433 if ((pos
= strchr (assertion_msg
, '\n')) != NULL
)
436 mono_json_writer_printf (writer
, "\"%s\",\n", assertion_msg
);
439 // Start threads array
440 mono_json_writer_indent (writer
);
441 mono_json_writer_object_key(writer
, "threads");
442 mono_json_writer_array_begin (writer
);
446 mono_native_state_add_epilogue (JsonWriter
*writer
)
448 mono_json_writer_indent_pop (writer
);
449 mono_json_writer_printf (writer
, "\n");
450 mono_json_writer_indent (writer
);
451 mono_json_writer_array_end (writer
);
453 mono_json_writer_indent_pop (writer
);
454 mono_json_writer_indent (writer
);
455 mono_json_writer_object_end (writer
);
459 mono_summarize_native_state_begin (void)
461 mono_json_writer_init_static ();
462 mono_native_state_add_prologue (&writer
);
466 mono_summarize_native_state_end (void)
468 mono_native_state_add_epilogue (&writer
);
469 return writer
.text
->str
;
473 mono_summarize_native_state_add_thread (MonoThreadSummary
*thread
, MonoContext
*ctx
)
475 mono_native_state_add_thread (&writer
, thread
, ctx
);