mirror of
git://source.winehq.org/git/wine.git
synced 2024-11-02 11:37:26 +00:00
winedump: Added -G option to dump raw stabs information from PE files.
This commit is contained in:
parent
9766dd1a5f
commit
c2f1240a53
5 changed files with 157 additions and 0 deletions
|
@ -582,3 +582,116 @@ 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");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void do_rawdebug (void)
|
||||
{
|
||||
globals.do_debug = 1;
|
||||
}
|
||||
|
||||
static void do_dumpall(void)
|
||||
{
|
||||
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>"},
|
||||
{"-C", DUMP, 0, do_symdmngl, "-C Turns on symbol demangling"},
|
||||
{"-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)"},
|
||||
{"-x", DUMP, 0, do_dumpall, "-x Dumps everything"},
|
||||
{"emf", EMF, 0, do_dumpemf, "emf Dumps an Enhanced Meta File"},
|
||||
|
|
|
@ -1076,6 +1076,36 @@ static void dump_dir_resource(void)
|
|||
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)
|
||||
{
|
||||
int all = (globals.dumpsect != NULL) && strcmp(globals.dumpsect, "ALL") == 0;
|
||||
|
@ -1118,6 +1148,8 @@ void pe_dump(const void* pmt)
|
|||
dump_dir_reloc();
|
||||
#endif
|
||||
}
|
||||
if (globals.do_debug)
|
||||
dump_debug();
|
||||
}
|
||||
|
||||
typedef struct _dll_symbol {
|
||||
|
|
|
@ -123,6 +123,7 @@ typedef struct __globals
|
|||
/* Options: dump mode */
|
||||
int do_demangle; /* -d */
|
||||
int do_dumpheader; /* -f */
|
||||
int do_debug; /* -G == 1, -g == 2 */
|
||||
|
||||
/* Option arguments: spec mode */
|
||||
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 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);
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
|
|
@ -80,6 +80,9 @@ Dumps everything.
|
|||
This command prints all available information about the
|
||||
file. You may wish to pipe the output through more/less or
|
||||
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
|
||||
.B Spec mode:
|
||||
.IP \fI<dll>\fR
|
||||
|
|
Loading…
Reference in a new issue