1//===-- sanitizer_rtems.cpp -----------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file is shared between various sanitizers' runtime libraries and
10// implements RTEMS-specific functions.
11//===----------------------------------------------------------------------===//
12
13#include "sanitizer_rtems.h"
14#if SANITIZER_RTEMS
15
16#define posix_memalign __real_posix_memalign
17#define free __real_free
18#define memset __real_memset
19
20#include "sanitizer_file.h"
21#include "sanitizer_symbolizer.h"
22#include <errno.h>
23#include <fcntl.h>
24#include <pthread.h>
25#include <sched.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <unistd.h>
30
31// There is no mmap on RTEMS.  Use memalign, etc.
32#define __mmap_alloc_aligned posix_memalign
33#define __mmap_free free
34#define __mmap_memset memset
35
36namespace __sanitizer {
37
38#include "sanitizer_syscall_generic.inc"
39
40void NORETURN internal__exit(int exitcode) {
41  _exit(exitcode);
42}
43
44uptr internal_sched_yield() {
45  return sched_yield();
46}
47
48uptr internal_getpid() {
49  return getpid();
50}
51
52bool FileExists(const char *filename) {
53  struct stat st;
54  if (stat(filename, &st))
55    return false;
56  // Sanity check: filename is a regular file.
57  return S_ISREG(st.st_mode);
58}
59
60uptr GetThreadSelf() { return static_cast<uptr>(pthread_self()); }
61
62tid_t GetTid() { return GetThreadSelf(); }
63
64void Abort() { abort(); }
65
66int Atexit(void (*function)(void)) { return atexit(function); }
67
68void SleepForSeconds(int seconds) { sleep(seconds); }
69
70void SleepForMillis(int millis) { usleep(millis * 1000); }
71
72bool SupportsColoredOutput(fd_t fd) { return false; }
73
74void GetThreadStackTopAndBottom(bool at_initialization,
75                                uptr *stack_top, uptr *stack_bottom) {
76  pthread_attr_t attr;
77  pthread_attr_init(&attr);
78  CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
79  void *base = nullptr;
80  size_t size = 0;
81  CHECK_EQ(pthread_attr_getstack(&attr, &base, &size), 0);
82  CHECK_EQ(pthread_attr_destroy(&attr), 0);
83
84  *stack_bottom = reinterpret_cast<uptr>(base);
85  *stack_top = *stack_bottom + size;
86}
87
88void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
89                          uptr *tls_addr, uptr *tls_size) {
90  uptr stack_top, stack_bottom;
91  GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
92  *stk_addr = stack_bottom;
93  *stk_size = stack_top - stack_bottom;
94  *tls_addr = *tls_size = 0;
95}
96
97void InitializePlatformEarly() {}
98void MaybeReexec() {}
99void CheckASLR() {}
100void CheckMPROTECT() {}
101void DisableCoreDumperIfNecessary() {}
102void InstallDeadlySignalHandlers(SignalHandlerType handler) {}
103void SetAlternateSignalStack() {}
104void UnsetAlternateSignalStack() {}
105void InitTlsSize() {}
106
107void PrintModuleMap() {}
108
109void SignalContext::DumpAllRegisters(void *context) {}
110const char *DescribeSignalOrException(int signo) { UNIMPLEMENTED(); }
111
112enum MutexState { MtxUnlocked = 0, MtxLocked = 1, MtxSleeping = 2 };
113
114BlockingMutex::BlockingMutex() {
115  internal_memset(this, 0, sizeof(*this));
116}
117
118void BlockingMutex::Lock() {
119  CHECK_EQ(owner_, 0);
120  atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
121  if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked)
122    return;
123  while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) {
124    internal_sched_yield();
125  }
126}
127
128void BlockingMutex::Unlock() {
129  atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
130  u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release);
131  CHECK_NE(v, MtxUnlocked);
132}
133
134void BlockingMutex::CheckLocked() {
135  atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
136  CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed));
137}
138
139uptr GetPageSize() { return getpagesize(); }
140
141uptr GetMmapGranularity() { return GetPageSize(); }
142
143uptr GetMaxVirtualAddress() {
144  return (1ULL << 32) - 1;  // 0xffffffff
145}
146
147void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
148  void* ptr = 0;
149  int res = __mmap_alloc_aligned(&ptr, GetPageSize(), size);
150  if (UNLIKELY(res))
151    ReportMmapFailureAndDie(size, mem_type, "allocate", res, raw_report);
152  __mmap_memset(ptr, 0, size);
153  IncreaseTotalMmap(size);
154  return ptr;
155}
156
157void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
158  void* ptr = 0;
159  int res = __mmap_alloc_aligned(&ptr, GetPageSize(), size);
160  if (UNLIKELY(res)) {
161    if (res == ENOMEM)
162      return nullptr;
163    ReportMmapFailureAndDie(size, mem_type, "allocate", false);
164  }
165  __mmap_memset(ptr, 0, size);
166  IncreaseTotalMmap(size);
167  return ptr;
168}
169
170void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
171                                   const char *mem_type) {
172  CHECK(IsPowerOfTwo(size));
173  CHECK(IsPowerOfTwo(alignment));
174  void* ptr = 0;
175  int res = __mmap_alloc_aligned(&ptr, alignment, size);
176  if (res)
177    ReportMmapFailureAndDie(size, mem_type, "align allocate", res, false);
178  __mmap_memset(ptr, 0, size);
179  IncreaseTotalMmap(size);
180  return ptr;
181}
182
183void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
184  return MmapOrDie(size, mem_type, false);
185}
186
187void UnmapOrDie(void *addr, uptr size) {
188  if (!addr || !size) return;
189  __mmap_free(addr);
190  DecreaseTotalMmap(size);
191}
192
193fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) {
194  int flags;
195  switch (mode) {
196    case RdOnly: flags = O_RDONLY; break;
197    case WrOnly: flags = O_WRONLY | O_CREAT | O_TRUNC; break;
198    case RdWr: flags = O_RDWR | O_CREAT; break;
199  }
200  fd_t res = open(filename, flags, 0660);
201  if (internal_iserror(res, errno_p))
202    return kInvalidFd;
203  return res;
204}
205
206void CloseFile(fd_t fd) {
207  close(fd);
208}
209
210bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read,
211                  error_t *error_p) {
212  uptr res = read(fd, buff, buff_size);
213  if (internal_iserror(res, error_p))
214    return false;
215  if (bytes_read)
216    *bytes_read = res;
217  return true;
218}
219
220bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written,
221                 error_t *error_p) {
222  uptr res = write(fd, buff, buff_size);
223  if (internal_iserror(res, error_p))
224    return false;
225  if (bytes_written)
226    *bytes_written = res;
227  return true;
228}
229
230void ReleaseMemoryPagesToOS(uptr beg, uptr end) {}
231void DumpProcessMap() {}
232
233// There is no page protection so everything is "accessible."
234bool IsAccessibleMemoryRange(uptr beg, uptr size) {
235  return true;
236}
237
238char **GetArgv() { return nullptr; }
239char **GetEnviron() { return nullptr; }
240
241const char *GetEnv(const char *name) {
242  return getenv(name);
243}
244
245uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
246  internal_strncpy(buf, "StubBinaryName", buf_len);
247  return internal_strlen(buf);
248}
249
250uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) {
251  internal_strncpy(buf, "StubProcessName", buf_len);
252  return internal_strlen(buf);
253}
254
255bool IsPathSeparator(const char c) {
256  return c == '/';
257}
258
259bool IsAbsolutePath(const char *path) {
260  return path != nullptr && IsPathSeparator(path[0]);
261}
262
263void ReportFile::Write(const char *buffer, uptr length) {
264  SpinMutexLock l(mu);
265  static const char *kWriteError =
266      "ReportFile::Write() can't output requested buffer!\n";
267  ReopenIfNecessary();
268  if (length != write(fd, buffer, length)) {
269    write(fd, kWriteError, internal_strlen(kWriteError));
270    Die();
271  }
272}
273
274uptr MainThreadStackBase, MainThreadStackSize;
275uptr MainThreadTlsBase, MainThreadTlsSize;
276
277} // namespace __sanitizer
278
279#endif  // SANITIZER_RTEMS
280