|
1 | 1 | #include "DFHackVersion.h" |
2 | 2 | #include <csignal> |
3 | | -#include <thread> |
| 3 | +#include <iomanip> |
4 | 4 | #include <filesystem> |
5 | 5 | #include <fstream> |
| 6 | +#include <thread> |
6 | 7 |
|
7 | 8 | #include <execinfo.h> |
8 | 9 |
|
@@ -41,7 +42,7 @@ extern "C" void dfhack_crashlog_handle_signal(int sig) { |
41 | 42 | } |
42 | 43 | crash_info.signal = sig; |
43 | 44 | crash_info.backtrace_entries = backtrace(crash_info.backtrace, BT_ENTRY_MAX); |
44 | | - |
| 45 | + |
45 | 46 | // Signal saving of crashlog and wait for completion |
46 | 47 | flag_set(crashlog_ready); |
47 | 48 | flag_wait(crashlog_complete); |
@@ -70,27 +71,49 @@ std::string signal_name(int sig) { |
70 | 71 | return ""; |
71 | 72 | } |
72 | 73 |
|
| 74 | +std::filesystem::path get_crashlog_path() { |
| 75 | + std::time_t time = std::time(nullptr); |
| 76 | + std::tm* tm = std::localtime(&time); |
| 77 | + |
| 78 | + std::string timestamp = "unknown"; |
| 79 | + if (tm) { |
| 80 | + char stamp[64]; |
| 81 | + std::size_t out = strftime(&stamp[0], 63, "%Y-%m-%d-%H-%M-%S", tm); |
| 82 | + if (out != 0) |
| 83 | + timestamp = stamp; |
| 84 | + } |
| 85 | + |
| 86 | + std::filesystem::path dir = "crashlog"; |
| 87 | + std::error_code err; |
| 88 | + std::filesystem::create_directories(dir, err); |
| 89 | + |
| 90 | + std::filesystem::path log_path = dir / ("crash_" + timestamp + ".txt"); |
| 91 | + return log_path; |
| 92 | +} |
| 93 | + |
73 | 94 | void dfhack_save_crashlog() { |
74 | 95 | char** backtrace_strings = backtrace_symbols(crash_info.backtrace, crash_info.backtrace_entries); |
75 | 96 | if (!backtrace_strings) { |
76 | 97 | // Allocation failed, give up |
77 | 98 | return; |
78 | 99 | } |
79 | | - std::filesystem::path crashlog_path = "./crash.txt"; |
80 | | - std::ofstream crashlog(crashlog_path); |
| 100 | + try { |
| 101 | + std::filesystem::path crashlog_path = get_crashlog_path(); |
| 102 | + std::ofstream crashlog(crashlog_path); |
81 | 103 |
|
82 | | - crashlog << "Dwarf Fortress Linux has crashed!" << "\n"; |
83 | | - crashlog << "Dwarf Fortress Version " << DFHack::Version::df_version() << "\n"; |
84 | | - crashlog << "DFHack Version " << DFHack::Version::dfhack_version() << "\n\n"; |
| 104 | + crashlog << "Dwarf Fortress Linux has crashed!" << "\n"; |
| 105 | + crashlog << "Dwarf Fortress Version " << DFHack::Version::df_version() << "\n"; |
| 106 | + crashlog << "DFHack Version " << DFHack::Version::dfhack_version() << "\n\n"; |
85 | 107 |
|
86 | | - std::string signal = signal_name(crash_info.signal); |
87 | | - if (!signal.empty()) { |
88 | | - crashlog << "Signal " << signal << "\n"; |
89 | | - } |
| 108 | + std::string signal = signal_name(crash_info.signal); |
| 109 | + if (!signal.empty()) { |
| 110 | + crashlog << "Signal " << signal << "\n"; |
| 111 | + } |
90 | 112 |
|
91 | | - for (int i = 0; i < crash_info.backtrace_entries; i++) { |
92 | | - crashlog << i << "> " << backtrace_strings[i] << "\n"; |
93 | | - } |
| 113 | + for (int i = 0; i < crash_info.backtrace_entries; i++) { |
| 114 | + crashlog << i << "> " << backtrace_strings[i] << "\n"; |
| 115 | + } |
| 116 | + } catch (...) {} |
94 | 117 |
|
95 | 118 | free(backtrace_strings); |
96 | 119 | } |
@@ -118,7 +141,7 @@ namespace DFHack { |
118 | 141 | // https://sourceware.org/glibc/manual/latest/html_mono/libc.html#index-backtrace-1 |
119 | 142 | // backtrace is AsyncSignal-Unsafe due to dynamic loading of libgcc_s |
120 | 143 | // Using it here ensures it is loaded before use in the signal handler. |
121 | | - int _ = backtrace(crash_info.backtrace, 1); |
| 144 | + [[maybe_unused]] int _ = backtrace(crash_info.backtrace, 1); |
122 | 145 |
|
123 | 146 | crashlog_thread = std::thread(dfhack_crashlog_thread); |
124 | 147 | } |
|
0 commit comments