ntdll: Fix more corner cases for arm64 packed info unwinding.

Make sure to restore sp from fp for CR == 3.

Fix unwinding of partial prologues/epilogues - the previous logic
had an off-by-one for the pos/skip handling; fix a few more
corner cases with odd number of saved registers.

Functions with the H flag set (saving x0-x7 on the stack) should
be considred having 4 nops (for the instructions saving the
registers) in the prologue for unwind purposes. When unwinding
through a partial epilogue, the same 4 nops should also be
considered to be there (even though no sane epilogue would restore
the registers there) based on how windows handles partial epilogue
unwinding in those cases.

Uncomment prologue/epilogue cases in an existing test and add
tests for many more cases.

Signed-off-by: Martin Storsjo <martin@martin.st>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Martin Storsjo 2020-09-07 13:14:57 +03:00 committed by Alexandre Julliard
parent 578aae071b
commit 3395ee3631
2 changed files with 340 additions and 23 deletions

View File

@ -708,6 +708,7 @@ static void *unwind_packed_data( ULONG_PTR base, ULONG_PTR pc, RUNTIME_FUNCTION
switch (func->u.s.CR) switch (func->u.s.CR)
{ {
case 3: case 3:
len++; /* mov x29,sp */
len++; /* stp x29,lr,[sp,0] */ len++; /* stp x29,lr,[sp,0] */
if (local_size <= 512) break; if (local_size <= 512) break;
/* fall through */ /* fall through */
@ -717,9 +718,10 @@ static void *unwind_packed_data( ULONG_PTR base, ULONG_PTR pc, RUNTIME_FUNCTION
if (local_size > 4088) len++; /* sub sp,sp,#4088 */ if (local_size > 4088) len++; /* sub sp,sp,#4088 */
break; break;
} }
if (offset < len + 4 * func->u.s.H) /* prolog */ len += 4 * func->u.s.H;
if (offset < len) /* prolog */
{ {
skip = len + 4 * func->u.s.H - offset; skip = len - offset;
} }
else if (offset >= func->u.s.FunctionLength - (len + 1)) /* epilog */ else if (offset >= func->u.s.FunctionLength - (len + 1)) /* epilog */
{ {
@ -733,6 +735,7 @@ static void *unwind_packed_data( ULONG_PTR base, ULONG_PTR pc, RUNTIME_FUNCTION
if (func->u.s.CR == 3) if (func->u.s.CR == 3)
{ {
DWORD64 *fp = (DWORD64 *) context->u.s.Fp; /* u.X[29] */ DWORD64 *fp = (DWORD64 *) context->u.s.Fp; /* u.X[29] */
context->Sp = context->u.s.Fp;
context->u.X[29] = fp[0]; context->u.X[29] = fp[0];
context->u.X[30] = fp[1]; context->u.X[30] = fp[1];
} }
@ -748,34 +751,36 @@ static void *unwind_packed_data( ULONG_PTR base, ULONG_PTR pc, RUNTIME_FUNCTION
switch (func->u.s.CR) switch (func->u.s.CR)
{ {
case 3: case 3:
/* mov x29,sp */
if (pos++ >= skip) context->Sp = context->u.s.Fp;
if (local_size <= 512) if (local_size <= 512)
{ {
/* stp x29,lr,[sp,-#local_size]! */ /* stp x29,lr,[sp,-#local_size]! */
if (pos++ > skip) restore_regs( 29, 2, -local_size_regs, context, ptrs ); if (pos++ >= skip) restore_regs( 29, 2, -local_size_regs, context, ptrs );
break; break;
} }
/* stp x29,lr,[sp,0] */ /* stp x29,lr,[sp,0] */
if (pos++ > skip) restore_regs( 29, 2, 0, context, ptrs ); if (pos++ >= skip) restore_regs( 29, 2, 0, context, ptrs );
/* fall through */ /* fall through */
case 0: case 0:
case 1: case 1:
if (!local_size) break; if (!local_size) break;
/* sub sp,sp,#local_size */ /* sub sp,sp,#local_size */
if (pos++ > skip) context->Sp += (local_size - 1) % 4088 + 1; if (pos++ >= skip) context->Sp += (local_size - 1) % 4088 + 1;
if (local_size > 4088 && pos++ > skip) context->Sp += 4088; if (local_size > 4088 && pos++ >= skip) context->Sp += 4088;
break; break;
} }
if (func->u.s.H && offset < len + 4) pos += 4; if (func->u.s.H) pos += 4;
if (fp_size) if (fp_size)
{ {
if (func->u.s.RegF % 2 == 0 && pos++ > skip) if (func->u.s.RegF % 2 == 0 && pos++ >= skip)
/* str d%u,[sp,#fp_size] */ /* str d%u,[sp,#fp_size] */
restore_fpregs( 8 + func->u.s.RegF, 1, int_regs + fp_regs - 1, context, ptrs ); restore_fpregs( 8 + func->u.s.RegF, 1, int_regs + fp_regs - 1, context, ptrs );
for (i = func->u.s.RegF / 2 - 1; i >= 0; i--) for (i = (func->u.s.RegF + 1) / 2 - 1; i >= 0; i--)
{ {
if (pos++ <= skip) continue; if (pos++ < skip) continue;
if (!i && !int_size) if (!i && !int_size)
/* stp d8,d9,[sp,-#regsave]! */ /* stp d8,d9,[sp,-#regsave]! */
restore_fpregs( 8, 2, -saved_regs, context, ptrs ); restore_fpregs( 8, 2, -saved_regs, context, ptrs );
@ -785,9 +790,9 @@ static void *unwind_packed_data( ULONG_PTR base, ULONG_PTR pc, RUNTIME_FUNCTION
} }
} }
if (pos++ > skip) if (func->u.s.RegI % 2)
{ {
if (func->u.s.RegI % 2) if (pos++ >= skip)
{ {
/* stp xn,lr,[sp,#offset] */ /* stp xn,lr,[sp,#offset] */
if (func->u.s.CR == 1) restore_regs( 30, 1, int_regs - 1, context, ptrs ); if (func->u.s.CR == 1) restore_regs( 30, 1, int_regs - 1, context, ptrs );
@ -796,14 +801,16 @@ static void *unwind_packed_data( ULONG_PTR base, ULONG_PTR pc, RUNTIME_FUNCTION
(func->u.s.RegI > 1) ? func->u.s.RegI - 1 : -saved_regs, (func->u.s.RegI > 1) ? func->u.s.RegI - 1 : -saved_regs,
context, ptrs ); context, ptrs );
} }
else if (func->u.s.CR == 1) }
/* str lr,[sp,#offset] */ else if (func->u.s.CR == 1)
restore_regs( 30, 1, func->u.s.RegI ? int_regs - 1 : -saved_regs, context, ptrs ); {
/* str lr,[sp,#offset] */
if (pos++ >= skip) restore_regs( 30, 1, func->u.s.RegI ? int_regs - 1 : -saved_regs, context, ptrs );
} }
for (i = func->u.s.RegI / 2 - 1; i >= 0; i--) for (i = func->u.s.RegI/ 2 - 1; i >= 0; i--)
{ {
if (pos++ <= skip) continue; if (pos++ < skip) continue;
if (i) if (i)
/* stp xn,xn+1,[sp,#offset] */ /* stp xn,xn+1,[sp,#offset] */
restore_regs( 19 + 2 * i, 2, 2 * i, context, ptrs ); restore_regs( 19 + 2 * i, 2, 2 * i, context, ptrs );

View File

@ -4572,23 +4572,17 @@ static void test_virtual_unwind(void)
static const BYTE unwind_info_1[] = { DW(unwind_info_1_packed) }; static const BYTE unwind_info_1[] = { DW(unwind_info_1_packed) };
/* The prologue/epilogue locations are commented out below, as we don't
* handle those cases at the moment. */
static const struct results results_1[] = static const struct results results_1[] =
{ {
/* offset fp handler pc frame offset registers */ /* offset fp handler pc frame offset registers */
#if 0
{ 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }}, { 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
{ 0x04, 0x00, 0, ORIG_LR, 0x020, TRUE, { {x19,0x00}, {x20,0x08}, {-1,-1} }}, { 0x04, 0x00, 0, ORIG_LR, 0x020, TRUE, { {x19,0x00}, {x20,0x08}, {-1,-1} }},
{ 0x08, 0x00, 0, 0x10, 0x020, TRUE, { {x19,0x00}, {x20,0x08}, {lr,0x10}, {-1,-1} }}, { 0x08, 0x00, 0, 0x10, 0x020, TRUE, { {x19,0x00}, {x20,0x08}, {lr,0x10}, {-1,-1} }},
#endif
{ 0x0c, 0x00, 0, 0x20, 0x030, TRUE, { {x19,0x10}, {x20,0x18}, {lr,0x20}, {-1,-1} }}, { 0x0c, 0x00, 0, 0x20, 0x030, TRUE, { {x19,0x10}, {x20,0x18}, {lr,0x20}, {-1,-1} }},
{ 0x10, 0x00, 0, 0x20, 0x030, TRUE, { {x19,0x10}, {x20,0x18}, {lr,0x20}, {-1,-1} }}, { 0x10, 0x00, 0, 0x20, 0x030, TRUE, { {x19,0x10}, {x20,0x18}, {lr,0x20}, {-1,-1} }},
#if 0
{ 0x14, 0x00, 0, 0x10, 0x020, TRUE, { {x19,0x00}, {x20,0x08}, {lr,0x10}, {-1,-1} }}, { 0x14, 0x00, 0, 0x10, 0x020, TRUE, { {x19,0x00}, {x20,0x08}, {lr,0x10}, {-1,-1} }},
{ 0x18, 0x00, 0, ORIG_LR, 0x020, TRUE, { {x19,0x00}, {x20,0x08}, {-1,-1} }}, { 0x18, 0x00, 0, ORIG_LR, 0x020, TRUE, { {x19,0x00}, {x20,0x08}, {-1,-1} }},
{ 0x1c, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }}, { 0x1c, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
#endif
}; };
static const BYTE function_2[] = static const BYTE function_2[] =
@ -4808,6 +4802,314 @@ static void test_virtual_unwind(void)
#endif #endif
}; };
static const BYTE function_6[] =
{
0xf3, 0x53, 0xbd, 0xa9, /* 00: stp x19, x20, [sp, #-48]! */
0xf5, 0x0b, 0x00, 0xf9, /* 04: str x21, [sp, #16] */
0xe8, 0xa7, 0x01, 0x6d, /* 08: stp d8, d9, [sp, #24] */
0xea, 0x17, 0x00, 0xfd, /* 0c: str d10, [sp, #40] */
0xff, 0x03, 0x00, 0xd1, /* 10: sub sp, sp, #0 */
0x1f, 0x20, 0x03, 0xd5, /* 14: nop */
0xff, 0x03, 0x00, 0x91, /* 18: add sp, sp, #0 */
0xea, 0x17, 0x40, 0xfd, /* 1c: ldr d10, [sp, #40] */
0xe8, 0xa7, 0x41, 0x6d, /* 20: ldp d8, d9, [sp, #24] */
0xf5, 0x0b, 0x40, 0xf9, /* 24: ldr x21, [sp, #16] */
0xf3, 0x53, 0xc3, 0xa8, /* 28: ldp x19, x20, [sp], #48 */
0xc0, 0x03, 0x5f, 0xd6, /* 2c: ret */
};
static const DWORD unwind_info_6_packed =
(1 << 0) | /* Flag */
(sizeof(function_6)/4 << 2) | /* FunctionLength */
(2 << 13) | /* RegF */
(3 << 16) | /* RegI */
(0 << 20) | /* H */
(0 << 21) | /* CR */
(3 << 23); /* FrameSize */
static const BYTE unwind_info_6[] = { DW(unwind_info_6_packed) };
static const struct results results_6[] =
{
/* offset fp handler pc frame offset registers */
{ 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
{ 0x04, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {-1,-1} }},
{ 0x08, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {-1,-1} }},
{ 0x0c, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {d8, 0x18}, {d9, 0x20}, {-1,-1} }},
{ 0x10, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {d8, 0x18}, {d9, 0x20}, {d10, 0x28}, {-1,-1} }},
{ 0x14, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {d8, 0x18}, {d9, 0x20}, {d10, 0x28}, {-1,-1} }},
{ 0x18, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {d8, 0x18}, {d9, 0x20}, {d10, 0x28}, {-1,-1} }},
{ 0x1c, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {d8, 0x18}, {d9, 0x20}, {d10, 0x28}, {-1,-1} }},
{ 0x20, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {d8, 0x18}, {d9, 0x20}, {-1,-1} }},
{ 0x24, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {-1,-1} }},
{ 0x28, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {-1,-1} }},
{ 0x2c, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
};
static const BYTE function_7[] =
{
0xf3, 0x0f, 0x1d, 0xf8, /* 00: str x19, [sp, #-48]! */
0xe8, 0xa7, 0x00, 0x6d, /* 04: stp d8, d9, [sp, #8] */
0xea, 0xaf, 0x01, 0x6d, /* 08: stp d10, d11, [sp, #24] */
0xff, 0x03, 0x00, 0xd1, /* 0c: sub sp, sp, #0 */
0x1f, 0x20, 0x03, 0xd5, /* 10: nop */
0xff, 0x03, 0x00, 0x91, /* 14: add sp, sp, #0 */
0xea, 0xaf, 0x41, 0x6d, /* 18: ldp d10, d11, [sp, #24] */
0xe8, 0xa7, 0x40, 0x6d, /* 1c: ldp d8, d9, [sp, #8] */
0xf3, 0x07, 0x43, 0xf8, /* 20: ldr x19, [sp], #48 */
0xc0, 0x03, 0x5f, 0xd6, /* 24: ret */
};
static const DWORD unwind_info_7_packed =
(1 << 0) | /* Flag */
(sizeof(function_7)/4 << 2) | /* FunctionLength */
(3 << 13) | /* RegF */
(1 << 16) | /* RegI */
(0 << 20) | /* H */
(0 << 21) | /* CR */
(3 << 23); /* FrameSize */
static const BYTE unwind_info_7[] = { DW(unwind_info_7_packed) };
static const struct results results_7[] =
{
/* offset fp handler pc frame offset registers */
{ 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
{ 0x04, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {-1,-1} }},
{ 0x08, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {d8, 0x08}, {d9, 0x10}, {-1,-1} }},
{ 0x0c, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {d8, 0x08}, {d9, 0x10}, {d10, 0x18}, {d11, 0x20}, {-1,-1} }},
{ 0x10, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {d8, 0x08}, {d9, 0x10}, {d10, 0x18}, {d11, 0x20}, {-1,-1} }},
{ 0x14, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {d8, 0x08}, {d9, 0x10}, {d10, 0x18}, {d11, 0x20}, {-1,-1} }},
{ 0x18, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {d8, 0x08}, {d9, 0x10}, {d10, 0x18}, {d11, 0x20}, {-1,-1} }},
{ 0x1c, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {d8, 0x08}, {d9, 0x10}, {-1,-1} }},
{ 0x20, 0x00, 0, ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {-1,-1} }},
{ 0x24, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
};
static const BYTE function_8[] =
{
0xe8, 0x27, 0xbf, 0x6d, /* 00: stp d8, d9, [sp, #-16]! */
0xff, 0x83, 0x00, 0xd1, /* 04: sub sp, sp, #32 */
0x1f, 0x20, 0x03, 0xd5, /* 08: nop */
0xff, 0x83, 0x00, 0x91, /* 0c: add sp, sp, #32 */
0xe8, 0x27, 0xc1, 0x6c, /* 10: ldp d8, d9, [sp], #16 */
0xc0, 0x03, 0x5f, 0xd6, /* 14: ret */
};
static const DWORD unwind_info_8_packed =
(1 << 0) | /* Flag */
(sizeof(function_8)/4 << 2) | /* FunctionLength */
(1 << 13) | /* RegF */
(0 << 16) | /* RegI */
(0 << 20) | /* H */
(0 << 21) | /* CR */
(3 << 23); /* FrameSize */
static const BYTE unwind_info_8[] = { DW(unwind_info_8_packed) };
static const struct results results_8[] =
{
/* offset fp handler pc frame offset registers */
{ 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
{ 0x04, 0x00, 0, ORIG_LR, 0x010, TRUE, { {d8, 0x00}, {d9, 0x08}, {-1,-1} }},
{ 0x08, 0x00, 0, ORIG_LR, 0x030, TRUE, { {d8, 0x20}, {d9, 0x28}, {-1,-1} }},
{ 0x0c, 0x00, 0, ORIG_LR, 0x030, TRUE, { {d8, 0x20}, {d9, 0x28}, {-1,-1} }},
{ 0x10, 0x00, 0, ORIG_LR, 0x010, TRUE, { {d8, 0x00}, {d9, 0x08}, {-1,-1} }},
{ 0x14, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
};
static const BYTE function_9[] =
{
0xf3, 0x0f, 0x1b, 0xf8, /* 00: str x19, [sp, #-80]! */
0xe0, 0x87, 0x00, 0xa9, /* 04: stp x0, x1, [sp, #8] */
0xe2, 0x8f, 0x01, 0xa9, /* 08: stp x2, x3, [sp, #24] */
0xe4, 0x97, 0x02, 0xa9, /* 0c: stp x4, x5, [sp, #40] */
0xe6, 0x9f, 0x03, 0xa9, /* 10: stp x6, x7, [sp, #56] */
0xff, 0x83, 0x00, 0xd1, /* 14: sub sp, sp, #32 */
0x1f, 0x20, 0x03, 0xd5, /* 18: nop */
0xff, 0x83, 0x00, 0x91, /* 1c: add sp, sp, #32 */
0x1f, 0x20, 0x03, 0xd5, /* 20: nop */
0x1f, 0x20, 0x03, 0xd5, /* 24: nop */
0x1f, 0x20, 0x03, 0xd5, /* 28: nop */
0x1f, 0x20, 0x03, 0xd5, /* 2c: nop */
0xf3, 0x0f, 0x1b, 0xf8, /* 30: ldr x19, [sp], #80 */
0xc0, 0x03, 0x5f, 0xd6, /* 34: ret */
};
static const DWORD unwind_info_9_packed =
(1 << 0) | /* Flag */
(sizeof(function_9)/4 << 2) | /* FunctionLength */
(0 << 13) | /* RegF */
(1 << 16) | /* RegI */
(1 << 20) | /* H */
(0 << 21) | /* CR */
(7 << 23); /* FrameSize */
static const BYTE unwind_info_9[] = { DW(unwind_info_9_packed) };
static const struct results results_9[] =
{
/* offset fp handler pc frame offset registers */
{ 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
{ 0x04, 0x00, 0, ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
{ 0x08, 0x00, 0, ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
{ 0x0c, 0x00, 0, ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
{ 0x10, 0x00, 0, ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
{ 0x14, 0x00, 0, ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
{ 0x18, 0x00, 0, ORIG_LR, 0x070, TRUE, { {x19, 0x20}, {-1,-1} }},
{ 0x1c, 0x00, 0, ORIG_LR, 0x070, TRUE, { {x19, 0x20}, {-1,-1} }},
{ 0x20, 0x00, 0, ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
{ 0x24, 0x00, 0, ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
{ 0x28, 0x00, 0, ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
{ 0x2c, 0x00, 0, ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
{ 0x30, 0x00, 0, ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
{ 0x34, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
};
static const BYTE function_10[] =
{
0xfe, 0x0f, 0x1f, 0xf8, /* 00: str lr, [sp, #-16]! */
0xff, 0x43, 0x00, 0xd1, /* 04: sub sp, sp, #16 */
0x1f, 0x20, 0x03, 0xd5, /* 08: nop */
0xff, 0x43, 0x00, 0x91, /* 0c: add sp, sp, #16 */
0xfe, 0x07, 0x41, 0xf8, /* 10: ldr lr, [sp], #16 */
0xc0, 0x03, 0x5f, 0xd6, /* 14: ret */
};
static const DWORD unwind_info_10_packed =
(1 << 0) | /* Flag */
(sizeof(function_10)/4 << 2) | /* FunctionLength */
(0 << 13) | /* RegF */
(0 << 16) | /* RegI */
(0 << 20) | /* H */
(1 << 21) | /* CR */
(2 << 23); /* FrameSize */
static const BYTE unwind_info_10[] = { DW(unwind_info_10_packed) };
static const struct results results_10[] =
{
/* offset fp handler pc frame offset registers */
{ 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
{ 0x04, 0x00, 0, 0x00, 0x010, TRUE, { {lr, 0x00}, {-1,-1} }},
{ 0x08, 0x00, 0, 0x10, 0x020, TRUE, { {lr, 0x10}, {-1,-1} }},
{ 0x0c, 0x00, 0, 0x10, 0x020, TRUE, { {lr, 0x10}, {-1,-1} }},
{ 0x10, 0x00, 0, 0x00, 0x010, TRUE, { {lr, 0x00}, {-1,-1} }},
{ 0x14, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
};
static const BYTE function_11[] =
{
0xf3, 0x53, 0xbe, 0xa9, /* 00: stp x19, x20, [sp, #-32]! */
0xf5, 0x7b, 0x01, 0xa9, /* 04: stp x21, lr, [sp, #16] */
0xff, 0x43, 0x00, 0xd1, /* 08: sub sp, sp, #16 */
0x1f, 0x20, 0x03, 0xd5, /* 0c: nop */
0xff, 0x43, 0x00, 0x91, /* 10: add sp, sp, #16 */
0xf5, 0x7b, 0x41, 0xa9, /* 14: ldp x21, lr, [sp, #16] */
0xf3, 0x53, 0xc2, 0xa8, /* 18: ldp x19, x20, [sp], #32 */
0xc0, 0x03, 0x5f, 0xd6, /* 1c: ret */
};
static const DWORD unwind_info_11_packed =
(1 << 0) | /* Flag */
(sizeof(function_11)/4 << 2) | /* FunctionLength */
(0 << 13) | /* RegF */
(3 << 16) | /* RegI */
(0 << 20) | /* H */
(1 << 21) | /* CR */
(3 << 23); /* FrameSize */
static const BYTE unwind_info_11[] = { DW(unwind_info_11_packed) };
static const struct results results_11[] =
{
/* offset fp handler pc frame offset registers */
{ 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
{ 0x04, 0x00, 0, ORIG_LR, 0x020, TRUE, { {x19, 0x00}, {x20, 0x08}, {-1,-1} }},
{ 0x08, 0x00, 0, 0x18, 0x020, TRUE, { {x19, 0x00}, {x20, 0x08}, {x21, 0x10}, {lr, 0x18}, {-1,-1} }},
{ 0x0c, 0x00, 0, 0x28, 0x030, TRUE, { {x19, 0x10}, {x20, 0x18}, {x21, 0x20}, {lr, 0x28}, {-1,-1} }},
{ 0x10, 0x00, 0, 0x28, 0x030, TRUE, { {x19, 0x10}, {x20, 0x18}, {x21, 0x20}, {lr, 0x28}, {-1,-1} }},
{ 0x14, 0x00, 0, 0x18, 0x020, TRUE, { {x19, 0x00}, {x20, 0x08}, {x21, 0x10}, {lr, 0x18}, {-1,-1} }},
{ 0x18, 0x00, 0, ORIG_LR, 0x020, TRUE, { {x19, 0x00}, {x20, 0x08}, {-1,-1} }},
{ 0x1c, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
};
static const BYTE function_12[] =
{
0xf3, 0x53, 0xbf, 0xa9, /* 00: stp x19, x20, [sp, #-16]! */
0xfd, 0x7b, 0xbe, 0xa9, /* 04: stp x29, lr, [sp, #-32]! */
0xfd, 0x03, 0x00, 0x91, /* 08: mov x29, sp */
0x1f, 0x20, 0x03, 0xd5, /* 0c: nop */
0xbf, 0x03, 0x00, 0x91, /* 10: mov sp, x29 */
0xfd, 0x7b, 0xc2, 0xa8, /* 14: ldp x29, lr, [sp], #32 */
0xf3, 0x53, 0xc1, 0xa8, /* 18: ldp x19, x20, [sp], #16 */
0xc0, 0x03, 0x5f, 0xd6, /* 1c: ret */
};
static const DWORD unwind_info_12_packed =
(1 << 0) | /* Flag */
(sizeof(function_12)/4 << 2) | /* FunctionLength */
(0 << 13) | /* RegF */
(2 << 16) | /* RegI */
(0 << 20) | /* H */
(3 << 21) | /* CR */
(3 << 23); /* FrameSize */
static const BYTE unwind_info_12[] = { DW(unwind_info_12_packed) };
static const struct results results_12[] =
{
/* offset fp handler pc frame offset registers */
{ 0x00, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
{ 0x04, 0x10, 0, ORIG_LR, 0x010, TRUE, { {x19, 0x00}, {x20, 0x08}, {-1,-1} }},
{ 0x08, 0x10, 0, 0x08, 0x030, TRUE, { {x19, 0x20}, {x20, 0x28}, {x29, 0x00}, {lr, 0x08}, {-1,-1} }},
{ 0x0c, 0x10, 0, 0x18, 0x040, TRUE, { {x19, 0x30}, {x20, 0x38}, {x29, 0x10}, {lr, 0x18}, {-1,-1} }},
{ 0x10, 0x10, 0, 0x18, 0x040, TRUE, { {x19, 0x30}, {x20, 0x38}, {x29, 0x10}, {lr, 0x18}, {-1,-1} }},
{ 0x14, 0x10, 0, 0x08, 0x030, TRUE, { {x19, 0x20}, {x20, 0x28}, {x29, 0x00}, {lr, 0x08}, {-1,-1} }},
{ 0x18, 0x10, 0, ORIG_LR, 0x010, TRUE, { {x19, 0x00}, {x20, 0x08}, {-1,-1} }},
{ 0x1c, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
};
static const BYTE function_13[] =
{
0xf3, 0x53, 0xbf, 0xa9, /* 00: stp x19, x20, [sp, #-16]! */
0xff, 0x43, 0x08, 0xd1, /* 04: sub sp, sp, #528 */
0xfd, 0x7b, 0x00, 0xd1, /* 08: stp x29, lr, [sp] */
0xfd, 0x03, 0x00, 0x91, /* 0c: mov x29, sp */
0x1f, 0x20, 0x03, 0xd5, /* 10: nop */
0xbf, 0x03, 0x00, 0x91, /* 14: mov sp, x29 */
0xfd, 0x7b, 0x40, 0xa9, /* 18: ldp x29, lr, [sp] */
0xff, 0x43, 0x08, 0x91, /* 1c: add sp, sp, #528 */
0xf3, 0x53, 0xc1, 0xa8, /* 20: ldp x19, x20, [sp], #16 */
0xc0, 0x03, 0x5f, 0xd6, /* 24: ret */
};
static const DWORD unwind_info_13_packed =
(1 << 0) | /* Flag */
(sizeof(function_13)/4 << 2) | /* FunctionLength */
(0 << 13) | /* RegF */
(2 << 16) | /* RegI */
(0 << 20) | /* H */
(3 << 21) | /* CR */
(34 << 23); /* FrameSize */
static const BYTE unwind_info_13[] = { DW(unwind_info_13_packed) };
static const struct results results_13[] =
{
/* offset fp handler pc frame offset registers */
{ 0x00, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
{ 0x04, 0x10, 0, ORIG_LR, 0x010, TRUE, { {x19, 0x00}, {x20, 0x08}, {-1,-1} }},
{ 0x08, 0x10, 0, ORIG_LR, 0x220, TRUE, { {x19, 0x210}, {x20, 0x218}, {-1,-1} }},
{ 0x0c, 0x10, 0, 0x08, 0x220, TRUE, { {x19, 0x210}, {x20, 0x218}, {x29, 0x00}, {lr, 0x08}, {-1,-1} }},
{ 0x10, 0x10, 0, 0x18, 0x230, TRUE, { {x19, 0x220}, {x20, 0x228}, {x29, 0x10}, {lr, 0x18}, {-1,-1} }},
{ 0x14, 0x10, 0, 0x18, 0x230, TRUE, { {x19, 0x220}, {x20, 0x228}, {x29, 0x10}, {lr, 0x18}, {-1,-1} }},
{ 0x18, 0x10, 0, 0x08, 0x220, TRUE, { {x19, 0x210}, {x20, 0x218}, {x29, 0x00}, {lr, 0x08}, {-1,-1} }},
{ 0x1c, 0x10, 0, ORIG_LR, 0x220, TRUE, { {x19, 0x210}, {x20, 0x218}, {-1,-1} }},
{ 0x20, 0x10, 0, ORIG_LR, 0x010, TRUE, { {x19, 0x00}, {x20, 0x08}, {-1,-1} }},
{ 0x24, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
};
static const struct unwind_test tests[] = static const struct unwind_test tests[] =
{ {
#define TEST(func, unwind, unwind_packed, results) \ #define TEST(func, unwind, unwind_packed, results) \
@ -4818,6 +5120,14 @@ static void test_virtual_unwind(void)
TEST(function_3, unwind_info_3, 0, results_3), TEST(function_3, unwind_info_3, 0, results_3),
TEST(function_4, unwind_info_4, 0, results_4), TEST(function_4, unwind_info_4, 0, results_4),
TEST(function_5, unwind_info_5, 0, results_5), TEST(function_5, unwind_info_5, 0, results_5),
TEST(function_6, unwind_info_6, 1, results_6),
TEST(function_7, unwind_info_7, 1, results_7),
TEST(function_8, unwind_info_8, 1, results_8),
TEST(function_9, unwind_info_9, 1, results_9),
TEST(function_10, unwind_info_10, 1, results_10),
TEST(function_11, unwind_info_11, 1, results_11),
TEST(function_12, unwind_info_12, 1, results_12),
TEST(function_13, unwind_info_13, 1, results_13),
#undef TEST #undef TEST
}; };
unsigned int i; unsigned int i;