winedump: Improved dumping of exception info on ARM.

This commit is contained in:
André Hentschel 2014-10-13 01:34:11 +02:00 committed by Alexandre Julliard
parent 8b07523c56
commit 9006dcb059
1 changed files with 429 additions and 25 deletions

View File

@ -600,10 +600,28 @@ struct unwind_info_x86_64
struct unwind_info_armnt
{
WORD function_length;
WORD unknown1 : 7;
WORD count : 5;
WORD unknown2 : 4;
DWORD function_length : 18;
DWORD version : 2;
DWORD x : 1;
DWORD e : 1;
DWORD f : 1;
DWORD count : 5;
DWORD words : 4;
};
struct unwind_info_ext_armnt
{
WORD excount;
BYTE exwords;
BYTE reserved;
};
struct unwind_info_epilogue_armnt
{
DWORD offset : 18;
DWORD res : 2;
DWORD cond : 4;
DWORD index : 8;
};
#define UWOP_PUSH_NONVOL 0
@ -725,35 +743,421 @@ static void dump_x86_64_unwind_info( const struct runtime_function_x86_64 *funct
(ULONG)(function->UnwindData + (const char *)(&handler_data->handler + 1) - (const char *)info ));
}
static void dump_armnt_unwind_info( const struct runtime_function_armnt *function )
static void dump_armnt_unwind_info( const struct runtime_function_armnt *fnc )
{
const struct unwind_info_armnt *info;
if (function->u.s.Flag)
const struct unwind_info_ext_armnt *infoex;
const struct unwind_info_epilogue_armnt *infoepi;
unsigned int rva;
WORD i, count = 0, words = 0;
if (fnc->u.s.Flag)
{
printf( "\nFunction %08x-%08x:\n", function->BeginAddress & ~1,
(function->BeginAddress & ~1) + function->u.s.FunctionLength * 2 );
printf( " Flag %x\n", function->u.s.Flag );
printf( " FunctionLength %x\n", function->u.s.FunctionLength );
printf( " Ret %x\n", function->u.s.Ret );
printf( " H %x\n", function->u.s.H );
printf( " Reg %x\n", function->u.s.Reg );
printf( " R %x\n", function->u.s.R );
printf( " L %x\n", function->u.s.L );
printf( " C %x\n", function->u.s.C );
printf( " StackAdjust %x\n", function->u.s.StackAdjust );
char intregs[32] = {0}, intregspop[32] = {0}, vfpregs[32] = {0};
WORD pf = 0, ef = 0, sc = 0;
printf( "\nFunction %08x-%08x:\n", fnc->BeginAddress & ~1,
(fnc->BeginAddress & ~1) + fnc->u.s.FunctionLength * 2 );
printf( " Flag %x\n", fnc->u.s.Flag );
printf( " FunctionLength %x\n", fnc->u.s.FunctionLength );
printf( " Ret %x\n", fnc->u.s.Ret );
printf( " H %x\n", fnc->u.s.H );
printf( " Reg %x\n", fnc->u.s.Reg );
printf( " R %x\n", fnc->u.s.R );
printf( " L %x\n", fnc->u.s.L );
printf( " C %x\n", fnc->u.s.C );
printf( " StackAdjust %x\n", fnc->u.s.StackAdjust );
if (fnc->u.s.StackAdjust >= 0x03f4)
{
pf = fnc->u.s.StackAdjust & 0x04;
ef = fnc->u.s.StackAdjust & 0x08;
}
if (!fnc->u.s.R && !pf)
{
if (fnc->u.s.Reg)
{
sprintf(intregs, "r4-r%u", fnc->u.s.Reg + 4);
sprintf(intregspop, "r4-r%u", fnc->u.s.Reg + 4);
}
else
{
strcpy(intregs, "r4");
strcpy(intregspop, "r4");
}
sc = fnc->u.s.Reg + 1;
if (fnc->u.s.C || fnc->u.s.L)
{
strcat(intregs, ", ");
if (fnc->u.s.C || fnc->u.s.L && !fnc->u.s.H)
strcat(intregspop, ", ");
}
}
else if (fnc->u.s.R && pf)
{
if (((~fnc->u.s.StackAdjust) & 3) != 3)
{
sprintf(intregs, "r%u-r3", (~fnc->u.s.StackAdjust) & 3);
sprintf(intregspop, "r%u-r3", (~fnc->u.s.StackAdjust) & 3);
}
else
{
sprintf(intregs, "r3");
sprintf(intregspop, "r3");
}
sc = 4 - ((~fnc->u.s.StackAdjust) & 3);
if (fnc->u.s.C || fnc->u.s.L)
{
strcat(intregs, ", ");
if (fnc->u.s.C || fnc->u.s.L && !fnc->u.s.H)
strcat(intregspop, ", ");
}
}
else if (!fnc->u.s.R && pf)
{
sprintf(intregs, "r%u-r%u", (~fnc->u.s.StackAdjust) & 3, fnc->u.s.Reg + 4);
sprintf(intregspop, "r%u-r%u", (~fnc->u.s.StackAdjust) & 3, fnc->u.s.Reg + 4);
sc = fnc->u.s.Reg + 5 - ((~fnc->u.s.StackAdjust) & 3);
if (fnc->u.s.C || fnc->u.s.L)
{
strcat(intregs, ", ");
if (fnc->u.s.C || fnc->u.s.L && !fnc->u.s.H)
strcat(intregspop, ", ");
}
}
else if (fnc->u.s.R && !pf)
{
if (!fnc->u.s.C && !fnc->u.s.L)
{
strcpy(intregs, "none");
strcpy(intregspop, "none");
}
}
if (fnc->u.s.C && !fnc->u.s.L)
{
strcat(intregs, "r11");
strcat(intregspop, "r11");
}
else if (fnc->u.s.C && fnc->u.s.L)
{
strcat(intregs, "r11, lr");
if (fnc->u.s.H)
strcat(intregspop, "r11");
else
strcat(intregspop, "r11, pc");
}
else if (!fnc->u.s.C && fnc->u.s.L)
{
strcat(intregs, "lr");
if (!fnc->u.s.H)
strcat(intregspop, "pc");
}
if (fnc->u.s.R)
{
if (fnc->u.s.Reg)
sprintf(vfpregs, "d8-d%u", fnc->u.s.Reg + 8);
else
strcpy(vfpregs, "d8");
}
else
strcpy(vfpregs, "none");
if (fnc->u.s.H)
printf( " Unwind Code\tpush {r0-r3}\n" );
if (fnc->u.s.R || fnc->u.s.L || fnc->u.s.C || pf)
printf( " Unwind Code\tpush {%s}\n", intregs );
if (fnc->u.s.C && fnc->u.s.R && !fnc->u.s.L && !pf)
printf( " Unwind Code\tmov r11, sp\n" );
else if (fnc->u.s.C && (!fnc->u.s.R || fnc->u.s.L || pf))
{
if (fnc->u.s.StackAdjust >= 0x03f4 && !sc)
printf( " Unwind Code\tadd r11, sp, #<unknown>\n");
else if (fnc->u.s.StackAdjust >= 0x03f4)
printf( " Unwind Code\tadd r11, sp, #%d\n", sc * 4 );
else
printf( " Unwind Code\tadd r11, sp, #%d\n", fnc->u.s.StackAdjust * 4 );
}
if (fnc->u.s.R && fnc->u.s.Reg != 0x07)
printf( " Unwind Code\tvpush {%s}\n", vfpregs );
if (fnc->u.s.StackAdjust < 0x03f4 && !pf)
printf( " Unwind Code\tsub sp, sp, #%d\n", fnc->u.s.StackAdjust * 4 );
if (fnc->u.s.StackAdjust < 0x03f4 && !ef)
printf( " Unwind Code\tadd sp, sp, #%d\n", fnc->u.s.StackAdjust * 4 );
if (fnc->u.s.R && fnc->u.s.Reg != 0x07)
printf( " Unwind Code\tvpop {%s}\n", vfpregs );
if (fnc->u.s.C || !fnc->u.s.R || ef || (fnc->u.s.L && !fnc->u.s.H))
printf( " Unwind Code\tpop {%s}\n", intregspop );
if (fnc->u.s.H && !fnc->u.s.L)
printf( " Unwind Code\tadd sp, sp, #16\n" );
else if (fnc->u.s.H && fnc->u.s.L)
printf( " Unwind Code\tldr pc, [sp], #20\n" );
if (fnc->u.s.Ret == 1)
printf( " Unwind Code\tbx <reg>\n" );
else if (fnc->u.s.Ret == 2)
printf( " Unwind Code\tb <address>\n" );
return;
}
info = RVA( function->u.UnwindData, sizeof(*info) );
info = RVA( fnc->u.UnwindData, sizeof(*info) );
rva = fnc->u.UnwindData + sizeof(*info);
count = info->count;
words = info->words;
printf( "\nFunction %08x-%08x:\n", function->BeginAddress & ~1,
(function->BeginAddress & ~1) + info->function_length * 2 );
printf( " unwind info at %08x\n", function->u.UnwindData );
printf( " Flag %x\n", function->u.s.Flag );
printf( "\nFunction %08x-%08x:\n", fnc->BeginAddress & ~1,
(fnc->BeginAddress & ~1) + info->function_length * 2 );
printf( " unwind info at %08x\n", fnc->u.UnwindData );
printf( " Flag %x\n", fnc->u.s.Flag );
printf( " FunctionLength %x\n", info->function_length );
printf( " Unknown1 %x\n", info->unknown1 );
printf( " Count %x\n", info->count );
printf( " Unknown2 %x\n", info->unknown2 );
printf( " Version %x\n", info->version );
printf( " X %x\n", info->x );
printf( " E %x\n", info->e );
printf( " F %x\n", info->f );
printf( " Count %x\n", count );
printf( " Words %x\n", words );
if (!info->count && !info->words)
{
infoex = RVA( rva, sizeof(*infoex) );
rva = rva + sizeof(*infoex);
count = infoex->excount;
words = infoex->exwords;
printf( " ExtCount %x\n", count );
printf( " ExtWords %x\n", words );
}
if (!info->e)
{
infoepi = RVA( rva, count * sizeof(*infoepi) );
rva = rva + count * sizeof(*infoepi);
for (i = 0; i < count; i++)
{
printf( " Epilogue Scope %x\n", i );
printf( " Offset %x\n", infoepi[i].offset );
printf( " Reserved %x\n", infoepi[i].res );
printf( " Condition %x\n", infoepi[i].cond );
printf( " Index %x\n", infoepi[i].index );
}
}
else
infoepi = NULL;
if (words)
{
const unsigned int *codes;
BYTE b, *bytes;
BOOL inepilogue = FALSE;
codes = RVA( rva, words * sizeof(*codes) );
rva = rva + words * sizeof(*codes);
bytes = (BYTE*)codes;
for (b = 0; b < words * sizeof(*codes); b++)
{
BYTE code = bytes[b];
if (info->e && b == count)
{
printf( "Epilogue:\n" );
inepilogue = TRUE;
}
else if (!info->e && infoepi)
{
for (i = 0; i < count; i++)
if (b == infoepi[i].index)
{
printf( "Epilogue from Scope %x at %08x:\n", i,
(fnc->BeginAddress & ~1) + infoepi[i].offset * 2 );
inepilogue = TRUE;
}
}
printf( " Unwind Code %x\t", code );
if (code == 0x00)
printf( "\n" );
else if (code <= 0x7f)
printf( "%s sp, sp, #%u\n", inepilogue ? "add" : "sub", code * 4 );
else if (code <= 0xbf)
{
WORD excode, f;
BOOL first = TRUE;
BYTE excodes = bytes[++b];
excode = (code << 8) | excodes;
printf( "%s {", inepilogue ? "pop" : "push" );
for (f = 0; f <= 12; f++)
{
if ((excode >> f) & 1)
{
printf( "%sr%u", first ? "" : ", ", f );
first = FALSE;
}
}
if (excode & 0x2000)
printf( "%s%s", first ? "" : ", ", inepilogue ? "pc" : "lr" );
printf( "}\n" );
}
else if (code <= 0xcf)
if (inepilogue)
printf( "mov sp, r%u\n", code & 0x0f );
else
printf( "mov r%u, sp\n", code & 0x0f );
else if (code <= 0xd7)
if (inepilogue)
printf( "pop {r4-r%u%s}\n", (code & 0x03) + 4, (code & 0x04) ? ", pc" : "" );
else
printf( "push {r4-r%u%s}\n", (code & 0x03) + 4, (code & 0x04) ? ", lr" : "" );
else if (code <= 0xdf)
if (inepilogue)
printf( "pop {r4-r%u%s}\n", (code & 0x03) + 8, (code & 0x04) ? ", pc" : "" );
else
printf( "push {r4-r%u%s}\n", (code & 0x03) + 8, (code & 0x04) ? ", lr" : "" );
else if (code <= 0xe7)
printf( "%s {d8-d%u}\n", inepilogue ? "vpop" : "vpush", (code & 0x07) + 8 );
else if (code <= 0xeb)
{
WORD excode;
BYTE excodes = bytes[++b];
excode = (code << 8) | excodes;
printf( "%s sp, sp, #%u\n", inepilogue ? "addw" : "subw", (excode & 0x03ff) *4 );
}
else if (code <= 0xed)
{
WORD excode, f;
BOOL first = TRUE;
BYTE excodes = bytes[++b];
excode = (code << 8) | excodes;
printf( "%s {", inepilogue ? "pop" : "push" );
for (f = 0; f < 8; f++)
{
if ((excode >> f) & 1)
{
printf( "%sr%u", first ? "" : ", ", f );
first = FALSE;
}
}
if (excode & 0x0100)
printf( "%s%s", first ? "" : ", ", inepilogue ? "pc" : "lr" );
printf( "}\n" );
}
else if (code == 0xee)
printf( "unknown 16\n" );
else if (code == 0xef)
{
WORD excode;
BYTE excodes = bytes[++b];
if (excodes <= 0x0f)
{
excode = (code << 8) | excodes;
if (inepilogue)
printf( "ldr lr, [sp], #%u\n", (excode & 0x0f) * 4 );
else
printf( "unknown 32\n" );
}
else
printf( "unknown 32\n" );
}
else if (code <= 0xf4)
printf( "unknown\n" );
else if (code <= 0xf6)
{
WORD excode, offset = (code == 0xf6) ? 16 : 0;
BYTE excodes = bytes[++b];
excode = (code << 8) | excodes;
printf( "%s {d%u-d%u}\n", inepilogue ? "vpop" : "vpush",
((excode & 0x00f0) >> 4) + offset, (excode & 0x0f) + offset );
}
else if (code <= 0xf7)
{
unsigned int excode;
BYTE excodes[2];
excodes[0] = bytes[++b];
excodes[1] = bytes[++b];
excode = (code << 16) | (excodes[0] << 8) | excodes[1];
printf( "%s sp, sp, #%u\n", inepilogue ? "add" : "sub", (excode & 0xffff) *4 );
}
else if (code <= 0xf8)
{
unsigned int excode;
BYTE excodes[3];
excodes[0] = bytes[++b];
excodes[1] = bytes[++b];
excodes[2] = bytes[++b];
excode = (code << 24) | (excodes[0] << 16) | (excodes[1] << 8) | excodes[2];
printf( "%s sp, sp, #%u\n", inepilogue ? "add" : "sub", (excode & 0xffffff) * 4 );
}
else if (code <= 0xf9)
{
unsigned int excode;
BYTE excodes[2];
excodes[0] = bytes[++b];
excodes[1] = bytes[++b];
excode = (code << 16) | (excodes[0] << 8) | excodes[1];
printf( "%s sp, sp, #%u\n", inepilogue ? "add" : "sub", (excode & 0xffff) *4 );
}
else if (code <= 0xfa)
{
unsigned int excode;
BYTE excodes[3];
excodes[0] = bytes[++b];
excodes[1] = bytes[++b];
excodes[2] = bytes[++b];
excode = (code << 24) | (excodes[0] << 16) | (excodes[1] << 8) | excodes[2];
printf( "%s sp, sp, #%u\n", inepilogue ? "add" : "sub", (excode & 0xffffff) * 4 );
}
else if (code <= 0xfc)
printf( "nop\n" );
else if (code <= 0xfe)
{
printf( "(end) nop\n" );
inepilogue = TRUE;
}
else
{
printf( "end\n" );
inepilogue = TRUE;
}
}
}
if (info->x)
{
const unsigned int *handler;
handler = RVA( rva, sizeof(*handler) );
rva = rva + sizeof(*handler);
printf( " handler %08x data at %08x\n", *handler, rva);
}
}
static void dump_dir_exceptions(void)