| /* |
| * Made after: |
| * 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 |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include "config.h" |
| #include "wine/port.h" |
| |
| #include <stdlib.h> |
| #include <stdarg.h> |
| #include <stdio.h> |
| #ifdef HAVE_UNISTD_H |
| # include <unistd.h> |
| #endif |
| #include <time.h> |
| #ifdef HAVE_SYS_TYPES_H |
| # include <sys/types.h> |
| #endif |
| #ifdef HAVE_SYS_STAT_H |
| # include <sys/stat.h> |
| #endif |
| #ifdef HAVE_SYS_MMAN_H |
| #include <sys/mman.h> |
| #endif |
| #include <fcntl.h> |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winedump.h" |
| #include "wine/mscvpdb.h" |
| |
| /* |
| * .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) |
| */ |
| |
| extern const IMAGE_NT_HEADERS* PE_nt_headers; |
| static const void* cv_base /* = 0 */; |
| |
| static int dump_cv_sst_module(const OMFDirEntry* omfde) |
| { |
| const OMFModule* module; |
| const OMFSegDesc* segDesc; |
| int i; |
| |
| module = PRD(Offset(cv_base) + omfde->lfo, sizeof(OMFModule)); |
| if (!module) {printf("Can't get the OMF-Module, aborting\n"); return FALSE;} |
| |
| printf(" olvNumber: %u\n", module->ovlNumber); |
| printf(" iLib: %u\n", module->iLib); |
| printf(" cSeg: %u\n", module->cSeg); |
| printf(" Style: %c%c\n", module->Style[0], module->Style[1]); |
| printf(" Name: %.*s\n", |
| *(const BYTE*)((const char*)(module + 1) + sizeof(OMFSegDesc) * module->cSeg), |
| (const char*)(module + 1) + sizeof(OMFSegDesc) * module->cSeg + 1); |
| |
| segDesc = PRD(Offset(module + 1), sizeof(OMFSegDesc) * module->cSeg); |
| if (!segDesc) {printf("Can't get the OMF-SegDesc, aborting\n"); return FALSE;} |
| |
| for (i = 0; i < module->cSeg; i++) |
| { |
| printf (" segment #%2d: offset = [0x%8x], size = [0x%8x]\n", |
| segDesc->Seg, segDesc->Off, segDesc->cbSeg); |
| segDesc++; |
| } |
| return TRUE; |
| } |
| |
| static int dump_cv_sst_global_pub(const OMFDirEntry* omfde) |
| { |
| long fileoffset; |
| const OMFSymHash* header; |
| const BYTE* symbols; |
| |
| fileoffset = Offset(cv_base) + omfde->lfo; |
| printf (" GlobalPub section starts at file offset 0x%lx\n", fileoffset); |
| printf (" Symbol table starts at 0x%lx\n", fileoffset + sizeof (OMFSymHash)); |
| |
| printf ("\n ----- Begin Symbol Table -----\n"); |
| |
| header = PRD(fileoffset, sizeof(OMFSymHash)); |
| if (!header) {printf("Can't get OMF-SymHash, aborting\n");return FALSE;} |
| |
| symbols = PRD(fileoffset + sizeof(OMFSymHash), header->cbSymbol); |
| if (!symbols) {printf("Can't OMF-SymHash details, aborting\n"); return FALSE;} |
| |
| codeview_dump_symbols(symbols, header->cbSymbol); |
| |
| return TRUE; |
| } |
| |
| static int dump_cv_sst_global_sym(const OMFDirEntry* omfde) |
| { |
| /*** NOT YET IMPLEMENTED ***/ |
| return TRUE; |
| } |
| |
| static int dump_cv_sst_static_sym(const OMFDirEntry* omfde) |
| { |
| /*** NOT YET IMPLEMENTED ***/ |
| return TRUE; |
| } |
| |
| static int dump_cv_sst_libraries(const OMFDirEntry* omfde) |
| { |
| /*** NOT YET IMPLEMENTED ***/ |
| return TRUE; |
| } |
| |
| static int dump_cv_sst_global_types(const OMFDirEntry* omfde) |
| { |
| long fileoffset; |
| const OMFGlobalTypes*types; |
| const BYTE* data; |
| unsigned sz; |
| |
| fileoffset = Offset(cv_base) + omfde->lfo; |
| printf (" GlobalTypes section starts at file offset 0x%lx\n", fileoffset); |
| |
| printf ("\n ----- Begin Global Types Table -----\n"); |
| |
| types = PRD(fileoffset, sizeof(OMFGlobalTypes)); |
| if (!types) {printf("Can't get OMF-GlobalTypes, aborting\n");return FALSE;} |
| |
| sz = omfde->cb - sizeof(OMFGlobalTypes) - sizeof(DWORD) * types->cTypes; |
| data = PRD(fileoffset + sizeof(OMFGlobalTypes) + sizeof(DWORD) * types->cTypes, sz); |
| if (!data) {printf("Can't OMF-SymHash details, aborting\n"); return FALSE;} |
| |
| /* doc says: |
| * - for NB07 & NB08 (that we don't support yet), offsets are from types |
| * - for NB09, offsets are from data |
| * For now, we only support the latter |
| */ |
| codeview_dump_types_from_offsets(data, (const DWORD*)(types + 1), types->cTypes); |
| |
| return TRUE; |
| } |
| |
| static int dump_cv_sst_seg_map(const OMFDirEntry* omfde) |
| { |
| const OMFSegMap* segMap; |
| const OMFSegMapDesc* segMapDesc; |
| int i; |
| |
| segMap = PRD(Offset(cv_base) + omfde->lfo, sizeof(OMFSegMap)); |
| if (!segMap) {printf("Can't get SegMap, aborting\n");return FALSE;} |
| |
| printf(" cSeg: %u\n", segMap->cSeg); |
| printf(" cSegLog: %u\n", segMap->cSegLog); |
| |
| segMapDesc = PRD(Offset(segMap + 1), segMap->cSeg * sizeof(OMFSegDesc)); |
| if (!segMapDesc) {printf("Can't get SegDescr array, aborting\n");return FALSE;} |
| |
| for (i = 0; i < segMap->cSeg; i++) |
| { |
| printf(" SegDescr #%2d\n", i + 1); |
| printf(" flags: %04X\n", segMapDesc[i].flags); |
| printf(" ovl: %u\n", segMapDesc[i].ovl); |
| printf(" group: %u\n", segMapDesc[i].group); |
| printf(" frame: %u\n", segMapDesc[i].frame); |
| printf(" iSegName: %u\n", segMapDesc[i].iSegName); |
| printf(" iClassName: %u\n", segMapDesc[i].iClassName); |
| printf(" offset: %lu\n", segMapDesc[i].offset); |
| printf(" cbSeg: %lu\n", segMapDesc[i].cbSeg); |
| } |
| |
| return TRUE; |
| } |
| |
| static int dump_cv_sst_file_index(const OMFDirEntry* omfde) |
| { |
| /*** NOT YET IMPLEMENTED ***/ |
| return TRUE; |
| } |
| |
| static int dump_cv_sst_src_module(const OMFDirEntry* omfde) |
| { |
| int i, j; |
| const BYTE* rawdata; |
| const unsigned long* seg_info_dw; |
| const unsigned short* seg_info_w; |
| unsigned ofs; |
| const OMFSourceModule* sourceModule; |
| const OMFSourceFile* sourceFile; |
| const OMFSourceLine* sourceLine; |
| |
| rawdata = PRD(Offset(cv_base) + omfde->lfo, omfde->cb); |
| if (!rawdata) {printf("Can't get srcModule subsection details, aborting\n");return FALSE;} |
| |
| /* FIXME: check ptr validity */ |
| sourceModule = (const void*)rawdata; |
| printf (" Module table: Found %d file(s) and %d segment(s)\n", |
| sourceModule->cFile, sourceModule->cSeg); |
| for (i = 0; i < sourceModule->cFile; i++) |
| { |
| printf (" File #%2d begins at an offset of 0x%lx in this section\n", |
| i + 1, sourceModule->baseSrcFile[i]); |
| } |
| |
| /* FIXME: check ptr validity */ |
| seg_info_dw = (const void*)((const char*)(sourceModule + 1) + |
| sizeof(unsigned long) * (sourceModule->cFile - 1)); |
| seg_info_w = (const unsigned short*)(&seg_info_dw[sourceModule->cSeg * 2]); |
| for (i = 0; i < sourceModule->cSeg; i++) |
| { |
| printf (" Segment #%2d start = 0x%lx, end = 0x%lx, seg index = %u\n", |
| i + 1, seg_info_dw[i * 2], seg_info_dw[(i * 2) + 1], |
| seg_info_w[i]); |
| } |
| ofs = sizeof(OMFSourceModule) + sizeof(unsigned long) * (sourceModule->cFile - 1) + |
| sourceModule->cSeg * (2 * sizeof(unsigned long) + sizeof(unsigned short)); |
| ofs = (ofs + 3) & ~3; |
| |
| /* the OMFSourceFile is quite unpleasant to use: |
| * we have first: |
| * unsigned short number of segments |
| * unsigned short reserved |
| * unsigned long baseSrcLn[# segments] |
| * unsigned long offset[2 * #segments] |
| * odd indices are start offsets |
| * even indices are end offsets |
| * unsigned char string length for file name |
| * char file name (length is previous field) |
| */ |
| /* FIXME: check ptr validity */ |
| sourceFile = (const void*)(rawdata + ofs); |
| seg_info_dw = (const void*)((const char*)sourceFile + 2 * sizeof(unsigned short) + |
| sourceFile->cSeg * sizeof(unsigned long)); |
| |
| ofs += 2 * sizeof(unsigned short) + 3 * sourceFile->cSeg * sizeof(unsigned long); |
| |
| printf(" File table: %.*s\n", |
| *(const BYTE*)((const char*)sourceModule + ofs), (const char*)sourceModule + ofs + 1); |
| |
| for (i = 0; i < sourceFile->cSeg; i++) |
| { |
| printf (" Segment #%2d start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", |
| i + 1, seg_info_dw[i * 2], seg_info_dw[(i * 2) + 1], sourceFile->baseSrcLn[i]); |
| } |
| /* add file name length */ |
| ofs += *(const BYTE*)((const char*)sourceModule + ofs) + 1; |
| ofs = (ofs + 3) & ~3; |
| |
| for (i = 0; i < sourceModule->cSeg; i++) |
| { |
| sourceLine = (const void*)(rawdata + ofs); |
| seg_info_dw = (const void*)((const char*)sourceLine + 2 * sizeof(unsigned short)); |
| seg_info_w = (const void*)(&seg_info_dw[sourceLine->cLnOff]); |
| |
| printf (" Line table #%2d: Found %d line numbers for segment index %d\n", |
| i, sourceLine->cLnOff, sourceLine->Seg); |
| |
| for (j = 0; j < sourceLine->cLnOff; j++) |
| { |
| printf (" Pair #%2d: offset = [0x%8lx], linenumber = %d\n", |
| j + 1, seg_info_dw[j], seg_info_w[j]); |
| } |
| ofs += 2 * sizeof(unsigned short) + |
| sourceLine->cLnOff * (sizeof(unsigned long) + sizeof(unsigned short)); |
| ofs = (ofs + 3) & ~3; |
| } |
| |
| return TRUE; |
| } |
| |
| static int dump_cv_sst_align_sym(const OMFDirEntry* omfde) |
| { |
| const char* rawdata = PRD(Offset(cv_base) + omfde->lfo, omfde->cb); |
| |
| if (!rawdata) {printf("Can't get srcAlignSym subsection details, aborting\n");return FALSE;} |
| if (omfde->cb < sizeof(DWORD)) return TRUE; |
| codeview_dump_symbols(rawdata + sizeof(DWORD), omfde->cb - sizeof(DWORD)); |
| |
| return TRUE; |
| } |
| |
| static void dump_codeview_all_modules(const OMFDirHeader *omfdh) |
| { |
| unsigned i; |
| const OMFDirEntry* dirEntry; |
| const char* str; |
| |
| if (!omfdh || !omfdh->cDir) return; |
| |
| dirEntry = PRD(Offset(omfdh + 1), omfdh->cDir * sizeof(OMFDirEntry)); |
| if (!dirEntry) {printf("Can't read DirEntry array, aborting\n"); return;} |
| |
| for (i = 0; i < omfdh->cDir; i++) |
| { |
| switch (dirEntry[i].SubSection) |
| { |
| case sstModule: str = "sstModule"; break; |
| case sstAlignSym: str = "sstAlignSym"; break; |
| case sstSrcModule: str = "sstSrcModule"; break; |
| case sstLibraries: str = "sstLibraries"; break; |
| case sstGlobalSym: str = "sstGlobalSym"; break; |
| case sstGlobalPub: str = "sstGlobalPub"; break; |
| case sstGlobalTypes: str = "sstGlobalTypes"; break; |
| case sstSegMap: str = "sstSegMap"; break; |
| case sstFileIndex: str = "sstFileIndex"; break; |
| case sstStaticSym: str = "sstStaticSym"; break; |
| default: str = "<undefined>"; break; |
| } |
| printf("Module #%2d (%p)\n", i + 1, &dirEntry[i]); |
| printf(" SubSection: %04X (%s)\n", dirEntry[i].SubSection, str); |
| printf(" iMod: %d\n", dirEntry[i].iMod); |
| printf(" lfo: %d\n", dirEntry[i].lfo); |
| printf(" cb: %u\n", dirEntry[i].cb); |
| |
| switch (dirEntry[i].SubSection) |
| { |
| case sstModule: dump_cv_sst_module(&dirEntry[i]); break; |
| case sstAlignSym: dump_cv_sst_align_sym(&dirEntry[i]); break; |
| case sstSrcModule: dump_cv_sst_src_module(&dirEntry[i]); break; |
| case sstLibraries: dump_cv_sst_libraries(&dirEntry[i]); break; |
| case sstGlobalSym: dump_cv_sst_global_sym(&dirEntry[i]); break; |
| case sstGlobalPub: dump_cv_sst_global_pub(&dirEntry[i]); break; |
| case sstGlobalTypes: dump_cv_sst_global_types(&dirEntry[i]); break; |
| case sstSegMap: dump_cv_sst_seg_map(&dirEntry[i]); break; |
| case sstFileIndex: dump_cv_sst_file_index(&dirEntry[i]); break; |
| case sstStaticSym: dump_cv_sst_static_sym(&dirEntry[i]); break; |
| default: printf("unsupported type %x\n", dirEntry[i].SubSection); break; |
| } |
| printf("\n"); |
| } |
| |
| return; |
| } |
| |
| static void dump_codeview_headers(unsigned long base, unsigned long len) |
| { |
| const OMFDirHeader* dirHeader; |
| const char* signature; |
| const OMFDirEntry* dirEntry; |
| const OMFSignature* sig; |
| unsigned i; |
| int modulecount = 0, alignsymcount = 0, srcmodulecount = 0, librariescount = 0; |
| int globalsymcount = 0, globalpubcount = 0, globaltypescount = 0; |
| int segmapcount = 0, fileindexcount = 0, staticsymcount = 0; |
| |
| cv_base = PRD(base, len); |
| if (!cv_base) {printf("Can't get full debug content, aborting\n");return;} |
| |
| signature = cv_base; |
| |
| printf(" CodeView Data\n"); |
| printf(" Signature: %.4s\n", signature); |
| |
| if (memcmp(signature, "NB10", 4) == 0) |
| { |
| const CODEVIEW_PDB_DATA* pdb_data; |
| pdb_data = (const void *)cv_base; |
| |
| printf(" Filepos: 0x%08lX\n", pdb_data->filepos); |
| printf(" TimeStamp: %08X (%s)\n", |
| pdb_data->timestamp, get_time_str(pdb_data->timestamp)); |
| printf(" Age: %08X\n", pdb_data->age); |
| printf(" Filename: %s\n", pdb_data->name); |
| return; |
| } |
| if (memcmp(signature, "RSDS", 4) == 0) |
| { |
| const OMFSignatureRSDS* rsds_data; |
| |
| rsds_data = (const void *)cv_base; |
| printf(" Guid: %s\n", get_guid_str(&rsds_data->guid)); |
| printf(" Age: %08X\n", rsds_data->age); |
| printf(" Filename: %s\n", rsds_data->name); |
| return; |
| } |
| |
| if (memcmp(signature, "NB09", 4) != 0 && memcmp(signature, "NB11", 4) != 0) |
| { |
| printf("Unsupported signature (%.4s), aborting\n", signature); |
| return; |
| } |
| |
| sig = cv_base; |
| |
| printf(" Filepos: 0x%08lX\n", sig->filepos); |
| |
| dirHeader = PRD(Offset(cv_base) + sig->filepos, sizeof(OMFDirHeader)); |
| if (!dirHeader) {printf("Can't get debug header, aborting\n"); return;} |
| |
| printf(" Size of header: 0x%4X\n", dirHeader->cbDirHeader); |
| printf(" Size per entry: 0x%4X\n", dirHeader->cbDirEntry); |
| printf(" # of entries: 0x%8X (%d)\n", dirHeader->cDir, dirHeader->cDir); |
| printf(" Offset to NextDir: 0x%8X\n", dirHeader->lfoNextDir); |
| printf(" Flags: 0x%8X\n", dirHeader->flags); |
| |
| if (!dirHeader->cDir) return; |
| |
| dirEntry = PRD(Offset(dirHeader + 1), sizeof(OMFDirEntry) * dirHeader->cDir); |
| if (!dirEntry) {printf("Can't get DirEntry array, aborting\n");return;} |
| |
| for (i = 0; i < dirHeader->cDir; i++) |
| { |
| switch (dirEntry[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); |
| |
| dump_codeview_all_modules(dirHeader); |
| } |
| |
| static const char *get_coff_name( const IMAGE_SYMBOL *coff_sym, const char *coff_strtab ) |
| { |
| static char namebuff[9]; |
| const char* nampnt; |
| |
| if( coff_sym->N.Name.Short ) |
| { |
| memcpy(namebuff, coff_sym->N.ShortName, 8); |
| namebuff[8] = '\0'; |
| nampnt = &namebuff[0]; |
| } |
| else |
| { |
| nampnt = coff_strtab + coff_sym->N.Name.Long; |
| } |
| |
| if( nampnt[0] == '_' ) |
| nampnt++; |
| return nampnt; |
| } |
| |
| static const char* storage_class(BYTE sc) |
| { |
| static char tmp[7]; |
| switch (sc) |
| { |
| case IMAGE_SYM_CLASS_STATIC: return "static"; |
| case IMAGE_SYM_CLASS_EXTERNAL: return "extrnl"; |
| case IMAGE_SYM_CLASS_LABEL: return "label "; |
| } |
| sprintf(tmp, "#%d", sc); |
| return tmp; |
| } |
| |
| void dump_coff_symbol_table(const IMAGE_SYMBOL *coff_symbols, unsigned num_sym, |
| const IMAGE_SECTION_HEADER *sectHead) |
| { |
| const IMAGE_SYMBOL *coff_sym; |
| const char *coff_strtab = (const char *) (coff_symbols + num_sym); |
| unsigned int i; |
| const char *nampnt; |
| int naux; |
| |
| printf("\nDebug table: COFF format.\n"); |
| printf(" ID | seg:offs [ abs ] | Kind | symbol/function name\n"); |
| for (i=0; i < num_sym; i++) |
| { |
| coff_sym = coff_symbols + i; |
| naux = coff_sym->NumberOfAuxSymbols; |
| |
| switch (coff_sym->StorageClass) |
| { |
| case IMAGE_SYM_CLASS_FILE: |
| printf("file %s\n", (const char *) (coff_sym + 1)); |
| break; |
| case IMAGE_SYM_CLASS_STATIC: |
| case IMAGE_SYM_CLASS_EXTERNAL: |
| case IMAGE_SYM_CLASS_LABEL: |
| if (coff_sym->SectionNumber > 0) |
| { |
| DWORD base = sectHead[coff_sym->SectionNumber - 1].VirtualAddress; |
| nampnt = get_coff_name( coff_sym, coff_strtab ); |
| |
| printf("%05d | %02d:%08x [%08x] | %s | %s\n", |
| i, coff_sym->SectionNumber - 1, coff_sym->Value, |
| base + coff_sym->Value, |
| storage_class(coff_sym->StorageClass), nampnt); |
| } |
| break; |
| default: |
| printf("%05d | %s\n", i, storage_class(coff_sym->StorageClass)); |
| } |
| /* |
| * For now, skip past the aux entries. |
| */ |
| i += naux; |
| } |
| } |
| |
| void dump_coff(unsigned long coffbase, unsigned long len, const IMAGE_SECTION_HEADER* sectHead) |
| { |
| const IMAGE_COFF_SYMBOLS_HEADER *coff = PRD(coffbase, len); |
| const IMAGE_SYMBOL *coff_symbols = |
| (const IMAGE_SYMBOL *) ((const char *)coff + coff->LvaToFirstSymbol); |
| |
| dump_coff_symbol_table(coff_symbols, coff->NumberOfSymbols, sectHead); |
| } |
| |
| void dump_codeview(unsigned long base, unsigned long len) |
| { |
| dump_codeview_headers(base, len); |
| } |
| |
| void dump_frame_pointer_omission(unsigned long base, unsigned long len) |
| { |
| const FPO_DATA* fpo; |
| const FPO_DATA* last; |
| const char* x; |
| /* FPO is used to describe nonstandard stack frames */ |
| printf("Range #loc #pmt Prlg #reg Info\n" |
| "-----------------+----+----+----+----+------------\n"); |
| |
| fpo = PRD(base, len); |
| if (!fpo) {printf("Couldn't get FPO blob\n"); return;} |
| last = (const FPO_DATA*)((const char*)fpo + len); |
| |
| while (fpo < last && fpo->ulOffStart) |
| { |
| switch (fpo->cbFrame) |
| { |
| case FRAME_FPO: x = "FRAME_FPO"; break; |
| case FRAME_NONFPO: x = "FRAME_NONFPO"; break; |
| case FRAME_TRAP: x = "FRAME_TRAP"; break; |
| case FRAME_TSS: x = "case FRAME_TSS"; break; |
| default: x = NULL; break; |
| } |
| printf("%08x-%08x %4u %4u %4u %4u %s%s%s\n", |
| fpo->ulOffStart, fpo->ulOffStart + fpo->cbProcSize, |
| fpo->cdwLocals, fpo->cdwParams, fpo->cbProlog, fpo->cbRegs, |
| x, fpo->fHasSEH ? " SEH" : "", fpo->fUseBP ? " UseBP" : ""); |
| fpo++; |
| } |
| } |
| |
| struct stab_nlist |
| { |
| union |
| { |
| char* n_name; |
| struct stab_nlist* n_next; |
| long n_strx; |
| } n_un; |
| unsigned char n_type; |
| char n_other; |
| short n_desc; |
| unsigned long n_value; |
| }; |
| |
| static const char * const stabs_defs[] = { |
| NULL,NULL,NULL,NULL, /* 00 */ |
| NULL,NULL,NULL,NULL, /* 08 */ |
| NULL,NULL,NULL,NULL, /* 10 */ |
| NULL,NULL,NULL,NULL, /* 18 */ |
| "GSYM","FNAME","FUN","STSYM", /* 20 */ |
| "LCSYM","MAIN","ROSYM","PC", /* 28 */ |
| NULL,"NSYMS","NOMAP",NULL, /* 30 */ |
| "OBJ",NULL,"OPT",NULL, /* 38 */ |
| "RSYM","M2C","SLINE","DSLINE", /* 40 */ |
| "BSLINE","DEFD","FLINE",NULL, /* 48 */ |
| "EHDECL",NULL,"CATCH",NULL, /* 50 */ |
| NULL,NULL,NULL,NULL, /* 58 */ |
| "SSYM","ENDM","SO",NULL, /* 60 */ |
| NULL,NULL,NULL,NULL, /* 68 */ |
| NULL,NULL,NULL,NULL, /* 70 */ |
| NULL,NULL,NULL,NULL, /* 78 */ |
| "LSYM","BINCL","SOL",NULL, /* 80 */ |
| NULL,NULL,NULL,NULL, /* 88 */ |
| NULL,NULL,NULL,NULL, /* 90 */ |
| NULL,NULL,NULL,NULL, /* 98 */ |
| "PSYM","EINCL","ENTRY",NULL, /* a0 */ |
| NULL,NULL,NULL,NULL, /* a8 */ |
| NULL,NULL,NULL,NULL, /* b0 */ |
| NULL,NULL,NULL,NULL, /* b8 */ |
| "LBRAC","EXCL","SCOPE",NULL, /* c0 */ |
| NULL,NULL,NULL,NULL, /* c8 */ |
| NULL,NULL,NULL,NULL, /* d0 */ |
| NULL,NULL,NULL,NULL, /* d8 */ |
| "RBRAC","BCOMM","ECOMM",NULL, /* e0 */ |
| "ECOML","WITH",NULL,NULL, /* e8 */ |
| "NBTEXT","NBDATA","NBBSS","NBSTS", /* f0 */ |
| "NBLCS",NULL,NULL,NULL /* f8 */ |
| }; |
| |
| void dump_stabs(const void* pv_stabs, unsigned szstabs, const char* stabstr, unsigned szstr) |
| { |
| int i; |
| int nstab; |
| const char* ptr; |
| char* stabbuff; |
| unsigned int stabbufflen; |
| const struct stab_nlist* stab_ptr = pv_stabs; |
| const char* strs_end; |
| char n_buffer[16]; |
| |
| nstab = szstabs / sizeof(struct stab_nlist); |
| strs_end = stabstr + szstr; |
| |
| /* |
| * Allocate a buffer into which we can build stab strings for cases |
| * where the stab is continued over multiple lines. |
| */ |
| stabbufflen = 65536; |
| stabbuff = malloc(stabbufflen); |
| |
| stabbuff[0] = '\0'; |
| |
| printf("#Sym n_type n_othr n_desc n_value n_strx String\n"); |
| |
| for (i = 0; i < nstab; i++, stab_ptr++) |
| { |
| ptr = stabstr + stab_ptr->n_un.n_strx; |
| if ((ptr > strs_end) || (ptr + strlen(ptr) > strs_end)) |
| { |
| ptr = "[[*** bad string ***]]"; |
| } |
| else if (ptr[strlen(ptr) - 1] == '\\') |
| { |
| /* |
| * Indicates continuation. Append this to the buffer, and go onto the |
| * next record. Repeat the process until we find a stab without the |
| * '/' character, as this indicates we have the whole thing. |
| */ |
| unsigned len = strlen(ptr); |
| if (strlen(stabbuff) + len > stabbufflen) |
| { |
| stabbufflen += 65536; |
| stabbuff = realloc(stabbuff, stabbufflen); |
| } |
| strncat(stabbuff, ptr, len - 1); |
| continue; |
| } |
| else if (stabbuff[0] != '\0') |
| { |
| strcat(stabbuff, ptr); |
| ptr = stabbuff; |
| } |
| if ((stab_ptr->n_type & 1) || !stabs_defs[stab_ptr->n_type / 2]) |
| sprintf(n_buffer, "<0x%02x>", stab_ptr->n_type); |
| else |
| sprintf(n_buffer, "%-6s", stabs_defs[stab_ptr->n_type / 2]); |
| printf("%4d %s %-8x % 6d %-8lx %-6lx %s\n", |
| i, n_buffer, stab_ptr->n_other, stab_ptr->n_desc, stab_ptr->n_value, |
| stab_ptr->n_un.n_strx, ptr); |
| } |
| free(stabbuff); |
| } |