17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-01 22:49:16 +01:00
Files
maszyna/utilities/crashdump_writer.cpp

99 lines
3.4 KiB
C++

// the minidump writer shared by the simulator and eu07_starter, see utilities/crashdump_channel.h
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#include <DbgHelp.h>
#include "utilities/crashdump_channel.h"
namespace
{
struct dump_context
{
ULONG64 main_module_base;
};
BOOL CALLBACK dump_callback(PVOID Parameter, PMINIDUMP_CALLBACK_INPUT const Input, PMINIDUMP_CALLBACK_OUTPUT Output)
{
if ((Input == nullptr) || (Output == nullptr))
{
return FALSE;
}
switch (Input->CallbackType)
{
case IncludeModuleCallback:
case IncludeThreadCallback:
case ThreadCallback:
case ThreadExCallback:
return TRUE;
case ModuleCallback:
{
// the data sections of the other modules, the graphics driver above all, take tens of megabytes and tell nothing about a crash of the simulator.
// its own globals stay in the dump
auto const *context{static_cast<dump_context const *>(Parameter)};
if (Input->Module.BaseOfImage != context->main_module_base)
{
Output->ModuleWriteFlags &= ~ModuleWriteDataSeg;
}
return TRUE;
}
default:
return FALSE;
}
}
} // namespace
bool crashdump_write_minidump(void *Process, crashdump::channel_data &Data, bool const ClientPointers)
{
Data.dump_path[crashdump::path_capacity - 1] = L'\0';
auto const file{::CreateFileW(Data.dump_path, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr)};
if (file == INVALID_HANDLE_VALUE)
{
Data.error = ::GetLastError();
Data.state = crashdump::dump_failed;
return false;
}
// the full dump, on request of crashdump.full in eu07.ini, has the whole memory of the process: hundreds of megabytes or more.
// the small one the stacks of all threads with the memory their pointers lead to, the globals of the simulator and the map of the memory
auto const type{static_cast<MINIDUMP_TYPE>(
(Data.full_memory != 0 ? MiniDumpWithFullMemory : (MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory)) | MiniDumpWithHandleData | MiniDumpWithFullMemoryInfo |
MiniDumpWithThreadInfo | MiniDumpWithUnloadedModules | MiniDumpWithProcessThreadData | MiniDumpIgnoreInaccessibleMemory)};
MINIDUMP_EXCEPTION_INFORMATION exception{};
exception.ThreadId = Data.thread_id;
exception.ExceptionPointers = reinterpret_cast<PEXCEPTION_POINTERS>(static_cast<ULONG_PTR>(Data.exception_pointers));
exception.ClientPointers = ClientPointers ? TRUE : FALSE;
auto const commentlength{Data.comment_length < crashdump::comment_capacity ? Data.comment_length : static_cast<std::uint32_t>(crashdump::comment_capacity)};
MINIDUMP_USER_STREAM comment{};
comment.Type = CommentStreamA;
comment.BufferSize = commentlength;
comment.Buffer = Data.comment;
MINIDUMP_USER_STREAM_INFORMATION streams{};
streams.UserStreamCount = commentlength > 0 ? 1 : 0;
streams.UserStreamArray = &comment;
dump_context context{Data.main_module_base};
MINIDUMP_CALLBACK_INFORMATION callback{};
callback.CallbackRoutine = dump_callback;
callback.CallbackParam = &context;
auto const result{::MiniDumpWriteDump(Process, Data.process_id, file, type, Data.exception_pointers != 0 ? &exception : nullptr, &streams, Data.full_memory != 0 ? nullptr : &callback)};
Data.error = result ? 0 : ::GetLastError();
::CloseHandle(file);
Data.state = result ? crashdump::dump_written : crashdump::dump_failed;
return result != FALSE;
}
#endif