minidump.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. /*
  2. * MiniDump dumping utility
  3. *
  4. * Copyright 2005 Eric Pouech
  5. *
  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.
  10. *
  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.
  15. *
  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
  19. */
  20. #include "config.h"
  21. #include <stdarg.h>
  22. #define NONAMELESSUNION
  23. #define NONAMELESSSTRUCT
  24. #include "windef.h"
  25. #include "winbase.h"
  26. #include "winver.h"
  27. #include "dbghelp.h"
  28. #include "winedump.h"
  29. static void dump_mdmp_data(const MINIDUMP_LOCATION_DESCRIPTOR* md, const char* pfx)
  30. {
  31. if (md->DataSize)
  32. dump_data(PRD(md->Rva, md->DataSize), md->DataSize, pfx);
  33. }
  34. static void dump_mdmp_string(DWORD rva)
  35. {
  36. const MINIDUMP_STRING* ms = PRD(rva, sizeof(MINIDUMP_STRING));
  37. if (ms)
  38. dump_unicode_str( ms->Buffer, ms->Length / sizeof(WCHAR) );
  39. else
  40. printf("<<?>>");
  41. }
  42. static const MINIDUMP_DIRECTORY* get_mdmp_dir(const MINIDUMP_HEADER* hdr, unsigned int str_idx)
  43. {
  44. const MINIDUMP_DIRECTORY* dir;
  45. unsigned int i;
  46. for (i = 0; i < hdr->NumberOfStreams; i++)
  47. {
  48. dir = PRD(hdr->StreamDirectoryRva + i * sizeof(MINIDUMP_DIRECTORY),
  49. sizeof(MINIDUMP_DIRECTORY));
  50. if (!dir) continue;
  51. if (dir->StreamType == str_idx) return dir;
  52. }
  53. return NULL;
  54. }
  55. enum FileSig get_kind_mdmp(void)
  56. {
  57. const DWORD* pdw;
  58. pdw = PRD(0, sizeof(DWORD));
  59. if (!pdw) {printf("Can't get main signature, aborting\n"); return SIG_UNKNOWN;}
  60. if (*pdw == 0x504D444D /* "MDMP" */) return SIG_MDMP;
  61. return SIG_UNKNOWN;
  62. }
  63. void mdmp_dump(void)
  64. {
  65. const MINIDUMP_HEADER* hdr = PRD(0, sizeof(MINIDUMP_HEADER));
  66. ULONG idx, ndir = 0;
  67. const MINIDUMP_DIRECTORY* dir;
  68. const void* stream;
  69. if (!hdr)
  70. {
  71. printf("Cannot get Minidump header\n");
  72. return;
  73. }
  74. printf("Signature: %u (%.4s)\n", hdr->Signature, (const char*)&hdr->Signature);
  75. printf("Version: %x\n", hdr->Version);
  76. printf("NumberOfStreams: %u\n", hdr->NumberOfStreams);
  77. printf("StreamDirectoryRva: %u\n", hdr->StreamDirectoryRva);
  78. printf("CheckSum: %u\n", hdr->CheckSum);
  79. printf("TimeDateStamp: %s\n", get_time_str(hdr->u.TimeDateStamp));
  80. printf("Flags: %x%08x\n", (DWORD)(hdr->Flags >> 32), (DWORD)hdr->Flags);
  81. for (idx = 0; idx <= LastReservedStream; idx++)
  82. {
  83. if (!(dir = get_mdmp_dir(hdr, idx))) continue;
  84. stream = PRD(dir->Location.Rva, dir->Location.DataSize);
  85. printf("Directory [%u]: ", ndir++);
  86. switch (dir->StreamType)
  87. {
  88. case ThreadListStream:
  89. {
  90. const MINIDUMP_THREAD_LIST* mtl = (const MINIDUMP_THREAD_LIST*)stream;
  91. const MINIDUMP_THREAD* mt = mtl->Threads;
  92. unsigned int i;
  93. printf("Threads: %u\n", mtl->NumberOfThreads);
  94. for (i = 0; i < mtl->NumberOfThreads; i++, mt++)
  95. {
  96. printf(" Thread: #%d\n", i);
  97. printf(" ThreadId: %u\n", mt->ThreadId);
  98. printf(" SuspendCount: %u\n", mt->SuspendCount);
  99. printf(" PriorityClass: %u\n", mt->PriorityClass);
  100. printf(" Priority: %u\n", mt->Priority);
  101. printf(" Teb: 0x%x%08x\n", (DWORD)(mt->Teb >> 32), (DWORD)mt->Teb);
  102. printf(" Stack: 0x%x%08x-0x%x%08x\n",
  103. (DWORD)(mt->Stack.StartOfMemoryRange >> 32),
  104. (DWORD)mt->Stack.StartOfMemoryRange,
  105. (DWORD)((mt->Stack.StartOfMemoryRange + mt->Stack.Memory.DataSize) >> 32),
  106. (DWORD)(mt->Stack.StartOfMemoryRange + mt->Stack.Memory.DataSize));
  107. dump_mdmp_data(&mt->Stack.Memory, " ");
  108. printf(" ThreadContext:\n");
  109. dump_mdmp_data(&mt->ThreadContext, " ");
  110. }
  111. }
  112. break;
  113. case ModuleListStream:
  114. case 0xFFF0:
  115. {
  116. const MINIDUMP_MODULE_LIST* mml = (const MINIDUMP_MODULE_LIST*)stream;
  117. const MINIDUMP_MODULE* mm = mml->Modules;
  118. unsigned int i;
  119. const char* p1;
  120. const char* p2;
  121. printf("Modules (%s): %u\n",
  122. dir->StreamType == ModuleListStream ? "PE" : "ELF",
  123. mml->NumberOfModules);
  124. for (i = 0; i < mml->NumberOfModules; i++, mm++)
  125. {
  126. printf(" Module #%d:\n", i);
  127. printf(" BaseOfImage: 0x%x%08x\n",
  128. (DWORD)(mm->BaseOfImage >> 32), (DWORD) mm->BaseOfImage);
  129. printf(" SizeOfImage: %u\n", mm->SizeOfImage);
  130. printf(" CheckSum: %u\n", mm->CheckSum);
  131. printf(" TimeDateStamp: %s\n", get_time_str(mm->TimeDateStamp));
  132. printf(" ModuleName: ");
  133. dump_mdmp_string(mm->ModuleNameRva);
  134. printf("\n");
  135. printf(" VersionInfo:\n");
  136. printf(" dwSignature: %x\n", mm->VersionInfo.dwSignature);
  137. printf(" dwStrucVersion: %x\n",
  138. mm->VersionInfo.dwStrucVersion);
  139. printf(" dwFileVersion: %d,%d,%d,%d\n",
  140. HIWORD(mm->VersionInfo.dwFileVersionMS),
  141. LOWORD(mm->VersionInfo.dwFileVersionMS),
  142. HIWORD(mm->VersionInfo.dwFileVersionLS),
  143. LOWORD(mm->VersionInfo.dwFileVersionLS));
  144. printf(" dwProductVersion %d,%d,%d,%d\n",
  145. HIWORD(mm->VersionInfo.dwProductVersionMS),
  146. LOWORD(mm->VersionInfo.dwProductVersionMS),
  147. HIWORD(mm->VersionInfo.dwProductVersionLS),
  148. LOWORD(mm->VersionInfo.dwProductVersionLS));
  149. printf(" dwFileFlagsMask: %u\n",
  150. mm->VersionInfo.dwFileFlagsMask);
  151. printf(" dwFileFlags: %s%s%s%s%s%s\n",
  152. mm->VersionInfo.dwFileFlags & VS_FF_DEBUG ? "Debug " : "",
  153. mm->VersionInfo.dwFileFlags & VS_FF_INFOINFERRED ? "Inferred " : "",
  154. mm->VersionInfo.dwFileFlags & VS_FF_PATCHED ? "Patched " : "",
  155. mm->VersionInfo.dwFileFlags & VS_FF_PRERELEASE ? "PreRelease " : "",
  156. mm->VersionInfo.dwFileFlags & VS_FF_PRIVATEBUILD ? "PrivateBuild " : "",
  157. mm->VersionInfo.dwFileFlags & VS_FF_SPECIALBUILD ? "SpecialBuild " : "");
  158. if (mm->VersionInfo.dwFileOS)
  159. {
  160. switch (mm->VersionInfo.dwFileOS & 0x000F)
  161. {
  162. case VOS__BASE: p1 = "_base"; break;
  163. case VOS__WINDOWS16:p1 = "16 bit Windows"; break;
  164. case VOS__PM16: p1 = "16 bit Presentation Manager"; break;
  165. case VOS__PM32: p1 = "32 bit Presentation Manager"; break;
  166. case VOS__WINDOWS32:p1 = "32 bit Windows"; break;
  167. default: p1 = "---"; break;
  168. }
  169. switch (mm->VersionInfo.dwFileOS & 0xF0000)
  170. {
  171. case VOS_UNKNOWN: p2 = "unknown"; break;
  172. case VOS_DOS: p2 = "DOS"; break;
  173. case VOS_OS216: p2 = "16 bit OS/2"; break;
  174. case VOS_OS232: p2 = "32 bit OS/2"; break;
  175. case VOS_NT: p2 = "Windows NT"; break;
  176. default: p2 = "---"; break;
  177. }
  178. printf(" dwFileOS: %s running on %s\n", p1, p2);
  179. }
  180. else printf(" dwFileOS: 0\n");
  181. switch (mm->VersionInfo.dwFileType)
  182. {
  183. case VFT_UNKNOWN: p1 = "Unknown"; break;
  184. case VFT_APP: p1 = "Application"; break;
  185. case VFT_DLL: p1 = "DLL"; break;
  186. case VFT_DRV: p1 = "Driver"; break;
  187. case VFT_FONT: p1 = "Font"; break;
  188. case VFT_VXD: p1 = "VxD"; break;
  189. case VFT_STATIC_LIB: p1 = "Static Library"; break;
  190. default: p1 = "---"; break;
  191. }
  192. printf(" dwFileType: %s\n", p1);
  193. printf(" dwFileSubtype: %u\n",
  194. mm->VersionInfo.dwFileSubtype);
  195. printf(" dwFileDate: %x%08x\n",
  196. mm->VersionInfo.dwFileDateMS, mm->VersionInfo.dwFileDateLS);
  197. printf(" CvRecord: <%u>\n", mm->CvRecord.DataSize);
  198. dump_mdmp_data(&mm->CvRecord, " ");
  199. printf(" MiscRecord: <%u>\n", mm->MiscRecord.DataSize);
  200. dump_mdmp_data(&mm->MiscRecord, " ");
  201. printf(" Reserved0: 0x%x%08x\n",
  202. (DWORD)(mm->Reserved0 >> 32), (DWORD)mm->Reserved0);
  203. printf(" Reserved1: 0x%x%08x\n",
  204. (DWORD)(mm->Reserved1 >> 32), (DWORD)mm->Reserved1);
  205. }
  206. }
  207. break;
  208. case MemoryListStream:
  209. {
  210. const MINIDUMP_MEMORY_LIST* mml = (const MINIDUMP_MEMORY_LIST*)stream;
  211. const MINIDUMP_MEMORY_DESCRIPTOR* mmd = mml->MemoryRanges;
  212. unsigned int i;
  213. printf("Memory Ranges: %u\n", mml->NumberOfMemoryRanges);
  214. for (i = 0; i < mml->NumberOfMemoryRanges; i++, mmd++)
  215. {
  216. printf(" Memory Range #%d:\n", i);
  217. printf(" Range: 0x%x%08x-0x%x%08x\n",
  218. (DWORD)(mmd->StartOfMemoryRange >> 32),
  219. (DWORD)mmd->StartOfMemoryRange,
  220. (DWORD)((mmd->StartOfMemoryRange + mmd->Memory.DataSize) >> 32),
  221. (DWORD)(mmd->StartOfMemoryRange + mmd->Memory.DataSize));
  222. dump_mdmp_data(&mmd->Memory, " ");
  223. }
  224. }
  225. break;
  226. case SystemInfoStream:
  227. {
  228. const MINIDUMP_SYSTEM_INFO* msi = (const MINIDUMP_SYSTEM_INFO*)stream;
  229. const char* str;
  230. char tmp[128];
  231. printf("System Information:\n");
  232. switch (msi->ProcessorArchitecture)
  233. {
  234. case PROCESSOR_ARCHITECTURE_UNKNOWN:
  235. str = "Unknown";
  236. break;
  237. case PROCESSOR_ARCHITECTURE_INTEL:
  238. strcpy(tmp, "Intel ");
  239. switch (msi->ProcessorLevel)
  240. {
  241. case 3: str = "80386"; break;
  242. case 4: str = "80486"; break;
  243. case 5: str = "Pentium"; break;
  244. case 6: str = "Pentium Pro/II or AMD Athlon"; break;
  245. case 15: str = "Pentium 4 or AMD Athlon64"; break;
  246. default: str = "???"; break;
  247. }
  248. strcat(tmp, str);
  249. strcat(tmp, " (");
  250. if (msi->ProcessorLevel == 3 || msi->ProcessorLevel == 4)
  251. {
  252. if (HIBYTE(msi->ProcessorRevision) == 0xFF)
  253. sprintf(tmp + strlen(tmp), "%c%d", 'A' + ((msi->ProcessorRevision>>4)&0xf)-0x0a, msi->ProcessorRevision&0xf);
  254. else
  255. sprintf(tmp + strlen(tmp), "%c%d", 'A' + HIBYTE(msi->ProcessorRevision), LOBYTE(msi->ProcessorRevision));
  256. }
  257. else sprintf(tmp + strlen(tmp), "%d.%d", HIBYTE(msi->ProcessorRevision), LOBYTE(msi->ProcessorRevision));
  258. str = tmp;
  259. break;
  260. case PROCESSOR_ARCHITECTURE_MIPS:
  261. str = "Mips";
  262. break;
  263. case PROCESSOR_ARCHITECTURE_ALPHA:
  264. str = "Alpha";
  265. break;
  266. case PROCESSOR_ARCHITECTURE_PPC:
  267. str = "PowerPC";
  268. break;
  269. case PROCESSOR_ARCHITECTURE_ARM:
  270. str = "ARM";
  271. break;
  272. case PROCESSOR_ARCHITECTURE_ARM64:
  273. str = "ARM64";
  274. break;
  275. case PROCESSOR_ARCHITECTURE_AMD64:
  276. str = "X86_64";
  277. break;
  278. case PROCESSOR_ARCHITECTURE_MSIL:
  279. str = "MSIL";
  280. break;
  281. case PROCESSOR_ARCHITECTURE_NEUTRAL:
  282. str = "Neutral";
  283. break;
  284. default:
  285. str = "???";
  286. break;
  287. }
  288. printf(" Processor: %s (#%d CPUs)\n", str, msi->u.s.NumberOfProcessors);
  289. switch (msi->MajorVersion)
  290. {
  291. case 3:
  292. switch (msi->MinorVersion)
  293. {
  294. case 51: str = "NT 3.51"; break;
  295. default: str = "3-????"; break;
  296. }
  297. break;
  298. case 4:
  299. switch (msi->MinorVersion)
  300. {
  301. case 0: str = (msi->PlatformId == VER_PLATFORM_WIN32_NT) ? "NT 4.0" : "95"; break;
  302. case 10: str = "98"; break;
  303. case 90: str = "ME"; break;
  304. default: str = "4-????"; break;
  305. }
  306. break;
  307. case 5:
  308. switch (msi->MinorVersion)
  309. {
  310. case 0: str = "2000"; break;
  311. case 1: str = "XP"; break;
  312. case 2:
  313. if (msi->u.s.ProductType == 1) str = "XP";
  314. else if (msi->u.s.ProductType == 3) str = "Server 2003";
  315. else str = "5-????";
  316. break;
  317. default: str = "5-????"; break;
  318. }
  319. break;
  320. case 6:
  321. switch (msi->MinorVersion)
  322. {
  323. case 0:
  324. if (msi->u.s.ProductType == 1) str = "Vista";
  325. else if (msi->u.s.ProductType == 3) str = "Server 2008";
  326. else str = "6-????";
  327. break;
  328. case 1:
  329. if (msi->u.s.ProductType == 1) str = "Win7";
  330. else if (msi->u.s.ProductType == 3) str = "Server 2008 R2";
  331. else str = "6-????";
  332. break;
  333. case 2:
  334. if (msi->u.s.ProductType == 1) str = "Win8";
  335. else if (msi->u.s.ProductType == 3) str = "Server 2012";
  336. else str = "6-????";
  337. break;
  338. case 3:
  339. if (msi->u.s.ProductType == 1) str = "Win8.1";
  340. else if (msi->u.s.ProductType == 3) str = "Server 2012 R2";
  341. else str = "6-????";
  342. break;
  343. default: str = "6-????"; break;
  344. }
  345. break;
  346. case 10:
  347. switch (msi->MinorVersion)
  348. {
  349. case 0:
  350. if (msi->u.s.ProductType == 1) str = "Win10";
  351. else str = "10-????";
  352. break;
  353. default: str = "10-????"; break;
  354. }
  355. break;
  356. default: str = "???"; break;
  357. }
  358. printf(" Version: Windows %s (%u)\n", str, msi->BuildNumber);
  359. printf(" PlatformId: %u\n", msi->PlatformId);
  360. printf(" CSD: ");
  361. dump_mdmp_string(msi->CSDVersionRva);
  362. printf("\n");
  363. printf(" Reserved1: %u\n", msi->u1.Reserved1);
  364. if (msi->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
  365. {
  366. printf(" x86.VendorId: %.12s\n",
  367. (const char*)msi->Cpu.X86CpuInfo.VendorId);
  368. printf(" x86.VersionInformation: %x\n",
  369. msi->Cpu.X86CpuInfo.VersionInformation);
  370. printf(" x86.FeatureInformation: %x\n",
  371. msi->Cpu.X86CpuInfo.FeatureInformation);
  372. printf(" x86.AMDExtendedCpuFeatures: %x\n",
  373. msi->Cpu.X86CpuInfo.AMDExtendedCpuFeatures);
  374. }
  375. if (sizeof(MINIDUMP_SYSTEM_INFO) + 4 > dir->Location.DataSize &&
  376. msi->CSDVersionRva >= dir->Location.Rva + 4)
  377. {
  378. const char* code = PRD(dir->Location.Rva + sizeof(MINIDUMP_SYSTEM_INFO), 4);
  379. const DWORD* wes;
  380. if (code && code[0] == 'W' && code[1] == 'I' && code[2] == 'N' && code[3] == 'E' &&
  381. *(wes = (const DWORD*)(code += 4)) >= 3)
  382. {
  383. /* assume we have wine extensions */
  384. printf(" Wine details:\n");
  385. printf(" build-id: %s\n", code + wes[1]);
  386. printf(" system: %s\n", code + wes[2]);
  387. printf(" release: %s\n", code + wes[3]);
  388. }
  389. }
  390. }
  391. break;
  392. case MiscInfoStream:
  393. {
  394. const MINIDUMP_MISC_INFO* mmi = (const MINIDUMP_MISC_INFO*)stream;
  395. printf("Misc Information\n");
  396. printf(" Size: %u\n", mmi->SizeOfInfo);
  397. printf(" Flags: %s%s\n",
  398. mmi->Flags1 & MINIDUMP_MISC1_PROCESS_ID ? "ProcessId " : "",
  399. mmi->Flags1 & MINIDUMP_MISC1_PROCESS_TIMES ? "ProcessTimes " : "");
  400. if (mmi->Flags1 & MINIDUMP_MISC1_PROCESS_ID)
  401. printf(" ProcessId: %u\n", mmi->ProcessId);
  402. if (mmi->Flags1 & MINIDUMP_MISC1_PROCESS_TIMES)
  403. {
  404. printf(" ProcessCreateTime: %u\n", mmi->ProcessCreateTime);
  405. printf(" ProcessUserTime: %u\n", mmi->ProcessUserTime);
  406. printf(" ProcessKernelTime: %u\n", mmi->ProcessKernelTime);
  407. }
  408. }
  409. break;
  410. case ExceptionStream:
  411. {
  412. const MINIDUMP_EXCEPTION_STREAM* mes = (const MINIDUMP_EXCEPTION_STREAM*)stream;
  413. unsigned int i;
  414. printf("Exception:\n");
  415. printf(" ThreadId: %08x\n", mes->ThreadId);
  416. printf(" ExceptionRecord:\n");
  417. printf(" ExceptionCode: %u\n", mes->ExceptionRecord.ExceptionCode);
  418. printf(" ExceptionFlags: %u\n", mes->ExceptionRecord.ExceptionFlags);
  419. printf(" ExceptionRecord: 0x%x%08x\n",
  420. (DWORD)(mes->ExceptionRecord.ExceptionRecord >> 32),
  421. (DWORD)mes->ExceptionRecord.ExceptionRecord);
  422. printf(" ExceptionAddress: 0x%x%08x\n",
  423. (DWORD)(mes->ExceptionRecord.ExceptionAddress >> 32),
  424. (DWORD)(mes->ExceptionRecord.ExceptionAddress));
  425. printf(" ExceptionNumberParameters: %u\n",
  426. mes->ExceptionRecord.NumberParameters);
  427. for (i = 0; i < mes->ExceptionRecord.NumberParameters; i++)
  428. {
  429. printf(" [%d]: 0x%x%08x\n", i,
  430. (DWORD)(mes->ExceptionRecord.ExceptionInformation[i] >> 32),
  431. (DWORD)mes->ExceptionRecord.ExceptionInformation[i]);
  432. }
  433. printf(" ThreadContext:\n");
  434. dump_mdmp_data(&mes->ThreadContext, " ");
  435. }
  436. break;
  437. default:
  438. printf("NIY %d\n", dir->StreamType);
  439. printf(" RVA: %u\n", dir->Location.Rva);
  440. printf(" Size: %u\n", dir->Location.DataSize);
  441. dump_mdmp_data(&dir->Location, " ");
  442. break;
  443. }
  444. }
  445. }