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;
+}
+
+