- Implement dumping of COFF debug symbol table.

- Fix winedump syntax description.
- Spelling fixes.
This commit is contained in:
Andreas Mohr 2002-09-11 00:49:48 +00:00 committed by Alexandre Julliard
parent 025b52d950
commit 52097fd703
4 changed files with 150 additions and 41 deletions

View File

@ -59,7 +59,7 @@ Winedump can be used for different usages:
- demangling MSVC C++ symbol names - demangling MSVC C++ symbol names
- dumping the 'PE' files contents - 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 When used in -h mode
-h Display this help message -h Display this help message
When used in sym mode When used in sym mode
@ -472,7 +472,7 @@ struct foobar { int _FIXME; };
The output should be piped through 'sort' and 'uniq' to remove multiple The output should be piped through 'sort' and 'uniq' to remove multiple
declarations, e.g: 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 By adding '#include "fixup.h"' to foobar_dll.h your compile errors will be
greatly reduced. greatly reduced.
@ -582,10 +582,13 @@ Which is enough information to begin implementing the function.
Dumping 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. pedump.
Usage: Usage:
winedump [-h | sym <sym> | spec <dll> | dump <dll> ] [switches]
winedump switches:
-h Display this help message -h Display this help message
-d <dll> Use dll for input file and generate implementation code -d <dll> Use dll for input file and generate implementation code
-C Turns on symbol demangling -C Turns on symbol demangling
@ -593,13 +596,13 @@ Usage:
-j dir_name Dumps only the content of directory dir_name (import, export, debug) -j dir_name Dumps only the content of directory dir_name (import, export, debug)
-x Dumps everything -x Dumps everything
The basic usage, to look everything in a file is: The basic usage, to look at everything in a file is:
winedump dump -d mydll.dll -x winedump dump mydll.dll -x
It'll print any available information on the file. This information can be splitted It'll print any available information on the file. This information can be splitted
into sub-categories: 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 plus the COFF sections
- directories: you can print them one after the other using the -j switch. Currently, - directories: you can print them one after the other using the -j switch.
only the import, export and debug directories are implemented. Currently, only the import, export and debug directories are implemented.
- -x displays the file headers and any available directory. - -x displays the file headers and any available directory.

View File

@ -97,6 +97,10 @@
* (OMFDirHeader.cDir) * (OMFDirHeader.cDir)
*/ */
extern void *PE_base;
extern IMAGE_NT_HEADERS* PE_nt_headers;
static void* cv_base /* = 0 */; static void* cv_base /* = 0 */;
static int dump_cv_sst_module(OMFDirEntry* omfde) 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); 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) void dump_codeview(unsigned long base, unsigned long len)
{ {
dump_codeview_headers(base, 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");
}

View File

@ -46,9 +46,9 @@
# define O_BINARY 0 # define O_BINARY 0
#endif #endif
static void* base; void* PE_base;
static unsigned long total_len; unsigned long PE_total_len;
static IMAGE_NT_HEADERS* nt_headers; IMAGE_NT_HEADERS* PE_nt_headers;
enum FileSig {SIG_UNKNOWN, SIG_DOS, SIG_PE, SIG_DBG}; 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) 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) unsigned long Offset(void* ptr)
{ {
if (ptr < base) {printf("<<<<<ptr below\n");return 0;} if (ptr < PE_base) {printf("<<<<<ptr below\n");return 0;}
if ((char *)ptr >= (char*)base + total_len) {printf("<<<<<ptr above\n");return 0;} if ((char *)ptr >= (char*)PE_base + PE_total_len) {printf("<<<<<ptr above\n");return 0;}
return (char*)ptr - (char*)base; return (char*)ptr - (char*)PE_base;
} }
void* RVA(unsigned long rva, unsigned long len) void* RVA(unsigned long rva, unsigned long len)
@ -100,13 +100,13 @@ void* RVA(unsigned long rva, unsigned long len)
IMAGE_SECTION_HEADER* sectHead; IMAGE_SECTION_HEADER* sectHead;
int i; 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) + sizeof(IMAGE_FILE_HEADER) +
nt_headers->FileHeader.SizeOfOptionalHeader); PE_nt_headers->FileHeader.SizeOfOptionalHeader);
if (rva == 0) return NULL; 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 && if (sectHead[i].VirtualAddress <= rva &&
rva + len <= (DWORD)sectHead[i].VirtualAddress + sectHead[i].SizeOfRawData) 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) static void* get_dir(unsigned idx)
{ {
if (idx >= nt_headers->OptionalHeader.NumberOfRvaAndSizes) if (idx >= PE_nt_headers->OptionalHeader.NumberOfRvaAndSizes)
return NULL; return NULL;
return RVA(nt_headers->OptionalHeader.DataDirectory[idx].VirtualAddress, return RVA(PE_nt_headers->OptionalHeader.DataDirectory[idx].VirtualAddress,
nt_headers->OptionalHeader.DataDirectory[idx].Size); PE_nt_headers->OptionalHeader.DataDirectory[idx].Size);
} }
static const char* DirectoryNames[16] = { static const char* DirectoryNames[16] = {
@ -146,7 +146,7 @@ static void dump_pe_header(void)
unsigned i; unsigned i;
printf("File Header\n"); printf("File Header\n");
fileHeader = &nt_headers->FileHeader; fileHeader = &PE_nt_headers->FileHeader;
printf(" Machine: %04X (%s)\n", printf(" Machine: %04X (%s)\n",
fileHeader->Machine, get_machine_str(fileHeader->Machine)); fileHeader->Machine, get_machine_str(fileHeader->Machine));
@ -175,7 +175,7 @@ static void dump_pe_header(void)
/* hope we have the right size */ /* hope we have the right size */
printf("Optional Header\n"); printf("Optional Header\n");
optionalHeader = &nt_headers->OptionalHeader; optionalHeader = &PE_nt_headers->OptionalHeader;
printf(" Magic 0x%-4X %u\n", printf(" Magic 0x%-4X %u\n",
optionalHeader->Magic, optionalHeader->Magic); optionalHeader->Magic, optionalHeader->Magic);
printf(" linker version %u.%02u\n", printf(" linker version %u.%02u\n",
@ -401,12 +401,12 @@ static void dump_dir_imported_functions(void)
unsigned nb_imp, i; unsigned nb_imp, i;
if (!importDesc) return; 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); sizeof(*importDesc);
if (!nb_imp) return; if (!nb_imp) return;
printf("Import Table size: %lu\n", 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 */ 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: case IMAGE_DEBUG_TYPE_UNKNOWN:
break; break;
case IMAGE_DEBUG_TYPE_COFF: case IMAGE_DEBUG_TYPE_COFF:
dump_coff(idd->PointerToRawData, idd->SizeOfData);
break; break;
case IMAGE_DEBUG_TYPE_CODEVIEW: case IMAGE_DEBUG_TYPE_CODEVIEW:
dump_codeview(idd->PointerToRawData, idd->SizeOfData); dump_codeview(idd->PointerToRawData, idd->SizeOfData);
break; break;
case IMAGE_DEBUG_TYPE_FPO: case IMAGE_DEBUG_TYPE_FPO:
dump_frame_pointer_omission(idd->PointerToRawData, idd->SizeOfData);
break; break;
case IMAGE_DEBUG_TYPE_MISC: case IMAGE_DEBUG_TYPE_MISC:
{ {
@ -535,7 +537,7 @@ static void dump_dir_debug(void)
unsigned nb_dbg, i; unsigned nb_dbg, i;
if (!debugDir) return; 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); sizeof(*debugDir);
if (!nb_dbg) return; if (!nb_dbg) return;
@ -740,10 +742,10 @@ static void do_dump(void)
if (globals.do_dumpheader) if (globals.do_dumpheader)
{ {
dump_pe_header(); dump_pe_header();
/* FIX%E: should check ptr */ /* FIXME: should check ptr */
dump_sections((char*)nt_headers + sizeof(DWORD) + dump_sections((char*)PE_nt_headers + sizeof(DWORD) +
sizeof(IMAGE_FILE_HEADER) + nt_headers->FileHeader.SizeOfOptionalHeader, sizeof(IMAGE_FILE_HEADER) + PE_nt_headers->FileHeader.SizeOfOptionalHeader,
nt_headers->FileHeader.NumberOfSections); PE_nt_headers->FileHeader.NumberOfSections);
} }
else if (!globals.dumpsect) else if (!globals.dumpsect)
{ {
@ -792,7 +794,7 @@ static enum FileSig check_headers(void)
{ {
if (*pdw == IMAGE_NT_SIGNATURE) 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; sig = SIG_PE;
} }
else 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 (fd == -1) fatal("Can't open file");
if (fstat(fd, &s) < 0) fatal("Can't get size"); if (fstat(fd, &s) < 0) fatal("Can't get size");
total_len = s.st_size; PE_total_len = s.st_size;
#ifdef HAVE_MMAP #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 #endif
{ {
if (!(base = malloc( total_len ))) fatal( "Out of memory" ); if (!(PE_base = malloc( PE_total_len ))) fatal( "Out of memory" );
if (read( fd, base, total_len ) != total_len) fatal( "Cannot read file" ); if (read( fd, PE_base, PE_total_len ) != PE_total_len) fatal( "Cannot read file" );
} }
effective_sig = check_headers(); 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... */ case SIG_UNKNOWN: /* shouldn't happen... */
ret = 0; break; ret = 0; break;
case SIG_PE: 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)(); (*fn)();
break; break;
case SIG_DBG: 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); if (ret) printf("Done dumping %s\n", name);
#ifdef HAVE_MMAP #ifdef HAVE_MMAP
if (munmap(base, total_len) == -1) if (munmap(PE_base, PE_total_len) == -1)
#endif #endif
{ {
free( base ); free( PE_base );
} }
close(fd); close(fd);

View File

@ -19,7 +19,8 @@
*/ */
extern void dump_codeview(unsigned long ptr, unsigned long len); 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 void* PRD(unsigned long prd, unsigned long len);
extern unsigned long Offset(void* ptr); extern unsigned long Offset(void* ptr);
extern char* get_time_str(DWORD _t); extern char* get_time_str(DWORD _t);