Commit 52097fd7 authored by Andreas Mohr's avatar Andreas Mohr Committed by Alexandre Julliard

- Implement dumping of COFF debug symbol table.

- Fix winedump syntax description. - Spelling fixes.
parent 025b52d9
......@@ -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);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment