1353944Sdim//===-- asan_rtems.cpp ----------------------------------------------------===// 2353944Sdim// 3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353944Sdim// See https://llvm.org/LICENSE.txt for license information. 5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6353944Sdim// 7353944Sdim//===----------------------------------------------------------------------===// 8353944Sdim// 9353944Sdim// This file is a part of AddressSanitizer, an address sanity checker. 10353944Sdim// 11353944Sdim// RTEMS-specific details. 12353944Sdim//===----------------------------------------------------------------------===// 13353944Sdim 14353944Sdim#include "sanitizer_common/sanitizer_rtems.h" 15353944Sdim#if SANITIZER_RTEMS 16353944Sdim 17353944Sdim#include "asan_internal.h" 18353944Sdim#include "asan_interceptors.h" 19353944Sdim#include "asan_mapping.h" 20353944Sdim#include "asan_poisoning.h" 21353944Sdim#include "asan_report.h" 22353944Sdim#include "asan_stack.h" 23353944Sdim#include "sanitizer_common/sanitizer_common.h" 24353944Sdim#include "sanitizer_common/sanitizer_libc.h" 25353944Sdim 26353944Sdim#include <pthread.h> 27353944Sdim#include <stdlib.h> 28353944Sdim 29353944Sdimnamespace __asan { 30353944Sdim 31353944Sdimstatic void ResetShadowMemory() { 32353944Sdim uptr shadow_start = SHADOW_OFFSET; 33353944Sdim uptr shadow_end = MEM_TO_SHADOW(kMyriadMemoryEnd32); 34353944Sdim uptr gap_start = MEM_TO_SHADOW(shadow_start); 35353944Sdim uptr gap_end = MEM_TO_SHADOW(shadow_end); 36353944Sdim 37353944Sdim REAL(memset)((void *)shadow_start, 0, shadow_end - shadow_start); 38353944Sdim REAL(memset)((void *)gap_start, kAsanShadowGap, gap_end - gap_start); 39353944Sdim} 40353944Sdim 41353944Sdimvoid InitializeShadowMemory() { 42353944Sdim kHighMemEnd = 0; 43353944Sdim kMidMemBeg = 0; 44353944Sdim kMidMemEnd = 0; 45353944Sdim 46353944Sdim ResetShadowMemory(); 47353944Sdim} 48353944Sdim 49353944Sdimvoid AsanApplyToGlobals(globals_op_fptr op, const void *needle) { 50353944Sdim UNIMPLEMENTED(); 51353944Sdim} 52353944Sdim 53353944Sdimvoid AsanCheckDynamicRTPrereqs() {} 54353944Sdimvoid AsanCheckIncompatibleRT() {} 55353944Sdimvoid InitializeAsanInterceptors() {} 56353944Sdimvoid InitializePlatformInterceptors() {} 57353944Sdimvoid InitializePlatformExceptionHandlers() {} 58353944Sdim 59353944Sdim// RTEMS only support static linking; it sufficies to return with no 60353944Sdim// error. 61353944Sdimvoid *AsanDoesNotSupportStaticLinkage() { return nullptr; } 62353944Sdim 63353944Sdimvoid AsanOnDeadlySignal(int signo, void *siginfo, void *context) { 64353944Sdim UNIMPLEMENTED(); 65353944Sdim} 66353944Sdim 67353944Sdimvoid EarlyInit() { 68353944Sdim // Provide early initialization of shadow memory so that 69353944Sdim // instrumented code running before full initialzation will not 70353944Sdim // report spurious errors. 71353944Sdim ResetShadowMemory(); 72353944Sdim} 73353944Sdim 74353944Sdim// We can use a plain thread_local variable for TSD. 75353944Sdimstatic thread_local void *per_thread; 76353944Sdim 77353944Sdimvoid *AsanTSDGet() { return per_thread; } 78353944Sdim 79353944Sdimvoid AsanTSDSet(void *tsd) { per_thread = tsd; } 80353944Sdim 81353944Sdim// There's no initialization needed, and the passed-in destructor 82353944Sdim// will never be called. Instead, our own thread destruction hook 83353944Sdim// (below) will call AsanThread::TSDDtor directly. 84353944Sdimvoid AsanTSDInit(void (*destructor)(void *tsd)) { 85353944Sdim DCHECK(destructor == &PlatformTSDDtor); 86353944Sdim} 87353944Sdim 88353944Sdimvoid PlatformTSDDtor(void *tsd) { UNREACHABLE(__func__); } 89353944Sdim 90353944Sdim// 91353944Sdim// Thread registration. We provide an API similar to the Fushia port. 92353944Sdim// 93353944Sdim 94353944Sdimstruct AsanThread::InitOptions { 95353944Sdim uptr stack_bottom, stack_size, tls_bottom, tls_size; 96353944Sdim}; 97353944Sdim 98353944Sdim// Shared setup between thread creation and startup for the initial thread. 99353944Sdimstatic AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid, 100353944Sdim uptr user_id, bool detached, 101353944Sdim uptr stack_bottom, uptr stack_size, 102353944Sdim uptr tls_bottom, uptr tls_size) { 103353944Sdim // In lieu of AsanThread::Create. 104353944Sdim AsanThread *thread = (AsanThread *)MmapOrDie(sizeof(AsanThread), __func__); 105353944Sdim AsanThreadContext::CreateThreadContextArgs args = {thread, stack}; 106353944Sdim asanThreadRegistry().CreateThread(user_id, detached, parent_tid, &args); 107353944Sdim 108353944Sdim // On other systems, AsanThread::Init() is called from the new 109353944Sdim // thread itself. But on RTEMS we already know the stack address 110353944Sdim // range beforehand, so we can do most of the setup right now. 111353944Sdim const AsanThread::InitOptions options = {stack_bottom, stack_size, 112353944Sdim tls_bottom, tls_size}; 113353944Sdim thread->Init(&options); 114353944Sdim return thread; 115353944Sdim} 116353944Sdim 117353944Sdim// This gets the same arguments passed to Init by CreateAsanThread, above. 118353944Sdim// We're in the creator thread before the new thread is actually started, but 119353944Sdim// its stack and tls address range are already known. 120353944Sdimvoid AsanThread::SetThreadStackAndTls(const AsanThread::InitOptions *options) { 121353944Sdim DCHECK_NE(GetCurrentThread(), this); 122353944Sdim DCHECK_NE(GetCurrentThread(), nullptr); 123353944Sdim CHECK_NE(options->stack_bottom, 0); 124353944Sdim CHECK_NE(options->stack_size, 0); 125353944Sdim stack_bottom_ = options->stack_bottom; 126353944Sdim stack_top_ = options->stack_bottom + options->stack_size; 127353944Sdim tls_begin_ = options->tls_bottom; 128353944Sdim tls_end_ = options->tls_bottom + options->tls_size; 129353944Sdim} 130353944Sdim 131353944Sdim// Called by __asan::AsanInitInternal (asan_rtl.c). Unlike other ports, the 132353944Sdim// main thread on RTEMS does not require special treatment; its AsanThread is 133353944Sdim// already created by the provided hooks. This function simply looks up and 134353944Sdim// returns the created thread. 135353944SdimAsanThread *CreateMainThread() { 136353944Sdim return GetThreadContextByTidLocked(0)->thread; 137353944Sdim} 138353944Sdim 139353944Sdim// This is called before each thread creation is attempted. So, in 140353944Sdim// its first call, the calling thread is the initial and sole thread. 141353944Sdimstatic void *BeforeThreadCreateHook(uptr user_id, bool detached, 142353944Sdim uptr stack_bottom, uptr stack_size, 143353944Sdim uptr tls_bottom, uptr tls_size) { 144353944Sdim EnsureMainThreadIDIsCorrect(); 145353944Sdim // Strict init-order checking is thread-hostile. 146353944Sdim if (flags()->strict_init_order) StopInitOrderChecking(); 147353944Sdim 148353944Sdim GET_STACK_TRACE_THREAD; 149353944Sdim u32 parent_tid = GetCurrentTidOrInvalid(); 150353944Sdim 151353944Sdim return CreateAsanThread(&stack, parent_tid, user_id, detached, 152353944Sdim stack_bottom, stack_size, tls_bottom, tls_size); 153353944Sdim} 154353944Sdim 155353944Sdim// This is called after creating a new thread (in the creating thread), 156353944Sdim// with the pointer returned by BeforeThreadCreateHook (above). 157353944Sdimstatic void ThreadCreateHook(void *hook, bool aborted) { 158353944Sdim AsanThread *thread = static_cast<AsanThread *>(hook); 159353944Sdim if (!aborted) { 160353944Sdim // The thread was created successfully. 161353944Sdim // ThreadStartHook is already running in the new thread. 162353944Sdim } else { 163353944Sdim // The thread wasn't created after all. 164353944Sdim // Clean up everything we set up in BeforeThreadCreateHook. 165353944Sdim asanThreadRegistry().FinishThread(thread->tid()); 166353944Sdim UnmapOrDie(thread, sizeof(AsanThread)); 167353944Sdim } 168353944Sdim} 169353944Sdim 170353944Sdim// This is called (1) in the newly-created thread before it runs anything else, 171353944Sdim// with the pointer returned by BeforeThreadCreateHook (above). (2) before a 172353944Sdim// thread restart. 173353944Sdimstatic void ThreadStartHook(void *hook, uptr os_id) { 174353944Sdim if (!hook) 175353944Sdim return; 176353944Sdim 177353944Sdim AsanThread *thread = static_cast<AsanThread *>(hook); 178353944Sdim SetCurrentThread(thread); 179353944Sdim 180353944Sdim ThreadStatus status = 181353944Sdim asanThreadRegistry().GetThreadLocked(thread->tid())->status; 182353944Sdim DCHECK(status == ThreadStatusCreated || status == ThreadStatusRunning); 183353944Sdim // Determine whether we are starting or restarting the thread. 184353944Sdim if (status == ThreadStatusCreated) { 185353944Sdim // In lieu of AsanThread::ThreadStart. 186353944Sdim asanThreadRegistry().StartThread(thread->tid(), os_id, ThreadType::Regular, 187353944Sdim nullptr); 188353944Sdim } else { 189353944Sdim // In a thread restart, a thread may resume execution at an 190353944Sdim // arbitrary function entry point, with its stack and TLS state 191353944Sdim // reset. We unpoison the stack in that case. 192353944Sdim PoisonShadow(thread->stack_bottom(), thread->stack_size(), 0); 193353944Sdim } 194353944Sdim} 195353944Sdim 196353944Sdim// Each thread runs this just before it exits, 197353944Sdim// with the pointer returned by BeforeThreadCreateHook (above). 198353944Sdim// All per-thread destructors have already been called. 199353944Sdimstatic void ThreadExitHook(void *hook, uptr os_id) { 200353944Sdim AsanThread *thread = static_cast<AsanThread *>(hook); 201353944Sdim if (thread) 202353944Sdim AsanThread::TSDDtor(thread->context()); 203353944Sdim} 204353944Sdim 205353944Sdimstatic void HandleExit() { 206353944Sdim // Disable ASan by setting it to uninitialized. Also reset the 207353944Sdim // shadow memory to avoid reporting errors after the run-time has 208353944Sdim // been desroyed. 209353944Sdim if (asan_inited) { 210353944Sdim asan_inited = false; 211353944Sdim ResetShadowMemory(); 212353944Sdim } 213353944Sdim} 214353944Sdim 215353944Sdimbool HandleDlopenInit() { 216353944Sdim // Not supported on this platform. 217353944Sdim static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN, 218353944Sdim "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false"); 219353944Sdim return false; 220353944Sdim} 221353944Sdim} // namespace __asan 222353944Sdim 223353944Sdim// These are declared (in extern "C") by <some_path/sanitizer.h>. 224353944Sdim// The system runtime will call our definitions directly. 225353944Sdim 226353944Sdimextern "C" { 227353944Sdimvoid __sanitizer_early_init() { 228353944Sdim __asan::EarlyInit(); 229353944Sdim} 230353944Sdim 231353944Sdimvoid *__sanitizer_before_thread_create_hook(uptr thread, bool detached, 232353944Sdim const char *name, 233353944Sdim void *stack_base, size_t stack_size, 234353944Sdim void *tls_base, size_t tls_size) { 235353944Sdim return __asan::BeforeThreadCreateHook( 236353944Sdim thread, detached, 237353944Sdim reinterpret_cast<uptr>(stack_base), stack_size, 238353944Sdim reinterpret_cast<uptr>(tls_base), tls_size); 239353944Sdim} 240353944Sdim 241353944Sdimvoid __sanitizer_thread_create_hook(void *handle, uptr thread, int status) { 242353944Sdim __asan::ThreadCreateHook(handle, status != 0); 243353944Sdim} 244353944Sdim 245353944Sdimvoid __sanitizer_thread_start_hook(void *handle, uptr self) { 246353944Sdim __asan::ThreadStartHook(handle, self); 247353944Sdim} 248353944Sdim 249353944Sdimvoid __sanitizer_thread_exit_hook(void *handle, uptr self) { 250353944Sdim __asan::ThreadExitHook(handle, self); 251353944Sdim} 252353944Sdim 253353944Sdimvoid __sanitizer_exit() { 254353944Sdim __asan::HandleExit(); 255353944Sdim} 256353944Sdim} // "C" 257353944Sdim 258353944Sdim#endif // SANITIZER_RTEMS 259