Skip to content

Commit

Permalink
i#5383 mac a64, part 6: Get OSX-labeled tests to succeed
Browse files Browse the repository at this point in the history
8 of the 13 tests on Mac AArch64 labeled "OSX" fail prior to this PR.
Here we fix the following:

+ Syscall success is indicated by the carry flag just like x86 Mac
+ Handle sigreturn with its extra parameters just like x86 Mac
+ Fix signal handler parameters
+ Fix stolen register support in signal contexts
+ Use MAP_JIT and pthread_jit_write_protect_np for +rwx gencode in tests
+ Use DYLD_LIBRARY_PATH on Mac in tests

Now all 13 tests pass:
---------------------------------------------------------------------------------------
ctest -j 5 -L OSX
 1/13 Test  #13: code_api|common.fib ................................  Passed  0.59 sec
 2/13 Test #243: code_api|libutil.frontend_test .....................  Passed  0.63 sec
 3/13 Test #231: code_api|api.ir ....................................  Passed  0.67 sec
 4/13 Test   #9: code_api|linux.sigaction.native ....................  Passed  0.25 sec
 5/13 Test  #31: code_api|linux.signal0000 ..........................  Passed  0.10 sec
 6/13 Test #240: code_api|api.ir-static .............................  Passed  0.34 sec
 7/13 Test #241: code_api|api.drdecode ..............................  Passed  0.38 sec
 8/13 Test #245: code_api|api.dis-a64 ...............................  Passed  1.15 sec
 9/13 Test #264: no_code_api,no_intercept_all_signals|linux.sigaction  Passed  0.08 sec
10/13 Test  #33: code_api|linux.signal0010 ..........................  Passed  0.34 sec
11/13 Test  #35: code_api|linux.signal0100 ..........................  Passed  0.42 sec
12/13 Test  #37: code_api|linux.signal0110 ..........................  Passed  0.45 sec
13/13 Test   #7: samples_proj .......................................  Passed  1.89 sec
100% tests passed, 0 tests failed out of 13
---------------------------------------------------------------------------------------

Issue: #5383
  • Loading branch information
derekbruening committed Jul 5, 2023
1 parent f3f909b commit 5537d2c
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 44 deletions.
22 changes: 15 additions & 7 deletions core/arch/aarch64/aarch64.asm
Expand Up @@ -587,14 +587,14 @@ GLOBAL_LABEL(main_signal_handler:)
#if defined(MACOS) && defined(AARCH64)
DECLARE_FUNC(dynamorio_sigreturn)
GLOBAL_LABEL(dynamorio_sigreturn:)
/* TODO i#5383: Get correct syscall number for svc. */
brk 0xb001 /* For now we break with a unique code. */
mov w16, #184 /* SYS_sigreturn. */
svc #0x80
END_FUNC(dynamorio_sigreturn)

DECLARE_FUNC(dynamorio_sys_exit)
GLOBAL_LABEL(dynamorio_sys_exit:)
/* TODO i#5383: Get correct syscall number for svc. */
brk 0xb002 /* For now we break with a unique code. */
mov w16, #1 /* SYS_exit. */
svc #0x80
END_FUNC(dynamorio_sys_exit)

DECLARE_FUNC(new_bsdthread_intercept)
Expand All @@ -607,9 +607,17 @@ GLOBAL_LABEL(new_bsdthread_intercept:)
#ifdef MACOS
DECLARE_FUNC(main_signal_handler)
GLOBAL_LABEL(main_signal_handler:)
/* see sendsig_set_thread_state64 in unix_signal.c */
mov ARG6, sp
b GLOBAL_REF(main_signal_handler_C) /* chain call */
/* See sendsig_set_thread_state64 in unix_signal.c */
mov ARG7, sp
/* Save 3 args (ucxt=5th, style=2nd, token=6th) for sigreturn. */
stp ARG5, ARG6, [sp, #-32]!
str ARG2, [sp, #16]
mov ARG6, ARG7
bl GLOBAL_REF(main_signal_handler_C)
ldr ARG2, [sp, #16]
ldp ARG1, ARG3, [sp], #32
CALLC0(GLOBAL_REF(dynamorio_sigreturn))
bl GLOBAL_REF(unexpected_return)
END_FUNC(main_signal_handler)
#endif

Expand Down
24 changes: 19 additions & 5 deletions core/unix/os.c
Expand Up @@ -5422,13 +5422,15 @@ syscall_successful(priv_mcontext_t *mc, int normalized_sysnum)
* We defer to drsyscall.
*/
return ((ptr_int_t)MCXT_SYSCALL_RES(mc) >= 0);
} else
} else {
# ifdef X86
return !TEST(EFLAGS_CF, mc->xflags);
# elif defined(AARCH64)
return !TEST(EFLAGS_C, mc->xflags);
# else
return -1;
# error NYI
# endif

}
#else
if (normalized_sysnum == IF_X64_ELSE(SYS_mmap, SYS_mmap2) ||
# if !defined(ARM) && !defined(X64)
Expand All @@ -5450,11 +5452,17 @@ set_success_return_val(dcontext_t *dcontext, reg_t val)
{
/* since always coming from d_r_dispatch now, only need to set mcontext */
priv_mcontext_t *mc = get_mcontext(dcontext);
#if defined(MACOS) && defined(X86)
#ifdef MACOS
/* On MacOS, success is determined by CF, except for Mach syscalls, but
* there it doesn't hurt to set CF.
*/
# ifdef X86
mc->xflags &= ~(EFLAGS_CF);
# elif defined(AARCH64)
mc->xflags &= ~(EFLAGS_C);
# else
# error NYI
# endif
#endif
MCXT_SYSCALL_RES(mc) = val;
}
Expand All @@ -5464,9 +5472,15 @@ static inline void
set_failure_return_val(dcontext_t *dcontext, uint errno_val)
{
priv_mcontext_t *mc = get_mcontext(dcontext);
#if defined(MACOS) && defined(X86)
#ifdef MACOS
/* On MacOS, success is determined by CF, and errno is positive */
# ifdef X86
mc->xflags |= EFLAGS_CF;
# elif defined(AARCH64)
mc->xflags |= EFLAGS_C;
# else
# error NYI
# endif
MCXT_SYSCALL_RES(mc) = errno_val;
#else
MCXT_SYSCALL_RES(mc) = -(int)errno_val;
Expand Down
23 changes: 14 additions & 9 deletions core/unix/signal.c
Expand Up @@ -340,7 +340,7 @@ dump_unmasked(dcontext_t *dcontext, const char *where)
LOG(THREAD, LOG_ASYNCH, 3, "%s: threads_unmasked: ", where);
for (int i = 1; i <= MAX_SIGNUM; i++) {
LOG(THREAD, LOG_ASYNCH, 3, "[%d]=%d ", i, info->sighand->threads_unmasked[i]);
if (i % 16 == 0)
if (i % 16 == 0 || i == MAX_SIGNUM)
LOG(THREAD, LOG_ASYNCH, 3, "\n");
}
}
Expand Down Expand Up @@ -3050,13 +3050,11 @@ set_sigcxt_stolen_reg(sigcontext_t *sc, reg_t val)
*(&sc->SC_R0 + (dr_reg_stolen - DR_REG_R0)) = val;
}

# ifndef MACOS /* TODO i#5383: Add full signal support. */
static reg_t
get_sigcxt_stolen_reg(sigcontext_t *sc)
{
return *(&sc->SC_R0 + (dr_reg_stolen - DR_REG_R0));
}
# endif

# ifndef AARCH64
static dr_isa_mode_t
Expand Down Expand Up @@ -4043,7 +4041,7 @@ transfer_from_sig_handler_to_fcache_return(dcontext_t *dcontext, kernel_ucontext
* still go to the private fcache_return for simplicity.
*/
sc->SC_XIP = (ptr_uint_t)fcache_return_routine(dcontext);
#if defined(AARCHXX) && !defined(MACOS)
#if defined(AARCHXX)
/* We do not have to set dr_reg_stolen in dcontext's mcontext here
* because dcontext's mcontext is stale and we used the mcontext
* created from recreate_app_state_internal with the original sigcontext.
Expand Down Expand Up @@ -6276,10 +6274,7 @@ execute_handler_from_dispatch(dcontext_t *dcontext, int sig)
dump_sigcontext(dcontext, sc);
LOG(THREAD, LOG_ASYNCH, 3, "\n");
}
# ifndef MACOS
IF_AARCHXX(ASSERT(get_sigcxt_stolen_reg(sc) != (reg_t)*get_dr_tls_base_addr()));
# endif

#endif
/* FIXME: other state? debug regs?
* if no syscall allowed between main_ (when frame created) and
Expand Down Expand Up @@ -6384,7 +6379,17 @@ execute_handler_from_dispatch(dcontext_t *dcontext, int sig)
/* Set up args to handler: int sig, kernel_siginfo_t *siginfo,
* kernel_ucontext_t *ucxt.
*/
#if defined(MACOS64) && defined(X86)
#if defined(MACOS64) && defined(AARCH64)
mcontext->r0 = (reg_t)info->sighand->action[sig]->handler;
int infostyle = TEST(SA_SIGINFO, info->sighand->action[sig]->flags)
? SIGHAND_STYLE_UC_FLAVOR
: SIGHAND_STYLE_UC_TRAD;
mcontext->r1 = infostyle;
mcontext->r2 = sig;
mcontext->r3 = (reg_t) & ((sigframe_rt_t *)xsp)->info;
mcontext->r4 = (reg_t) & ((sigframe_rt_t *)xsp)->uc;
mcontext->lr = (reg_t)dynamorio_sigreturn;
#elif defined(MACOS64) && defined(X86)
mcontext->xdi = (reg_t)info->sighand->action[sig]->handler;
int infostyle = TEST(SA_SIGINFO, info->sighand->action[sig]->flags)
? SIGHAND_STYLE_UC_FLAVOR
Expand Down Expand Up @@ -7347,7 +7352,7 @@ handle_sigreturn(dcontext_t *dcontext, void *ucxt_param, int style)
* look like whatever would happen to the app...
*/
ASSERT((app_pc)sc->SC_XIP != next_pc);
# if defined(AARCHXX) && !defined(MACOS)
# if defined(AARCHXX)
ASSERT(get_sigcxt_stolen_reg(sc) != (reg_t)*get_dr_tls_base_addr());
/* We're called from DR and are not yet in the cache, so we want to set the
* mcontext slot, not the TLS slot, to set the stolen reg value.
Expand Down
53 changes: 42 additions & 11 deletions core/unix/signal_macos.c
@@ -1,5 +1,5 @@
/* *******************************************************************************
* Copyright (c) 2013-2022 Google, Inc. All rights reserved.
* Copyright (c) 2013-2023 Google, Inc. All rights reserved.
* *******************************************************************************/

/*
Expand Down Expand Up @@ -152,10 +152,14 @@ void
sigcontext_to_mcontext_simd(priv_mcontext_t *mc, sig_full_cxt_t *sc_full)
{
#ifdef AARCH64
ASSERT_NOT_IMPLEMENTED(false);
#endif

#ifdef X86
_STRUCT_ARM_NEON_STATE64 *fpc = (_STRUCT_ARM_NEON_STATE64 *)sc_full->fp_simd_state;
if (fpc == NULL)
return;
mc->fpsr = fpc->__fpsr;
mc->fpcr = fpc->__fpcr;
ASSERT(sizeof(mc->simd) == sizeof(fpc->__v));
memcpy(&mc->simd, &fpc->__v, sizeof(mc->simd));
#elif defined(X86)
/* We assume that _STRUCT_X86_FLOAT_STATE* matches exactly the first
* half of _STRUCT_X86_AVX_STATE*, and similarly for AVX and AVX512.
*/
Expand Down Expand Up @@ -190,8 +194,15 @@ sigcontext_to_mcontext_simd(priv_mcontext_t *mc, sig_full_cxt_t *sc_full)
void
mcontext_to_sigcontext_simd(sig_full_cxt_t *sc_full, priv_mcontext_t *mc)
{
IF_AARCHXX(ASSERT_NOT_REACHED());
#ifdef X86
#ifdef AARCH64
_STRUCT_ARM_NEON_STATE64 *fpc = (_STRUCT_ARM_NEON_STATE64 *)sc_full->fp_simd_state;
if (fpc == NULL)
return;
fpc->__fpsr = mc->fpsr;
fpc->__fpcr = mc->fpcr;
ASSERT(sizeof(mc->simd) == sizeof(fpc->__v));
memcpy(&fpc->__v, &mc->simd, sizeof(mc->simd));
#elif defined(X86)
sigcontext_t *sc = sc_full->sc;
int i;
for (i = 0; i < proc_num_simd_registers(); i++) {
Expand Down Expand Up @@ -223,8 +234,19 @@ mcontext_to_sigcontext_simd(sig_full_cxt_t *sc_full, priv_mcontext_t *mc)
static void
dump_fpstate(dcontext_t *dcontext, sigcontext_t *sc)
{
IF_AARCHXX(ASSERT_NOT_REACHED());
#ifdef X86
#ifdef AARCH64
_STRUCT_ARM_NEON_STATE64 *fpc = &sc->__ns;
LOG(THREAD, LOG_ASYNCH, 1, "\tfpsr=0x%08x\n", fpc->__fpsr);
LOG(THREAD, LOG_ASYNCH, 1, "\tfpcr=0x%08x\n", fpc->__fpcr);
int i, j;
for (i = 0; i < sizeof(fpc->__v) / sizeof(fpc->__v[0]); i++) {
LOG(THREAD, LOG_ASYNCH, 1, "\tv[%d] = 0x", i);
for (j = 0; j < 4; j++) {
LOG(THREAD, LOG_ASYNCH, 1, "%08x", *(((uint *)&fpc->__v[i]) + j));
}
LOG(THREAD, LOG_ASYNCH, 1, "\n");
}
#elif defined(X86)
int i, j;
LOG(THREAD, LOG_ASYNCH, 1, "\tfcw=0x%04x\n", *(ushort *)&sc->__fs.__fpu_fcw);
LOG(THREAD, LOG_ASYNCH, 1, "\tfsw=0x%04x\n", *(ushort *)&sc->__fs.__fpu_fsw);
Expand Down Expand Up @@ -306,8 +328,17 @@ dump_sigcontext(dcontext_t *dcontext, sigcontext_t *sc)
LOG(THREAD, LOG_ASYNCH, 1, "\terr=0x%08x\n", sc->__es.__err);
LOG(THREAD, LOG_ASYNCH, 1, "\tfaultvaddr=" PFX "\n", sc->__es.__faultvaddr);
#else
/* TODO i#5383: NYI. */
LOG(THREAD, LOG_ASYNCH, 1, "\tTODO: AARCH64 DUMP\n");
LOG(THREAD, LOG_ASYNCH, 1, "\tfault=" PFX "\n", sc->__es.__far);
LOG(THREAD, LOG_ASYNCH, 1, "\tesr=0x08x\n", sc->__es.__esr);
LOG(THREAD, LOG_ASYNCH, 1, "\tcount=0x%08x\n", sc->__es.__exception);
int i;
for (i = 0; i < 29; i++)
LOG(THREAD, LOG_ASYNCH, 1, "\tr%d=" PFX "\n", i, sc->__ss.__x[i]);
LOG(THREAD, LOG_ASYNCH, 1, "\tfp=" PFX "\n", sc->__ss.__fp);
LOG(THREAD, LOG_ASYNCH, 1, "\tlr=" PFX "\n", sc->__ss.__lr);
LOG(THREAD, LOG_ASYNCH, 1, "\tsp=" PFX "\n", sc->__ss.__sp);
LOG(THREAD, LOG_ASYNCH, 1, "\tpc=" PFX "\n", sc->__ss.__pc);
LOG(THREAD, LOG_ASYNCH, 1, "\tcpsr=0x%08x\n", sc->__ss.__cpsr);
#endif

dump_fpstate(dcontext, sc);
Expand Down
16 changes: 8 additions & 8 deletions core/unix/signal_private.h
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2011-2022 Google, Inc. All rights reserved.
* Copyright (c) 2011-2023 Google, Inc. All rights reserved.
* Copyright (c) 2008-2010 VMware, Inc. All rights reserved.
* **********************************************************/

Expand Down Expand Up @@ -288,7 +288,11 @@ typedef struct rt_sigframe {
# endif

#elif defined(MACOS)
# ifdef X64
# ifdef AARCH64
kernel_siginfo_t info;
struct __darwin_ucontext64 uc;
struct __darwin_mcontext64 mc;
# elif defined(X64)
/* Kernel places padding to align to 16 (via an inefficient alignment macro!),
* and then skips the retaddr slot to align to 8.
*/
Expand All @@ -299,13 +303,9 @@ typedef struct rt_sigframe {
* like on Linux? We would get the size by counting from "info".
* Also, should we change this to sigcontext_t.
*/
# if defined(AARCH64)
struct __darwin_mcontext64 mc;
# else
struct __darwin_mcontext_avx64 mc; /* sigcontext, "struct mcontext_avx64" to kernel */
# endif
kernel_siginfo_t info; /* matches user-mode sys/signal.h struct */
struct __darwin_ucontext64 uc; /* "struct user_ucontext64" to kernel */
kernel_siginfo_t info; /* matches user-mode sys/signal.h struct */
struct __darwin_ucontext64 uc; /* "struct user_ucontext64" to kernel */
# else
app_pc retaddr;
app_pc handler;
Expand Down
9 changes: 9 additions & 0 deletions core/unix/tls_macos.c
Expand Up @@ -193,6 +193,15 @@ get_app_tls_swap_slot_addr(void)
}
#endif

#ifdef AARCH64
/* Shared with Linux AArch64 code. */
byte **
get_dr_tls_base_addr(void)
{
return get_app_tls_swap_slot_addr();
}
#endif

void
tls_thread_init(os_local_state_t *os_tls, byte *segment)
{
Expand Down
9 changes: 7 additions & 2 deletions suite/tests/CMakeLists.txt
Expand Up @@ -1221,8 +1221,13 @@ function(runtest_cmd outcmd outops key native standalone_dr dr_ops_aux separate_
prefix_cmd_if_necessary(cmd OFF ${cmd})
# We set LD_LIBRARY_PATH for native api/ apps since we're not setting
# rpath (to make it easier to try different trees)
set(cmd ${cmd} -env LD_LIBRARY_PATH
"${MAIN_LIBRARY_OUTPUT_DIRECTORY}:${EXT_LIBRARY_OUTPUT_DIRECTORY}:$ENV{LD_LIBRARY_PATH}")
if (APPLE)
set(libvar "DYLD_LIBRARY_PATH")
else ()
set(libvar "LD_LIBRARY_PATH")
endif ()
set(cmd ${cmd} -env ${libvar}
"${MAIN_LIBRARY_OUTPUT_DIRECTORY}:${EXT_LIBRARY_OUTPUT_DIRECTORY}:$ENV{${libvar}}")
# add dr_ops last to avoid needing extra \ on ;
string(REPLACE ";" " " dr_ops_string "${dr_ops}")
set(${outcmd} ${cmd} -env DYNAMORIO_OPTIONS "${dr_ops_string}" PARENT_SCOPE)
Expand Down
22 changes: 20 additions & 2 deletions suite/tests/tools.c
Expand Up @@ -41,6 +41,10 @@
# ifdef MACOS
# include <mach/mach.h>
# include <mach/semaphore.h>
# ifdef AARCH64
void
pthread_jit_write_protect_np(int enabled);
# endif
# endif

# define ASSERT_NOT_IMPLEMENTED() \
Expand Down Expand Up @@ -170,8 +174,16 @@ char *
allocate_mem(size_t size, int prot)
{
# ifdef UNIX
char *res = (char *)mmap((void *)0, size, get_os_prot_word(prot),
MAP_PRIVATE | MAP_ANON, -1, 0);
int flags = MAP_PRIVATE | MAP_ANON;
# if defined(MACOS) && defined(AARCH64)
# ifdef MACOS
if (TEST(ALLOW_EXEC, prot)) {
flags |= MAP_JIT;
pthread_jit_write_protect_np(0);
}
# endif
# endif
char *res = (char *)mmap((void *)0, size, get_os_prot_word(prot), flags, -1, 0);
if (res == MAP_FAILED)
return NULL;
return res;
Expand Down Expand Up @@ -201,6 +213,12 @@ protect_mem(void *start, size_t len, int prot)
void *page_start = (void *)(((ptr_int_t)start) & ~(PAGE_SIZE - 1));
int page_len = (len + ((ptr_int_t)start - (ptr_int_t)page_start) + PAGE_SIZE - 1) &
~(PAGE_SIZE - 1);
# ifdef MACOS
if (TEST(ALLOW_EXEC, prot) && !TEST(ALLOW_WRITE, prot)) {
pthread_jit_write_protect_np(1);
return;
}
# endif
if (mprotect(page_start, page_len, get_os_prot_word(prot)) != 0) {
print("Error on mprotect: %d\n", errno);
}
Expand Down

0 comments on commit 5537d2c

Please sign in to comment.