From 52097fd7038726cf5e6ea728d131a40f30a76d6e Mon Sep 17 00:00:00 2001 From: Andreas Mohr Date: Wed, 11 Sep 2002 00:49:48 +0000 Subject: [PATCH] - Implement dumping of COFF debug symbol table. - Fix winedump syntax description. - Spelling fixes. --- tools/winedump/README | 23 +++++---- tools/winedump/debug.c | 103 +++++++++++++++++++++++++++++++++++++++++ tools/winedump/pe.c | 62 +++++++++++++------------ tools/winedump/pe.h | 3 +- 4 files changed, 150 insertions(+), 41 deletions(-) diff --git a/tools/winedump/README b/tools/winedump/README index 293ac63c1bc..1a7732ad80b 100644 --- a/tools/winedump/README +++ b/tools/winedump/README @@ -59,7 +59,7 @@ Winedump can be used for different usages: - demangling MSVC C++ symbol names - dumping the 'PE' files contents -Usage: winedump [-h sym spec dump ] [mode options] +Usage: winedump [-h | sym | spec | dump ] [mode options] When used in -h mode -h Display this help message When used in sym mode @@ -436,7 +436,7 @@ The definition for the _complex struct needs to be given. Since it is passed by value, its size also needs to be correct in order to forward the call correctly to a native DLL. In this case the structure is 8 bytes in size, which means that the gcc compile flag -freg-struct-return must be given when -compiling the function in order to be compatable with the native DLL. (In +compiling the function in order to be compatable with the native DLL. (In general this is not an issue, but you need to be aware of such issues if you encounter problems with your forwarding DLL). @@ -472,7 +472,7 @@ struct foobar { int _FIXME; }; The output should be piped through 'sort' and 'uniq' to remove multiple declarations, e.g: -winedump -d foo -c -I "inc/*.h" -v | grep FIXME | sort | uniq > fixup.h +winedump foo -c -I "inc/*.h" -v | grep FIXME | sort | uniq > fixup.h By adding '#include "fixup.h"' to foobar_dll.h your compile errors will be greatly reduced. @@ -481,7 +481,7 @@ If winedump encounters a type it doesnt know that is passed by value (as in the _cabs example above), it also prints a FIXME message like: /* FIXME: By value type: Assumed 'int' */ typedef int ldiv_t; - + If the type is not an int, you will need to change the code and possibly the .spec entry in order to forward correctly. Otherwise, include the typedef in your fixup header to avoid compile errors. @@ -582,10 +582,13 @@ Which is enough information to begin implementing the function. Dumping ------- -Another tool might be helpful digging into a 32bit DLL (and any PE image file): +Another tool might be helpful for digging into a 32bit DLL (and any PE image file): pedump. Usage: +winedump [-h | sym | spec | dump ] [switches] + +winedump switches: -h Display this help message -d Use dll for input file and generate implementation code -C Turns on symbol demangling @@ -593,13 +596,13 @@ Usage: -j dir_name Dumps only the content of directory dir_name (import, export, debug) -x Dumps everything -The basic usage, to look everything in a file is: -winedump dump -d mydll.dll -x +The basic usage, to look at everything in a file is: +winedump dump mydll.dll -x It'll print any available information on the file. This information can be splitted into sub-categories: -- file hedaers (request by -f or -x) are made of the standard PE header structures, +- file headers (request by -f or -x) are made of the standard PE header structures, plus the COFF sections -- directories: you can print them one after the other using the -j switch. Currently, - only the import, export and debug directories are implemented. +- directories: you can print them one after the other using the -j switch. + Currently, only the import, export and debug directories are implemented. - -x displays the file headers and any available directory. diff --git a/tools/winedump/debug.c b/tools/winedump/debug.c index bd9164e307f..988a8b30d0e 100644 --- a/tools/winedump/debug.c +++ b/tools/winedump/debug.c @@ -97,6 +97,10 @@ * (OMFDirHeader.cDir) */ +extern void *PE_base; + +extern IMAGE_NT_HEADERS* PE_nt_headers; + static void* cv_base /* = 0 */; static int dump_cv_sst_module(OMFDirEntry* omfde) @@ -482,7 +486,106 @@ static void dump_codeview_headers(unsigned long base, unsigned long len) 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) +{ + PIMAGE_COFF_SYMBOLS_HEADER coff; + PIMAGE_SYMBOL coff_sym; + PIMAGE_SYMBOL coff_symbols; + PIMAGE_LINENUMBER coff_linetab; + char * coff_strtab; + IMAGE_SECTION_HEADER *sectHead = (IMAGE_SECTION_HEADER*)((char*)PE_nt_headers + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + PE_nt_headers->FileHeader.SizeOfOptionalHeader); + 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", PE_base, 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"); +} diff --git a/tools/winedump/pe.c b/tools/winedump/pe.c index 058cdeb0afd..1da91df44f1 100644 --- a/tools/winedump/pe.c +++ b/tools/winedump/pe.c @@ -46,9 +46,9 @@ # define O_BINARY 0 #endif -static void* base; -static unsigned long total_len; -static IMAGE_NT_HEADERS* nt_headers; +void* PE_base; +unsigned long PE_total_len; +IMAGE_NT_HEADERS* PE_nt_headers; enum FileSig {SIG_UNKNOWN, SIG_DOS, SIG_PE, SIG_DBG}; @@ -85,14 +85,14 @@ static const char* get_machine_str(DWORD mach) void* PRD(unsigned long prd, unsigned long len) { - return (prd + len > total_len) ? NULL : (char*)base + prd; + return (prd + len > PE_total_len) ? NULL : (char*)PE_base + prd; } unsigned long Offset(void* ptr) { - if (ptr < base) {printf("<<<<= (char*)base + total_len) {printf("<<<<= (char*)PE_base + PE_total_len) {printf("<<<<FileHeader.SizeOfOptionalHeader); + PE_nt_headers->FileHeader.SizeOfOptionalHeader); if (rva == 0) return NULL; - for (i = nt_headers->FileHeader.NumberOfSections - 1; i >= 0; i--) + for (i = PE_nt_headers->FileHeader.NumberOfSections - 1; i >= 0; i--) { if (sectHead[i].VirtualAddress <= rva && rva + len <= (DWORD)sectHead[i].VirtualAddress + sectHead[i].SizeOfRawData) @@ -125,10 +125,10 @@ void* RVA(unsigned long rva, unsigned long len) static void* get_dir(unsigned idx) { - if (idx >= nt_headers->OptionalHeader.NumberOfRvaAndSizes) + if (idx >= PE_nt_headers->OptionalHeader.NumberOfRvaAndSizes) return NULL; - return RVA(nt_headers->OptionalHeader.DataDirectory[idx].VirtualAddress, - nt_headers->OptionalHeader.DataDirectory[idx].Size); + return RVA(PE_nt_headers->OptionalHeader.DataDirectory[idx].VirtualAddress, + PE_nt_headers->OptionalHeader.DataDirectory[idx].Size); } static const char* DirectoryNames[16] = { @@ -146,7 +146,7 @@ static void dump_pe_header(void) unsigned i; printf("File Header\n"); - fileHeader = &nt_headers->FileHeader; + fileHeader = &PE_nt_headers->FileHeader; printf(" Machine: %04X (%s)\n", fileHeader->Machine, get_machine_str(fileHeader->Machine)); @@ -175,7 +175,7 @@ static void dump_pe_header(void) /* hope we have the right size */ printf("Optional Header\n"); - optionalHeader = &nt_headers->OptionalHeader; + optionalHeader = &PE_nt_headers->OptionalHeader; printf(" Magic 0x%-4X %u\n", optionalHeader->Magic, optionalHeader->Magic); printf(" linker version %u.%02u\n", @@ -401,12 +401,12 @@ static void dump_dir_imported_functions(void) unsigned nb_imp, i; if (!importDesc) return; - nb_imp = nt_headers->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].Size / + nb_imp = PE_nt_headers->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].Size / sizeof(*importDesc); if (!nb_imp) return; printf("Import Table size: %lu\n", - nt_headers->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].Size);/* FIXME */ + PE_nt_headers->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].Size);/* FIXME */ for (i = 0; i < nb_imp - 1; i++) /* the last descr is set as 0 as a sentinel */ { @@ -495,11 +495,13 @@ static void dump_dir_debug_dir(IMAGE_DEBUG_DIRECTORY* idd, int idx) case IMAGE_DEBUG_TYPE_UNKNOWN: break; case IMAGE_DEBUG_TYPE_COFF: + dump_coff(idd->PointerToRawData, idd->SizeOfData); break; case IMAGE_DEBUG_TYPE_CODEVIEW: dump_codeview(idd->PointerToRawData, idd->SizeOfData); break; case IMAGE_DEBUG_TYPE_FPO: + dump_frame_pointer_omission(idd->PointerToRawData, idd->SizeOfData); break; case IMAGE_DEBUG_TYPE_MISC: { @@ -535,7 +537,7 @@ static void dump_dir_debug(void) unsigned nb_dbg, i; if (!debugDir) return; - nb_dbg = nt_headers->OptionalHeader.DataDirectory[IMAGE_FILE_DEBUG_DIRECTORY].Size / + nb_dbg = PE_nt_headers->OptionalHeader.DataDirectory[IMAGE_FILE_DEBUG_DIRECTORY].Size / sizeof(*debugDir); if (!nb_dbg) return; @@ -740,10 +742,10 @@ static void do_dump(void) if (globals.do_dumpheader) { dump_pe_header(); - /* FIX%E: should check ptr */ - dump_sections((char*)nt_headers + sizeof(DWORD) + - sizeof(IMAGE_FILE_HEADER) + nt_headers->FileHeader.SizeOfOptionalHeader, - nt_headers->FileHeader.NumberOfSections); + /* FIXME: should check ptr */ + dump_sections((char*)PE_nt_headers + sizeof(DWORD) + + sizeof(IMAGE_FILE_HEADER) + PE_nt_headers->FileHeader.SizeOfOptionalHeader, + PE_nt_headers->FileHeader.NumberOfSections); } else if (!globals.dumpsect) { @@ -792,7 +794,7 @@ static enum FileSig check_headers(void) { if (*pdw == IMAGE_NT_SIGNATURE) { - nt_headers = PRD(dh->e_lfanew, sizeof(DWORD)); + PE_nt_headers = PRD(dh->e_lfanew, sizeof(DWORD)); sig = SIG_PE; } else @@ -830,14 +832,14 @@ int pe_analysis(const char* name, void (*fn)(void), enum FileSig wanted_sig) if (fd == -1) fatal("Can't open file"); if (fstat(fd, &s) < 0) fatal("Can't get size"); - total_len = s.st_size; + PE_total_len = s.st_size; #ifdef HAVE_MMAP - if ((base = mmap(NULL, total_len, PROT_READ, MAP_PRIVATE, fd, 0)) == (void *)-1) + if ((PE_base = mmap(NULL, PE_total_len, PROT_READ, MAP_PRIVATE, fd, 0)) == (void *)-1) #endif { - if (!(base = malloc( total_len ))) fatal( "Out of memory" ); - if (read( fd, base, total_len ) != total_len) fatal( "Cannot read file" ); + if (!(PE_base = malloc( PE_total_len ))) fatal( "Out of memory" ); + if (read( fd, PE_base, PE_total_len ) != PE_total_len) fatal( "Cannot read file" ); } effective_sig = check_headers(); @@ -854,7 +856,7 @@ int pe_analysis(const char* name, void (*fn)(void), enum FileSig wanted_sig) case SIG_UNKNOWN: /* shouldn't happen... */ ret = 0; break; case SIG_PE: - printf("Contents of \"%s\": %ld bytes\n\n", name, total_len); + printf("Contents of \"%s\": %ld bytes\n\n", name, PE_total_len); (*fn)(); break; case SIG_DBG: @@ -872,10 +874,10 @@ int pe_analysis(const char* name, void (*fn)(void), enum FileSig wanted_sig) if (ret) printf("Done dumping %s\n", name); #ifdef HAVE_MMAP - if (munmap(base, total_len) == -1) + if (munmap(PE_base, PE_total_len) == -1) #endif { - free( base ); + free( PE_base ); } close(fd); diff --git a/tools/winedump/pe.h b/tools/winedump/pe.h index a01f61c690c..a258b2967cd 100644 --- a/tools/winedump/pe.h +++ b/tools/winedump/pe.h @@ -19,7 +19,8 @@ */ extern void dump_codeview(unsigned long ptr, unsigned long len); +extern void dump_coff(unsigned long coffbase, unsigned long len); +extern void dump_frame_pointer_omission(unsigned long base, unsigned long len); extern void* PRD(unsigned long prd, unsigned long len); extern unsigned long Offset(void* ptr); extern char* get_time_str(DWORD _t); -