Added cvdump tool to dump CodeView symbol information.
[wine/gsoc-2012-control.git] / tools / cvdump / cvdump.c
blobd30018a69dd30acb1081a8855d41822fdebbee3b
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_dbg_dircount - 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 CodeView subsection%c...\n", g_dbg_dircount,
334 (g_dbg_dircount == 1) ? '.' : 's');
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 #if 0
351 else
353 int i;
355 /* Find the .rdata section.
357 for (i = 0; i < g_numsects; i++)
358 if (strcmp (g_secthdrs[i].Name, ".rdata") == 0)
359 break;
361 filepos = g_secthdrs[i].PointerToRawData;
363 #endif
365 if (!ReadDebugDir (debugfile, g_dbg_dircount, &g_debugdirs))
366 return FALSE;
368 /* Print out the contents of the directories.
370 for (i = 0; i < g_dbg_dircount; i++)
372 /* Remember start of debug data...for later
374 if (g_debugdirs[i].Type == IMAGE_DEBUG_TYPE_CODEVIEW)
376 g_dwStartOfCodeView = g_debugdirs[i].PointerToRawData;
377 #ifdef VERBOSE
378 printf ("\n[ Found start of CodeView data, at 0x%lx ]\n\n", g_dwStartOfCodeView);
379 #endif
382 printf ("\n");
383 PrintDebugDirectoryType (g_debugdirs[i].Type);
384 printf (" Characteristics = [0x%8lx]\n", g_debugdirs[i].Characteristics);
385 printf (" TimeDateStamp = [0x%8lx]\n", g_debugdirs[i].TimeDateStamp);
386 printf (" Version = %d.%d\n", g_debugdirs[i].MajorVersion, g_debugdirs[i].MinorVersion);
387 printf (" SizeOfData = [0x%8lx]\n", g_debugdirs[i].SizeOfData);
388 printf (" AddressOfRawData = [0x%8lx]\n", g_debugdirs[i].AddressOfRawData);
389 printf (" PointerToRawData = [0x%8lx]\n", g_debugdirs[i].PointerToRawData);
392 free (g_debugdirs);
393 return TRUE;
396 void PrintSubsectionName (int ssNum)
398 switch (ssNum)
400 case sstModule:
401 printf ("sstModule");
402 break;
403 case sstAlignSym:
404 printf ("sstAlignSym");
405 break;
406 case sstSrcModule:
407 printf ("sstSrcModule");
408 break;
409 case sstLibraries:
410 printf ("sstLibraries");
411 break;
412 case sstGlobalSym:
413 printf ("sstGlobalSym");
414 break;
415 case sstGlobalPub:
416 printf ("sstGlobalPub");
417 break;
418 case sstGlobalTypes:
419 printf ("sstGlobalTypes");
420 break;
421 case sstSegMap:
422 printf ("sstSegMap");
423 break;
424 case sstFileIndex:
425 printf ("sstFileIndex");
426 break;
427 case sstStaticSym:
428 printf ("sstStaticSym");
429 break;
431 default:
432 printf ("<undefined> - %x", ssNum);
436 int DumpCodeViewSummary (OMFDirEntry *entries, long entrycount)
438 int i;
439 int modulecount = 0, alignsymcount = 0, srcmodulecount = 0, librariescount = 0;
440 int globalsymcount = 0, globalpubcount = 0, globaltypescount = 0;
441 int segmapcount = 0, fileindexcount = 0, staticsymcount = 0;
443 if (entries == NULL || entrycount == 0)
444 return FALSE;
446 for (i = 0; i < entrycount; i++)
448 switch ((int)g_cvEntries[i].SubSection)
450 case sstModule:
451 modulecount++;
452 break;
453 case sstAlignSym:
454 alignsymcount++;
455 break;
456 case sstSrcModule:
457 srcmodulecount++;
458 break;
459 case sstLibraries:
460 librariescount++;
461 break;
462 case sstGlobalSym:
463 globalsymcount++;
464 break;
465 case sstGlobalPub:
466 globalpubcount++;
467 break;
468 case sstGlobalTypes:
469 globaltypescount++;
470 break;
471 case sstSegMap:
472 segmapcount++;
473 break;
474 case sstFileIndex:
475 fileindexcount++;
476 break;
477 case sstStaticSym:
478 staticsymcount++;
479 break;
483 /* This one has to be > 0
485 printf ("\nFound: %d sstModule subsections\n", modulecount);
487 if (alignsymcount > 0) printf (" %d sstAlignSym subsections\n", alignsymcount);
488 if (srcmodulecount > 0) printf (" %d sstSrcModule subsections\n", srcmodulecount);
489 if (librariescount > 0) printf (" %d sstLibraries subsections\n", librariescount);
490 if (globalsymcount > 0) printf (" %d sstGlobalSym subsections\n", globalsymcount);
491 if (globalpubcount > 0) printf (" %d sstGlobalPub subsections\n", globalpubcount);
492 if (globaltypescount > 0) printf (" %d sstGlobalTypes subsections\n", globaltypescount);
493 if (segmapcount > 0) printf (" %d sstSegMap subsections\n", segmapcount);
494 if (fileindexcount > 0) printf (" %d sstFileIndex subsections\n", fileindexcount);
495 if (staticsymcount > 0) printf (" %d sstStaticSym subsections\n", staticsymcount);
497 return TRUE;
500 int DumpCodeViewHeaders (FILE *debugfile)
502 printf ("\n============================================================\n");
503 printf (" CODEVIEW HEADERS\n");
504 printf ("============================================================\n");
506 PrintFilePos (debugfile);
508 fseek (debugfile, g_dwStartOfCodeView, SEEK_SET);
509 printf ("CodeView Directory Table begins at filepos = 0x%lx\n\n", ftell (debugfile));
511 if (!ReadCodeViewHeader (debugfile, &g_cvSig, &g_cvHeader))
512 return FALSE;
514 printf ("Signature = %.4s\n", g_cvSig.Signature);
515 printf ("filepos = [0x%8lx]\n", g_cvSig.filepos);
516 printf ("File Location of debug directories = [0x%8lx]\n\n", g_cvSig.filepos + g_dwStartOfCodeView);
518 printf ("Size of header = [0x%4x]\n", g_cvHeader.cbDirHeader);
519 printf ("Size per entry = [0x%4x]\n", g_cvHeader.cbDirEntry);
520 printf ("# of entries = [0x%8lx] (%ld)\n", g_cvHeader.cDir, g_cvHeader.cDir);
521 printf ("Offset to NextDir = [0x%8lx]\n", g_cvHeader.lfoNextDir);
522 printf ("Flags = [0x%8lx]\n", g_cvHeader.flags);
524 if (!ReadCodeViewDirectory (debugfile, g_cvHeader.cDir, &g_cvEntries))
525 return FALSE;
527 DumpCodeViewSummary (g_cvEntries, g_cvHeader.cDir);
529 return TRUE;
533 * Print out the info contained in the sstModule section of a single module
535 int DumpModuleInfo (int index)
537 int segnum;
539 if (g_cvEntries == NULL || g_cvModules == NULL)
540 return FALSE;
542 printf ("---------------------- sstModule ----------------------\n");
544 /* Print out some juicy module data
546 printf (" '%s' module holds %d segment(s) (style %c%c)\n",
547 g_cvModules[index].Name, g_cvModules[index].cSeg,
548 g_cvModules[index].Style[0], g_cvModules[index].Style[1]);
550 /* Print out info from module's OMFDirEntry
552 printf (" file offset = [0x%8lx]\n", g_cvEntries[index].lfo);
553 printf (" size = [0x%8lx]\n\n", g_cvEntries[index].cb);
555 for (segnum = 0; segnum < g_cvModules[index].cSeg; segnum++)
557 printf (" segment #%d: offset = [0x%8lx], size = [0x%8lx]\n",
558 g_cvModules[index].SegInfo[segnum].Seg,
559 g_cvModules[index].SegInfo[segnum].Off,
560 g_cvModules[index].SegInfo[segnum].cbSeg);
563 return TRUE;
566 int DumpGlobalPubInfo (int index, FILE *debugfile)
568 long fileoffset;
569 unsigned long sectionsize;
570 OMFSymHash header;
571 BYTE *symbols;
572 BYTE *curpos;
573 PUBSYM32 *sym;
574 char symlen;
575 char *symname;
576 int recordlen;
577 char nametmp[256] = { 0 }; /* Zero out */
579 if (g_cvEntries == NULL || debugfile == NULL ||
580 g_cvEntries[index].SubSection != sstGlobalPub)
581 return FALSE;
583 printf ("-------------------- sstGlobalPub --------------------\n");
585 sectionsize = g_cvEntries[index].cb;
586 printf (" offset = [0x%8lx]\n size = [0x%8lx]\n", g_cvEntries[index].lfo, sectionsize);
588 fileoffset = g_dwStartOfCodeView + g_cvEntries[index].lfo;
589 printf (" GlobalPub section starts at file offset 0x%lx\n", fileoffset);
590 printf (" Symbol table starts at 0x%lx\n", fileoffset + sizeof (OMFSymHash));
592 #ifdef VERBOSE
593 printf (" [iMod = %d] [index = %d]\n", g_cvEntries[index].iMod, index);
594 #endif
596 printf ("\n ----- Begin Symbol Table -----\n");
597 printf (" (type) (symbol name) (offset) (len) (seg) (ind)\n");
599 /* Read the section header.
601 if (!ReadChunk (debugfile, (void*)&header, sizeof (OMFSymHash), fileoffset))
602 return FALSE;
603 PrintFilePos (debugfile);
605 /* Read the entire sstGlobalPub symbol table.
607 symbols = malloc (header.cbSymbol);
608 if (!ReadChunk (debugfile, (void*)symbols, header.cbSymbol, -1))
609 return FALSE;
611 /* We don't know how many symbols are in this block of memory...only what
612 * the total size of the block is. Because the symbol's name is tacked
613 * on to the end of the PUBSYM32 struct, each symbol may take up a different
614 * # of bytes. This makes it harder to parse through the symbol table,
615 * since we won't know the exact location of the following symbol until we've
616 * already parsed the current one.
618 curpos = symbols;
619 while (curpos < symbols + header.cbSymbol)
621 /* Point to the next PUBSYM32 in the table.
623 sym = (PUBSYM32*)curpos;
625 /* Ugly hack to find the start of the (length-prefixed) name string.
626 * Must be careful about pointer math (i.e. can't use 'sym').
628 * FIXME: Should take into account the length...this approach hopes
629 * for a coincidental NULL after the string.
631 symlen = *(curpos + sizeof (PUBSYM32));
632 symname = curpos + sizeof (PUBSYM32) + 1;
634 /* " (type) (symbol name) (offset) (len) (seg) (typind)" */
636 snprintf (nametmp, symlen + 1, "%s", symname);
637 printf (" 0x%04x %-30.30s [0x%8lx] [0x%4x] %d %ld\n",
638 sym->rectyp, nametmp, sym->off, sym->reclen, sym->seg, sym->typind);
640 /* The entire record is null-padded to the nearest 4-byte
641 * boundary, so we must do a little extra math to keep things straight.
643 recordlen = sym->reclen;
644 if (recordlen % 4)
645 recordlen += 4 - (recordlen % 4);
647 /* printf ("Padding length of %d bytes to %d\n", sym->reclen, recordlen); */
649 curpos += recordlen;
652 printf (" Freeing symbol memory...\n");
653 free (symbols);
655 return TRUE;
658 int DumpGlobalSymInfo (int index, FILE *debugfile)
660 if (g_cvEntries == NULL || debugfile == NULL ||
661 g_cvEntries[index].SubSection != sstGlobalSym)
662 return FALSE;
664 /*** NOT YET IMPLEMENTED ***/
665 printf ("---Found section ");
666 PrintSubsectionName (g_cvEntries[index].SubSection);
667 printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
668 printf (" of module #%d---\n", index + 1);
670 return TRUE;
673 int DumpStaticSymInfo (int index, FILE *debugfile)
675 if (g_cvEntries == NULL || debugfile == NULL ||
676 g_cvEntries[index].SubSection != sstStaticSym)
677 return FALSE;
679 /*** NOT YET IMPLEMENTED ***/
680 printf ("---Found section ");
681 PrintSubsectionName (g_cvEntries[index].SubSection);
682 printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
683 printf (" of module #%d---\n", index + 1);
685 return TRUE;
688 int DumpLibrariesInfo (int index, FILE *debugfile)
690 if (g_cvEntries == NULL || debugfile == NULL ||
691 g_cvEntries[index].SubSection != sstLibraries)
692 return FALSE;
694 /*** NOT YET IMPLEMENTED ***/
695 printf ("---Found section ");
696 PrintSubsectionName (g_cvEntries[index].SubSection);
697 printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
698 printf (" of module #%d---\n", index + 1);
700 return TRUE;
703 int DumpGlobalTypesInfo (int index, FILE *debugfile)
705 if (g_cvEntries == NULL || debugfile == NULL ||
706 g_cvEntries[index].SubSection != sstGlobalTypes)
707 return FALSE;
709 /*** NOT YET IMPLEMENTED ***/
710 printf ("---Found section ");
711 PrintSubsectionName (g_cvEntries[index].SubSection);
712 printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
713 printf (" of module #%d---\n", index + 1);
715 return TRUE;
718 int DumpSegMapInfo (int index, FILE *debugfile)
720 if (g_cvEntries == NULL || debugfile == NULL ||
721 g_cvEntries[index].SubSection != sstSegMap)
722 return FALSE;
724 printf ("-------------------- sstSegMap --------------------\n");
726 printf ("---Found section ");
727 PrintSubsectionName (g_cvEntries[index].SubSection);
728 printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
729 printf (" of module #%d---\n", index + 1);
731 return TRUE;
734 int DumpFileIndexInfo (int index, FILE *debugfile)
736 if (g_cvEntries == NULL || debugfile == NULL ||
737 g_cvEntries[index].SubSection != sstFileIndex)
738 return FALSE;
740 /*** NOT YET IMPLEMENTED ***/
741 printf ("---Found section ");
742 PrintSubsectionName (g_cvEntries[index].SubSection);
743 printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
744 printf (" of module #%d---\n", index + 1);
746 return TRUE;
749 int DumpSrcModuleInfo (int index, FILE *debugfile)
751 int i;
752 int fileoffset;
753 BYTE *rawdata;
754 BYTE *curpos;
755 short filecount;
756 short segcount;
758 int moduledatalen;
759 int filedatalen;
760 int linedatalen;
762 if (g_cvEntries == NULL || debugfile == NULL ||
763 g_cvEntries[index].SubSection != sstSrcModule)
764 return FALSE;
766 printf ("--------------------- sstSrcModule --------------------\n");
767 printf (" file offset = [0x%8lx]\n", g_dwStartOfCodeView + g_cvEntries[index].lfo);
768 printf (" size = [0x%8lx]\n", g_cvEntries[index].cb);
770 /* Where in the .DBG file should we start reading?
772 fileoffset = g_dwStartOfCodeView + g_cvEntries[index].lfo;
774 /* Allocate a chunk of memory for the entire sstSrcModule
776 rawdata = malloc (g_cvEntries[index].cb);
777 if (!rawdata)
779 printf ("ERROR - Unable to allocate %ld bytes for DumpSrcModuleInfo()\n",
780 g_cvEntries[index].cb);
781 return FALSE;
784 /* Read in the entire sstSrcModule from the .DBG file. We'll process it
785 * bit by bit, but passing memory pointers into the various functions in
786 * cvprint.c.
788 if (!ReadChunk (debugfile, (void*)rawdata, g_cvEntries[index].cb, fileoffset))
789 return FALSE;
791 moduledatalen = PrintSrcModuleInfo (rawdata, &filecount, &segcount);
792 #ifdef VERBOSE
793 printf ("*** PrintSrcModuleInfo() returned %d\n", moduledatalen);
794 #endif
796 curpos = rawdata + moduledatalen;
797 filedatalen = PrintSrcModuleFileInfo (curpos);
798 #ifdef VERBOSE
799 printf ("*** PrintSrcModuleFileInfo() returned %d\n", filedatalen);
800 #endif
802 curpos += filedatalen;
803 for (i = 0; i < segcount; i++)
805 linedatalen = PrintSrcModuleLineInfo (curpos, i);
806 #ifdef VERBOSE
807 printf ("*** PrintSrcModuleLineInfo() returned %d\n", linedatalen);
808 #endif
810 curpos += linedatalen;
813 free (rawdata);
815 return TRUE;
818 int DumpAlignSymInfo (int index, FILE *debugfile)
820 if (g_cvEntries == NULL || debugfile == NULL ||
821 g_cvEntries[index].SubSection != sstAlignSym)
822 return FALSE;
824 /*** NOT YET IMPLEMENTED ***/
825 printf ("--------------------- sstAlignSym ---------------------\n");
826 printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
827 printf (" of module #%d\n", index + 1);
829 return TRUE;
833 * Print out the info of all related modules (e.g. sstAlignSym, sstSrcModule)
834 * for the desired sub-section (i.e. sstModule).
836 int DumpRelatedSections (int index, FILE *debugfile)
838 int i;
840 if (g_cvEntries == NULL)
841 return FALSE;
843 /* printf ("...Scanning %ld entries for matches on module #%d\n", g_cvHeader.cDir, module_num); */
845 for (i = 0; i < g_cvHeader.cDir; i++)
847 if (g_cvEntries[i].iMod != (index + 1) ||
848 g_cvEntries[i].SubSection == sstModule)
849 continue;
851 /* Pass in index of entry in g_cvEntries array to individual sub-section
852 * dumping functions. Each function will figure out where in the file its
853 * sub-section lies and seek the file position itself, before parsing out
854 * its data.
856 switch (g_cvEntries[i].SubSection)
858 case sstAlignSym:
859 DumpAlignSymInfo (i, debugfile);
860 break;
861 case sstSrcModule:
862 DumpSrcModuleInfo (i, debugfile);
863 break;
865 default:
866 printf ("---Found section ");
867 PrintSubsectionName (g_cvEntries[i].SubSection);
868 printf (" [iMod = %d] [i = %d]", g_cvEntries[i].iMod, i);
869 printf (" of module #%d---\n", index + 1);
873 return TRUE;
876 int DumpMiscSections (int index, FILE *debugfile)
878 /* The module # 65535 is reserved for all free-standing modules, not
879 * associated with a sstModule sub-section. These are the only sections
880 * we wish to process here.
882 if (g_cvEntries == NULL || g_cvEntries[index].iMod != 65535)
883 return FALSE;
885 /* Pass in index of entry in g_cvEntries array to individual sub-section
886 * dumping functions. Each function will figure out where in the file its
887 * sub-section lies and seek the file position itself, before parsing out
888 * its data.
890 switch (g_cvEntries[index].SubSection)
892 case sstGlobalPub:
893 DumpGlobalPubInfo (index, debugfile);
894 break;
895 case sstGlobalSym:
896 DumpGlobalSymInfo (index, debugfile);
897 break;
898 case sstStaticSym:
899 DumpStaticSymInfo (index, debugfile);
900 break;
901 case sstLibraries:
902 DumpLibrariesInfo (index, debugfile);
903 break;
904 case sstGlobalTypes:
905 DumpGlobalTypesInfo (index, debugfile);
906 break;
907 case sstSegMap:
908 DumpSegMapInfo (index, debugfile);
909 break;
910 case sstFileIndex:
911 DumpFileIndexInfo (index, debugfile);
912 break;
914 default:
915 printf ("---Found section ");
916 PrintSubsectionName (g_cvEntries[index].SubSection);
917 printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
918 printf (" of module #%d---\n", index + 1);
921 return TRUE;
924 int DumpAllModules (FILE *debugfile)
926 int i;
928 if (g_cvHeader.cDir == 0 || g_cvEntries == NULL)
930 printf ("ERROR: Bailing out of Module Data Dump\n");
931 printf ("%ld %p\n", g_cvHeader.cDir, g_cvEntries);
932 return FALSE;
935 printf ("\n============================================================\n");
936 printf (" MODULE LISTING\n");
937 printf ("============================================================\n");
939 /* Seek to beginning of debug data
941 fseek (debugfile, g_dwStartOfCodeView + g_cvEntries[0].lfo, SEEK_SET);
942 #ifdef VERBOSE
943 printf ("[ Moving to filepos = 0x%lx to read in CodeView module info ]\n",
944 ftell (debugfile));
945 #endif
947 /* Load all OMFModuleFull data from file into memory
949 if (!ReadModuleData (debugfile, g_cvHeader.cDir, g_cvEntries,
950 &g_module_count, &g_cvModules))
952 PrintFilePos (debugfile);
953 return FALSE;
956 /* Print out bulk of info (depends on the fact that all sstModule's
957 * are packed at the beginning of the array).
959 printf ("Found %d modules\n", g_module_count);
960 for (i = 0; i < g_module_count; i++)
962 printf ("\n====================== Module #%d ======================\n", i + 1);
963 DumpModuleInfo (i);
964 DumpRelatedSections (i, debugfile);
965 printf ("=======================================================\n");
968 printf ("\n============================================================\n");
969 printf (" MISCELLANEOUS MODULES\n");
970 printf ("============================================================\n");
972 for (i = 0; i < g_cvHeader.cDir; i++)
974 DumpMiscSections (i, debugfile);
977 return TRUE;
982 * Free Global data used by OMFModuleFull structs. Can't just use free() because
983 * the 'SegInfo' and 'Name' fields also have allocated memory.
985 void FreeCVModules ()
987 int i;
988 OMFModuleFull *module;
990 for (i = 0; i < g_module_count; i++)
992 module = &(g_cvModules[i]);
994 free (module->SegInfo);
995 free (module->Name);
996 free (module);
1000 int DumpCVFile (LPSTR filename)
1002 FILE *debugfile;
1004 if (strlen (filename) == 0)
1005 return (-1);
1007 debugfile = fopen (filename, "r");
1008 if (debugfile == NULL)
1010 printf ("============================================================\n");
1011 printf (" ERROR: Unable to open file [%s]\n", filename);
1012 printf ("============================================================\n");
1013 return (-1);
1016 printf ("============================================================\n");
1017 printf (" Performing bindump on file %s\n", filename);
1018 printf ("============================================================\n\n");
1020 if (!DumpFileHeaders (debugfile))
1022 printf ("============================================================\n");
1023 printf (" ERROR: Bailed out while printing file headers!\n");
1024 printf ("============================================================\n");
1025 return (-1);
1028 if (g_exe_mode)
1029 g_numsects = g_nthdr.FileHeader.NumberOfSections;
1030 else
1031 g_numsects = g_dbghdr.NumberOfSections;
1033 if (!DumpSectionHeaders (debugfile))
1035 printf ("============================================================\n");
1036 printf (" ERROR: Bailed out while printing section headers\n");
1037 printf ("============================================================\n");
1038 return (-1);
1041 if (g_exe_mode)
1042 g_dbg_dircount = g_nthdr.OptionalHeader.DataDirectory[IMAGE_FILE_DEBUG_DIRECTORY].Size /
1043 sizeof (IMAGE_DEBUG_DIRECTORY);
1044 else
1045 g_dbg_dircount = g_dbghdr.DebugDirectorySize / sizeof (IMAGE_DEBUG_DIRECTORY);
1047 #ifdef VERBOSE
1048 printf ("\n[ Found %d debug directories in %s file. ]\n", g_dbg_dircount,
1049 g_exe_mode ? "PE" : "DBG");
1050 #endif
1052 if (!DumpDebugDir (debugfile))
1054 printf ("============================================================\n");
1055 printf (" ERROR: Bailed out while printing Debug Directories\n");
1056 printf ("============================================================\n");
1057 return (-1);
1060 /* Only dump CodeView data if we know where it is!
1062 if (g_dwStartOfCodeView == 0)
1064 printf ("============================================================\n");
1065 printf (" ERROR: Unable to find CodeView info!\n");
1066 printf ("============================================================\n");
1067 return (-1);
1070 if (!DumpCodeViewHeaders (debugfile))
1072 printf ("============================================================\n");
1073 printf (" ERROR: Bailed out while printing CodeView headers\n");
1074 printf ("============================================================\n");
1075 return (-1);
1078 if (!DumpAllModules (debugfile))
1080 printf ("============================================================\n");
1081 printf (" ERROR: Bailed out while printing CodeView debug info\n");
1082 printf ("============================================================\n");
1083 return (-1);
1086 /* Clean up our trash
1088 printf ("Shutting down...\n");
1090 free (g_debugdirs);
1091 free (g_secthdrs);
1093 /* FIXME: For some reason, this call segfaults...check it out later */
1094 /* free (g_cvEntries); */
1096 /* printf ("Freeing module data..."); */
1097 /* FreeCVModules (); */
1099 return 0;
1102 int main(int argc, char *argv[])
1104 int i;
1106 if (argc == 1)
1108 printf ("Usage:\n\tcvdump FILE [FILES...]\n");
1109 return (-1);
1112 for (i = 1; i < argc; i++)
1113 DumpCVFile (argv[i]);
1114 return 0;