//===-- 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 #include #include #include #include #include #include #include // 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(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(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(&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(&opaque_storage_); u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release); CHECK_NE(v, MtxUnlocked); } void BlockingMutex::CheckLocked() { atomic_uint32_t *m = reinterpret_cast(&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