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