[PATCH 10/18] winedump: Rewrite dumping of packed ARM unwind info.
Martin Storsjö
martin at martin.st
Tue Nov 9 08:05:47 CST 2021
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 at martin.st>
---
tools/winedump/pe.c | 146 ++++++++++++++++++--------------------------
1 file changed, 58 insertions(+), 88 deletions(-)
diff --git a/tools/winedump/pe.c b/tools/winedump/pe.c
index 43ba0618615..6ff14f95791 100644
--- a/tools/winedump/pe.c
+++ b/tools/winedump/pe.c
@@ -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, ", ");
- }
+ sprintf(intregs, "r%u-r%u", first, last);
+ fpoffset = last + 1 - first;
}
- else if (fnc->u.s.R && pf)
+
+ if (!fnc->u.s.R || ef)
{
- if (((~fnc->u.s.StackAdjust) & 3) != 3)
+ int first = 4, last = fnc->u.s.Reg + 4;
+ if (ef)
{
- sprintf(intregs, "r%u-r3", (~fnc->u.s.StackAdjust) & 3);
- sprintf(intregspop, "r%u-r3", (~fnc->u.s.StackAdjust) & 3);
+ first = (~fnc->u.s.StackAdjust) & 3;
+ if (fnc->u.s.R)
+ last = 3;
}
+ if (first == last)
+ sprintf(intregspop, "r%u", first);
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(intregspop, "r%u-r%u", first, last);
}
- if (fnc->u.s.C && !fnc->u.s.L)
+ 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 (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 (stack && !pf)
+ printf( " Unwind Code\tsub sp, sp, #%d\n", stack * 4 );
+ }
+ if (fnc->u.s.Ret == 3)
+ return;
+ printf( "Epilogue:\n" );
- 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)
--
2.25.1
More information about the wine-devel
mailing list