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
35 namespace __sanitizer {
36
37 #include "sanitizer_syscall_generic.inc"
38
internal__exit(int exitcode)39 void NORETURN internal__exit(int exitcode) {
40 _exit(exitcode);
41 }
42
internal_sched_yield()43 uptr internal_sched_yield() {
44 return sched_yield();
45 }
46
internal_getpid()47 uptr internal_getpid() {
48 return getpid();
49 }
50
internal_dlinfo(void * handle,int request,void * p)51 int internal_dlinfo(void *handle, int request, void *p) {
52 UNIMPLEMENTED();
53 }
54
FileExists(const char * filename)55 bool 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
GetThreadSelf()63 uptr GetThreadSelf() { return static_cast<uptr>(pthread_self()); }
64
GetTid()65 tid_t GetTid() { return GetThreadSelf(); }
66
Abort()67 void Abort() { abort(); }
68
Atexit(void (* function)(void))69 int Atexit(void (*function)(void)) { return atexit(function); }
70
SleepForSeconds(int seconds)71 void SleepForSeconds(int seconds) { sleep(seconds); }
72
SleepForMillis(int millis)73 void SleepForMillis(int millis) { usleep(millis * 1000); }
74
SupportsColoredOutput(fd_t fd)75 bool SupportsColoredOutput(fd_t fd) { return false; }
76
GetThreadStackTopAndBottom(bool at_initialization,uptr * stack_top,uptr * stack_bottom)77 void 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
GetThreadStackAndTls(bool main,uptr * stk_addr,uptr * stk_size,uptr * tls_addr,uptr * tls_size)91 void 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
MaybeReexec()100 void MaybeReexec() {}
CheckASLR()101 void CheckASLR() {}
DisableCoreDumperIfNecessary()102 void DisableCoreDumperIfNecessary() {}
InstallDeadlySignalHandlers(SignalHandlerType handler)103 void InstallDeadlySignalHandlers(SignalHandlerType handler) {}
SetAlternateSignalStack()104 void SetAlternateSignalStack() {}
UnsetAlternateSignalStack()105 void UnsetAlternateSignalStack() {}
InitTlsSize()106 void InitTlsSize() {}
107
PrintModuleMap()108 void PrintModuleMap() {}
109
DumpAllRegisters(void * context)110 void SignalContext::DumpAllRegisters(void *context) {}
DescribeSignalOrException(int signo)111 const char *DescribeSignalOrException(int signo) { UNIMPLEMENTED(); }
112
113 enum MutexState { MtxUnlocked = 0, MtxLocked = 1, MtxSleeping = 2 };
114
BlockingMutex()115 BlockingMutex::BlockingMutex() {
116 internal_memset(this, 0, sizeof(*this));
117 }
118
Lock()119 void 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
Unlock()129 void 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
CheckLocked()135 void 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
GetPageSize()140 uptr GetPageSize() { return getpagesize(); }
141
GetMmapGranularity()142 uptr GetMmapGranularity() { return GetPageSize(); }
143
GetMaxVirtualAddress()144 uptr GetMaxVirtualAddress() {
145 return (1ULL << 32) - 1; // 0xffffffff
146 }
147
MmapOrDie(uptr size,const char * mem_type,bool raw_report)148 void *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
MmapOrDieOnFatalError(uptr size,const char * mem_type)158 void *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
MmapAlignedOrDieOnFatalError(uptr size,uptr alignment,const char * mem_type)171 void *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
MmapNoReserveOrDie(uptr size,const char * mem_type)184 void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
185 return MmapOrDie(size, mem_type, false);
186 }
187
UnmapOrDie(void * addr,uptr size)188 void UnmapOrDie(void *addr, uptr size) {
189 if (!addr || !size) return;
190 __mmap_free(addr);
191 DecreaseTotalMmap(size);
192 }
193
OpenFile(const char * filename,FileAccessMode mode,error_t * errno_p)194 fd_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
CloseFile(fd_t fd)207 void CloseFile(fd_t fd) {
208 close(fd);
209 }
210
ReadFromFile(fd_t fd,void * buff,uptr buff_size,uptr * bytes_read,error_t * error_p)211 bool 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
WriteToFile(fd_t fd,const void * buff,uptr buff_size,uptr * bytes_written,error_t * error_p)221 bool 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
RenameFile(const char * oldpath,const char * newpath,error_t * error_p)231 bool 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
ReleaseMemoryPagesToOS(uptr beg,uptr end)236 void ReleaseMemoryPagesToOS(uptr beg, uptr end) {}
DumpProcessMap()237 void DumpProcessMap() {}
238
239 // There is no page protection so everything is "accessible."
IsAccessibleMemoryRange(uptr beg,uptr size)240 bool IsAccessibleMemoryRange(uptr beg, uptr size) {
241 return true;
242 }
243
GetArgv()244 char **GetArgv() { return nullptr; }
245
GetEnv(const char * name)246 const char *GetEnv(const char *name) {
247 return getenv(name);
248 }
249
ReadBinaryName(char * buf,uptr buf_len)250 uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
251 internal_strncpy(buf, "StubBinaryName", buf_len);
252 return internal_strlen(buf);
253 }
254
ReadLongProcessName(char * buf,uptr buf_len)255 uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) {
256 internal_strncpy(buf, "StubProcessName", buf_len);
257 return internal_strlen(buf);
258 }
259
IsPathSeparator(const char c)260 bool IsPathSeparator(const char c) {
261 return c == '/';
262 }
263
IsAbsolutePath(const char * path)264 bool IsAbsolutePath(const char *path) {
265 return path != nullptr && IsPathSeparator(path[0]);
266 }
267
Write(const char * buffer,uptr length)268 void 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
279 uptr MainThreadStackBase, MainThreadStackSize;
280 uptr MainThreadTlsBase, MainThreadTlsSize;
281
282 } // namespace __sanitizer
283
284 #endif // SANITIZER_RTEMS
285