[asan] Add target-specific files for Myriad RTEMS port

Differential Revision: https://reviews.llvm.org/D46468

llvm-svn: 332691
This commit is contained in:
Walter Lee 2018-05-18 04:10:12 +00:00
parent ce26498e3f
commit e35f57f023
5 changed files with 582 additions and 0 deletions

View File

@ -23,6 +23,7 @@ set(ASAN_SOURCES
asan_posix.cc
asan_premap_shadow.cc
asan_report.cc
asan_rtems.cc
asan_rtl.cc
asan_shadow_setup.cc
asan_stack.cc

View File

@ -0,0 +1,263 @@
//===-- asan_rtems.cc -----------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// RTEMS-specific details.
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_rtems.h"
#if SANITIZER_RTEMS
#include "asan_internal.h"
#include "asan_interceptors.h"
#include "asan_mapping.h"
#include "asan_poisoning.h"
#include "asan_report.h"
#include "asan_stack.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"
#include <pthread.h>
#include <stdlib.h>
namespace __asan {
void InitializeShadowMemory() {
kHighMemEnd = 0;
kMidMemBeg = 0;
kMidMemEnd = 0;
uptr shadow_start = SHADOW_OFFSET;
uptr shadow_end = MEM_TO_SHADOW(kMyriadMemoryEnd32);
uptr shadow_size = shadow_end - shadow_start;
uptr gap_start = MEM_TO_SHADOW(shadow_start);
uptr gap_end = MEM_TO_SHADOW(shadow_end);
REAL(memset)((void *)shadow_start, 0, shadow_size);
REAL(memset)((void *)gap_start, kAsanShadowGap, gap_end - gap_start);
}
void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
UNIMPLEMENTED();
}
void AsanCheckDynamicRTPrereqs() {}
void AsanCheckIncompatibleRT() {}
void InitializeAsanInterceptors() {}
void InitializePlatformInterceptors() {}
void InitializePlatformExceptionHandlers() {}
// RTEMS only support static linking; it sufficies to return with no
// error.
void *AsanDoesNotSupportStaticLinkage() { return nullptr; }
void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
UNIMPLEMENTED();
}
void EarlyInit() {
// Provide early initialization of shadow memory so that
// instrumented code running before full initialzation will not
// report spurious errors.
InitializeShadowMemory();
}
// Main thread information. Initialized in CreateMainThread() and
// used by ThreadStartHook().
static uptr MainThreadSelf;
static AsanThread *MainThread;
// We can use a plain thread_local variable for TSD.
static thread_local void *per_thread;
void *AsanTSDGet() { return per_thread; }
void AsanTSDSet(void *tsd) { per_thread = tsd; }
// There's no initialization needed, and the passed-in destructor
// will never be called. Instead, our own thread destruction hook
// (below) will call AsanThread::TSDDtor directly.
void AsanTSDInit(void (*destructor)(void *tsd)) {
DCHECK(destructor == &PlatformTSDDtor);
}
void PlatformTSDDtor(void *tsd) { UNREACHABLE(__func__); }
//
// Thread registration. We provide an API similar to the Fushia port.
//
struct AsanThread::InitOptions {
uptr stack_bottom, stack_size, tls_bottom, tls_size;
};
// Shared setup between thread creation and startup for the initial thread.
static AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid,
uptr user_id, bool detached,
uptr stack_bottom, uptr stack_size,
uptr tls_bottom, uptr tls_size) {
// In lieu of AsanThread::Create.
AsanThread *thread = (AsanThread *)MmapOrDie(sizeof(AsanThread), __func__);
AsanThreadContext::CreateThreadContextArgs args = {thread, stack};
asanThreadRegistry().CreateThread(user_id, detached, parent_tid, &args);
// On other systems, AsanThread::Init() is called from the new
// thread itself. But on RTEMS we already know the stack address
// range beforehand, so we can do most of the setup right now.
const AsanThread::InitOptions options = {stack_bottom, stack_size,
tls_bottom, tls_size};
thread->Init(&options);
return thread;
}
// This gets the same arguments passed to Init by CreateAsanThread, above.
// We're in the creator thread before the new thread is actually started,
// but its stack address range is already known. We don't bother tracking
// the static TLS address range because the system itself already uses an
// ASan-aware allocator for that.
void AsanThread::SetThreadStackAndTls(const AsanThread::InitOptions *options) {
DCHECK_NE(GetCurrentThread(), this);
DCHECK_NE(GetCurrentThread(), nullptr);
CHECK_NE(options->stack_bottom, 0);
CHECK_NE(options->stack_size, 0);
stack_bottom_ = options->stack_bottom;
stack_top_ = options->stack_bottom + options->stack_size;
tls_begin_ = options->tls_bottom;
tls_end_ = options->tls_bottom + options->tls_size;
}
// Called by __asan::AsanInitInternal (asan_rtl.c).
AsanThread *CreateMainThread() {
CHECK_NE(__sanitizer::MainThreadStackBase, 0);
CHECK_GT(__sanitizer::MainThreadStackSize, 0);
AsanThread *t = CreateAsanThread(
nullptr, 0, GetThreadSelf(), true,
__sanitizer::MainThreadStackBase, __sanitizer::MainThreadStackSize,
__sanitizer::MainThreadTlsBase, __sanitizer::MainThreadTlsSize);
SetCurrentThread(t);
MainThreadSelf = pthread_self();
MainThread = t;
return t;
}
// This is called before each thread creation is attempted. So, in
// its first call, the calling thread is the initial and sole thread.
static void *BeforeThreadCreateHook(uptr user_id, bool detached,
uptr stack_bottom, uptr stack_size,
uptr tls_bottom, uptr tls_size) {
EnsureMainThreadIDIsCorrect();
// Strict init-order checking is thread-hostile.
if (flags()->strict_init_order) StopInitOrderChecking();
GET_STACK_TRACE_THREAD;
u32 parent_tid = GetCurrentTidOrInvalid();
return CreateAsanThread(&stack, parent_tid, user_id, detached,
stack_bottom, stack_size, tls_bottom, tls_size);
}
// This is called after creating a new thread (in the creating thread),
// with the pointer returned by BeforeThreadCreateHook (above).
static void ThreadCreateHook(void *hook, bool aborted) {
AsanThread *thread = static_cast<AsanThread *>(hook);
if (!aborted) {
// The thread was created successfully.
// ThreadStartHook is already running in the new thread.
} else {
// The thread wasn't created after all.
// Clean up everything we set up in BeforeThreadCreateHook.
asanThreadRegistry().FinishThread(thread->tid());
UnmapOrDie(thread, sizeof(AsanThread));
}
}
// This is called (1) in the newly-created thread before it runs
// anything else, with the pointer returned by BeforeThreadCreateHook
// (above). cf. asan_interceptors.cc:asan_thread_start. (2) before
// a thread restart.
static void ThreadStartHook(void *hook, uptr os_id) {
if (!hook && !MainThreadSelf)
return;
DCHECK(hook || os_id == MainThreadSelf);
AsanThread *thread = hook ? static_cast<AsanThread *>(hook) : MainThread;
SetCurrentThread(thread);
ThreadStatus status =
asanThreadRegistry().GetThreadLocked(thread->tid())->status;
DCHECK(status == ThreadStatusCreated || status == ThreadStatusRunning);
// Determine whether we are starting or restarting the thread.
if (status == ThreadStatusCreated)
// In lieu of AsanThread::ThreadStart.
asanThreadRegistry().StartThread(thread->tid(), os_id,
/*workerthread*/ false, nullptr);
else {
// In a thread restart, a thread may resume execution at an
// arbitrary function entry point, with its stack and TLS state
// reset. We unpoison the stack in that case.
PoisonShadow(thread->stack_bottom(), thread->stack_size(), 0);
}
}
// Each thread runs this just before it exits,
// with the pointer returned by BeforeThreadCreateHook (above).
// All per-thread destructors have already been called.
static void ThreadExitHook(void *hook, uptr os_id) {
AsanThread *thread = static_cast<AsanThread *>(hook);
if (thread)
AsanThread::TSDDtor(thread->context());
}
static void HandleExit() {
// Disable ASan by setting it to uninitialized. Also reset the
// shadow memory to avoid reporting errors after the run-time has
// been desroyed.
asan_inited = false;
// InitializeShadowMemory();
}
} // namespace __asan
// These are declared (in extern "C") by <some_path/sanitizer.h>.
// The system runtime will call our definitions directly.
extern "C" {
void __sanitizer_early_init() {
__asan::EarlyInit();
}
void *__sanitizer_before_thread_create_hook(uptr thread, bool detached,
const char *name,
void *stack_base, size_t stack_size,
void *tls_base, size_t tls_size) {
return __asan::BeforeThreadCreateHook(
thread, detached,
reinterpret_cast<uptr>(stack_base), stack_size,
reinterpret_cast<uptr>(tls_base), tls_size);
}
void __sanitizer_thread_create_hook(void *handle, uptr thread, int status) {
__asan::ThreadCreateHook(handle, status != 0);
}
void __sanitizer_thread_start_hook(void *handle, uptr self) {
__asan::ThreadStartHook(handle, self);
}
void __sanitizer_thread_exit_hook(void *handle, uptr self) {
__asan::ThreadExitHook(handle, self);
}
void __sanitizer_exit() {
__asan::HandleExit();
}
} // "C"
#endif // SANITIZER_RTEMS

View File

@ -30,6 +30,7 @@ set(SANITIZER_SOURCES_NOTERMINATION
sanitizer_procmaps_linux.cc
sanitizer_procmaps_mac.cc
sanitizer_procmaps_solaris.cc
sanitizer_rtems.cc
sanitizer_solaris.cc
sanitizer_stoptheworld_mac.cc
sanitizer_suppressions.cc
@ -140,6 +141,7 @@ set(SANITIZER_HEADERS
sanitizer_procmaps.h
sanitizer_quarantine.h
sanitizer_report_decorator.h
sanitizer_rtems.h
sanitizer_stackdepot.h
sanitizer_stackdepotbase.h
sanitizer_stacktrace.h

View File

@ -0,0 +1,288 @@
//===-- sanitizer_rtems.cc ------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is shared between various sanitizers' runtime libraries and
// implements RTEMS-specific functions.
//===----------------------------------------------------------------------===//
#include "sanitizer_rtems.h"
#if SANITIZER_RTEMS
#define posix_memalign __real_posix_memalign
#define free __real_free
#define memset __real_memset
#include "sanitizer_file.h"
#include "sanitizer_symbolizer.h"
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
// There is no mmap on RTEMS. Use memalign, etc.
#define __mmap_alloc_aligned posix_memalign
#define __mmap_free free
#define __mmap_memset memset
namespace __sanitizer {
#include "sanitizer_syscall_generic.inc"
void NORETURN internal__exit(int exitcode) {
_exit(exitcode);
}
uptr internal_sched_yield() {
return sched_yield();
}
uptr internal_getpid() {
return getpid();
}
bool FileExists(const char *filename) {
struct stat st;
if (stat(filename, &st))
return false;
// Sanity check: filename is a regular file.
return S_ISREG(st.st_mode);
}
uptr GetThreadSelf() { return static_cast<uptr>(pthread_self()); }
tid_t GetTid() { return GetThreadSelf(); }
void Abort() { abort(); }
int Atexit(void (*function)(void)) { return atexit(function); }
void SleepForSeconds(int seconds) { sleep(seconds); }
void SleepForMillis(int millis) { usleep(millis * 1000); }
bool SupportsColoredOutput(fd_t fd) { return false; }
void GetThreadStackTopAndBottom(bool at_initialization,
uptr *stack_top, uptr *stack_bottom) {
pthread_attr_t attr;
pthread_attr_init(&attr);
CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
void *base = nullptr;
size_t size = 0;
CHECK_EQ(pthread_attr_getstack(&attr, &base, &size), 0);
CHECK_EQ(pthread_attr_destroy(&attr), 0);
*stack_bottom = reinterpret_cast<uptr>(base);
*stack_top = *stack_bottom + size;
}
void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
uptr *tls_addr, uptr *tls_size) {
uptr stack_top, stack_bottom;
GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
*stk_addr = stack_bottom;
*stk_size = stack_top - stack_bottom;
*tls_addr = *tls_size = 0;
}
void MaybeReexec() {}
void DisableCoreDumperIfNecessary() {}
void InstallDeadlySignalHandlers(SignalHandlerType handler) {}
void SetAlternateSignalStack() {}
void UnsetAlternateSignalStack() {}
void InitTlsSize() {}
void PrintModuleMap() {}
void SignalContext::DumpAllRegisters(void *context) {}
const char *DescribeSignalOrException(int signo) { UNIMPLEMENTED(); }
enum MutexState { MtxUnlocked = 0, MtxLocked = 1, MtxSleeping = 2 };
BlockingMutex::BlockingMutex() {
internal_memset(this, 0, sizeof(*this));
}
void BlockingMutex::Lock() {
CHECK_EQ(owner_, 0);
atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked)
return;
while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) {
internal_sched_yield();
}
}
void BlockingMutex::Unlock() {
atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release);
CHECK_NE(v, MtxUnlocked);
}
void BlockingMutex::CheckLocked() {
atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed));
}
uptr GetPageSize() { return getpagesize(); }
uptr GetMmapGranularity() { return GetPageSize(); }
uptr GetMaxVirtualAddress() {
return (1ULL << 32) - 1; // 0xffffffff
}
void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
void* ptr = 0;
int res = __mmap_alloc_aligned(&ptr, GetPageSize(), size);
if (UNLIKELY(res))
ReportMmapFailureAndDie(size, mem_type, "allocate", res, raw_report);
__mmap_memset(ptr, 0, size);
IncreaseTotalMmap(size);
return ptr;
}
void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
void* ptr = 0;
int res = __mmap_alloc_aligned(&ptr, GetPageSize(), size);
if (UNLIKELY(res)) {
if (res == ENOMEM)
return nullptr;
ReportMmapFailureAndDie(size, mem_type, "allocate", false);
}
__mmap_memset(ptr, 0, size);
IncreaseTotalMmap(size);
return ptr;
}
void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
const char *mem_type) {
CHECK(IsPowerOfTwo(size));
CHECK(IsPowerOfTwo(alignment));
void* ptr = 0;
int res = __mmap_alloc_aligned(&ptr, alignment, size);
if (res)
ReportMmapFailureAndDie(size, mem_type, "align allocate", res, false);
__mmap_memset(ptr, 0, size);
IncreaseTotalMmap(size);
return ptr;
}
void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
return MmapOrDie(size, mem_type, false);
}
void UnmapOrDie(void *addr, uptr size) {
if (!addr || !size) return;
__mmap_free(addr);
DecreaseTotalMmap(size);
}
fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) {
int flags;
switch (mode) {
case RdOnly: flags = O_RDONLY; break;
case WrOnly: flags = O_WRONLY | O_CREAT; break;
case RdWr: flags = O_RDWR | O_CREAT; break;
}
fd_t res = open(filename, flags, 0660);
if (internal_iserror(res, errno_p))
return kInvalidFd;
return res;
}
void CloseFile(fd_t fd) {
close(fd);
}
bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read,
error_t *error_p) {
uptr res = read(fd, buff, buff_size);
if (internal_iserror(res, error_p))
return false;
if (bytes_read)
*bytes_read = res;
return true;
}
bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written,
error_t *error_p) {
uptr res = write(fd, buff, buff_size);
if (internal_iserror(res, error_p))
return false;
if (bytes_written)
*bytes_written = res;
return true;
}
bool RenameFile(const char *oldpath, const char *newpath, error_t *error_p) {
uptr res = rename(oldpath, newpath);
return !internal_iserror(res, error_p);
}
void ReleaseMemoryPagesToOS(uptr beg, uptr end) {}
void DumpProcessMap() {}
// There is no page protection so everything is "accessible."
bool IsAccessibleMemoryRange(uptr beg, uptr size) {
return true;
}
char **GetArgv() { return NULL; }
const char *GetEnv(const char *name) { return NULL; }
uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
internal_strncpy(buf, "StubBinaryName", buf_len);
return internal_strlen(buf);
}
uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) {
internal_strncpy(buf, "StubProcessName", buf_len);
return internal_strlen(buf);
}
bool IsPathSeparator(const char c) {
return c == '/';
}
bool IsAbsolutePath(const char *path) {
return path != nullptr && IsPathSeparator(path[0]);
}
void ReportFile::Write(const char *buffer, uptr length) {
SpinMutexLock l(mu);
static const char *kWriteError =
"ReportFile::Write() can't output requested buffer!\n";
ReopenIfNecessary();
if (length != write(fd, buffer, length)) {
write(fd, kWriteError, internal_strlen(kWriteError));
Die();
}
}
uptr MainThreadStackBase, MainThreadStackSize;
uptr MainThreadTlsBase, MainThreadTlsSize;
} // namespace __sanitizer
extern "C" {
void __sanitizer_startup_hook(void *stack_base, size_t stack_size,
void *tls_base, size_t tls_size) {
__sanitizer::MainThreadStackBase = reinterpret_cast<uintptr_t>(stack_base);
__sanitizer::MainThreadStackSize = stack_size;
__sanitizer::MainThreadTlsBase = reinterpret_cast<uintptr_t>(tls_base);
__sanitizer::MainThreadTlsSize = tls_size;
}
} // extern "C"
#endif // SANITIZER_RTEMS

View File

@ -0,0 +1,28 @@
//===-- sanitizer_rtems.h ---------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is shared between various sanitizers' runtime libraries and
// provides definitions for RTEMS-specific functions.
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_RTEMS_H
#define SANITIZER_RTEMS_H
#include "sanitizer_platform.h"
#if SANITIZER_RTEMS
#include "sanitizer_common.h"
namespace __sanitizer {
extern uptr MainThreadStackBase, MainThreadStackSize;
extern uptr MainThreadTlsBase, MainThreadTlsSize;
} // namespace __sanitizer
#endif // SANITIZER_RTEMS
#endif // SANITIZER_RTEMS_H