Hi all, I needed COFF debug symbol dumping, so I implemented it :) (well, "implemented" meaning: shamelessly stolen from winedbg) - implement dumping of COFF debug symbol table - FIX WINEDUMP SYNTAX DESCRIPTION Grrrrr, who the h*ll changed syntax without documenting the changes again !?!?!?!?!? Not even the bloody invocation *example* worked !!! (not to mention that it failed with such a bloody error message as "Unrecognized option") This is p*** p***. And who said that OSS development method was superiour to commercial software development again ? Get a life ! :-\ (just joking, but sometimes I'm really drowning in doubts) - spelling fixes Sounds like winedump is slowly starting to become better than any of the other PE dumping tools, given the dumping functionality we now have, though :) Oh, and yes, this patch is inline. I just hope vim did the right thing when reading in the patch file... Greetings, the cosmetics police ;-) Index: tools/winedump/README =================================================================== RCS file: /home/wine/wine/tools/winedump/README,v retrieving revision 1.2 diff -u -r1.2 README --- tools/winedump/README 29 May 2002 19:09:54 -0000 1.2 +++ tools/winedump/README 10 Sep 2002 10:44:08 -0000 @@ -59,7 +59,7 @@ - demangling MSVC C++ symbol names - dumping the 'PE' files contents -Usage: winedump [-h sym <sym> spec <dll> dump <dll>] [mode options] +Usage: winedump [-h | sym <sym> | spec <dll> | dump <dll>] [mode options] When used in -h mode -h Display this help message When used in sym mode @@ -472,7 +472,7 @@ 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. @@ -582,10 +582,13 @@ 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 <sym> | spec <dll> | dump <dll> ] [switches] + +winedump switches: -h Display this help message -d <dll> Use dll for input file and generate implementation code -C Turns on symbol demangling @@ -593,13 +596,13 @@ -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. Index: tools/winedump/debug.c =================================================================== RCS file: /home/wine/wine/tools/winedump/debug.c,v retrieving revision 1.6 diff -u -r1.6 debug.c --- tools/winedump/debug.c 17 Aug 2002 18:28:43 -0000 1.6 +++ tools/winedump/debug.c 10 Sep 2002 10:44:08 -0000 @@ -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 @@ 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"); } Index: tools/winedump/pe.c =================================================================== RCS file: /home/wine/wine/tools/winedump/pe.c,v retrieving revision 1.16 diff -u -r1.16 pe.c --- tools/winedump/pe.c 26 Aug 2002 21:47:41 -0000 1.16 +++ tools/winedump/pe.c 10 Sep 2002 10:44:09 -0000 @@ -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 @@ 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("<<<<<ptr below\n");return 0;} - if ((char *)ptr >= (char*)base + total_len) {printf("<<<<<ptr above\n");return 0;} - return (char*)ptr - (char*)base; + if (ptr < PE_base) {printf("<<<<<ptr below\n");return 0;} + if ((char *)ptr >= (char*)PE_base + PE_total_len) {printf("<<<<<ptr above\n");return 0;} + return (char*)ptr - (char*)PE_base; } void* RVA(unsigned long rva, unsigned long len) @@ -100,13 +100,13 @@ IMAGE_SECTION_HEADER* sectHead; int i; - sectHead = (IMAGE_SECTION_HEADER*)((char*)nt_headers + sizeof(DWORD) + + sectHead = (IMAGE_SECTION_HEADER*)((char*)PE_nt_headers + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + - nt_headers->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 @@ 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 @@ 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 @@ /* 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ { 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 @@ 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 @@ 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 @@ 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); Index: tools/winedump/pe.h =================================================================== RCS file: /home/wine/wine/tools/winedump/pe.h,v retrieving revision 1.2 diff -u -r1.2 pe.h --- tools/winedump/pe.h 10 Mar 2002 00:24:24 -0000 1.2 +++ tools/winedump/pe.h 10 Sep 2002 10:44:09 -0000 @@ -19,6 +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); -- Andreas Mohr Stauferstr. 6, D-71272 Renningen, Germany