[compiler-rt] [tsan] Enable intercept setjmp/longjmp for AArch64

This patch adds assembly routines to enable setjmp/longjmp for aarch64
on linux.  It fixes:

 * test/tsan/longjmp2.cc
 * test/tsan/longjmp3.cc
 * test/tsan/longjmp4.cc
 * test/tsan/signal_longjmp.cc

I also checked with perlbench from specpu2006 (it fails to run
with missing setjmp/longjmp intrumentation).

llvm-svn: 253205
This commit is contained in:
Adhemerval Zanella 2015-11-16 13:55:19 +00:00
parent bdf8751609
commit 2f7f5e3535
9 changed files with 227 additions and 11 deletions

View File

@ -23,8 +23,11 @@
# define CFI_STARTPROC .cfi_startproc # define CFI_STARTPROC .cfi_startproc
# define CFI_ENDPROC .cfi_endproc # define CFI_ENDPROC .cfi_endproc
# define CFI_ADJUST_CFA_OFFSET(n) .cfi_adjust_cfa_offset n # define CFI_ADJUST_CFA_OFFSET(n) .cfi_adjust_cfa_offset n
# define CFI_DEF_CFA_OFFSET(n) .cfi_def_cfa_offset n
# define CFI_REL_OFFSET(reg, n) .cfi_rel_offset reg, n # define CFI_REL_OFFSET(reg, n) .cfi_rel_offset reg, n
# define CFI_OFFSET(reg, n) .cfi_offset reg, n
# define CFI_DEF_CFA_REGISTER(reg) .cfi_def_cfa_register reg # define CFI_DEF_CFA_REGISTER(reg) .cfi_def_cfa_register reg
# define CFI_DEF_CFA(reg, n) .cfi_def_cfa reg, n
# define CFI_RESTORE(reg) .cfi_restore reg # define CFI_RESTORE(reg) .cfi_restore reg
#else // No CFI #else // No CFI
@ -32,8 +35,11 @@
# define CFI_STARTPROC # define CFI_STARTPROC
# define CFI_ENDPROC # define CFI_ENDPROC
# define CFI_ADJUST_CFA_OFFSET(n) # define CFI_ADJUST_CFA_OFFSET(n)
# define CFI_DEF_CFA_OFFSET(n)
# define CFI_REL_OFFSET(reg, n) # define CFI_REL_OFFSET(reg, n)
# define CFI_OFFSET(reg, n)
# define CFI_DEF_CFA_REGISTER(reg) # define CFI_DEF_CFA_REGISTER(reg)
# define CFI_DEF_CFA(reg, n)
# define CFI_RESTORE(reg) # define CFI_RESTORE(reg)
#endif #endif

View File

@ -121,6 +121,11 @@ else()
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/go WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/go
COMMENT "Checking TSan Go runtime..." COMMENT "Checking TSan Go runtime..."
VERBATIM) VERBATIM)
elseif(arch STREQUAL "aarch64")
set(TSAN_ASM_SOURCES rtl/tsan_rtl_aarch64.S)
# Pass ASM file directly to the C++ compiler.
set_source_files_properties(${TSAN_ASM_SOURCES} PROPERTIES
LANGUAGE C)
else() else()
set(TSAN_ASM_SOURCES) set(TSAN_ASM_SOURCES)
endif() endif()

View File

@ -451,8 +451,12 @@ static void SetJmp(ThreadState *thr, uptr sp, uptr mangled_sp) {
static void LongJmp(ThreadState *thr, uptr *env) { static void LongJmp(ThreadState *thr, uptr *env) {
#if SANITIZER_FREEBSD #if SANITIZER_FREEBSD
uptr mangled_sp = env[2]; uptr mangled_sp = env[2];
#else #elif defined(SANITIZER_LINUX)
# ifdef __aarch64__
uptr mangled_sp = env[13];
# else
uptr mangled_sp = env[6]; uptr mangled_sp = env[6];
# endif
#endif // SANITIZER_FREEBSD #endif // SANITIZER_FREEBSD
// Find the saved buf by mangled_sp. // Find the saved buf by mangled_sp.
for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) { for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) {

View File

@ -0,0 +1,206 @@
#include "sanitizer_common/sanitizer_asm.h"
.section .text
.hidden __tsan_setjmp
.comm _ZN14__interception11real_setjmpE,8,8
.type setjmp, @function
setjmp:
CFI_STARTPROC
// save env parameters for function call
stp x29, x30, [sp, -32]!
CFI_DEF_CFA_OFFSET (32)
CFI_OFFSET (29, -32)
CFI_OFFSET (30, -24)
// Adjust the SP for previous frame
add x29, sp, 0
CFI_DEF_CFA_REGISTER (29)
// Save jmp_buf
str x19, [sp, 16]
CFI_OFFSET (19, -16)
mov x19, x0
// SP pointer mangling (see glibc setjmp)
adrp x2, :got:__pointer_chk_guard
ldr x2, [x2, #:got_lo12:__pointer_chk_guard]
add x0, x29, 32
ldr x2, [x2]
eor x1, x2, x0
// call tsan interceptor
bl __tsan_setjmp
// restore env parameter
mov x0, x19
ldr x19, [sp, 16]
ldp x29, x30, [sp], 32
CFI_RESTORE (30)
CFI_RESTORE (19)
CFI_DEF_CFA (31, 0)
// tail jump to libc setjmp
adrp x1, :got:_ZN14__interception11real_setjmpE
ldr x1, [x1, #:got_lo12:_ZN14__interception11real_setjmpE]
ldr x1, [x1]
br x1
CFI_ENDPROC
.size setjmp, .-setjmp
.comm _ZN14__interception12real__setjmpE,8,8
.globl _setjmp
.type _setjmp, @function
_setjmp:
CFI_STARTPROC
// save env parameters for function call
stp x29, x30, [sp, -32]!
CFI_DEF_CFA_OFFSET (32)
CFI_OFFSET (29, -32)
CFI_OFFSET (30, -24)
// Adjust the SP for previous frame
add x29, sp, 0
CFI_DEF_CFA_REGISTER (29)
// Save jmp_buf
str x19, [sp, 16]
CFI_OFFSET (19, -16)
mov x19, x0
// SP pointer mangling (see glibc setjmp)
adrp x2, :got:__pointer_chk_guard
ldr x2, [x2, #:got_lo12:__pointer_chk_guard]
add x0, x29, 32
ldr x2, [x2]
eor x1, x2, x0
// call tsan interceptor
bl __tsan_setjmp
// Restore jmp_buf parameter
mov x0, x19
ldr x19, [sp, 16]
ldp x29, x30, [sp], 32
CFI_RESTORE (30)
CFI_RESTORE (19)
CFI_DEF_CFA (31, 0)
// tail jump to libc setjmp
adrp x1, :got:_ZN14__interception12real__setjmpE
ldr x1, [x1, #:got_lo12:_ZN14__interception12real__setjmpE]
ldr x1, [x1]
br x1
CFI_ENDPROC
.size _setjmp, .-_setjmp
.comm _ZN14__interception14real_sigsetjmpE,8,8
.globl sigsetjmp
.type sigsetjmp, @function
sigsetjmp:
CFI_STARTPROC
// save env parameters for function call
stp x29, x30, [sp, -32]!
CFI_DEF_CFA_OFFSET (32)
CFI_OFFSET (29, -32)
CFI_OFFSET (30, -24)
// Adjust the SP for previous frame
add x29, sp, 0
CFI_DEF_CFA_REGISTER (29)
// Save jmp_buf and savesigs
stp x19, x20, [sp, 16]
CFI_OFFSET (19, -16)
CFI_OFFSET (20, -8)
mov w20, w1
mov x19, x0
// SP pointer mangling (see glibc setjmp)
adrp x2, :got:__pointer_chk_guard
ldr x2, [x2, #:got_lo12:__pointer_chk_guard]
add x0, x29, 32
ldr x2, [x2]
eor x1, x2, x0
// call tsan interceptor
bl __tsan_setjmp
// restore env parameter
mov w1, w20
mov x0, x19
ldp x19, x20, [sp, 16]
ldp x29, x30, [sp], 32
CFI_RESTORE (30)
CFI_RESTORE (29)
CFI_RESTORE (19)
CFI_RESTORE (20)
CFI_DEF_CFA (31, 0)
// tail jump to libc sigsetjmp
adrp x2, :got:_ZN14__interception14real_sigsetjmpE
ldr x2, [x2, #:got_lo12:_ZN14__interception14real_sigsetjmpE]
ldr x2, [x2]
br x2
CFI_ENDPROC
.size sigsetjmp, .-sigsetjmp
.comm _ZN14__interception16real___sigsetjmpE,8,8
.globl __sigsetjmp
.type __sigsetjmp, @function
__sigsetjmp:
CFI_STARTPROC
// save env parameters for function call
stp x29, x30, [sp, -32]!
CFI_DEF_CFA_OFFSET (32)
CFI_OFFSET (29, -32)
CFI_OFFSET (30, -24)
// Adjust the SP for previous frame
add x29, sp, 0
CFI_DEF_CFA_REGISTER (29)
// Save jmp_buf and savesigs
stp x19, x20, [sp, 16]
CFI_OFFSET (19, -16)
CFI_OFFSET (20, -8)
mov w20, w1
mov x19, x0
// SP pointer mangling (see glibc setjmp)
adrp x2, :got:__pointer_chk_guard
ldr x2, [x2, #:got_lo12:__pointer_chk_guard]
add x0, x29, 32
ldr x2, [x2]
eor x1, x2, x0
// call tsan interceptor
bl __tsan_setjmp
mov w1, w20
mov x0, x19
ldp x19, x20, [sp, 16]
ldp x29, x30, [sp], 32
CFI_RESTORE (30)
CFI_RESTORE (29)
CFI_RESTORE (19)
CFI_RESTORE (20)
CFI_DEF_CFA (31, 0)
// tail jump to libc __sigsetjmp
adrp x2, :got:_ZN14__interception16real___sigsetjmpE
ldr x2, [x2, #:got_lo12:_ZN14__interception16real___sigsetjmpE]
ldr x2, [x2]
br x2
CFI_ENDPROC
.size __sigsetjmp, .-__sigsetjmp
#if defined(__linux__)
/* We do not need executable stack. */
.section .note.GNU-stack,"",@progbits
#endif

View File

@ -1,8 +1,7 @@
// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
// Longjmp assembly has not been implemented for mips64 or aarch64 yet // Longjmp assembly has not been implemented for mips64 yet
// XFAIL: mips64 // XFAIL: mips64
// XFAIL: aarch64
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>

View File

@ -1,8 +1,7 @@
// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
// Longjmp assembly has not been implemented for mips64 or aarch64 yet // Longjmp assembly has not been implemented for mips64 yet
// XFAIL: mips64 // XFAIL: mips64
// XFAIL: aarch64
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>

View File

@ -1,8 +1,7 @@
// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s // RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
// Longjmp assembly has not been implemented for mips64 or aarch64 yet // Longjmp assembly has not been implemented for mips64 yet
// XFAIL: mips64 // XFAIL: mips64
// XFAIL: aarch64
#include <pthread.h> #include <pthread.h>
#include <stdio.h> #include <stdio.h>

View File

@ -1,8 +1,7 @@
// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s // RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
// Longjmp assembly has not been implemented for mips64 or aarch64 yet // Longjmp assembly has not been implemented for mips64 yet
// XFAIL: mips64 // XFAIL: mips64
// XFAIL: aarch64
#include <pthread.h> #include <pthread.h>
#include <stdio.h> #include <stdio.h>

View File

@ -3,9 +3,8 @@
// Test case for longjumping out of signal handler: // Test case for longjumping out of signal handler:
// https://code.google.com/p/thread-sanitizer/issues/detail?id=75 // https://code.google.com/p/thread-sanitizer/issues/detail?id=75
// Longjmp assembly has not been implemented for mips64 or aarch64 yet // Longjmp assembly has not been implemented for mips64 yet
// XFAIL: mips64 // XFAIL: mips64
// XFAIL: aarch64
#include <setjmp.h> #include <setjmp.h>
#include <signal.h> #include <signal.h>