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