From e61d33bfd1ddd575f69616870f1a700b764ab18d Mon Sep 17 00:00:00 2001 From: "John R. Sheets" Date: Sun, 26 Mar 2000 20:25:23 +0000 Subject: [PATCH] Added cvdump tool to dump CodeView symbol information. --- Makefile.in | 2 +- configure | 2 + configure.in | 1 + tools/cvdump/.cvsignore | 2 + tools/cvdump/Makefile.in | 18 + tools/cvdump/cvcrunch.c | 186 ++++++++ tools/cvdump/cvdump.c | 1115 ++++++++++++++++++++++++++++++++++++++++++++++ tools/cvdump/cvdump.h | 36 ++ tools/cvdump/cvinclude.h | 172 +++++++ tools/cvdump/cvload.c | 430 ++++++++++++++++++ 10 files changed, 1963 insertions(+), 1 deletion(-) create mode 100644 tools/cvdump/.cvsignore create mode 100644 tools/cvdump/Makefile.in create mode 100644 tools/cvdump/cvcrunch.c create mode 100644 tools/cvdump/cvdump.c create mode 100644 tools/cvdump/cvdump.h create mode 100644 tools/cvdump/cvinclude.h create mode 100644 tools/cvdump/cvload.c diff --git a/Makefile.in b/Makefile.in index 1d865c9133c..fd5a4a30322 100644 --- a/Makefile.in +++ b/Makefile.in @@ -92,7 +92,7 @@ INSTALLSUBDIRS = $(DLLDIR) $(DOCSUBDIRS) $(INCSUBDIRS) LINTSUBDIRS = $(LIBSUBDIRS) $(DLLDIR) $(EMUSUBDIRS) $(DOCSUBDIRS) # Extra sub-directories to clean -CLEANSUBDIRS = dlls include include/bitmaps include/wine +CLEANSUBDIRS = dlls include include/bitmaps include/wine tools/cvdump LIBOBJS = \ controls/controls.o \ diff --git a/configure b/configure index 6f4ee7c33e4..152cb8fd651 100755 --- a/configure +++ b/configure @@ -6314,6 +6314,7 @@ resources/Makefile scheduler/Makefile server/Makefile tools/Makefile +tools/cvdump/Makefile tools/wrc/Makefile tsx11/Makefile win32/Makefile @@ -6537,6 +6538,7 @@ resources/Makefile scheduler/Makefile server/Makefile tools/Makefile +tools/cvdump/Makefile tools/wrc/Makefile tsx11/Makefile win32/Makefile diff --git a/configure.in b/configure.in index 1071257b91f..ead21fa561c 100644 --- a/configure.in +++ b/configure.in @@ -1056,6 +1056,7 @@ resources/Makefile scheduler/Makefile server/Makefile tools/Makefile +tools/cvdump/Makefile tools/wrc/Makefile tsx11/Makefile win32/Makefile diff --git a/tools/cvdump/.cvsignore b/tools/cvdump/.cvsignore new file mode 100644 index 00000000000..e8ef3798449 --- /dev/null +++ b/tools/cvdump/.cvsignore @@ -0,0 +1,2 @@ +Makefile +cvdump diff --git a/tools/cvdump/Makefile.in b/tools/cvdump/Makefile.in new file mode 100644 index 00000000000..e9c23efe738 --- /dev/null +++ b/tools/cvdump/Makefile.in @@ -0,0 +1,18 @@ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ + +PROGRAMS = cvdump@PROGEXT@ +MODULE = none + +C_SRCS = cvcrunch.c cvdump.c cvload.c + +all: $(PROGRAMS) + +@MAKE_RULES@ + +cvdump@PROGEXT@: $(OBJS) + $(CC) $(CFLAGS) -o cvdump@PROGEXT@ $(OBJS) + +### Dependencies: diff --git a/tools/cvdump/cvcrunch.c b/tools/cvdump/cvcrunch.c new file mode 100644 index 00000000000..b5d2070f633 --- /dev/null +++ b/tools/cvdump/cvcrunch.c @@ -0,0 +1,186 @@ +/* + * Functions to process in-memory arrays of CodeView data sections + * (currently only contains sstSrcModule). + * + * Copyright 2000 John R. Sheets + */ + +/* FIXME - Change to cvprint.c */ + +#include +#include +#include +#include + +#include "peexe.h" +#include "cvinclude.h" + +/************************ sstSrcModule ************************/ + +/* Print out stuff in OMFSourceModule block. Rather than using the supplied + * OMFSourceModule struct, we'll extract each piece of data separately from + * the block of memory (rawdata). This struct (and the others used in + * sstSrcModule sections) is pretty useless. We can't use sizeof() on it + * because it contains the first element of the file offset array (i.e. baseSrcFile), + * which we need to parse separately anyway. See below for problems with the + * other structs. + * + * The contents of this section look like this (the first two fields are + * already extracted and passed in as parameters): + * + * unsigned short cFile + * unsigned short cSeg + * unsigned long baseSrcFile[cFile] + * unsigned long segarray[cSeg * 2] + * unsigned short segindexarray[cSeg] + */ +int PrintSrcModuleInfo (BYTE* rawdata, short *filecount, short *segcount) +{ + int i; + int datalen; + + unsigned short cFile; + unsigned short cSeg; + unsigned long *baseSrcFile; + unsigned long *segarray; + unsigned short *segindexarray; + + /* Get all our pointers straightened out + */ + cFile = *(short*)rawdata; + cSeg = *(short*)(rawdata + 2); + baseSrcFile = (long*)(rawdata + 4); + segarray = &baseSrcFile[cFile]; + segindexarray = (short*)(&segarray[cSeg * 2]); + + /* Pass # of segments and files back to calling function + */ + *filecount = cFile; + *segcount = cSeg; + + printf ("\n Module table: Found %d file(s) and %d segment(s)\n", cFile, cSeg); + for (i = 0; i < cFile; i++) + { + printf (" File #%d begins at an offset of 0x%lx in this section\n", + i + 1, baseSrcFile[i]); + } + + for (i = 0; i < cSeg; i++) + { + printf (" Segment #%d start = 0x%lx, end = 0x%lx, seg index = %d\n", + i + 1, segarray[i * 2], segarray[(i * 2) + 1], segindexarray[i]); + } + + /* Return the total length of the data (in bytes) that we used, so + * we'll know how far to jump ahead for the next part of the sstSrcModule. + */ + datalen = ((BYTE*)(&segindexarray[cSeg]) - rawdata); + /* printf ("datalen before padding = %d\n", datalen); */ + if (datalen % 4) + datalen += 4 - (datalen % 4); + /* printf ("datalen after padding = %d\n", datalen); */ + + return datalen; +} + +/* Print out the contents of a OMFSourceFile block. Unfortunately, the official + * version of this struct (probably quite outdated) claims that the 'cFName' field + * is a short. Based on experimentation with MSVC 5.0 .DBG files, this field is + * quite clearly only a single byte. Yet another reason to do it all by hand + * and avoid the "official" structs. + * + * The contents of this section look like this (the first field is + * pre-extracted, and 'pad' is ignored): + * + * unsigned short cSeg + * unsigned short pad + * unsigned long baseSrcLn[cSeg] + * unsigned long segarray[cSeg * 2] + * char cFName + * char Name[cFName] + */ +int PrintSrcModuleFileInfo (BYTE* rawdata) +{ + int i; + int datalen; + + unsigned short cSeg; + unsigned long *baseSrcLn; + unsigned long *segarray; + unsigned char cFName; + char Name[256]; + + /* Get all our pointers straightened out + */ + cSeg = *(short*)(rawdata); + /* Skip the 'pad' field */ + baseSrcLn = (long*)(rawdata + 4); + segarray = &baseSrcLn[cSeg]; + cFName = *((char*)&segarray[cSeg * 2]); + snprintf (Name, cFName + 1, "%s", (char*)&segarray[cSeg * 2] + 1); + + /* printf ("cSeg = %d\n", cSeg); */ + printf ("\n File table: '%s'\n", Name); + + for (i = 0; i < cSeg; i++) + { + printf (" Segment #%d start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", + i + 1, segarray[i * 2], segarray[(i * 2) + 1], baseSrcLn[i]); + } + + /* Return the total length of the data (in bytes) that we used, so + * we'll know how far to jump ahead for the next part of the sstSrcModule. + */ + datalen = ((BYTE*)(&segarray[cSeg * 2]) + cFName + 1 - rawdata); + /* printf ("datalen before padding = %d\n", datalen); */ + if (datalen % 4) + datalen += 4 - (datalen % 4); + /* printf ("datalen after padding = %d\n", datalen); */ + + return datalen; +} + +/* Print out the contents of a OMFSourceLine block. The contents of this section + * look like this: + * + * unsigned short Seg + * unsigned short cPair + * unsigned long offset[cPair] + * unsigned long linenumber[cPair] + */ +int PrintSrcModuleLineInfo (BYTE* rawdata, int tablecount) +{ + int i; + int datalen; + + unsigned short Seg; + unsigned short cPair; + unsigned long *offset; + unsigned short *linenumber; + + Seg = *(short*)rawdata; + cPair = *(short*)(rawdata + 2); + offset = (long*)(rawdata + 4); + linenumber = (short*)&offset[cPair]; + + printf ("\n Line table #%d: Found %d line numbers for segment index %d\n", + tablecount, cPair, Seg); + + for (i = 0; i < cPair; i++) + { + printf (" Pair #%2d: offset = [0x%8lx], linenumber = %d\n", + i + 1, offset[i], linenumber[i]); + } + + /* Return the total length of the data (in bytes) that we used, so + * we'll know how far to jump ahead for the next part of the sstSrcModule. + */ + datalen = ((BYTE*)(&linenumber[cPair]) - rawdata); + /* printf ("datalen before padding = %d\n", datalen); */ + if (datalen % 4) + datalen += 4 - (datalen % 4); + /* printf ("datalen after padding = %d\n", datalen); */ + + return datalen; +} + diff --git a/tools/cvdump/cvdump.c b/tools/cvdump/cvdump.c new file mode 100644 index 00000000000..d30018a69dd --- /dev/null +++ b/tools/cvdump/cvdump.c @@ -0,0 +1,1115 @@ +/* + * 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 +#include +#include +#include + +#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_dbg_dircount - 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 (" - %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 (" - %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 CodeView subsection%c...\n", g_dbg_dircount, + (g_dbg_dircount == 1) ? '.' : 's'); + + 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); + } +#if 0 + else + { + int i; + + /* Find the .rdata section. + */ + for (i = 0; i < g_numsects; i++) + if (strcmp (g_secthdrs[i].Name, ".rdata") == 0) + break; + + filepos = g_secthdrs[i].PointerToRawData; + } +#endif + + 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); + } + + 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 (" - %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, but passing memory pointers into the various functions in + * cvprint.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 desired sub-section (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 || g_cvEntries == NULL) + { + printf ("ERROR: 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; +} diff --git a/tools/cvdump/cvdump.h b/tools/cvdump/cvdump.h new file mode 100644 index 00000000000..b7cda4334fa --- /dev/null +++ b/tools/cvdump/cvdump.h @@ -0,0 +1,36 @@ +/* + * Includes for cvdump tool. + * + * Copyright 2000 John R. Sheets + */ + +/* #define VERBOSE */ + +#include "peexe.h" +#include "neexe.h" +#include "cvinclude.h" + +typedef enum { CV_NONE, CV_DOS, CV_NT, CV_DBG } CVHeaderType; + +/* + * Function Prototypes + */ + +/* From cvload.c */ +CVHeaderType GetHeaderType (FILE *debugfile); +int ReadDOSFileHeader (FILE *debugfile, IMAGE_DOS_HEADER *doshdr); +int ReadPEFileHeader (FILE *debugfile, IMAGE_NT_HEADERS *nthdr); +int ReadDBGFileHeader (FILE *debugfile, IMAGE_SEPARATE_DEBUG_HEADER *dbghdr); + +int ReadSectionHeaders (FILE *debugfile, int numsects, IMAGE_SECTION_HEADER **secthdrs); +int ReadDebugDir (FILE *debugfile, int numdirs, IMAGE_DEBUG_DIRECTORY **debugdirs); +int ReadCodeViewHeader (FILE *debugfile, OMFSignature *sig, OMFDirHeader *dirhdr); +int ReadCodeViewDirectory (FILE *debugfile, int entrynum, OMFDirEntry **entries); +int ReadModuleData (FILE *debugfile, int entrynum, OMFDirEntry *entries, + int *module_count, OMFModuleFull **modules); +int ReadChunk (FILE *debugfile, void *dest, int length, int fileoffset); + +/* From cvprint.c */ +int PrintSrcModuleInfo (BYTE* rawdata, short *filecount, short *segcount); +int PrintSrcModuleFileInfo (BYTE* rawdata); +int PrintSrcModuleLineInfo (BYTE* rawdata, int tablecount); diff --git a/tools/cvdump/cvinclude.h b/tools/cvdump/cvinclude.h new file mode 100644 index 00000000000..2fd5112a707 --- /dev/null +++ b/tools/cvdump/cvinclude.h @@ -0,0 +1,172 @@ +/* + * CodeView 4 Debug format - declarations + * + * (based on cvinfo.h and cvexefmt.h from the Win32 SDK) + */ + +#define sstModule 0x120 +#define sstAlignSym 0x125 +#define sstSrcModule 0x127 +#define sstLibraries 0x128 +#define sstGlobalSym 0x129 +#define sstGlobalPub 0x12a +#define sstGlobalTypes 0x12b +#define sstSegMap 0x12d +#define sstFileIndex 0x133 +#define sstStaticSym 0x134 + +#if 0 +/* Old, crusty value */ +#define S_PUB32 0x0203 +#endif + +#define S_PUB32 0x1009 + +#include "pshpack1.h" + +/* + * CodeView headers + */ + +typedef struct OMFSignature +{ + char Signature[4]; + long filepos; +} OMFSignature; + +typedef struct OMFDirHeader +{ + unsigned short cbDirHeader; + unsigned short cbDirEntry; + unsigned long cDir; + long lfoNextDir; + unsigned long flags; +} OMFDirHeader; + +typedef struct OMFDirEntry +{ + unsigned short SubSection; + unsigned short iMod; + long lfo; + unsigned long cb; +} OMFDirEntry; + + +/* + * sstModule subsection + */ + +typedef struct OMFSegDesc +{ + unsigned short Seg; + unsigned short pad; + unsigned long Off; + unsigned long cbSeg; +} OMFSegDesc; + +/* Must chop off the OMFSegDesc* field, because we need to write this + * struct out to a file. If we write the whole struct out, we'll end up + * with (*OMFSegDesc), not (OMFSegDesc). See OMFModuleFull. + */ +typedef struct OMFModule +{ + unsigned short ovlNumber; + unsigned short iLib; + unsigned short cSeg; + char Style[2]; +} OMFModule; + +/* Full version, with memory pointers, too. Use OMFModule for writing out to + * a file, and OMFModuleFull for reading. If offsetof() were available, we + * could use that instead. + */ +typedef struct OMFModuleFull +{ + unsigned short ovlNumber; + unsigned short iLib; + unsigned short cSeg; + char Style[2]; + OMFSegDesc *SegInfo; + char *Name; +} OMFModuleFull; + + +/* + * sstGlobalPub section + */ + +/* Header for symbol table. + */ +typedef struct OMFSymHash +{ + unsigned short symhash; + unsigned short addrhash; + unsigned long cbSymbol; + unsigned long cbHSym; + unsigned long cbHAddr; +} OMFSymHash; + +/* Symbol table entry. + */ +typedef struct DATASYM32 +{ + unsigned short reclen; + unsigned short rectyp; + unsigned long typind; + unsigned long off; + unsigned short seg; +} DATASYM32; +typedef DATASYM32 PUBSYM32; + +/* + * sstSegMap section + */ + +typedef struct OMFSegMapDesc +{ + unsigned short flags; + unsigned short ovl; + unsigned short group; + unsigned short frame; + unsigned short iSegName; + unsigned short iClassName; + unsigned long offset; + unsigned long cbSeg; +} OMFSegMapDesc; + +typedef struct OMFSegMap +{ + unsigned short cSeg; + unsigned short cSegLog; + OMFSegMapDesc rgDesc[0]; +} OMFSegMap; + + +/* + * sstSrcModule section + */ + +typedef struct OMFSourceLine +{ + unsigned short Seg; + unsigned short cLnOff; + unsigned long offset[1]; + unsigned short lineNbr[1]; +} OMFSourceLine; + +typedef struct OMFSourceFile +{ + unsigned short cSeg; + unsigned short reserved; + unsigned long baseSrcLn[1]; + unsigned short cFName; + char Name; +} OMFSourceFile; + +typedef struct OMFSourceModule +{ + unsigned short cFile; + unsigned short cSeg; + unsigned long baseSrcFile[1]; +} OMFSourceModule; + diff --git a/tools/cvdump/cvload.c b/tools/cvdump/cvload.c new file mode 100644 index 00000000000..e8df089ce34 --- /dev/null +++ b/tools/cvdump/cvload.c @@ -0,0 +1,430 @@ +/* + * Functions to read parts of a .DBG file into their respective struct's + * + * Copyright 2000 John R. Sheets + */ + +/* + * .DBG File Layout: + * + * IMAGE_SEPARATE_DEBUG_HEADER + * IMAGE_SECTION_HEADER[] + * IMAGE_DEBUG_DIRECTORY[] + * OMFSignature + * debug data (typical example) + * - IMAGE_DEBUG_TYPE_MISC + * - IMAGE_DEBUG_TYPE_FPO + * - IMAGE_DEBUG_TYPE_CODEVIEW + * OMFDirHeader + * OMFDirEntry[] + */ + +/* + * Descriptions: + * + * (hdr) IMAGE_SEPARATE_DEBUG_HEADER - .DBG-specific file header; holds info that + * applies to the file as a whole, including # of COFF sections, file offsets, etc. + * (hdr) IMAGE_SECTION_HEADER - list of COFF sections copied verbatim from .EXE; + * although this directory contains file offsets, these offsets are meaningless + * in the context of the .DBG file, because only the section headers are copied + * to the .DBG file...not the binary data it points to. + * (hdr) IMAGE_DEBUG_DIRECTORY - list of different formats of debug info contained in file + * (see IMAGE_DEBUG_TYPE_* descriptions below); tells where each section starts + * (hdr) OMFSignature (CV) - Contains "NBxx" signature, plus file offset telling how far + * into the IMAGE_DEBUG_TYPE_CODEVIEW section the OMFDirHeader and OMFDirEntry's sit + * (data) IMAGE_DEBUG_TYPE_MISC - usually holds name of original .EXE file + * (data) IMAGE_DEBUG_TYPE_FPO - Frame Pointer Optimization data; used for dealing with + * optimized stack frames (optional) + * (data) IMAGE_DEBUG_TYPE_CODEVIEW - *** THE GOOD STUFF *** + * This block of data contains all the symbol tables, line number info, etc., + * that the Visual C++ debugger needs. + * (hdr) OMFDirHeader (CV) - + * (hdr) OMFDirEntry (CV) - list of subsections within CodeView debug data section + */ + +/* + * The .DBG file typically has three arrays of directory entries, which tell + * the OS or debugger where in the file to look for the actual data + * + * IMAGE_SECTION_HEADER - number of entries determined by: + * (IMAGE_SEPARATE_DEBUG_HEADER.NumberOfSections) + * + * IMAGE_DEBUG_DIRECTORY - number of entries determined by: + * (IMAGE_SEPARATE_DEBUG_HEADER.DebugDirectorySize / sizeof (IMAGE_DEBUG_DIRECTORY)) + * + * OMFDirEntry - number of entries determined by: + * (OMFDirHeader.cDir) + */ + +#include +#include +#include +#include + +#include "cvdump.h" + +extern DWORD g_dwStartOfCodeView; + +/* + * Extract a generic block of data from debugfile (pass in fileoffset == -1 + * to avoid the fseek()). + */ +int ReadChunk (FILE *debugfile, void *dest, int length, int fileoffset) +{ + size_t bytes_read; + + if (fileoffset >= 0) + fseek (debugfile, fileoffset, SEEK_SET); + + bytes_read = fread (dest, 1, length, debugfile); + if (bytes_read < length) + { + printf ("ERROR: Only able to read %d bytes of %d-byte chunk!\n", + bytes_read, length); + return FALSE; + } + + return TRUE; +} + +/* + * Scan the next two bytes of a file, and see if they correspond to a file + * header signature. Don't forget to put the file pointer back where we + * found it... + */ +CVHeaderType GetHeaderType (FILE *debugfile) +{ + WORD hdrtype; + CVHeaderType ret = CV_NONE; + + int oldpos = ftell (debugfile); + +#ifdef VERBOSE + printf (" *** Current file position = %lx\n", ftell (debugfile)); +#endif + + if (!ReadChunk (debugfile, &hdrtype, sizeof (WORD), -1)) + { + fseek (debugfile, oldpos, SEEK_SET); + return CV_NONE; + } + + if (hdrtype == 0x5A4D) /* "MZ" */ + ret = CV_DOS; + else if (hdrtype == 0x4550) /* "PE" */ + ret = CV_NT; + else if (hdrtype == 0x4944) /* "DI" */ + ret = CV_DBG; + + fseek (debugfile, oldpos, SEEK_SET); + +#ifdef VERBOSE + printf ("Returning header type = %d [0x%x]\n", ret, hdrtype); + printf (" *** Current file position = %lx\n", ftell (debugfile)); +#endif + + return ret; +} + +/* + * Extract the DOS file headers from an executable + */ +int ReadDOSFileHeader (FILE *debugfile, IMAGE_DOS_HEADER *doshdr) +{ + size_t bytes_read; + + bytes_read = fread (doshdr, 1, sizeof (IMAGE_DOS_HEADER), debugfile); + if (bytes_read < sizeof (IMAGE_DOS_HEADER)) + { + printf ("ERROR: Only able to read %d bytes of %d-byte DOS file header!\n", + bytes_read, sizeof (IMAGE_DOS_HEADER)); + return FALSE; + } + + /* Skip over stub data, if present + */ + if (doshdr->e_lfanew) + fseek (debugfile, doshdr->e_lfanew, SEEK_SET); + + return TRUE; +} + +/* + * Extract the DOS and NT file headers from an executable + */ +int ReadPEFileHeader (FILE *debugfile, IMAGE_NT_HEADERS *nthdr) +{ + size_t bytes_read; + + bytes_read = fread (nthdr, 1, sizeof (IMAGE_NT_HEADERS), debugfile); + if (bytes_read < sizeof (IMAGE_NT_HEADERS)) + { + printf ("ERROR: Only able to read %d bytes of %d-byte NT file header!\n", + bytes_read, sizeof (IMAGE_NT_HEADERS)); + return FALSE; + } + + return TRUE; +} + +/* + * Extract the DBG file header from debugfile + */ +int ReadDBGFileHeader (FILE *debugfile, IMAGE_SEPARATE_DEBUG_HEADER *dbghdr) +{ + size_t bytes_read; + + bytes_read = fread (dbghdr, 1, sizeof (IMAGE_SEPARATE_DEBUG_HEADER), debugfile); + if (bytes_read < sizeof (IMAGE_SEPARATE_DEBUG_HEADER)) + { + printf ("ERROR: Only able to read %d bytes of %d-byte DBG file header!\n", + bytes_read, sizeof (IMAGE_SEPARATE_DEBUG_HEADER)); + return FALSE; + } + + return TRUE; +} + +/* + * Extract all of the file's COFF section headers into an array of + * IMAGE_SECTION_HEADER's. These COFF sections don't really apply to + * the .DBG file directly (they contain file offsets into the .EXE file + * which don't correspond to anything in the .DBG file). They are + * copied verbatim into this .DBG file to help make the debugging process + * more robust. By referencing these COFF section headers, the debugger + * can still function in the absence of the original .EXE file! + * + * NOTE: Do not bother pre-allocating memory. This function will + * allocate it for you. Don't forget to free() it when you're done, + * though. + */ +int ReadSectionHeaders (FILE *debugfile, int numsects, IMAGE_SECTION_HEADER **secthdrs) +{ + size_t bytes_read; + + /* Need a double-pointer so we can change the destination of the pointer + * and return the new allocation back to the caller. + */ + *secthdrs = calloc (numsects, sizeof (IMAGE_SECTION_HEADER)); + bytes_read = fread (*secthdrs, sizeof (IMAGE_SECTION_HEADER), numsects, debugfile); + if (bytes_read < numsects) + { + printf ("ERROR while reading COFF headers: Only able to " + "read %d headers out of %d desired!\n", + bytes_read, sizeof (IMAGE_SECTION_HEADER)); + return FALSE; + } + + return TRUE; +} + +/* + * Load in the debug directory table. This directory describes the various + * blocks of debug data that reside at the end of the file (after the COFF + * sections), including FPO data, COFF-style debug info, and the CodeView + * we are *really* after. + */ +int ReadDebugDir (FILE *debugfile, int numdirs, IMAGE_DEBUG_DIRECTORY **debugdirs) +{ + size_t bytes_read; + + /* Need a double-pointer so we can change the destination of the pointer + * and return the new allocation back to the caller. + */ + *debugdirs = calloc (numdirs, sizeof (IMAGE_DEBUG_DIRECTORY)); + bytes_read = fread (*debugdirs, sizeof (IMAGE_DEBUG_DIRECTORY), numdirs, debugfile); + if (bytes_read < numdirs) + { + printf ("ERROR while reading Debug Directory: Only able to " + "read %d headers out of %d desired!\n", + bytes_read, numdirs); + return FALSE; + } + + return TRUE; +} + +/* + * Load in the CodeView-style headers inside the CodeView debug section. + * The 'sig' and 'dirhdr' parameters must point to already-allocated + * data structures. + */ +int ReadCodeViewHeader (FILE *debugfile, OMFSignature *sig, OMFDirHeader *dirhdr) +{ + size_t bytes_read; + + bytes_read = fread (sig, 1, sizeof (OMFSignature), debugfile); + if (bytes_read < sizeof (OMFSignature)) + { + printf ("ERROR while reading CodeView Header Signature: Only " + "able to read %d bytes out of %d desired!\n", + bytes_read, sizeof (OMFSignature)); + return FALSE; + } + + /* Must perform a massive jump, almost to the end of the file, to find the + * CodeView Directory Header (OMFDirHeader), which is immediately followed + * by the array of entries (OMFDirEntry). We calculate the jump based on + * the beginning of the CodeView debug section (from the CodeView entry in + * the IMAGE_DEBUG_DIRECTORY array), with the added offset from OMGSignature. + */ + fseek (debugfile, sig->filepos + g_dwStartOfCodeView, SEEK_SET); + bytes_read = fread (dirhdr, 1, sizeof (OMFDirHeader), debugfile); + if (bytes_read < sizeof (OMFDirHeader)) + { + printf ("ERROR while reading CodeView Directory Header: Only " + "able to read %d bytes out of %d desired!\n", + bytes_read, sizeof (OMFDirHeader)); + return FALSE; + } + + /* File pointer is now at first OMGDirEntry, so we can begin reading those now, + * with an immediate call to ReadCodeViewDirectory (). + */ + + return TRUE; +} + +/* + * Load in the CodeView directory entries, which each point to a CodeView + * subsection (e.g. sstModules, sstGlobalPub). The number of entries in + * this table is determined by OMFDirEntry.cDir. + * + * Strangely enough, this particular section comes immediately *after* + * the debug data (as opposed to immediately *before* the data as is the + * standard with the COFF headers). + */ +int ReadCodeViewDirectory (FILE *debugfile, int entrynum, OMFDirEntry **entries) +{ + size_t bytes_read; + + /* Need a double-pointer so we can change the destination of the pointer + * and return the new allocation back to the caller. + */ + /* printf ("Allocating space for %d entries\n", entrynum); */ + *entries = calloc (entrynum, sizeof (OMFDirEntry)); + /* printf ("Allocated memory at %p (%p)\n", *entries, entries); */ + bytes_read = fread (*entries, sizeof (OMFDirEntry), entrynum, debugfile); + if (bytes_read < entrynum) + { + printf ("ERROR while reading CodeView Debug Directories: Only " + "able to read %d entries out of %d desired!\n", + bytes_read, entrynum); + return FALSE; + } + + return TRUE; +} + +/* + * Load in the data contents of all CodeView sstModule sub-sections in the file (likely a + * large array, as there is one sub-section for every module... > 100 modules is normal). + * 'entrynum' should hold the total number of CV sub-sections, not the number of sstModule + * subsections. The function will ignore anything that isn't a sstModule. + * + * NOTE: 'debugfile' must already be pointing to the correct location. + */ +int ReadModuleData (FILE *debugfile, int entrynum, OMFDirEntry *entries, + int *module_count, OMFModuleFull **modules) +{ + int i; + int segnum; + size_t bytes_read; + OMFSegDesc *segarray; + char namelen; + OMFModuleFull *module; + int pad; + + /* How much of the OMFModuleFull struct can we pull directly from the file? + * (Kind of a hack, but not much else we can do...the 'SegInfo' and 'Name' + * fields will hold memory pointers, not the actual data from the file.) + */ + int module_bytes = (sizeof (unsigned short) * 3) + (sizeof (char) * 2); + + if (entries == NULL) + return FALSE; + + /* Find out how many sstModule sub-sections we have in 'entries' + */ + *module_count = 0; + for (i = 0; i < entrynum; i++) + { + if (entries[i].SubSection == sstModule) + (*module_count)++; + } + + /* Need a double-pointer so we can change the destination of the pointer + * and return the new allocation back to the caller. + */ + *modules = calloc (*module_count, sizeof (OMFModuleFull)); + for (i = 0; i < *module_count; i++) + { + /* Convenience pointer to current module + */ + module = &(*modules)[i]; + + /* Must extract each OMFModuleFull separately from file, because the 'SegInfo' + * and 'Name' fields also require separate allocations; the data for these + * fields is interspersed in the file, between OMFModuleFull blocks. + */ + bytes_read = fread (module, sizeof (char), module_bytes, debugfile); + if (bytes_read < module_bytes) + { + printf ("ERROR while reading CodeView Module Sub-section Data: " + "Only able to read %d bytes from entry %d!\n", + bytes_read, i); + return FALSE; + } + + /* Allocate space for, and grab the entire 'SegInfo' array. + */ + segnum = module->cSeg; + segarray = calloc (segnum, sizeof (OMFSegDesc)); + + bytes_read = fread (segarray, sizeof (OMFSegDesc), segnum, debugfile); + if (bytes_read < segnum) + { + printf ("ERROR while reading CodeView Module SegInfo Data: " + "Only able to read %d segments from module %d!\n", + bytes_read, i); + return FALSE; + } + module->SegInfo = segarray; + + /* Allocate space for the (length-prefixed) 'Name' field. + */ + bytes_read = fread (&namelen, sizeof (char), 1, debugfile); + if (bytes_read < 1) + { + printf ("ERROR while reading CodeView Module Name length!\n"); + return FALSE; + } + + /* Read 'Name' field from file. 'Name' must be aligned on a 4-byte + * boundary, so we must do a little extra math on the string length. + * (NOTE: Must include namelen byte in total padding length, too.) + */ + pad = ((namelen + 1) % 4); + if (pad) + namelen += (4 - pad); + + module->Name = calloc (namelen, sizeof (char) + 1); + bytes_read = fread (module->Name, sizeof (char), namelen, debugfile); + if (bytes_read < namelen) + { + printf ("ERROR while reading CodeView Module Name: " + "Only able to read %d chars from module %d!\n", + bytes_read, i); + return FALSE; + } + /* printf ("%s\n", module->Name); */ + } + +#ifdef VERBOSE + printf ("Done reading %d modules\n", *module_count); +#endif + + return TRUE; +} + + -- 2.11.4.GIT