winedump: Add dumping of the .apiset PE section.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2022-02-18 10:00:55 +01:00
parent 4a5a3ba702
commit 6f1fd16f92
3 changed files with 123 additions and 15 deletions

View File

@ -207,7 +207,8 @@ static const struct my_option option_table[] = {
{"-C", DUMP, 0, do_symdmngl, "-C Turn on symbol demangling"},
{"-f", DUMP, 0, do_dumphead, "-f Dump file header 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"},
{"-x", DUMP, 0, do_dumpall, "-x Dump everything"},
{"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;
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 ("\tWhen used in --help mode\n");
printf (" When used in --help mode\n");
for (opt = option_table; opt->name; opt++)
if (opt->mode == NONE)
printf ("\t %s\n", opt->usage);
printf ("\tWhen used in sym mode\n");
printf (" %s\n", opt->usage);
printf (" When used in sym mode\n");
for (opt = option_table; opt->name; opt++)
if (opt->mode == DMGL)
printf ("\t %s\n", opt->usage);
printf ("\tWhen used in spec mode\n");
printf (" %s\n", opt->usage);
printf (" When used in spec mode\n");
for (opt = option_table; opt->name; opt++)
if (opt->mode == SPEC)
printf ("\t %s\n", opt->usage);
printf ("\tWhen used in dump mode\n");
printf (" %s\n", opt->usage);
printf (" When used in dump mode\n");
for (opt = option_table; opt->name; opt++)
if (opt->mode == DUMP)
printf ("\t %s\n", opt->usage);
printf (" %s\n", opt->usage);
puts ("");
exit (1);

View File

@ -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)
{
unsigned int size = 0;
@ -2336,6 +2441,8 @@ void pe_dump(void)
dump_dir_reloc();
if (all || !strcmp(globals.dumpsect, "except"))
dump_dir_exceptions();
if (all || !strcmp(globals.dumpsect, "apiset"))
dump_section_apiset();
}
if (globals.do_symbol_table)
dump_symbol_table();

View File

@ -70,12 +70,12 @@ Dumps file header information.
This option dumps only the standard PE header structures,
along with the COFF sections available in the file.
.IP "\fB-j \fIdir_name\fR"
Dumps only the content of directory \fIdir_name\fR, for files
which header points to directories.
For PE files, currently the import, export, debug, resource,
tls and clr directories are implemented.
For NE files, currently the export and resource directories are
implemented.
Dumps only the content of directory \fIdir_name\fR, for files which
header points to directories. For PE files, the \fBimport\fR,
\fBexport\fR, \fBdebug\fR, \fBresource\fR, \fBtls\fR, \fBloadcfg\fR,
\fBclr\fR, \fBreloc\fR and \fBexcept\fR directories, as well as the
\fBapiset\fR section, are implemented. For NE files, the \fBexport\fR
and \fBresource\fR directories are implemented.
.IP \fB-x\fR
Dumps everything.
This command prints all available information (including all