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