forked from OSchip/llvm-project
[asan] Add target-specific files for Myriad RTEMS port
Differential Revision: https://reviews.llvm.org/D46468 llvm-svn: 332691
This commit is contained in:
parent
ce26498e3f
commit
e35f57f023
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue