| 199 | } |
| 200 | |
| 201 | LONG WINAPI TopLevelFilter(EXCEPTION_POINTERS* ep) { |
| 202 | bool expected = false; |
| 203 | if (!g_handling.compare_exchange_strong(expected, true)) { |
| 204 | // Already handling a prior crash on another thread: just terminate. |
| 205 | return EXCEPTION_EXECUTE_HANDLER; |
| 206 | } |
| 207 | |
| 208 | EnsureCrashDir(); |
| 209 | char stamp[64]; |
| 210 | FormatStamp(stamp, sizeof(stamp)); |
| 211 | |
| 212 | // Snapshot guest console first (cheap, no external calls). |
| 213 | std::string guest_tail; |
| 214 | { |
| 215 | // Best-effort: if the lock is currently held by the faulting thread |
| 216 | // try_lock prevents a deadlock at the cost of missing a few bytes. |
| 217 | if (g_guest.mu.try_lock()) { |
| 218 | guest_tail = SnapshotLocked(g_guest); |
| 219 | g_guest.mu.unlock(); |
| 220 | } |
| 221 | } |
| 222 | |
| 223 | if (!g_config.crash_dir.empty()) { |
| 224 | std::string dump_path = JoinPath(g_config.crash_dir, |
| 225 | std::string("crash_") + stamp + ".dmp"); |
| 226 | |
| 227 | HANDLE file = CreateFileA(dump_path.c_str(), GENERIC_WRITE, 0, nullptr, |
| 228 | CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); |
| 229 | if (file != INVALID_HANDLE_VALUE) { |
| 230 | MINIDUMP_EXCEPTION_INFORMATION info{}; |
| 231 | info.ThreadId = GetCurrentThreadId(); |
| 232 | info.ExceptionPointers = ep; |
| 233 | info.ClientPointers = FALSE; |
| 234 | |
| 235 | // MiniDumpWithDataSegs + indirectly referenced memory gives a |
| 236 | // useful stack-walkable dump without bloating to a full heap. |
| 237 | // Keep the size manageable — host VM process may have many GB of |
| 238 | // guest RAM mapped, which we deliberately omit. |
| 239 | MINIDUMP_TYPE type = static_cast<MINIDUMP_TYPE>( |
| 240 | MiniDumpWithDataSegs | |
| 241 | MiniDumpWithHandleData | |
| 242 | MiniDumpWithIndirectlyReferencedMemory | |
| 243 | MiniDumpWithThreadInfo | |
| 244 | MiniDumpWithUnloadedModules); |
| 245 | |
| 246 | MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), |
| 247 | file, type, ep ? &info : nullptr, nullptr, nullptr); |
| 248 | FlushFileBuffers(file); |
| 249 | CloseHandle(file); |
| 250 | } |
| 251 | |
| 252 | WriteMetaFile(stamp, ep, guest_tail); |
| 253 | |
| 254 | // Also write a line to stderr so it shows up in runtime.log. |
| 255 | std::fprintf(stderr, "\n[FATAL] tenbox-vm-runtime crashed: code=0x%08lx " |
| 256 | "dump=%s\n", |
| 257 | ep && ep->ExceptionRecord ? ep->ExceptionRecord->ExceptionCode : 0ul, |
| 258 | dump_path.c_str()); |
nothing calls this directly
no test coverage detected