102 Patches: Detours to the Rescue
C reference for DttR maintainers and modders.
Loading...
Searching...
No Matches
crashdump.c
Go to the documentation of this file.
1#include <dttr_config.h>
2#include <dttr_crashdump.h>
3#include <dttr_errors.h>
4#include <dttr_imgui.h>
5#include <dttr_path.h>
6#include <dttr_sdl.h>
7
8#include <Zydis/Zydis.h>
9#include <dbghelp.h>
10
11#include <dttr_log.h>
12#include <sds.h>
13
14#include <stdint.h>
15
16static char crash_dump_dir[MAX_PATH];
17
18static INIT_ONCE dbghelp_lock_once = INIT_ONCE_STATIC_INIT;
19static CRITICAL_SECTION dbghelp_lock;
22
23static BOOL CALLBACK init_dbghelp_lock(PINIT_ONCE, PVOID, PVOID *) {
24 InitializeCriticalSection(&dbghelp_lock);
25 return TRUE;
26}
27
28static void enter_dbghelp_lock() {
29 InitOnceExecuteOnce(&dbghelp_lock_once, init_dbghelp_lock, NULL, NULL);
30 EnterCriticalSection(&dbghelp_lock);
31}
32
33static void leave_dbghelp_lock() {
34 LeaveCriticalSection(&dbghelp_lock);
35}
36
37static void invoke_symbol_provider(HANDLE process) {
40 }
41}
42
52
56
57#define MAX_STACK_FRAMES 64
58#define SYMBOL_NAME_CAPACITY 256
59#define SYMBOL_BUFFER_SIZE (sizeof(IMAGEHLP_SYMBOL) + SYMBOL_NAME_CAPACITY)
60#define DISASM_BYTES_BEFORE 16u
61#define DISASM_BYTES_AFTER 32u
62#define DISASM_MAX_BYTES (DISASM_BYTES_BEFORE + DISASM_BYTES_AFTER)
63#define DISASM_MAX_INSTRUCTIONS 6
64#define DISASM_MAX_LINES (DISASM_BYTES_BEFORE + DISASM_MAX_INSTRUCTIONS)
65#define DISASM_TEXT_CAPACITY 160
66
68 if (protect & (PAGE_GUARD | PAGE_NOACCESS)) {
69 return false;
70 }
71
72 protect &= 0xFF;
73 switch (protect) {
74 case PAGE_READONLY:
75 case PAGE_READWRITE:
76 case PAGE_WRITECOPY:
77 case PAGE_EXECUTE_READ:
78 case PAGE_EXECUTE_READWRITE:
79 case PAGE_EXECUTE_WRITECOPY:
80 return true;
81 default:
82 return false;
83 }
84}
85
86static sds append_disassembly_unavailable(sds message, const char *reason) {
87 return sdscatprintf(
88 message,
89 "\n<disassembly unavailable: %s>",
90 reason ? reason : "unknown"
91 );
92}
93
98
100 sds message,
101 DWORD address,
102 const char *text,
103 bool failed
104) {
105 if (failed) {
106 return sdscatprintf(message, "\n=> 0x%08lX %s", address, text);
107 }
108
109 return sdscatprintf(message, "\n0x%08lX %s", address, text);
110}
111
113 ZydisDecoder *decoder,
114 ZydisFormatter *formatter,
115 const uint8_t *bytes,
116 size_t size,
117 DWORD address,
118 ZydisDecodedInstruction *instruction,
119 char *text,
120 size_t text_size
121) {
122 ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT] = {0};
123 if (!ZYAN_SUCCESS(ZydisDecoderDecodeFull(decoder, bytes, size, instruction, operands))
124 || instruction->length == 0) {
125 return false;
126 }
127
128 return ZYAN_SUCCESS(ZydisFormatterFormatInstruction(
129 formatter,
130 instruction,
131 operands,
132 instruction->operand_count_visible,
133 text,
134 text_size,
135 address,
136 ZYAN_NULL
137 ));
138}
139
141 sds message,
142 ZydisDecoder *decoder,
143 ZydisFormatter *formatter,
144 const uint8_t *bytes,
145 size_t size,
146 DWORD failed_eip
147) {
148 size_t offset = 0;
149
150 for (int emitted = 0; offset < size && emitted < DISASM_MAX_INSTRUCTIONS; emitted++) {
151 ZydisDecodedInstruction instruction = {0};
152 char text[DISASM_TEXT_CAPACITY] = {0};
154 decoder,
155 formatter,
156 bytes + offset,
157 size - offset,
158 failed_eip + (DWORD)offset,
159 &instruction,
160 text,
161 sizeof(text)
162 )) {
163 return emitted > 0 ? message
164 : append_disassembly_unavailable(message, "decode failed");
165 }
166
167 message = append_disassembly_line(
168 message,
169 failed_eip + (DWORD)offset,
170 text,
171 offset == 0
172 );
173 offset += instruction.length;
174 }
175
176 return message;
177}
178
180 sds message,
181 const uint8_t *bytes,
182 size_t size,
183 DWORD runtime_base,
184 DWORD failed_eip
185) {
186 if (!bytes || size == 0 || failed_eip < runtime_base) {
187 return append_disassembly_unavailable(message, "decode failed");
188 }
189
190 const size_t failed_offset = (size_t)(failed_eip - runtime_base);
191 if (failed_offset >= size) {
192 return append_disassembly_unavailable(message, "decode failed");
193 }
194
195 ZydisDecoder decoder = {0};
196 if (!ZYAN_SUCCESS(
197 ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LEGACY_32, ZYDIS_STACK_WIDTH_32)
198 )) {
199 return append_disassembly_unavailable(message, "decoder unavailable");
200 }
201
202 ZydisFormatter formatter = {0};
203 if (!ZYAN_SUCCESS(ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL))) {
204 return append_disassembly_unavailable(message, "decoder unavailable");
205 }
206
208 size_t line_count = 0;
209 size_t failed_index = SIZE_MAX;
210 size_t offset = 0;
211
212 while (offset < size && line_count < DISASM_MAX_LINES) {
213 ZydisDecodedInstruction instruction = {0};
215 &decoder,
216 &formatter,
217 bytes + offset,
218 size - offset,
219 runtime_base + (DWORD)offset,
220 &instruction,
221 lines[line_count].text,
222 sizeof(lines[line_count].text)
223 )) {
224 break;
225 }
226
227 lines[line_count].address = runtime_base + (DWORD)offset;
228 if (lines[line_count].address == failed_eip) {
229 failed_index = line_count;
230 }
231
232 line_count++;
233 offset += instruction.length;
234 }
235
236 if (failed_index == SIZE_MAX) {
238 message,
239 &decoder,
240 &formatter,
241 bytes + failed_offset,
242 size - failed_offset,
243 failed_eip
244 );
245 }
246
247 size_t first = failed_index > 2 ? failed_index - 2 : 0;
248 size_t last = first + DISASM_MAX_INSTRUCTIONS;
249 if (last > line_count) {
250 last = line_count;
251 }
252 if (last - first < DISASM_MAX_INSTRUCTIONS && last == line_count) {
253 const size_t available = last - first;
254 if (available < DISASM_MAX_INSTRUCTIONS && first > 0) {
255 const size_t backfill = DISASM_MAX_INSTRUCTIONS - available;
256 first = first > backfill ? first - backfill : 0;
257 }
258 }
259
260 for (size_t i = first; i < last; i++) {
261 message = append_disassembly_line(
262 message,
263 lines[i].address,
264 lines[i].text,
265 i == failed_index
266 );
267 }
268
269 return message;
270}
271
272static sds append_registers(sds message, const CONTEXT *ctx) {
273 if (!ctx) {
274 return sdscat(message, "\n<context unavailable>");
275 }
276
277 return sdscatprintf(
278 message,
279 "\nContextFlags=0x%08lX"
280 "\nEAX=0x%08lX EBX=0x%08lX ECX=0x%08lX EDX=0x%08lX"
281 "\nESI=0x%08lX EDI=0x%08lX EBP=0x%08lX ESP=0x%08lX"
282 "\nEIP=0x%08lX EFLAGS=0x%08lX"
283 "\nSEGCS=0x%08lX SEGSS=0x%08lX SEGDS=0x%08lX SEGES=0x%08lX "
284 "SEGFS=0x%08lX SEGGS=0x%08lX"
285 "\nDR0=0x%08lX DR1=0x%08lX DR2=0x%08lX DR3=0x%08lX "
286 "DR6=0x%08lX DR7=0x%08lX"
287 "\n"
288 "\nFPU:"
289 "\nControlWord=0x%08lX StatusWord=0x%08lX TagWord=0x%08lX"
290 "\nErrorOffset=0x%08lX ErrorSelector=0x%08lX"
291 "\nDataOffset=0x%08lX DataSelector=0x%08lX Cr0NpxState=0x%08lX"
292 "\n",
293 ctx->ContextFlags,
294 ctx->Eax,
295 ctx->Ebx,
296 ctx->Ecx,
297 ctx->Edx,
298 ctx->Esi,
299 ctx->Edi,
300 ctx->Ebp,
301 ctx->Esp,
302 ctx->Eip,
303 ctx->EFlags,
304 ctx->SegCs,
305 ctx->SegSs,
306 ctx->SegDs,
307 ctx->SegEs,
308 ctx->SegFs,
309 ctx->SegGs,
310 ctx->Dr0,
311 ctx->Dr1,
312 ctx->Dr2,
313 ctx->Dr3,
314 ctx->Dr6,
315 ctx->Dr7,
316 ctx->FloatSave.ControlWord,
317 ctx->FloatSave.StatusWord,
318 ctx->FloatSave.TagWord,
319 ctx->FloatSave.ErrorOffset,
320 ctx->FloatSave.ErrorSelector,
321 ctx->FloatSave.DataOffset,
322 ctx->FloatSave.DataSelector,
323 ctx->FloatSave.Cr0NpxState
324 );
325}
326
327static sds append_disassembly_window(sds message, HANDLE process, DWORD failed_eip) {
328 if (!process) {
329 return append_disassembly_unavailable(message, "process unavailable");
330 }
331
332 MEMORY_BASIC_INFORMATION mbi = {0};
333 if (VirtualQueryEx(process, (LPCVOID)(uintptr_t)failed_eip, &mbi, sizeof(mbi))
334 != sizeof(mbi)) {
335 return append_disassembly_unavailable(message, "unreadable code");
336 }
337
338 if (mbi.State != MEM_COMMIT || !memory_protection_is_readable(mbi.Protect)) {
339 return append_disassembly_unavailable(message, "unreadable code");
340 }
341
342 const uintptr_t region_base = (uintptr_t)mbi.BaseAddress;
343 const uintptr_t region_end = region_base + mbi.RegionSize;
344 uintptr_t start = failed_eip > DISASM_BYTES_BEFORE
345 ? (uintptr_t)failed_eip - DISASM_BYTES_BEFORE
346 : (uintptr_t)failed_eip;
347 if (start < region_base) {
348 start = region_base;
349 }
350
351 uintptr_t end = (uintptr_t)failed_eip + DISASM_BYTES_AFTER;
352 if (end > region_end) {
353 end = region_end;
354 }
355
356 if (end <= start) {
357 return append_disassembly_unavailable(message, "unreadable code");
358 }
359
360 size_t size = (size_t)(end - start);
361 if (size > DISASM_MAX_BYTES) {
363 }
364
365 uint8_t bytes[DISASM_MAX_BYTES] = {0};
366 SIZE_T bytes_read = 0;
367 if (!ReadProcessMemory(process, (LPCVOID)start, bytes, size, &bytes_read)
368 || bytes_read == 0) {
369 return append_disassembly_unavailable(message, "unreadable code");
370 }
371
373 message,
374 bytes,
375 (size_t)bytes_read,
376 (DWORD)start,
377 failed_eip
378 );
379}
380
381static sds append_crash_diagnostics(sds message, HANDLE process, const CONTEXT *context) {
382 message = sdscat(message, "\n");
383 message = append_registers(message, context);
384 if (!context) {
385 return message;
386 }
387
388 return append_disassembly_window(message, process, context->Eip);
389}
390
391static MINIDUMP_TYPE minidump_type() {
392 if (dttr_config.minidump_type == DTTR_MINIDUMP_DETAILED) {
393 return MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory;
394 }
395
396 return MiniDumpNormal;
397}
398
399static sds build_crash_message(DWORD code, const char *filename) {
400 if (filename) {
401 return sdscatprintf(
402 sdsempty(),
403 "Exception 0x%08lX\n\nDump written to:\n%s",
404 code,
405 filename
406 );
407 }
408
409 return sdscatprintf(
410 sdsempty(),
411 "Exception 0x%08lX\n\nFailed to write crash dump.",
412 code
413 );
414}
415
416sds DTTR_CrashDump_AppendReportMessage(sds message, const char *stack_trace) {
417 if (!message) {
418 message = sdsempty();
419 }
420
421 if (stack_trace) {
422 message = sdscat(message, stack_trace);
423 }
424
425 return sdscat(message, DTTR_REPORT_SUFFIX);
426}
427
429 HANDLE process,
430 DWORD pid,
431 DWORD tid,
432 EXCEPTION_POINTERS *exception_info
433) {
434 SYSTEMTIME st;
435 GetLocalTime(&st);
436
437 sds filename = sdscatprintf(
438 sdsempty(),
439 "%sdttr_crash_%04d%02d%02d_%02d%02d%02d.dmp",
441 st.wYear,
442 st.wMonth,
443 st.wDay,
444 st.wHour,
445 st.wMinute,
446 st.wSecond
447 );
448
449 HANDLE file = CreateFileA(
450 filename,
451 GENERIC_WRITE,
452 0,
453 NULL,
454 CREATE_ALWAYS,
455 FILE_ATTRIBUTE_NORMAL,
456 NULL
457 );
458 if (file == INVALID_HANDLE_VALUE) {
459 DTTR_LOG_ERROR("Failed to create dump file %s", filename);
460 sdsfree(filename);
461 return NULL;
462 }
463
464 MINIDUMP_EXCEPTION_INFORMATION mei = {
465 .ThreadId = tid,
466 .ExceptionPointers = exception_info,
467 .ClientPointers = FALSE,
468 };
469
471 const BOOL
472 success = MiniDumpWriteDump(process, pid, file, minidump_type(), &mei, NULL, NULL);
474 CloseHandle(file);
475
476 if (!success) {
477 DTTR_LOG_ERROR("Failed to write crash dump to %s", filename);
478 sdsfree(filename);
479 return NULL;
480 }
481
482 DTTR_LOG_INFO("Crash dump written to %s", filename);
483 return filename;
484}
485
486void DTTR_CrashDump_LogAndTraceReport(const char *message) {
487 if (!message) {
488 return;
489 }
490
491 DTTR_LOG_ERROR("%s", message);
492 OutputDebugStringA(message);
493 OutputDebugStringA("\n");
494}
495
496sds DTTR_CrashDump_FormatStackTrace(HANDLE process, HANDLE thread, const CONTEXT *context) {
497 sds message = append_crash_diagnostics(sdsempty(), process, context);
498 message = sdscat(message, "\n\nStack trace:");
499 if (!process || !thread || !context) {
500 return sdscat(message, "\n <unavailable>");
501 }
502
503 CONTEXT ctx = *context;
505 if (!SymInitialize(process, NULL, TRUE)) {
507 return sdscat(message, "\n <symbols unavailable>");
508 }
509
510 invoke_symbol_provider(process);
511
512 STACKFRAME frame = {0};
513 frame.AddrPC.Offset = ctx.Eip;
514 frame.AddrPC.Mode = AddrModeFlat;
515 frame.AddrFrame.Offset = ctx.Ebp;
516 frame.AddrFrame.Mode = AddrModeFlat;
517 frame.AddrStack.Offset = ctx.Esp;
518 frame.AddrStack.Mode = AddrModeFlat;
519
520 int frame_count = 0;
521 for (int i = 0; i < MAX_STACK_FRAMES; i++) {
522 if (!StackWalk(
523 IMAGE_FILE_MACHINE_I386,
524 process,
525 thread,
526 &frame,
527 &ctx,
528 NULL,
529 SymFunctionTableAccess,
530 SymGetModuleBase,
531 NULL
532 )
533 || frame.AddrPC.Offset == 0) {
534 break;
535 }
536
537 const DWORD addr = (DWORD)frame.AddrPC.Offset;
538
539 IMAGEHLP_MODULE module_info = {.SizeOfStruct = sizeof(IMAGEHLP_MODULE)};
540 const char *mod_name = "???";
541 if (SymGetModuleInfo(process, addr, &module_info)) {
542 mod_name = module_info.ModuleName;
543 }
544
545 frame_count++;
546
547 _Alignas(IMAGEHLP_SYMBOL) char sym_buf[SYMBOL_BUFFER_SIZE];
548 IMAGEHLP_SYMBOL *sym = (IMAGEHLP_SYMBOL *)sym_buf;
549 sym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
550 sym->MaxNameLength = SYMBOL_NAME_CAPACITY;
551
552 DWORD displacement = 0;
553 if (!SymGetSymFromAddr(process, addr, &displacement, sym)) {
554 message = sdscatprintf(message, "\n %s!0x%08lX", mod_name, addr);
555 continue;
556 }
557
558 message = sdscatprintf(
559 message,
560 "\n %s!%s+0x%lX",
561 mod_name,
562 sym->Name,
563 displacement
564 );
565 }
566
567 SymCleanup(process);
569 if (frame_count == 0) {
570 message = sdscat(message, "\n <unavailable>");
571 }
572
573 return message;
574}
575
576static LONG WINAPI unhandled_exception_filter(EXCEPTION_POINTERS *const exception_info) {
577 const DWORD code = exception_info->ExceptionRecord->ExceptionCode;
578 const HANDLE process = GetCurrentProcess();
579 const DWORD pid = GetCurrentProcessId();
580 const DWORD tid = GetCurrentThreadId();
581 sds filename = DTTR_CrashDump_Write(process, pid, tid, exception_info);
582
583 sds summary = build_crash_message(code, filename);
584 sds stack_trace = DTTR_CrashDump_FormatStackTrace(
585 process,
586 GetCurrentThread(),
587 exception_info->ContextRecord
588 );
589
590 sds report_message = DTTR_CrashDump_AppendReportMessage(summary, stack_trace);
591 sdsfree(stack_trace);
592
593 DTTR_CrashDump_LogAndTraceReport(report_message);
594
595 if (dttr_config.show_crash_popup
596 && !DTTR_ImGui_ErrorShow("DttR: Crash", report_message)) {
598 SDL_MESSAGEBOX_ERROR,
599 "DttR: Crash",
600 report_message,
601 NULL
602 );
603 }
604
605 sdsfree(report_message);
606 sdsfree(filename);
607 ExitProcess(1);
608 return EXCEPTION_CONTINUE_SEARCH;
609}
610
611static bool set_dump_dir(const char *base_dir) {
612 sds dump_dir_path = sdsnew(base_dir);
613 if (!dump_dir_path
614 || !DTTR_Path_AppendSegment(&dump_dir_path, "dumps", DTTR_PATH_NATIVE_SEPARATOR)) {
615 sdsfree(dump_dir_path);
616 return false;
617 }
618
619 if (!CreateDirectoryA(dump_dir_path, NULL)
620 && GetLastError() != ERROR_ALREADY_EXISTS) {
621 DTTR_LOG_ERROR("Failed to create crash dump directory %s", dump_dir_path);
622 sdsfree(dump_dir_path);
623 return false;
624 }
625
627 || !DTTR_Path_CopySds(crash_dump_dir, sizeof(crash_dump_dir), dump_dir_path)) {
628 sdsfree(dump_dir_path);
629 return false;
630 }
631
632 sdsfree(dump_dir_path);
633 return true;
634}
635
636void DTTR_CrashDump_Init(const char *const dump_dir) {
637 if (!set_dump_dir(dump_dir)) {
638 DTTR_LOG_ERROR("Could not initialize crash dump directory");
639 crash_dump_dir[0] = '\0';
640 }
641
642 SetUnhandledExceptionFilter(unhandled_exception_filter);
643 DTTR_LOG_DEBUG("Crash dump handler installed");
644}
DTTR_Graphics_COM_Direct3DDevice7 void *status DTTR_Graphics_COM_Direct3DDevice7 DWORD DWORD void DWORD DWORD f DTTR_Graphics_COM_Direct3DDevice7 DWORD void DWORD st
DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 void void void void DWORD f BOOL
void void * ctx
DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 void void void void DWORD f FALSE
const DWORD size
DTTR_Graphics_COM_DirectDrawSurface7 DWORD flags void NULL
static sds append_failed_instruction_decode(sds message, ZydisDecoder *decoder, ZydisFormatter *formatter, const uint8_t *bytes, size_t size, DWORD failed_eip)
Definition crashdump.c:140
void DTTR_CrashDump_Init(const char *const dump_dir)
Definition crashdump.c:636
#define DISASM_TEXT_CAPACITY
Definition crashdump.c:65
void DTTR_CrashDump_LogAndTraceReport(const char *message)
Definition crashdump.c:486
static sds append_disassembly_from_bytes(sds message, const uint8_t *bytes, size_t size, DWORD runtime_base, DWORD failed_eip)
Definition crashdump.c:179
static sds append_disassembly_window(sds message, HANDLE process, DWORD failed_eip)
Definition crashdump.c:327
void DTTR_CrashDump_SetSymbolProvider(DTTR_CrashDump_SymbolProvider provider, void *context)
Registers a synchronous symbol provider used by crash stack formatting.
Definition crashdump.c:43
static bool format_instruction_at(ZydisDecoder *decoder, ZydisFormatter *formatter, const uint8_t *bytes, size_t size, DWORD address, ZydisDecodedInstruction *instruction, char *text, size_t text_size)
Definition crashdump.c:112
static BOOL init_dbghelp_lock(PINIT_ONCE, PVOID, PVOID *)
Definition crashdump.c:23
#define MAX_STACK_FRAMES
Definition crashdump.c:57
static sds append_disassembly_unavailable(sds message, const char *reason)
Definition crashdump.c:86
static sds append_registers(sds message, const CONTEXT *ctx)
Definition crashdump.c:272
sds DTTR_CrashDump_Write(HANDLE process, DWORD pid, DWORD tid, EXCEPTION_POINTERS *exception_info)
Definition crashdump.c:428
static bool set_dump_dir(const char *base_dir)
Definition crashdump.c:611
static sds build_crash_message(DWORD code, const char *filename)
Definition crashdump.c:399
static CRITICAL_SECTION dbghelp_lock
Definition crashdump.c:19
static void enter_dbghelp_lock()
Definition crashdump.c:28
void DTTR_CrashDump_ClearSymbolProvider()
Definition crashdump.c:53
sds DTTR_CrashDump_FormatStackTrace(HANDLE process, HANDLE thread, const CONTEXT *context)
Formats a stack trace from a thread context. Caller frees the returned sds.
Definition crashdump.c:496
static LONG unhandled_exception_filter(EXCEPTION_POINTERS *const exception_info)
Definition crashdump.c:576
#define SYMBOL_NAME_CAPACITY
Definition crashdump.c:58
static sds append_crash_diagnostics(sds message, HANDLE process, const CONTEXT *context)
Definition crashdump.c:381
sds DTTR_CrashDump_AppendReportMessage(sds message, const char *stack_trace)
Definition crashdump.c:416
static char crash_dump_dir[MAX_PATH]
Definition crashdump.c:16
#define DISASM_MAX_INSTRUCTIONS
Definition crashdump.c:63
static void invoke_symbol_provider(HANDLE process)
Definition crashdump.c:37
static bool memory_protection_is_readable(DWORD protect)
Definition crashdump.c:67
static DTTR_CrashDump_SymbolProvider crash_symbol_provider
Definition crashdump.c:20
#define DISASM_MAX_BYTES
Definition crashdump.c:62
#define DISASM_MAX_LINES
Definition crashdump.c:64
#define SYMBOL_BUFFER_SIZE
Definition crashdump.c:59
#define DISASM_BYTES_AFTER
Definition crashdump.c:61
static sds append_disassembly_line(sds message, DWORD address, const char *text, bool failed)
Definition crashdump.c:99
static INIT_ONCE dbghelp_lock_once
Definition crashdump.c:18
static MINIDUMP_TYPE minidump_type()
Definition crashdump.c:391
static void leave_dbghelp_lock()
Definition crashdump.c:33
#define DISASM_BYTES_BEFORE
Definition crashdump.c:60
static void * crash_symbol_provider_context
Definition crashdump.c:21
@ DTTR_MINIDUMP_DETAILED
Definition dttr_config.h:27
DTTR_Config dttr_config
Definition defaults.c:53
bool(* DTTR_CrashDump_SymbolProvider)(HANDLE process, void *context)
Adds process-local symbols after DbgHelp initialization and before stack walking.
#define DTTR_REPORT_SUFFIX
Definition dttr_errors.h:26
bool DTTR_ImGui_ErrorShow(const char *title, const char *message)
#define DTTR_LOG_DEBUG(...)
Definition dttr_log.h:28
#define DTTR_LOG_INFO(...)
Definition dttr_log.h:29
#define DTTR_LOG_ERROR(...)
Definition dttr_log.h:31
bool DTTR_Path_CopySds(char *out, size_t out_size, sds value)
Definition path.c:72
#define DTTR_PATH_NATIVE_SEPARATOR
Definition dttr_path.h:9
bool DTTR_Path_AppendSeparator(sds *path, char separator)
Definition path.c:272
bool DTTR_Path_AppendSegment(sds *path, const char *segment, char separator)
Definition path.c:276
bool DTTR_SDL_ShowSimpleMessageBox(SDL_MessageBoxFlags flags, const char *title, const char *message, SDL_Window *window)
Definition sdl.c:121
static ZydisDecoder decoder
char text[DISASM_TEXT_CAPACITY]
Definition crashdump.c:96