/* XXX THIS SHOULD BE IN SYSTEM !!!! */ void erl_crash_dump_v(char *file, int line, char* fmt, va_list args) { #ifdef ERTS_SMP ErtsThrPrgrData tpd_buf; /* in case we aren't a managed thread... */ #endif int fd; size_t envsz; time_t now; char env[21]; /* enough to hold any 64-bit integer */ size_t dumpnamebufsize = MAXPATHLEN; char dumpnamebuf[MAXPATHLEN]; char* dumpname; int secs; int env_erl_crash_dump_seconds_set = 1; int i; if (ERTS_SOMEONE_IS_CRASH_DUMPING) return; #ifdef ERTS_SMP /* Order all managed threads to block, this has to be done first to guarantee that this is the only thread to generate crash dump. */ erts_thr_progress_fatal_error_block(&tpd_buf); #ifdef ERTS_THR_HAVE_SIG_FUNCS /* * We suspend all scheduler threads so that we can dump some * data about the currently running processes and scheduler data. * We have to be very very careful when doing this as the schedulers * could be anywhere. */ for (i = 0; i < erts_no_schedulers; i++) { erts_tid_t tid = ERTS_SCHEDULER_IX(i)->tid; if (!erts_equal_tids(tid,erts_thr_self())) sys_thr_suspend(tid); } #endif /* Allow us to pass certain places without locking... */ erts_smp_atomic32_set_mb(&erts_writing_erl_crash_dump, 1); erts_smp_tsd_set(erts_is_crash_dumping_key, (void *) 1); #else /* !ERTS_SMP */ erts_writing_erl_crash_dump = 1; #endif /* ERTS_SMP */ envsz = sizeof(env); /* ERL_CRASH_DUMP_SECONDS not set * if we have a heart port, break immediately * otherwise dump crash indefinitely (until crash is complete) * same as ERL_CRASH_DUMP_SECONDS = 0 * - do not write dump * - do not set an alarm * - break immediately * * ERL_CRASH_DUMP_SECONDS = 0 * - do not write dump * - do not set an alarm * - break immediately * * ERL_CRASH_DUMP_SECONDS < 0 * - do not set alarm * - write dump until done * * ERL_CRASH_DUMP_SECONDS = S (and S positive) * - Don't dump file forever * - set alarm (set in sys) * - write dump until alarm or file is written completely */ if (erts_sys_getenv__("ERL_CRASH_DUMP_SECONDS", env, &envsz) != 0) { env_erl_crash_dump_seconds_set = 0; secs = -1; } else { env_erl_crash_dump_seconds_set = 1; secs = atoi(env); } if (secs == 0) { return; } /* erts_sys_prepare_crash_dump returns 1 if heart port is found, otherwise 0 * If we don't find heart (0) and we don't have ERL_CRASH_DUMP_SECONDS set * we should continue writing a dump * * beware: secs -1 means no alarm */ if (erts_sys_prepare_crash_dump(secs) && !env_erl_crash_dump_seconds_set ) { return; } if (erts_sys_getenv__("ERL_CRASH_DUMP",&dumpnamebuf[0],&dumpnamebufsize) != 0) dumpname = "erl_crash.dump"; else dumpname = &dumpnamebuf[0]; erts_fprintf(stderr,"\nCrash dump is being written to: %s...", dumpname); fd = open(dumpname,O_WRONLY | O_CREAT | O_TRUNC,0640); if (fd < 0) return; /* Can't create the crash dump, skip it */ time(&now); erts_fdprintf(fd, "=erl_crash_dump:0.3\n%s", ctime(&now)); if (file != NULL) erts_fdprintf(fd, "The error occurred in file %s, line %d\n", file, line); if (fmt != NULL && *fmt != '\0') { erts_fdprintf(fd, "Slogan: "); erts_vfdprintf(fd, fmt, args); } erts_fdprintf(fd, "System version: "); erts_print_system_version(fd, NULL, NULL); erts_fdprintf(fd, "%s\n", "Compiled: " ERLANG_COMPILE_DATE); erts_fdprintf(fd, "Taints: "); erts_print_nif_taints(fd, NULL); erts_fdprintf(fd, "Atoms: %d\n", atom_table_size()); #ifdef USE_THREADS /* We want to note which thread it was that called erl_exit */ if (erts_get_scheduler_data()) { erts_fdprintf(fd, "Calling Thread: scheduler:%d\n", erts_get_scheduler_data()->no); } else { if (!erts_thr_getname(erts_thr_self(), dumpnamebuf, MAXPATHLEN)) erts_fdprintf(fd, "Calling Thread: %s\n", dumpnamebuf); else erts_fdprintf(fd, "Calling Thread: %p\n", erts_thr_self()); } #else erts_fdprintf(fd, "Calling Thread: scheduler:1\n"); #endif #if defined(ERTS_HAVE_TRY_CATCH) /* * erts_print_scheduler_info is not guaranteed to be safe to call * here for all schedulers as we may have suspended a scheduler * in the middle of updating the STACK_TOP and STACK_START * variables and thus when scanning the stack we could get * segmentation faults. We protect against this very unlikely * scenario by using the ERTS_SYS_TRY_CATCH. */ for (i = 0; i < erts_no_schedulers; i++) { ERTS_SYS_TRY_CATCH( erts_print_scheduler_info(fd, NULL, ERTS_SCHEDULER_IX(i)), erts_fdprintf(fd, "** crashed **\n")); } #endif #ifdef ERTS_SMP #if defined(ERTS_THR_HAVE_SIG_FUNCS) /* We resume all schedulers so that we are in a known safe state when we write the rest of the crash dump */ for (i = 0; i < erts_no_schedulers; i++) { erts_tid_t tid = ERTS_SCHEDULER_IX(i)->tid; if (!erts_equal_tids(tid,erts_thr_self())) sys_thr_resume(tid); } #endif /* * Wait for all managed threads to block. If all threads haven't blocked * after a minute, we go anyway and hope for the best... * * We do not release system again. We expect an exit() or abort() after * dump has been written. */ erts_thr_progress_fatal_error_wait(60000); /* Either worked or not... */ #endif #ifndef ERTS_HAVE_TRY_CATCH /* This is safe to call here, as all schedulers are blocked */ for (i = 0; i < erts_no_schedulers; i++) { erts_print_scheduler_info(fd, NULL, ERTS_SCHEDULER_IX(i)); } #endif info(fd, NULL); /* General system info */ if (erts_ptab_initialized(&erts_proc)) process_info(fd, NULL); /* Info about each process and port */ db_info(fd, NULL, 0); erts_print_bif_timer_info(fd, NULL); distribution_info(fd, NULL); erts_fdprintf(fd, "=loaded_modules\n"); loaded(fd, NULL); erts_dump_fun_entries(fd, NULL); erts_deep_process_dump(fd, NULL); erts_fdprintf(fd, "=atoms\n"); dump_atoms(fd, NULL); /* Keep the instrumentation data at the end of the dump */ if (erts_instr_memory_map || erts_instr_stat) { erts_fdprintf(fd, "=instr_data\n"); if (erts_instr_stat) { erts_fdprintf(fd, "=memory_status\n"); erts_instr_dump_stat_to_fd(fd, 0); } if (erts_instr_memory_map) { erts_fdprintf(fd, "=memory_map\n"); erts_instr_dump_memory_map_to_fd(fd); } } erts_fdprintf(fd, "=end\n"); close(fd); erts_fprintf(stderr,"done\n"); }
/* XXX THIS SHOULD BE IN SYSTEM !!!! */ void erl_crash_dump_v(char *file, int line, char* fmt, va_list args) { #ifdef ERTS_SMP ErtsThrPrgrData tpd_buf; /* in case we aren't a managed thread... */ #endif int fd; size_t envsz; time_t now; char env[21]; /* enough to hold any 64-bit integer */ size_t dumpnamebufsize = MAXPATHLEN; char dumpnamebuf[MAXPATHLEN]; char* dumpname; int secs; int env_erl_crash_dump_seconds_set = 1; if (ERTS_SOMEONE_IS_CRASH_DUMPING) return; #ifdef ERTS_SMP /* * Wait for all managed threads to block. If all threads haven't blocked * after a minute, we go anyway and hope for the best... * * We do not release system again. We expect an exit() or abort() after * dump has been written. */ erts_thr_progress_fatal_error_block(60000, &tpd_buf); /* Either worked or not... */ /* Allow us to pass certain places without locking... */ erts_smp_atomic32_set_mb(&erts_writing_erl_crash_dump, 1); erts_smp_tsd_set(erts_is_crash_dumping_key, (void *) 1); #else erts_writing_erl_crash_dump = 1; #endif envsz = sizeof(env); /* ERL_CRASH_DUMP_SECONDS not set * if we have a heart port, break immediately * otherwise dump crash indefinitely (until crash is complete) * same as ERL_CRASH_DUMP_SECONDS = 0 * - do not write dump * - do not set an alarm * - break immediately * * ERL_CRASH_DUMP_SECONDS = 0 * - do not write dump * - do not set an alarm * - break immediately * * ERL_CRASH_DUMP_SECONDS < 0 * - do not set alarm * - write dump until done * * ERL_CRASH_DUMP_SECONDS = S (and S positive) * - Don't dump file forever * - set alarm (set in sys) * - write dump until alarm or file is written completely */ if (erts_sys_getenv__("ERL_CRASH_DUMP_SECONDS", env, &envsz) != 0) { env_erl_crash_dump_seconds_set = 0; secs = -1; } else { env_erl_crash_dump_seconds_set = 1; secs = atoi(env); } if (secs == 0) { return; } /* erts_sys_prepare_crash_dump returns 1 if heart port is found, otherwise 0 * If we don't find heart (0) and we don't have ERL_CRASH_DUMP_SECONDS set * we should continue writing a dump * * beware: secs -1 means no alarm */ if (erts_sys_prepare_crash_dump(secs) && !env_erl_crash_dump_seconds_set ) { return; } if (erts_sys_getenv__("ERL_CRASH_DUMP",&dumpnamebuf[0],&dumpnamebufsize) != 0) dumpname = "erl_crash.dump"; else dumpname = &dumpnamebuf[0]; fd = open(dumpname,O_WRONLY | O_CREAT | O_TRUNC,0640); if (fd < 0) return; /* Can't create the crash dump, skip it */ time(&now); erts_fdprintf(fd, "=erl_crash_dump:0.3\n%s", ctime(&now)); if (file != NULL) erts_fdprintf(fd, "The error occurred in file %s, line %d\n", file, line); if (fmt != NULL && *fmt != '\0') { erts_fdprintf(fd, "Slogan: "); erts_vfdprintf(fd, fmt, args); } erts_fdprintf(fd, "System version: "); erts_print_system_version(fd, NULL, NULL); erts_fdprintf(fd, "%s\n", "Compiled: " ERLANG_COMPILE_DATE); erts_fdprintf(fd, "Taints: "); erts_print_nif_taints(fd, NULL); erts_fdprintf(fd, "Atoms: %d\n", atom_table_size()); info(fd, NULL); /* General system info */ if (erts_ptab_initialized(&erts_proc)) process_info(fd, NULL); /* Info about each process and port */ db_info(fd, NULL, 0); erts_print_bif_timer_info(fd, NULL); distribution_info(fd, NULL); erts_fdprintf(fd, "=loaded_modules\n"); loaded(fd, NULL); erts_dump_fun_entries(fd, NULL); erts_deep_process_dump(fd, NULL); erts_fdprintf(fd, "=atoms\n"); dump_atoms(fd, NULL); /* Keep the instrumentation data at the end of the dump */ if (erts_instr_memory_map || erts_instr_stat) { erts_fdprintf(fd, "=instr_data\n"); if (erts_instr_stat) { erts_fdprintf(fd, "=memory_status\n"); erts_instr_dump_stat_to_fd(fd, 0); } if (erts_instr_memory_map) { erts_fdprintf(fd, "=memory_map\n"); erts_instr_dump_memory_map_to_fd(fd); } } erts_fdprintf(fd, "=end\n"); close(fd); erts_fprintf(stderr,"\nCrash dump was written to: %s\n", dumpname); }
void do_break(void) { int i; #ifdef __WIN32__ char *mode; /* enough for storing "window" */ /* check if we're in console mode and, if so, halt immediately if break is called */ mode = erts_read_env("ERL_CONSOLE_MODE"); if (mode && strcmp(mode, "window") != 0) erl_exit(0, ""); erts_free_read_env(mode); #endif /* __WIN32__ */ erts_printf("\n" "BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded\n" " (v)ersion (k)ill (D)b-tables (d)istribution\n"); while (1) { if ((i = sys_get_key(0)) <= 0) erl_exit(0, ""); switch (i) { case 'q': case 'a': case '*': /* * The asterisk is an read error on windows, * where sys_get_key isn't that great in console mode. * The usual reason for a read error is Ctrl-C. Treat this as * 'a' to avoid infinite loop. */ erl_exit(0, ""); case 'A': /* Halt generating crash dump */ erl_exit(1, "Crash dump requested by user"); case 'c': return; case 'p': process_info(ERTS_PRINT_STDOUT, NULL); return; case 'm': return; case 'o': port_info(ERTS_PRINT_STDOUT, NULL); return; case 'i': info(ERTS_PRINT_STDOUT, NULL); return; case 'l': loaded(ERTS_PRINT_STDOUT, NULL); return; case 'v': erts_printf("Erlang (%s) emulator version " ERLANG_VERSION "\n", EMULATOR); erts_printf("Compiled on " ERLANG_COMPILE_DATE "\n"); return; case 'd': distribution_info(ERTS_PRINT_STDOUT, NULL); return; case 'D': db_info(ERTS_PRINT_STDOUT, NULL, 1); return; case 'k': process_killer(); return; #ifdef OPPROF case 'X': dump_frequencies(); return; case 'x': { int i; for (i = 0; i <= HIGHEST_OP; i++) { if (opc[i].name != NULL) { erts_printf("%-16s %8d\n", opc[i].name, opc[i].count); } } } return; case 'z': { int i; for (i = 0; i <= HIGHEST_OP; i++) opc[i].count = 0; } return; #endif #ifdef DEBUG case 't': erts_p_slpq(); return; case 'b': bin_check(); return; case 'C': abort(); #endif case '\n': continue; default: erts_printf("Eh?\n\n"); } } }
/* XXX THIS SHOULD BE IN SYSTEM !!!! */ void erl_crash_dump_v(char *file, int line, char* fmt, va_list args) { #ifdef ERTS_SMP ErtsThrPrgrData tpd_buf; /* in case we aren't a managed thread... */ #endif int fd; time_t now; size_t dumpnamebufsize = MAXPATHLEN; char dumpnamebuf[MAXPATHLEN]; char* dumpname; if (ERTS_SOMEONE_IS_CRASH_DUMPING) return; #ifdef ERTS_SMP /* * Wait for all managed threads to block. If all threads haven't blocked * after a minute, we go anyway and hope for the best... * * We do not release system again. We expect an exit() or abort() after * dump has been written. */ erts_thr_progress_fatal_error_block(60000, &tpd_buf); /* Either worked or not... */ /* Allow us to pass certain places without locking... */ erts_smp_atomic32_set_mb(&erts_writing_erl_crash_dump, 1); erts_smp_tsd_set(erts_is_crash_dumping_key, (void *) 1); #else erts_writing_erl_crash_dump = 1; #endif erts_sys_prepare_crash_dump(); if (erts_sys_getenv_raw("ERL_CRASH_DUMP",&dumpnamebuf[0],&dumpnamebufsize) != 0) dumpname = "erl_crash.dump"; else dumpname = &dumpnamebuf[0]; fd = open(dumpname,O_WRONLY | O_CREAT | O_TRUNC,0640); if (fd < 0) return; /* Can't create the crash dump, skip it */ time(&now); erts_fdprintf(fd, "=erl_crash_dump:0.1\n%s", ctime(&now)); if (file != NULL) erts_fdprintf(fd, "The error occurred in file %s, line %d\n", file, line); if (fmt != NULL && *fmt != '\0') { erts_fdprintf(fd, "Slogan: "); erts_vfdprintf(fd, fmt, args); } erts_fdprintf(fd, "System version: "); erts_print_system_version(fd, NULL, NULL); erts_fdprintf(fd, "%s\n", "Compiled: " ERLANG_COMPILE_DATE); erts_fdprintf(fd, "Taints: "); erts_print_nif_taints(fd, NULL); erts_fdprintf(fd, "Atoms: %d\n", atom_table_size()); info(fd, NULL); /* General system info */ if (erts_proc.tab) process_info(fd, NULL); /* Info about each process and port */ db_info(fd, NULL, 0); erts_print_bif_timer_info(fd, NULL); distribution_info(fd, NULL); erts_fdprintf(fd, "=loaded_modules\n"); loaded(fd, NULL); erts_dump_fun_entries(fd, NULL); erts_deep_process_dump(fd, NULL); erts_fdprintf(fd, "=atoms\n"); dump_atoms(fd, NULL); /* Keep the instrumentation data at the end of the dump */ if (erts_instr_memory_map || erts_instr_stat) { erts_fdprintf(fd, "=instr_data\n"); if (erts_instr_stat) { erts_fdprintf(fd, "=memory_status\n"); erts_instr_dump_stat_to_fd(fd, 0); } if (erts_instr_memory_map) { erts_fdprintf(fd, "=memory_map\n"); erts_instr_dump_memory_map_to_fd(fd); } } erts_fdprintf(fd, "=end\n"); close(fd); erts_fprintf(stderr,"\nCrash dump was written to: %s\n", dumpname); }