| /* | |
| * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "pe.h" | |
| #include "cvinclude.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 IMAGE_NT_HEADERS* PE_nt_headers; | |
| static void* cv_base /* = 0 */; | |
| static int dump_cv_sst_module(OMFDirEntry* omfde) | |
| { | |
| OMFModule* module; | |
| 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", | |
| *(BYTE*)((char*)(module + 1) + sizeof(OMFSegDesc) * module->cSeg), | |
| (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%8lx], size = [0x%8lx]\n", | |
| segDesc->Seg, segDesc->Off, segDesc->cbSeg); | |
| segDesc++; | |
| } | |
| return TRUE; | |
| } | |
| static int dump_cv_sst_global_pub(OMFDirEntry* omfde) | |
| { | |
| long fileoffset; | |
| OMFSymHash* header; | |
| BYTE* symbols; | |
| BYTE* curpos; | |
| PUBSYM32* sym; | |
| unsigned symlen; | |
| int recordlen; | |
| char nametmp[256]; | |
| 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"); | |
| printf (" (type) (symbol name) (offset) (len) (seg) (ind)\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;} | |
| /* 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. | |
| */ | |
| for (curpos = symbols; curpos < symbols + header->cbSymbol; curpos += recordlen) | |
| { | |
| /* Point to the next PUBSYM32 in the table. | |
| */ | |
| sym = (PUBSYM32*)curpos; | |
| if (sym->reclen < sizeof(PUBSYM32)) break; | |
| symlen = sym->reclen - sizeof(PUBSYM32) + 1; | |
| if (symlen > sizeof(nametmp)) {printf("\nsqueeze%d\n", symlen);symlen = sizeof(nametmp) - 1;} | |
| memcpy(nametmp, curpos + sizeof (PUBSYM32) + 1, symlen); | |
| nametmp[symlen] = '\0'; | |
| 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 + 3) & ~3; | |
| } | |
| return TRUE; | |
| } | |
| static int dump_cv_sst_global_sym(OMFDirEntry* omfde) | |
| { | |
| /*** NOT YET IMPLEMENTED ***/ | |
| return TRUE; | |
| } | |
| static int dump_cv_sst_static_sym(OMFDirEntry* omfde) | |
| { | |
| /*** NOT YET IMPLEMENTED ***/ | |
| return TRUE; | |
| } | |
| static int dump_cv_sst_libraries(OMFDirEntry* omfde) | |
| { | |
| /*** NOT YET IMPLEMENTED ***/ | |
| return TRUE; | |
| } | |
| static int dump_cv_sst_global_types(OMFDirEntry* omfde) | |
| { | |
| /*** NOT YET IMPLEMENTED ***/ | |
| return TRUE; | |
| } | |
| static int dump_cv_sst_seg_map(OMFDirEntry* omfde) | |
| { | |
| OMFSegMap* segMap; | |
| 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(OMFDirEntry* omfde) | |
| { | |
| /*** NOT YET IMPLEMENTED ***/ | |
| return TRUE; | |
| } | |
| static int dump_cv_sst_src_module(OMFDirEntry* omfde) | |
| { | |
| int i, j; | |
| BYTE* rawdata; | |
| unsigned long* seg_info_dw; | |
| unsigned short* seg_info_w; | |
| unsigned ofs; | |
| OMFSourceModule* sourceModule; | |
| OMFSourceFile* sourceFile; | |
| 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 = (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 = (void*)((char*)(sourceModule + 1) + | |
| sizeof(unsigned long) * (sourceModule->cFile - 1)); | |
| seg_info_w = (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 reservered | |
| * 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 = (void*)(rawdata + ofs); | |
| seg_info_dw = (void*)((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", | |
| *(BYTE*)((char*)sourceModule + ofs), (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 += *(BYTE*)((char*)sourceModule + ofs) + 1; | |
| ofs = (ofs + 3) & ~3; | |
| for (i = 0; i < sourceModule->cSeg; i++) | |
| { | |
| sourceLine = (void*)(rawdata + ofs); | |
| seg_info_dw = (void*)((char*)sourceLine + 2 * sizeof(unsigned short)); | |
| seg_info_w = (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(OMFDirEntry* omfde) | |
| { | |
| /*** NOT YET IMPLEMENTED ***/ | |
| return TRUE; | |
| } | |
| static void dump_codeview_all_modules(OMFDirHeader *omfdh) | |
| { | |
| unsigned i; | |
| 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: %ld\n", dirEntry[i].lfo); | |
| printf(" cb: %lu\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) | |
| { | |
| OMFDirHeader *dirHeader; | |
| OMFSignature *signature; | |
| OMFDirEntry *dirEntry; | |
| 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->Signature); | |
| printf(" Filepos: 0x%08lX\n", signature->filepos); | |
| if (memcmp(signature->Signature, "NB10", 4) == 0) | |
| { | |
| struct {DWORD TimeStamp; DWORD Dunno; char Name[1];}* pdb_data; | |
| pdb_data = (void*)(signature + 1); | |
| printf(" TimeStamp: %08lX (%s)\n", | |
| pdb_data->TimeStamp, get_time_str(pdb_data->TimeStamp)); | |
| printf(" Dunno: %08lX\n", pdb_data->Dunno); | |
| printf(" Filename: %s\n", pdb_data->Name); | |
| return; | |
| } | |
| if (memcmp(signature->Signature, "NB09", 4) != 0 && memcmp(signature->Signature, "NB11", 4) != 0) | |
| { | |
| printf("Unsupported signature, aborting\n"); | |
| return; | |
| } | |
| dirHeader = PRD(Offset(cv_base) + signature->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%8lX (%ld)\n", dirHeader->cDir, dirHeader->cDir); | |
| printf(" Offset to NextDir: 0x%8lX\n", dirHeader->lfoNextDir); | |
| printf(" Flags: 0x%8lX\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( PIMAGE_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; | |
| } | |
| void dump_coff(unsigned long coffbase, unsigned long len, void* pmt) | |
| { | |
| PIMAGE_COFF_SYMBOLS_HEADER coff; | |
| PIMAGE_SYMBOL coff_sym; | |
| PIMAGE_SYMBOL coff_symbols; | |
| PIMAGE_LINENUMBER coff_linetab; | |
| char * coff_strtab; | |
| IMAGE_SECTION_HEADER * sectHead = pmt; | |
| unsigned int i; | |
| const char * nampnt; | |
| int naux; | |
| coff = (PIMAGE_COFF_SYMBOLS_HEADER)PRD(coffbase, len); | |
| coff_symbols = (PIMAGE_SYMBOL) ((unsigned int) coff + coff->LvaToFirstSymbol); | |
| coff_linetab = (PIMAGE_LINENUMBER) ((unsigned int) coff + coff->LvaToFirstLinenumber); | |
| coff_strtab = (char *) (coff_symbols + coff->NumberOfSymbols); | |
| printf("\nDebug table: COFF format. modbase %p, coffbase %p\n", PRD(0, 0), coff); | |
| printf(" ID | seg:offs [ abs ] | symbol/function name\n"); | |
| for(i=0; i < coff->NumberOfSymbols; i++ ) | |
| { | |
| coff_sym = coff_symbols + i; | |
| naux = coff_sym->NumberOfAuxSymbols; | |
| if( coff_sym->StorageClass == IMAGE_SYM_CLASS_FILE ) | |
| { | |
| printf("file %s\n", (char *) (coff_sym + 1)); | |
| i += naux; | |
| continue; | |
| } | |
| if( (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC) | |
| && (naux == 0) | |
| && (coff_sym->SectionNumber == 1) ) | |
| { | |
| DWORD base = sectHead[coff_sym->SectionNumber - 1].VirtualAddress; | |
| /* | |
| * This is a normal static function when naux == 0. | |
| * Just register it. The current file is the correct | |
| * one in this instance. | |
| */ | |
| nampnt = get_coff_name( coff_sym, coff_strtab ); | |
| printf("%05d | %02d:%08lx [%08lx] | %s\n", i, coff_sym->SectionNumber - 1, coff_sym->Value - base, coff_sym->Value, nampnt); | |
| i += naux; | |
| continue; | |
| } | |
| if( (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) | |
| && ISFCN(coff_sym->Type) | |
| && (coff_sym->SectionNumber > 0) ) | |
| { | |
| DWORD base = sectHead[coff_sym->SectionNumber - 1].VirtualAddress; | |
| nampnt = get_coff_name( coff_sym, coff_strtab ); | |
| /* FIXME: add code to find out the file this symbol belongs to, | |
| * see winedbg */ | |
| printf("%05d | %02d:%08lx [%08lx] | %s\n", i, coff_sym->SectionNumber - 1, coff_sym->Value - base, coff_sym->Value, nampnt); | |
| i += naux; | |
| continue; | |
| } | |
| /* | |
| * For now, skip past the aux entries. | |
| */ | |
| i += naux; | |
| } | |
| } | |
| 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) | |
| { | |
| /* FPO is used to describe nonstandard stack frames */ | |
| printf("FIXME: FPO (frame pointer omission) debug symbol dumping not implemented yet.\n"); | |
| } |