@@ -971,3 +971,175 @@ term context_get_monitor_pid(Context *ctx, uint64_t ref_ticks, bool *is_monitori
971971 }
972972 return term_invalid_term ();
973973}
974+
975+ int context_get_catch_label (Context * ctx , Module * * mod )
976+ {
977+ term * ct = ctx -> e ;
978+ term * last_frame = ctx -> e ;
979+
980+ while (ct != ctx -> heap .heap_end ) {
981+ if (term_is_catch_label (* ct )) {
982+ int target_module ;
983+ int target_label = term_to_catch_label_and_module (* ct , & target_module );
984+ TRACE ("- found catch: label: %i, module: %i\n" , target_label , target_module );
985+ * mod = globalcontext_get_module_by_index (ctx -> global , target_module );
986+
987+ DEBUG_DUMP_STACK (ctx );
988+ ctx -> e = last_frame ;
989+ DEBUG_DUMP_STACK (ctx );
990+
991+ return target_label ;
992+
993+ } else if (term_is_cp (* ct )) {
994+ last_frame = ct + 1 ;
995+ }
996+
997+ ct ++ ;
998+ }
999+
1000+ return 0 ;
1001+ }
1002+
1003+ COLD_FUNC void context_dump (Context * ctx )
1004+ {
1005+ GlobalContext * glb = ctx -> global ;
1006+
1007+ fprintf (stderr , "CRASH \n======\n" );
1008+
1009+ fprintf (stderr , "pid: " );
1010+ term_display (stderr , term_from_local_process_id (ctx -> process_id ), ctx );
1011+ fprintf (stderr , "\n" );
1012+
1013+ fprintf (stderr , "\nStacktrace:\n" );
1014+ term_display (stderr , stacktrace_build (ctx , & ctx -> x [2 ], 3 ), ctx );
1015+ fprintf (stderr , "\n\n" );
1016+
1017+ {
1018+ Module * cp_mod ;
1019+ int label ;
1020+ int offset ;
1021+ module_cp_to_label_offset (ctx -> cp , & cp_mod , & label , & offset , NULL , ctx -> global );
1022+ fprintf (stderr , "cp: #CP<module: %i, label: %i, offset: %i>\n\n" ,
1023+ cp_mod -> module_index , label , offset );
1024+ }
1025+
1026+ fprintf (stderr , "x[0]: " );
1027+ term_display (stderr , ctx -> x [0 ], ctx );
1028+ fprintf (stderr , "\nx[1]: " );
1029+ term_display (stderr , ctx -> x [1 ], ctx );
1030+ fprintf (stderr , "\nx[2]: " );
1031+ term_display (stderr , ctx -> x [2 ], ctx );
1032+ fprintf (stderr , "\n\nStack \n-----\n\n" );
1033+
1034+ term * ct = ctx -> e ;
1035+
1036+ while (ct != ctx -> heap .heap_end ) {
1037+ if (term_is_catch_label (* ct )) {
1038+ int target_module ;
1039+ int target_label = term_to_catch_label_and_module (* ct , & target_module );
1040+ fprintf (stderr , "catch: %i:%i\n" , target_label , target_module );
1041+
1042+ } else if (term_is_cp (* ct )) {
1043+ Module * cp_mod ;
1044+ int label ;
1045+ int offset ;
1046+ module_cp_to_label_offset (* ct , & cp_mod , & label , & offset , NULL , ctx -> global );
1047+ fprintf (stderr , "#CP<module: %i, label: %i, offset: %i>\n" , cp_mod -> module_index , label , offset );
1048+
1049+ } else {
1050+ term_display (stderr , * ct , ctx );
1051+ fprintf (stderr , "\n" );
1052+ }
1053+
1054+ ct ++ ;
1055+ }
1056+
1057+ fprintf (stderr , "\n\nMailbox\n-------\n" );
1058+ mailbox_crashdump (ctx );
1059+
1060+ fprintf (stderr , "\n\nMonitors\n--------\n" );
1061+ // Lock processes table to make sure any dying process will not modify monitors
1062+ struct ListHead * processes_table = synclist_rdlock (& glb -> processes_table );
1063+ UNUSED (processes_table );
1064+ struct ListHead * item ;
1065+ LIST_FOR_EACH (item , & ctx -> monitors_head ) {
1066+ struct Monitor * monitor = GET_LIST_ENTRY (item , struct Monitor , monitor_list_head );
1067+ switch (monitor -> monitor_type ) {
1068+ case CONTEXT_MONITOR_LINK_LOCAL : {
1069+ struct LinkLocalMonitor * link_monitor = CONTAINER_OF (monitor , struct LinkLocalMonitor , monitor );
1070+ fprintf (stderr , "link " );
1071+ if (link_monitor -> unlink_id ) {
1072+ fprintf (stderr , "(inactive) " );
1073+ }
1074+ fprintf (stderr , "to " );
1075+ term_display (stderr , link_monitor -> link_local_process_id , ctx );
1076+ fprintf (stderr , "\n" );
1077+ break ;
1078+ }
1079+ case CONTEXT_MONITOR_LINK_REMOTE : {
1080+ struct LinkRemoteMonitor * link_monitor = CONTAINER_OF (monitor , struct LinkRemoteMonitor , monitor );
1081+ fprintf (stderr , "remote link " );
1082+ if (link_monitor -> unlink_id ) {
1083+ fprintf (stderr , "(inactive) " );
1084+ }
1085+ fprintf (stderr , "to " );
1086+ term_display (stderr , link_monitor -> node , ctx );
1087+ fprintf (stderr , "\n" );
1088+ break ;
1089+ }
1090+ case CONTEXT_MONITOR_MONITORING_LOCAL : {
1091+ struct MonitorLocalMonitor * monitoring_monitor = CONTAINER_OF (monitor , struct MonitorLocalMonitor , monitor );
1092+ fprintf (stderr , "monitor to " );
1093+ term_display (stderr , monitoring_monitor -> monitor_obj , ctx );
1094+ fprintf (stderr , " ref=%lu" , (long unsigned ) monitoring_monitor -> ref_ticks );
1095+ fprintf (stderr , "\n" );
1096+ break ;
1097+ }
1098+ case CONTEXT_MONITOR_MONITORED_LOCAL : {
1099+ struct MonitorLocalMonitor * monitored_monitor = CONTAINER_OF (monitor , struct MonitorLocalMonitor , monitor );
1100+ fprintf (stderr , "monitored by " );
1101+ term_display (stderr , monitored_monitor -> monitor_obj , ctx );
1102+ fprintf (stderr , " ref=%lu" , (long unsigned ) monitored_monitor -> ref_ticks );
1103+ fprintf (stderr , "\n" );
1104+ break ;
1105+ }
1106+ case CONTEXT_MONITOR_RESOURCE : {
1107+ struct ResourceContextMonitor * resource_monitor = CONTAINER_OF (monitor , struct ResourceContextMonitor , monitor );
1108+ fprintf (stderr , "monitored by resource %p ref=%lu" , resource_monitor -> resource_obj , (long unsigned ) resource_monitor -> ref_ticks );
1109+ fprintf (stderr , "\n" );
1110+ break ;
1111+ }
1112+ }
1113+ }
1114+ synclist_unlock (& glb -> processes_table );
1115+
1116+ // If crash is caused by out_of_memory, print more data about memory usage
1117+ if (ctx -> x [0 ] == ERROR_ATOM && ctx -> x [1 ] == OUT_OF_MEMORY_ATOM ) {
1118+ fprintf (stderr , "\n\nContext memory info\n-------------------\n" );
1119+ fprintf (stderr , "context_size = %zu\n" , context_size (ctx ));
1120+ fprintf (stderr , "context_avail_free_memory = %zu\n" , context_avail_free_memory (ctx ));
1121+ fprintf (stderr , "heap_size = %zu\n" , memory_heap_youngest_size (& ctx -> heap ));
1122+ fprintf (stderr , "total_heap_size = %zu\n" , memory_heap_memory_size (& ctx -> heap ));
1123+ fprintf (stderr , "stack_size = %zu\n" , context_stack_size (ctx ));
1124+ fprintf (stderr , "message_queue_len = %zu\n" , context_message_queue_len (ctx ));
1125+ fprintf (stderr , "\n\nGlobal memory info\n------------------\n" );
1126+
1127+ processes_table = synclist_rdlock (& glb -> processes_table );
1128+ size_t process_count = 0 ;
1129+ size_t ports_count = 0 ;
1130+ LIST_FOR_EACH (item , processes_table ) {
1131+ Context * p = GET_LIST_ENTRY (item , Context , processes_table_head );
1132+ process_count ++ ;
1133+ if (p -> native_handler ) {
1134+ ports_count ++ ;
1135+ }
1136+ }
1137+ synclist_unlock (& glb -> processes_table );
1138+
1139+ fprintf (stderr , "process_count = %zu\n" , process_count );
1140+ fprintf (stderr , "ports_count = %zu\n" , ports_count );
1141+ fprintf (stderr , "atoms_count = %zu\n" , atom_table_count (glb -> atom_table ));
1142+ fprintf (stderr , "refc_binary_total_size = %zu\n" , refc_binary_total_size (ctx ));
1143+ }
1144+ fprintf (stderr , "\n\n**End Of Crash Report**\n" );
1145+ }
0 commit comments