winedump: Add dumping of x86_64 exception tables.

This commit is contained in:
Alexandre Julliard 2009-05-06 12:06:20 +02:00
parent b03d07dff4
commit 8ad9457fca
1 changed files with 173 additions and 0 deletions

View File

@ -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();