winedump: Rewrite dumping of packed ARM unwind info.

This differs slightly from the official docs (which is clear in some
places, vague in others, and contradictory in some places), based
on actual observed behaviour.

Signed-off-by: Martin Storsjö <martin@martin.st>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Martin Storsjö 2021-11-09 16:05:47 +02:00 committed by Alexandre Julliard
parent ae7979a42d
commit aa256deedd
1 changed files with 64 additions and 94 deletions

View File

@ -787,7 +787,7 @@ static void dump_armnt_unwind_info( const struct runtime_function_armnt *fnc )
if (fnc->u.s.Flag)
{
char intregs[32] = {0}, intregspop[32] = {0}, vfpregs[32] = {0};
WORD pf = 0, ef = 0, sc = 0;
WORD pf = 0, ef = 0, fpoffset = 0, stack = fnc->u.s.StackAdjust;
printf( "\nFunction %08x-%08x:\n", fnc->BeginAddress & ~1,
(fnc->BeginAddress & ~1) + fnc->u.s.FunctionLength * 2 );
@ -805,86 +805,60 @@ static void dump_armnt_unwind_info( const struct runtime_function_armnt *fnc )
{
pf = fnc->u.s.StackAdjust & 0x04;
ef = fnc->u.s.StackAdjust & 0x08;
stack = (fnc->u.s.StackAdjust & 3) + 1;
}
if (!fnc->u.s.R && !pf)
if (!fnc->u.s.R || pf)
{
if (fnc->u.s.Reg)
int first = 4, last = fnc->u.s.Reg + 4;
if (pf)
{
sprintf(intregs, "r4-r%u", fnc->u.s.Reg + 4);
sprintf(intregspop, "r4-r%u", fnc->u.s.Reg + 4);
first = (~fnc->u.s.StackAdjust) & 3;
if (fnc->u.s.R)
last = 3;
}
if (first == last)
sprintf(intregs, "r%u", first);
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");
}
sprintf(intregs, "r%u-r%u", first, last);
fpoffset = last + 1 - first;
}
if (fnc->u.s.C && !fnc->u.s.L)
if (!fnc->u.s.R || ef)
{
int first = 4, last = fnc->u.s.Reg + 4;
if (ef)
{
first = (~fnc->u.s.StackAdjust) & 3;
if (fnc->u.s.R)
last = 3;
}
if (first == last)
sprintf(intregspop, "r%u", first);
else
sprintf(intregspop, "r%u-r%u", first, last);
}
if (fnc->u.s.C)
{
if (intregs[0])
strcat(intregs, ", ");
if (intregspop[0])
strcat(intregspop, ", ");
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)
if (fnc->u.s.L)
{
if (intregs[0])
strcat(intregs, ", ");
strcat(intregs, "lr");
if (!fnc->u.s.H)
if (intregspop[0] && (fnc->u.s.Ret != 0 || !fnc->u.s.H))
strcat(intregspop, ", ");
if (fnc->u.s.Ret != 0)
strcat(intregspop, "lr");
else if (!fnc->u.s.H)
strcat(intregspop, "pc");
}
@ -895,46 +869,42 @@ static void dump_armnt_unwind_info( const struct runtime_function_armnt *fnc )
else
strcpy(vfpregs, "d8");
}
else
strcpy(vfpregs, "none");
if (fnc->u.s.H)
printf( " Unwind Code\tpush {r0-r3}\n" );
if (fnc->u.s.Flag == 1) {
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 (intregs[0])
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.C && fpoffset == 0)
printf( " Unwind Code\tmov r11, sp\n" );
else if (fnc->u.s.C)
printf( " Unwind Code\tadd r11, sp, #%d\n", fpoffset * 4 );
if (fnc->u.s.R && fnc->u.s.Reg != 0x07)
printf( " Unwind Code\tvpush {%s}\n", vfpregs );
if (stack && !pf)
printf( " Unwind Code\tsub sp, sp, #%d\n", stack * 4 );
}
if (fnc->u.s.R && fnc->u.s.Reg != 0x07)
printf( " Unwind Code\tvpush {%s}\n", vfpregs );
if (fnc->u.s.Ret == 3)
return;
printf( "Epilogue:\n" );
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 (stack && !ef)
printf( " Unwind Code\tadd sp, sp, #%d\n", stack * 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))
if (intregspop[0])
printf( " Unwind Code\tpop {%s}\n", intregspop );
if (fnc->u.s.H && !fnc->u.s.L)
if (fnc->u.s.H && !(fnc->u.s.L && fnc->u.s.Ret == 0))
printf( " Unwind Code\tadd sp, sp, #16\n" );
else if (fnc->u.s.H && fnc->u.s.L)
else if (fnc->u.s.H && (fnc->u.s.L && fnc->u.s.Ret == 0))
printf( " Unwind Code\tldr pc, [sp], #20\n" );
if (fnc->u.s.Ret == 1)