winedump: Add dumping of the .apiset PE section.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
4a5a3ba702
commit
6f1fd16f92
|
@ -207,7 +207,8 @@ static const struct my_option option_table[] = {
|
||||||
{"-C", DUMP, 0, do_symdmngl, "-C Turn on symbol demangling"},
|
{"-C", DUMP, 0, do_symdmngl, "-C Turn on symbol demangling"},
|
||||||
{"-f", DUMP, 0, do_dumphead, "-f Dump file header information"},
|
{"-f", DUMP, 0, do_dumphead, "-f Dump file header information"},
|
||||||
{"-G", DUMP, 0, do_rawdebug, "-G Dump raw debug information"},
|
{"-G", DUMP, 0, do_rawdebug, "-G Dump raw debug information"},
|
||||||
{"-j", DUMP, 1, do_dumpsect, "-j <sect_name> Dump only the content of section 'sect_name' (import, export, debug, resource, tls, loadcfg, clr, reloc, except)"},
|
{"-j", DUMP, 1, do_dumpsect, "-j <sect_name> Dump only the content of section 'sect_name'\n"
|
||||||
|
" (import, export, debug, resource, tls, loadcfg, clr, reloc, except, apiset)"},
|
||||||
{"-t", DUMP, 0, do_symtable, "-t Dump symbol table"},
|
{"-t", DUMP, 0, do_symtable, "-t Dump symbol table"},
|
||||||
{"-x", DUMP, 0, do_dumpall, "-x Dump everything"},
|
{"-x", DUMP, 0, do_dumpall, "-x Dump everything"},
|
||||||
{"sym", DMGL, 0, do_demangle, "sym <sym> Demangle C++ symbol <sym> and exit"},
|
{"sym", DMGL, 0, do_demangle, "sym <sym> Demangle C++ symbol <sym> and exit"},
|
||||||
|
@ -232,22 +233,22 @@ void do_usage (const char *arg)
|
||||||
const struct my_option *opt;
|
const struct my_option *opt;
|
||||||
printf ("Usage: winedump [-h | sym <sym> | spec <dll> | dump <file>]\n");
|
printf ("Usage: winedump [-h | sym <sym> | spec <dll> | dump <file>]\n");
|
||||||
printf ("Mode options (can be put as the mode (sym/spec/dump...) is declared):\n");
|
printf ("Mode options (can be put as the mode (sym/spec/dump...) is declared):\n");
|
||||||
printf ("\tWhen used in --help mode\n");
|
printf (" When used in --help mode\n");
|
||||||
for (opt = option_table; opt->name; opt++)
|
for (opt = option_table; opt->name; opt++)
|
||||||
if (opt->mode == NONE)
|
if (opt->mode == NONE)
|
||||||
printf ("\t %s\n", opt->usage);
|
printf (" %s\n", opt->usage);
|
||||||
printf ("\tWhen used in sym mode\n");
|
printf (" When used in sym mode\n");
|
||||||
for (opt = option_table; opt->name; opt++)
|
for (opt = option_table; opt->name; opt++)
|
||||||
if (opt->mode == DMGL)
|
if (opt->mode == DMGL)
|
||||||
printf ("\t %s\n", opt->usage);
|
printf (" %s\n", opt->usage);
|
||||||
printf ("\tWhen used in spec mode\n");
|
printf (" When used in spec mode\n");
|
||||||
for (opt = option_table; opt->name; opt++)
|
for (opt = option_table; opt->name; opt++)
|
||||||
if (opt->mode == SPEC)
|
if (opt->mode == SPEC)
|
||||||
printf ("\t %s\n", opt->usage);
|
printf (" %s\n", opt->usage);
|
||||||
printf ("\tWhen used in dump mode\n");
|
printf (" When used in dump mode\n");
|
||||||
for (opt = option_table; opt->name; opt++)
|
for (opt = option_table; opt->name; opt++)
|
||||||
if (opt->mode == DUMP)
|
if (opt->mode == DUMP)
|
||||||
printf ("\t %s\n", opt->usage);
|
printf (" %s\n", opt->usage);
|
||||||
|
|
||||||
puts ("");
|
puts ("");
|
||||||
exit (1);
|
exit (1);
|
||||||
|
|
|
@ -491,6 +491,111 @@ static void dump_sections(const void *base, const void* addr, unsigned num_sect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *get_str( char *buffer, unsigned int rva, unsigned int len )
|
||||||
|
{
|
||||||
|
const WCHAR *wstr = PRD( rva, len );
|
||||||
|
char *ret = buffer;
|
||||||
|
|
||||||
|
len /= sizeof(WCHAR);
|
||||||
|
while (len--) *buffer++ = *wstr++;
|
||||||
|
*buffer = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dump_section_apiset(void)
|
||||||
|
{
|
||||||
|
const IMAGE_SECTION_HEADER *sect = IMAGE_FIRST_SECTION(PE_nt_headers);
|
||||||
|
const UINT *ptr, *entry, *value, *hash;
|
||||||
|
unsigned int i, j, count, val_count, rva;
|
||||||
|
char buffer[128];
|
||||||
|
|
||||||
|
for (i = 0; i < PE_nt_headers->FileHeader.NumberOfSections; i++, sect++)
|
||||||
|
{
|
||||||
|
if (strncmp( (const char *)sect->Name, ".apiset", 8 )) continue;
|
||||||
|
rva = sect->PointerToRawData;
|
||||||
|
ptr = PRD( rva, sizeof(*ptr) );
|
||||||
|
printf( "ApiSet section:\n" );
|
||||||
|
switch (ptr[0]) /* version */
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
printf( " Version: %u\n", ptr[0] );
|
||||||
|
printf( " Count: %08x\n", ptr[1] );
|
||||||
|
count = ptr[1];
|
||||||
|
if (!(entry = PRD( rva + 2 * sizeof(*ptr), count * 3 * sizeof(*entry) ))) break;
|
||||||
|
for (i = 0; i < count; i++, entry += 3)
|
||||||
|
{
|
||||||
|
printf( " %s ->", get_str( buffer, rva + entry[0], entry[1] ));
|
||||||
|
if (!(value = PRD( rva + entry[2], sizeof(*value) ))) break;
|
||||||
|
val_count = *value++;
|
||||||
|
for (j = 0; j < val_count; j++, value += 4)
|
||||||
|
{
|
||||||
|
putchar( ' ' );
|
||||||
|
if (value[1]) printf( "%s:", get_str( buffer, rva + value[0], value[1] ));
|
||||||
|
printf( "%s", get_str( buffer, rva + value[2], value[3] ));
|
||||||
|
}
|
||||||
|
printf( "\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
printf( " Version: %u\n", ptr[0] );
|
||||||
|
printf( " Size: %08x\n", ptr[1] );
|
||||||
|
printf( " Flags: %08x\n", ptr[2] );
|
||||||
|
printf( " Count: %08x\n", ptr[3] );
|
||||||
|
count = ptr[3];
|
||||||
|
if (!(entry = PRD( rva + 4 * sizeof(*ptr), count * 6 * sizeof(*entry) ))) break;
|
||||||
|
for (i = 0; i < count; i++, entry += 6)
|
||||||
|
{
|
||||||
|
printf( " %08x %s ->", entry[0], get_str( buffer, rva + entry[1], entry[2] ));
|
||||||
|
if (!(value = PRD( rva + entry[5], sizeof(*value) ))) break;
|
||||||
|
value++; /* flags */
|
||||||
|
val_count = *value++;
|
||||||
|
for (j = 0; j < val_count; j++, value += 5)
|
||||||
|
{
|
||||||
|
putchar( ' ' );
|
||||||
|
if (value[1]) printf( "%s:", get_str( buffer, rva + value[1], value[2] ));
|
||||||
|
printf( "%s", get_str( buffer, rva + value[3], value[4] ));
|
||||||
|
}
|
||||||
|
printf( "\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
printf( " Version: %u\n", ptr[0] );
|
||||||
|
printf( " Size: %08x\n", ptr[1] );
|
||||||
|
printf( " Flags: %08x\n", ptr[2] );
|
||||||
|
printf( " Count: %08x\n", ptr[3] );
|
||||||
|
printf( " EntryOffset: %08x\n", ptr[4] );
|
||||||
|
printf( " HashOffset: %08x\n", ptr[5] );
|
||||||
|
printf( " HashFactor: %08x\n", ptr[6] );
|
||||||
|
count = ptr[3];
|
||||||
|
if (!(entry = PRD( rva + ptr[4], count * 6 * sizeof(*entry) ))) break;
|
||||||
|
for (i = 0; i < count; i++, entry += 6)
|
||||||
|
{
|
||||||
|
printf( " %08x %s ->", entry[0], get_str( buffer, rva + entry[1], entry[2] ));
|
||||||
|
if (!(value = PRD( rva + entry[4], entry[5] * 5 * sizeof(*value) ))) break;
|
||||||
|
for (j = 0; j < entry[5]; j++, value += 5)
|
||||||
|
{
|
||||||
|
putchar( ' ' );
|
||||||
|
if (value[1]) printf( "%s:", get_str( buffer, rva + value[1], value[2] ));
|
||||||
|
printf( "%s", get_str( buffer, rva + value[3], value[4] ));
|
||||||
|
}
|
||||||
|
printf( "\n" );
|
||||||
|
}
|
||||||
|
printf( " Hash table:\n" );
|
||||||
|
if (!(hash = PRD( rva + ptr[5], count * 2 * sizeof(*hash) ))) break;
|
||||||
|
for (i = 0; i < count; i++, hash += 2)
|
||||||
|
{
|
||||||
|
entry = PRD( rva + ptr[4] + hash[1] * 6 * sizeof(*entry), 6 * sizeof(*entry) );
|
||||||
|
printf( " %08x -> %s\n", hash[0], get_str( buffer, rva + entry[1], entry[3] ));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf( "*** Unknown version %u\n", ptr[0] );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void dump_dir_exported_functions(void)
|
static void dump_dir_exported_functions(void)
|
||||||
{
|
{
|
||||||
unsigned int size = 0;
|
unsigned int size = 0;
|
||||||
|
@ -2336,6 +2441,8 @@ void pe_dump(void)
|
||||||
dump_dir_reloc();
|
dump_dir_reloc();
|
||||||
if (all || !strcmp(globals.dumpsect, "except"))
|
if (all || !strcmp(globals.dumpsect, "except"))
|
||||||
dump_dir_exceptions();
|
dump_dir_exceptions();
|
||||||
|
if (all || !strcmp(globals.dumpsect, "apiset"))
|
||||||
|
dump_section_apiset();
|
||||||
}
|
}
|
||||||
if (globals.do_symbol_table)
|
if (globals.do_symbol_table)
|
||||||
dump_symbol_table();
|
dump_symbol_table();
|
||||||
|
|
|
@ -70,12 +70,12 @@ Dumps file header information.
|
||||||
This option dumps only the standard PE header structures,
|
This option dumps only the standard PE header structures,
|
||||||
along with the COFF sections available in the file.
|
along with the COFF sections available in the file.
|
||||||
.IP "\fB-j \fIdir_name\fR"
|
.IP "\fB-j \fIdir_name\fR"
|
||||||
Dumps only the content of directory \fIdir_name\fR, for files
|
Dumps only the content of directory \fIdir_name\fR, for files which
|
||||||
which header points to directories.
|
header points to directories. For PE files, the \fBimport\fR,
|
||||||
For PE files, currently the import, export, debug, resource,
|
\fBexport\fR, \fBdebug\fR, \fBresource\fR, \fBtls\fR, \fBloadcfg\fR,
|
||||||
tls and clr directories are implemented.
|
\fBclr\fR, \fBreloc\fR and \fBexcept\fR directories, as well as the
|
||||||
For NE files, currently the export and resource directories are
|
\fBapiset\fR section, are implemented. For NE files, the \fBexport\fR
|
||||||
implemented.
|
and \fBresource\fR directories are implemented.
|
||||||
.IP \fB-x\fR
|
.IP \fB-x\fR
|
||||||
Dumps everything.
|
Dumps everything.
|
||||||
This command prints all available information (including all
|
This command prints all available information (including all
|
||||||
|
|
Loading…
Reference in New Issue