Module: wine Branch: master Commit: 8ad9457fca96c0070e54156d84017030e850a706 URL: http://source.winehq.org/git/wine.git/?a=commit;h=8ad9457fca96c0070e54156d84...
Author: Alexandre Julliard julliard@winehq.org Date: Wed May 6 12:06:20 2009 +0200
winedump: Add dumping of x86_64 exception tables.
---
tools/winedump/pe.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 173 insertions(+), 0 deletions(-)
diff --git a/tools/winedump/pe.c b/tools/winedump/pe.c index 491228f..bbe4d56 100644 --- a/tools/winedump/pe.c +++ b/tools/winedump/pe.c @@ -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();