| //===-- sanitizer_rtems.cpp -----------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // 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(); |
| } |
| |
| int internal_dlinfo(void *handle, int request, void *p) { |
| UNIMPLEMENTED(); |
| } |
| |
| 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 InitializePlatformEarly() {} |
| void MaybeReexec() {} |
| void CheckASLR() {} |
| void CheckMPROTECT() {} |
| void DisableCoreDumperIfNecessary() {} |
| void InstallDeadlySignalHandlers(SignalHandlerType handler) {} |
| void SetAlternateSignalStack() {} |
| void UnsetAlternateSignalStack() {} |
| void InitTlsSize() {} |
| |
| 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 | O_TRUNC; 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; |
| } |
| |
| 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 nullptr; } |
| char **GetEnviron() { return nullptr; } |
| |
| const char *GetEnv(const char *name) { |
| return getenv(name); |
| } |
| |
| 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 |
| |
| #endif // SANITIZER_RTEMS |