minidump.c 20 KB

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