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