mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-03 01:01:44 +00:00
winedump: Dump exception data for known exception handlers.
This commit is contained in:
parent
bb8ef91f46
commit
02a6ad92ab
|
@ -931,6 +931,353 @@ struct unwind_info_epilogue_armnt
|
|||
#define UNW_FLAG_UHANDLER 2
|
||||
#define UNW_FLAG_CHAININFO 4
|
||||
|
||||
static void dump_c_exception_data( unsigned int rva )
|
||||
{
|
||||
unsigned int i;
|
||||
const struct
|
||||
{
|
||||
UINT count;
|
||||
struct
|
||||
{
|
||||
UINT begin;
|
||||
UINT end;
|
||||
UINT handler;
|
||||
UINT target;
|
||||
} rec[];
|
||||
} *table = RVA( rva, sizeof(*table) );
|
||||
|
||||
if (!table) return;
|
||||
printf( " C exception data at %08x count %u\n", rva, table->count );
|
||||
for (i = 0; i < table->count; i++)
|
||||
printf( " %u: %08x-%08x handler %08x target %08x\n", i,
|
||||
table->rec[i].begin, table->rec[i].end, table->rec[i].handler, table->rec[i].target );
|
||||
}
|
||||
|
||||
static void dump_cxx_exception_data( unsigned int rva, unsigned int func_rva )
|
||||
{
|
||||
unsigned int i, j, flags = 0;
|
||||
const unsigned int *ptr = RVA( rva, sizeof(*ptr) );
|
||||
|
||||
const struct
|
||||
{
|
||||
int prev;
|
||||
UINT handler;
|
||||
} *unwind_info;
|
||||
|
||||
const struct
|
||||
{
|
||||
int start;
|
||||
int end;
|
||||
int catch;
|
||||
int catchblock_count;
|
||||
UINT catchblock;
|
||||
} *tryblock;
|
||||
|
||||
const struct
|
||||
{
|
||||
UINT flags;
|
||||
UINT type_info;
|
||||
int offset;
|
||||
UINT handler;
|
||||
UINT frame;
|
||||
} *catchblock;
|
||||
|
||||
const struct
|
||||
{
|
||||
UINT ip;
|
||||
int state;
|
||||
} *ipmap;
|
||||
|
||||
const struct
|
||||
{
|
||||
UINT magic;
|
||||
UINT unwind_count;
|
||||
UINT unwind_table;
|
||||
UINT tryblock_count;
|
||||
UINT tryblock;
|
||||
UINT ipmap_count;
|
||||
UINT ipmap;
|
||||
int unwind_help;
|
||||
UINT expect_list;
|
||||
UINT flags;
|
||||
} *func;
|
||||
|
||||
if (!ptr || !*ptr) return;
|
||||
rva = *ptr;
|
||||
if (!(func = RVA( rva, sizeof(*func) ))) return;
|
||||
if (func->magic < 0x19930520 || func->magic > 0x19930522) return;
|
||||
if (func->magic > 0x19930521) flags = func->flags;
|
||||
printf( " C++ exception data at %08x magic %08x", rva, func->magic );
|
||||
if (flags & 1) printf( " sync" );
|
||||
if (flags & 4) printf( " noexcept" );
|
||||
printf( "\n" );
|
||||
printf( " unwind help %+d\n", func->unwind_help );
|
||||
if (func->magic > 0x19930520 && func->expect_list)
|
||||
printf( " expect_list %08x\n", func->expect_list );
|
||||
if (func->unwind_count)
|
||||
{
|
||||
printf( " unwind table at %08x count %u\n", func->unwind_table, func->unwind_count );
|
||||
if ((unwind_info = RVA( func->unwind_table, func->unwind_count * sizeof(*unwind_info) )))
|
||||
{
|
||||
for (i = 0; i < func->unwind_count; i++)
|
||||
printf( " %u: prev %d func %08x\n", i,
|
||||
unwind_info[i].prev, unwind_info[i].handler );
|
||||
}
|
||||
}
|
||||
if (func->tryblock_count)
|
||||
{
|
||||
printf( " try table at %08x count %u\n", func->tryblock, func->tryblock_count );
|
||||
if ((tryblock = RVA( func->tryblock, func->tryblock_count * sizeof(*tryblock) )))
|
||||
{
|
||||
for (i = 0; i < func->tryblock_count; i++)
|
||||
{
|
||||
catchblock = RVA( tryblock[i].catchblock, sizeof(*catchblock) );
|
||||
printf( " %d: start %d end %d catch %d count %u\n", i,
|
||||
tryblock[i].start, tryblock[i].end, tryblock[i].catch,
|
||||
tryblock[i].catchblock_count );
|
||||
for (j = 0; j < tryblock[i].catchblock_count; j++)
|
||||
{
|
||||
const char *type = "<none>";
|
||||
if (catchblock[j].type_info)
|
||||
{
|
||||
if (PE_nt_headers->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
|
||||
type = RVA( catchblock[j].type_info + 16, 1 );
|
||||
else
|
||||
type = RVA( catchblock[j].type_info + 8, 1 );
|
||||
}
|
||||
printf( " %d: flags %x offset %+d handler %08x frame %x type %s\n", j,
|
||||
catchblock[j].flags, catchblock[j].offset,
|
||||
catchblock[j].handler, catchblock[j].frame, type );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (func->ipmap_count)
|
||||
{
|
||||
printf( " ip map at %08x count %u\n", func->ipmap, func->ipmap_count );
|
||||
if ((ipmap = RVA( func->ipmap, func->ipmap_count * sizeof(*ipmap) )))
|
||||
{
|
||||
for (i = 0; i < func->ipmap_count; i++)
|
||||
printf( " %u: ip %08x state %d\n", i, ipmap[i].ip, ipmap[i].state );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static UINT v4_decode_uint( const BYTE **b )
|
||||
{
|
||||
UINT ret;
|
||||
const BYTE *p = *b;
|
||||
|
||||
if ((*p & 1) == 0)
|
||||
{
|
||||
ret = p[0] >> 1;
|
||||
p += 1;
|
||||
}
|
||||
else if ((*p & 3) == 1)
|
||||
{
|
||||
ret = (p[0] >> 2) + (p[1] << 6);
|
||||
p += 2;
|
||||
}
|
||||
else if ((*p & 7) == 3)
|
||||
{
|
||||
ret = (p[0] >> 3) + (p[1] << 5) + (p[2] << 13);
|
||||
p += 3;
|
||||
}
|
||||
else if ((*p & 15) == 7)
|
||||
{
|
||||
ret = (p[0] >> 4) + (p[1] << 4) + (p[2] << 12) + (p[3] << 20);
|
||||
p += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = 0;
|
||||
p += 5;
|
||||
}
|
||||
|
||||
*b = p;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static UINT v4_read_rva( const BYTE **b )
|
||||
{
|
||||
UINT ret = *(UINT *)*b;
|
||||
*b += sizeof(UINT);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define FUNC_DESCR_IS_CATCH 0x01
|
||||
#define FUNC_DESCR_IS_SEPARATED 0x02
|
||||
#define FUNC_DESCR_BBT 0x04
|
||||
#define FUNC_DESCR_UNWIND_MAP 0x08
|
||||
#define FUNC_DESCR_TRYBLOCK_MAP 0x10
|
||||
#define FUNC_DESCR_EHS 0x20
|
||||
#define FUNC_DESCR_NO_EXCEPT 0x40
|
||||
#define FUNC_DESCR_RESERVED 0x80
|
||||
|
||||
#define CATCHBLOCK_FLAGS 0x01
|
||||
#define CATCHBLOCK_TYPE_INFO 0x02
|
||||
#define CATCHBLOCK_OFFSET 0x04
|
||||
#define CATCHBLOCK_SEPARATED 0x08
|
||||
#define CATCHBLOCK_RET_ADDR_MASK 0x30
|
||||
#define CATCHBLOCK_RET_ADDR 0x10
|
||||
#define CATCHBLOCK_TWO_RET_ADDRS 0x20
|
||||
|
||||
static void dump_cxx_exception_data_v4( unsigned int rva, unsigned int func_rva )
|
||||
{
|
||||
const unsigned int *ptr = RVA( rva, sizeof(*ptr) );
|
||||
const BYTE *p;
|
||||
BYTE flags;
|
||||
UINT unwind_map = 0, tryblock_map = 0, ip_map, count, i, j, k;
|
||||
|
||||
if (!ptr || !*ptr) return;
|
||||
rva = *ptr;
|
||||
if (!(p = RVA( rva, 1 ))) return;
|
||||
flags = *p++;
|
||||
printf( " C++ v4 exception data at %08x", rva );
|
||||
if (flags & FUNC_DESCR_BBT) printf( " bbt %08x", v4_decode_uint( &p ));
|
||||
if (flags & FUNC_DESCR_UNWIND_MAP) unwind_map = v4_read_rva( &p );
|
||||
if (flags & FUNC_DESCR_TRYBLOCK_MAP) tryblock_map = v4_read_rva( &p );
|
||||
ip_map = v4_read_rva(&p);
|
||||
if (flags & FUNC_DESCR_IS_CATCH) printf( " frame %08x", v4_decode_uint( &p ));
|
||||
if (flags & FUNC_DESCR_EHS) printf( " sync" );
|
||||
if (flags & FUNC_DESCR_NO_EXCEPT) printf( " noexcept" );
|
||||
printf( "\n" );
|
||||
|
||||
if (unwind_map)
|
||||
{
|
||||
int *offsets;
|
||||
const BYTE *start, *p = RVA( unwind_map, 1 );
|
||||
count = v4_decode_uint( &p );
|
||||
printf( " unwind map at %08x count %u\n", unwind_map, count );
|
||||
offsets = calloc( count, sizeof(*offsets) );
|
||||
start = p;
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
UINT handler, object, type;
|
||||
int offset = p - start, off, prev = -2;
|
||||
|
||||
offsets[i] = offset;
|
||||
type = v4_decode_uint( &p );
|
||||
off = (type >> 2);
|
||||
if (off > offset) prev = -1;
|
||||
else for (j = 0; j < i; j++) if (offsets[j] == offset - off) prev = j;
|
||||
|
||||
switch (type & 3)
|
||||
{
|
||||
case 0:
|
||||
printf( " %u: prev %d no handler\n", i, prev );
|
||||
break;
|
||||
case 1:
|
||||
handler = v4_read_rva( &p );
|
||||
object = v4_decode_uint( &p );
|
||||
printf( " %u: prev %d dtor obj handler %08x obj %+d\n",
|
||||
i, prev, handler, (int)object );
|
||||
break;
|
||||
case 2:
|
||||
handler = v4_read_rva( &p );
|
||||
object = v4_decode_uint( &p );
|
||||
printf( " %u: prev %d dtor ptr handler %08x obj %+d\n",
|
||||
i, prev, handler, (int)object );
|
||||
break;
|
||||
case 3:
|
||||
handler = v4_read_rva( &p );
|
||||
printf( " %u: prev %d handler %08x\n", i, prev, handler );
|
||||
break;
|
||||
}
|
||||
}
|
||||
free( offsets );
|
||||
}
|
||||
|
||||
if (tryblock_map)
|
||||
{
|
||||
const BYTE *p = RVA( tryblock_map, 1 );
|
||||
count = v4_decode_uint( &p );
|
||||
printf( " tryblock map at %08x count %u\n", tryblock_map, count );
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
int start = v4_decode_uint( &p );
|
||||
int end = v4_decode_uint( &p );
|
||||
int catch = v4_decode_uint( &p );
|
||||
UINT catchblock = v4_read_rva( &p );
|
||||
|
||||
printf( " %u: start %d end %d catch %d\n", i, start, end, catch );
|
||||
if (catchblock)
|
||||
{
|
||||
UINT cont[3];
|
||||
const BYTE *p = RVA( catchblock, 1 );
|
||||
count = v4_decode_uint( &p );
|
||||
for (j = 0; j < count; j++)
|
||||
{
|
||||
BYTE flags = *p++;
|
||||
printf( " %u:", j );
|
||||
if (flags & CATCHBLOCK_FLAGS)
|
||||
printf( " flags %08x", v4_decode_uint( &p ));
|
||||
if (flags & CATCHBLOCK_TYPE_INFO)
|
||||
printf( " type %08x", v4_read_rva( &p ));
|
||||
if (flags & CATCHBLOCK_OFFSET)
|
||||
printf( " offset %08x", v4_decode_uint( &p ));
|
||||
printf( " handler %08x", v4_read_rva( &p ));
|
||||
for (k = 0; k < ((flags >> 4) & 3); k++)
|
||||
if (flags & CATCHBLOCK_SEPARATED) cont[k] = v4_read_rva( &p );
|
||||
else cont[k] = func_rva + v4_decode_uint( &p );
|
||||
if (k == 1) printf( " cont %08x", cont[0] );
|
||||
else if (k == 2) printf( " cont %08x,%08x", cont[0], cont[1] );
|
||||
printf( "\n" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ip_map && (flags & FUNC_DESCR_IS_SEPARATED))
|
||||
{
|
||||
const BYTE *p = RVA( ip_map, 1 );
|
||||
|
||||
count = v4_decode_uint( &p );
|
||||
printf( " separated ip map at %08x count %u\n", ip_map, count );
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
UINT ip = v4_read_rva( &p );
|
||||
UINT map = v4_read_rva( &p );
|
||||
|
||||
if (map)
|
||||
{
|
||||
UINT state, count2;
|
||||
const BYTE *p = RVA( map, 1 );
|
||||
|
||||
count2 = v4_decode_uint( &p );
|
||||
printf( " %u: start %08x map %08x\n", i, ip, map );
|
||||
for (j = 0; j < count2; j++)
|
||||
{
|
||||
ip += v4_decode_uint( &p );
|
||||
state = v4_decode_uint( &p );
|
||||
printf( " %u: ip %08x state %d\n", i, ip, state );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ip_map)
|
||||
{
|
||||
UINT ip = func_rva, state;
|
||||
const BYTE *p = RVA( ip_map, 1 );
|
||||
|
||||
count = v4_decode_uint( &p );
|
||||
printf( " ip map at %08x count %u\n", ip_map, count );
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
ip += v4_decode_uint( &p );
|
||||
state = v4_decode_uint( &p );
|
||||
printf( " %u: ip %08x state %d\n", i, ip, state );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_exception_data( unsigned int rva, unsigned int func_rva, const char *name )
|
||||
{
|
||||
if (strstr( name, "__C_specific_handler" )) dump_c_exception_data( rva );
|
||||
if (strstr( name, "__CxxFrameHandler4" )) dump_cxx_exception_data_v4( rva, func_rva );
|
||||
else dump_cxx_exception_data( rva, func_rva );
|
||||
}
|
||||
|
||||
static void dump_x86_64_unwind_info( const struct runtime_function_x86_64 *function )
|
||||
{
|
||||
static const char * const reg_names[16] =
|
||||
|
@ -1063,6 +1410,7 @@ static void dump_x86_64_unwind_info( const struct runtime_function_x86_64 *funct
|
|||
const char *name = get_function_name( handler_data->handler );
|
||||
|
||||
printf( " handler %08x%s data at %08x\n", handler_data->handler, name, rva );
|
||||
dump_exception_data( rva, function->BeginAddress, name );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1458,6 +1806,7 @@ static void dump_armnt_unwind_info( const struct runtime_function_armnt *fnc )
|
|||
rva = rva + sizeof(*handler);
|
||||
name = get_function_name( *handler );
|
||||
printf( " handler %08x%s data at %08x\n", *handler, name, rva );
|
||||
dump_exception_data( rva, fnc->BeginAddress & ~1, name );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1804,6 +2153,7 @@ static void dump_arm64_unwind_info( const struct runtime_function_arm64 *func )
|
|||
|
||||
rva += sizeof(*handler);
|
||||
printf( " handler: %08x%s data %08x\n", *handler, name, rva );
|
||||
dump_exception_data( rva, func->BeginAddress, name );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue