winedump: Added -G option to dump raw stabs information from PE files.
This commit is contained in:
parent
9766dd1a5f
commit
c2f1240a53
|
@ -582,3 +582,116 @@ void dump_frame_pointer_omission(unsigned long base, unsigned long len)
|
||||||
/* FPO is used to describe nonstandard stack frames */
|
/* FPO is used to describe nonstandard stack frames */
|
||||||
printf("FIXME: FPO (frame pointer omission) debug symbol dumping not implemented yet.\n");
|
printf("FIXME: FPO (frame pointer omission) debug symbol dumping not implemented yet.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct stab_nlist
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
char* n_name;
|
||||||
|
struct stab_nlist* n_next;
|
||||||
|
long n_strx;
|
||||||
|
} n_un;
|
||||||
|
unsigned char n_type;
|
||||||
|
char n_other;
|
||||||
|
short n_desc;
|
||||||
|
unsigned long n_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char* stabs_defs[] = {
|
||||||
|
NULL,NULL,NULL,NULL, /* 00 */
|
||||||
|
NULL,NULL,NULL,NULL, /* 08 */
|
||||||
|
NULL,NULL,NULL,NULL, /* 10 */
|
||||||
|
NULL,NULL,NULL,NULL, /* 18 */
|
||||||
|
"GSYM","FNAME","FUN","STSYM", /* 20 */
|
||||||
|
"LCSYM","MAIN","ROSYM","PC", /* 28 */
|
||||||
|
NULL,"NSYMS","NOMAP",NULL, /* 30 */
|
||||||
|
"OBJ",NULL,"OPT",NULL, /* 38 */
|
||||||
|
"RSYM","M2C","SLINE","DSLINE", /* 40 */
|
||||||
|
"BSLINE","DEFD","FLINE",NULL, /* 48 */
|
||||||
|
"EHDECL",NULL,"CATCH",NULL, /* 50 */
|
||||||
|
NULL,NULL,NULL,NULL, /* 58 */
|
||||||
|
"SSYM","ENDM","SO",NULL, /* 60 */
|
||||||
|
NULL,NULL,NULL,NULL, /* 68 */
|
||||||
|
NULL,NULL,NULL,NULL, /* 70 */
|
||||||
|
NULL,NULL,NULL,NULL, /* 78 */
|
||||||
|
"LSYM","BINCL","SOL",NULL, /* 80 */
|
||||||
|
NULL,NULL,NULL,NULL, /* 88 */
|
||||||
|
NULL,NULL,NULL,NULL, /* 90 */
|
||||||
|
NULL,NULL,NULL,NULL, /* 98 */
|
||||||
|
"PSYM","EINCL","ENTRY",NULL, /* a0 */
|
||||||
|
NULL,NULL,NULL,NULL, /* a8 */
|
||||||
|
NULL,NULL,NULL,NULL, /* b0 */
|
||||||
|
NULL,NULL,NULL,NULL, /* b8 */
|
||||||
|
"LBRAC","EXCL","SCOPE",NULL, /* c0 */
|
||||||
|
NULL,NULL,NULL,NULL, /* c8 */
|
||||||
|
NULL,NULL,NULL,NULL, /* d0 */
|
||||||
|
NULL,NULL,NULL,NULL, /* d8 */
|
||||||
|
"RBRAC","BCOMM","ECOMM",NULL, /* e0 */
|
||||||
|
"ECOML","WITH",NULL,NULL, /* e8 */
|
||||||
|
"NBTEXT","NBDATA","NBBSS","NBSTS", /* f0 */
|
||||||
|
"NBLCS",NULL,NULL,NULL /* f8 */
|
||||||
|
};
|
||||||
|
|
||||||
|
void dump_stabs(const void* pv_stabs, unsigned szstabs, const char* stabstr, unsigned szstr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int nstab;
|
||||||
|
const char* ptr;
|
||||||
|
char* stabbuff;
|
||||||
|
unsigned int stabbufflen;
|
||||||
|
const struct stab_nlist* stab_ptr = pv_stabs;
|
||||||
|
const char* strs_end;
|
||||||
|
char n_buffer[16];
|
||||||
|
|
||||||
|
nstab = szstabs / sizeof(struct stab_nlist);
|
||||||
|
strs_end = stabstr + szstr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate a buffer into which we can build stab strings for cases
|
||||||
|
* where the stab is continued over multiple lines.
|
||||||
|
*/
|
||||||
|
stabbufflen = 65536;
|
||||||
|
stabbuff = malloc(stabbufflen);
|
||||||
|
|
||||||
|
stabbuff[0] = '\0';
|
||||||
|
|
||||||
|
printf("#Sym n_type n_othr n_desc n_value n_strx String\n");
|
||||||
|
|
||||||
|
for (i = 0; i < nstab; i++, stab_ptr++)
|
||||||
|
{
|
||||||
|
ptr = stabstr + stab_ptr->n_un.n_strx;
|
||||||
|
if ((ptr > strs_end) || (ptr + strlen(ptr) > strs_end))
|
||||||
|
{
|
||||||
|
ptr = "[[*** bad string ***]]";
|
||||||
|
}
|
||||||
|
else if (ptr[strlen(ptr) - 1] == '\\')
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Indicates continuation. Append this to the buffer, and go onto the
|
||||||
|
* next record. Repeat the process until we find a stab without the
|
||||||
|
* '/' character, as this indicates we have the whole thing.
|
||||||
|
*/
|
||||||
|
unsigned len = strlen(ptr);
|
||||||
|
if (strlen(stabbuff) + len > stabbufflen)
|
||||||
|
{
|
||||||
|
stabbufflen += 65536;
|
||||||
|
stabbuff = realloc(stabbuff, stabbufflen);
|
||||||
|
}
|
||||||
|
strncat(stabbuff, ptr, len - 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (stabbuff[0] != '\0')
|
||||||
|
{
|
||||||
|
strcat(stabbuff, ptr);
|
||||||
|
ptr = stabbuff;
|
||||||
|
}
|
||||||
|
if ((stab_ptr->n_type & 1) || !stabs_defs[stab_ptr->n_type / 2])
|
||||||
|
sprintf(n_buffer, "<0x%02x>", stab_ptr->n_type);
|
||||||
|
else
|
||||||
|
sprintf(n_buffer, "%-6s", stabs_defs[stab_ptr->n_type / 2]);
|
||||||
|
printf("%4d %s %-8x % 6d %-8lx %-6lx %s\n",
|
||||||
|
i, n_buffer, stab_ptr->n_other, stab_ptr->n_desc, stab_ptr->n_value,
|
||||||
|
stab_ptr->n_un.n_strx, ptr);
|
||||||
|
}
|
||||||
|
free(stabbuff);
|
||||||
|
}
|
||||||
|
|
|
@ -192,6 +192,11 @@ static void do_dumpsect (const char* arg)
|
||||||
globals.dumpsect = arg;
|
globals.dumpsect = arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void do_rawdebug (void)
|
||||||
|
{
|
||||||
|
globals.do_debug = 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void do_dumpall(void)
|
static void do_dumpall(void)
|
||||||
{
|
{
|
||||||
globals.do_dumpheader = 1;
|
globals.do_dumpheader = 1;
|
||||||
|
@ -228,6 +233,7 @@ static const struct my_option option_table[] = {
|
||||||
{"dump", DUMP, 0, do_dump, "dump <mod> Dumps the content of the module (dll, exe...) named <mod>"},
|
{"dump", DUMP, 0, do_dump, "dump <mod> Dumps the content of the module (dll, exe...) named <mod>"},
|
||||||
{"-C", DUMP, 0, do_symdmngl, "-C Turns on symbol demangling"},
|
{"-C", DUMP, 0, do_symdmngl, "-C Turns on symbol demangling"},
|
||||||
{"-f", DUMP, 0, do_dumphead, "-f Dumps file header information"},
|
{"-f", DUMP, 0, do_dumphead, "-f Dumps file header information"},
|
||||||
|
{"-G", DUMP, 0, do_rawdebug, "-G Dumps raw debug information"},
|
||||||
{"-j", DUMP, 1, do_dumpsect, "-j sect_name Dumps only the content of section sect_name (import, export, debug, resource, tls)"},
|
{"-j", DUMP, 1, do_dumpsect, "-j sect_name Dumps only the content of section sect_name (import, export, debug, resource, tls)"},
|
||||||
{"-x", DUMP, 0, do_dumpall, "-x Dumps everything"},
|
{"-x", DUMP, 0, do_dumpall, "-x Dumps everything"},
|
||||||
{"emf", EMF, 0, do_dumpemf, "emf Dumps an Enhanced Meta File"},
|
{"emf", EMF, 0, do_dumpemf, "emf Dumps an Enhanced Meta File"},
|
||||||
|
|
|
@ -1076,6 +1076,36 @@ static void dump_dir_resource(void)
|
||||||
printf( "\n\n" );
|
printf( "\n\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dump_debug(void)
|
||||||
|
{
|
||||||
|
const char* stabs = NULL;
|
||||||
|
unsigned szstabs = 0;
|
||||||
|
const char* stabstr = NULL;
|
||||||
|
unsigned szstr = 0;
|
||||||
|
unsigned i;
|
||||||
|
const IMAGE_SECTION_HEADER* sectHead;
|
||||||
|
|
||||||
|
sectHead = (const IMAGE_SECTION_HEADER*)
|
||||||
|
((const char*)PE_nt_headers + sizeof(DWORD) +
|
||||||
|
sizeof(IMAGE_FILE_HEADER) + PE_nt_headers->FileHeader.SizeOfOptionalHeader);
|
||||||
|
|
||||||
|
for (i = 0; i < PE_nt_headers->FileHeader.NumberOfSections; i++, sectHead++)
|
||||||
|
{
|
||||||
|
if (!strcmp((const char *)sectHead->Name, ".stab"))
|
||||||
|
{
|
||||||
|
stabs = RVA(sectHead->VirtualAddress, sectHead->Misc.VirtualSize);
|
||||||
|
szstabs = sectHead->Misc.VirtualSize;
|
||||||
|
}
|
||||||
|
if (!strncmp((const char *)sectHead->Name, ".stabstr", 8))
|
||||||
|
{
|
||||||
|
stabstr = RVA(sectHead->VirtualAddress, sectHead->Misc.VirtualSize);
|
||||||
|
szstr = sectHead->Misc.VirtualSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (stabs && stabstr)
|
||||||
|
dump_stabs(stabs, szstabs, stabstr, szstr);
|
||||||
|
}
|
||||||
|
|
||||||
void pe_dump(const void* pmt)
|
void pe_dump(const void* pmt)
|
||||||
{
|
{
|
||||||
int all = (globals.dumpsect != NULL) && strcmp(globals.dumpsect, "ALL") == 0;
|
int all = (globals.dumpsect != NULL) && strcmp(globals.dumpsect, "ALL") == 0;
|
||||||
|
@ -1118,6 +1148,8 @@ void pe_dump(const void* pmt)
|
||||||
dump_dir_reloc();
|
dump_dir_reloc();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
if (globals.do_debug)
|
||||||
|
dump_debug();
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct _dll_symbol {
|
typedef struct _dll_symbol {
|
||||||
|
|
|
@ -123,6 +123,7 @@ typedef struct __globals
|
||||||
/* Options: dump mode */
|
/* Options: dump mode */
|
||||||
int do_demangle; /* -d */
|
int do_demangle; /* -d */
|
||||||
int do_dumpheader; /* -f */
|
int do_dumpheader; /* -f */
|
||||||
|
int do_debug; /* -G == 1, -g == 2 */
|
||||||
|
|
||||||
/* Option arguments: spec mode */
|
/* Option arguments: spec mode */
|
||||||
int start_ordinal; /* -s */
|
int start_ordinal; /* -s */
|
||||||
|
@ -238,6 +239,8 @@ void ne_dump( const void *exe, size_t exe_size );
|
||||||
void le_dump( const void *exe, size_t exe_size );
|
void le_dump( const void *exe, size_t exe_size );
|
||||||
void mdmp_dump( void );
|
void mdmp_dump( void );
|
||||||
|
|
||||||
|
void dump_stabs(const void* pv_stabs, unsigned szstabs, const char* stabstr, unsigned szstr);
|
||||||
|
|
||||||
FILE *open_file (const char *name, const char *ext, const char *mode);
|
FILE *open_file (const char *name, const char *ext, const char *mode);
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
|
|
|
@ -80,6 +80,9 @@ Dumps everything.
|
||||||
This command prints all available information about the
|
This command prints all available information about the
|
||||||
file. You may wish to pipe the output through more/less or
|
file. You may wish to pipe the output through more/less or
|
||||||
into a file, since a lot of output will be produced.
|
into a file, since a lot of output will be produced.
|
||||||
|
.IP \fB-G\fR
|
||||||
|
Dumps contents of debug section if any (for now, only stabs
|
||||||
|
information is supported).
|
||||||
.PP
|
.PP
|
||||||
.B Spec mode:
|
.B Spec mode:
|
||||||
.IP \fI<dll>\fR
|
.IP \fI<dll>\fR
|
||||||
|
|
Loading…
Reference in New Issue