Added cvdump tool to dump CodeView symbol information.
diff --git a/Makefile.in b/Makefile.in
index 1d865c9..fd5a4a3 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -92,7 +92,7 @@
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 6f4ee7c..152cb8f 100755
--- a/configure
+++ b/configure
@@ -6314,6 +6314,7 @@
scheduler/Makefile
server/Makefile
tools/Makefile
+tools/cvdump/Makefile
tools/wrc/Makefile
tsx11/Makefile
win32/Makefile
@@ -6537,6 +6538,7 @@
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 1071257..ead21fa 100644
--- a/configure.in
+++ b/configure.in
@@ -1056,6 +1056,7 @@
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 0000000..e8ef379
--- /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 0000000..e9c23ef
--- /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 0000000..b5d2070
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <windows.h>
+
+#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 0000000..d30018a
--- /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 <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_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 ("<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 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 ("<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, 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 0000000..b7cda43
--- /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 0000000..2fd5112
--- /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 0000000..e8df089
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <windows.h>
+
+#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;
+}
+
+