| //===-- hwasan.h ------------------------------------------------*- C++ -*-===// | 
 | // | 
 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
 | // See https://llvm.org/LICENSE.txt for license information. | 
 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 | // | 
 | // This file is a part of HWAddressSanitizer. | 
 | // | 
 | // Private Hwasan header. | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #ifndef HWASAN_H | 
 | #define HWASAN_H | 
 |  | 
 | #include "hwasan_flags.h" | 
 | #include "hwasan_interface_internal.h" | 
 | #include "sanitizer_common/sanitizer_common.h" | 
 | #include "sanitizer_common/sanitizer_flags.h" | 
 | #include "sanitizer_common/sanitizer_internal_defs.h" | 
 | #include "sanitizer_common/sanitizer_stacktrace.h" | 
 | #include "ubsan/ubsan_platform.h" | 
 |  | 
 | #ifndef HWASAN_CONTAINS_UBSAN | 
 | # define HWASAN_CONTAINS_UBSAN CAN_SANITIZE_UB | 
 | #endif | 
 |  | 
 | #ifndef HWASAN_WITH_INTERCEPTORS | 
 | #define HWASAN_WITH_INTERCEPTORS 0 | 
 | #endif | 
 |  | 
 | #ifndef HWASAN_REPLACE_OPERATORS_NEW_AND_DELETE | 
 | #define HWASAN_REPLACE_OPERATORS_NEW_AND_DELETE HWASAN_WITH_INTERCEPTORS | 
 | #endif | 
 |  | 
 | typedef u8 tag_t; | 
 |  | 
 | #if defined(HWASAN_ALIASING_MODE) | 
 | #  if !defined(__x86_64__) | 
 | #    error Aliasing mode is only supported on x86_64 | 
 | #  endif | 
 | // Tags are done in middle bits using userspace aliasing. | 
 | constexpr unsigned kAddressTagShift = 39; | 
 | constexpr unsigned kTagBits = 3; | 
 |  | 
 | // The alias region is placed next to the shadow so the upper bits of all | 
 | // taggable addresses matches the upper bits of the shadow base.  This shift | 
 | // value determines which upper bits must match.  It has a floor of 44 since the | 
 | // shadow is always 8TB. | 
 | // TODO(morehouse): In alias mode we can shrink the shadow and use a | 
 | // simpler/faster shadow calculation. | 
 | constexpr unsigned kTaggableRegionCheckShift = | 
 |     __sanitizer::Max(kAddressTagShift + kTagBits + 1U, 44U); | 
 | #elif defined(__x86_64__) | 
 | // Tags are done in upper bits using Intel LAM. | 
 | constexpr unsigned kAddressTagShift = 57; | 
 | constexpr unsigned kTagBits = 6; | 
 | #else | 
 | // TBI (Top Byte Ignore) feature of AArch64: bits [63:56] are ignored in address | 
 | // translation and can be used to store a tag. | 
 | constexpr unsigned kAddressTagShift = 56; | 
 | constexpr unsigned kTagBits = 8; | 
 | #endif  // defined(HWASAN_ALIASING_MODE) | 
 |  | 
 | // Mask for extracting tag bits from the lower 8 bits. | 
 | constexpr uptr kTagMask = (1UL << kTagBits) - 1; | 
 |  | 
 | // Mask for extracting tag bits from full pointers. | 
 | constexpr uptr kAddressTagMask = kTagMask << kAddressTagShift; | 
 |  | 
 | // Minimal alignment of the shadow base address. Determines the space available | 
 | // for threads and stack histories. This is an ABI constant. | 
 | const unsigned kShadowBaseAlignment = 32; | 
 |  | 
 | const unsigned kRecordAddrBaseTagShift = 3; | 
 | const unsigned kRecordFPShift = 48; | 
 | const unsigned kRecordFPLShift = 4; | 
 | const unsigned kRecordFPModulus = 1 << (64 - kRecordFPShift + kRecordFPLShift); | 
 |  | 
 | static inline tag_t GetTagFromPointer(uptr p) { | 
 |   return (p >> kAddressTagShift) & kTagMask; | 
 | } | 
 |  | 
 | static inline uptr UntagAddr(uptr tagged_addr) { | 
 |   return tagged_addr & ~kAddressTagMask; | 
 | } | 
 |  | 
 | static inline void *UntagPtr(const void *tagged_ptr) { | 
 |   return reinterpret_cast<void *>( | 
 |       UntagAddr(reinterpret_cast<uptr>(tagged_ptr))); | 
 | } | 
 |  | 
 | static inline uptr AddTagToPointer(uptr p, tag_t tag) { | 
 |   return (p & ~kAddressTagMask) | ((uptr)tag << kAddressTagShift); | 
 | } | 
 |  | 
 | namespace __hwasan { | 
 |  | 
 | extern int hwasan_inited; | 
 | extern bool hwasan_init_is_running; | 
 | extern int hwasan_report_count; | 
 |  | 
 | bool InitShadow(); | 
 | void InitializeOsSupport(); | 
 | void InitThreads(); | 
 | void InitializeInterceptors(); | 
 |  | 
 | void HwasanAllocatorInit(); | 
 | void HwasanAllocatorLock(); | 
 | void HwasanAllocatorUnlock(); | 
 |  | 
 | void *hwasan_malloc(uptr size, StackTrace *stack); | 
 | void *hwasan_calloc(uptr nmemb, uptr size, StackTrace *stack); | 
 | void *hwasan_realloc(void *ptr, uptr size, StackTrace *stack); | 
 | void *hwasan_reallocarray(void *ptr, uptr nmemb, uptr size, StackTrace *stack); | 
 | void *hwasan_valloc(uptr size, StackTrace *stack); | 
 | void *hwasan_pvalloc(uptr size, StackTrace *stack); | 
 | void *hwasan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack); | 
 | void *hwasan_memalign(uptr alignment, uptr size, StackTrace *stack); | 
 | int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size, | 
 |                         StackTrace *stack); | 
 | void hwasan_free(void *ptr, StackTrace *stack); | 
 |  | 
 | void InstallAtExitHandler(); | 
 |  | 
 | #define GET_MALLOC_STACK_TRACE                                            \ | 
 |   BufferedStackTrace stack;                                               \ | 
 |   if (hwasan_inited)                                                      \ | 
 |     stack.Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(),         \ | 
 |                  nullptr, common_flags()->fast_unwind_on_malloc,          \ | 
 |                  common_flags()->malloc_context_size) | 
 |  | 
 | #define GET_FATAL_STACK_TRACE_PC_BP(pc, bp)              \ | 
 |   BufferedStackTrace stack;                              \ | 
 |   if (hwasan_inited)                                     \ | 
 |     stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_fatal) | 
 |  | 
 | void HwasanTSDInit(); | 
 | void HwasanTSDThreadInit(); | 
 | void HwasanAtExit(); | 
 |  | 
 | void HwasanOnDeadlySignal(int signo, void *info, void *context); | 
 |  | 
 | void HwasanInstallAtForkHandler(); | 
 |  | 
 | void UpdateMemoryUsage(); | 
 |  | 
 | void AppendToErrorMessageBuffer(const char *buffer); | 
 |  | 
 | void AndroidTestTlsSlot(); | 
 |  | 
 | // This is a compiler-generated struct that can be shared between hwasan | 
 | // implementations. | 
 | struct AccessInfo { | 
 |   uptr addr; | 
 |   uptr size; | 
 |   bool is_store; | 
 |   bool is_load; | 
 |   bool recover; | 
 | }; | 
 |  | 
 | // Given access info and frame information, unwind the stack and report the tag | 
 | // mismatch. | 
 | void HandleTagMismatch(AccessInfo ai, uptr pc, uptr frame, void *uc, | 
 |                        uptr *registers_frame = nullptr); | 
 |  | 
 | // This dispatches to HandleTagMismatch but sets up the AccessInfo, program | 
 | // counter, and frame pointer. | 
 | void HwasanTagMismatch(uptr addr, uptr pc, uptr frame, uptr access_info, | 
 |                        uptr *registers_frame, size_t outsize); | 
 |  | 
 | }  // namespace __hwasan | 
 |  | 
 | #if HWASAN_WITH_INTERCEPTORS | 
 | // For both bionic and glibc __sigset_t is an unsigned long. | 
 | typedef unsigned long __hw_sigset_t; | 
 | // Setjmp and longjmp implementations are platform specific, and hence the | 
 | // interception code is platform specific too. | 
 | #  if defined(__aarch64__) | 
 | constexpr size_t kHwRegisterBufSize = 22; | 
 | #  elif defined(__x86_64__) | 
 | constexpr size_t kHwRegisterBufSize = 8; | 
 | #  elif SANITIZER_RISCV64 | 
 | // saving PC, 12 int regs, sp, 12 fp regs | 
 | #    ifndef __riscv_float_abi_soft | 
 | constexpr size_t kHwRegisterBufSize = 1 + 12 + 1 + 12; | 
 | #    else | 
 | constexpr size_t kHwRegisterBufSize = 1 + 12 + 1; | 
 | #    endif | 
 | #  endif | 
 | typedef unsigned long long __hw_register_buf[kHwRegisterBufSize]; | 
 | struct __hw_jmp_buf_struct { | 
 |   // NOTE: The machine-dependent definition of `__sigsetjmp' | 
 |   // assume that a `__hw_jmp_buf' begins with a `__hw_register_buf' and that | 
 |   // `__mask_was_saved' follows it.  Do not move these members or add others | 
 |   // before it. | 
 |   // | 
 |   // We add a __magic field to our struct to catch cases where libc's setjmp | 
 |   // populated the jmp_buf instead of our interceptor. | 
 |   __hw_register_buf __jmpbuf; // Calling environment. | 
 |   unsigned __mask_was_saved : 1;  // Saved the signal mask? | 
 |   unsigned __magic : 31;      // Used to distinguish __hw_jmp_buf from jmp_buf. | 
 |   __hw_sigset_t __saved_mask; // Saved signal mask. | 
 | }; | 
 | typedef struct __hw_jmp_buf_struct __hw_jmp_buf[1]; | 
 | typedef struct __hw_jmp_buf_struct __hw_sigjmp_buf[1]; | 
 | constexpr unsigned kHwJmpBufMagic = 0x248ACE77; | 
 | #endif  // HWASAN_WITH_INTERCEPTORS | 
 |  | 
 | #define ENSURE_HWASAN_INITED()      \ | 
 |   do {                              \ | 
 |     CHECK(!hwasan_init_is_running); \ | 
 |     if (!hwasan_inited) {           \ | 
 |       __hwasan_init();              \ | 
 |     }                               \ | 
 |   } while (0) | 
 |  | 
 | #endif  // HWASAN_H |