1353944Sdim//===-- sanitizer_rtems.cpp -----------------------------------------------===//
2353944Sdim//
3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353944Sdim// See https://llvm.org/LICENSE.txt for license information.
5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6353944Sdim//
7353944Sdim//===----------------------------------------------------------------------===//
8353944Sdim//
9353944Sdim// This file is shared between various sanitizers' runtime libraries and
10353944Sdim// implements RTEMS-specific functions.
11353944Sdim//===----------------------------------------------------------------------===//
12353944Sdim
13353944Sdim#include "sanitizer_rtems.h"
14353944Sdim#if SANITIZER_RTEMS
15353944Sdim
16353944Sdim#define posix_memalign __real_posix_memalign
17353944Sdim#define free __real_free
18353944Sdim#define memset __real_memset
19353944Sdim
20353944Sdim#include "sanitizer_file.h"
21353944Sdim#include "sanitizer_symbolizer.h"
22353944Sdim#include <errno.h>
23353944Sdim#include <fcntl.h>
24353944Sdim#include <pthread.h>
25353944Sdim#include <sched.h>
26353944Sdim#include <stdio.h>
27353944Sdim#include <stdlib.h>
28353944Sdim#include <string.h>
29353944Sdim#include <unistd.h>
30353944Sdim
31353944Sdim// There is no mmap on RTEMS.  Use memalign, etc.
32353944Sdim#define __mmap_alloc_aligned posix_memalign
33353944Sdim#define __mmap_free free
34353944Sdim#define __mmap_memset memset
35353944Sdim
36353944Sdimnamespace __sanitizer {
37353944Sdim
38353944Sdim#include "sanitizer_syscall_generic.inc"
39353944Sdim
40353944Sdimvoid NORETURN internal__exit(int exitcode) {
41353944Sdim  _exit(exitcode);
42353944Sdim}
43353944Sdim
44353944Sdimuptr internal_sched_yield() {
45353944Sdim  return sched_yield();
46353944Sdim}
47353944Sdim
48353944Sdimuptr internal_getpid() {
49353944Sdim  return getpid();
50353944Sdim}
51353944Sdim
52353944Sdimbool FileExists(const char *filename) {
53353944Sdim  struct stat st;
54353944Sdim  if (stat(filename, &st))
55353944Sdim    return false;
56353944Sdim  // Sanity check: filename is a regular file.
57353944Sdim  return S_ISREG(st.st_mode);
58353944Sdim}
59353944Sdim
60353944Sdimuptr GetThreadSelf() { return static_cast<uptr>(pthread_self()); }
61353944Sdim
62353944Sdimtid_t GetTid() { return GetThreadSelf(); }
63353944Sdim
64353944Sdimvoid Abort() { abort(); }
65353944Sdim
66353944Sdimint Atexit(void (*function)(void)) { return atexit(function); }
67353944Sdim
68353944Sdimvoid SleepForSeconds(int seconds) { sleep(seconds); }
69353944Sdim
70353944Sdimvoid SleepForMillis(int millis) { usleep(millis * 1000); }
71353944Sdim
72353944Sdimbool SupportsColoredOutput(fd_t fd) { return false; }
73353944Sdim
74353944Sdimvoid GetThreadStackTopAndBottom(bool at_initialization,
75353944Sdim                                uptr *stack_top, uptr *stack_bottom) {
76353944Sdim  pthread_attr_t attr;
77353944Sdim  pthread_attr_init(&attr);
78353944Sdim  CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
79353944Sdim  void *base = nullptr;
80353944Sdim  size_t size = 0;
81353944Sdim  CHECK_EQ(pthread_attr_getstack(&attr, &base, &size), 0);
82353944Sdim  CHECK_EQ(pthread_attr_destroy(&attr), 0);
83353944Sdim
84353944Sdim  *stack_bottom = reinterpret_cast<uptr>(base);
85353944Sdim  *stack_top = *stack_bottom + size;
86353944Sdim}
87353944Sdim
88353944Sdimvoid GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
89353944Sdim                          uptr *tls_addr, uptr *tls_size) {
90353944Sdim  uptr stack_top, stack_bottom;
91353944Sdim  GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
92353944Sdim  *stk_addr = stack_bottom;
93353944Sdim  *stk_size = stack_top - stack_bottom;
94353944Sdim  *tls_addr = *tls_size = 0;
95353944Sdim}
96353944Sdim
97353944Sdimvoid InitializePlatformEarly() {}
98353944Sdimvoid MaybeReexec() {}
99353944Sdimvoid CheckASLR() {}
100353944Sdimvoid CheckMPROTECT() {}
101353944Sdimvoid DisableCoreDumperIfNecessary() {}
102353944Sdimvoid InstallDeadlySignalHandlers(SignalHandlerType handler) {}
103353944Sdimvoid SetAlternateSignalStack() {}
104353944Sdimvoid UnsetAlternateSignalStack() {}
105353944Sdimvoid InitTlsSize() {}
106353944Sdim
107353944Sdimvoid PrintModuleMap() {}
108353944Sdim
109353944Sdimvoid SignalContext::DumpAllRegisters(void *context) {}
110353944Sdimconst char *DescribeSignalOrException(int signo) { UNIMPLEMENTED(); }
111353944Sdim
112353944Sdimenum MutexState { MtxUnlocked = 0, MtxLocked = 1, MtxSleeping = 2 };
113353944Sdim
114353944SdimBlockingMutex::BlockingMutex() {
115353944Sdim  internal_memset(this, 0, sizeof(*this));
116353944Sdim}
117353944Sdim
118353944Sdimvoid BlockingMutex::Lock() {
119353944Sdim  CHECK_EQ(owner_, 0);
120353944Sdim  atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
121353944Sdim  if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked)
122353944Sdim    return;
123353944Sdim  while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) {
124353944Sdim    internal_sched_yield();
125353944Sdim  }
126353944Sdim}
127353944Sdim
128353944Sdimvoid BlockingMutex::Unlock() {
129353944Sdim  atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
130353944Sdim  u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release);
131353944Sdim  CHECK_NE(v, MtxUnlocked);
132353944Sdim}
133353944Sdim
134353944Sdimvoid BlockingMutex::CheckLocked() {
135353944Sdim  atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
136353944Sdim  CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed));
137353944Sdim}
138353944Sdim
139353944Sdimuptr GetPageSize() { return getpagesize(); }
140353944Sdim
141353944Sdimuptr GetMmapGranularity() { return GetPageSize(); }
142353944Sdim
143353944Sdimuptr GetMaxVirtualAddress() {
144353944Sdim  return (1ULL << 32) - 1;  // 0xffffffff
145353944Sdim}
146353944Sdim
147353944Sdimvoid *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
148353944Sdim  void* ptr = 0;
149353944Sdim  int res = __mmap_alloc_aligned(&ptr, GetPageSize(), size);
150353944Sdim  if (UNLIKELY(res))
151353944Sdim    ReportMmapFailureAndDie(size, mem_type, "allocate", res, raw_report);
152353944Sdim  __mmap_memset(ptr, 0, size);
153353944Sdim  IncreaseTotalMmap(size);
154353944Sdim  return ptr;
155353944Sdim}
156353944Sdim
157353944Sdimvoid *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
158353944Sdim  void* ptr = 0;
159353944Sdim  int res = __mmap_alloc_aligned(&ptr, GetPageSize(), size);
160353944Sdim  if (UNLIKELY(res)) {
161353944Sdim    if (res == ENOMEM)
162353944Sdim      return nullptr;
163353944Sdim    ReportMmapFailureAndDie(size, mem_type, "allocate", false);
164353944Sdim  }
165353944Sdim  __mmap_memset(ptr, 0, size);
166353944Sdim  IncreaseTotalMmap(size);
167353944Sdim  return ptr;
168353944Sdim}
169353944Sdim
170353944Sdimvoid *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
171353944Sdim                                   const char *mem_type) {
172353944Sdim  CHECK(IsPowerOfTwo(size));
173353944Sdim  CHECK(IsPowerOfTwo(alignment));
174353944Sdim  void* ptr = 0;
175353944Sdim  int res = __mmap_alloc_aligned(&ptr, alignment, size);
176353944Sdim  if (res)
177353944Sdim    ReportMmapFailureAndDie(size, mem_type, "align allocate", res, false);
178353944Sdim  __mmap_memset(ptr, 0, size);
179353944Sdim  IncreaseTotalMmap(size);
180353944Sdim  return ptr;
181353944Sdim}
182353944Sdim
183353944Sdimvoid *MmapNoReserveOrDie(uptr size, const char *mem_type) {
184353944Sdim  return MmapOrDie(size, mem_type, false);
185353944Sdim}
186353944Sdim
187353944Sdimvoid UnmapOrDie(void *addr, uptr size) {
188353944Sdim  if (!addr || !size) return;
189353944Sdim  __mmap_free(addr);
190353944Sdim  DecreaseTotalMmap(size);
191353944Sdim}
192353944Sdim
193353944Sdimfd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) {
194353944Sdim  int flags;
195353944Sdim  switch (mode) {
196353944Sdim    case RdOnly: flags = O_RDONLY; break;
197353944Sdim    case WrOnly: flags = O_WRONLY | O_CREAT | O_TRUNC; break;
198353944Sdim    case RdWr: flags = O_RDWR | O_CREAT; break;
199353944Sdim  }
200353944Sdim  fd_t res = open(filename, flags, 0660);
201353944Sdim  if (internal_iserror(res, errno_p))
202353944Sdim    return kInvalidFd;
203353944Sdim  return res;
204353944Sdim}
205353944Sdim
206353944Sdimvoid CloseFile(fd_t fd) {
207353944Sdim  close(fd);
208353944Sdim}
209353944Sdim
210353944Sdimbool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read,
211353944Sdim                  error_t *error_p) {
212353944Sdim  uptr res = read(fd, buff, buff_size);
213353944Sdim  if (internal_iserror(res, error_p))
214353944Sdim    return false;
215353944Sdim  if (bytes_read)
216353944Sdim    *bytes_read = res;
217353944Sdim  return true;
218353944Sdim}
219353944Sdim
220353944Sdimbool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written,
221353944Sdim                 error_t *error_p) {
222353944Sdim  uptr res = write(fd, buff, buff_size);
223353944Sdim  if (internal_iserror(res, error_p))
224353944Sdim    return false;
225353944Sdim  if (bytes_written)
226353944Sdim    *bytes_written = res;
227353944Sdim  return true;
228353944Sdim}
229353944Sdim
230353944Sdimvoid ReleaseMemoryPagesToOS(uptr beg, uptr end) {}
231353944Sdimvoid DumpProcessMap() {}
232353944Sdim
233353944Sdim// There is no page protection so everything is "accessible."
234353944Sdimbool IsAccessibleMemoryRange(uptr beg, uptr size) {
235353944Sdim  return true;
236353944Sdim}
237353944Sdim
238353944Sdimchar **GetArgv() { return nullptr; }
239353944Sdimchar **GetEnviron() { return nullptr; }
240353944Sdim
241353944Sdimconst char *GetEnv(const char *name) {
242353944Sdim  return getenv(name);
243353944Sdim}
244353944Sdim
245353944Sdimuptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
246353944Sdim  internal_strncpy(buf, "StubBinaryName", buf_len);
247353944Sdim  return internal_strlen(buf);
248353944Sdim}
249353944Sdim
250353944Sdimuptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) {
251353944Sdim  internal_strncpy(buf, "StubProcessName", buf_len);
252353944Sdim  return internal_strlen(buf);
253353944Sdim}
254353944Sdim
255353944Sdimbool IsPathSeparator(const char c) {
256353944Sdim  return c == '/';
257353944Sdim}
258353944Sdim
259353944Sdimbool IsAbsolutePath(const char *path) {
260353944Sdim  return path != nullptr && IsPathSeparator(path[0]);
261353944Sdim}
262353944Sdim
263353944Sdimvoid ReportFile::Write(const char *buffer, uptr length) {
264353944Sdim  SpinMutexLock l(mu);
265353944Sdim  static const char *kWriteError =
266353944Sdim      "ReportFile::Write() can't output requested buffer!\n";
267353944Sdim  ReopenIfNecessary();
268353944Sdim  if (length != write(fd, buffer, length)) {
269353944Sdim    write(fd, kWriteError, internal_strlen(kWriteError));
270353944Sdim    Die();
271353944Sdim  }
272353944Sdim}
273353944Sdim
274353944Sdimuptr MainThreadStackBase, MainThreadStackSize;
275353944Sdimuptr MainThreadTlsBase, MainThreadTlsSize;
276353944Sdim
277353944Sdim} // namespace __sanitizer
278353944Sdim
279353944Sdim#endif  // SANITIZER_RTEMS
280