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
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
30 static void dump_mdmp_data(const MINIDUMP_LOCATION_DESCRIPTOR
* md
, const char* pfx
)
33 dump_data(PRD(md
->Rva
, md
->DataSize
), md
->DataSize
, pfx
);
36 static void dump_mdmp_string(DWORD rva
)
38 const MINIDUMP_STRING
* ms
= PRD(rva
, sizeof(MINIDUMP_STRING
));
40 dump_unicode_str( ms
->Buffer
, ms
->Length
/ sizeof(WCHAR
) );
45 static const MINIDUMP_DIRECTORY
* get_mdmp_dir(const MINIDUMP_HEADER
* hdr
, unsigned int str_idx
)
47 const MINIDUMP_DIRECTORY
* dir
;
50 for (i
= 0; i
< hdr
->NumberOfStreams
; i
++)
52 dir
= PRD(hdr
->StreamDirectoryRva
+ i
* sizeof(MINIDUMP_DIRECTORY
),
53 sizeof(MINIDUMP_DIRECTORY
));
55 if (dir
->StreamType
== str_idx
) return dir
;
60 enum FileSig
get_kind_mdmp(void)
64 pdw
= PRD(0, sizeof(DWORD
));
65 if (!pdw
) {printf("Can't get main signature, aborting\n"); return SIG_UNKNOWN
;}
67 if (*pdw
== 0x504D444D /* "MDMP" */) return SIG_MDMP
;
73 const MINIDUMP_HEADER
* hdr
= PRD(0, sizeof(MINIDUMP_HEADER
));
75 const MINIDUMP_DIRECTORY
* dir
;
80 printf("Cannot get Minidump header\n");
84 printf("Signature: %u (%.4s)\n", hdr
->Signature
, (const char*)&hdr
->Signature
);
85 printf("Version: %x\n", hdr
->Version
);
86 printf("NumberOfStreams: %u\n", hdr
->NumberOfStreams
);
87 printf("StreamDirectoryRva: %u\n", hdr
->StreamDirectoryRva
);
88 printf("CheckSum: %u\n", hdr
->CheckSum
);
89 printf("TimeDateStamp: %s\n", get_time_str(hdr
->u
.TimeDateStamp
));
90 printf("Flags: %x%08x\n", (DWORD
)(hdr
->Flags
>> 32), (DWORD
)hdr
->Flags
);
92 for (idx
= 0; idx
<= LastReservedStream
; idx
++)
94 if (!(dir
= get_mdmp_dir(hdr
, idx
))) continue;
96 stream
= PRD(dir
->Location
.Rva
, dir
->Location
.DataSize
);
97 printf("Directory [%u]: ", ndir
++);
98 switch (dir
->StreamType
)
100 case ThreadListStream
:
102 const MINIDUMP_THREAD_LIST
* mtl
= (const MINIDUMP_THREAD_LIST
*)stream
;
103 const MINIDUMP_THREAD
* mt
= mtl
->Threads
;
106 printf("Threads: %u\n", mtl
->NumberOfThreads
);
107 for (i
= 0; i
< mtl
->NumberOfThreads
; i
++, mt
++)
109 printf(" Thread: #%d\n", i
);
110 printf(" ThreadId: %u\n", mt
->ThreadId
);
111 printf(" SuspendCount: %u\n", mt
->SuspendCount
);
112 printf(" PriorityClass: %u\n", mt
->PriorityClass
);
113 printf(" Priority: %u\n", mt
->Priority
);
114 printf(" Teb: 0x%x%08x\n", (DWORD
)(mt
->Teb
>> 32), (DWORD
)mt
->Teb
);
115 printf(" Stack: 0x%x%08x-0x%x%08x\n",
116 (DWORD
)(mt
->Stack
.StartOfMemoryRange
>> 32),
117 (DWORD
)mt
->Stack
.StartOfMemoryRange
,
118 (DWORD
)((mt
->Stack
.StartOfMemoryRange
+ mt
->Stack
.Memory
.DataSize
) >> 32),
119 (DWORD
)(mt
->Stack
.StartOfMemoryRange
+ mt
->Stack
.Memory
.DataSize
));
120 dump_mdmp_data(&mt
->Stack
.Memory
, " ");
121 printf(" ThreadContext:\n");
122 dump_mdmp_data(&mt
->ThreadContext
, " ");
126 case ModuleListStream
:
129 const MINIDUMP_MODULE_LIST
* mml
= (const MINIDUMP_MODULE_LIST
*)stream
;
130 const MINIDUMP_MODULE
* mm
= mml
->Modules
;
135 printf("Modules (%s): %u\n",
136 dir
->StreamType
== ModuleListStream
? "PE" : "ELF",
137 mml
->NumberOfModules
);
138 for (i
= 0; i
< mml
->NumberOfModules
; i
++, mm
++)
140 printf(" Module #%d:\n", i
);
141 printf(" BaseOfImage: 0x%x%08x\n",
142 (DWORD
)(mm
->BaseOfImage
>> 32), (DWORD
) mm
->BaseOfImage
);
143 printf(" SizeOfImage: %u\n", mm
->SizeOfImage
);
144 printf(" CheckSum: %u\n", mm
->CheckSum
);
145 printf(" TimeDateStamp: %s\n", get_time_str(mm
->TimeDateStamp
));
146 printf(" ModuleName: ");
147 dump_mdmp_string(mm
->ModuleNameRva
);
149 printf(" VersionInfo:\n");
150 printf(" dwSignature: %x\n", mm
->VersionInfo
.dwSignature
);
151 printf(" dwStrucVersion: %x\n",
152 mm
->VersionInfo
.dwStrucVersion
);
153 printf(" dwFileVersion: %d,%d,%d,%d\n",
154 HIWORD(mm
->VersionInfo
.dwFileVersionMS
),
155 LOWORD(mm
->VersionInfo
.dwFileVersionMS
),
156 HIWORD(mm
->VersionInfo
.dwFileVersionLS
),
157 LOWORD(mm
->VersionInfo
.dwFileVersionLS
));
158 printf(" dwProductVersion %d,%d,%d,%d\n",
159 HIWORD(mm
->VersionInfo
.dwProductVersionMS
),
160 LOWORD(mm
->VersionInfo
.dwProductVersionMS
),
161 HIWORD(mm
->VersionInfo
.dwProductVersionLS
),
162 LOWORD(mm
->VersionInfo
.dwProductVersionLS
));
163 printf(" dwFileFlagsMask: %u\n",
164 mm
->VersionInfo
.dwFileFlagsMask
);
165 printf(" dwFileFlags: %s%s%s%s%s%s\n",
166 mm
->VersionInfo
.dwFileFlags
& VS_FF_DEBUG
? "Debug " : "",
167 mm
->VersionInfo
.dwFileFlags
& VS_FF_INFOINFERRED
? "Inferred " : "",
168 mm
->VersionInfo
.dwFileFlags
& VS_FF_PATCHED
? "Patched " : "",
169 mm
->VersionInfo
.dwFileFlags
& VS_FF_PRERELEASE
? "PreRelease " : "",
170 mm
->VersionInfo
.dwFileFlags
& VS_FF_PRIVATEBUILD
? "PrivateBuild " : "",
171 mm
->VersionInfo
.dwFileFlags
& VS_FF_SPECIALBUILD
? "SpecialBuild " : "");
172 if (mm
->VersionInfo
.dwFileOS
)
174 switch (mm
->VersionInfo
.dwFileOS
& 0x000F)
176 case VOS__BASE
: p1
= "_base"; break;
177 case VOS__WINDOWS16
:p1
= "16 bit Windows"; break;
178 case VOS__PM16
: p1
= "16 bit Presentation Manager"; break;
179 case VOS__PM32
: p1
= "32 bit Presentation Manager"; break;
180 case VOS__WINDOWS32
:p1
= "32 bit Windows"; break;
181 default: p1
= "---"; break;
183 switch (mm
->VersionInfo
.dwFileOS
& 0xF0000)
185 case VOS_UNKNOWN
: p2
= "unknown"; break;
186 case VOS_DOS
: p2
= "DOS"; break;
187 case VOS_OS216
: p2
= "16 bit OS/2"; break;
188 case VOS_OS232
: p2
= "32 bit OS/2"; break;
189 case VOS_NT
: p2
= "Windows NT"; break;
190 default: p2
= "---"; break;
192 printf(" dwFileOS: %s running on %s\n", p1
, p2
);
194 else printf(" dwFileOS: 0\n");
195 switch (mm
->VersionInfo
.dwFileType
)
197 case VFT_UNKNOWN
: p1
= "Unknown"; break;
198 case VFT_APP
: p1
= "Application"; break;
199 case VFT_DLL
: p1
= "DLL"; break;
200 case VFT_DRV
: p1
= "Driver"; break;
201 case VFT_FONT
: p1
= "Font"; break;
202 case VFT_VXD
: p1
= "VxD"; break;
203 case VFT_STATIC_LIB
: p1
= "Static Library"; break;
204 default: p1
= "---"; break;
206 printf(" dwFileType: %s\n", p1
);
207 printf(" dwFileSubtype: %u\n",
208 mm
->VersionInfo
.dwFileSubtype
);
209 printf(" dwFileDate: %x%08x\n",
210 mm
->VersionInfo
.dwFileDateMS
, mm
->VersionInfo
.dwFileDateLS
);
211 printf(" CvRecord: <%u>\n", mm
->CvRecord
.DataSize
);
212 dump_mdmp_data(&mm
->CvRecord
, " ");
213 printf(" MiscRecord: <%u>\n", mm
->MiscRecord
.DataSize
);
214 dump_mdmp_data(&mm
->MiscRecord
, " ");
215 printf(" Reserved0: 0x%x%08x\n",
216 (DWORD
)(mm
->Reserved0
>> 32), (DWORD
)mm
->Reserved0
);
217 printf(" Reserved1: 0x%x%08x\n",
218 (DWORD
)(mm
->Reserved1
>> 32), (DWORD
)mm
->Reserved1
);
222 case MemoryListStream
:
224 const MINIDUMP_MEMORY_LIST
* mml
= (const MINIDUMP_MEMORY_LIST
*)stream
;
225 const MINIDUMP_MEMORY_DESCRIPTOR
* mmd
= mml
->MemoryRanges
;
228 printf("Memory Ranges: %u\n", mml
->NumberOfMemoryRanges
);
229 for (i
= 0; i
< mml
->NumberOfMemoryRanges
; i
++, mmd
++)
231 printf(" Memory Range #%d:\n", i
);
232 printf(" Range: 0x%x%08x-0x%x%08x\n",
233 (DWORD
)(mmd
->StartOfMemoryRange
>> 32),
234 (DWORD
)mmd
->StartOfMemoryRange
,
235 (DWORD
)((mmd
->StartOfMemoryRange
+ mmd
->Memory
.DataSize
) >> 32),
236 (DWORD
)(mmd
->StartOfMemoryRange
+ mmd
->Memory
.DataSize
));
237 dump_mdmp_data(&mmd
->Memory
, " ");
241 case SystemInfoStream
:
243 const MINIDUMP_SYSTEM_INFO
* msi
= (const MINIDUMP_SYSTEM_INFO
*)stream
;
247 printf("System Information:\n");
248 switch (msi
->ProcessorArchitecture
)
250 case PROCESSOR_ARCHITECTURE_UNKNOWN
:
253 case PROCESSOR_ARCHITECTURE_INTEL
:
254 strcpy(tmp
, "Intel ");
255 switch (msi
->ProcessorLevel
)
257 case 3: str
= "80386"; break;
258 case 4: str
= "80486"; break;
259 case 5: str
= "Pentium"; break;
260 case 6: str
= "Pentium Pro/II or AMD Athlon"; break;
261 case 15: str
= "Pentium 4 or AMD Athlon64"; break;
262 default: str
= "???"; break;
266 if (msi
->ProcessorLevel
== 3 || msi
->ProcessorLevel
== 4)
268 if (HIBYTE(msi
->ProcessorRevision
) == 0xFF)
269 sprintf(tmp
+ strlen(tmp
), "%c%d", 'A' + ((msi
->ProcessorRevision
>>4)&0xf)-0x0a, msi
->ProcessorRevision
&0xf);
271 sprintf(tmp
+ strlen(tmp
), "%c%d", 'A' + HIBYTE(msi
->ProcessorRevision
), LOBYTE(msi
->ProcessorRevision
));
273 else sprintf(tmp
+ strlen(tmp
), "%d.%d", HIBYTE(msi
->ProcessorRevision
), LOBYTE(msi
->ProcessorRevision
));
276 case PROCESSOR_ARCHITECTURE_MIPS
:
279 case PROCESSOR_ARCHITECTURE_ALPHA
:
282 case PROCESSOR_ARCHITECTURE_PPC
:
285 case PROCESSOR_ARCHITECTURE_ARM
:
288 case PROCESSOR_ARCHITECTURE_ARM64
:
291 case PROCESSOR_ARCHITECTURE_AMD64
:
294 case PROCESSOR_ARCHITECTURE_MSIL
:
297 case PROCESSOR_ARCHITECTURE_NEUTRAL
:
304 printf(" Processor: %s (#%d CPUs)\n", str
, msi
->u
.s
.NumberOfProcessors
);
305 switch (msi
->MajorVersion
)
308 switch (msi
->MinorVersion
)
310 case 51: str
= "NT 3.51"; break;
311 default: str
= "3-????"; break;
315 switch (msi
->MinorVersion
)
317 case 0: str
= (msi
->PlatformId
== VER_PLATFORM_WIN32_NT
) ? "NT 4.0" : "95"; break;
318 case 10: str
= "98"; break;
319 case 90: str
= "ME"; break;
320 default: str
= "4-????"; break;
324 switch (msi
->MinorVersion
)
326 case 0: str
= "2000"; break;
327 case 1: str
= "XP"; break;
329 if (msi
->u
.s
.ProductType
== 1) str
= "XP";
330 else if (msi
->u
.s
.ProductType
== 3) str
= "Server 2003";
333 default: str
= "5-????"; break;
337 switch (msi
->MinorVersion
)
340 if (msi
->u
.s
.ProductType
== 1) str
= "Vista";
341 else if (msi
->u
.s
.ProductType
== 3) str
= "Server 2008";
345 if (msi
->u
.s
.ProductType
== 1) str
= "Win7";
346 else if (msi
->u
.s
.ProductType
== 3) str
= "Server 2008 R2";
350 if (msi
->u
.s
.ProductType
== 1) str
= "Win8";
351 else if (msi
->u
.s
.ProductType
== 3) str
= "Server 2012";
355 if (msi
->u
.s
.ProductType
== 1) str
= "Win8.1";
356 else if (msi
->u
.s
.ProductType
== 3) str
= "Server 2012 R2";
359 default: str
= "6-????"; break;
363 switch (msi
->MinorVersion
)
366 if (msi
->u
.s
.ProductType
== 1) str
= "Win10";
367 else str
= "10-????";
369 default: str
= "10-????"; break;
372 default: str
= "???"; break;
374 printf(" Version: Windows %s (%u)\n", str
, msi
->BuildNumber
);
375 printf(" PlatformId: %u\n", msi
->PlatformId
);
377 dump_mdmp_string(msi
->CSDVersionRva
);
379 printf(" Reserved1: %u\n", msi
->u1
.Reserved1
);
380 if (msi
->ProcessorArchitecture
== PROCESSOR_ARCHITECTURE_INTEL
)
382 printf(" x86.VendorId: %.12s\n",
383 (const char*)msi
->Cpu
.X86CpuInfo
.VendorId
);
384 printf(" x86.VersionInformation: %x\n",
385 msi
->Cpu
.X86CpuInfo
.VersionInformation
);
386 printf(" x86.FeatureInformation: %x\n",
387 msi
->Cpu
.X86CpuInfo
.FeatureInformation
);
388 printf(" x86.AMDExtendedCpuFeatures: %x\n",
389 msi
->Cpu
.X86CpuInfo
.AMDExtendedCpuFeatures
);
391 if (sizeof(MINIDUMP_SYSTEM_INFO
) + 4 > dir
->Location
.DataSize
&&
392 msi
->CSDVersionRva
>= dir
->Location
.Rva
+ 4)
394 const char* code
= PRD(dir
->Location
.Rva
+ sizeof(MINIDUMP_SYSTEM_INFO
), 4);
396 if (code
&& code
[0] == 'W' && code
[1] == 'I' && code
[2] == 'N' && code
[3] == 'E' &&
397 *(wes
= (const DWORD
*)(code
+= 4)) >= 3)
399 /* assume we have wine extensions */
400 printf(" Wine details:\n");
401 printf(" build-id: %s\n", code
+ wes
[1]);
402 printf(" system: %s\n", code
+ wes
[2]);
403 printf(" release: %s\n", code
+ wes
[3]);
410 const MINIDUMP_MISC_INFO
* mmi
= (const MINIDUMP_MISC_INFO
*)stream
;
412 printf("Misc Information\n");
413 printf(" Size: %u\n", mmi
->SizeOfInfo
);
414 printf(" Flags: %s%s\n",
415 mmi
->Flags1
& MINIDUMP_MISC1_PROCESS_ID
? "ProcessId " : "",
416 mmi
->Flags1
& MINIDUMP_MISC1_PROCESS_TIMES
? "ProcessTimes " : "");
417 if (mmi
->Flags1
& MINIDUMP_MISC1_PROCESS_ID
)
418 printf(" ProcessId: %u\n", mmi
->ProcessId
);
419 if (mmi
->Flags1
& MINIDUMP_MISC1_PROCESS_TIMES
)
421 printf(" ProcessCreateTime: %u\n", mmi
->ProcessCreateTime
);
422 printf(" ProcessUserTime: %u\n", mmi
->ProcessUserTime
);
423 printf(" ProcessKernelTime: %u\n", mmi
->ProcessKernelTime
);
427 case ExceptionStream
:
429 const MINIDUMP_EXCEPTION_STREAM
* mes
= (const MINIDUMP_EXCEPTION_STREAM
*)stream
;
432 printf("Exception:\n");
433 printf(" ThreadId: %08x\n", mes
->ThreadId
);
434 printf(" ExceptionRecord:\n");
435 printf(" ExceptionCode: %u\n", mes
->ExceptionRecord
.ExceptionCode
);
436 printf(" ExceptionFlags: %u\n", mes
->ExceptionRecord
.ExceptionFlags
);
437 printf(" ExceptionRecord: 0x%x%08x\n",
438 (DWORD
)(mes
->ExceptionRecord
.ExceptionRecord
>> 32),
439 (DWORD
)mes
->ExceptionRecord
.ExceptionRecord
);
440 printf(" ExceptionAddress: 0x%x%08x\n",
441 (DWORD
)(mes
->ExceptionRecord
.ExceptionAddress
>> 32),
442 (DWORD
)(mes
->ExceptionRecord
.ExceptionAddress
));
443 printf(" ExceptionNumberParameters: %u\n",
444 mes
->ExceptionRecord
.NumberParameters
);
445 for (i
= 0; i
< mes
->ExceptionRecord
.NumberParameters
; i
++)
447 printf(" [%d]: 0x%x%08x\n", i
,
448 (DWORD
)(mes
->ExceptionRecord
.ExceptionInformation
[i
] >> 32),
449 (DWORD
)mes
->ExceptionRecord
.ExceptionInformation
[i
]);
451 printf(" ThreadContext:\n");
452 dump_mdmp_data(&mes
->ThreadContext
, " ");
457 printf("NIY %d\n", dir
->StreamType
);
458 printf(" RVA: %u\n", dir
->Location
.Rva
);
459 printf(" Size: %u\n", dir
->Location
.DataSize
);
460 dump_mdmp_data(&dir
->Location
, " ");