A user sends you a crash report. Attached is a file with a .dmp extension. You
open it in a text editor and see binary garbage. You try Windows Event Viewer and get a
hex offset and a module name. You install WinDbg, spend an hour configuring symbol paths,
and eventually get a stack trace but half the frames just say ??? 0x00000000.
This is the standard experience. It doesn't have to be. Let's start with what a minidump actually is, then work through how to get something useful out of it.
What is a Windows minidump?
A minidump is a structured binary snapshot of a Windows process at a specific moment
typically the moment it crashed. It is written by the operating system automatically for
some crash types (via Windows Error Reporting), or by your own application using the
MiniDumpWriteDump Win32 API when an unhandled exception occurs.
Despite the "mini" prefix, a minidump contains a significant amount of information. It is
divided into streams typed sections, each containing a specific category of data.
The streams present in any given dump depend on which flags were passed to
MiniDumpWriteDump, but a typical crash dump includes:
- SystemInfo stream OS version, build number, processor architecture, processor count
- ExceptionInfo stream the exception record: code, flags, faulting address, and for access violations, the read/write type and target address
- ThreadList stream every thread active at crash time, with its ID, suspend count, and stack memory
- ModuleList stream every DLL and EXE loaded in the process, with base address, size, version string, and a pointer to the matching PDB file (path, GUID, and age)
- Memory64List stream raw memory regions captured at crash time, used during stack walking to resolve addresses
The raw data in all of these streams is binary and not human-readable. To get function names, file names, and line numbers from the addresses in the thread stacks, you need symbolication the process of mapping addresses back to source code using PDB files.
What the raw output looks like
If you open a .dmp in Windows Event Viewer or look at what Windows Error Reporting
captures, you typically get something like this:
Faulting application name: MyGame.exe
Faulting module name: MyGame-Win64-Shipping.dll
Exception code: 0xc0000005
Fault offset: 0x0000000001a2f4c1
Stack:
ntdll.dll
KERNELBASE.dll
MyGame-Win64-Shipping.dll + 0x1a2f4c1
...
You know it crashed in your game DLL. You have an offset. You have nothing else.
The traditional approach: WinDbg
WinDbg is the authoritative Windows debugging tool and it can fully parse a minidump. Getting it to produce useful output requires:
- Installing the Windows SDK or WinDbg Preview from the Microsoft Store
- Configuring a symbol path — a semicolon-delimited list of local PDB directories and/or symbol server URLs
- Opening the dump file (File > Open Crash Dump)
- Running
.sympath srv*C:\Symbols*https://msdl.microsoft.com/download/symbolsto add the Microsoft public symbol server - Running
.reload /fto force-load symbols - Running
!analyze -vto get an automated analysis
When it works when the PDB that exactly matches your binary is on the symbol path — WinDbg
produces a fully symbolicated stack. When it doesn't work, you get a wall of
??? 0x00000000 frames and you're left guessing why symbols didn't load.
The PDB matching requirement is strict. WinDbg validates the PDB GUID and age against the binary. A PDB from a slightly different build even a recompile with the same source won't match. For crashes from user machines running Shipping builds, you need to have archived the exact PDB from that specific build. If you haven't, you're working blind.
The symbol path problem
Assuming you have the right PDB, you still need to tell DbgHelp (the Windows symbolication API that WinDbg uses under the hood) where to find it. Symbol paths can be:
- A local directory:
C:\MyGame\Build\Symbols - A symbol server with local cache:
srv*C:\SymCache*https://msdl.microsoft.com/download/symbols - Multiple paths chained together with semicolons
For system DLLs (ntdll.dll, KERNELBASE.dll, etc.), the Microsoft
public symbol server works automatically and fills in those frames. For your own code, you
need your PDB on a path that DbgHelp can reach. Getting this right for a crash from a user
machine where the build may be months old requires deliberate symbol archiving as part
of your build pipeline.
What the output looks like when it works
EXCEPTION_CODE: (NTSTATUS) 0xc0000005
ACCESS_VIOLATION
FAULTING_IP:
MyGame_Win64!AEnemyCharacter::TakeDamage+0x34
00007ff6`1a2f4c35 488b4810 mov rcx,qword ptr [rax+10h]
STACK_TEXT:
MyGame_Win64!AEnemyCharacter::TakeDamage+0x34
MyGame_Win64!UCombatComponent::ApplyDamage+0x118
MyGame_Win64!AGameMode::HandleHit+0x2c
UE4Editor_Engine!UWorld::Tick+0x4a1
ntdll!RtlUserThreadStart+0x21
This is genuinely useful. You can see the faulting function, the line context, and the
call chain that led there. But you still need to interpret what happened the access
violation is at [rax+10h], which means rax was null or invalid.
You'd need to look at the register state and reason about what rax was pointing
to in order to form a hypothesis.
Getting the same result without the setup
CrashCatch Analyze uses the same DbgHelp and DIA SDK APIs under the hood the identical
symbolication stack as WinDbg but wraps it in a drag-and-drop interface. Open a
.dmp file, add your PDB directories in Tools > Symbol Paths,
and you get a fully symbolicated stack immediately.
Beyond symbolication, the Intel Engine runs automatically on every dump and classifies
the crash null pointer, heap corruption, stack overflow, race condition with a
confidence score and a list of the specific indicators that led to the classification.
No command-line flags. No .reload commands.
If you want a plain-English explanation "here's what caused this crash and where to look" Explain Mode sends a structured summary to Claude and returns a root cause, evidence list, and suggested fix.
Stop reading raw hex. Start reading crashes.
Download CrashCatch Analyze free beta, Windows x64.