diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 85d3d139e55..722f3126278 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -8119,6 +8119,7 @@ struct unwind_test const struct results *results; unsigned int nb_results; int unwound_clear; + int last_set_reg_ptr; }; enum regs @@ -8170,7 +8171,7 @@ static void call_virtual_unwind( int testnum, const struct unwind_test *test ) for (i = 0; i < test->nb_results; i++) { winetest_push_context( "%u/%u", testnum, i ); - memset( &ctx_ptr, 0, sizeof(ctx_ptr) ); + memset( &ctx_ptr, 0x55, sizeof(ctx_ptr) ); memset( &context, 0x55, sizeof(context) ); memset( &unset_reg, 0x55, sizeof(unset_reg) ); for (j = 0; j < 256; j++) fake_stack[j] = j * 8; @@ -8255,17 +8256,27 @@ static void call_virtual_unwind( int testnum, const struct unwind_test *test ) if (test->results[i].regs[k][0] == j) break; } - if (regptr) - ok( k < nb_regs, "register %s should not be set to %llx\n", reg_names[j], regval ); - if (k < nb_regs) { ok( regval == test->results[i].regs[k][1], "register %s wrong %llx/%llx\n", reg_names[j], regval, test->results[i].regs[k][1] ); + if (regptr) + { + if (test->last_set_reg_ptr && j > test->last_set_reg_ptr && j <= 30) + ok( regptr == (void *)unset_reg, "register %s should not have pointer set\n", reg_names[j] ); + else + { + ok( regptr != (void *)unset_reg, "register %s should have pointer set\n", reg_names[j] ); + if (regptr != (void *)unset_reg) + ok( *regptr == regval, "register %s should have reg pointer to %llx / %llx\n", + reg_names[j], *regptr, regval ); + } + } } else { ok( k == nb_regs, "register %s should be set\n", reg_names[j] ); + ok( !regptr || regptr == (void *)unset_reg, "register %s should not have pointer set\n", reg_names[j] ); if (j == lr) ok( context.Lr == ORIG_LR, "register lr wrong %llx/unset\n", context.Lr ); else if (j == x29) @@ -9052,26 +9063,26 @@ static void test_virtual_unwind(void) static const struct unwind_test tests[] = { -#define TEST(func, unwind, unwind_packed, results, unwound_clear) \ - { func, sizeof(func), unwind, unwind_packed ? 0 : sizeof(unwind), results, ARRAY_SIZE(results), unwound_clear } - TEST(function_0, unwind_info_0, 0, results_0, 0), - TEST(function_1, unwind_info_1, 1, results_1, 0), - TEST(function_2, unwind_info_2, 0, results_2, 1), - TEST(function_3, unwind_info_3, 0, results_3, 1), - TEST(function_4, unwind_info_4, 0, results_4, 0), - TEST(function_5, unwind_info_5, 0, results_5, 0), - TEST(function_6, unwind_info_6, 1, results_6, 0), - TEST(function_7, unwind_info_7, 1, results_7, 0), - TEST(function_8, unwind_info_8, 1, results_8, 0), - TEST(function_9, unwind_info_9, 1, results_9, 0), - TEST(function_10, unwind_info_10, 1, results_10, 0), - TEST(function_11, unwind_info_11, 1, results_11, 0), - TEST(function_12, unwind_info_12, 1, results_12, 0), - TEST(function_13, unwind_info_13, 1, results_13, 0), - TEST(function_14, unwind_info_14, 0, results_14, 0), - TEST(function_15, unwind_info_15, 0, results_15, 0), - TEST(function_16, unwind_info_16, 0, results_16, 1), - TEST(function_17, unwind_info_17, 0, results_17, 2), +#define TEST(func, unwind, unwind_packed, results, unwound_clear, last_ptr) \ + { func, sizeof(func), unwind, unwind_packed ? 0 : sizeof(unwind), results, ARRAY_SIZE(results), unwound_clear, last_ptr } + TEST(function_0, unwind_info_0, 0, results_0, 0, 0), + TEST(function_1, unwind_info_1, 1, results_1, 0, 0), + TEST(function_2, unwind_info_2, 0, results_2, 1, 0), + TEST(function_3, unwind_info_3, 0, results_3, 1, x28), + TEST(function_4, unwind_info_4, 0, results_4, 0, 0), + TEST(function_5, unwind_info_5, 0, results_5, 0, 0), + TEST(function_6, unwind_info_6, 1, results_6, 0, 0), + TEST(function_7, unwind_info_7, 1, results_7, 0, 0), + TEST(function_8, unwind_info_8, 1, results_8, 0, 0), + TEST(function_9, unwind_info_9, 1, results_9, 0, 0), + TEST(function_10, unwind_info_10, 1, results_10, 0, 0), + TEST(function_11, unwind_info_11, 1, results_11, 0, 0), + TEST(function_12, unwind_info_12, 1, results_12, 0, 0), + TEST(function_13, unwind_info_13, 1, results_13, 0, 0), + TEST(function_14, unwind_info_14, 0, results_14, 0, 0), + TEST(function_15, unwind_info_15, 0, results_15, 0, 0), + TEST(function_16, unwind_info_16, 0, results_16, 1, x18), + TEST(function_17, unwind_info_17, 0, results_17, 2, 0), #undef TEST }; unsigned int i; diff --git a/dlls/ntdll/unwind.c b/dlls/ntdll/unwind.c index a7cd28785b8..5c8a01e4e8a 100644 --- a/dlls/ntdll/unwind.c +++ b/dlls/ntdll/unwind.c @@ -388,7 +388,7 @@ static void do_pac_auth( ARM64_NT_CONTEXT *context ) static void process_unwind_codes( BYTE *ptr, BYTE *end, ARM64_NT_CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS_ARM64 *ptrs, int skip ) { - unsigned int val, len, save_next = 2; + unsigned int i, val, len, save_next = 2; /* skip codes */ while (ptr < end && skip) @@ -473,6 +473,11 @@ static void process_unwind_codes( BYTE *ptr, BYTE *end, ARM64_NT_CONTEXT *contex ARM64_NT_CONTEXT *src_ctx = (ARM64_NT_CONTEXT *)context->Sp; *context = *src_ctx; context->ContextFlags = flags | (src_ctx->ContextFlags & CONTEXT_UNWOUND_TO_CALL); + if (ptrs) + { + for (i = 19; i < 29; i++) (&ptrs->X19)[i - 19] = &src_ctx->X[i]; + for (i = 8; i < 16; i++) (&ptrs->D8)[i - 8] = &src_ctx->V[i].Low; + } } else if (*ptr == 0xeb) /* MSFT_OP_EC_CONTEXT */ { @@ -480,6 +485,7 @@ static void process_unwind_codes( BYTE *ptr, BYTE *end, ARM64_NT_CONTEXT *contex ARM64EC_NT_CONTEXT *src_ctx = (ARM64EC_NT_CONTEXT *)context->Sp; context_x64_to_arm( context, src_ctx ); context->ContextFlags = flags | (src_ctx->ContextFlags & CONTEXT_UNWOUND_TO_CALL); + if (ptrs) for (i = 8; i < 16; i++) (&ptrs->D8)[i - 8] = &src_ctx->V[i].Low; } else if (*ptr == 0xec) /* MSFT_OP_CLEAR_UNWOUND_TO_CALL */ { @@ -562,10 +568,9 @@ static void *unwind_packed_data( ULONG_PTR base, ULONG_PTR pc, ARM64_RUNTIME_FUN { if (func->CR == 3 || func->CR == 2) { - DWORD64 *fp = (DWORD64 *) context->Fp; /* X[29] */ + /* mov x29,sp */ context->Sp = context->Fp; - context->X[29] = fp[0]; - context->X[30] = fp[1]; + restore_regs( 29, 2, 0, context, ptrs ); } context->Sp += local_size; if (fp_size) restore_fpregs( 8, fp_regs, int_regs, context, ptrs );