Added mappings for a few messages.
[wine] / tools / cvdump / cvdump.c
1 /*
2  * CVDump - Parses through a Visual Studio .DBG file in CodeView 4 format
3  * and dumps the info to STDOUT in a human-readable format
4  *
5  * Copyright 2000 John R. Sheets
6  */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <windows.h>
12
13 #include "cvdump.h"
14
15 DWORD g_dwStartOfCodeView = 0;
16
17 int g_exe_mode = TRUE;
18 IMAGE_DOS_HEADER g_doshdr;
19 IMAGE_SEPARATE_DEBUG_HEADER g_dbghdr;
20 IMAGE_NT_HEADERS g_nthdr;
21
22 IMAGE_SECTION_HEADER *g_secthdrs = NULL;
23 int g_numsects;
24 int g_dbg_dircount;
25
26 IMAGE_DEBUG_DIRECTORY *g_debugdirs = NULL;
27 OMFSignature g_cvSig;
28 OMFDirHeader g_cvHeader;
29 OMFDirEntry *g_cvEntries = NULL;
30 int g_module_count = 0;
31 OMFModuleFull *g_cvModules = NULL;
32
33 void PrintFilePos (FILE *file)
34 {
35 #ifdef VERBOSE
36     printf (" *** Current file position = %lx\n", ftell (file));
37 #endif
38 }
39
40 /* Calculate the file offset, based on the RVA.
41  */
42 DWORD GetOffsetFromRVA (DWORD rva)
43 {
44     int i;
45     DWORD offset;
46     DWORD filepos;
47     DWORD sectbegin;
48
49     /* Assumes all RVA's in the section headers are sorted in increasing
50      * order (which should be the case).
51      */
52     for (i = g_numsects - 1; i >= 0; i--)
53     {
54         sectbegin = g_secthdrs[i].VirtualAddress;
55 #ifdef VERBOSE
56         printf ("iter = %d, rva = 0x%lx, sectbegin = 0x%lx\n", i, rva, sectbegin);
57 #endif
58         if (rva >= sectbegin)
59             break;
60     }
61
62     /* Calculate the difference between the section's RVA and file position.
63      */
64     offset = g_secthdrs[i].VirtualAddress - g_secthdrs[i].PointerToRawData;
65
66     /* Calculate the actual file position.
67      */
68     filepos = rva - offset;
69
70 #ifdef VERBOSE
71     printf (">>> Found RVA 0x%lx in section %d, at 0x%lx (section offset = 0x%lx)\n",
72             rva, i, filepos, offset);
73 #endif
74
75     return filepos;
76 }
77
78 int DumpFileHeaders (FILE *debugfile)
79 {
80     CVHeaderType hdrtype;
81
82     hdrtype = GetHeaderType (debugfile);
83
84     if (hdrtype == CV_DOS)
85     {
86         if (!ReadDOSFileHeader (debugfile, &g_doshdr))
87             return FALSE;
88
89         printf ("\n============================================================\n");
90         printf ("                   DOS FILE HEADER\n");
91         printf ("============================================================\n");
92
93         printf ("Magic Signature = [0x%4x]\n", g_doshdr.e_magic);
94         printf ("e_cblp          = [0x%4x]\n", g_doshdr.e_cblp);
95         printf ("e_cp            = [0x%4x]\n", g_doshdr.e_cp);
96         printf ("e_cric          = [0x%4x]\n", g_doshdr.e_crlc);
97         printf ("e_cparhdr       = [0x%4x]\n", g_doshdr.e_cparhdr);
98         printf ("e_minalloc      = [0x%4x]\n", g_doshdr.e_minalloc);
99         printf ("e_maxalloc      = [0x%4x]\n", g_doshdr.e_maxalloc);
100         printf ("e_ss            = [0x%4x]\n", g_doshdr.e_ss);
101         printf ("e_sp            = [0x%4x]\n", g_doshdr.e_sp);
102         printf ("e_csum          = [0x%4x]\n", g_doshdr.e_csum);
103         printf ("e_ip            = [0x%4x]\n", g_doshdr.e_ip);
104         printf ("e_cs            = [0x%4x]\n", g_doshdr.e_cs);
105         printf ("e_lfarlc        = [0x%4x]\n", g_doshdr.e_lfarlc);
106         printf ("e_ovno          = [0x%4x]\n", g_doshdr.e_ovno);
107         printf ("e_res           = [0x%4x ...]\n", g_doshdr.e_res[0]);  /* worth FIXME? */
108         printf ("e_oemid         = [0x%4x]\n", g_doshdr.e_oemid);
109         printf ("e_oeminfo       = [0x%4x]\n", g_doshdr.e_oeminfo);
110         printf ("e_res2          = [0x%4x ...]\n", g_doshdr.e_res2[0]); /* worth FIXME? */
111         printf ("e_lfanew        = [0x%8lx]\n", g_doshdr.e_lfanew);
112
113         /* Roll forward to next type */
114         hdrtype = GetHeaderType (debugfile);
115     }
116
117     if (hdrtype == CV_NT)
118     {
119         if (!ReadPEFileHeader (debugfile, &g_nthdr))
120             return FALSE;
121         
122         printf ("\n============================================================\n");
123         printf ("                PE EXECUTABLE FILE HEADER\n");
124         printf ("============================================================\n");
125
126         printf ("Signature               = [0x%8lx]\n", g_nthdr.Signature);
127         printf ("Machine                 = [0x%4x]\n", g_nthdr.FileHeader.Machine);
128         printf ("# of Sections           = [0x%4x]\n", g_nthdr.FileHeader.NumberOfSections);
129         printf ("Time/Date Stamp         = [0x%08lx]\n", g_nthdr.FileHeader.TimeDateStamp);
130         printf ("Pointer to Symbol Table = [0x%8lx]\n", g_nthdr.FileHeader.PointerToSymbolTable);
131         printf ("# of Symbols            = [0x%8lx]\n", g_nthdr.FileHeader.NumberOfSymbols);
132         printf ("Size of Opt. Hdr        = [0x%4x]\n", g_nthdr.FileHeader.SizeOfOptionalHeader);
133         printf ("Characteristics         = [0x%4x]\n", g_nthdr.FileHeader.Characteristics);
134
135         printf ("\n============================================================\n");
136         printf ("                   NT FILE HEADER\n");
137         printf ("============================================================\n");
138
139         printf ("Magic          = [0x%4x]\n", g_nthdr.OptionalHeader.Magic);
140         printf ("Linker Version = %d.%d\n", g_nthdr.OptionalHeader.MajorLinkerVersion,
141                 g_nthdr.OptionalHeader.MinorLinkerVersion);
142         printf ("Size of Code   = [0x%8lx]\n", g_nthdr.OptionalHeader.SizeOfCode);
143         printf ("Init. Data     = [0x%8lx]\n", g_nthdr.OptionalHeader.SizeOfInitializedData);
144         printf ("Uninit. Data   = [0x%8lx]\n", g_nthdr.OptionalHeader.SizeOfUninitializedData);
145         printf ("Entry Point    = [0x%8lx]\n", g_nthdr.OptionalHeader.AddressOfEntryPoint);
146         printf ("Base of Code   = [0x%8lx]\n", g_nthdr.OptionalHeader.BaseOfCode);
147         printf ("Base of Data   = [0x%8lx]\n", g_nthdr.OptionalHeader.BaseOfData);
148
149         printf ("\n============================================================\n");
150         printf ("                 NT OPTIONAL FILE HEADER\n");
151         printf ("============================================================\n");
152
153         printf ("Image Base            = [0x%8lx]\n", g_nthdr.OptionalHeader.ImageBase);
154         printf ("Section Alignment     = [0x%8lx]\n", g_nthdr.OptionalHeader.SectionAlignment);
155         printf ("File Alignment        = [0x%8lx]\n", g_nthdr.OptionalHeader.FileAlignment);
156         printf ("OS Version            = %d.%d\n", g_nthdr.OptionalHeader.MajorOperatingSystemVersion,
157                 g_nthdr.OptionalHeader.MinorOperatingSystemVersion);
158         printf ("Image Version         = %d.%d\n", g_nthdr.OptionalHeader.MajorImageVersion,
159                 g_nthdr.OptionalHeader.MinorImageVersion);
160         printf ("Subsystem Version     = %d.%d\n", g_nthdr.OptionalHeader.MajorSubsystemVersion,
161                 g_nthdr.OptionalHeader.MinorSubsystemVersion);
162         printf ("Size of Image         = [0x%8lx]\n", g_nthdr.OptionalHeader.SizeOfImage);
163         printf ("Size of Headers       = [0x%8lx]\n", g_nthdr.OptionalHeader.SizeOfHeaders);
164         printf ("Checksum              = [0x%8lx]\n", g_nthdr.OptionalHeader.CheckSum);
165         printf ("Subsystem             = [0x%4x]\n", g_nthdr.OptionalHeader.Subsystem);
166         printf ("DLL Characteristics   = [0x%4x]\n", g_nthdr.OptionalHeader.DllCharacteristics);
167         printf ("Size of Stack Reserve = [0x%8lx]\n", g_nthdr.OptionalHeader.SizeOfStackReserve);
168         printf ("Size of Stack Commit  = [0x%8lx]\n", g_nthdr.OptionalHeader.SizeOfStackCommit);
169         printf ("Size of Heap Reserve  = [0x%8lx]\n", g_nthdr.OptionalHeader.SizeOfHeapReserve);
170         printf ("Size of Heap Commit   = [0x%8lx]\n", g_nthdr.OptionalHeader.SizeOfHeapCommit);
171         printf ("Loader Flags          = [0x%8lx]\n", g_nthdr.OptionalHeader.LoaderFlags);
172         printf ("# of RVA              = [0x%8lx]\n", g_nthdr.OptionalHeader.NumberOfRvaAndSizes);
173
174         printf ("\n============================================================\n");
175         printf ("           RVA (RELATIVE VIRTUAL ADDRESS) TABLE\n");
176         printf ("============================================================\n");
177
178         printf ("NAME                    RVA         SIZE\n");
179         printf ("Export            [0x%8lx] [0x%8lx]\n",
180                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
181                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size);
182         printf ("Import            [0x%8lx] [0x%8lx]\n", 
183                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
184                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size);
185         printf ("Resource          [0x%8lx] [0x%8lx]\n", 
186                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress,
187                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size);
188         printf ("Exception         [0x%8lx] [0x%8lx]\n", 
189                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress,
190                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size);
191         printf ("Security          [0x%8lx] [0x%8lx]\n", 
192                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress,
193                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size);
194         printf ("Base Relocations  [0x%8lx] [0x%8lx]\n", 
195                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
196                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);
197         printf ("Debug             [0x%8lx] [0x%8lx]\n", 
198                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress,
199                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size);
200         printf ("Description       [0x%8lx] [0x%8lx]\n", 
201                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COPYRIGHT].VirtualAddress,
202                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COPYRIGHT].Size);
203         printf ("Special           [0x%8lx] [0x%8lx]\n", 
204                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR].VirtualAddress,
205                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR].Size);
206         printf ("Thread (TLS)      [0x%8lx] [0x%8lx]\n", 
207                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress,
208                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size);
209         printf ("Load Config       [0x%8lx] [0x%8lx]\n", 
210                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress,
211                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size);
212         printf ("Bound Import      [0x%8lx] [0x%8lx]\n", 
213                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress,
214                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size);
215         printf ("Import Addr Tbl   [0x%8lx] [0x%8lx]\n", 
216                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress,
217                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size);
218         printf ("Delay Import      [0x%8lx] [0x%8lx]\n", 
219                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress,
220                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size);
221         printf ("COM Descriptor    [0x%8lx] [0x%8lx]\n", 
222                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress,
223                 g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size);
224
225     }
226     else if (hdrtype == CV_DBG)
227     {
228         if (!ReadDBGFileHeader (debugfile, &g_dbghdr))
229             return FALSE;
230
231         g_exe_mode = FALSE;
232 #ifdef VERBOSE
233         printf ("[ Found DBG header...file is not a PE executable. ]\n");
234 #endif
235
236         printf ("\n============================================================\n");
237         printf ("          STANDALONE DEBUG FILE HEADER (.DBG)\n");
238         printf ("============================================================\n");
239
240         printf ("Signature          = [0x%4x]\n", g_dbghdr.Signature);
241         printf ("Flags              = [0x%4x]\n", g_dbghdr.Flags);
242         printf ("Machine            = [0x%4x]\n", g_dbghdr.Machine);
243         printf ("Characteristics    = [0x%4x]\n", g_dbghdr.Characteristics);
244         printf ("TimeDateStamp      = [0x%8lx]\n", g_dbghdr.TimeDateStamp);
245         printf ("CheckSum           = [0x%8lx]\n", g_dbghdr.CheckSum);
246         printf ("ImageBase          = [0x%8lx]\n", g_dbghdr.ImageBase);
247         printf ("SizeOfImage        = [0x%8lx]\n", g_dbghdr.SizeOfImage);
248         printf ("NumberOfSections   = [0x%8lx]\n", g_dbghdr.NumberOfSections);
249         printf ("ExportedNamesSize  = [0x%8lx]\n", g_dbghdr.ExportedNamesSize);
250         printf ("DebugDirectorySize = [0x%8lx]\n", g_dbghdr.DebugDirectorySize);
251
252         return TRUE;
253     }
254
255     return TRUE;
256 }
257
258 int DumpSectionHeaders (FILE *debugfile)
259 {
260     int i;
261
262     printf ("\n============================================================\n");
263     printf ("                 COFF SECTION HEADERS\n");
264     printf ("============================================================\n");
265
266     PrintFilePos (debugfile);
267     if (!ReadSectionHeaders (debugfile, g_numsects, &g_secthdrs))
268         return FALSE;
269
270     /* Print out a quick list of section names
271      */
272     for (i = 0; i < g_numsects; i++)
273         printf ("%8s (0x%08lx bytes long, starts at 0x%08lx)\n", g_secthdrs[i].Name,
274                 g_secthdrs[i].SizeOfRawData, g_secthdrs[i].PointerToRawData);
275
276     /* Print out bulk of info
277      */
278     for (i = 0; i < g_numsects; i++)
279     {
280         printf ("\nContents of IMAGE_SECTION_HEADER %s:\n\n", g_secthdrs[i].Name);
281
282         printf ("Name                 = %s\n", g_secthdrs[i].Name);
283         printf ("VirtualSize          = [0x%8lx]\n", g_secthdrs[i].Misc.VirtualSize);
284         printf ("VirtualAddress       = [0x%8lx]\n", g_secthdrs[i].VirtualAddress);
285         printf ("SizeOfRawData        = [0x%8lx]\n", g_secthdrs[i].SizeOfRawData);
286         printf ("PointerToRawData     = [0x%8lx]\n", g_secthdrs[i].PointerToRawData);
287         printf ("PointerToRelocations = [0x%8lx]\n", g_secthdrs[i].PointerToRelocations);
288         printf ("PointerToLinenumbers = [0x%8lx]\n", g_secthdrs[i].PointerToLinenumbers);
289         printf ("NumberOfRelocations  = [0x%4x]\n", g_secthdrs[i].NumberOfRelocations);
290         printf ("NumberOfLinenumbers  = [0x%4x]\n", g_secthdrs[i].NumberOfLinenumbers);
291         printf ("Characteristics      = [0x%8lx]\n", g_secthdrs[i].Characteristics);
292     }
293
294     return TRUE;
295 }
296
297 void PrintDebugDirectoryType (DWORD type)
298 {
299     switch (type)
300     {
301     case IMAGE_DEBUG_TYPE_UNKNOWN:
302         printf ("<Unknown Directory> - %ld\n", type);
303         break;
304     case IMAGE_DEBUG_TYPE_COFF:
305         printf ("COFF Directory:\n");
306         break;
307     case IMAGE_DEBUG_TYPE_CODEVIEW:
308         printf ("CodeView Directory:\n");
309         break;
310     case IMAGE_DEBUG_TYPE_FPO:
311         printf ("FPO Directory:\n");
312         break;
313     case IMAGE_DEBUG_TYPE_MISC:
314         printf ("MISC Directory:\n");
315         break;
316
317     default:
318         printf ("<Undefined Directory> - %ld\n", type);
319     }
320 }
321
322 int DumpDebugDir (FILE *debugfile)
323 {
324     int i;
325     int filepos;
326
327     printf ("\n============================================================\n");
328     printf ("                CODEVIEW DEBUG DIRECTORY\n");
329     printf ("============================================================\n");
330
331     PrintFilePos (debugfile);
332
333     printf ("Found %d Debug director%s...\n", g_dbg_dircount,
334             (g_dbg_dircount == 1) ? "y" : "ies");
335
336     if (g_dbg_dircount == 0)
337         return FALSE;
338
339     /* Find the location of the debug directory table.
340      */
341     if (g_exe_mode)
342     {
343         /* Convert the RVA to a file offset.
344          */
345         filepos = GetOffsetFromRVA (g_nthdr.OptionalHeader.DataDirectory[IMAGE_FILE_DEBUG_DIRECTORY].VirtualAddress);
346
347         fseek (debugfile, filepos, SEEK_SET);
348         PrintFilePos (debugfile);
349     }
350     else
351     {
352         fseek( debugfile, g_dbghdr.ExportedNamesSize, SEEK_CUR);
353         PrintFilePos (debugfile);
354     }
355
356     if (!ReadDebugDir (debugfile, g_dbg_dircount, &g_debugdirs))
357         return FALSE;
358
359     /* Print out the contents of the directories.
360      */
361     for (i = 0; i < g_dbg_dircount; i++)
362     {
363         /* Remember start of debug data...for later
364          */
365         if (g_debugdirs[i].Type == IMAGE_DEBUG_TYPE_CODEVIEW)
366         {
367             g_dwStartOfCodeView = g_debugdirs[i].PointerToRawData;
368 #ifdef VERBOSE
369             printf ("\n[ Found start of CodeView data, at 0x%lx ]\n\n", g_dwStartOfCodeView);
370 #endif
371         }
372
373         printf ("\n");
374         PrintDebugDirectoryType (g_debugdirs[i].Type);
375         printf ("  Characteristics  = [0x%8lx]\n", g_debugdirs[i].Characteristics);
376         printf ("  TimeDateStamp    = [0x%8lx]\n", g_debugdirs[i].TimeDateStamp);
377         printf ("  Version          = %d.%d\n", g_debugdirs[i].MajorVersion, g_debugdirs[i].MinorVersion);
378         printf ("  SizeOfData       = [0x%8lx]\n", g_debugdirs[i].SizeOfData);
379         printf ("  AddressOfRawData = [0x%8lx]\n", g_debugdirs[i].AddressOfRawData);
380         printf ("  PointerToRawData = [0x%8lx]\n", g_debugdirs[i].PointerToRawData);
381
382         if (g_debugdirs[i].Type == IMAGE_DEBUG_TYPE_MISC)
383         {
384             IMAGE_DEBUG_DIRECTORY_MISC misc;
385             int lastpos = ftell (debugfile);
386             size_t bytes_read;
387
388             /* FIXME: Not sure exactly what the contents are supposed to be. */
389             fseek (debugfile, g_debugdirs[i].PointerToRawData, SEEK_SET);
390             bytes_read = fread (&misc, 1, sizeof (IMAGE_DEBUG_DIRECTORY_MISC), debugfile);
391             printf ("\n    [0x%8lx]\n    [0x%8lx]\n    [0x%4x]\n    [0x%4x]\n    '%s'\n",
392                     misc.unknown1, misc.SizeOfData, misc.unknown2,
393                     misc.unknown3, misc.Name);
394
395             fseek (debugfile, lastpos, SEEK_SET);
396         }
397     }
398
399     free (g_debugdirs);
400     return TRUE;
401 }
402
403 void PrintSubsectionName (int ssNum)
404 {
405     switch (ssNum)
406     {
407     case sstModule:
408         printf ("sstModule");
409         break;
410     case sstAlignSym:
411         printf ("sstAlignSym");
412         break;
413     case sstSrcModule:
414         printf ("sstSrcModule");
415         break;
416     case sstLibraries:
417         printf ("sstLibraries");
418         break;
419     case sstGlobalSym:
420         printf ("sstGlobalSym");
421         break;
422     case sstGlobalPub:
423         printf ("sstGlobalPub");
424         break;
425     case sstGlobalTypes:
426         printf ("sstGlobalTypes");
427         break;
428     case sstSegMap:
429         printf ("sstSegMap");
430         break;
431     case sstFileIndex:
432         printf ("sstFileIndex");
433         break;
434     case sstStaticSym:
435         printf ("sstStaticSym");
436         break;
437
438     default:
439         printf ("<undefined> - %x", ssNum);
440     }
441 }
442
443 int DumpCodeViewSummary (OMFDirEntry *entries, long entrycount)
444 {
445     int i;
446     int modulecount = 0, alignsymcount = 0, srcmodulecount = 0, librariescount = 0;
447     int globalsymcount = 0, globalpubcount = 0, globaltypescount = 0;
448     int segmapcount = 0, fileindexcount = 0, staticsymcount = 0;
449
450     if (entries == NULL || entrycount == 0)
451         return FALSE;
452
453     for (i = 0; i < entrycount; i++)
454     {
455         switch ((int)g_cvEntries[i].SubSection)
456         {
457         case sstModule:
458             modulecount++;
459             break;
460         case sstAlignSym:
461             alignsymcount++;
462             break;
463         case sstSrcModule:
464             srcmodulecount++;
465             break;
466         case sstLibraries:
467             librariescount++;
468             break;
469         case sstGlobalSym:
470             globalsymcount++;
471             break;
472         case sstGlobalPub:
473             globalpubcount++;
474             break;
475         case sstGlobalTypes:
476             globaltypescount++;
477             break;
478         case sstSegMap:
479             segmapcount++;
480             break;
481         case sstFileIndex:
482             fileindexcount++;
483             break;
484         case sstStaticSym:
485             staticsymcount++;
486             break;
487         }       
488     }
489
490     /* This one has to be > 0
491      */
492     printf ("\nFound: %d sstModule subsections\n", modulecount);
493
494     if (alignsymcount > 0)    printf ("       %d sstAlignSym subsections\n", alignsymcount);
495     if (srcmodulecount > 0)   printf ("       %d sstSrcModule subsections\n", srcmodulecount);
496     if (librariescount > 0)   printf ("       %d sstLibraries subsections\n", librariescount);
497     if (globalsymcount > 0)   printf ("       %d sstGlobalSym subsections\n", globalsymcount);
498     if (globalpubcount > 0)   printf ("       %d sstGlobalPub subsections\n", globalpubcount);
499     if (globaltypescount > 0) printf ("       %d sstGlobalTypes subsections\n", globaltypescount);
500     if (segmapcount > 0)      printf ("       %d sstSegMap subsections\n", segmapcount);
501     if (fileindexcount > 0)   printf ("       %d sstFileIndex subsections\n", fileindexcount);
502     if (staticsymcount > 0)   printf ("       %d sstStaticSym subsections\n", staticsymcount);
503     
504     return TRUE;
505 }
506
507 int DumpCodeViewHeaders (FILE *debugfile)
508 {
509     printf ("\n============================================================\n");
510     printf ("                    CODEVIEW HEADERS\n");
511     printf ("============================================================\n");
512
513     PrintFilePos (debugfile);
514
515     fseek (debugfile, g_dwStartOfCodeView, SEEK_SET);
516     printf ("CodeView Directory Table begins at filepos = 0x%lx\n\n", ftell (debugfile));
517
518     if (!ReadCodeViewHeader (debugfile, &g_cvSig, &g_cvHeader))
519         return FALSE;
520
521     printf ("Signature   = %.4s\n", g_cvSig.Signature);
522     printf ("filepos     = [0x%8lx]\n", g_cvSig.filepos);
523     printf ("File Location of debug directories = [0x%8lx]\n\n", g_cvSig.filepos + g_dwStartOfCodeView);
524
525     printf ("Size of header    = [0x%4x]\n", g_cvHeader.cbDirHeader);
526     printf ("Size per entry    = [0x%4x]\n", g_cvHeader.cbDirEntry);
527     printf ("# of entries      = [0x%8lx] (%ld)\n", g_cvHeader.cDir, g_cvHeader.cDir);
528     printf ("Offset to NextDir = [0x%8lx]\n", g_cvHeader.lfoNextDir);
529     printf ("Flags             = [0x%8lx]\n", g_cvHeader.flags);
530
531     if (!ReadCodeViewDirectory (debugfile, g_cvHeader.cDir, &g_cvEntries))
532         return FALSE;
533
534     DumpCodeViewSummary (g_cvEntries, g_cvHeader.cDir);
535
536     return TRUE;
537 }
538
539 /*
540  * Print out the info contained in the sstModule section of a single module
541  */
542 int DumpModuleInfo (int index)
543 {
544     int segnum;
545
546     if (g_cvEntries == NULL || g_cvModules == NULL)
547         return FALSE;
548
549     printf ("---------------------- sstModule ----------------------\n");
550
551     /* Print out some juicy module data
552      */
553     printf ("  '%s' module holds %d segment(s) (style %c%c)\n",
554             g_cvModules[index].Name, g_cvModules[index].cSeg,
555             g_cvModules[index].Style[0], g_cvModules[index].Style[1]);
556
557     /* Print out info from module's OMFDirEntry
558      */
559     printf ("             file offset = [0x%8lx]\n", g_cvEntries[index].lfo);
560     printf ("             size        = [0x%8lx]\n\n", g_cvEntries[index].cb);
561
562     for (segnum = 0; segnum < g_cvModules[index].cSeg; segnum++)
563     {
564         printf ("  segment #%d: offset = [0x%8lx], size = [0x%8lx]\n",
565                 g_cvModules[index].SegInfo[segnum].Seg, 
566                 g_cvModules[index].SegInfo[segnum].Off, 
567                 g_cvModules[index].SegInfo[segnum].cbSeg);
568     }
569
570     return TRUE;
571 }
572
573 int DumpGlobalPubInfo (int index, FILE *debugfile)
574 {
575     long fileoffset;
576     unsigned long sectionsize;
577     OMFSymHash header;
578     BYTE *symbols;
579     BYTE *curpos;
580     PUBSYM32 *sym;
581     char symlen;
582     char *symname;
583     int recordlen;
584     char nametmp[256] = { 0 };  /* Zero out */
585
586     if (g_cvEntries == NULL || debugfile == NULL || 
587         g_cvEntries[index].SubSection != sstGlobalPub)
588         return FALSE;
589
590     printf ("-------------------- sstGlobalPub --------------------\n");
591
592     sectionsize = g_cvEntries[index].cb;
593     printf ("  offset = [0x%8lx]\n  size   = [0x%8lx]\n", g_cvEntries[index].lfo, sectionsize);
594
595     fileoffset = g_dwStartOfCodeView + g_cvEntries[index].lfo;
596     printf ("  GlobalPub section starts at file offset 0x%lx\n", fileoffset);
597     printf ("  Symbol table starts at 0x%lx\n", fileoffset + sizeof (OMFSymHash));
598
599 #ifdef VERBOSE
600     printf (" [iMod = %d] [index = %d]\n", g_cvEntries[index].iMod, index);
601 #endif
602
603     printf ("\n                       ----- Begin Symbol Table -----\n");
604     printf ("  (type)      (symbol name)                 (offset)      (len) (seg) (ind)\n");
605
606     /* Read the section header.
607      */
608     if (!ReadChunk (debugfile, (void*)&header, sizeof (OMFSymHash), fileoffset))
609         return FALSE;
610     PrintFilePos (debugfile);
611
612     /* Read the entire sstGlobalPub symbol table.
613      */
614     symbols = malloc (header.cbSymbol);
615     if (!ReadChunk (debugfile, (void*)symbols, header.cbSymbol, -1))
616         return FALSE;
617
618     /* We don't know how many symbols are in this block of memory...only what
619      * the total size of the block is.  Because the symbol's name is tacked
620      * on to the end of the PUBSYM32 struct, each symbol may take up a different
621      * # of bytes.  This makes it harder to parse through the symbol table,
622      * since we won't know the exact location of the following symbol until we've
623      * already parsed the current one.
624      */
625     curpos = symbols;
626     while (curpos < symbols + header.cbSymbol)
627     {
628         /* Point to the next PUBSYM32 in the table.
629          */
630         sym = (PUBSYM32*)curpos;
631
632         /* Ugly hack to find the start of the (length-prefixed) name string.
633          * Must be careful about pointer math (i.e. can't use 'sym').
634          *
635          * FIXME: Should take into account the length...this approach hopes
636          * for a coincidental NULL after the string.
637          */
638         symlen = *(curpos + sizeof (PUBSYM32));
639         symname = curpos + sizeof (PUBSYM32) + 1;
640
641         /* "  (type) (symbol name)         (offset)   (len) (seg) (typind)" */
642
643         snprintf (nametmp, symlen + 1, "%s", symname);
644         printf ("  0x%04x  %-30.30s  [0x%8lx]  [0x%4x]  %d     %ld\n",
645                 sym->rectyp, nametmp, sym->off, sym->reclen, sym->seg, sym->typind);
646
647         /* The entire record is null-padded to the nearest 4-byte
648          * boundary, so we must do a little extra math to keep things straight.
649          */
650         recordlen = sym->reclen;
651         if (recordlen % 4)
652             recordlen += 4 - (recordlen % 4);
653         
654         /*  printf ("Padding length of %d bytes to %d\n", sym->reclen, recordlen); */
655
656         curpos += recordlen;
657     }
658
659     printf ("  Freeing symbol memory...\n");
660     free (symbols);
661
662     return TRUE;
663 }
664
665 int DumpGlobalSymInfo (int index, FILE *debugfile)
666 {
667     if (g_cvEntries == NULL || debugfile == NULL || 
668         g_cvEntries[index].SubSection != sstGlobalSym)
669         return FALSE;
670
671     /*** NOT YET IMPLEMENTED ***/
672     printf ("---Found section ");
673     PrintSubsectionName (g_cvEntries[index].SubSection);
674     printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
675     printf (" of module #%d---\n", index + 1);
676
677     return TRUE;
678 }
679
680 int DumpStaticSymInfo (int index, FILE *debugfile)
681 {
682     if (g_cvEntries == NULL || debugfile == NULL || 
683         g_cvEntries[index].SubSection != sstStaticSym)
684         return FALSE;
685
686     /*** NOT YET IMPLEMENTED ***/
687     printf ("---Found section ");
688     PrintSubsectionName (g_cvEntries[index].SubSection);
689     printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
690     printf (" of module #%d---\n", index + 1);
691
692     return TRUE;
693 }
694
695 int DumpLibrariesInfo (int index, FILE *debugfile)
696 {
697     if (g_cvEntries == NULL || debugfile == NULL || 
698         g_cvEntries[index].SubSection != sstLibraries)
699         return FALSE;
700
701     /*** NOT YET IMPLEMENTED ***/
702     printf ("---Found section ");
703     PrintSubsectionName (g_cvEntries[index].SubSection);
704     printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
705     printf (" of module #%d---\n", index + 1);
706
707     return TRUE;
708 }
709
710 int DumpGlobalTypesInfo (int index, FILE *debugfile)
711 {
712     if (g_cvEntries == NULL || debugfile == NULL || 
713         g_cvEntries[index].SubSection != sstGlobalTypes)
714         return FALSE;
715
716     /*** NOT YET IMPLEMENTED ***/
717     printf ("---Found section ");
718     PrintSubsectionName (g_cvEntries[index].SubSection);
719     printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
720     printf (" of module #%d---\n", index + 1);
721
722     return TRUE;
723 }
724
725 int DumpSegMapInfo (int index, FILE *debugfile)
726 {
727     if (g_cvEntries == NULL || debugfile == NULL || 
728         g_cvEntries[index].SubSection != sstSegMap)
729         return FALSE;
730
731     printf ("-------------------- sstSegMap --------------------\n");
732
733     printf ("---Found section ");
734     PrintSubsectionName (g_cvEntries[index].SubSection);
735     printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
736     printf (" of module #%d---\n", index + 1);
737
738     return TRUE;
739 }
740
741 int DumpFileIndexInfo (int index, FILE *debugfile)
742 {
743     if (g_cvEntries == NULL || debugfile == NULL || 
744         g_cvEntries[index].SubSection != sstFileIndex)
745         return FALSE;
746
747     /*** NOT YET IMPLEMENTED ***/
748     printf ("---Found section ");
749     PrintSubsectionName (g_cvEntries[index].SubSection);
750     printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
751     printf (" of module #%d---\n", index + 1);
752
753     return TRUE;
754 }
755
756 int DumpSrcModuleInfo (int index, FILE *debugfile)
757 {
758     int i;
759     int fileoffset;
760     BYTE *rawdata;
761     BYTE *curpos;
762     short filecount;
763     short segcount;
764
765     int moduledatalen;
766     int filedatalen;
767     int linedatalen;
768
769     if (g_cvEntries == NULL || debugfile == NULL || 
770         g_cvEntries[index].SubSection != sstSrcModule)
771         return FALSE;
772
773     printf ("--------------------- sstSrcModule --------------------\n");
774     printf ("             file offset = [0x%8lx]\n", g_dwStartOfCodeView + g_cvEntries[index].lfo);
775     printf ("             size        = [0x%8lx]\n", g_cvEntries[index].cb);
776
777     /* Where in the .DBG file should we start reading?
778      */
779     fileoffset = g_dwStartOfCodeView + g_cvEntries[index].lfo;
780
781     /* Allocate a chunk of memory for the entire sstSrcModule
782      */
783     rawdata = malloc (g_cvEntries[index].cb);
784     if (!rawdata)
785     {
786         printf ("ERROR - Unable to allocate %ld bytes for DumpSrcModuleInfo()\n",
787                 g_cvEntries[index].cb);
788         return FALSE;
789     }
790
791     /* Read in the entire sstSrcModule from the .DBG file.  We'll process it
792      * bit by bit, by passing memory pointers into the various functions in
793      * cvcrunch.c.
794      */
795     if (!ReadChunk (debugfile, (void*)rawdata, g_cvEntries[index].cb, fileoffset))
796         return FALSE;
797
798     moduledatalen = PrintSrcModuleInfo (rawdata, &filecount, &segcount);
799 #ifdef VERBOSE
800     printf ("*** PrintSrcModuleInfo() returned %d\n", moduledatalen);
801 #endif
802
803     curpos = rawdata + moduledatalen;
804     filedatalen = PrintSrcModuleFileInfo (curpos);
805 #ifdef VERBOSE
806     printf ("*** PrintSrcModuleFileInfo() returned %d\n", filedatalen);
807 #endif
808
809     curpos += filedatalen;
810     for (i = 0; i < segcount; i++)
811     {
812         linedatalen = PrintSrcModuleLineInfo (curpos, i);
813 #ifdef VERBOSE
814         printf ("*** PrintSrcModuleLineInfo() returned %d\n", linedatalen);
815 #endif
816
817         curpos += linedatalen;
818     }
819
820     free (rawdata);
821
822     return TRUE;
823 }
824
825 int DumpAlignSymInfo (int index, FILE *debugfile)
826 {
827     if (g_cvEntries == NULL || debugfile == NULL || 
828         g_cvEntries[index].SubSection != sstAlignSym)
829         return FALSE;
830
831     /*** NOT YET IMPLEMENTED ***/
832     printf ("--------------------- sstAlignSym ---------------------\n");
833     printf ("  [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
834     printf (" of module #%d\n", index + 1);
835
836     return TRUE;
837 }
838
839 /*
840  * Print out the info of all related modules (e.g. sstAlignSym, sstSrcModule)
841  * for the given sub-section index (i.e. sstModule).
842  */
843 int DumpRelatedSections (int index, FILE *debugfile)
844 {
845     int i;
846
847     if (g_cvEntries == NULL)
848         return FALSE;
849
850     /*  printf ("...Scanning %ld entries for matches on module #%d\n", g_cvHeader.cDir, module_num); */
851
852     for (i = 0; i < g_cvHeader.cDir; i++)
853     {
854         if (g_cvEntries[i].iMod != (index + 1) ||
855             g_cvEntries[i].SubSection == sstModule)
856             continue;
857
858         /* Pass in index of entry in g_cvEntries array to individual sub-section
859          * dumping functions.  Each function will figure out where in the file its
860          * sub-section lies and seek the file position itself, before parsing out
861          * its data.
862          */
863         switch (g_cvEntries[i].SubSection)
864         {
865         case sstAlignSym:
866             DumpAlignSymInfo (i, debugfile);
867             break;
868         case sstSrcModule:
869             DumpSrcModuleInfo (i, debugfile);
870             break;
871
872         default:
873             printf ("---Found section ");
874             PrintSubsectionName (g_cvEntries[i].SubSection);
875             printf (" [iMod = %d] [i = %d]", g_cvEntries[i].iMod, i);
876             printf (" of module #%d---\n", index + 1);
877         }
878     }
879
880     return TRUE;
881 }
882
883 int DumpMiscSections (int index, FILE *debugfile)
884 {
885     /* The module # 65535 is reserved for all free-standing modules, not
886      * associated with a sstModule sub-section.  These are the only sections
887      * we wish to process here.
888      */
889     if (g_cvEntries == NULL || g_cvEntries[index].iMod != 65535)
890         return FALSE;
891
892     /* Pass in index of entry in g_cvEntries array to individual sub-section
893      * dumping functions.  Each function will figure out where in the file its
894      * sub-section lies and seek the file position itself, before parsing out
895      * its data.
896      */
897     switch (g_cvEntries[index].SubSection)
898     {
899     case sstGlobalPub:
900         DumpGlobalPubInfo (index, debugfile);
901         break;
902     case sstGlobalSym:
903         DumpGlobalSymInfo (index, debugfile);
904         break;
905     case sstStaticSym:
906         DumpStaticSymInfo (index, debugfile);
907         break;
908     case sstLibraries:
909         DumpLibrariesInfo (index, debugfile);
910         break;
911     case sstGlobalTypes:
912         DumpGlobalTypesInfo (index, debugfile);
913         break;
914     case sstSegMap:
915         DumpSegMapInfo (index, debugfile);
916         break;
917     case sstFileIndex:
918         DumpFileIndexInfo (index, debugfile);
919         break;
920
921     default:
922         printf ("---Found section ");
923         PrintSubsectionName (g_cvEntries[index].SubSection);
924         printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
925         printf (" of module #%d---\n", index + 1);
926     }
927
928     return TRUE;
929 }
930
931 int DumpAllModules (FILE *debugfile)
932 {
933     int i;
934
935     if (g_cvHeader.cDir == 0)
936     {
937         printf ("\nStrange...found CodeView header, but no module entries\n\n");
938         return TRUE;
939     }
940
941     if (g_cvEntries == NULL)
942     {
943         printf ("ERROR: Invalid entry table, bailing out of Module Data Dump\n");
944         printf ("%ld %p\n", g_cvHeader.cDir, g_cvEntries);
945         return FALSE;
946     }
947
948     printf ("\n============================================================\n");
949     printf ("                    MODULE LISTING\n");
950     printf ("============================================================\n");
951
952     /* Seek to beginning of debug data
953      */
954     fseek (debugfile, g_dwStartOfCodeView + g_cvEntries[0].lfo, SEEK_SET);
955 #ifdef VERBOSE
956     printf ("[ Moving to filepos = 0x%lx to read in CodeView module info ]\n",
957             ftell (debugfile));
958 #endif
959
960     /* Load all OMFModuleFull data from file into memory
961      */
962     if (!ReadModuleData (debugfile, g_cvHeader.cDir, g_cvEntries,
963                          &g_module_count, &g_cvModules))
964     {
965         PrintFilePos (debugfile);
966         return FALSE;
967     }
968
969     /* Print out bulk of info (depends on the fact that all sstModule's
970      * are packed at the beginning of the array).
971      */
972     printf ("Found %d modules\n", g_module_count);
973     for (i = 0; i < g_module_count; i++)
974     {
975         printf ("\n====================== Module #%d ======================\n", i + 1);
976         DumpModuleInfo (i);
977         DumpRelatedSections (i, debugfile);
978         printf ("=======================================================\n");
979     }
980
981     printf ("\n============================================================\n");
982     printf ("                  MISCELLANEOUS MODULES\n");
983     printf ("============================================================\n");
984
985     for (i = 0; i < g_cvHeader.cDir; i++)
986     {
987         DumpMiscSections (i, debugfile);
988     }
989
990     return TRUE;
991 }
992
993
994 /*
995  * Free Global data used by OMFModuleFull structs.  Can't just use free() because
996  * the 'SegInfo' and 'Name' fields also have allocated memory.
997  */
998 void FreeCVModules ()
999 {
1000     int i;
1001     OMFModuleFull *module;
1002
1003     for (i = 0; i < g_module_count; i++)
1004     {
1005         module = &(g_cvModules[i]);
1006
1007         free (module->SegInfo);
1008         free (module->Name);
1009         free (module);
1010     }
1011 }
1012
1013 int DumpCVFile (LPSTR filename)
1014 {
1015     FILE *debugfile;
1016
1017     if (strlen (filename) == 0)
1018         return (-1);
1019
1020     debugfile = fopen (filename, "r");
1021     if (debugfile == NULL)
1022     {
1023         printf ("============================================================\n");
1024         printf ("   ERROR: Unable to open file [%s]\n", filename);
1025         printf ("============================================================\n");
1026         return (-1);
1027     }
1028
1029     printf ("============================================================\n");
1030     printf ("        Performing bindump on file %s\n", filename);
1031     printf ("============================================================\n\n");
1032
1033     if (!DumpFileHeaders (debugfile))
1034     {
1035         printf ("============================================================\n");
1036         printf ("   ERROR: Bailed out while printing file headers!\n");
1037         printf ("============================================================\n");
1038         return (-1);
1039     }
1040
1041     if (g_exe_mode)
1042         g_numsects = g_nthdr.FileHeader.NumberOfSections;
1043     else
1044         g_numsects = g_dbghdr.NumberOfSections;
1045
1046     if (!DumpSectionHeaders (debugfile))
1047     {
1048         printf ("============================================================\n");
1049         printf ("   ERROR: Bailed out while printing section headers\n");
1050         printf ("============================================================\n");
1051         return (-1);
1052     }
1053
1054     if (g_exe_mode)
1055         g_dbg_dircount = g_nthdr.OptionalHeader.DataDirectory[IMAGE_FILE_DEBUG_DIRECTORY].Size /
1056             sizeof (IMAGE_DEBUG_DIRECTORY);
1057     else
1058         g_dbg_dircount = g_dbghdr.DebugDirectorySize / sizeof (IMAGE_DEBUG_DIRECTORY);
1059
1060 #ifdef VERBOSE
1061     printf ("\n[ Found %d debug directories in %s file. ]\n", g_dbg_dircount,
1062             g_exe_mode ? "PE" : "DBG");
1063 #endif
1064
1065     if (!DumpDebugDir (debugfile))
1066     {
1067         printf ("============================================================\n");
1068         printf ("   ERROR: Bailed out while printing Debug Directories\n");
1069         printf ("============================================================\n");
1070         return (-1);
1071     }
1072
1073     /* Only dump CodeView data if we know where it is!
1074      */
1075     if (g_dwStartOfCodeView == 0)
1076     {
1077         printf ("============================================================\n");
1078         printf ("   ERROR: Unable to find CodeView info!\n");
1079         printf ("============================================================\n");
1080         return (-1);
1081     }
1082
1083     if (!DumpCodeViewHeaders (debugfile))
1084     {
1085         printf ("============================================================\n");
1086         printf ("   ERROR: Bailed out while printing CodeView headers\n");
1087         printf ("============================================================\n");
1088         return (-1);
1089     }
1090
1091     if (!DumpAllModules (debugfile))
1092     {
1093         printf ("============================================================\n");
1094         printf ("   ERROR: Bailed out while printing CodeView debug info\n");
1095         printf ("============================================================\n");
1096         return (-1);
1097     }
1098
1099     /* Clean up our trash
1100      */
1101     printf ("Shutting down...\n");
1102
1103     free (g_debugdirs);
1104     free (g_secthdrs);
1105
1106     /* FIXME: For some reason, this call segfaults...check it out later */
1107     /*  free (g_cvEntries); */
1108
1109     /*  printf ("Freeing module data..."); */
1110     /*  FreeCVModules (); */
1111
1112     return 0;
1113 }
1114
1115 int main(int argc, char *argv[])
1116 {
1117     int i;
1118
1119     if (argc == 1)
1120     {
1121         printf ("Usage:\n\tcvdump FILE [FILES...]\n");
1122         return (-1);
1123     }
1124
1125     for (i = 1; i < argc; i++)
1126        DumpCVFile (argv[i]);
1127     return 0;
1128 }