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
52int internal_dlinfo(void *handle, int request, void *p) {
53  UNIMPLEMENTED();
54}
55
56bool FileExists(const char *filename) {
57  struct stat st;
58  if (stat(filename, &st))
59    return false;
60  // Sanity check: filename is a regular file.
61  return S_ISREG(st.st_mode);
62}
63
64uptr GetThreadSelf() { return static_cast<uptr>(pthread_self()); }
65
66tid_t GetTid() { return GetThreadSelf(); }
67
68void Abort() { abort(); }
69
70int Atexit(void (*function)(void)) { return atexit(function); }
71
72void SleepForSeconds(int seconds) { sleep(seconds); }
73
74void SleepForMillis(int millis) { usleep(millis * 1000); }
75
76bool SupportsColoredOutput(fd_t fd) { return false; }
77
78void GetThreadStackTopAndBottom(bool at_initialization,
79                                uptr *stack_top, uptr *stack_bottom) {
80  pthread_attr_t attr;
81  pthread_attr_init(&attr);
82  CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
83  void *base = nullptr;
84  size_t size = 0;
85  CHECK_EQ(pthread_attr_getstack(&attr, &base, &size), 0);
86  CHECK_EQ(pthread_attr_destroy(&attr), 0);
87
88  *stack_bottom = reinterpret_cast<uptr>(base);
89  *stack_top = *stack_bottom + size;
90}
91
92void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
93                          uptr *tls_addr, uptr *tls_size) {
94  uptr stack_top, stack_bottom;
95  GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
96  *stk_addr = stack_bottom;
97  *stk_size = stack_top - stack_bottom;
98  *tls_addr = *tls_size = 0;
99}
100
101void InitializePlatformEarly() {}
102void MaybeReexec() {}
103void CheckASLR() {}
104void CheckMPROTECT() {}
105void DisableCoreDumperIfNecessary() {}
106void InstallDeadlySignalHandlers(SignalHandlerType handler) {}
107void SetAlternateSignalStack() {}
108void UnsetAlternateSignalStack() {}
109void InitTlsSize() {}
110
111void PrintModuleMap() {}
112
113void SignalContext::DumpAllRegisters(void *context) {}
114const char *DescribeSignalOrException(int signo) { UNIMPLEMENTED(); }
115
116enum MutexState { MtxUnlocked = 0, MtxLocked = 1, MtxSleeping = 2 };
117
118BlockingMutex::BlockingMutex() {
119  internal_memset(this, 0, sizeof(*this));
120}
121
122void BlockingMutex::Lock() {
123  CHECK_EQ(owner_, 0);
124  atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
125  if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked)
126    return;
127  while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) {
128    internal_sched_yield();
129  }
130}
131
132void BlockingMutex::Unlock() {
133  atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
134  u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release);
135  CHECK_NE(v, MtxUnlocked);
136}
137
138void BlockingMutex::CheckLocked() {
139  atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
140  CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed));
141}
142
143uptr GetPageSize() { return getpagesize(); }
144
145uptr GetMmapGranularity() { return GetPageSize(); }
146
147uptr GetMaxVirtualAddress() {
148  return (1ULL << 32) - 1;  // 0xffffffff
149}
150
151void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
152  void* ptr = 0;
153  int res = __mmap_alloc_aligned(&ptr, GetPageSize(), size);
154  if (UNLIKELY(res))
155    ReportMmapFailureAndDie(size, mem_type, "allocate", res, raw_report);
156  __mmap_memset(ptr, 0, size);
157  IncreaseTotalMmap(size);
158  return ptr;
159}
160
161void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
162  void* ptr = 0;
163  int res = __mmap_alloc_aligned(&ptr, GetPageSize(), size);
164  if (UNLIKELY(res)) {
165    if (res == ENOMEM)
166      return nullptr;
167    ReportMmapFailureAndDie(size, mem_type, "allocate", false);
168  }
169  __mmap_memset(ptr, 0, size);
170  IncreaseTotalMmap(size);
171  return ptr;
172}
173
174void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
175                                   const char *mem_type) {
176  CHECK(IsPowerOfTwo(size));
177  CHECK(IsPowerOfTwo(alignment));
178  void* ptr = 0;
179  int res = __mmap_alloc_aligned(&ptr, alignment, size);
180  if (res)
181    ReportMmapFailureAndDie(size, mem_type, "align allocate", res, false);
182  __mmap_memset(ptr, 0, size);
183  IncreaseTotalMmap(size);
184  return ptr;
185}
186
187void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
188  return MmapOrDie(size, mem_type, false);
189}
190
191void UnmapOrDie(void *addr, uptr size) {
192  if (!addr || !size) return;
193  __mmap_free(addr);
194  DecreaseTotalMmap(size);
195}
196
197fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) {
198  int flags;
199  switch (mode) {
200    case RdOnly: flags = O_RDONLY; break;
201    case WrOnly: flags = O_WRONLY | O_CREAT | O_TRUNC; break;
202    case RdWr: flags = O_RDWR | O_CREAT; break;
203  }
204  fd_t res = open(filename, flags, 0660);
205  if (internal_iserror(res, errno_p))
206    return kInvalidFd;
207  return res;
208}
209
210void CloseFile(fd_t fd) {
211  close(fd);
212}
213
214bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read,
215                  error_t *error_p) {
216  uptr res = read(fd, buff, buff_size);
217  if (internal_iserror(res, error_p))
218    return false;
219  if (bytes_read)
220    *bytes_read = res;
221  return true;
222}
223
224bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written,
225                 error_t *error_p) {
226  uptr res = write(fd, buff, buff_size);
227  if (internal_iserror(res, error_p))
228    return false;
229  if (bytes_written)
230    *bytes_written = res;
231  return true;
232}
233
234void ReleaseMemoryPagesToOS(uptr beg, uptr end) {}
235void DumpProcessMap() {}
236
237// There is no page protection so everything is "accessible."
238bool IsAccessibleMemoryRange(uptr beg, uptr size) {
239  return true;
240}
241
242char **GetArgv() { return nullptr; }
243char **GetEnviron() { return nullptr; }
244
245const char *GetEnv(const char *name) {
246  return getenv(name);
247}
248
249uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
250  internal_strncpy(buf, "StubBinaryName", buf_len);
251  return internal_strlen(buf);
252}
253
254uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) {
255  internal_strncpy(buf, "StubProcessName", buf_len);
256  return internal_strlen(buf);
257}
258
259bool IsPathSeparator(const char c) {
260  return c == '/';
261}
262
263bool IsAbsolutePath(const char *path) {
264  return path != nullptr && IsPathSeparator(path[0]);
265}
266
267void ReportFile::Write(const char *buffer, uptr length) {
268  SpinMutexLock l(mu);
269  static const char *kWriteError =
270      "ReportFile::Write() can't output requested buffer!\n";
271  ReopenIfNecessary();
272  if (length != write(fd, buffer, length)) {
273    write(fd, kWriteError, internal_strlen(kWriteError));
274    Die();
275  }
276}
277
278uptr MainThreadStackBase, MainThreadStackSize;
279uptr MainThreadTlsBase, MainThreadTlsSize;
280
281} // namespace __sanitizer
282
283#endif  // SANITIZER_RTEMS
284