(root)/
gcc-13.2.0/
libsanitizer/
sanitizer_common/
sanitizer_tls_get_addr.h
       1  //===-- sanitizer_tls_get_addr.h --------------------------------*- C++ -*-===//
       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  // Handle the __tls_get_addr call.
      10  //
      11  // All this magic is specific to glibc and is required to workaround
      12  // the lack of interface that would tell us about the Dynamic TLS (DTLS).
      13  // https://sourceware.org/bugzilla/show_bug.cgi?id=16291
      14  //
      15  // The matters get worse because the glibc implementation changed between
      16  // 2.18 and 2.19:
      17  // https://groups.google.com/forum/#!topic/address-sanitizer/BfwYD8HMxTM
      18  //
      19  // Before 2.19, every DTLS chunk is allocated with __libc_memalign,
      20  // which we intercept and thus know where is the DTLS.
      21  // Since 2.19, DTLS chunks are allocated with __signal_safe_memalign,
      22  // which is an internal function that wraps a mmap call, neither of which
      23  // we can intercept. Luckily, __signal_safe_memalign has a simple parseable
      24  // header which we can use.
      25  //
      26  //===----------------------------------------------------------------------===//
      27  
      28  #ifndef SANITIZER_TLS_GET_ADDR_H
      29  #define SANITIZER_TLS_GET_ADDR_H
      30  
      31  #include "sanitizer_atomic.h"
      32  #include "sanitizer_common.h"
      33  
      34  namespace __sanitizer {
      35  
      36  struct DTLS {
      37    // Array of DTLS chunks for the current Thread.
      38    // If beg == 0, the chunk is unused.
      39    struct DTV {
      40      uptr beg, size;
      41    };
      42    struct DTVBlock {
      43      atomic_uintptr_t next;
      44      DTV dtvs[(4096UL - sizeof(next)) / sizeof(DTLS::DTV)];
      45    };
      46  
      47    static_assert(sizeof(DTVBlock) <= 4096UL, "Unexpected block size");
      48  
      49    atomic_uintptr_t dtv_block;
      50  
      51    // Auxiliary fields, don't access them outside sanitizer_tls_get_addr.cpp
      52    uptr last_memalign_size;
      53    uptr last_memalign_ptr;
      54  };
      55  
      56  template <typename Fn>
      57  void ForEachDVT(DTLS *dtls, const Fn &fn) {
      58    DTLS::DTVBlock *block =
      59        (DTLS::DTVBlock *)atomic_load(&dtls->dtv_block, memory_order_acquire);
      60    while (block) {
      61      int id = 0;
      62      for (auto &d : block->dtvs) fn(d, id++);
      63      block = (DTLS::DTVBlock *)atomic_load(&block->next, memory_order_acquire);
      64    }
      65  }
      66  
      67  // Returns pointer and size of a linker-allocated TLS block.
      68  // Each block is returned exactly once.
      69  DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res, uptr static_tls_begin,
      70                                  uptr static_tls_end);
      71  void DTLS_on_libc_memalign(void *ptr, uptr size);
      72  DTLS *DTLS_Get();
      73  void DTLS_Destroy();  // Make sure to call this before the thread is destroyed.
      74  // Returns true if DTLS of suspended thread is in destruction process.
      75  bool DTLSInDestruction(DTLS *dtls);
      76  
      77  }  // namespace __sanitizer
      78  
      79  #endif  // SANITIZER_TLS_GET_ADDR_H