blob: 0035dde5bd98c72f4d39a8b528b2edf5b14744a4 [file] [log] [blame]
/*
* CVDump - Parses through a Visual Studio .DBG file in CodeView 4 format
* and dumps the info to STDOUT in a human-readable format
*
* Copyright 2000 John R. Sheets
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include "cvdump.h"
DWORD g_dwStartOfCodeView = 0;
int g_exe_mode = TRUE;
IMAGE_DOS_HEADER g_doshdr;
IMAGE_SEPARATE_DEBUG_HEADER g_dbghdr;
IMAGE_NT_HEADERS g_nthdr;
IMAGE_SECTION_HEADER *g_secthdrs = NULL;
int g_numsects;
int g_dbg_dircount;
IMAGE_DEBUG_DIRECTORY *g_debugdirs = NULL;
OMFSignature g_cvSig;
OMFDirHeader g_cvHeader;
OMFDirEntry *g_cvEntries = NULL;
int g_module_count = 0;
OMFModuleFull *g_cvModules = NULL;
void PrintFilePos (FILE *file)
{
#ifdef VERBOSE
printf (" *** Current file position = %lx\n", ftell (file));
#endif
}
/* Calculate the file offset, based on the RVA.
*/
DWORD GetOffsetFromRVA (DWORD rva)
{
int i;
DWORD offset;
DWORD filepos;
DWORD sectbegin;
/* Assumes all RVA's in the section headers are sorted in increasing
* order (which should be the case).
*/
for (i = g_numsects - 1; i >= 0; i--)
{
sectbegin = g_secthdrs[i].VirtualAddress;
#ifdef VERBOSE
printf ("iter = %d, rva = 0x%lx, sectbegin = 0x%lx\n", i, rva, sectbegin);
#endif
if (rva >= sectbegin)
break;
}
/* Calculate the difference between the section's RVA and file position.
*/
offset = g_secthdrs[i].VirtualAddress - g_secthdrs[i].PointerToRawData;
/* Calculate the actual file position.
*/
filepos = rva - offset;
#ifdef VERBOSE
printf (">>> Found RVA 0x%lx in section %d, at 0x%lx (section offset = 0x%lx)\n",
rva, i, filepos, offset);
#endif
return filepos;
}
int DumpFileHeaders (FILE *debugfile)
{
CVHeaderType hdrtype;
hdrtype = GetHeaderType (debugfile);
if (hdrtype == CV_DOS)
{
if (!ReadDOSFileHeader (debugfile, &g_doshdr))
return FALSE;
printf ("\n============================================================\n");
printf (" DOS FILE HEADER\n");
printf ("============================================================\n");
printf ("Magic Signature = [0x%4x]\n", g_doshdr.e_magic);
printf ("e_cblp = [0x%4x]\n", g_doshdr.e_cblp);
printf ("e_cp = [0x%4x]\n", g_doshdr.e_cp);
printf ("e_cric = [0x%4x]\n", g_doshdr.e_crlc);
printf ("e_cparhdr = [0x%4x]\n", g_doshdr.e_cparhdr);
printf ("e_minalloc = [0x%4x]\n", g_doshdr.e_minalloc);
printf ("e_maxalloc = [0x%4x]\n", g_doshdr.e_maxalloc);
printf ("e_ss = [0x%4x]\n", g_doshdr.e_ss);
printf ("e_sp = [0x%4x]\n", g_doshdr.e_sp);
printf ("e_csum = [0x%4x]\n", g_doshdr.e_csum);
printf ("e_ip = [0x%4x]\n", g_doshdr.e_ip);
printf ("e_cs = [0x%4x]\n", g_doshdr.e_cs);
printf ("e_lfarlc = [0x%4x]\n", g_doshdr.e_lfarlc);
printf ("e_ovno = [0x%4x]\n", g_doshdr.e_ovno);
printf ("e_res = [0x%4x ...]\n", g_doshdr.e_res[0]); /* worth FIXME? */
printf ("e_oemid = [0x%4x]\n", g_doshdr.e_oemid);
printf ("e_oeminfo = [0x%4x]\n", g_doshdr.e_oeminfo);
printf ("e_res2 = [0x%4x ...]\n", g_doshdr.e_res2[0]); /* worth FIXME? */
printf ("e_lfanew = [0x%8lx]\n", g_doshdr.e_lfanew);
/* Roll forward to next type */
hdrtype = GetHeaderType (debugfile);
}
if (hdrtype == CV_NT)
{
if (!ReadPEFileHeader (debugfile, &g_nthdr))
return FALSE;
printf ("\n============================================================\n");
printf (" PE EXECUTABLE FILE HEADER\n");
printf ("============================================================\n");
printf ("Signature = [0x%8lx]\n", g_nthdr.Signature);
printf ("Machine = [0x%4x]\n", g_nthdr.FileHeader.Machine);
printf ("# of Sections = [0x%4x]\n", g_nthdr.FileHeader.NumberOfSections);
printf ("Time/Date Stamp = [0x%08lx]\n", g_nthdr.FileHeader.TimeDateStamp);
printf ("Pointer to Symbol Table = [0x%8lx]\n", g_nthdr.FileHeader.PointerToSymbolTable);
printf ("# of Symbols = [0x%8lx]\n", g_nthdr.FileHeader.NumberOfSymbols);
printf ("Size of Opt. Hdr = [0x%4x]\n", g_nthdr.FileHeader.SizeOfOptionalHeader);
printf ("Characteristics = [0x%4x]\n", g_nthdr.FileHeader.Characteristics);
printf ("\n============================================================\n");
printf (" NT FILE HEADER\n");
printf ("============================================================\n");
printf ("Magic = [0x%4x]\n", g_nthdr.OptionalHeader.Magic);
printf ("Linker Version = %d.%d\n", g_nthdr.OptionalHeader.MajorLinkerVersion,
g_nthdr.OptionalHeader.MinorLinkerVersion);
printf ("Size of Code = [0x%8lx]\n", g_nthdr.OptionalHeader.SizeOfCode);
printf ("Init. Data = [0x%8lx]\n", g_nthdr.OptionalHeader.SizeOfInitializedData);
printf ("Uninit. Data = [0x%8lx]\n", g_nthdr.OptionalHeader.SizeOfUninitializedData);
printf ("Entry Point = [0x%8lx]\n", g_nthdr.OptionalHeader.AddressOfEntryPoint);
printf ("Base of Code = [0x%8lx]\n", g_nthdr.OptionalHeader.BaseOfCode);
printf ("Base of Data = [0x%8lx]\n", g_nthdr.OptionalHeader.BaseOfData);
printf ("\n============================================================\n");
printf (" NT OPTIONAL FILE HEADER\n");
printf ("============================================================\n");
printf ("Image Base = [0x%8lx]\n", g_nthdr.OptionalHeader.ImageBase);
printf ("Section Alignment = [0x%8lx]\n", g_nthdr.OptionalHeader.SectionAlignment);
printf ("File Alignment = [0x%8lx]\n", g_nthdr.OptionalHeader.FileAlignment);
printf ("OS Version = %d.%d\n", g_nthdr.OptionalHeader.MajorOperatingSystemVersion,
g_nthdr.OptionalHeader.MinorOperatingSystemVersion);
printf ("Image Version = %d.%d\n", g_nthdr.OptionalHeader.MajorImageVersion,
g_nthdr.OptionalHeader.MinorImageVersion);
printf ("Subsystem Version = %d.%d\n", g_nthdr.OptionalHeader.MajorSubsystemVersion,
g_nthdr.OptionalHeader.MinorSubsystemVersion);
printf ("Size of Image = [0x%8lx]\n", g_nthdr.OptionalHeader.SizeOfImage);
printf ("Size of Headers = [0x%8lx]\n", g_nthdr.OptionalHeader.SizeOfHeaders);
printf ("Checksum = [0x%8lx]\n", g_nthdr.OptionalHeader.CheckSum);
printf ("Subsystem = [0x%4x]\n", g_nthdr.OptionalHeader.Subsystem);
printf ("DLL Characteristics = [0x%4x]\n", g_nthdr.OptionalHeader.DllCharacteristics);
printf ("Size of Stack Reserve = [0x%8lx]\n", g_nthdr.OptionalHeader.SizeOfStackReserve);
printf ("Size of Stack Commit = [0x%8lx]\n", g_nthdr.OptionalHeader.SizeOfStackCommit);
printf ("Size of Heap Reserve = [0x%8lx]\n", g_nthdr.OptionalHeader.SizeOfHeapReserve);
printf ("Size of Heap Commit = [0x%8lx]\n", g_nthdr.OptionalHeader.SizeOfHeapCommit);
printf ("Loader Flags = [0x%8lx]\n", g_nthdr.OptionalHeader.LoaderFlags);
printf ("# of RVA = [0x%8lx]\n", g_nthdr.OptionalHeader.NumberOfRvaAndSizes);
printf ("\n============================================================\n");
printf (" RVA (RELATIVE VIRTUAL ADDRESS) TABLE\n");
printf ("============================================================\n");
printf ("NAME RVA SIZE\n");
printf ("Export [0x%8lx] [0x%8lx]\n",
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size);
printf ("Import [0x%8lx] [0x%8lx]\n",
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size);
printf ("Resource [0x%8lx] [0x%8lx]\n",
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress,
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size);
printf ("Exception [0x%8lx] [0x%8lx]\n",
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress,
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size);
printf ("Security [0x%8lx] [0x%8lx]\n",
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress,
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size);
printf ("Base Relocations [0x%8lx] [0x%8lx]\n",
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);
printf ("Debug [0x%8lx] [0x%8lx]\n",
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress,
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size);
printf ("Description [0x%8lx] [0x%8lx]\n",
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COPYRIGHT].VirtualAddress,
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COPYRIGHT].Size);
printf ("Special [0x%8lx] [0x%8lx]\n",
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR].VirtualAddress,
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR].Size);
printf ("Thread (TLS) [0x%8lx] [0x%8lx]\n",
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress,
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size);
printf ("Load Config [0x%8lx] [0x%8lx]\n",
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress,
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size);
printf ("Bound Import [0x%8lx] [0x%8lx]\n",
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress,
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size);
printf ("Import Addr Tbl [0x%8lx] [0x%8lx]\n",
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress,
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size);
printf ("Delay Import [0x%8lx] [0x%8lx]\n",
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress,
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size);
printf ("COM Descriptor [0x%8lx] [0x%8lx]\n",
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress,
g_nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size);
}
else if (hdrtype == CV_DBG)
{
if (!ReadDBGFileHeader (debugfile, &g_dbghdr))
return FALSE;
g_exe_mode = FALSE;
#ifdef VERBOSE
printf ("[ Found DBG header...file is not a PE executable. ]\n");
#endif
printf ("\n============================================================\n");
printf (" STANDALONE DEBUG FILE HEADER (.DBG)\n");
printf ("============================================================\n");
printf ("Signature = [0x%4x]\n", g_dbghdr.Signature);
printf ("Flags = [0x%4x]\n", g_dbghdr.Flags);
printf ("Machine = [0x%4x]\n", g_dbghdr.Machine);
printf ("Characteristics = [0x%4x]\n", g_dbghdr.Characteristics);
printf ("TimeDateStamp = [0x%8lx]\n", g_dbghdr.TimeDateStamp);
printf ("CheckSum = [0x%8lx]\n", g_dbghdr.CheckSum);
printf ("ImageBase = [0x%8lx]\n", g_dbghdr.ImageBase);
printf ("SizeOfImage = [0x%8lx]\n", g_dbghdr.SizeOfImage);
printf ("NumberOfSections = [0x%8lx]\n", g_dbghdr.NumberOfSections);
printf ("ExportedNamesSize = [0x%8lx]\n", g_dbghdr.ExportedNamesSize);
printf ("DebugDirectorySize = [0x%8lx]\n", g_dbghdr.DebugDirectorySize);
return TRUE;
}
return TRUE;
}
int DumpSectionHeaders (FILE *debugfile)
{
int i;
printf ("\n============================================================\n");
printf (" COFF SECTION HEADERS\n");
printf ("============================================================\n");
PrintFilePos (debugfile);
if (!ReadSectionHeaders (debugfile, g_numsects, &g_secthdrs))
return FALSE;
/* Print out a quick list of section names
*/
for (i = 0; i < g_numsects; i++)
printf ("%8s (0x%08lx bytes long, starts at 0x%08lx)\n", g_secthdrs[i].Name,
g_secthdrs[i].SizeOfRawData, g_secthdrs[i].PointerToRawData);
/* Print out bulk of info
*/
for (i = 0; i < g_numsects; i++)
{
printf ("\nContents of IMAGE_SECTION_HEADER %s:\n\n", g_secthdrs[i].Name);
printf ("Name = %s\n", g_secthdrs[i].Name);
printf ("VirtualSize = [0x%8lx]\n", g_secthdrs[i].Misc.VirtualSize);
printf ("VirtualAddress = [0x%8lx]\n", g_secthdrs[i].VirtualAddress);
printf ("SizeOfRawData = [0x%8lx]\n", g_secthdrs[i].SizeOfRawData);
printf ("PointerToRawData = [0x%8lx]\n", g_secthdrs[i].PointerToRawData);
printf ("PointerToRelocations = [0x%8lx]\n", g_secthdrs[i].PointerToRelocations);
printf ("PointerToLinenumbers = [0x%8lx]\n", g_secthdrs[i].PointerToLinenumbers);
printf ("NumberOfRelocations = [0x%4x]\n", g_secthdrs[i].NumberOfRelocations);
printf ("NumberOfLinenumbers = [0x%4x]\n", g_secthdrs[i].NumberOfLinenumbers);
printf ("Characteristics = [0x%8lx]\n", g_secthdrs[i].Characteristics);
}
return TRUE;
}
void PrintDebugDirectoryType (DWORD type)
{
switch (type)
{
case IMAGE_DEBUG_TYPE_UNKNOWN:
printf ("<Unknown Directory> - %ld\n", type);
break;
case IMAGE_DEBUG_TYPE_COFF:
printf ("COFF Directory:\n");
break;
case IMAGE_DEBUG_TYPE_CODEVIEW:
printf ("CodeView Directory:\n");
break;
case IMAGE_DEBUG_TYPE_FPO:
printf ("FPO Directory:\n");
break;
case IMAGE_DEBUG_TYPE_MISC:
printf ("MISC Directory:\n");
break;
default:
printf ("<Undefined Directory> - %ld\n", type);
}
}
int DumpDebugDir (FILE *debugfile)
{
int i;
int filepos;
printf ("\n============================================================\n");
printf (" CODEVIEW DEBUG DIRECTORY\n");
printf ("============================================================\n");
PrintFilePos (debugfile);
printf ("Found %d Debug director%s...\n", g_dbg_dircount,
(g_dbg_dircount == 1) ? "y" : "ies");
if (g_dbg_dircount == 0)
return FALSE;
/* Find the location of the debug directory table.
*/
if (g_exe_mode)
{
/* Convert the RVA to a file offset.
*/
filepos = GetOffsetFromRVA (g_nthdr.OptionalHeader.DataDirectory[IMAGE_FILE_DEBUG_DIRECTORY].VirtualAddress);
fseek (debugfile, filepos, SEEK_SET);
PrintFilePos (debugfile);
}
else
{
fseek( debugfile, g_dbghdr.ExportedNamesSize, SEEK_CUR);
PrintFilePos (debugfile);
}
if (!ReadDebugDir (debugfile, g_dbg_dircount, &g_debugdirs))
return FALSE;
/* Print out the contents of the directories.
*/
for (i = 0; i < g_dbg_dircount; i++)
{
/* Remember start of debug data...for later
*/
if (g_debugdirs[i].Type == IMAGE_DEBUG_TYPE_CODEVIEW)
{
g_dwStartOfCodeView = g_debugdirs[i].PointerToRawData;
#ifdef VERBOSE
printf ("\n[ Found start of CodeView data, at 0x%lx ]\n\n", g_dwStartOfCodeView);
#endif
}
printf ("\n");
PrintDebugDirectoryType (g_debugdirs[i].Type);
printf (" Characteristics = [0x%8lx]\n", g_debugdirs[i].Characteristics);
printf (" TimeDateStamp = [0x%8lx]\n", g_debugdirs[i].TimeDateStamp);
printf (" Version = %d.%d\n", g_debugdirs[i].MajorVersion, g_debugdirs[i].MinorVersion);
printf (" SizeOfData = [0x%8lx]\n", g_debugdirs[i].SizeOfData);
printf (" AddressOfRawData = [0x%8lx]\n", g_debugdirs[i].AddressOfRawData);
printf (" PointerToRawData = [0x%8lx]\n", g_debugdirs[i].PointerToRawData);
if (g_debugdirs[i].Type == IMAGE_DEBUG_TYPE_MISC)
{
IMAGE_DEBUG_DIRECTORY_MISC misc;
int lastpos = ftell (debugfile);
size_t bytes_read;
/* FIXME: Not sure exactly what the contents are supposed to be. */
fseek (debugfile, g_debugdirs[i].PointerToRawData, SEEK_SET);
bytes_read = fread (&misc, 1, sizeof (IMAGE_DEBUG_DIRECTORY_MISC), debugfile);
printf ("\n [0x%8lx]\n [0x%8lx]\n [0x%4x]\n [0x%4x]\n '%s'\n",
misc.unknown1, misc.SizeOfData, misc.unknown2,
misc.unknown3, misc.Name);
fseek (debugfile, lastpos, SEEK_SET);
}
}
free (g_debugdirs);
return TRUE;
}
void PrintSubsectionName (int ssNum)
{
switch (ssNum)
{
case sstModule:
printf ("sstModule");
break;
case sstAlignSym:
printf ("sstAlignSym");
break;
case sstSrcModule:
printf ("sstSrcModule");
break;
case sstLibraries:
printf ("sstLibraries");
break;
case sstGlobalSym:
printf ("sstGlobalSym");
break;
case sstGlobalPub:
printf ("sstGlobalPub");
break;
case sstGlobalTypes:
printf ("sstGlobalTypes");
break;
case sstSegMap:
printf ("sstSegMap");
break;
case sstFileIndex:
printf ("sstFileIndex");
break;
case sstStaticSym:
printf ("sstStaticSym");
break;
default:
printf ("<undefined> - %x", ssNum);
}
}
int DumpCodeViewSummary (OMFDirEntry *entries, long entrycount)
{
int i;
int modulecount = 0, alignsymcount = 0, srcmodulecount = 0, librariescount = 0;
int globalsymcount = 0, globalpubcount = 0, globaltypescount = 0;
int segmapcount = 0, fileindexcount = 0, staticsymcount = 0;
if (entries == NULL || entrycount == 0)
return FALSE;
for (i = 0; i < entrycount; i++)
{
switch ((int)g_cvEntries[i].SubSection)
{
case sstModule:
modulecount++;
break;
case sstAlignSym:
alignsymcount++;
break;
case sstSrcModule:
srcmodulecount++;
break;
case sstLibraries:
librariescount++;
break;
case sstGlobalSym:
globalsymcount++;
break;
case sstGlobalPub:
globalpubcount++;
break;
case sstGlobalTypes:
globaltypescount++;
break;
case sstSegMap:
segmapcount++;
break;
case sstFileIndex:
fileindexcount++;
break;
case sstStaticSym:
staticsymcount++;
break;
}
}
/* This one has to be > 0
*/
printf ("\nFound: %d sstModule subsections\n", modulecount);
if (alignsymcount > 0) printf (" %d sstAlignSym subsections\n", alignsymcount);
if (srcmodulecount > 0) printf (" %d sstSrcModule subsections\n", srcmodulecount);
if (librariescount > 0) printf (" %d sstLibraries subsections\n", librariescount);
if (globalsymcount > 0) printf (" %d sstGlobalSym subsections\n", globalsymcount);
if (globalpubcount > 0) printf (" %d sstGlobalPub subsections\n", globalpubcount);
if (globaltypescount > 0) printf (" %d sstGlobalTypes subsections\n", globaltypescount);
if (segmapcount > 0) printf (" %d sstSegMap subsections\n", segmapcount);
if (fileindexcount > 0) printf (" %d sstFileIndex subsections\n", fileindexcount);
if (staticsymcount > 0) printf (" %d sstStaticSym subsections\n", staticsymcount);
return TRUE;
}
int DumpCodeViewHeaders (FILE *debugfile)
{
printf ("\n============================================================\n");
printf (" CODEVIEW HEADERS\n");
printf ("============================================================\n");
PrintFilePos (debugfile);
fseek (debugfile, g_dwStartOfCodeView, SEEK_SET);
printf ("CodeView Directory Table begins at filepos = 0x%lx\n\n", ftell (debugfile));
if (!ReadCodeViewHeader (debugfile, &g_cvSig, &g_cvHeader))
return FALSE;
printf ("Signature = %.4s\n", g_cvSig.Signature);
printf ("filepos = [0x%8lx]\n", g_cvSig.filepos);
printf ("File Location of debug directories = [0x%8lx]\n\n", g_cvSig.filepos + g_dwStartOfCodeView);
printf ("Size of header = [0x%4x]\n", g_cvHeader.cbDirHeader);
printf ("Size per entry = [0x%4x]\n", g_cvHeader.cbDirEntry);
printf ("# of entries = [0x%8lx] (%ld)\n", g_cvHeader.cDir, g_cvHeader.cDir);
printf ("Offset to NextDir = [0x%8lx]\n", g_cvHeader.lfoNextDir);
printf ("Flags = [0x%8lx]\n", g_cvHeader.flags);
if (!ReadCodeViewDirectory (debugfile, g_cvHeader.cDir, &g_cvEntries))
return FALSE;
DumpCodeViewSummary (g_cvEntries, g_cvHeader.cDir);
return TRUE;
}
/*
* Print out the info contained in the sstModule section of a single module
*/
int DumpModuleInfo (int index)
{
int segnum;
if (g_cvEntries == NULL || g_cvModules == NULL)
return FALSE;
printf ("---------------------- sstModule ----------------------\n");
/* Print out some juicy module data
*/
printf (" '%s' module holds %d segment(s) (style %c%c)\n",
g_cvModules[index].Name, g_cvModules[index].cSeg,
g_cvModules[index].Style[0], g_cvModules[index].Style[1]);
/* Print out info from module's OMFDirEntry
*/
printf (" file offset = [0x%8lx]\n", g_cvEntries[index].lfo);
printf (" size = [0x%8lx]\n\n", g_cvEntries[index].cb);
for (segnum = 0; segnum < g_cvModules[index].cSeg; segnum++)
{
printf (" segment #%d: offset = [0x%8lx], size = [0x%8lx]\n",
g_cvModules[index].SegInfo[segnum].Seg,
g_cvModules[index].SegInfo[segnum].Off,
g_cvModules[index].SegInfo[segnum].cbSeg);
}
return TRUE;
}
int DumpGlobalPubInfo (int index, FILE *debugfile)
{
long fileoffset;
unsigned long sectionsize;
OMFSymHash header;
BYTE *symbols;
BYTE *curpos;
PUBSYM32 *sym;
char symlen;
char *symname;
int recordlen;
char nametmp[256] = { 0 }; /* Zero out */
if (g_cvEntries == NULL || debugfile == NULL ||
g_cvEntries[index].SubSection != sstGlobalPub)
return FALSE;
printf ("-------------------- sstGlobalPub --------------------\n");
sectionsize = g_cvEntries[index].cb;
printf (" offset = [0x%8lx]\n size = [0x%8lx]\n", g_cvEntries[index].lfo, sectionsize);
fileoffset = g_dwStartOfCodeView + g_cvEntries[index].lfo;
printf (" GlobalPub section starts at file offset 0x%lx\n", fileoffset);
printf (" Symbol table starts at 0x%lx\n", fileoffset + sizeof (OMFSymHash));
#ifdef VERBOSE
printf (" [iMod = %d] [index = %d]\n", g_cvEntries[index].iMod, index);
#endif
printf ("\n ----- Begin Symbol Table -----\n");
printf (" (type) (symbol name) (offset) (len) (seg) (ind)\n");
/* Read the section header.
*/
if (!ReadChunk (debugfile, (void*)&header, sizeof (OMFSymHash), fileoffset))
return FALSE;
PrintFilePos (debugfile);
/* Read the entire sstGlobalPub symbol table.
*/
symbols = malloc (header.cbSymbol);
if (!ReadChunk (debugfile, (void*)symbols, header.cbSymbol, -1))
return FALSE;
/* We don't know how many symbols are in this block of memory...only what
* the total size of the block is. Because the symbol's name is tacked
* on to the end of the PUBSYM32 struct, each symbol may take up a different
* # of bytes. This makes it harder to parse through the symbol table,
* since we won't know the exact location of the following symbol until we've
* already parsed the current one.
*/
curpos = symbols;
while (curpos < symbols + header.cbSymbol)
{
/* Point to the next PUBSYM32 in the table.
*/
sym = (PUBSYM32*)curpos;
/* Ugly hack to find the start of the (length-prefixed) name string.
* Must be careful about pointer math (i.e. can't use 'sym').
*
* FIXME: Should take into account the length...this approach hopes
* for a coincidental NULL after the string.
*/
symlen = *(curpos + sizeof (PUBSYM32));
symname = curpos + sizeof (PUBSYM32) + 1;
/* " (type) (symbol name) (offset) (len) (seg) (typind)" */
snprintf (nametmp, symlen + 1, "%s", symname);
printf (" 0x%04x %-30.30s [0x%8lx] [0x%4x] %d %ld\n",
sym->rectyp, nametmp, sym->off, sym->reclen, sym->seg, sym->typind);
/* The entire record is null-padded to the nearest 4-byte
* boundary, so we must do a little extra math to keep things straight.
*/
recordlen = sym->reclen;
if (recordlen % 4)
recordlen += 4 - (recordlen % 4);
/* printf ("Padding length of %d bytes to %d\n", sym->reclen, recordlen); */
curpos += recordlen;
}
printf (" Freeing symbol memory...\n");
free (symbols);
return TRUE;
}
int DumpGlobalSymInfo (int index, FILE *debugfile)
{
if (g_cvEntries == NULL || debugfile == NULL ||
g_cvEntries[index].SubSection != sstGlobalSym)
return FALSE;
/*** NOT YET IMPLEMENTED ***/
printf ("---Found section ");
PrintSubsectionName (g_cvEntries[index].SubSection);
printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
printf (" of module #%d---\n", index + 1);
return TRUE;
}
int DumpStaticSymInfo (int index, FILE *debugfile)
{
if (g_cvEntries == NULL || debugfile == NULL ||
g_cvEntries[index].SubSection != sstStaticSym)
return FALSE;
/*** NOT YET IMPLEMENTED ***/
printf ("---Found section ");
PrintSubsectionName (g_cvEntries[index].SubSection);
printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
printf (" of module #%d---\n", index + 1);
return TRUE;
}
int DumpLibrariesInfo (int index, FILE *debugfile)
{
if (g_cvEntries == NULL || debugfile == NULL ||
g_cvEntries[index].SubSection != sstLibraries)
return FALSE;
/*** NOT YET IMPLEMENTED ***/
printf ("---Found section ");
PrintSubsectionName (g_cvEntries[index].SubSection);
printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
printf (" of module #%d---\n", index + 1);
return TRUE;
}
int DumpGlobalTypesInfo (int index, FILE *debugfile)
{
if (g_cvEntries == NULL || debugfile == NULL ||
g_cvEntries[index].SubSection != sstGlobalTypes)
return FALSE;
/*** NOT YET IMPLEMENTED ***/
printf ("---Found section ");
PrintSubsectionName (g_cvEntries[index].SubSection);
printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
printf (" of module #%d---\n", index + 1);
return TRUE;
}
int DumpSegMapInfo (int index, FILE *debugfile)
{
if (g_cvEntries == NULL || debugfile == NULL ||
g_cvEntries[index].SubSection != sstSegMap)
return FALSE;
printf ("-------------------- sstSegMap --------------------\n");
printf ("---Found section ");
PrintSubsectionName (g_cvEntries[index].SubSection);
printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
printf (" of module #%d---\n", index + 1);
return TRUE;
}
int DumpFileIndexInfo (int index, FILE *debugfile)
{
if (g_cvEntries == NULL || debugfile == NULL ||
g_cvEntries[index].SubSection != sstFileIndex)
return FALSE;
/*** NOT YET IMPLEMENTED ***/
printf ("---Found section ");
PrintSubsectionName (g_cvEntries[index].SubSection);
printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
printf (" of module #%d---\n", index + 1);
return TRUE;
}
int DumpSrcModuleInfo (int index, FILE *debugfile)
{
int i;
int fileoffset;
BYTE *rawdata;
BYTE *curpos;
short filecount;
short segcount;
int moduledatalen;
int filedatalen;
int linedatalen;
if (g_cvEntries == NULL || debugfile == NULL ||
g_cvEntries[index].SubSection != sstSrcModule)
return FALSE;
printf ("--------------------- sstSrcModule --------------------\n");
printf (" file offset = [0x%8lx]\n", g_dwStartOfCodeView + g_cvEntries[index].lfo);
printf (" size = [0x%8lx]\n", g_cvEntries[index].cb);
/* Where in the .DBG file should we start reading?
*/
fileoffset = g_dwStartOfCodeView + g_cvEntries[index].lfo;
/* Allocate a chunk of memory for the entire sstSrcModule
*/
rawdata = malloc (g_cvEntries[index].cb);
if (!rawdata)
{
printf ("ERROR - Unable to allocate %ld bytes for DumpSrcModuleInfo()\n",
g_cvEntries[index].cb);
return FALSE;
}
/* Read in the entire sstSrcModule from the .DBG file. We'll process it
* bit by bit, by passing memory pointers into the various functions in
* cvcrunch.c.
*/
if (!ReadChunk (debugfile, (void*)rawdata, g_cvEntries[index].cb, fileoffset))
return FALSE;
moduledatalen = PrintSrcModuleInfo (rawdata, &filecount, &segcount);
#ifdef VERBOSE
printf ("*** PrintSrcModuleInfo() returned %d\n", moduledatalen);
#endif
curpos = rawdata + moduledatalen;
filedatalen = PrintSrcModuleFileInfo (curpos);
#ifdef VERBOSE
printf ("*** PrintSrcModuleFileInfo() returned %d\n", filedatalen);
#endif
curpos += filedatalen;
for (i = 0; i < segcount; i++)
{
linedatalen = PrintSrcModuleLineInfo (curpos, i);
#ifdef VERBOSE
printf ("*** PrintSrcModuleLineInfo() returned %d\n", linedatalen);
#endif
curpos += linedatalen;
}
free (rawdata);
return TRUE;
}
int DumpAlignSymInfo (int index, FILE *debugfile)
{
if (g_cvEntries == NULL || debugfile == NULL ||
g_cvEntries[index].SubSection != sstAlignSym)
return FALSE;
/*** NOT YET IMPLEMENTED ***/
printf ("--------------------- sstAlignSym ---------------------\n");
printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
printf (" of module #%d\n", index + 1);
return TRUE;
}
/*
* Print out the info of all related modules (e.g. sstAlignSym, sstSrcModule)
* for the given sub-section index (i.e. sstModule).
*/
int DumpRelatedSections (int index, FILE *debugfile)
{
int i;
if (g_cvEntries == NULL)
return FALSE;
/* printf ("...Scanning %ld entries for matches on module #%d\n", g_cvHeader.cDir, module_num); */
for (i = 0; i < g_cvHeader.cDir; i++)
{
if (g_cvEntries[i].iMod != (index + 1) ||
g_cvEntries[i].SubSection == sstModule)
continue;
/* Pass in index of entry in g_cvEntries array to individual sub-section
* dumping functions. Each function will figure out where in the file its
* sub-section lies and seek the file position itself, before parsing out
* its data.
*/
switch (g_cvEntries[i].SubSection)
{
case sstAlignSym:
DumpAlignSymInfo (i, debugfile);
break;
case sstSrcModule:
DumpSrcModuleInfo (i, debugfile);
break;
default:
printf ("---Found section ");
PrintSubsectionName (g_cvEntries[i].SubSection);
printf (" [iMod = %d] [i = %d]", g_cvEntries[i].iMod, i);
printf (" of module #%d---\n", index + 1);
}
}
return TRUE;
}
int DumpMiscSections (int index, FILE *debugfile)
{
/* The module # 65535 is reserved for all free-standing modules, not
* associated with a sstModule sub-section. These are the only sections
* we wish to process here.
*/
if (g_cvEntries == NULL || g_cvEntries[index].iMod != 65535)
return FALSE;
/* Pass in index of entry in g_cvEntries array to individual sub-section
* dumping functions. Each function will figure out where in the file its
* sub-section lies and seek the file position itself, before parsing out
* its data.
*/
switch (g_cvEntries[index].SubSection)
{
case sstGlobalPub:
DumpGlobalPubInfo (index, debugfile);
break;
case sstGlobalSym:
DumpGlobalSymInfo (index, debugfile);
break;
case sstStaticSym:
DumpStaticSymInfo (index, debugfile);
break;
case sstLibraries:
DumpLibrariesInfo (index, debugfile);
break;
case sstGlobalTypes:
DumpGlobalTypesInfo (index, debugfile);
break;
case sstSegMap:
DumpSegMapInfo (index, debugfile);
break;
case sstFileIndex:
DumpFileIndexInfo (index, debugfile);
break;
default:
printf ("---Found section ");
PrintSubsectionName (g_cvEntries[index].SubSection);
printf (" [iMod = %d] [index = %d]", g_cvEntries[index].iMod, index);
printf (" of module #%d---\n", index + 1);
}
return TRUE;
}
int DumpAllModules (FILE *debugfile)
{
int i;
if (g_cvHeader.cDir == 0)
{
printf ("\nStrange...found CodeView header, but no module entries\n\n");
return TRUE;
}
if (g_cvEntries == NULL)
{
printf ("ERROR: Invalid entry table, bailing out of Module Data Dump\n");
printf ("%ld %p\n", g_cvHeader.cDir, g_cvEntries);
return FALSE;
}
printf ("\n============================================================\n");
printf (" MODULE LISTING\n");
printf ("============================================================\n");
/* Seek to beginning of debug data
*/
fseek (debugfile, g_dwStartOfCodeView + g_cvEntries[0].lfo, SEEK_SET);
#ifdef VERBOSE
printf ("[ Moving to filepos = 0x%lx to read in CodeView module info ]\n",
ftell (debugfile));
#endif
/* Load all OMFModuleFull data from file into memory
*/
if (!ReadModuleData (debugfile, g_cvHeader.cDir, g_cvEntries,
&g_module_count, &g_cvModules))
{
PrintFilePos (debugfile);
return FALSE;
}
/* Print out bulk of info (depends on the fact that all sstModule's
* are packed at the beginning of the array).
*/
printf ("Found %d modules\n", g_module_count);
for (i = 0; i < g_module_count; i++)
{
printf ("\n====================== Module #%d ======================\n", i + 1);
DumpModuleInfo (i);
DumpRelatedSections (i, debugfile);
printf ("=======================================================\n");
}
printf ("\n============================================================\n");
printf (" MISCELLANEOUS MODULES\n");
printf ("============================================================\n");
for (i = 0; i < g_cvHeader.cDir; i++)
{
DumpMiscSections (i, debugfile);
}
return TRUE;
}
/*
* Free Global data used by OMFModuleFull structs. Can't just use free() because
* the 'SegInfo' and 'Name' fields also have allocated memory.
*/
void FreeCVModules ()
{
int i;
OMFModuleFull *module;
for (i = 0; i < g_module_count; i++)
{
module = &(g_cvModules[i]);
free (module->SegInfo);
free (module->Name);
free (module);
}
}
int DumpCVFile (LPSTR filename)
{
FILE *debugfile;
if (strlen (filename) == 0)
return (-1);
debugfile = fopen (filename, "r");
if (debugfile == NULL)
{
printf ("============================================================\n");
printf (" ERROR: Unable to open file [%s]\n", filename);
printf ("============================================================\n");
return (-1);
}
printf ("============================================================\n");
printf (" Performing bindump on file %s\n", filename);
printf ("============================================================\n\n");
if (!DumpFileHeaders (debugfile))
{
printf ("============================================================\n");
printf (" ERROR: Bailed out while printing file headers!\n");
printf ("============================================================\n");
return (-1);
}
if (g_exe_mode)
g_numsects = g_nthdr.FileHeader.NumberOfSections;
else
g_numsects = g_dbghdr.NumberOfSections;
if (!DumpSectionHeaders (debugfile))
{
printf ("============================================================\n");
printf (" ERROR: Bailed out while printing section headers\n");
printf ("============================================================\n");
return (-1);
}
if (g_exe_mode)
g_dbg_dircount = g_nthdr.OptionalHeader.DataDirectory[IMAGE_FILE_DEBUG_DIRECTORY].Size /
sizeof (IMAGE_DEBUG_DIRECTORY);
else
g_dbg_dircount = g_dbghdr.DebugDirectorySize / sizeof (IMAGE_DEBUG_DIRECTORY);
#ifdef VERBOSE
printf ("\n[ Found %d debug directories in %s file. ]\n", g_dbg_dircount,
g_exe_mode ? "PE" : "DBG");
#endif
if (!DumpDebugDir (debugfile))
{
printf ("============================================================\n");
printf (" ERROR: Bailed out while printing Debug Directories\n");
printf ("============================================================\n");
return (-1);
}
/* Only dump CodeView data if we know where it is!
*/
if (g_dwStartOfCodeView == 0)
{
printf ("============================================================\n");
printf (" ERROR: Unable to find CodeView info!\n");
printf ("============================================================\n");
return (-1);
}
if (!DumpCodeViewHeaders (debugfile))
{
printf ("============================================================\n");
printf (" ERROR: Bailed out while printing CodeView headers\n");
printf ("============================================================\n");
return (-1);
}
if (!DumpAllModules (debugfile))
{
printf ("============================================================\n");
printf (" ERROR: Bailed out while printing CodeView debug info\n");
printf ("============================================================\n");
return (-1);
}
/* Clean up our trash
*/
printf ("Shutting down...\n");
free (g_debugdirs);
free (g_secthdrs);
/* FIXME: For some reason, this call segfaults...check it out later */
/* free (g_cvEntries); */
/* printf ("Freeing module data..."); */
/* FreeCVModules (); */
return 0;
}
int main(int argc, char *argv[])
{
int i;
if (argc == 1)
{
printf ("Usage:\n\tcvdump FILE [FILES...]\n");
return (-1);
}
for (i = 1; i < argc; i++)
DumpCVFile (argv[i]);
return 0;
}