asan_rtems.cpp revision 360784
1//===-- asan_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 a part of AddressSanitizer, an address sanity checker. 10// 11// RTEMS-specific details. 12//===----------------------------------------------------------------------===// 13 14#include "sanitizer_common/sanitizer_rtems.h" 15#if SANITIZER_RTEMS 16 17#include "asan_internal.h" 18#include "asan_interceptors.h" 19#include "asan_mapping.h" 20#include "asan_poisoning.h" 21#include "asan_report.h" 22#include "asan_stack.h" 23#include "sanitizer_common/sanitizer_common.h" 24#include "sanitizer_common/sanitizer_libc.h" 25 26#include <pthread.h> 27#include <stdlib.h> 28 29namespace __asan { 30 31static void ResetShadowMemory() { 32 uptr shadow_start = SHADOW_OFFSET; 33 uptr shadow_end = MEM_TO_SHADOW(kMyriadMemoryEnd32); 34 uptr gap_start = MEM_TO_SHADOW(shadow_start); 35 uptr gap_end = MEM_TO_SHADOW(shadow_end); 36 37 REAL(memset)((void *)shadow_start, 0, shadow_end - shadow_start); 38 REAL(memset)((void *)gap_start, kAsanShadowGap, gap_end - gap_start); 39} 40 41void InitializeShadowMemory() { 42 kHighMemEnd = 0; 43 kMidMemBeg = 0; 44 kMidMemEnd = 0; 45 46 ResetShadowMemory(); 47} 48 49void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { 50 UNIMPLEMENTED(); 51} 52 53void AsanCheckDynamicRTPrereqs() {} 54void AsanCheckIncompatibleRT() {} 55void InitializeAsanInterceptors() {} 56void InitializePlatformInterceptors() {} 57void InitializePlatformExceptionHandlers() {} 58 59// RTEMS only support static linking; it sufficies to return with no 60// error. 61void *AsanDoesNotSupportStaticLinkage() { return nullptr; } 62 63void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { 64 UNIMPLEMENTED(); 65} 66 67void EarlyInit() { 68 // Provide early initialization of shadow memory so that 69 // instrumented code running before full initialzation will not 70 // report spurious errors. 71 ResetShadowMemory(); 72} 73 74// We can use a plain thread_local variable for TSD. 75static thread_local void *per_thread; 76 77void *AsanTSDGet() { return per_thread; } 78 79void AsanTSDSet(void *tsd) { per_thread = tsd; } 80 81// There's no initialization needed, and the passed-in destructor 82// will never be called. Instead, our own thread destruction hook 83// (below) will call AsanThread::TSDDtor directly. 84void AsanTSDInit(void (*destructor)(void *tsd)) { 85 DCHECK(destructor == &PlatformTSDDtor); 86} 87 88void PlatformTSDDtor(void *tsd) { UNREACHABLE(__func__); } 89 90// 91// Thread registration. We provide an API similar to the Fushia port. 92// 93 94struct AsanThread::InitOptions { 95 uptr stack_bottom, stack_size, tls_bottom, tls_size; 96}; 97 98// Shared setup between thread creation and startup for the initial thread. 99static AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid, 100 uptr user_id, bool detached, 101 uptr stack_bottom, uptr stack_size, 102 uptr tls_bottom, uptr tls_size) { 103 // In lieu of AsanThread::Create. 104 AsanThread *thread = (AsanThread *)MmapOrDie(sizeof(AsanThread), __func__); 105 AsanThreadContext::CreateThreadContextArgs args = {thread, stack}; 106 asanThreadRegistry().CreateThread(user_id, detached, parent_tid, &args); 107 108 // On other systems, AsanThread::Init() is called from the new 109 // thread itself. But on RTEMS we already know the stack address 110 // range beforehand, so we can do most of the setup right now. 111 const AsanThread::InitOptions options = {stack_bottom, stack_size, 112 tls_bottom, tls_size}; 113 thread->Init(&options); 114 return thread; 115} 116 117// This gets the same arguments passed to Init by CreateAsanThread, above. 118// We're in the creator thread before the new thread is actually started, but 119// its stack and tls address range are already known. 120void AsanThread::SetThreadStackAndTls(const AsanThread::InitOptions *options) { 121 DCHECK_NE(GetCurrentThread(), this); 122 DCHECK_NE(GetCurrentThread(), nullptr); 123 CHECK_NE(options->stack_bottom, 0); 124 CHECK_NE(options->stack_size, 0); 125 stack_bottom_ = options->stack_bottom; 126 stack_top_ = options->stack_bottom + options->stack_size; 127 tls_begin_ = options->tls_bottom; 128 tls_end_ = options->tls_bottom + options->tls_size; 129} 130 131// Called by __asan::AsanInitInternal (asan_rtl.c). Unlike other ports, the 132// main thread on RTEMS does not require special treatment; its AsanThread is 133// already created by the provided hooks. This function simply looks up and 134// returns the created thread. 135AsanThread *CreateMainThread() { 136 return GetThreadContextByTidLocked(0)->thread; 137} 138 139// This is called before each thread creation is attempted. So, in 140// its first call, the calling thread is the initial and sole thread. 141static void *BeforeThreadCreateHook(uptr user_id, bool detached, 142 uptr stack_bottom, uptr stack_size, 143 uptr tls_bottom, uptr tls_size) { 144 EnsureMainThreadIDIsCorrect(); 145 // Strict init-order checking is thread-hostile. 146 if (flags()->strict_init_order) StopInitOrderChecking(); 147 148 GET_STACK_TRACE_THREAD; 149 u32 parent_tid = GetCurrentTidOrInvalid(); 150 151 return CreateAsanThread(&stack, parent_tid, user_id, detached, 152 stack_bottom, stack_size, tls_bottom, tls_size); 153} 154 155// This is called after creating a new thread (in the creating thread), 156// with the pointer returned by BeforeThreadCreateHook (above). 157static void ThreadCreateHook(void *hook, bool aborted) { 158 AsanThread *thread = static_cast<AsanThread *>(hook); 159 if (!aborted) { 160 // The thread was created successfully. 161 // ThreadStartHook is already running in the new thread. 162 } else { 163 // The thread wasn't created after all. 164 // Clean up everything we set up in BeforeThreadCreateHook. 165 asanThreadRegistry().FinishThread(thread->tid()); 166 UnmapOrDie(thread, sizeof(AsanThread)); 167 } 168} 169 170// This is called (1) in the newly-created thread before it runs anything else, 171// with the pointer returned by BeforeThreadCreateHook (above). (2) before a 172// thread restart. 173static void ThreadStartHook(void *hook, uptr os_id) { 174 if (!hook) 175 return; 176 177 AsanThread *thread = static_cast<AsanThread *>(hook); 178 SetCurrentThread(thread); 179 180 ThreadStatus status = 181 asanThreadRegistry().GetThreadLocked(thread->tid())->status; 182 DCHECK(status == ThreadStatusCreated || status == ThreadStatusRunning); 183 // Determine whether we are starting or restarting the thread. 184 if (status == ThreadStatusCreated) { 185 // In lieu of AsanThread::ThreadStart. 186 asanThreadRegistry().StartThread(thread->tid(), os_id, ThreadType::Regular, 187 nullptr); 188 } else { 189 // In a thread restart, a thread may resume execution at an 190 // arbitrary function entry point, with its stack and TLS state 191 // reset. We unpoison the stack in that case. 192 PoisonShadow(thread->stack_bottom(), thread->stack_size(), 0); 193 } 194} 195 196// Each thread runs this just before it exits, 197// with the pointer returned by BeforeThreadCreateHook (above). 198// All per-thread destructors have already been called. 199static void ThreadExitHook(void *hook, uptr os_id) { 200 AsanThread *thread = static_cast<AsanThread *>(hook); 201 if (thread) 202 AsanThread::TSDDtor(thread->context()); 203} 204 205static void HandleExit() { 206 // Disable ASan by setting it to uninitialized. Also reset the 207 // shadow memory to avoid reporting errors after the run-time has 208 // been desroyed. 209 if (asan_inited) { 210 asan_inited = false; 211 ResetShadowMemory(); 212 } 213} 214 215bool HandleDlopenInit() { 216 // Not supported on this platform. 217 static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN, 218 "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false"); 219 return false; 220} 221} // namespace __asan 222 223// These are declared (in extern "C") by <some_path/sanitizer.h>. 224// The system runtime will call our definitions directly. 225 226extern "C" { 227void __sanitizer_early_init() { 228 __asan::EarlyInit(); 229} 230 231void *__sanitizer_before_thread_create_hook(uptr thread, bool detached, 232 const char *name, 233 void *stack_base, size_t stack_size, 234 void *tls_base, size_t tls_size) { 235 return __asan::BeforeThreadCreateHook( 236 thread, detached, 237 reinterpret_cast<uptr>(stack_base), stack_size, 238 reinterpret_cast<uptr>(tls_base), tls_size); 239} 240 241void __sanitizer_thread_create_hook(void *handle, uptr thread, int status) { 242 __asan::ThreadCreateHook(handle, status != 0); 243} 244 245void __sanitizer_thread_start_hook(void *handle, uptr self) { 246 __asan::ThreadStartHook(handle, self); 247} 248 249void __sanitizer_thread_exit_hook(void *handle, uptr self) { 250 __asan::ThreadExitHook(handle, self); 251} 252 253void __sanitizer_exit() { 254 __asan::HandleExit(); 255} 256} // "C" 257 258#endif // SANITIZER_RTEMS 259