Use "CALL" and "RET" in capital letters for distinction.
[wine.git] / tools / cvdump / cvdump.c
blob0035dde5bd98c72f4d39a8b528b2edf5b14744a4
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
5 * Copyright 2000 John R. Sheets
6 */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <windows.h>
13 #include "cvdump.h"
15 DWORD g_dwStartOfCodeView = 0;
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;
22 IMAGE_SECTION_HEADER *g_secthdrs = NULL;
23 int g_numsects;
24 int g_dbg_dircount;
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;
33 void PrintFilePos (FILE *file)
35 #ifdef VERBOSE
36 printf (" *** Current file position = %lx\n", ftell (file));
37 #endif
40 /* Calculate the file offset, based on the RVA.
42 DWORD GetOffsetFromRVA (DWORD rva)
44 int i;
45 DWORD offset;
46 DWORD filepos;
47 DWORD sectbegin;
49 /* Assumes all RVA's in the section headers are sorted in increasing
50 * order (which should be the case).
52 for (i = g_numsects - 1; i >= 0; i--)
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;
62 /* Calculate the difference between the section's RVA and file position.
64 offset = g_secthdrs[i].VirtualAddress - g_secthdrs[i].PointerToRawData;
66 /* Calculate the actual file position.
68 filepos = rva - offset;
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
75 return filepos;
78 int DumpFileHeaders (FILE *debugfile)
80 CVHeaderType hdrtype;
82 hdrtype = GetHeaderType (debugfile);
84 if (hdrtype == CV_DOS)
86 if (!ReadDOSFileHeader (debugfile, &g_doshdr))
87 return FALSE;
89 printf ("\n============================================================\n");
90 printf (" DOS FILE HEADER\n");
91 printf ("============================================================\n");
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);
113 /* Roll forward to next type */
114 hdrtype = GetHeaderType (debugfile);
117 if (hdrtype == CV_NT)
119 if (!ReadPEFileHeader (debugfile, &g_nthdr))
120 return FALSE;
122 printf ("\n============================================================\n");
123 printf (" PE EXECUTABLE FILE HEADER\n");
124 printf ("============================================================\n");
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);
135 printf ("\n============================================================\n");
136 printf (" NT FILE HEADER\n");
137 printf ("============================================================\n");
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);
149 printf ("\n============================================================\n");
150 printf (" NT OPTIONAL FILE HEADER\n");
151 printf ("============================================================\n");
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);
174 printf ("\n============================================================\n");
175 printf (" RVA (RELATIVE VIRTUAL ADDRESS) TABLE\n");
176 printf ("============================================================\n");
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);
226 else if (hdrtype == CV_DBG)
228 if (!ReadDBGFileHeader (debugfile, &g_dbghdr))
229 return FALSE;
231 g_exe_mode = FALSE;
232 #ifdef VERBOSE
233 printf ("[ Found DBG header...file is not a PE executable. ]\n");
234 #endif
236 printf ("\n============================================================\n");
237 printf (" STANDALONE DEBUG FILE HEADER (.DBG)\n");
238 printf ("============================================================\n");
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);
252 return TRUE;
255 return TRUE;
258 int DumpSectionHeaders (FILE *debugfile)
260 int i;
262 printf ("\n============================================================\n");
263 printf (" COFF SECTION HEADERS\n");
264 printf ("============================================================\n");
266 PrintFilePos (debugfile);
267 if (!ReadSectionHeaders (debugfile, g_numsects, &g_secthdrs))
268 return FALSE;
270 /* Print out a quick list of section names
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);
276 /* Print out bulk of info
278 for (i = 0; i < g_numsects; i++)
280 printf ("\nContents of IMAGE_SECTION_HEADER %s:\n\n", g_secthdrs[i].Name);
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);
294 return TRUE;
297 void PrintDebugDirectoryType (DWORD type)
299 switch (type)
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;
317 default:
318 printf ("<Undefined Directory> - %ld\n", type);
322 int DumpDebugDir (FILE *debugfile)
324 int i;
325 int filepos;
327 printf ("\n============================================================\n");
328 printf (" CODEVIEW DEBUG DIRECTORY\n");
329 printf ("============================================================\n");
331 PrintFilePos (debugfile);
333 printf ("Found %d Debug director%s...\n", g_dbg_dircount,
334 (g_dbg_dircount == 1) ? "y" : "ies");
336 if (g_dbg_dircount == 0)
337 return FALSE;
339 /* Find the location of the debug directory table.
341 if (g_exe_mode)
343 /* Convert the RVA to a file offset.
345 filepos = GetOffsetFromRVA (g_nthdr.OptionalHeader.DataDirectory[IMAGE_FILE_DEBUG_DIRECTORY].VirtualAddress);
347 fseek (debugfile, filepos, SEEK_SET);
348 PrintFilePos (debugfile);
350 else
352 fseek( debugfile, g_dbghdr.ExportedNamesSize, SEEK_CUR);
353 PrintFilePos (debugfile);
356 if (!ReadDebugDir (debugfile, g_dbg_dircount, &g_debugdirs))
357 return FALSE;
359 /* Print out the contents of the directories.
361 for (i = 0; i < g_dbg_dircount; i++)
363 /* Remember start of debug data...for later
365 if (g_debugdirs[i].Type == IMAGE_DEBUG_TYPE_CODEVIEW)
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
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);
382 if (g_debugdirs[i].Type == IMAGE_DEBUG_TYPE_MISC)
384 IMAGE_DEBUG_DIRECTORY_MISC misc;
385 int lastpos = ftell (debugfile);
386 size_t bytes_read;
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);
395 fseek (debugfile, lastpos, SEEK_SET);
399 free (g_debugdirs);
400 return TRUE;
403 void PrintSubsectionName (int ssNum)
405 switch (ssNum)
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;
438 default:
439 printf ("<undefined> - %x", ssNum);
443 int DumpCodeViewSummary (OMFDirEntry *entries, long entrycount)
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;
450 if (entries == NULL || entrycount == 0)
451 return FALSE;
453 for (i = 0; i < entrycount; i++)
455 switch ((int)g_cvEntries[i].SubSection)
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;
490 /* This one has to be > 0
492 printf ("\nFound: %d sstModule subsections\n", modulecount);
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);
504 return TRUE;
507 int DumpCodeViewHeaders (FILE *debugfile)
509 printf ("\n============================================================\n");
510 printf (" CODEVIEW HEADERS\n");
511 printf ("============================================================\n");
513 PrintFilePos (debugfile);
515 fseek (debugfile, g_dwStartOfCodeView, SEEK_SET);
516 printf ("CodeView Directory Table begins at filepos = 0x%lx\n\n", ftell (debugfile));
518 if (!ReadCodeViewHeader (debugfile, &g_cvSig, &g_cvHeader))
519 return FALSE;
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);
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);
531 if (!ReadCodeViewDirectory (debugfile, g_cvHeader.cDir, &g_cvEntries))
532 return FALSE;
534 DumpCodeViewSummary (g_cvEntries, g_cvHeader.cDir);
536 return TRUE;
540 * Print out the info contained in the sstModule section of a single module
542 int DumpModuleInfo (int index)
544 int segnum;
546 if (g_cvEntries == NULL || g_cvModules == NULL)
547 return FALSE;
549 printf ("---------------------- sstModule ----------------------\n");
551 /* Print out some juicy module data
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]);
557 /* Print out info from module's OMFDirEntry
559 printf (" file offset = [0x%8lx]\n", g_cvEntries[index].lfo);
560 printf (" size = [0x%8lx]\n\n", g_cvEntries[index].cb);
562 for (segnum = 0; segnum < g_cvModules[index].cSeg; segnum++)
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);
570 return TRUE;
573 int DumpGlobalPubInfo (int index, FILE *debugfile)
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 */
586 if (g_cvEntries == NULL || debugfile == NULL ||
587 g_cvEntries[index].SubSection != sstGlobalPub)
588 return FALSE;
590 printf ("-------------------- sstGlobalPub --------------------\n");
592 sectionsize = g_cvEntries[index].cb;
593 printf (" offset = [0x%8lx]\n size = [0x%8lx]\n", g_cvEntries[index].lfo, sectionsize);
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));
599 #ifdef VERBOSE
600 printf (" [iMod = %d] [index = %d]\n", g_cvEntries[index].iMod, index);
601 #endif
603 printf ("\n ----- Begin Symbol Table -----\n");
604 printf (" (type) (symbol name) (offset) (len) (seg) (ind)\n");
606 /* Read the section header.
608 if (!ReadChunk (debugfile, (void*)&header, sizeof (OMFSymHash), fileoffset))
609 return FALSE;
610 PrintFilePos (debugfile);
612 /* Read the entire sstGlobalPub symbol table.
614 symbols = malloc (header.cbSymbol);
615 if (!ReadChunk (debugfile, (void*)symbols, header.cbSymbol, -1))
616 return FALSE;
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.
625 curpos = symbols;
626 while (curpos < symbols + header.cbSymbol)
628 /* Point to the next PUBSYM32 in the table.
630 sym = (PUBSYM32*)curpos;
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').
635 * FIXME: Should take into account the length...this approach hopes
636 * for a coincidental NULL after the string.
638 symlen = *(curpos + sizeof (PUBSYM32));
639 symname = curpos + sizeof (PUBSYM32) + 1;
641 /* " (type) (symbol name) (offset) (len) (seg) (typind)" */
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);
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.
650 recordlen = sym->reclen;
651 if (recordlen % 4)
652 recordlen += 4 - (recordlen % 4);
654 /* printf ("Padding length of %d bytes to %d\n", sym->reclen, recordlen); */
656 curpos += recordlen;
659 printf (" Freeing symbol memory...\n");
660 free (symbols);
662 return TRUE;
665 int DumpGlobalSymInfo (int index, FILE *debugfile)
667 if (g_cvEntries == NULL || debugfile == NULL ||
668 g_cvEntries[index].SubSection != sstGlobalSym)
669 return FALSE;
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);
677 return TRUE;
680 int DumpStaticSymInfo (int index, FILE *debugfile)
682 if (g_cvEntries == NULL || debugfile == NULL ||
683 g_cvEntries[index].SubSection != sstStaticSym)
684 return FALSE;
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);
692 return TRUE;
695 int DumpLibrariesInfo (int index, FILE *debugfile)
697 if (g_cvEntries == NULL || debugfile == NULL ||
698 g_cvEntries[index].SubSection != sstLibraries)
699 return FALSE;
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);
707 return TRUE;
710 int DumpGlobalTypesInfo (int index, FILE *debugfile)
712 if (g_cvEntries == NULL || debugfile == NULL ||
713 g_cvEntries[index].SubSection != sstGlobalTypes)
714 return FALSE;
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);
722 return TRUE;
725 int DumpSegMapInfo (int index, FILE *debugfile)
727 if (g_cvEntries == NULL || debugfile == NULL ||
728 g_cvEntries[index].SubSection != sstSegMap)
729 return FALSE;
731 printf ("-------------------- sstSegMap --------------------\n");
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);
738 return TRUE;
741 int DumpFileIndexInfo (int index, FILE *debugfile)
743 if (g_cvEntries == NULL || debugfile == NULL ||
744 g_cvEntries[index].SubSection != sstFileIndex)
745 return FALSE;
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);
753 return TRUE;
756 int DumpSrcModuleInfo (int index, FILE *debugfile)
758 int i;
759 int fileoffset;
760 BYTE *rawdata;
761 BYTE *curpos;
762 short filecount;
763 short segcount;
765 int moduledatalen;
766 int filedatalen;
767 int linedatalen;
769 if (g_cvEntries == NULL || debugfile == NULL ||
770 g_cvEntries[index].SubSection != sstSrcModule)
771 return FALSE;
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);
777 /* Where in the .DBG file should we start reading?
779 fileoffset = g_dwStartOfCodeView + g_cvEntries[index].lfo;
781 /* Allocate a chunk of memory for the entire sstSrcModule
783 rawdata = malloc (g_cvEntries[index].cb);
784 if (!rawdata)
786 printf ("ERROR - Unable to allocate %ld bytes for DumpSrcModuleInfo()\n",
787 g_cvEntries[index].cb);
788 return FALSE;
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.
795 if (!ReadChunk (debugfile, (void*)rawdata, g_cvEntries[index].cb, fileoffset))
796 return FALSE;
798 moduledatalen = PrintSrcModuleInfo (rawdata, &filecount, &segcount);
799 #ifdef VERBOSE
800 printf ("*** PrintSrcModuleInfo() returned %d\n", moduledatalen);
801 #endif
803 curpos = rawdata + moduledatalen;
804 filedatalen = PrintSrcModuleFileInfo (curpos);
805 #ifdef VERBOSE
806 printf ("*** PrintSrcModuleFileInfo() returned %d\n", filedatalen);
807 #endif
809 curpos += filedatalen;
810 for (i = 0; i < segcount; i++)
812 linedatalen = PrintSrcModuleLineInfo (curpos, i);
813 #ifdef VERBOSE
814 printf ("*** PrintSrcModuleLineInfo() returned %d\n", linedatalen);
815 #endif
817 curpos += linedatalen;
820 free (rawdata);
822 return TRUE;
825 int DumpAlignSymInfo (int index, FILE *debugfile)
827 if (g_cvEntries == NULL || debugfile == NULL ||
828 g_cvEntries[index].SubSection != sstAlignSym)
829 return FALSE;
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);
836 return TRUE;
840 * Print out the info of all related modules (e.g. sstAlignSym, sstSrcModule)
841 * for the given sub-section index (i.e. sstModule).
843 int DumpRelatedSections (int index, FILE *debugfile)
845 int i;
847 if (g_cvEntries == NULL)
848 return FALSE;
850 /* printf ("...Scanning %ld entries for matches on module #%d\n", g_cvHeader.cDir, module_num); */
852 for (i = 0; i < g_cvHeader.cDir; i++)
854 if (g_cvEntries[i].iMod != (index + 1) ||
855 g_cvEntries[i].SubSection == sstModule)
856 continue;
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.
863 switch (g_cvEntries[i].SubSection)
865 case sstAlignSym:
866 DumpAlignSymInfo (i, debugfile);
867 break;
868 case sstSrcModule:
869 DumpSrcModuleInfo (i, debugfile);
870 break;
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);
880 return TRUE;
883 int DumpMiscSections (int index, FILE *debugfile)
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.
889 if (g_cvEntries == NULL || g_cvEntries[index].iMod != 65535)
890 return FALSE;
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.
897 switch (g_cvEntries[index].SubSection)
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;
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);
928 return TRUE;
931 int DumpAllModules (FILE *debugfile)
933 int i;
935 if (g_cvHeader.cDir == 0)
937 printf ("\nStrange...found CodeView header, but no module entries\n\n");
938 return TRUE;
941 if (g_cvEntries == NULL)
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;
948 printf ("\n============================================================\n");
949 printf (" MODULE LISTING\n");
950 printf ("============================================================\n");
952 /* Seek to beginning of debug data
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
960 /* Load all OMFModuleFull data from file into memory
962 if (!ReadModuleData (debugfile, g_cvHeader.cDir, g_cvEntries,
963 &g_module_count, &g_cvModules))
965 PrintFilePos (debugfile);
966 return FALSE;
969 /* Print out bulk of info (depends on the fact that all sstModule's
970 * are packed at the beginning of the array).
972 printf ("Found %d modules\n", g_module_count);
973 for (i = 0; i < g_module_count; i++)
975 printf ("\n====================== Module #%d ======================\n", i + 1);
976 DumpModuleInfo (i);
977 DumpRelatedSections (i, debugfile);
978 printf ("=======================================================\n");
981 printf ("\n============================================================\n");
982 printf (" MISCELLANEOUS MODULES\n");
983 printf ("============================================================\n");
985 for (i = 0; i < g_cvHeader.cDir; i++)
987 DumpMiscSections (i, debugfile);
990 return TRUE;
995 * Free Global data used by OMFModuleFull structs. Can't just use free() because
996 * the 'SegInfo' and 'Name' fields also have allocated memory.
998 void FreeCVModules ()
1000 int i;
1001 OMFModuleFull *module;
1003 for (i = 0; i < g_module_count; i++)
1005 module = &(g_cvModules[i]);
1007 free (module->SegInfo);
1008 free (module->Name);
1009 free (module);
1013 int DumpCVFile (LPSTR filename)
1015 FILE *debugfile;
1017 if (strlen (filename) == 0)
1018 return (-1);
1020 debugfile = fopen (filename, "r");
1021 if (debugfile == NULL)
1023 printf ("============================================================\n");
1024 printf (" ERROR: Unable to open file [%s]\n", filename);
1025 printf ("============================================================\n");
1026 return (-1);
1029 printf ("============================================================\n");
1030 printf (" Performing bindump on file %s\n", filename);
1031 printf ("============================================================\n\n");
1033 if (!DumpFileHeaders (debugfile))
1035 printf ("============================================================\n");
1036 printf (" ERROR: Bailed out while printing file headers!\n");
1037 printf ("============================================================\n");
1038 return (-1);
1041 if (g_exe_mode)
1042 g_numsects = g_nthdr.FileHeader.NumberOfSections;
1043 else
1044 g_numsects = g_dbghdr.NumberOfSections;
1046 if (!DumpSectionHeaders (debugfile))
1048 printf ("============================================================\n");
1049 printf (" ERROR: Bailed out while printing section headers\n");
1050 printf ("============================================================\n");
1051 return (-1);
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);
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
1065 if (!DumpDebugDir (debugfile))
1067 printf ("============================================================\n");
1068 printf (" ERROR: Bailed out while printing Debug Directories\n");
1069 printf ("============================================================\n");
1070 return (-1);
1073 /* Only dump CodeView data if we know where it is!
1075 if (g_dwStartOfCodeView == 0)
1077 printf ("============================================================\n");
1078 printf (" ERROR: Unable to find CodeView info!\n");
1079 printf ("============================================================\n");
1080 return (-1);
1083 if (!DumpCodeViewHeaders (debugfile))
1085 printf ("============================================================\n");
1086 printf (" ERROR: Bailed out while printing CodeView headers\n");
1087 printf ("============================================================\n");
1088 return (-1);
1091 if (!DumpAllModules (debugfile))
1093 printf ("============================================================\n");
1094 printf (" ERROR: Bailed out while printing CodeView debug info\n");
1095 printf ("============================================================\n");
1096 return (-1);
1099 /* Clean up our trash
1101 printf ("Shutting down...\n");
1103 free (g_debugdirs);
1104 free (g_secthdrs);
1106 /* FIXME: For some reason, this call segfaults...check it out later */
1107 /* free (g_cvEntries); */
1109 /* printf ("Freeing module data..."); */
1110 /* FreeCVModules (); */
1112 return 0;
1115 int main(int argc, char *argv[])
1117 int i;
1119 if (argc == 1)
1121 printf ("Usage:\n\tcvdump FILE [FILES...]\n");
1122 return (-1);
1125 for (i = 1; i < argc; i++)
1126 DumpCVFile (argv[i]);
1127 return 0;