ntdll: Add support for the save_any_reg ARM64 unwind code.
Based on a patch by Billy Laws.
This commit is contained in:
parent
7c4ca6ff74
commit
a271fc9e19
2 changed files with 95 additions and 3 deletions
|
@ -8092,6 +8092,7 @@ static void test_collided_unwind(void)
|
|||
#define UWOP_END 0xE4
|
||||
#define UWOP_END_C 0xE5
|
||||
#define UWOP_SAVE_NEXT 0xE6
|
||||
#define UWOP_SAVE_ANY_REG(reg,offset) 0xE7,(reg),(offset)
|
||||
#define UWOP_TRAP_FRAME 0xE8
|
||||
#define UWOP_MACHINE_FRAME 0xE9
|
||||
#define UWOP_CONTEXT 0xEA
|
||||
|
@ -8164,8 +8165,6 @@ static void call_virtual_unwind( int testnum, const struct unwind_test *test )
|
|||
else
|
||||
memcpy(&runtime_func.UnwindData, test->unwind_info, 4);
|
||||
|
||||
trace( "code: %p stack: %p\n", code_mem, fake_stack );
|
||||
|
||||
for (i = 0; i < test->nb_results; i++)
|
||||
{
|
||||
memset( &ctx_ptr, 0, sizeof(ctx_ptr) );
|
||||
|
@ -8900,6 +8899,59 @@ static void test_virtual_unwind(void)
|
|||
{ 0x24, 0x10, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
|
||||
};
|
||||
|
||||
static const BYTE function_14[] =
|
||||
{
|
||||
0xe6, 0x9f, 0xba, 0xad, /* 00: stp q6, q7, [sp, #-0xb0]! */
|
||||
0xe8, 0x27, 0x01, 0xad, /* 04: stp q8, q9, [sp, #0x20] */
|
||||
0xea, 0x2f, 0x02, 0xad, /* 08: stp q10, q11, [sp, #0x40] */
|
||||
0xec, 0x37, 0x03, 0xad, /* 0c: stp q12, q13, [sp, #0x60] */
|
||||
0xee, 0x3f, 0x04, 0xad, /* 10: stp q14, q15, [sp, #0x80] */
|
||||
0xfd, 0x7b, 0x0a, 0xa9, /* 14: stp x29, x30, [sp, #0xa0] */
|
||||
0xfd, 0x83, 0x02, 0x91, /* 18: add x29, sp, #0xa0 */
|
||||
0x1f, 0x20, 0x03, 0xd5, /* 1c: nop */
|
||||
0xfd, 0x7b, 0x4a, 0xa9, /* 20: ldp x29, x30, [sp, #0xa0] */
|
||||
0xee, 0x3f, 0x44, 0xad, /* 24: ldp q14, q15, [sp, #0x80] */
|
||||
0xec, 0x37, 0x43, 0xad, /* 28: ldp q12, q13, [sp, #0x60] */
|
||||
0xea, 0x2f, 0x42, 0xad, /* 2c: ldp q10, q11, [sp, #0x40] */
|
||||
0xe8, 0x27, 0x41, 0xad, /* 30: ldp q8, q9, [sp, #0x20] */
|
||||
0xe6, 0x9f, 0xc5, 0xac, /* 34: ldp q6, q7, [sp], #0xb0 */
|
||||
0xc0, 0x03, 0x5f, 0xd6, /* 38: ret */
|
||||
};
|
||||
|
||||
static const DWORD unwind_info_14_header =
|
||||
(sizeof(function_14)/4) | /* function length */
|
||||
(0 << 20) | /* X */
|
||||
(1 << 21) | /* E */
|
||||
(2 << 22) | /* epilog */
|
||||
(5 << 27); /* codes */
|
||||
|
||||
static const BYTE unwind_info_14[] =
|
||||
{
|
||||
DW(unwind_info_14_header),
|
||||
UWOP_ADD_FP(0xa0), /* 18: add x29, sp, #0xa0 */
|
||||
UWOP_SAVE_FPLR(0xa0), /* 14: stp x29, x30, [sp, #0xa0] */
|
||||
UWOP_SAVE_ANY_REG(0x4e,0x88), /* 10: stp q14, q15, [sp, #0x80] */
|
||||
UWOP_SAVE_NEXT, /* 0c: stp q12, q13, [sp, #0x60] */
|
||||
UWOP_SAVE_ANY_REG(0x4a,0x84), /* 08: stp q10, q11, [sp, #0x40] */
|
||||
UWOP_SAVE_ANY_REG(0x48,0x82), /* 04: stp q8, q9, [sp, #0x20] */
|
||||
UWOP_SAVE_ANY_REG(0x66,0x8a), /* 00: stp q6, q7, [sp, #-0xb0]! */
|
||||
UWOP_END,
|
||||
UWOP_NOP /* padding */
|
||||
};
|
||||
|
||||
static const struct results results_14[] =
|
||||
{
|
||||
/* offset fp handler pc frame offset registers */
|
||||
{ 0x00, 0x00, 0, ORIG_LR, 0x000, TRUE, { {-1,-1} }},
|
||||
{ 0x04, 0x00, 0, ORIG_LR, 0x0b0, TRUE, { {d6, 0x00}, {d7, 0x10}, {-1,-1} }},
|
||||
{ 0x08, 0x00, 0, ORIG_LR, 0x0b0, TRUE, { {d6, 0x00}, {d7, 0x10}, {d8, 0x20}, {d9, 0x30}, {-1,-1} }},
|
||||
{ 0x0c, 0x00, 0, ORIG_LR, 0x0b0, TRUE, { {d6, 0x00}, {d7, 0x10}, {d8, 0x20}, {d9, 0x30}, {d10, 0x40}, {d11, 0x50}, {-1,-1} }},
|
||||
{ 0x10, 0x00, 0, ORIG_LR, 0x0b0, TRUE, { {d6, 0x00}, {d7, 0x10}, {d8, 0x20}, {d9, 0x30}, {d10, 0x40}, {d11, 0x50}, {d12, 0x60}, {d13, 0x70}, {-1,-1} }},
|
||||
{ 0x14, 0x00, 0, ORIG_LR, 0x0b0, TRUE, { {d6, 0x00}, {d7, 0x10}, {d8, 0x20}, {d9, 0x30}, {d10, 0x40}, {d11, 0x50}, {d12, 0x60}, {d13, 0x70}, {d14, 0x80}, {d15, 0x90}, {-1,-1} }},
|
||||
{ 0x18, 0x00, 0, 0xa8, 0x0b0, TRUE, { {d6, 0x00}, {d7, 0x10}, {d8, 0x20}, {d9, 0x30}, {d10, 0x40}, {d11, 0x50}, {d12, 0x60}, {d13, 0x70}, {d14, 0x80}, {d15, 0x90}, {lr, 0xa8}, {x29, 0xa0}, {-1,-1} }},
|
||||
{ 0x1c, 0xa0, 0, 0xa8, 0x0b0, TRUE, { {d6, 0x00}, {d7, 0x10}, {d8, 0x20}, {d9, 0x30}, {d10, 0x40}, {d11, 0x50}, {d12, 0x60}, {d13, 0x70}, {d14, 0x80}, {d15, 0x90}, {lr, 0xa8}, {x29, 0xa0}, {-1,-1} }},
|
||||
};
|
||||
|
||||
static const struct unwind_test tests[] =
|
||||
{
|
||||
#define TEST(func, unwind, unwind_packed, results) \
|
||||
|
@ -8918,6 +8970,7 @@ static void test_virtual_unwind(void)
|
|||
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),
|
||||
TEST(function_14, unwind_info_14, 0, results_14),
|
||||
#undef TEST
|
||||
};
|
||||
unsigned int i;
|
||||
|
|
|
@ -296,7 +296,7 @@ static const BYTE unwind_code_len[256] =
|
|||
/* 80 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
/* a0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
/* c0 */ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||
/* e0 */ 4,1,2,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
||||
/* e0 */ 4,1,2,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
||||
};
|
||||
|
||||
static unsigned int get_sequence_len( BYTE *ptr, BYTE *end )
|
||||
|
@ -336,6 +336,40 @@ static void restore_fpregs( int reg, int count, int pos, ARM64_NT_CONTEXT *conte
|
|||
if (pos < 0) context->Sp += -8 * pos;
|
||||
}
|
||||
|
||||
static void restore_qregs( int reg, int count, int pos, ARM64_NT_CONTEXT *context,
|
||||
KNONVOLATILE_CONTEXT_POINTERS_ARM64 *ptrs )
|
||||
{
|
||||
int i, offset = max( 0, pos );
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (ptrs && reg + i >= 8) (&ptrs->D8)[reg + i - 8] = (DWORD64 *)context->Sp + 2 * (i + offset);
|
||||
context->V[reg + i].Low = ((DWORD64 *)context->Sp)[2 * (i + offset)];
|
||||
context->V[reg + i].High = ((DWORD64 *)context->Sp)[2 * (i + offset) + 1];
|
||||
}
|
||||
if (pos < 0) context->Sp += -16 * pos;
|
||||
}
|
||||
|
||||
static void restore_any_reg( int reg, int count, int type, int pos, ARM64_NT_CONTEXT *context,
|
||||
KNONVOLATILE_CONTEXT_POINTERS_ARM64 *ptrs )
|
||||
{
|
||||
if (reg & 0x20) pos = -pos - 1;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
if (count > 1 || pos < 0) pos *= 2;
|
||||
restore_regs( reg & 0x1f, count, pos, context, ptrs );
|
||||
break;
|
||||
case 1:
|
||||
if (count > 1 || pos < 0) pos *= 2;
|
||||
restore_fpregs( reg & 0x1f, count, pos, context, ptrs );
|
||||
break;
|
||||
case 2:
|
||||
restore_qregs( reg & 0x1f, count, pos, context, ptrs );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void do_pac_auth( ARM64_NT_CONTEXT *context )
|
||||
{
|
||||
register DWORD64 x17 __asm__( "x17" ) = context->Lr;
|
||||
|
@ -421,6 +455,11 @@ static void process_unwind_codes( BYTE *ptr, BYTE *end, ARM64_NT_CONTEXT *contex
|
|||
ptr += len;
|
||||
continue;
|
||||
}
|
||||
else if (*ptr == 0xe7) /* save_any_reg */
|
||||
{
|
||||
restore_any_reg( ptr[1], (ptr[1] & 0x40) ? save_next : 1,
|
||||
ptr[2] >> 6, ptr[2] & 0x3f, context, ptrs );
|
||||
}
|
||||
else if (*ptr == 0xe9) /* MSFT_OP_MACHINE_FRAME */
|
||||
{
|
||||
context->Pc = ((DWORD64 *)context->Sp)[1];
|
||||
|
|
Loading…
Add table
Reference in a new issue