- Implement dumping of COFF debug symbol table.
- Fix winedump syntax description. - Spelling fixes.
This commit is contained in:
parent
025b52d950
commit
52097fd703
|
@ -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 <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
|
||||
|
@ -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 <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 @@ 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.
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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("<<<<<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 @@ void* RVA(unsigned long rva, unsigned long len)
|
|||
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 @@ 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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue