summaryrefslogtreecommitdiff
path: root/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc
diff options
context:
space:
mode:
authorKamil Rytarowski <n54@gmx.com>2017-12-14 20:14:29 +0000
committerKamil Rytarowski <n54@gmx.com>2017-12-14 20:14:29 +0000
commit4307093b9d285837b4c89fe3872cf7bd9ac65ca7 (patch)
tree2396c78a3a5845c21a9214d6a8384543855a26de /compiler-rt/lib/sanitizer_common/sanitizer_linux.cc
parenta90a168f0f2b46c3164a0cd6c97ba679ea48ace6 (diff)
[Sanitizers] Basic sanitizer Solaris support (PR 33274)
Summary: This is the first mostly working version of the Sanitizer port to 32-bit Solaris/x86. It is currently based on Solaris 11.4 Beta. This part was initially developed inside libsanitizer in the GCC tree and should apply to both. Subsequent parts will address changes to clang, the compiler-rt build system and testsuite. I'm not yet sure what the right patch granularity is: if it's profitable to split the patch up, I'd like to get guidance on how to do so. Most of the changes are probably straightforward with a few exceptions: * The Solaris syscall interface isn't stable, undocumented and can change within an OS release. The stable interface is the libc interface, which I'm using here, if possible using the internal _-prefixed names. * While the patch primarily target 32-bit x86, I've left a few sparc changes in. They cannot currently be used with clang due to a backend limitation, but have worked fine inside the gcc tree. * Some functions (e.g. largefile versions of functions like open64) only exist in 32-bit Solaris, so I've introduced a separate SANITIZER_SOLARIS32 to check for that. The patch (with the subsequent ones to be submitted shortly) was tested on i386-pc-solaris2.11. Only a few failures remain, some of them analyzed, some still TBD: AddressSanitizer-i386-sunos :: TestCases/Posix/concurrent_overflow.cc AddressSanitizer-i386-sunos :: TestCases/init-order-atexit.cc AddressSanitizer-i386-sunos :: TestCases/log-path_test.cc AddressSanitizer-i386-sunos :: TestCases/malloc-no-intercept.c AddressSanitizer-i386-sunos-dynamic :: TestCases/Posix/concurrent_overflow.cc AddressSanitizer-i386-sunos-dynamic :: TestCases/Posix/start-deactivated.cc AddressSanitizer-i386-sunos-dynamic :: TestCases/default_options.cc AddressSanitizer-i386-sunos-dynamic :: TestCases/init-order-atexit.cc AddressSanitizer-i386-sunos-dynamic :: TestCases/log-path_test.cc AddressSanitizer-i386-sunos-dynamic :: TestCases/malloc-no-intercept.c SanitizerCommon-Unit :: ./Sanitizer-i386-Test/MemoryMappingLayout.DumpListOfModules SanitizerCommon-Unit :: ./Sanitizer-i386-Test/SanitizerCommon.PthreadDestructorIterations Maybe this is good enough the get the ball rolling. Reviewers: kcc, alekseyshl Reviewed By: alekseyshl Subscribers: srhines, jyknight, kubamracek, krytarowski, fedor.sergeev, llvm-commits, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D40898
Diffstat (limited to 'compiler-rt/lib/sanitizer_common/sanitizer_linux.cc')
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_linux.cc81
1 files changed, 72 insertions, 9 deletions
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc
index 89c76422c88..6c83e8db42a 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc
@@ -14,7 +14,8 @@
#include "sanitizer_platform.h"
-#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
+#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
+ SANITIZER_SOLARIS
#include "sanitizer_common.h"
#include "sanitizer_flags.h"
@@ -55,7 +56,9 @@
#include <pthread.h>
#include <sched.h>
#include <sys/mman.h>
+#if !SANITIZER_SOLARIS
#include <sys/ptrace.h>
+#endif
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/syscall.h>
@@ -92,6 +95,14 @@ extern char **environ; // provided by crt1
extern struct ps_strings *__ps_strings;
#endif // SANITIZER_NETBSD
+#if SANITIZER_SOLARIS
+#include <stdlib.h>
+#include <thread.h>
+
+extern char **_environ;
+#define environ _environ
+#endif
+
#if !SANITIZER_ANDROID
#include <sys/signal.h>
#endif
@@ -146,6 +157,7 @@ namespace __sanitizer {
#endif
// --------------- sanitizer_libc.h
+#if !SANITIZER_SOLARIS
#if !SANITIZER_S390
uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
OFF_T offset) {
@@ -424,6 +436,7 @@ uptr internal_execve(const char *filename, char *const argv[],
return internal_syscall_ptr(SYSCALL(execve), (uptr)filename, (uptr)argv,
(uptr)envp);
}
+#endif // !SANITIZER_SOLARIS
// ----------------- sanitizer_common.h
bool FileExists(const char *filename) {
@@ -443,11 +456,14 @@ tid_t GetTid() {
return (uptr)pthread_self();
#elif SANITIZER_NETBSD
return _lwp_self();
+#elif SANITIZER_SOLARIS
+ return (uptr)thr_self();
#else
return internal_syscall(SYSCALL(gettid));
#endif
}
+#if !SANITIZER_SOLARIS
u64 NanoTime() {
#if SANITIZER_FREEBSD || SANITIZER_NETBSD
timeval tv;
@@ -462,12 +478,13 @@ u64 NanoTime() {
uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) {
return internal_syscall_ptr(SYSCALL(clock_gettime), clk_id, tp);
}
+#endif // !SANITIZER_SOLARIS
// Like getenv, but reads env directly from /proc (on Linux) or parses the
-// 'environ' array (on FreeBSD) and does not use libc. This function should be
-// called first inside __asan_init.
+// 'environ' array (on some others) and does not use libc. This function
+// should be called first inside __asan_init.
const char *GetEnv(const char *name) {
-#if SANITIZER_FREEBSD || SANITIZER_NETBSD
+#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_SOLARIS
if (::environ != 0) {
uptr NameLen = internal_strlen(name);
for (char **Env = ::environ; *Env != 0; Env++) {
@@ -590,6 +607,9 @@ void ReExec() {
len = sizeof(path);
if (sysctl(name, ARRAY_SIZE(name), path, &len, NULL, 0) != -1)
pathname = path;
+#elif SANITIZER_SOLARIS
+ pathname = getexecname();
+ CHECK_NE(pathname, NULL);
#endif
GetArgsAndEnv(&argv, &envp);
@@ -600,6 +620,7 @@ void ReExec() {
Die();
}
+#if !SANITIZER_SOLARIS
enum MutexState {
MtxUnlocked = 0,
MtxLocked = 1,
@@ -619,7 +640,7 @@ void BlockingMutex::Lock() {
#if SANITIZER_FREEBSD
_umtx_op(m, UMTX_OP_WAIT_UINT, MtxSleeping, 0, 0);
#elif SANITIZER_NETBSD
- sched_yield(); /* No userspace futex-like synchromization */
+ sched_yield(); /* No userspace futex-like synchronization */
#else
internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAIT, MtxSleeping, 0, 0, 0);
#endif
@@ -634,7 +655,7 @@ void BlockingMutex::Unlock() {
#if SANITIZER_FREEBSD
_umtx_op(m, UMTX_OP_WAKE, 1, 0, 0);
#elif SANITIZER_NETBSD
- /* No userspace futex-like synchromization */
+ /* No userspace futex-like synchronization */
#else
internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAKE, 1, 0, 0, 0);
#endif
@@ -645,6 +666,7 @@ void BlockingMutex::CheckLocked() {
atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed));
}
+#endif // !SANITIZER_SOLARIS
// ----------------- sanitizer_linux.h
// The actual size of this structure is specified by d_reclen.
@@ -677,6 +699,7 @@ struct linux_dirent {
};
#endif
+#if !SANITIZER_SOLARIS
// Syscall wrappers.
uptr internal_ptrace(int request, int pid, void *addr, void *data) {
#if SANITIZER_NETBSD
@@ -854,6 +877,7 @@ bool internal_sigismember(__sanitizer_sigset_t *set, int signum) {
return k_set->sig[idx] & (1 << bit);
}
#endif // SANITIZER_LINUX
+#endif // !SANITIZER_SOLARIS
// ThreadLister implementation.
ThreadLister::ThreadLister(int pid)
@@ -1011,6 +1035,11 @@ uptr GetPageSize() {
}
uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
+#if SANITIZER_SOLARIS
+ const char *default_module_name = getexecname();
+ CHECK_NE(default_module_name, NULL);
+ return internal_snprintf(buf, buf_len, "%s", default_module_name);
+#else
#if SANITIZER_FREEBSD || SANITIZER_NETBSD
#if SANITIZER_FREEBSD
const int Mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
@@ -1028,7 +1057,7 @@ uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
default_module_name, buf, buf_len);
int readlink_error;
bool IsErr = internal_iserror(module_name_len, &readlink_error);
-#endif
+#endif // SANITIZER_SOLARIS
if (IsErr) {
// We can't read binary name for some reason, assume it's unknown.
Report("WARNING: reading executable name failed with errno %d, "
@@ -1038,6 +1067,7 @@ uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
CHECK_LT(module_name_len, buf_len);
}
return module_name_len;
+#endif
}
uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) {
@@ -1662,6 +1692,9 @@ SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
uptr err = ucontext->uc_mcontext.mc_err;
#elif SANITIZER_NETBSD
uptr err = ucontext->uc_mcontext.__gregs[_REG_ERR];
+#elif SANITIZER_SOLARIS && defined(__i386__)
+# define ERR 13
+ uptr err = ucontext->uc_mcontext.gregs[ERR];
#else
uptr err = ucontext->uc_mcontext.gregs[REG_ERR];
#endif
@@ -1675,6 +1708,12 @@ SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
u64 esr;
if (!Aarch64GetESR(ucontext, &esr)) return UNKNOWN;
return esr & ESR_ELx_WNR ? WRITE : READ;
+#elif SANITIZER_SOLARIS && defined(__sparc__)
+ // Decode the instruction to determine the access type.
+ // From OpenSolaris $SRC/uts/sun4/os/trap.c (get_accesstype).
+ uptr pc = ucontext->uc_mcontext.gregs[REG_PC];
+ u32 instr = *(u32 *)pc;
+ return (instr >> 21) & 1 ? WRITE: READ;
#else
(void)ucontext;
return UNKNOWN; // FIXME: Implement.
@@ -1732,6 +1771,19 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
*sp = ucontext->uc_mcontext.__gregs[_REG_ESP];
# else
ucontext_t *ucontext = (ucontext_t*)context;
+# if SANITIZER_SOLARIS
+ /* Use the numeric values: the symbolic ones are undefined by llvm
+ include/llvm/Support/Solaris.h. */
+# ifndef REG_EIP
+# define REG_EIP 14 // REG_PC
+# endif
+# ifndef REG_EBP
+# define REG_EBP 6 // REG_FP
+# endif
+# ifndef REG_ESP
+# define REG_ESP 17 // REG_SP
+# endif
+# endif
*pc = ucontext->uc_mcontext.gregs[REG_EIP];
*bp = ucontext->uc_mcontext.gregs[REG_EBP];
*sp = ucontext->uc_mcontext.gregs[REG_ESP];
@@ -1746,7 +1798,16 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
#elif defined(__sparc__)
ucontext_t *ucontext = (ucontext_t*)context;
uptr *stk_ptr;
-# if defined (__arch64__)
+# if defined (__sparcv9)
+# ifndef MC_PC
+# define MC_PC REG_PC
+# endif
+# ifndef MC_O6
+# define MC_O6 REG_O6
+# endif
+# ifdef SANITIZER_SOLARIS
+# define mc_gregs gregs
+# endif
*pc = ucontext->uc_mcontext.mc_gregs[MC_PC];
*sp = ucontext->uc_mcontext.mc_gregs[MC_O6];
stk_ptr = (uptr *) (*sp + 2047);
@@ -1835,4 +1896,6 @@ bool GetRandom(void *buffer, uptr length, bool blocking) {
} // namespace __sanitizer
-#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||
+ // SANITIZER_SOLARIS
+