winedump: Add dumping of x86_64 exception tables.
This commit is contained in:
parent
b03d07dff4
commit
8ad9457fca
|
@ -520,6 +520,177 @@ static void dump_dir_exported_functions(void)
|
|||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
struct runtime_function
|
||||
{
|
||||
DWORD BeginAddress;
|
||||
DWORD EndAddress;
|
||||
DWORD UnwindData;
|
||||
};
|
||||
|
||||
union handler_data
|
||||
{
|
||||
struct runtime_function chain;
|
||||
DWORD handler;
|
||||
};
|
||||
|
||||
struct opcode
|
||||
{
|
||||
BYTE offset;
|
||||
BYTE code : 4;
|
||||
BYTE info : 4;
|
||||
};
|
||||
|
||||
struct unwind_info
|
||||
{
|
||||
BYTE version : 3;
|
||||
BYTE flags : 5;
|
||||
BYTE prolog;
|
||||
BYTE count;
|
||||
BYTE frame_reg : 4;
|
||||
BYTE frame_offset : 4;
|
||||
struct opcode opcodes[1]; /* count entries */
|
||||
/* followed by union handler_data */
|
||||
};
|
||||
|
||||
#define UWOP_PUSH_NONVOL 0
|
||||
#define UWOP_ALLOC_LARGE 1
|
||||
#define UWOP_ALLOC_SMALL 2
|
||||
#define UWOP_SET_FPREG 3
|
||||
#define UWOP_SAVE_NONVOL 4
|
||||
#define UWOP_SAVE_NONVOL_FAR 5
|
||||
#define UWOP_SAVE_XMM128 8
|
||||
#define UWOP_SAVE_XMM128_FAR 9
|
||||
#define UWOP_PUSH_MACHFRAME 10
|
||||
|
||||
#define UNW_FLAG_EHANDLER 1
|
||||
#define UNW_FLAG_UHANDLER 2
|
||||
#define UNW_FLAG_CHAININFO 4
|
||||
|
||||
static void dump_x86_64_unwind_info( const struct runtime_function *function )
|
||||
{
|
||||
static const char * const reg_names[16] =
|
||||
{ "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
|
||||
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" };
|
||||
|
||||
union handler_data *handler_data;
|
||||
const struct unwind_info *info;
|
||||
unsigned int i, count;
|
||||
|
||||
printf( "\nFunction %08x-%08x:\n", function->BeginAddress, function->EndAddress );
|
||||
if (function->UnwindData & 1)
|
||||
{
|
||||
const struct runtime_function *next = RVA( function->UnwindData & ~1, sizeof(*next) );
|
||||
printf( " -> function %08x-%08x\n", next->BeginAddress, next->EndAddress );
|
||||
return;
|
||||
}
|
||||
info = RVA( function->UnwindData, sizeof(*info) );
|
||||
|
||||
printf( " unwind info at %08x\n", function->UnwindData );
|
||||
if (info->version != 1)
|
||||
{
|
||||
printf( " *** unknown version %u\n", info->version );
|
||||
return;
|
||||
}
|
||||
printf( " flags %x", info->flags );
|
||||
if (info->flags & UNW_FLAG_EHANDLER) printf( " EHANDLER" );
|
||||
if (info->flags & UNW_FLAG_UHANDLER) printf( " UHANDLER" );
|
||||
if (info->flags & UNW_FLAG_CHAININFO) printf( " CHAININFO" );
|
||||
printf( "\n prolog 0x%x bytes\n", info->prolog );
|
||||
|
||||
if (info->frame_reg)
|
||||
printf( " frame register %s offset 0x%x(%%rsp)\n",
|
||||
reg_names[info->frame_reg], info->frame_offset * 16 );
|
||||
|
||||
for (i = 0; i < info->count; i++)
|
||||
{
|
||||
printf( " 0x%02x: ", info->opcodes[i].offset );
|
||||
switch (info->opcodes[i].code)
|
||||
{
|
||||
case UWOP_PUSH_NONVOL:
|
||||
printf( "push %%%s\n", reg_names[info->opcodes[i].info] );
|
||||
break;
|
||||
case UWOP_ALLOC_LARGE:
|
||||
if (info->opcodes[i].info)
|
||||
{
|
||||
count = *(DWORD *)&info->opcodes[i+1];
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = *(USHORT *)&info->opcodes[i+1] * 8;
|
||||
i++;
|
||||
}
|
||||
printf( "sub $0x%x,%%rsp\n", count );
|
||||
break;
|
||||
case UWOP_ALLOC_SMALL:
|
||||
count = (info->opcodes[i].info + 1) * 8;
|
||||
printf( "sub $0x%x,%%rsp\n", count );
|
||||
break;
|
||||
case UWOP_SET_FPREG:
|
||||
printf( "lea 0x%x(%%rsp),%s\n",
|
||||
info->frame_offset * 16, reg_names[info->frame_reg] );
|
||||
break;
|
||||
case UWOP_SAVE_NONVOL:
|
||||
count = *(USHORT *)&info->opcodes[i+1] * 8;
|
||||
printf( "mov %%%s,0x%x(%%rsp)\n", reg_names[info->opcodes[i].info], count );
|
||||
i++;
|
||||
break;
|
||||
case UWOP_SAVE_NONVOL_FAR:
|
||||
count = *(DWORD *)&info->opcodes[i+1];
|
||||
printf( "mov %%%s,0x%x(%%rsp)\n", reg_names[info->opcodes[i].info], count );
|
||||
i += 2;
|
||||
break;
|
||||
case UWOP_SAVE_XMM128:
|
||||
count = *(USHORT *)&info->opcodes[i+1] * 16;
|
||||
printf( "movaps %%xmm%u,0x%x(%%rsp)\n", info->opcodes[i].info, count );
|
||||
i++;
|
||||
break;
|
||||
case UWOP_SAVE_XMM128_FAR:
|
||||
count = *(DWORD *)&info->opcodes[i+1];
|
||||
printf( "movaps %%xmm%u,0x%x(%%rsp)\n", info->opcodes[i].info, count );
|
||||
i += 2;
|
||||
break;
|
||||
case UWOP_PUSH_MACHFRAME:
|
||||
printf( "PUSH_MACHFRAME %u\n", info->opcodes[i].info );
|
||||
break;
|
||||
default:
|
||||
printf( "*** unknown code %u\n", info->opcodes[i].code );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
handler_data = (union handler_data *)&info->opcodes[(info->count + 1) & ~1];
|
||||
if (info->flags & UNW_FLAG_CHAININFO)
|
||||
{
|
||||
printf( " -> function %08x-%08x\n",
|
||||
handler_data->chain.BeginAddress, handler_data->chain.EndAddress );
|
||||
return;
|
||||
}
|
||||
if (info->flags & (UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER))
|
||||
printf( " handler %08x data at %08x\n", handler_data->handler,
|
||||
function->UnwindData + (char *)(&handler_data->handler + 1) - (char *)info );
|
||||
}
|
||||
|
||||
static void dump_dir_exceptions(void)
|
||||
{
|
||||
unsigned int i, size = 0;
|
||||
const struct runtime_function *funcs = get_dir_and_size(IMAGE_FILE_EXCEPTION_DIRECTORY, &size);
|
||||
const IMAGE_FILE_HEADER *file_header = &PE_nt_headers->FileHeader;
|
||||
|
||||
if (!funcs) return;
|
||||
|
||||
if (file_header->Machine == IMAGE_FILE_MACHINE_AMD64)
|
||||
{
|
||||
size /= sizeof(*funcs);
|
||||
printf( "Exception info (%u functions):\n", size );
|
||||
for (i = 0; i < size; i++) dump_x86_64_unwind_info( funcs + i );
|
||||
}
|
||||
else printf( "Exception information not supported for %s binaries\n",
|
||||
get_machine_str(file_header->Machine));
|
||||
}
|
||||
|
||||
|
||||
static void dump_image_thunk_data64(const IMAGE_THUNK_DATA64 *il)
|
||||
{
|
||||
/* FIXME: This does not properly handle large images */
|
||||
|
@ -1295,6 +1466,8 @@ void pe_dump(void)
|
|||
dump_dir_clr_header();
|
||||
if (all || !strcmp(globals.dumpsect, "reloc"))
|
||||
dump_dir_reloc();
|
||||
if (all || !strcmp(globals.dumpsect, "except"))
|
||||
dump_dir_exceptions();
|
||||
}
|
||||
if (globals.do_debug)
|
||||
dump_debug();
|
||||
|
|
Loading…
Reference in New Issue