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