From 9e81c16f180c7859b44c3b2f69fb23bde49c954e Mon Sep 17 00:00:00 2001 From: Andrew Haberlandt Date: Fri, 27 Dec 2024 00:54:33 -0500 Subject: [PATCH 1/6] i5383: Fix macOS arm64 test build/run - Disable selfmod tests due to build failures on M3 - Fix macOS build for mangle_pauth test (test still fails for some reason) - Mark dump_ucontext as NYI on macOS - Fixes NULL sigcontext_t in os_forge_exception - Adds -vm_size 500M to client tests to avoid reachablity assert --- core/unix/signal.c | 9 +++++++-- suite/tests/CMakeLists.txt | 8 ++++++-- suite/tests/client-interface/cbr-retarget.c | 8 ++++++-- suite/tests/client-interface/strace.dll.c | 4 +++- suite/tests/linux/mangle_pauth.c | 7 ++++--- suite/tests/tools.c | 6 +++++- 6 files changed, 31 insertions(+), 11 deletions(-) diff --git a/core/unix/signal.c b/core/unix/signal.c index 55f3eafa390..1f44aea51d7 100644 --- a/core/unix/signal.c +++ b/core/unix/signal.c @@ -7691,8 +7691,6 @@ os_forge_exception(app_pc target_pc, dr_exception_type_t type) sigframe_rt_t *frame = (sigframe_rt_t *)frame_no_xstate; int sig; dr_where_am_i_t cur_whereami = dcontext->whereami; - kernel_ucontext_t *uc = get_ucontext_from_rt_frame(frame); - sigcontext_t *sc = SIGCXT_FROM_UCXT(uc); switch (type) { case ILLEGAL_INSTRUCTION_EXCEPTION: sig = SIGILL; break; case UNREADABLE_MEMORY_EXECUTION_EXCEPTION: sig = SIGSEGV; break; @@ -7710,6 +7708,13 @@ os_forge_exception(app_pc target_pc, dr_exception_type_t type) * to a plain frame on delivery. */ memset(frame, 0, sizeof(*frame)); + + kernel_ucontext_t *uc = get_ucontext_from_rt_frame(frame); +#if defined(MACOS) + uc->uc_mcontext64 = &frame->mc; +#endif + sigcontext_t *sc = SIGCXT_FROM_UCXT(uc); + frame->info.si_signo = sig; /* Set si_code to match what would happen natively. We also need this to * avoid the !is_sys_kill() check in record_pending_signal() to avoid an diff --git a/suite/tests/CMakeLists.txt b/suite/tests/CMakeLists.txt index 6ba6d409f91..ff80fba0c91 100644 --- a/suite/tests/CMakeLists.txt +++ b/suite/tests/CMakeLists.txt @@ -1242,6 +1242,10 @@ if (CMAKE_CROSSCOMPILING AND DEFINED CMAKE_FIND_ROOT_PATH) set(dr_test_ops -xarch_root ${CMAKE_FIND_ROOT_PATH} ${dr_test_ops}) endif () +if (APPLE AND AARCH64) + set(dr_test_ops -vm_size 500M ${dr_test_ops}) +endif () + function(runtest_cmd outcmd outops key native standalone_dr dr_ops_aux separate_script) # assumes tools have been built: enforced at top level set(dr_ops ${dr_test_ops} ${dr_ops_aux} ${TEST_OPTIONS}) @@ -6040,7 +6044,7 @@ if (NOT ARM) # FIXME i#1551: fix bugs on ARM endif () endif (NOT ARM) -if (X86 OR AARCH64) # FIXME i#1551: port asm to ARM +if (X86 OR AARCH64 AND NOT (APPLE AND AARCH64)) # FIXME i#1551: port asm to ARM tobuild(security-common.selfmod2 security-common/selfmod2.c) tochcon(security-common.selfmod2 textrel_shlib_t) @@ -6059,7 +6063,7 @@ if (X86) # FIXME i#1551, i#1569: port asm to ARM and AArch64 endif () endif (X86) -if (X64 AND NOT AARCH64 AND NOT RISCV64) # FIXME i#1569: get working on AArch64 +if (X64 AND NOT AARCH64 AND NOT RISCV64 AND NOT (APPLE AND AARCH64)) # FIXME i#1569: get working on AArch64 # Reachability tests # Floating DR lib. We'd have to build a 2nd dynamorio.dll on Windows so diff --git a/suite/tests/client-interface/cbr-retarget.c b/suite/tests/client-interface/cbr-retarget.c index 29dc48ebef5..86d0b382eb1 100644 --- a/suite/tests/client-interface/cbr-retarget.c +++ b/suite/tests/client-interface/cbr-retarget.c @@ -62,9 +62,13 @@ main(void) } ; #elif defined(AARCH64) - __asm("cbnz xzr, skip"); + __asm("cbnz xzr, 1f"); +# ifdef MACOS + __asm("bl _foo"); +# else __asm("bl foo"); - __asm("skip:"); +# endif + __asm("1:"); #else __asm("movl $0x0, %ecx"); __asm("cmp $0x0, %ecx"); diff --git a/suite/tests/client-interface/strace.dll.c b/suite/tests/client-interface/strace.dll.c index a07e8eaa955..c15e81fca99 100644 --- a/suite/tests/client-interface/strace.dll.c +++ b/suite/tests/client-interface/strace.dll.c @@ -349,7 +349,9 @@ event_post_syscall(void *drcontext, int sysnum) static int get_write_sysnum(void) { -#ifdef UNIX +#if defined(MACOS) + return SYS_write_nocancel; +#elif defined(UNIX) return SYS_write; #else byte *entry; diff --git a/suite/tests/linux/mangle_pauth.c b/suite/tests/linux/mangle_pauth.c index ad530a533c3..9f0f028b615 100644 --- a/suite/tests/linux/mangle_pauth.c +++ b/suite/tests/linux/mangle_pauth.c @@ -109,8 +109,9 @@ handle_signal(int signal, siginfo_t *siginfo, ucontext_t *ucxt) * We need to strip the PAC from from the fault address to canonicalize it and * compare it to the expected branch target address. */ - const uintptr_t fault_pc = strip_pac(ucxt->uc_mcontext.pc); - LOG(" ucxt->uc_mcontext.pc = " PFX "\n", ucxt->uc_mcontext.pc); + const uintptr_t pc = IF_MACOS_ELSE(ucxt->uc_mcontext->__ss.__pc, ucxt->uc_mcontext.pc); + const uintptr_t fault_pc = strip_pac(pc); + LOG(" ucxt->uc_mcontext.pc = " PFX "\n", pc); LOG(" fault_pc = " PFX "\n", fault_pc); LOG(" branch_target_addr = " PFX "\n", branch_target_addr); if (fault_pc == branch_target_addr) @@ -123,7 +124,7 @@ handle_signal(int signal, siginfo_t *siginfo, ucontext_t *ucxt) /* CPU has FEAT_FPACCOMBINE so the branch instruction generated an authentication * failure exception and the fault PC should match the branch instruction address. */ - const uintptr_t fault_pc = ucxt->uc_mcontext.pc; + const uintptr_t fault_pc = IF_MACOS_ELSE(ucxt->uc_mcontext->__ss.__pc, ucxt->uc_mcontext.pc); LOG(" fault_pc = " PFX "\n", fault_pc); LOG(" branch_instr_addr = " PFX "\n", branch_instr_addr); if (fault_pc == branch_instr_addr) diff --git a/suite/tests/tools.c b/suite/tests/tools.c index 44560c533f0..c696c058b1b 100644 --- a/suite/tests/tools.c +++ b/suite/tests/tools.c @@ -506,7 +506,10 @@ intercept_signal(int sig, handler_3_t handler, bool sigstack) void dump_ucontext(ucontext_t *ucxt, bool is_sve, int vl_bytes) { - struct _aarch64_ctx *head = (struct _aarch64_ctx *)(ucxt->uc_mcontext.RESERVED); +#ifdef MACOS + assert(false); /* NYI */ +#else + struct _aarch64_ctx *head = (struct _aarch64_ctx *)(ucxt->uc_mcontext64.__reserved); assert(head->magic == FPSIMD_MAGIC); assert(head->size == sizeof(struct fpsimd_context)); @@ -602,6 +605,7 @@ dump_ucontext(ucontext_t *ucxt, bool is_sve, int vl_bytes) } } # endif +#endif } # endif From 9d52c6554d1568fae00161db78f2c635cea4551b Mon Sep 17 00:00:00 2001 From: Andrew Haberlandt Date: Fri, 27 Dec 2024 06:10:07 +0000 Subject: [PATCH 2/6] clang-format --- suite/tests/linux/mangle_pauth.c | 6 ++++-- suite/tests/tools.c | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/suite/tests/linux/mangle_pauth.c b/suite/tests/linux/mangle_pauth.c index 9f0f028b615..a2e73034f37 100644 --- a/suite/tests/linux/mangle_pauth.c +++ b/suite/tests/linux/mangle_pauth.c @@ -109,7 +109,8 @@ handle_signal(int signal, siginfo_t *siginfo, ucontext_t *ucxt) * We need to strip the PAC from from the fault address to canonicalize it and * compare it to the expected branch target address. */ - const uintptr_t pc = IF_MACOS_ELSE(ucxt->uc_mcontext->__ss.__pc, ucxt->uc_mcontext.pc); + const uintptr_t pc = + IF_MACOS_ELSE(ucxt->uc_mcontext->__ss.__pc, ucxt->uc_mcontext.pc); const uintptr_t fault_pc = strip_pac(pc); LOG(" ucxt->uc_mcontext.pc = " PFX "\n", pc); LOG(" fault_pc = " PFX "\n", fault_pc); @@ -124,7 +125,8 @@ handle_signal(int signal, siginfo_t *siginfo, ucontext_t *ucxt) /* CPU has FEAT_FPACCOMBINE so the branch instruction generated an authentication * failure exception and the fault PC should match the branch instruction address. */ - const uintptr_t fault_pc = IF_MACOS_ELSE(ucxt->uc_mcontext->__ss.__pc, ucxt->uc_mcontext.pc); + const uintptr_t fault_pc = + IF_MACOS_ELSE(ucxt->uc_mcontext->__ss.__pc, ucxt->uc_mcontext.pc); LOG(" fault_pc = " PFX "\n", fault_pc); LOG(" branch_instr_addr = " PFX "\n", branch_instr_addr); if (fault_pc == branch_instr_addr) diff --git a/suite/tests/tools.c b/suite/tests/tools.c index c696c058b1b..c5a8a312044 100644 --- a/suite/tests/tools.c +++ b/suite/tests/tools.c @@ -506,9 +506,9 @@ intercept_signal(int sig, handler_3_t handler, bool sigstack) void dump_ucontext(ucontext_t *ucxt, bool is_sve, int vl_bytes) { -#ifdef MACOS +# ifdef MACOS assert(false); /* NYI */ -#else +# else struct _aarch64_ctx *head = (struct _aarch64_ctx *)(ucxt->uc_mcontext64.__reserved); assert(head->magic == FPSIMD_MAGIC); assert(head->size == sizeof(struct fpsimd_context)); @@ -524,7 +524,7 @@ dump_ucontext(ucontext_t *ucxt, bool is_sve, int vl_bytes) } print("\n"); -# ifndef DR_HOST_NOT_TARGET +# ifndef DR_HOST_NOT_TARGET if (is_sve) { size_t offset = sizeof(struct fpsimd_context); struct _aarch64_ctx *next_head = @@ -604,8 +604,8 @@ dump_ucontext(ucontext_t *ucxt, bool is_sve, int vl_bytes) next_head = (struct _aarch64_ctx *)(ucxt->uc_mcontext.RESERVED + offset); } } +# endif # endif -#endif } # endif From 7d1af39f3b1aa619deff009bafef94e8092098af Mon Sep 17 00:00:00 2001 From: Andrew Haberlandt Date: Fri, 27 Dec 2024 06:19:37 +0000 Subject: [PATCH 3/6] fix copy/paste error --- suite/tests/tools.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/suite/tests/tools.c b/suite/tests/tools.c index c5a8a312044..22008014564 100644 --- a/suite/tests/tools.c +++ b/suite/tests/tools.c @@ -509,7 +509,7 @@ dump_ucontext(ucontext_t *ucxt, bool is_sve, int vl_bytes) # ifdef MACOS assert(false); /* NYI */ # else - struct _aarch64_ctx *head = (struct _aarch64_ctx *)(ucxt->uc_mcontext64.__reserved); + struct _aarch64_ctx *head = (struct _aarch64_ctx *)(ucxt->uc_mcontext.RESERVED); assert(head->magic == FPSIMD_MAGIC); assert(head->size == sizeof(struct fpsimd_context)); From daaeb2e594211f47aacf0c025ace817e3d330077 Mon Sep 17 00:00:00 2001 From: Andrew Haberlandt Date: Fri, 27 Dec 2024 01:33:00 -0500 Subject: [PATCH 4/6] Fix uc_mcontext field initialization on macOS --- core/unix/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unix/signal.c b/core/unix/signal.c index 1f44aea51d7..61bc2e7bf90 100644 --- a/core/unix/signal.c +++ b/core/unix/signal.c @@ -7711,7 +7711,7 @@ os_forge_exception(app_pc target_pc, dr_exception_type_t type) kernel_ucontext_t *uc = get_ucontext_from_rt_frame(frame); #if defined(MACOS) - uc->uc_mcontext64 = &frame->mc; + uc->IF_X64_ELSE(uc_mcontext64, uc_mcontext) = (sigcontext_t*)&frame->mc; #endif sigcontext_t *sc = SIGCXT_FROM_UCXT(uc); From 28dc822dbdfa35173e725ef760c478688d727f1b Mon Sep 17 00:00:00 2001 From: Andrew Haberlandt Date: Fri, 27 Dec 2024 02:02:57 -0500 Subject: [PATCH 5/6] fix --- core/unix/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unix/signal.c b/core/unix/signal.c index 61bc2e7bf90..282e84a7375 100644 --- a/core/unix/signal.c +++ b/core/unix/signal.c @@ -7711,7 +7711,7 @@ os_forge_exception(app_pc target_pc, dr_exception_type_t type) kernel_ucontext_t *uc = get_ucontext_from_rt_frame(frame); #if defined(MACOS) - uc->IF_X64_ELSE(uc_mcontext64, uc_mcontext) = (sigcontext_t*)&frame->mc; + uc->IF_X64_ELSE(uc_mcontext64, uc_mcontext) = (void *)&frame->mc; #endif sigcontext_t *sc = SIGCXT_FROM_UCXT(uc); From 5b3fcaab312223b30c84254cd93abf1adaa74e9b Mon Sep 17 00:00:00 2001 From: Andrew Haberlandt Date: Fri, 27 Dec 2024 04:16:27 -0500 Subject: [PATCH 6/6] cleanup + comments --- core/unix/signal.c | 3 +++ suite/tests/CMakeLists.txt | 9 +++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/core/unix/signal.c b/core/unix/signal.c index 282e84a7375..2a256aabdf4 100644 --- a/core/unix/signal.c +++ b/core/unix/signal.c @@ -7711,6 +7711,9 @@ os_forge_exception(app_pc target_pc, dr_exception_type_t type) kernel_ucontext_t *uc = get_ucontext_from_rt_frame(frame); #if defined(MACOS) + /* Since SIGCXT_FROM_UCXT just accesses the uc->uc_mcontext ptr field on + * macOS, sc will be NULL below if we do not initialize uc_mcontext first + */ uc->IF_X64_ELSE(uc_mcontext64, uc_mcontext) = (void *)&frame->mc; #endif sigcontext_t *sc = SIGCXT_FROM_UCXT(uc); diff --git a/suite/tests/CMakeLists.txt b/suite/tests/CMakeLists.txt index ff80fba0c91..fd3fde2690b 100644 --- a/suite/tests/CMakeLists.txt +++ b/suite/tests/CMakeLists.txt @@ -1243,6 +1243,9 @@ if (CMAKE_CROSSCOMPILING AND DEFINED CMAKE_FIND_ROOT_PATH) endif () if (APPLE AND AARCH64) + # On macOS + arm64 tests will randomly fail depending on + # whether mmap returns a region satisfying 32-bit reachability constraints. + # Reducing the vm_size appears to eliminate this issue. set(dr_test_ops -vm_size 500M ${dr_test_ops}) endif () @@ -6044,7 +6047,9 @@ if (NOT ARM) # FIXME i#1551: fix bugs on ARM endif () endif (NOT ARM) -if (X86 OR AARCH64 AND NOT (APPLE AND AARCH64)) # FIXME i#1551: port asm to ARM +# FIXME i#1551: port asm to ARM +# FIXME i#xxx: selfmod tests fail to build on macOS + ARM64 +if (X86 OR AARCH64 AND NOT (APPLE AND AARCH64)) tobuild(security-common.selfmod2 security-common/selfmod2.c) tochcon(security-common.selfmod2 textrel_shlib_t) @@ -6063,7 +6068,7 @@ if (X86) # FIXME i#1551, i#1569: port asm to ARM and AArch64 endif () endif (X86) -if (X64 AND NOT AARCH64 AND NOT RISCV64 AND NOT (APPLE AND AARCH64)) # FIXME i#1569: get working on AArch64 +if (X64 AND NOT AARCH64 AND NOT RISCV64) # FIXME i#1569: get working on AArch64 # Reachability tests # Floating DR lib. We'd have to build a 2nd dynamorio.dll on Windows so