diff options
Diffstat (limited to 'lib/asan/asan_linux.cc')
-rw-r--r-- | lib/asan/asan_linux.cc | 144 |
1 files changed, 94 insertions, 50 deletions
diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc index 26a08ae..9a3d6bd 100644 --- a/lib/asan/asan_linux.cc +++ b/lib/asan/asan_linux.cc @@ -13,87 +13,131 @@ //===----------------------------------------------------------------------===// #ifdef __linux__ +#include "asan_interceptors.h" #include "asan_internal.h" +#include "asan_lock.h" +#include "asan_thread.h" +#include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_procmaps.h" +#include <sys/time.h> +#include <sys/resource.h> #include <sys/mman.h> #include <sys/syscall.h> #include <sys/types.h> #include <fcntl.h> +#include <pthread.h> +#include <stdio.h> #include <unistd.h> +#include <unwind.h> -extern char _DYNAMIC[]; +#ifndef ANDROID +// FIXME: where to get ucontext on Android? +#include <sys/ucontext.h> +#endif + +extern "C" void* _DYNAMIC; namespace __asan { void *AsanDoesNotSupportStaticLinkage() { // This will fail to link with -static. - return &_DYNAMIC; -} - -static void *asan_mmap(void *addr, size_t length, int prot, int flags, - int fd, uint64_t offset) { -# if __WORDSIZE == 64 - return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset); -# else - return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset); -# endif + return &_DYNAMIC; // defined in link.h } -void *AsanMmapSomewhereOrDie(size_t size, const char *mem_type) { - size = RoundUpTo(size, kPageSize); - void *res = asan_mmap(0, size, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, -1, 0); - if (res == (void*)-1) { - OutOfMemoryMessageAndDie(mem_type, size); - } - return res; +void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { +#ifdef ANDROID + *pc = *sp = *bp = 0; +#elif defined(__arm__) + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.arm_pc; + *bp = ucontext->uc_mcontext.arm_fp; + *sp = ucontext->uc_mcontext.arm_sp; +# elif defined(__x86_64__) + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.gregs[REG_RIP]; + *bp = ucontext->uc_mcontext.gregs[REG_RBP]; + *sp = ucontext->uc_mcontext.gregs[REG_RSP]; +# elif defined(__i386__) + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.gregs[REG_EIP]; + *bp = ucontext->uc_mcontext.gregs[REG_EBP]; + *sp = ucontext->uc_mcontext.gregs[REG_ESP]; +#else +# error "Unsupported arch" +#endif } -void *AsanMmapFixedNoReserve(uintptr_t fixed_addr, size_t size) { - return asan_mmap((void*)fixed_addr, size, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, - 0, 0); +bool AsanInterceptsSignal(int signum) { + return signum == SIGSEGV && flags()->handle_segv; } -void *AsanMmapFixedReserve(uintptr_t fixed_addr, size_t size) { - return asan_mmap((void*)fixed_addr, size, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON | MAP_FIXED, - 0, 0); +void AsanPlatformThreadInit() { + // Nothing here for now. } -void *AsanMprotect(uintptr_t fixed_addr, size_t size) { - return asan_mmap((void*)fixed_addr, size, - PROT_NONE, - MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, - 0, 0); +AsanLock::AsanLock(LinkerInitialized) { + // We assume that pthread_mutex_t initialized to all zeroes is a valid + // unlocked mutex. We can not use PTHREAD_MUTEX_INITIALIZER as it triggers + // a gcc warning: + // extended initializer lists only available with -std=c++0x or -std=gnu++0x } -void AsanUnmapOrDie(void *addr, size_t size) { - if (!addr || !size) return; - int res = syscall(__NR_munmap, addr, size); - if (res != 0) { - Report("Failed to unmap\n"); - ASAN_DIE; - } +void AsanLock::Lock() { + CHECK(sizeof(pthread_mutex_t) <= sizeof(opaque_storage_)); + pthread_mutex_lock((pthread_mutex_t*)&opaque_storage_); + CHECK(!owner_); + owner_ = (uptr)pthread_self(); } -ssize_t AsanWrite(int fd, const void *buf, size_t count) { - return (ssize_t)syscall(__NR_write, fd, buf, count); +void AsanLock::Unlock() { + CHECK(owner_ == (uptr)pthread_self()); + owner_ = 0; + pthread_mutex_unlock((pthread_mutex_t*)&opaque_storage_); } -int AsanOpenReadonly(const char* filename) { - return open(filename, O_RDONLY); +#ifdef __arm__ +#define UNWIND_STOP _URC_END_OF_STACK +#define UNWIND_CONTINUE _URC_NO_REASON +#else +#define UNWIND_STOP _URC_NORMAL_STOP +#define UNWIND_CONTINUE _URC_NO_REASON +#endif + +uptr Unwind_GetIP(struct _Unwind_Context *ctx) { +#ifdef __arm__ + uptr val; + _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE, + 15 /* r15 = PC */, _UVRSD_UINT32, &val); + CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed"); + // Clear the Thumb bit. + return val & ~(uptr)1; +#else + return _Unwind_GetIP(ctx); +#endif } -ssize_t AsanRead(int fd, void *buf, size_t count) { - return (ssize_t)syscall(__NR_read, fd, buf, count); +_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, + void *param) { + AsanStackTrace *b = (AsanStackTrace*)param; + CHECK(b->size < b->max_size); + uptr pc = Unwind_GetIP(ctx); + b->trace[b->size++] = pc; + if (b->size == b->max_size) return UNWIND_STOP; + return UNWIND_CONTINUE; } -int AsanClose(int fd) { - return close(fd); +void AsanStackTrace::GetStackTrace(uptr max_s, uptr pc, uptr bp) { + size = 0; + trace[0] = pc; + if ((max_s) > 1) { + max_size = max_s; +#ifdef __arm__ + _Unwind_Backtrace(Unwind_Trace, this); +#else + FastUnwindStack(pc, bp); +#endif + } } } // namespace __asan |