/* * CVDump - Parses through a Visual Studio .DBG file in CodeView 4 format * and dumps the info to STDOUT in a human-readable format * * Copyright 2000 John R. Sheets */ #include #include #include #include #include "cvdump.h" DWORD g_dwStartOfCodeView = 0; int g_exe_mode = TRUE; IMAGE_DOS_HEADER g_doshdr; IMAGE_SEPARATE_DEBUG_HEADER g_dbghdr; IMAGE_NT_HEADERS g_nthdr; IMAGE_SECTION_HEADER *g_secthdrs = NULL; int g_numsects; int g_dbg_dircount; IMAGE_DEBUG_DIRECTORY *g_debugdirs = NULL; OMFSignature g_cvSig; OMFDirHeader g_cvHeader; OMFDirEntry *g_cvEntries = NULL; int g_module_count = 0; OMFModuleFull *g_cvModules = NULL; void PrintFilePos (FILE *file) { #ifdef VERBOSE printf (" *** Current file position = %lx\n", ftell (file)); #endif } /* Calculate the file offset, based on the RVA. */ DWORD GetOffsetFromRVA (DWORD rva) { int i; DWORD offset; DWORD filepos; DWORD sectbegin; /* Assumes all RVA's in the section headers are sorted in increasing * order (which should be the case). */ for (i = g_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 (" - %ld\n", type); break; case IMAGE_DEBUG_TYPE_COFF: printf ("COFF Directory:\n"); break; case IMAGE_DEBUG_TYPE_CODEVIEW: printf ("CodeView Directory:\n"); break; case IMAGE_DEBUG_TYPE_FPO: printf ("FPO Directory:\n"); break; case IMAGE_DEBUG_TYPE_MISC: printf ("MISC Directory:\n"); break; default: printf (" - %ld\n", type); } } int DumpDebugDir (FILE *debugfile) { int i; int filepos; printf ("\n============================================================\n"); printf (" CODEVIEW DEBUG DIRECTORY\n"); printf ("============================================================\n"); PrintFilePos (debugfile); printf ("Found %d 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 (" - %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; }