winedump patch: add COFF dumping
Andreas Mohr
andi at rhlx01.fht-esslingen.de
Tue Sep 10 05:53:52 CDT 2002
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
More information about the wine-patches
mailing list