2 * MiniDump dumping utility
4 * Copyright 2005 Eric Pouech
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 static void dump_mdmp_data(const MINIDUMP_LOCATION_DESCRIPTOR
* md
, const char* pfx
)
31 dump_data(PRD(md
->Rva
, md
->DataSize
), md
->DataSize
, pfx
);
34 static void dump_mdmp_string(DWORD rva
)
36 const MINIDUMP_STRING
* ms
= PRD(rva
, sizeof(MINIDUMP_STRING
));
40 dump_unicode_str( ms
->Buffer
, ms
->Length
/ sizeof(WCHAR
) );
45 enum FileSig
get_kind_mdmp(void)
49 pdw
= PRD(0, sizeof(DWORD
));
50 if (!pdw
) {printf("Can't get main signature, aborting\n"); return SIG_UNKNOWN
;}
52 if (*pdw
== 0x504D444D /* "MDMP" */) return SIG_MDMP
;
56 static inline void print_longlong(const char *title
, ULONG64 value
)
58 printf("%s: 0x", title
);
59 if (sizeof(value
) > sizeof(unsigned long) && value
>> 32)
60 printf("%lx%08lx\n", (unsigned long)(value
>> 32), (unsigned long)value
);
62 printf("%lx\n", (unsigned long)value
);
65 static inline void print_longlong_range(const char *title
, ULONG64 start
, ULONG64 length
)
67 ULONG64 value
= start
;
68 printf("%s: 0x", title
);
69 if (sizeof(value
) > sizeof(unsigned long) && value
>> 32)
70 printf("%lx%08lx-", (unsigned long)(value
>> 32), (unsigned long)value
);
72 printf("%lx-", (unsigned long)value
);
73 value
= start
+ length
;
74 if (sizeof(value
) > sizeof(unsigned long) && value
>> 32)
75 printf("0x%lx%08lx\n", (unsigned long)(value
>> 32), (unsigned long)value
);
77 printf("0x%lx\n", (unsigned long)value
);
82 const MINIDUMP_HEADER
* hdr
= PRD(0, sizeof(MINIDUMP_HEADER
));
83 const MINIDUMP_DIRECTORY
* dir
;
90 printf("Cannot get Minidump header\n");
94 printf("Signature: %#x (%.4s)\n", hdr
->Signature
, (const char*)&hdr
->Signature
);
95 printf("Version: %#x\n", hdr
->Version
);
96 printf("NumberOfStreams: %u\n", hdr
->NumberOfStreams
);
97 printf("StreamDirectoryRva: %u\n", (UINT
)hdr
->StreamDirectoryRva
);
98 printf("CheckSum: %u\n", hdr
->CheckSum
);
99 printf("TimeDateStamp: %s\n", get_time_str(hdr
->TimeDateStamp
));
100 print_longlong("Flags", hdr
->Flags
);
102 for (idx
= 0; idx
< hdr
->NumberOfStreams
; ++idx
)
104 dir
= PRD(hdr
->StreamDirectoryRva
+ idx
* sizeof(MINIDUMP_DIRECTORY
), sizeof(*dir
));
107 stream
= PRD(dir
->Location
.Rva
, dir
->Location
.DataSize
);
109 printf("Stream [%u]: ", idx
);
110 switch (dir
->StreamType
)
112 case ThreadListStream
:
114 const MINIDUMP_THREAD_LIST
*mtl
= stream
;
115 const MINIDUMP_THREAD
*mt
= mtl
->Threads
;
117 printf("Threads: %u\n", (UINT
)mtl
->NumberOfThreads
);
118 for (i
= 0; i
< mtl
->NumberOfThreads
; i
++, mt
++)
120 printf("Thread: #%d\n", i
);
121 printf(" ThreadId: %u\n", mt
->ThreadId
);
122 printf(" SuspendCount: %u\n", mt
->SuspendCount
);
123 printf(" PriorityClass: %u\n", mt
->PriorityClass
);
124 printf(" Priority: %u\n", mt
->Priority
);
125 print_longlong(" Teb", mt
->Teb
);
126 print_longlong_range(" Stack", mt
->Stack
.StartOfMemoryRange
, mt
->Stack
.Memory
.DataSize
);
127 dump_mdmp_data(&mt
->Stack
.Memory
, " ");
128 printf(" ThreadContext:\n");
129 dump_mdmp_data(&mt
->ThreadContext
, " ");
133 case ModuleListStream
:
136 const MINIDUMP_MODULE_LIST
*mml
= stream
;
137 const MINIDUMP_MODULE
* mm
= mml
->Modules
;
141 printf("Modules (%s): %u\n",
142 dir
->StreamType
== ModuleListStream
? "PE" : "ELF",
143 mml
->NumberOfModules
);
144 for (i
= 0; i
< mml
->NumberOfModules
; i
++, mm
++)
146 printf(" Module #%d:\n", i
);
147 print_longlong(" BaseOfImage", mm
->BaseOfImage
);
148 printf(" SizeOfImage: %u\n", mm
->SizeOfImage
);
149 printf(" CheckSum: %#x\n", mm
->CheckSum
);
150 printf(" TimeDateStamp: %s\n", get_time_str(mm
->TimeDateStamp
));
151 printf(" ModuleName: ");
152 dump_mdmp_string(mm
->ModuleNameRva
);
154 printf(" VersionInfo:\n");
155 printf(" dwSignature: %x\n", (UINT
)mm
->VersionInfo
.dwSignature
);
156 printf(" dwStrucVersion: %x\n", (UINT
)mm
->VersionInfo
.dwStrucVersion
);
157 printf(" dwFileVersion: %d,%d,%d,%d\n",
158 HIWORD(mm
->VersionInfo
.dwFileVersionMS
),
159 LOWORD(mm
->VersionInfo
.dwFileVersionMS
),
160 HIWORD(mm
->VersionInfo
.dwFileVersionLS
),
161 LOWORD(mm
->VersionInfo
.dwFileVersionLS
));
162 printf(" dwProductVersion %d,%d,%d,%d\n",
163 HIWORD(mm
->VersionInfo
.dwProductVersionMS
),
164 LOWORD(mm
->VersionInfo
.dwProductVersionMS
),
165 HIWORD(mm
->VersionInfo
.dwProductVersionLS
),
166 LOWORD(mm
->VersionInfo
.dwProductVersionLS
));
167 printf(" dwFileFlagsMask: %u\n", (UINT
)mm
->VersionInfo
.dwFileFlagsMask
);
168 printf(" dwFileFlags: %s%s%s%s%s%s\n",
169 mm
->VersionInfo
.dwFileFlags
& VS_FF_DEBUG
? "Debug " : "",
170 mm
->VersionInfo
.dwFileFlags
& VS_FF_INFOINFERRED
? "Inferred " : "",
171 mm
->VersionInfo
.dwFileFlags
& VS_FF_PATCHED
? "Patched " : "",
172 mm
->VersionInfo
.dwFileFlags
& VS_FF_PRERELEASE
? "PreRelease " : "",
173 mm
->VersionInfo
.dwFileFlags
& VS_FF_PRIVATEBUILD
? "PrivateBuild " : "",
174 mm
->VersionInfo
.dwFileFlags
& VS_FF_SPECIALBUILD
? "SpecialBuild " : "");
175 if (mm
->VersionInfo
.dwFileOS
)
177 switch (mm
->VersionInfo
.dwFileOS
& 0x000F)
179 case VOS__BASE
: p1
= "_base"; break;
180 case VOS__WINDOWS16
:p1
= "16 bit Windows"; break;
181 case VOS__PM16
: p1
= "16 bit Presentation Manager"; break;
182 case VOS__PM32
: p1
= "32 bit Presentation Manager"; break;
183 case VOS__WINDOWS32
:p1
= "32 bit Windows"; break;
184 default: p1
= "---"; break;
186 switch (mm
->VersionInfo
.dwFileOS
& 0xF0000)
188 case VOS_UNKNOWN
: p2
= "unknown"; break;
189 case VOS_DOS
: p2
= "DOS"; break;
190 case VOS_OS216
: p2
= "16 bit OS/2"; break;
191 case VOS_OS232
: p2
= "32 bit OS/2"; break;
192 case VOS_NT
: p2
= "Windows NT"; break;
193 default: p2
= "---"; break;
195 printf(" dwFileOS: %s running on %s\n", p1
, p2
);
197 else printf(" dwFileOS: 0\n");
198 switch (mm
->VersionInfo
.dwFileType
)
200 case VFT_UNKNOWN
: p1
= "Unknown"; break;
201 case VFT_APP
: p1
= "Application"; break;
202 case VFT_DLL
: p1
= "DLL"; break;
203 case VFT_DRV
: p1
= "Driver"; break;
204 case VFT_FONT
: p1
= "Font"; break;
205 case VFT_VXD
: p1
= "VxD"; break;
206 case VFT_STATIC_LIB
: p1
= "Static Library"; break;
207 default: p1
= "---"; break;
209 printf(" dwFileType: %s\n", p1
);
210 printf(" dwFileSubtype: %u\n", (UINT
)mm
->VersionInfo
.dwFileSubtype
);
211 printf(" dwFileDate: %x%08x\n",
212 (UINT
)mm
->VersionInfo
.dwFileDateMS
, (UINT
)mm
->VersionInfo
.dwFileDateLS
);
213 printf(" CvRecord: <%u>\n", (UINT
)mm
->CvRecord
.DataSize
);
214 dump_mdmp_data(&mm
->CvRecord
, " ");
215 printf(" MiscRecord: <%u>\n", (UINT
)mm
->MiscRecord
.DataSize
);
216 dump_mdmp_data(&mm
->MiscRecord
, " ");
217 printf(" Reserved0: 0x%x%08x\n",
218 (UINT
)(mm
->Reserved0
>> 32), (UINT
)mm
->Reserved0
);
219 printf(" Reserved1: 0x%x%08x\n",
220 (UINT
)(mm
->Reserved1
>> 32), (UINT
)mm
->Reserved1
);
224 case MemoryListStream
:
226 const MINIDUMP_MEMORY_LIST
*mml
= stream
;
227 const MINIDUMP_MEMORY_DESCRIPTOR
* mmd
= mml
->MemoryRanges
;
229 printf("Memory Ranges: %u\n", mml
->NumberOfMemoryRanges
);
230 for (i
= 0; i
< mml
->NumberOfMemoryRanges
; i
++, mmd
++)
232 printf(" Memory Range #%d:\n", i
);
233 print_longlong_range(" Range", mmd
->StartOfMemoryRange
, mmd
->Memory
.DataSize
);
234 dump_mdmp_data(&mmd
->Memory
, " ");
238 case SystemInfoStream
:
240 const MINIDUMP_SYSTEM_INFO
*msi
= stream
;
244 printf("System Information:\n");
245 switch (msi
->ProcessorArchitecture
)
247 case PROCESSOR_ARCHITECTURE_UNKNOWN
:
250 case PROCESSOR_ARCHITECTURE_INTEL
:
251 strcpy(tmp
, "Intel ");
252 switch (msi
->ProcessorLevel
)
254 case 3: str
= "80386"; break;
255 case 4: str
= "80486"; break;
256 case 5: str
= "Pentium"; break;
257 case 6: str
= "Pentium Pro/II or AMD Athlon"; break;
258 case 15: str
= "Pentium 4 or AMD Athlon64"; break;
259 default: str
= "???"; break;
263 if (msi
->ProcessorLevel
== 3 || msi
->ProcessorLevel
== 4)
265 if (HIBYTE(msi
->ProcessorRevision
) == 0xFF)
266 sprintf(tmp
+ strlen(tmp
), "%c%d", 'A' + ((msi
->ProcessorRevision
>>4)&0xf)-0x0a, msi
->ProcessorRevision
&0xf);
268 sprintf(tmp
+ strlen(tmp
), "%c%d", 'A' + HIBYTE(msi
->ProcessorRevision
), LOBYTE(msi
->ProcessorRevision
));
270 else sprintf(tmp
+ strlen(tmp
), "%d.%d", HIBYTE(msi
->ProcessorRevision
), LOBYTE(msi
->ProcessorRevision
));
273 case PROCESSOR_ARCHITECTURE_MIPS
:
276 case PROCESSOR_ARCHITECTURE_ALPHA
:
279 case PROCESSOR_ARCHITECTURE_PPC
:
282 case PROCESSOR_ARCHITECTURE_ARM
:
285 case PROCESSOR_ARCHITECTURE_ARM64
:
288 case PROCESSOR_ARCHITECTURE_AMD64
:
291 case PROCESSOR_ARCHITECTURE_MSIL
:
294 case PROCESSOR_ARCHITECTURE_NEUTRAL
:
301 printf(" Processor: %s (#%d CPUs)\n", str
, msi
->NumberOfProcessors
);
302 switch (msi
->MajorVersion
)
305 switch (msi
->MinorVersion
)
307 case 51: str
= "NT 3.51"; break;
308 default: str
= "3-????"; break;
312 switch (msi
->MinorVersion
)
314 case 0: str
= (msi
->PlatformId
== VER_PLATFORM_WIN32_NT
) ? "NT 4.0" : "95"; break;
315 case 10: str
= "98"; break;
316 case 90: str
= "ME"; break;
317 default: str
= "4-????"; break;
321 switch (msi
->MinorVersion
)
323 case 0: str
= "2000"; break;
324 case 1: str
= "XP"; break;
326 if (msi
->ProductType
== 1) str
= "XP";
327 else if (msi
->ProductType
== 3) str
= "Server 2003";
330 default: str
= "5-????"; break;
334 switch (msi
->MinorVersion
)
337 if (msi
->ProductType
== 1) str
= "Vista";
338 else if (msi
->ProductType
== 3) str
= "Server 2008";
342 if (msi
->ProductType
== 1) str
= "Win7";
343 else if (msi
->ProductType
== 3) str
= "Server 2008 R2";
347 if (msi
->ProductType
== 1) str
= "Win8";
348 else if (msi
->ProductType
== 3) str
= "Server 2012";
352 if (msi
->ProductType
== 1) str
= "Win8.1";
353 else if (msi
->ProductType
== 3) str
= "Server 2012 R2";
356 default: str
= "6-????"; break;
360 switch (msi
->MinorVersion
)
363 if (msi
->ProductType
== 1) str
= "Win10";
364 else str
= "10-????";
366 default: str
= "10-????"; break;
369 default: str
= "???"; break;
371 printf(" Version: Windows %s (%u)\n", str
, msi
->BuildNumber
);
372 printf(" PlatformId: %u\n", msi
->PlatformId
);
374 dump_mdmp_string(msi
->CSDVersionRva
);
376 printf(" Reserved1: %u\n", msi
->Reserved1
);
377 if (msi
->ProcessorArchitecture
== PROCESSOR_ARCHITECTURE_INTEL
)
379 printf(" x86.VendorId: %.12s\n",
380 (const char*)msi
->Cpu
.X86CpuInfo
.VendorId
);
381 printf(" x86.VersionInformation: %x\n", msi
->Cpu
.X86CpuInfo
.VersionInformation
);
382 printf(" x86.FeatureInformation: %x\n", msi
->Cpu
.X86CpuInfo
.FeatureInformation
);
383 printf(" x86.AMDExtendedCpuFeatures: %x\n", msi
->Cpu
.X86CpuInfo
.AMDExtendedCpuFeatures
);
385 if (sizeof(MINIDUMP_SYSTEM_INFO
) + 4 > dir
->Location
.DataSize
&&
386 msi
->CSDVersionRva
>= dir
->Location
.Rva
+ 4)
388 const char* code
= PRD(dir
->Location
.Rva
+ sizeof(MINIDUMP_SYSTEM_INFO
), 4);
390 if (code
&& code
[0] == 'W' && code
[1] == 'I' && code
[2] == 'N' && code
[3] == 'E' &&
391 *(wes
= (const DWORD
*)(code
+= 4)) >= 3)
393 /* assume we have wine extensions */
394 printf(" Wine details:\n");
395 printf(" build-id: %s\n", code
+ wes
[1]);
396 printf(" system: %s\n", code
+ wes
[2]);
397 printf(" release: %s\n", code
+ wes
[3]);
404 const MINIDUMP_MISC_INFO
*mmi
= stream
;
406 printf("Misc Information\n");
407 printf(" Size: %u\n", mmi
->SizeOfInfo
);
408 printf(" Flags: %#x\n", mmi
->Flags1
);
409 if (mmi
->Flags1
& MINIDUMP_MISC1_PROCESS_ID
)
410 printf(" ProcessId: %u\n", mmi
->ProcessId
);
411 if (mmi
->Flags1
& MINIDUMP_MISC1_PROCESS_TIMES
)
413 printf(" ProcessCreateTime: %s\n", get_time_str(mmi
->ProcessCreateTime
));
414 printf(" ProcessUserTime: %u\n", mmi
->ProcessUserTime
);
415 printf(" ProcessKernelTime: %u\n", mmi
->ProcessKernelTime
);
419 case ExceptionStream
:
421 const MINIDUMP_EXCEPTION_STREAM
*mes
= stream
;
423 printf("Exception:\n");
424 printf(" ThreadId: %#x\n", mes
->ThreadId
);
425 printf(" ExceptionRecord:\n");
426 printf(" ExceptionCode: %#x\n", mes
->ExceptionRecord
.ExceptionCode
);
427 printf(" ExceptionFlags: %#x\n", mes
->ExceptionRecord
.ExceptionFlags
);
428 print_longlong(" ExceptionRecord", mes
->ExceptionRecord
.ExceptionRecord
);
429 print_longlong(" ExceptionAddress", mes
->ExceptionRecord
.ExceptionAddress
);
430 printf(" ExceptionNumberParameters: %u\n", mes
->ExceptionRecord
.NumberParameters
);
431 for (i
= 0; i
< mes
->ExceptionRecord
.NumberParameters
; i
++)
434 print_longlong(" ", mes
->ExceptionRecord
.ExceptionInformation
[i
]);
436 printf(" ThreadContext:\n");
437 dump_mdmp_data(&mes
->ThreadContext
, " ");
440 case HandleDataStream
:
442 const MINIDUMP_HANDLE_DATA_STREAM
*mhd
= stream
;
444 printf("Handle data:\n");
445 printf(" SizeOfHeader: %u\n", mhd
->SizeOfHeader
);
446 printf(" SizeOfDescriptor: %u\n", mhd
->SizeOfDescriptor
);
447 printf(" NumberOfDescriptors: %u\n", mhd
->NumberOfDescriptors
);
449 ptr
= (BYTE
*)mhd
+ sizeof(*mhd
);
450 for (i
= 0; i
< mhd
->NumberOfDescriptors
; ++i
)
452 const MINIDUMP_HANDLE_DESCRIPTOR_2
*hd
= (void *)ptr
;
454 printf(" Handle [%u]:\n", i
);
455 print_longlong(" Handle", hd
->Handle
);
456 printf(" TypeName: ");
457 dump_mdmp_string(hd
->TypeNameRva
);
459 printf(" ObjectName: ");
460 dump_mdmp_string(hd
->ObjectNameRva
);
462 printf(" Attributes: %#x\n", hd
->Attributes
);
463 printf(" GrantedAccess: %#x\n", hd
->GrantedAccess
);
464 printf(" HandleCount: %u\n", hd
->HandleCount
);
465 printf(" PointerCount: %#x\n", hd
->PointerCount
);
467 if (mhd
->SizeOfDescriptor
>= sizeof(MINIDUMP_HANDLE_DESCRIPTOR_2
))
469 printf(" ObjectInfo: ");
470 dump_mdmp_string(hd
->ObjectInfoRva
);
472 printf(" Reserved0: %#x\n", hd
->Reserved0
);
475 ptr
+= mhd
->SizeOfDescriptor
;
479 case ThreadInfoListStream
:
481 const MINIDUMP_THREAD_INFO_LIST
*til
= stream
;
483 printf("Thread Info List:\n");
484 printf(" SizeOfHeader: %u\n", (UINT
)til
->SizeOfHeader
);
485 printf(" SizeOfEntry: %u\n", (UINT
)til
->SizeOfEntry
);
486 printf(" NumberOfEntries: %u\n", (UINT
)til
->NumberOfEntries
);
488 ptr
= (BYTE
*)til
+ sizeof(*til
);
489 for (i
= 0; i
< til
->NumberOfEntries
; ++i
)
491 const MINIDUMP_THREAD_INFO
*ti
= (void *)ptr
;
493 printf(" Thread [%u]:\n", i
);
494 printf(" ThreadId: %u\n", ti
->ThreadId
);
495 printf(" DumpFlags: %#x\n", ti
->DumpFlags
);
496 printf(" DumpError: %u\n", ti
->DumpError
);
497 printf(" ExitStatus: %u\n", ti
->ExitStatus
);
498 print_longlong(" CreateTime", ti
->CreateTime
);
499 print_longlong(" ExitTime", ti
->ExitTime
);
500 print_longlong(" KernelTime", ti
->KernelTime
);
501 print_longlong(" UserTime", ti
->UserTime
);
502 print_longlong(" StartAddress", ti
->StartAddress
);
503 print_longlong(" Affinity", ti
->Affinity
);
505 ptr
+= til
->SizeOfEntry
;
510 case UnloadedModuleListStream
:
512 const MINIDUMP_UNLOADED_MODULE_LIST
*uml
= stream
;
514 printf("Unloaded module list:\n");
515 printf(" SizeOfHeader: %u\n", uml
->SizeOfHeader
);
516 printf(" SizeOfEntry: %u\n", uml
->SizeOfEntry
);
517 printf(" NumberOfEntries: %u\n", uml
->NumberOfEntries
);
519 ptr
= (BYTE
*)uml
+ sizeof(*uml
);
520 for (i
= 0; i
< uml
->NumberOfEntries
; ++i
)
522 const MINIDUMP_UNLOADED_MODULE
*mod
= (void *)ptr
;
524 printf(" Module [%u]:\n", i
);
525 print_longlong(" BaseOfImage", mod
->BaseOfImage
);
526 printf(" SizeOfImage: %u\n", mod
->SizeOfImage
);
527 printf(" CheckSum: %#x\n", mod
->CheckSum
);
528 printf(" TimeDateStamp: %s\n", get_time_str(mod
->TimeDateStamp
));
529 printf(" ModuleName: ");
530 dump_mdmp_string(mod
->ModuleNameRva
);
533 ptr
+= uml
->SizeOfEntry
;
539 printf("NIY %d\n", dir
->StreamType
);
540 printf(" RVA: %u\n", (UINT
)dir
->Location
.Rva
);
541 printf(" Size: %u\n", dir
->Location
.DataSize
);
542 dump_mdmp_data(&dir
->Location
, " ");