168d75effSDimitry Andric //===-- sanitizer_linux_libcdep.cpp ---------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is shared between AddressSanitizer and ThreadSanitizer
1068d75effSDimitry Andric // run-time libraries and implements linux-specific functions from
1168d75effSDimitry Andric // sanitizer_libc.h.
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric 
1468d75effSDimitry Andric #include "sanitizer_platform.h"
1568d75effSDimitry Andric 
1668d75effSDimitry Andric #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
17e8d8bef9SDimitry Andric     SANITIZER_SOLARIS
1868d75effSDimitry Andric 
1968d75effSDimitry Andric #  include "sanitizer_allocator_internal.h"
2068d75effSDimitry Andric #  include "sanitizer_atomic.h"
2168d75effSDimitry Andric #  include "sanitizer_common.h"
2268d75effSDimitry Andric #  include "sanitizer_file.h"
2368d75effSDimitry Andric #  include "sanitizer_flags.h"
2468d75effSDimitry Andric #  include "sanitizer_getauxval.h"
2568d75effSDimitry Andric #  include "sanitizer_glibc_version.h"
2668d75effSDimitry Andric #  include "sanitizer_linux.h"
2768d75effSDimitry Andric #  include "sanitizer_placement_new.h"
2868d75effSDimitry Andric #  include "sanitizer_procmaps.h"
29fcaf7f86SDimitry Andric #  include "sanitizer_solaris.h"
3068d75effSDimitry Andric 
31e8d8bef9SDimitry Andric #  if SANITIZER_NETBSD
32e8d8bef9SDimitry Andric #    define _RTLD_SOURCE  // for __lwp_gettcb_fast() / __lwp_getprivate_fast()
33e8d8bef9SDimitry Andric #  endif
34e8d8bef9SDimitry Andric 
3568d75effSDimitry Andric #  include <dlfcn.h>  // for dlsym()
3668d75effSDimitry Andric #  include <link.h>
3768d75effSDimitry Andric #  include <pthread.h>
3868d75effSDimitry Andric #  include <signal.h>
39fe6060f1SDimitry Andric #  include <sys/mman.h>
4068d75effSDimitry Andric #  include <sys/resource.h>
4168d75effSDimitry Andric #  include <syslog.h>
4268d75effSDimitry Andric 
435ffd83dbSDimitry Andric #  if !defined(ElfW)
445ffd83dbSDimitry Andric #    define ElfW(type) Elf_##type
455ffd83dbSDimitry Andric #  endif
465ffd83dbSDimitry Andric 
4768d75effSDimitry Andric #  if SANITIZER_FREEBSD
485f757f3fSDimitry Andric #    include <pthread_np.h>
4996fe7c8aSEd Maste #    include <sys/auxv.h>
5068d75effSDimitry Andric #    include <sys/sysctl.h>
5168d75effSDimitry Andric #    define pthread_getattr_np pthread_attr_get_np
52fe6060f1SDimitry Andric // The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before
53fe6060f1SDimitry Andric // that, it was never implemented. So just define it to zero.
54fe6060f1SDimitry Andric #    undef MAP_NORESERVE
55fe6060f1SDimitry Andric #    define MAP_NORESERVE 0
568b181c2fSDimitry Andric extern const Elf_Auxinfo *__elf_aux_vector __attribute__ ((weak));
5768d75effSDimitry Andric #  endif
5868d75effSDimitry Andric 
5968d75effSDimitry Andric #  if SANITIZER_NETBSD
605f757f3fSDimitry Andric #    include <lwp.h>
6168d75effSDimitry Andric #    include <sys/sysctl.h>
6268d75effSDimitry Andric #    include <sys/tls.h>
6368d75effSDimitry Andric #  endif
6468d75effSDimitry Andric 
6568d75effSDimitry Andric #  if SANITIZER_SOLARIS
66fcaf7f86SDimitry Andric #    include <stddef.h>
6768d75effSDimitry Andric #    include <stdlib.h>
6868d75effSDimitry Andric #    include <thread.h>
6968d75effSDimitry Andric #  endif
7068d75effSDimitry Andric 
7168d75effSDimitry Andric #  if SANITIZER_ANDROID
7268d75effSDimitry Andric #    include <android/api-level.h>
7368d75effSDimitry Andric #    if !defined(CPU_COUNT) && !defined(__aarch64__)
7468d75effSDimitry Andric #      include <dirent.h>
7568d75effSDimitry Andric #      include <fcntl.h>
7668d75effSDimitry Andric struct __sanitizer::linux_dirent {
7768d75effSDimitry Andric   long d_ino;
7868d75effSDimitry Andric   off_t d_off;
7968d75effSDimitry Andric   unsigned short d_reclen;
8068d75effSDimitry Andric   char d_name[];
8168d75effSDimitry Andric };
8268d75effSDimitry Andric #    endif
8368d75effSDimitry Andric #  endif
8468d75effSDimitry Andric 
8568d75effSDimitry Andric #  if !SANITIZER_ANDROID
8668d75effSDimitry Andric #    include <elf.h>
8768d75effSDimitry Andric #    include <unistd.h>
8868d75effSDimitry Andric #  endif
8968d75effSDimitry Andric 
9068d75effSDimitry Andric namespace __sanitizer {
9168d75effSDimitry Andric 
925f757f3fSDimitry Andric SANITIZER_WEAK_ATTRIBUTE int real_sigaction(int signum, const void *act,
935f757f3fSDimitry Andric                                             void *oldact);
9468d75effSDimitry Andric 
internal_sigaction(int signum,const void * act,void * oldact)9568d75effSDimitry Andric int internal_sigaction(int signum, const void *act, void *oldact) {
9668d75effSDimitry Andric #  if !SANITIZER_GO
9768d75effSDimitry Andric   if (&real_sigaction)
9868d75effSDimitry Andric     return real_sigaction(signum, act, oldact);
9968d75effSDimitry Andric #  endif
10068d75effSDimitry Andric   return sigaction(signum, (const struct sigaction *)act,
10168d75effSDimitry Andric                    (struct sigaction *)oldact);
10268d75effSDimitry Andric }
10368d75effSDimitry Andric 
GetThreadStackTopAndBottom(bool at_initialization,uptr * stack_top,uptr * stack_bottom)10468d75effSDimitry Andric void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
10568d75effSDimitry Andric                                 uptr *stack_bottom) {
10668d75effSDimitry Andric   CHECK(stack_top);
10768d75effSDimitry Andric   CHECK(stack_bottom);
10868d75effSDimitry Andric   if (at_initialization) {
10968d75effSDimitry Andric     // This is the main thread. Libpthread may not be initialized yet.
11068d75effSDimitry Andric     struct rlimit rl;
11168d75effSDimitry Andric     CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
11268d75effSDimitry Andric 
11368d75effSDimitry Andric     // Find the mapping that contains a stack variable.
11468d75effSDimitry Andric     MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
11568d75effSDimitry Andric     if (proc_maps.Error()) {
11668d75effSDimitry Andric       *stack_top = *stack_bottom = 0;
11768d75effSDimitry Andric       return;
11868d75effSDimitry Andric     }
11968d75effSDimitry Andric     MemoryMappedSegment segment;
12068d75effSDimitry Andric     uptr prev_end = 0;
12168d75effSDimitry Andric     while (proc_maps.Next(&segment)) {
1225f757f3fSDimitry Andric       if ((uptr)&rl < segment.end)
1235f757f3fSDimitry Andric         break;
12468d75effSDimitry Andric       prev_end = segment.end;
12568d75effSDimitry Andric     }
12668d75effSDimitry Andric     CHECK((uptr)&rl >= segment.start && (uptr)&rl < segment.end);
12768d75effSDimitry Andric 
12868d75effSDimitry Andric     // Get stacksize from rlimit, but clip it so that it does not overlap
12968d75effSDimitry Andric     // with other mappings.
13068d75effSDimitry Andric     uptr stacksize = rl.rlim_cur;
1315f757f3fSDimitry Andric     if (stacksize > segment.end - prev_end)
1325f757f3fSDimitry Andric       stacksize = segment.end - prev_end;
13368d75effSDimitry Andric     // When running with unlimited stack size, we still want to set some limit.
13468d75effSDimitry Andric     // The unlimited stack size is caused by 'ulimit -s unlimited'.
13568d75effSDimitry Andric     // Also, for some reason, GNU make spawns subprocesses with unlimited stack.
13668d75effSDimitry Andric     if (stacksize > kMaxThreadStackSize)
13768d75effSDimitry Andric       stacksize = kMaxThreadStackSize;
13868d75effSDimitry Andric     *stack_top = segment.end;
13968d75effSDimitry Andric     *stack_bottom = segment.end - stacksize;
14068d75effSDimitry Andric     return;
14168d75effSDimitry Andric   }
14268d75effSDimitry Andric   uptr stacksize = 0;
14368d75effSDimitry Andric   void *stackaddr = nullptr;
14468d75effSDimitry Andric #  if SANITIZER_SOLARIS
14568d75effSDimitry Andric   stack_t ss;
14668d75effSDimitry Andric   CHECK_EQ(thr_stksegment(&ss), 0);
14768d75effSDimitry Andric   stacksize = ss.ss_size;
14868d75effSDimitry Andric   stackaddr = (char *)ss.ss_sp - stacksize;
14968d75effSDimitry Andric #  else   // !SANITIZER_SOLARIS
15068d75effSDimitry Andric   pthread_attr_t attr;
15168d75effSDimitry Andric   pthread_attr_init(&attr);
15268d75effSDimitry Andric   CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
15306c3fb27SDimitry Andric   internal_pthread_attr_getstack(&attr, &stackaddr, &stacksize);
15468d75effSDimitry Andric   pthread_attr_destroy(&attr);
15568d75effSDimitry Andric #  endif  // SANITIZER_SOLARIS
15668d75effSDimitry Andric 
15768d75effSDimitry Andric   *stack_top = (uptr)stackaddr + stacksize;
15868d75effSDimitry Andric   *stack_bottom = (uptr)stackaddr;
15968d75effSDimitry Andric }
16068d75effSDimitry Andric 
16168d75effSDimitry Andric #  if !SANITIZER_GO
SetEnv(const char * name,const char * value)16268d75effSDimitry Andric bool SetEnv(const char *name, const char *value) {
16368d75effSDimitry Andric   void *f = dlsym(RTLD_NEXT, "setenv");
16468d75effSDimitry Andric   if (!f)
16568d75effSDimitry Andric     return false;
16668d75effSDimitry Andric   typedef int (*setenv_ft)(const char *name, const char *value, int overwrite);
16768d75effSDimitry Andric   setenv_ft setenv_f;
16868d75effSDimitry Andric   CHECK_EQ(sizeof(setenv_f), sizeof(f));
16968d75effSDimitry Andric   internal_memcpy(&setenv_f, &f, sizeof(f));
17068d75effSDimitry Andric   return setenv_f(name, value, 1) == 0;
17168d75effSDimitry Andric }
17268d75effSDimitry Andric #  endif
17368d75effSDimitry Andric 
GetLibcVersion(int * major,int * minor,int * patch)17468d75effSDimitry Andric __attribute__((unused)) static bool GetLibcVersion(int *major, int *minor,
17568d75effSDimitry Andric                                                    int *patch) {
17668d75effSDimitry Andric #  ifdef _CS_GNU_LIBC_VERSION
17768d75effSDimitry Andric   char buf[64];
17868d75effSDimitry Andric   uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf));
17968d75effSDimitry Andric   if (len >= sizeof(buf))
18068d75effSDimitry Andric     return false;
18168d75effSDimitry Andric   buf[len] = 0;
18268d75effSDimitry Andric   static const char kGLibC[] = "glibc ";
18368d75effSDimitry Andric   if (internal_strncmp(buf, kGLibC, sizeof(kGLibC) - 1) != 0)
18468d75effSDimitry Andric     return false;
18568d75effSDimitry Andric   const char *p = buf + sizeof(kGLibC) - 1;
18668d75effSDimitry Andric   *major = internal_simple_strtoll(p, &p, 10);
18768d75effSDimitry Andric   *minor = (*p == '.') ? internal_simple_strtoll(p + 1, &p, 10) : 0;
18868d75effSDimitry Andric   *patch = (*p == '.') ? internal_simple_strtoll(p + 1, &p, 10) : 0;
18968d75effSDimitry Andric   return true;
19068d75effSDimitry Andric #  else
19168d75effSDimitry Andric   return false;
19268d75effSDimitry Andric #  endif
19368d75effSDimitry Andric }
19468d75effSDimitry Andric 
195fe6060f1SDimitry Andric // True if we can use dlpi_tls_data. glibc before 2.25 may leave NULL (BZ
196fe6060f1SDimitry Andric // #19826) so dlpi_tls_data cannot be used.
197fe6060f1SDimitry Andric //
198fe6060f1SDimitry Andric // musl before 1.2.3 and FreeBSD as of 12.2 incorrectly set dlpi_tls_data to
199fe6060f1SDimitry Andric // the TLS initialization image
200fe6060f1SDimitry Andric // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=254774
201fe6060f1SDimitry Andric __attribute__((unused)) static int g_use_dlpi_tls_data;
202fe6060f1SDimitry Andric 
203e8d8bef9SDimitry Andric #  if SANITIZER_GLIBC && !SANITIZER_GO
204fe6060f1SDimitry Andric __attribute__((unused)) static size_t g_tls_size;
InitTlsSize()20568d75effSDimitry Andric void InitTlsSize() {
206fe6060f1SDimitry Andric   int major, minor, patch;
207fe6060f1SDimitry Andric   g_use_dlpi_tls_data =
208fe6060f1SDimitry Andric       GetLibcVersion(&major, &minor, &patch) && major == 2 && minor >= 25;
209fe6060f1SDimitry Andric 
2105f757f3fSDimitry Andric #    if defined(__aarch64__) || defined(__x86_64__) || \
2115f757f3fSDimitry Andric         defined(__powerpc64__) || defined(__loongarch__)
212fe6060f1SDimitry Andric   void *get_tls_static_info = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
213fe6060f1SDimitry Andric   size_t tls_align;
214fe6060f1SDimitry Andric   ((void (*)(size_t *, size_t *))get_tls_static_info)(&g_tls_size, &tls_align);
215fe6060f1SDimitry Andric #    endif
21668d75effSDimitry Andric }
21768d75effSDimitry Andric #  else
InitTlsSize()21868d75effSDimitry Andric void InitTlsSize() {}
219e8d8bef9SDimitry Andric #  endif  // SANITIZER_GLIBC && !SANITIZER_GO
22068d75effSDimitry Andric 
221fe6060f1SDimitry Andric // On glibc x86_64, ThreadDescriptorSize() needs to be precise due to the usage
222fe6060f1SDimitry Andric // of g_tls_size. On other targets, ThreadDescriptorSize() is only used by lsan
223fe6060f1SDimitry Andric // to get the pointer to thread-specific data keys in the thread control block.
22481ad6265SDimitry Andric #  if (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_SOLARIS) && \
22581ad6265SDimitry Andric       !SANITIZER_ANDROID && !SANITIZER_GO
22668d75effSDimitry Andric // sizeof(struct pthread) from glibc.
22768d75effSDimitry Andric static atomic_uintptr_t thread_descriptor_size;
22868d75effSDimitry Andric 
ThreadDescriptorSizeFallback()229d56accc7SDimitry Andric static uptr ThreadDescriptorSizeFallback() {
230d56accc7SDimitry Andric   uptr val = 0;
23168d75effSDimitry Andric #    if defined(__x86_64__) || defined(__i386__) || defined(__arm__)
23268d75effSDimitry Andric   int major;
23368d75effSDimitry Andric   int minor;
23468d75effSDimitry Andric   int patch;
23568d75effSDimitry Andric   if (GetLibcVersion(&major, &minor, &patch) && major == 2) {
23668d75effSDimitry Andric     /* sizeof(struct pthread) values from various glibc versions.  */
23768d75effSDimitry Andric     if (SANITIZER_X32)
23868d75effSDimitry Andric       val = 1728;  // Assume only one particular version for x32.
23968d75effSDimitry Andric     // For ARM sizeof(struct pthread) changed in Glibc 2.23.
24068d75effSDimitry Andric     else if (SANITIZER_ARM)
24168d75effSDimitry Andric       val = minor <= 22 ? 1120 : 1216;
24268d75effSDimitry Andric     else if (minor <= 3)
24368d75effSDimitry Andric       val = FIRST_32_SECOND_64(1104, 1696);
24468d75effSDimitry Andric     else if (minor == 4)
24568d75effSDimitry Andric       val = FIRST_32_SECOND_64(1120, 1728);
24668d75effSDimitry Andric     else if (minor == 5)
24768d75effSDimitry Andric       val = FIRST_32_SECOND_64(1136, 1728);
24868d75effSDimitry Andric     else if (minor <= 9)
24968d75effSDimitry Andric       val = FIRST_32_SECOND_64(1136, 1712);
25068d75effSDimitry Andric     else if (minor == 10)
25168d75effSDimitry Andric       val = FIRST_32_SECOND_64(1168, 1776);
25268d75effSDimitry Andric     else if (minor == 11 || (minor == 12 && patch == 1))
25368d75effSDimitry Andric       val = FIRST_32_SECOND_64(1168, 2288);
25468d75effSDimitry Andric     else if (minor <= 14)
25568d75effSDimitry Andric       val = FIRST_32_SECOND_64(1168, 2304);
256e8d8bef9SDimitry Andric     else if (minor < 32)  // Unknown version
25768d75effSDimitry Andric       val = FIRST_32_SECOND_64(1216, 2304);
258e8d8bef9SDimitry Andric     else  // minor == 32
259e8d8bef9SDimitry Andric       val = FIRST_32_SECOND_64(1344, 2496);
26068d75effSDimitry Andric   }
261fe6060f1SDimitry Andric #    elif defined(__s390__) || defined(__sparc__)
262fe6060f1SDimitry Andric   // The size of a prefix of TCB including pthread::{specific_1stblock,specific}
263fe6060f1SDimitry Andric   // suffices. Just return offsetof(struct pthread, specific_used), which hasn't
264fe6060f1SDimitry Andric   // changed since 2007-05. Technically this applies to i386/x86_64 as well but
265fe6060f1SDimitry Andric   // we call _dl_get_tls_static_info and need the precise size of struct
266fe6060f1SDimitry Andric   // pthread.
267fe6060f1SDimitry Andric   return FIRST_32_SECOND_64(524, 1552);
26868d75effSDimitry Andric #    elif defined(__mips__)
26968d75effSDimitry Andric   // TODO(sagarthakur): add more values as per different glibc versions.
27068d75effSDimitry Andric   val = FIRST_32_SECOND_64(1152, 1776);
271bdd1243dSDimitry Andric #    elif SANITIZER_LOONGARCH64
272bdd1243dSDimitry Andric   val = 1856;  // from glibc 2.36
273e8d8bef9SDimitry Andric #    elif SANITIZER_RISCV64
274e8d8bef9SDimitry Andric   int major;
275e8d8bef9SDimitry Andric   int minor;
276e8d8bef9SDimitry Andric   int patch;
277e8d8bef9SDimitry Andric   if (GetLibcVersion(&major, &minor, &patch) && major == 2) {
278e8d8bef9SDimitry Andric     // TODO: consider adding an optional runtime check for an unknown (untested)
279e8d8bef9SDimitry Andric     // glibc version
280e8d8bef9SDimitry Andric     if (minor <= 28)  // WARNING: the highest tested version is 2.29
281e8d8bef9SDimitry Andric       val = 1772;     // no guarantees for this one
282e8d8bef9SDimitry Andric     else if (minor <= 31)
283e8d8bef9SDimitry Andric       val = 1772;  // tested against glibc 2.29, 2.31
284e8d8bef9SDimitry Andric     else
285e8d8bef9SDimitry Andric       val = 1936;  // tested against glibc 2.32
286e8d8bef9SDimitry Andric   }
287e8d8bef9SDimitry Andric 
28868d75effSDimitry Andric #    elif defined(__aarch64__)
28968d75effSDimitry Andric   // The sizeof (struct pthread) is the same from GLIBC 2.17 to 2.22.
29068d75effSDimitry Andric   val = 1776;
29168d75effSDimitry Andric #    elif defined(__powerpc64__)
29268d75effSDimitry Andric   val = 1776;  // from glibc.ppc64le 2.20-8.fc21
29368d75effSDimitry Andric #    endif
294d56accc7SDimitry Andric   return val;
295d56accc7SDimitry Andric }
296d56accc7SDimitry Andric 
ThreadDescriptorSize()297d56accc7SDimitry Andric uptr ThreadDescriptorSize() {
298d56accc7SDimitry Andric   uptr val = atomic_load_relaxed(&thread_descriptor_size);
29968d75effSDimitry Andric   if (val)
300d56accc7SDimitry Andric     return val;
301d56accc7SDimitry Andric   // _thread_db_sizeof_pthread is a GLIBC_PRIVATE symbol that is exported in
302d56accc7SDimitry Andric   // glibc 2.34 and later.
303d56accc7SDimitry Andric   if (unsigned *psizeof = static_cast<unsigned *>(
304d56accc7SDimitry Andric           dlsym(RTLD_DEFAULT, "_thread_db_sizeof_pthread")))
305d56accc7SDimitry Andric     val = *psizeof;
306d56accc7SDimitry Andric   if (!val)
307d56accc7SDimitry Andric     val = ThreadDescriptorSizeFallback();
30868d75effSDimitry Andric   atomic_store_relaxed(&thread_descriptor_size, val);
30968d75effSDimitry Andric   return val;
31068d75effSDimitry Andric }
31168d75effSDimitry Andric 
312bdd1243dSDimitry Andric #    if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64 || \
313bdd1243dSDimitry Andric         SANITIZER_LOONGARCH64
31468d75effSDimitry Andric // TlsPreTcbSize includes size of struct pthread_descr and size of tcb
31568d75effSDimitry Andric // head structure. It lies before the static tls blocks.
TlsPreTcbSize()31668d75effSDimitry Andric static uptr TlsPreTcbSize() {
31768d75effSDimitry Andric #      if defined(__mips__)
31868d75effSDimitry Andric   const uptr kTcbHead = 16;  // sizeof (tcbhead_t)
31968d75effSDimitry Andric #      elif defined(__powerpc64__)
32068d75effSDimitry Andric   const uptr kTcbHead = 88;  // sizeof (tcbhead_t)
321e8d8bef9SDimitry Andric #      elif SANITIZER_RISCV64
322e8d8bef9SDimitry Andric   const uptr kTcbHead = 16;  // sizeof (tcbhead_t)
323bdd1243dSDimitry Andric #      elif SANITIZER_LOONGARCH64
324bdd1243dSDimitry Andric   const uptr kTcbHead = 16;  // sizeof (tcbhead_t)
32568d75effSDimitry Andric #      endif
32668d75effSDimitry Andric   const uptr kTlsAlign = 16;
32768d75effSDimitry Andric   const uptr kTlsPreTcbSize =
32868d75effSDimitry Andric       RoundUpTo(ThreadDescriptorSize() + kTcbHead, kTlsAlign);
32968d75effSDimitry Andric   return kTlsPreTcbSize;
33068d75effSDimitry Andric }
33168d75effSDimitry Andric #    endif
33268d75effSDimitry Andric 
333fe6060f1SDimitry Andric namespace {
334fe6060f1SDimitry Andric struct TlsBlock {
335fe6060f1SDimitry Andric   uptr begin, end, align;
336fe6060f1SDimitry Andric   size_t tls_modid;
operator <__sanitizer::__anonc7372d950111::TlsBlock337fe6060f1SDimitry Andric   bool operator<(const TlsBlock &rhs) const { return begin < rhs.begin; }
338fe6060f1SDimitry Andric };
339fe6060f1SDimitry Andric }  // namespace
34068d75effSDimitry Andric 
341fe6060f1SDimitry Andric #    ifdef __s390__
342fe6060f1SDimitry Andric extern "C" uptr __tls_get_offset(void *arg);
343fe6060f1SDimitry Andric 
TlsGetOffset(uptr ti_module,uptr ti_offset)344fe6060f1SDimitry Andric static uptr TlsGetOffset(uptr ti_module, uptr ti_offset) {
345fe6060f1SDimitry Andric   // The __tls_get_offset ABI requires %r12 to point to GOT and %r2 to be an
346fe6060f1SDimitry Andric   // offset of a struct tls_index inside GOT. We don't possess either of the
347fe6060f1SDimitry Andric   // two, so violate the letter of the "ELF Handling For Thread-Local
348fe6060f1SDimitry Andric   // Storage" document and assume that the implementation just dereferences
349fe6060f1SDimitry Andric   // %r2 + %r12.
350fe6060f1SDimitry Andric   uptr tls_index[2] = {ti_module, ti_offset};
351fe6060f1SDimitry Andric   register uptr r2 asm("2") = 0;
352fe6060f1SDimitry Andric   register void *r12 asm("12") = tls_index;
353fe6060f1SDimitry Andric   asm("basr %%r14, %[__tls_get_offset]"
354fe6060f1SDimitry Andric       : "+r"(r2)
355fe6060f1SDimitry Andric       : [__tls_get_offset] "r"(__tls_get_offset), "r"(r12)
356fe6060f1SDimitry Andric       : "memory", "cc", "0", "1", "3", "4", "5", "14");
357fe6060f1SDimitry Andric   return r2;
358fe6060f1SDimitry Andric }
35968d75effSDimitry Andric #    else
360fe6060f1SDimitry Andric extern "C" void *__tls_get_addr(size_t *);
36168d75effSDimitry Andric #    endif
362fe6060f1SDimitry Andric 
363fcaf7f86SDimitry Andric static size_t main_tls_modid;
364fcaf7f86SDimitry Andric 
CollectStaticTlsBlocks(struct dl_phdr_info * info,size_t size,void * data)365fe6060f1SDimitry Andric static int CollectStaticTlsBlocks(struct dl_phdr_info *info, size_t size,
366fe6060f1SDimitry Andric                                   void *data) {
367fcaf7f86SDimitry Andric   size_t tls_modid;
368fcaf7f86SDimitry Andric #    if SANITIZER_SOLARIS
369fcaf7f86SDimitry Andric   // dlpi_tls_modid is only available since Solaris 11.4 SRU 10.  Use
370fcaf7f86SDimitry Andric   // dlinfo(RTLD_DI_LINKMAP) instead which works on all of Solaris 11.3,
371fcaf7f86SDimitry Andric   // 11.4, and Illumos.  The tlsmodid of the executable was changed to 1 in
372fcaf7f86SDimitry Andric   // 11.4 to match other implementations.
373fcaf7f86SDimitry Andric   if (size >= offsetof(dl_phdr_info_test, dlpi_tls_modid))
374fcaf7f86SDimitry Andric     main_tls_modid = 1;
375fcaf7f86SDimitry Andric   else
376fcaf7f86SDimitry Andric     main_tls_modid = 0;
377fcaf7f86SDimitry Andric   g_use_dlpi_tls_data = 0;
378fcaf7f86SDimitry Andric   Rt_map *map;
379fcaf7f86SDimitry Andric   dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &map);
380fcaf7f86SDimitry Andric   tls_modid = map->rt_tlsmodid;
381fcaf7f86SDimitry Andric #    else
382fcaf7f86SDimitry Andric   main_tls_modid = 1;
383fcaf7f86SDimitry Andric   tls_modid = info->dlpi_tls_modid;
384fcaf7f86SDimitry Andric #    endif
385fcaf7f86SDimitry Andric 
386fcaf7f86SDimitry Andric   if (tls_modid < main_tls_modid)
387fe6060f1SDimitry Andric     return 0;
388fcaf7f86SDimitry Andric   uptr begin;
389fcaf7f86SDimitry Andric #    if !SANITIZER_SOLARIS
390fcaf7f86SDimitry Andric   begin = (uptr)info->dlpi_tls_data;
391fcaf7f86SDimitry Andric #    endif
392fe6060f1SDimitry Andric   if (!g_use_dlpi_tls_data) {
393fe6060f1SDimitry Andric     // Call __tls_get_addr as a fallback. This forces TLS allocation on glibc
394fe6060f1SDimitry Andric     // and FreeBSD.
395fe6060f1SDimitry Andric #    ifdef __s390__
3965f757f3fSDimitry Andric     begin = (uptr)__builtin_thread_pointer() + TlsGetOffset(tls_modid, 0);
397fe6060f1SDimitry Andric #    else
398fcaf7f86SDimitry Andric     size_t mod_and_off[2] = {tls_modid, 0};
399fe6060f1SDimitry Andric     begin = (uptr)__tls_get_addr(mod_and_off);
400fe6060f1SDimitry Andric #    endif
401fe6060f1SDimitry Andric   }
402fe6060f1SDimitry Andric   for (unsigned i = 0; i != info->dlpi_phnum; ++i)
403fe6060f1SDimitry Andric     if (info->dlpi_phdr[i].p_type == PT_TLS) {
404fe6060f1SDimitry Andric       static_cast<InternalMmapVector<TlsBlock> *>(data)->push_back(
405fe6060f1SDimitry Andric           TlsBlock{begin, begin + info->dlpi_phdr[i].p_memsz,
406fcaf7f86SDimitry Andric                    info->dlpi_phdr[i].p_align, tls_modid});
407fe6060f1SDimitry Andric       break;
408fe6060f1SDimitry Andric     }
409fe6060f1SDimitry Andric   return 0;
41068d75effSDimitry Andric }
41168d75effSDimitry Andric 
GetStaticTlsBoundary(uptr * addr,uptr * size,uptr * align)412fe6060f1SDimitry Andric __attribute__((unused)) static void GetStaticTlsBoundary(uptr *addr, uptr *size,
413fe6060f1SDimitry Andric                                                          uptr *align) {
414fe6060f1SDimitry Andric   InternalMmapVector<TlsBlock> ranges;
415fe6060f1SDimitry Andric   dl_iterate_phdr(CollectStaticTlsBlocks, &ranges);
416fe6060f1SDimitry Andric   uptr len = ranges.size();
417fe6060f1SDimitry Andric   Sort(ranges.begin(), len);
418fcaf7f86SDimitry Andric   // Find the range with tls_modid == main_tls_modid. For glibc, because
419fcaf7f86SDimitry Andric   // libc.so uses PT_TLS, this module is guaranteed to exist and is one of
420fcaf7f86SDimitry Andric   // the initially loaded modules.
421fe6060f1SDimitry Andric   uptr one = 0;
422fcaf7f86SDimitry Andric   while (one != len && ranges[one].tls_modid != main_tls_modid) ++one;
423fe6060f1SDimitry Andric   if (one == len) {
424fe6060f1SDimitry Andric     // This may happen with musl if no module uses PT_TLS.
425fe6060f1SDimitry Andric     *addr = 0;
426fe6060f1SDimitry Andric     *size = 0;
427fe6060f1SDimitry Andric     *align = 1;
428fe6060f1SDimitry Andric     return;
42968d75effSDimitry Andric   }
430fe6060f1SDimitry Andric   // Find the maximum consecutive ranges. We consider two modules consecutive if
431fcaf7f86SDimitry Andric   // the gap is smaller than the alignment of the latter range. The dynamic
432fcaf7f86SDimitry Andric   // loader places static TLS blocks this way not to waste space.
433fe6060f1SDimitry Andric   uptr l = one;
434fe6060f1SDimitry Andric   *align = ranges[l].align;
435fcaf7f86SDimitry Andric   while (l != 0 && ranges[l].begin < ranges[l - 1].end + ranges[l].align)
436fe6060f1SDimitry Andric     *align = Max(*align, ranges[--l].align);
437fe6060f1SDimitry Andric   uptr r = one + 1;
438fcaf7f86SDimitry Andric   while (r != len && ranges[r].begin < ranges[r - 1].end + ranges[r].align)
439fe6060f1SDimitry Andric     *align = Max(*align, ranges[r++].align);
440fe6060f1SDimitry Andric   *addr = ranges[l].begin;
441fe6060f1SDimitry Andric   *size = ranges[r - 1].end - ranges[l].begin;
442fe6060f1SDimitry Andric }
443fe6060f1SDimitry Andric #  endif  // (x86_64 || i386 || mips || ...) && (SANITIZER_FREEBSD ||
444d56accc7SDimitry Andric           // SANITIZER_LINUX) && !SANITIZER_ANDROID && !SANITIZER_GO
44568d75effSDimitry Andric 
44668d75effSDimitry Andric #  if SANITIZER_NETBSD
ThreadSelfTlsTcb()44768d75effSDimitry Andric static struct tls_tcb *ThreadSelfTlsTcb() {
448e8d8bef9SDimitry Andric   struct tls_tcb *tcb = nullptr;
449e8d8bef9SDimitry Andric #    ifdef __HAVE___LWP_GETTCB_FAST
450e8d8bef9SDimitry Andric   tcb = (struct tls_tcb *)__lwp_gettcb_fast();
451e8d8bef9SDimitry Andric #    elif defined(__HAVE___LWP_GETPRIVATE_FAST)
452e8d8bef9SDimitry Andric   tcb = (struct tls_tcb *)__lwp_getprivate_fast();
453e8d8bef9SDimitry Andric #    endif
454e8d8bef9SDimitry Andric   return tcb;
45568d75effSDimitry Andric }
45668d75effSDimitry Andric 
ThreadSelf()4575f757f3fSDimitry Andric uptr ThreadSelf() { return (uptr)ThreadSelfTlsTcb()->tcb_pthread; }
45868d75effSDimitry Andric 
GetSizeFromHdr(struct dl_phdr_info * info,size_t size,void * data)45968d75effSDimitry Andric int GetSizeFromHdr(struct dl_phdr_info *info, size_t size, void *data) {
46068d75effSDimitry Andric   const Elf_Phdr *hdr = info->dlpi_phdr;
46168d75effSDimitry Andric   const Elf_Phdr *last_hdr = hdr + info->dlpi_phnum;
46268d75effSDimitry Andric 
46368d75effSDimitry Andric   for (; hdr != last_hdr; ++hdr) {
46468d75effSDimitry Andric     if (hdr->p_type == PT_TLS && info->dlpi_tls_modid == 1) {
46568d75effSDimitry Andric       *(uptr *)data = hdr->p_memsz;
46668d75effSDimitry Andric       break;
46768d75effSDimitry Andric     }
46868d75effSDimitry Andric   }
46968d75effSDimitry Andric   return 0;
47068d75effSDimitry Andric }
47168d75effSDimitry Andric #  endif  // SANITIZER_NETBSD
47268d75effSDimitry Andric 
473e8d8bef9SDimitry Andric #  if SANITIZER_ANDROID
474e8d8bef9SDimitry Andric // Bionic provides this API since S.
475e8d8bef9SDimitry Andric extern "C" SANITIZER_WEAK_ATTRIBUTE void __libc_get_static_tls_bounds(void **,
476e8d8bef9SDimitry Andric                                                                       void **);
477e8d8bef9SDimitry Andric #  endif
478e8d8bef9SDimitry Andric 
47968d75effSDimitry Andric #  if !SANITIZER_GO
GetTls(uptr * addr,uptr * size)48068d75effSDimitry Andric static void GetTls(uptr *addr, uptr *size) {
481e8d8bef9SDimitry Andric #    if SANITIZER_ANDROID
482e8d8bef9SDimitry Andric   if (&__libc_get_static_tls_bounds) {
483e8d8bef9SDimitry Andric     void *start_addr;
484e8d8bef9SDimitry Andric     void *end_addr;
485e8d8bef9SDimitry Andric     __libc_get_static_tls_bounds(&start_addr, &end_addr);
486e8d8bef9SDimitry Andric     *addr = reinterpret_cast<uptr>(start_addr);
487e8d8bef9SDimitry Andric     *size =
488e8d8bef9SDimitry Andric         reinterpret_cast<uptr>(end_addr) - reinterpret_cast<uptr>(start_addr);
489e8d8bef9SDimitry Andric   } else {
490e8d8bef9SDimitry Andric     *addr = 0;
491e8d8bef9SDimitry Andric     *size = 0;
492e8d8bef9SDimitry Andric   }
493fe6060f1SDimitry Andric #    elif SANITIZER_GLIBC && defined(__x86_64__)
494fe6060f1SDimitry Andric   // For aarch64 and x86-64, use an O(1) approach which requires relatively
495fe6060f1SDimitry Andric   // precise ThreadDescriptorSize. g_tls_size was initialized in InitTlsSize.
49681ad6265SDimitry Andric #      if SANITIZER_X32
49781ad6265SDimitry Andric   asm("mov %%fs:8,%0" : "=r"(*addr));
49881ad6265SDimitry Andric #      else
499fe6060f1SDimitry Andric   asm("mov %%fs:16,%0" : "=r"(*addr));
50081ad6265SDimitry Andric #      endif
501fe6060f1SDimitry Andric   *size = g_tls_size;
50268d75effSDimitry Andric   *addr -= *size;
50368d75effSDimitry Andric   *addr += ThreadDescriptorSize();
504fe6060f1SDimitry Andric #    elif SANITIZER_GLIBC && defined(__aarch64__)
505fe6060f1SDimitry Andric   *addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
506fe6060f1SDimitry Andric           ThreadDescriptorSize();
507fe6060f1SDimitry Andric   *size = g_tls_size + ThreadDescriptorSize();
508bdd1243dSDimitry Andric #    elif SANITIZER_GLIBC && defined(__loongarch__)
509bdd1243dSDimitry Andric #      ifdef __clang__
510bdd1243dSDimitry Andric   *addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
511bdd1243dSDimitry Andric           ThreadDescriptorSize();
512bdd1243dSDimitry Andric #      else
513bdd1243dSDimitry Andric   asm("or %0,$tp,$zero" : "=r"(*addr));
514bdd1243dSDimitry Andric   *addr -= ThreadDescriptorSize();
515bdd1243dSDimitry Andric #      endif
516bdd1243dSDimitry Andric   *size = g_tls_size + ThreadDescriptorSize();
517fe6060f1SDimitry Andric #    elif SANITIZER_GLIBC && defined(__powerpc64__)
518fe6060f1SDimitry Andric   // Workaround for glibc<2.25(?). 2.27 is known to not need this.
519fe6060f1SDimitry Andric   uptr tp;
520fe6060f1SDimitry Andric   asm("addi %0,13,-0x7000" : "=r"(tp));
521fe6060f1SDimitry Andric   const uptr pre_tcb_size = TlsPreTcbSize();
522fe6060f1SDimitry Andric   *addr = tp - pre_tcb_size;
523fe6060f1SDimitry Andric   *size = g_tls_size + pre_tcb_size;
52481ad6265SDimitry Andric #    elif SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_SOLARIS
525fe6060f1SDimitry Andric   uptr align;
526fe6060f1SDimitry Andric   GetStaticTlsBoundary(addr, size, &align);
527fe6060f1SDimitry Andric #      if defined(__x86_64__) || defined(__i386__) || defined(__s390__) || \
528fe6060f1SDimitry Andric           defined(__sparc__)
529fe6060f1SDimitry Andric   if (SANITIZER_GLIBC) {
530fe6060f1SDimitry Andric #        if defined(__x86_64__) || defined(__i386__)
531fe6060f1SDimitry Andric     align = Max<uptr>(align, 64);
53268d75effSDimitry Andric #        else
533fe6060f1SDimitry Andric     align = Max<uptr>(align, 16);
53468d75effSDimitry Andric #        endif
53568d75effSDimitry Andric   }
536fe6060f1SDimitry Andric   const uptr tp = RoundUpTo(*addr + *size, align);
537fe6060f1SDimitry Andric 
538fe6060f1SDimitry Andric   // lsan requires the range to additionally cover the static TLS surplus
539fe6060f1SDimitry Andric   // (elf/dl-tls.c defines 1664). Otherwise there may be false positives for
540fe6060f1SDimitry Andric   // allocations only referenced by tls in dynamically loaded modules.
541fe6060f1SDimitry Andric   if (SANITIZER_GLIBC)
542fe6060f1SDimitry Andric     *size += 1644;
543fe6060f1SDimitry Andric   else if (SANITIZER_FREEBSD)
544fe6060f1SDimitry Andric     *size += 128;  // RTLD_STATIC_TLS_EXTRA
545fe6060f1SDimitry Andric 
546fe6060f1SDimitry Andric   // Extend the range to include the thread control block. On glibc, lsan needs
547fe6060f1SDimitry Andric   // the range to include pthread::{specific_1stblock,specific} so that
548fe6060f1SDimitry Andric   // allocations only referenced by pthread_setspecific can be scanned. This may
549fe6060f1SDimitry Andric   // underestimate by at most TLS_TCB_ALIGN-1 bytes but it should be fine
550fe6060f1SDimitry Andric   // because the number of bytes after pthread::specific is larger.
551fe6060f1SDimitry Andric   *addr = tp - RoundUpTo(*size, align);
552fe6060f1SDimitry Andric   *size = tp - *addr + ThreadDescriptorSize();
553fe6060f1SDimitry Andric #      else
554fe6060f1SDimitry Andric   if (SANITIZER_GLIBC)
555fe6060f1SDimitry Andric     *size += 1664;
556fe6060f1SDimitry Andric   else if (SANITIZER_FREEBSD)
557fe6060f1SDimitry Andric     *size += 128;  // RTLD_STATIC_TLS_EXTRA
558fe6060f1SDimitry Andric #        if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
559fe6060f1SDimitry Andric   const uptr pre_tcb_size = TlsPreTcbSize();
560fe6060f1SDimitry Andric   *addr -= pre_tcb_size;
561fe6060f1SDimitry Andric   *size += pre_tcb_size;
562fe6060f1SDimitry Andric #        else
563fe6060f1SDimitry Andric   // arm and aarch64 reserve two words at TP, so this underestimates the range.
564fe6060f1SDimitry Andric   // However, this is sufficient for the purpose of finding the pointers to
565fe6060f1SDimitry Andric   // thread-specific data keys.
566fe6060f1SDimitry Andric   const uptr tcb_size = ThreadDescriptorSize();
567fe6060f1SDimitry Andric   *addr -= tcb_size;
568fe6060f1SDimitry Andric   *size += tcb_size;
569fe6060f1SDimitry Andric #        endif
570fe6060f1SDimitry Andric #      endif
57168d75effSDimitry Andric #    elif SANITIZER_NETBSD
57268d75effSDimitry Andric   struct tls_tcb *const tcb = ThreadSelfTlsTcb();
57368d75effSDimitry Andric   *addr = 0;
57468d75effSDimitry Andric   *size = 0;
57568d75effSDimitry Andric   if (tcb != 0) {
57668d75effSDimitry Andric     // Find size (p_memsz) of dlpi_tls_modid 1 (TLS block of the main program).
57768d75effSDimitry Andric     // ld.elf_so hardcodes the index 1.
57868d75effSDimitry Andric     dl_iterate_phdr(GetSizeFromHdr, size);
57968d75effSDimitry Andric 
58068d75effSDimitry Andric     if (*size != 0) {
58168d75effSDimitry Andric       // The block has been found and tcb_dtv[1] contains the base address
58268d75effSDimitry Andric       *addr = (uptr)tcb->tcb_dtv[1];
58368d75effSDimitry Andric     }
58468d75effSDimitry Andric   }
5851ac55f4cSDimitry Andric #    else
58668d75effSDimitry Andric #      error "Unknown OS"
58768d75effSDimitry Andric #    endif
58868d75effSDimitry Andric }
58968d75effSDimitry Andric #  endif
59068d75effSDimitry Andric 
59168d75effSDimitry Andric #  if !SANITIZER_GO
GetTlsSize()59268d75effSDimitry Andric uptr GetTlsSize() {
593fe6060f1SDimitry Andric #    if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
594e8d8bef9SDimitry Andric         SANITIZER_SOLARIS
59568d75effSDimitry Andric   uptr addr, size;
59668d75effSDimitry Andric   GetTls(&addr, &size);
59768d75effSDimitry Andric   return size;
598e8d8bef9SDimitry Andric #    else
599e8d8bef9SDimitry Andric   return 0;
600e8d8bef9SDimitry Andric #    endif
60168d75effSDimitry Andric }
60268d75effSDimitry Andric #  endif
60368d75effSDimitry Andric 
GetThreadStackAndTls(bool main,uptr * stk_addr,uptr * stk_size,uptr * tls_addr,uptr * tls_size)60468d75effSDimitry Andric void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
60568d75effSDimitry Andric                           uptr *tls_addr, uptr *tls_size) {
60668d75effSDimitry Andric #  if SANITIZER_GO
60768d75effSDimitry Andric   // Stub implementation for Go.
60868d75effSDimitry Andric   *stk_addr = *stk_size = *tls_addr = *tls_size = 0;
60968d75effSDimitry Andric #  else
61068d75effSDimitry Andric   GetTls(tls_addr, tls_size);
61168d75effSDimitry Andric 
61268d75effSDimitry Andric   uptr stack_top, stack_bottom;
61368d75effSDimitry Andric   GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
61468d75effSDimitry Andric   *stk_addr = stack_bottom;
61568d75effSDimitry Andric   *stk_size = stack_top - stack_bottom;
61668d75effSDimitry Andric 
61768d75effSDimitry Andric   if (!main) {
61868d75effSDimitry Andric     // If stack and tls intersect, make them non-intersecting.
61968d75effSDimitry Andric     if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) {
620fe6060f1SDimitry Andric       if (*stk_addr + *stk_size < *tls_addr + *tls_size)
621fe6060f1SDimitry Andric         *tls_size = *stk_addr + *stk_size - *tls_addr;
622fe6060f1SDimitry Andric       *stk_size = *tls_addr - *stk_addr;
62368d75effSDimitry Andric     }
62468d75effSDimitry Andric   }
62568d75effSDimitry Andric #  endif
62668d75effSDimitry Andric }
62768d75effSDimitry Andric 
628e8d8bef9SDimitry Andric #  if !SANITIZER_FREEBSD
62968d75effSDimitry Andric typedef ElfW(Phdr) Elf_Phdr;
630647cbc5dSDimitry Andric #  endif
63168d75effSDimitry Andric 
63268d75effSDimitry Andric struct DlIteratePhdrData {
63368d75effSDimitry Andric   InternalMmapVectorNoCtor<LoadedModule> *modules;
63468d75effSDimitry Andric   bool first;
63568d75effSDimitry Andric };
63668d75effSDimitry Andric 
AddModuleSegments(const char * module_name,dl_phdr_info * info,InternalMmapVectorNoCtor<LoadedModule> * modules)637fe6060f1SDimitry Andric static int AddModuleSegments(const char *module_name, dl_phdr_info *info,
638fe6060f1SDimitry Andric                              InternalMmapVectorNoCtor<LoadedModule> *modules) {
63968d75effSDimitry Andric   if (module_name[0] == '\0')
64068d75effSDimitry Andric     return 0;
64168d75effSDimitry Andric   LoadedModule cur_module;
642fe6060f1SDimitry Andric   cur_module.set(module_name, info->dlpi_addr);
64368d75effSDimitry Andric   for (int i = 0; i < (int)info->dlpi_phnum; i++) {
64468d75effSDimitry Andric     const Elf_Phdr *phdr = &info->dlpi_phdr[i];
64568d75effSDimitry Andric     if (phdr->p_type == PT_LOAD) {
64668d75effSDimitry Andric       uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
64768d75effSDimitry Andric       uptr cur_end = cur_beg + phdr->p_memsz;
64868d75effSDimitry Andric       bool executable = phdr->p_flags & PF_X;
64968d75effSDimitry Andric       bool writable = phdr->p_flags & PF_W;
6505f757f3fSDimitry Andric       cur_module.addAddressRange(cur_beg, cur_end, executable, writable);
6510eae32dcSDimitry Andric     } else if (phdr->p_type == PT_NOTE) {
65204eeddc0SDimitry Andric #  ifdef NT_GNU_BUILD_ID
6530eae32dcSDimitry Andric       uptr off = 0;
65404eeddc0SDimitry Andric       while (off + sizeof(ElfW(Nhdr)) < phdr->p_memsz) {
6550eae32dcSDimitry Andric         auto *nhdr = reinterpret_cast<const ElfW(Nhdr) *>(info->dlpi_addr +
6560eae32dcSDimitry Andric                                                           phdr->p_vaddr + off);
6570eae32dcSDimitry Andric         constexpr auto kGnuNamesz = 4;  // "GNU" with NUL-byte.
6580eae32dcSDimitry Andric         static_assert(kGnuNamesz % 4 == 0, "kGnuNameSize is aligned to 4.");
6590eae32dcSDimitry Andric         if (nhdr->n_type == NT_GNU_BUILD_ID && nhdr->n_namesz == kGnuNamesz) {
6600eae32dcSDimitry Andric           if (off + sizeof(ElfW(Nhdr)) + nhdr->n_namesz + nhdr->n_descsz >
6610eae32dcSDimitry Andric               phdr->p_memsz) {
6620eae32dcSDimitry Andric             // Something is very wrong, bail out instead of reading potentially
6630eae32dcSDimitry Andric             // arbitrary memory.
6640eae32dcSDimitry Andric             break;
6650eae32dcSDimitry Andric           }
6660eae32dcSDimitry Andric           const char *name =
6670eae32dcSDimitry Andric               reinterpret_cast<const char *>(nhdr) + sizeof(*nhdr);
6680eae32dcSDimitry Andric           if (internal_memcmp(name, "GNU", 3) == 0) {
6690eae32dcSDimitry Andric             const char *value = reinterpret_cast<const char *>(nhdr) +
6700eae32dcSDimitry Andric                                 sizeof(*nhdr) + kGnuNamesz;
6710eae32dcSDimitry Andric             cur_module.setUuid(value, nhdr->n_descsz);
6720eae32dcSDimitry Andric             break;
6730eae32dcSDimitry Andric           }
6740eae32dcSDimitry Andric         }
6750eae32dcSDimitry Andric         off += sizeof(*nhdr) + RoundUpTo(nhdr->n_namesz, 4) +
6760eae32dcSDimitry Andric                RoundUpTo(nhdr->n_descsz, 4);
6770eae32dcSDimitry Andric       }
67804eeddc0SDimitry Andric #  endif
67968d75effSDimitry Andric     }
68068d75effSDimitry Andric   }
681fe6060f1SDimitry Andric   modules->push_back(cur_module);
682fe6060f1SDimitry Andric   return 0;
683fe6060f1SDimitry Andric }
684fe6060f1SDimitry Andric 
dl_iterate_phdr_cb(dl_phdr_info * info,size_t size,void * arg)685fe6060f1SDimitry Andric static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
686fe6060f1SDimitry Andric   DlIteratePhdrData *data = (DlIteratePhdrData *)arg;
687fe6060f1SDimitry Andric   if (data->first) {
688fe6060f1SDimitry Andric     InternalMmapVector<char> module_name(kMaxPathLength);
689fe6060f1SDimitry Andric     data->first = false;
690fe6060f1SDimitry Andric     // First module is the binary itself.
691fe6060f1SDimitry Andric     ReadBinaryNameCached(module_name.data(), module_name.size());
692fe6060f1SDimitry Andric     return AddModuleSegments(module_name.data(), info, data->modules);
693fe6060f1SDimitry Andric   }
694fe6060f1SDimitry Andric 
6955f757f3fSDimitry Andric   if (info->dlpi_name)
6965f757f3fSDimitry Andric     return AddModuleSegments(info->dlpi_name, info, data->modules);
697fe6060f1SDimitry Andric 
69868d75effSDimitry Andric   return 0;
69968d75effSDimitry Andric }
70068d75effSDimitry Andric 
70168d75effSDimitry Andric #  if SANITIZER_ANDROID && __ANDROID_API__ < 21
70268d75effSDimitry Andric extern "C" __attribute__((weak)) int dl_iterate_phdr(
70368d75effSDimitry Andric     int (*)(struct dl_phdr_info *, size_t, void *), void *);
70468d75effSDimitry Andric #  endif
70568d75effSDimitry Andric 
requiresProcmaps()70668d75effSDimitry Andric static bool requiresProcmaps() {
70768d75effSDimitry Andric #  if SANITIZER_ANDROID && __ANDROID_API__ <= 22
70868d75effSDimitry Andric   // Fall back to /proc/maps if dl_iterate_phdr is unavailable or broken.
70968d75effSDimitry Andric   // The runtime check allows the same library to work with
71068d75effSDimitry Andric   // both K and L (and future) Android releases.
71168d75effSDimitry Andric   return AndroidGetApiLevel() <= ANDROID_LOLLIPOP_MR1;
71268d75effSDimitry Andric #  else
71368d75effSDimitry Andric   return false;
71468d75effSDimitry Andric #  endif
71568d75effSDimitry Andric }
71668d75effSDimitry Andric 
procmapsInit(InternalMmapVectorNoCtor<LoadedModule> * modules)71768d75effSDimitry Andric static void procmapsInit(InternalMmapVectorNoCtor<LoadedModule> *modules) {
71868d75effSDimitry Andric   MemoryMappingLayout memory_mapping(/*cache_enabled*/ true);
71968d75effSDimitry Andric   memory_mapping.DumpListOfModules(modules);
72068d75effSDimitry Andric }
72168d75effSDimitry Andric 
init()72268d75effSDimitry Andric void ListOfModules::init() {
72368d75effSDimitry Andric   clearOrInit();
72468d75effSDimitry Andric   if (requiresProcmaps()) {
72568d75effSDimitry Andric     procmapsInit(&modules_);
72668d75effSDimitry Andric   } else {
72768d75effSDimitry Andric     DlIteratePhdrData data = {&modules_, true};
72868d75effSDimitry Andric     dl_iterate_phdr(dl_iterate_phdr_cb, &data);
72968d75effSDimitry Andric   }
73068d75effSDimitry Andric }
73168d75effSDimitry Andric 
73268d75effSDimitry Andric // When a custom loader is used, dl_iterate_phdr may not contain the full
73368d75effSDimitry Andric // list of modules. Allow callers to fall back to using procmaps.
fallbackInit()73468d75effSDimitry Andric void ListOfModules::fallbackInit() {
73568d75effSDimitry Andric   if (!requiresProcmaps()) {
73668d75effSDimitry Andric     clearOrInit();
73768d75effSDimitry Andric     procmapsInit(&modules_);
73868d75effSDimitry Andric   } else {
73968d75effSDimitry Andric     clear();
74068d75effSDimitry Andric   }
74168d75effSDimitry Andric }
74268d75effSDimitry Andric 
74368d75effSDimitry Andric // getrusage does not give us the current RSS, only the max RSS.
74468d75effSDimitry Andric // Still, this is better than nothing if /proc/self/statm is not available
74568d75effSDimitry Andric // for some reason, e.g. due to a sandbox.
GetRSSFromGetrusage()74668d75effSDimitry Andric static uptr GetRSSFromGetrusage() {
74768d75effSDimitry Andric   struct rusage usage;
74868d75effSDimitry Andric   if (getrusage(RUSAGE_SELF, &usage))  // Failed, probably due to a sandbox.
74968d75effSDimitry Andric     return 0;
75068d75effSDimitry Andric   return usage.ru_maxrss << 10;  // ru_maxrss is in Kb.
75168d75effSDimitry Andric }
75268d75effSDimitry Andric 
GetRSS()75368d75effSDimitry Andric uptr GetRSS() {
75468d75effSDimitry Andric   if (!common_flags()->can_use_proc_maps_statm)
75568d75effSDimitry Andric     return GetRSSFromGetrusage();
75668d75effSDimitry Andric   fd_t fd = OpenFile("/proc/self/statm", RdOnly);
75768d75effSDimitry Andric   if (fd == kInvalidFd)
75868d75effSDimitry Andric     return GetRSSFromGetrusage();
75968d75effSDimitry Andric   char buf[64];
76068d75effSDimitry Andric   uptr len = internal_read(fd, buf, sizeof(buf) - 1);
76168d75effSDimitry Andric   internal_close(fd);
76268d75effSDimitry Andric   if ((sptr)len <= 0)
76368d75effSDimitry Andric     return 0;
76468d75effSDimitry Andric   buf[len] = 0;
76568d75effSDimitry Andric   // The format of the file is:
76668d75effSDimitry Andric   // 1084 89 69 11 0 79 0
76768d75effSDimitry Andric   // We need the second number which is RSS in pages.
76868d75effSDimitry Andric   char *pos = buf;
76968d75effSDimitry Andric   // Skip the first number.
7705f757f3fSDimitry Andric   while (*pos >= '0' && *pos <= '9') pos++;
77168d75effSDimitry Andric   // Skip whitespaces.
7725f757f3fSDimitry Andric   while (!(*pos >= '0' && *pos <= '9') && *pos != 0) pos++;
77368d75effSDimitry Andric   // Read the number.
77468d75effSDimitry Andric   uptr rss = 0;
7755f757f3fSDimitry Andric   while (*pos >= '0' && *pos <= '9') rss = rss * 10 + *pos++ - '0';
77668d75effSDimitry Andric   return rss * GetPageSizeCached();
77768d75effSDimitry Andric }
77868d75effSDimitry Andric 
77968d75effSDimitry Andric // sysconf(_SC_NPROCESSORS_{CONF,ONLN}) cannot be used on most platforms as
78068d75effSDimitry Andric // they allocate memory.
GetNumberOfCPUs()78168d75effSDimitry Andric u32 GetNumberOfCPUs() {
782e8d8bef9SDimitry Andric #  if SANITIZER_FREEBSD || SANITIZER_NETBSD
78368d75effSDimitry Andric   u32 ncpu;
78468d75effSDimitry Andric   int req[2];
78568d75effSDimitry Andric   uptr len = sizeof(ncpu);
78668d75effSDimitry Andric   req[0] = CTL_HW;
78768d75effSDimitry Andric   req[1] = HW_NCPU;
78868d75effSDimitry Andric   CHECK_EQ(internal_sysctl(req, 2, &ncpu, &len, NULL, 0), 0);
78968d75effSDimitry Andric   return ncpu;
79068d75effSDimitry Andric #  elif SANITIZER_ANDROID && !defined(CPU_COUNT) && !defined(__aarch64__)
79168d75effSDimitry Andric   // Fall back to /sys/devices/system/cpu on Android when cpu_set_t doesn't
79268d75effSDimitry Andric   // exist in sched.h. That is the case for toolchains generated with older
79368d75effSDimitry Andric   // NDKs.
79468d75effSDimitry Andric   // This code doesn't work on AArch64 because internal_getdents makes use of
79568d75effSDimitry Andric   // the 64bit getdents syscall, but cpu_set_t seems to always exist on AArch64.
79668d75effSDimitry Andric   uptr fd = internal_open("/sys/devices/system/cpu", O_RDONLY | O_DIRECTORY);
79768d75effSDimitry Andric   if (internal_iserror(fd))
79868d75effSDimitry Andric     return 0;
79968d75effSDimitry Andric   InternalMmapVector<u8> buffer(4096);
80068d75effSDimitry Andric   uptr bytes_read = buffer.size();
80168d75effSDimitry Andric   uptr n_cpus = 0;
80268d75effSDimitry Andric   u8 *d_type;
80368d75effSDimitry Andric   struct linux_dirent *entry = (struct linux_dirent *)&buffer[bytes_read];
80468d75effSDimitry Andric   while (true) {
80568d75effSDimitry Andric     if ((u8 *)entry >= &buffer[bytes_read]) {
80668d75effSDimitry Andric       bytes_read = internal_getdents(fd, (struct linux_dirent *)buffer.data(),
80768d75effSDimitry Andric                                      buffer.size());
80868d75effSDimitry Andric       if (internal_iserror(bytes_read) || !bytes_read)
80968d75effSDimitry Andric         break;
81068d75effSDimitry Andric       entry = (struct linux_dirent *)buffer.data();
81168d75effSDimitry Andric     }
81268d75effSDimitry Andric     d_type = (u8 *)entry + entry->d_reclen - 1;
81368d75effSDimitry Andric     if (d_type >= &buffer[bytes_read] ||
81468d75effSDimitry Andric         (u8 *)&entry->d_name[3] >= &buffer[bytes_read])
81568d75effSDimitry Andric       break;
81668d75effSDimitry Andric     if (entry->d_ino != 0 && *d_type == DT_DIR) {
81768d75effSDimitry Andric       if (entry->d_name[0] == 'c' && entry->d_name[1] == 'p' &&
8185f757f3fSDimitry Andric           entry->d_name[2] == 'u' && entry->d_name[3] >= '0' &&
8195f757f3fSDimitry Andric           entry->d_name[3] <= '9')
82068d75effSDimitry Andric         n_cpus++;
82168d75effSDimitry Andric     }
82268d75effSDimitry Andric     entry = (struct linux_dirent *)(((u8 *)entry) + entry->d_reclen);
82368d75effSDimitry Andric   }
82468d75effSDimitry Andric   internal_close(fd);
82568d75effSDimitry Andric   return n_cpus;
82668d75effSDimitry Andric #  elif SANITIZER_SOLARIS
82768d75effSDimitry Andric   return sysconf(_SC_NPROCESSORS_ONLN);
82868d75effSDimitry Andric #  else
82968d75effSDimitry Andric   cpu_set_t CPUs;
83068d75effSDimitry Andric   CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0);
83168d75effSDimitry Andric   return CPU_COUNT(&CPUs);
83268d75effSDimitry Andric #  endif
83368d75effSDimitry Andric }
83468d75effSDimitry Andric 
83568d75effSDimitry Andric #  if SANITIZER_LINUX
83668d75effSDimitry Andric 
83768d75effSDimitry Andric #    if SANITIZER_ANDROID
83868d75effSDimitry Andric static atomic_uint8_t android_log_initialized;
83968d75effSDimitry Andric 
AndroidLogInit()84068d75effSDimitry Andric void AndroidLogInit() {
84168d75effSDimitry Andric   openlog(GetProcessName(), 0, LOG_USER);
84268d75effSDimitry Andric   atomic_store(&android_log_initialized, 1, memory_order_release);
84368d75effSDimitry Andric }
84468d75effSDimitry Andric 
ShouldLogAfterPrintf()84568d75effSDimitry Andric static bool ShouldLogAfterPrintf() {
84668d75effSDimitry Andric   return atomic_load(&android_log_initialized, memory_order_acquire);
84768d75effSDimitry Andric }
84868d75effSDimitry Andric 
8495f757f3fSDimitry Andric extern "C" SANITIZER_WEAK_ATTRIBUTE int async_safe_write_log(int pri,
8505f757f3fSDimitry Andric                                                              const char *tag,
8515f757f3fSDimitry Andric                                                              const char *msg);
8525f757f3fSDimitry Andric extern "C" SANITIZER_WEAK_ATTRIBUTE int __android_log_write(int prio,
8535f757f3fSDimitry Andric                                                             const char *tag,
8545f757f3fSDimitry Andric                                                             const char *msg);
85568d75effSDimitry Andric 
85668d75effSDimitry Andric // ANDROID_LOG_INFO is 4, but can't be resolved at runtime.
85768d75effSDimitry Andric #      define SANITIZER_ANDROID_LOG_INFO 4
85868d75effSDimitry Andric 
85968d75effSDimitry Andric // async_safe_write_log is a new public version of __libc_write_log that is
86068d75effSDimitry Andric // used behind syslog. It is preferable to syslog as it will not do any dynamic
86168d75effSDimitry Andric // memory allocation or formatting.
86268d75effSDimitry Andric // If the function is not available, syslog is preferred for L+ (it was broken
86368d75effSDimitry Andric // pre-L) as __android_log_write triggers a racey behavior with the strncpy
86468d75effSDimitry Andric // interceptor. Fallback to __android_log_write pre-L.
WriteOneLineToSyslog(const char * s)86568d75effSDimitry Andric void WriteOneLineToSyslog(const char *s) {
86668d75effSDimitry Andric   if (&async_safe_write_log) {
86768d75effSDimitry Andric     async_safe_write_log(SANITIZER_ANDROID_LOG_INFO, GetProcessName(), s);
86868d75effSDimitry Andric   } else if (AndroidGetApiLevel() > ANDROID_KITKAT) {
86968d75effSDimitry Andric     syslog(LOG_INFO, "%s", s);
87068d75effSDimitry Andric   } else {
87168d75effSDimitry Andric     CHECK(&__android_log_write);
87268d75effSDimitry Andric     __android_log_write(SANITIZER_ANDROID_LOG_INFO, nullptr, s);
87368d75effSDimitry Andric   }
87468d75effSDimitry Andric }
87568d75effSDimitry Andric 
8765f757f3fSDimitry Andric extern "C" SANITIZER_WEAK_ATTRIBUTE void android_set_abort_message(
8775f757f3fSDimitry Andric     const char *);
87868d75effSDimitry Andric 
SetAbortMessage(const char * str)87968d75effSDimitry Andric void SetAbortMessage(const char *str) {
88068d75effSDimitry Andric   if (&android_set_abort_message)
88168d75effSDimitry Andric     android_set_abort_message(str);
88268d75effSDimitry Andric }
88368d75effSDimitry Andric #    else
AndroidLogInit()88468d75effSDimitry Andric void AndroidLogInit() {}
88568d75effSDimitry Andric 
ShouldLogAfterPrintf()88668d75effSDimitry Andric static bool ShouldLogAfterPrintf() { return true; }
88768d75effSDimitry Andric 
WriteOneLineToSyslog(const char * s)88868d75effSDimitry Andric void WriteOneLineToSyslog(const char *s) { syslog(LOG_INFO, "%s", s); }
88968d75effSDimitry Andric 
SetAbortMessage(const char * str)89068d75effSDimitry Andric void SetAbortMessage(const char *str) {}
89168d75effSDimitry Andric #    endif  // SANITIZER_ANDROID
89268d75effSDimitry Andric 
LogMessageOnPrintf(const char * str)89368d75effSDimitry Andric void LogMessageOnPrintf(const char *str) {
89468d75effSDimitry Andric   if (common_flags()->log_to_syslog && ShouldLogAfterPrintf())
89568d75effSDimitry Andric     WriteToSyslog(str);
89668d75effSDimitry Andric }
89768d75effSDimitry Andric 
89868d75effSDimitry Andric #  endif  // SANITIZER_LINUX
89968d75effSDimitry Andric 
900fe6060f1SDimitry Andric #  if SANITIZER_GLIBC && !SANITIZER_GO
90168d75effSDimitry Andric // glibc crashes when using clock_gettime from a preinit_array function as the
90268d75effSDimitry Andric // vDSO function pointers haven't been initialized yet. __progname is
90368d75effSDimitry Andric // initialized after the vDSO function pointers, so if it exists, is not null
90468d75effSDimitry Andric // and is not empty, we can use clock_gettime.
90568d75effSDimitry Andric extern "C" SANITIZER_WEAK_ATTRIBUTE char *__progname;
CanUseVDSO()906fe6060f1SDimitry Andric inline bool CanUseVDSO() { return &__progname && __progname && *__progname; }
90768d75effSDimitry Andric 
90868d75effSDimitry Andric // MonotonicNanoTime is a timing function that can leverage the vDSO by calling
90968d75effSDimitry Andric // clock_gettime. real_clock_gettime only exists if clock_gettime is
91068d75effSDimitry Andric // intercepted, so define it weakly and use it if available.
9115f757f3fSDimitry Andric extern "C" SANITIZER_WEAK_ATTRIBUTE int real_clock_gettime(u32 clk_id,
9125f757f3fSDimitry Andric                                                            void *tp);
MonotonicNanoTime()91368d75effSDimitry Andric u64 MonotonicNanoTime() {
91468d75effSDimitry Andric   timespec ts;
91568d75effSDimitry Andric   if (CanUseVDSO()) {
91668d75effSDimitry Andric     if (&real_clock_gettime)
91768d75effSDimitry Andric       real_clock_gettime(CLOCK_MONOTONIC, &ts);
91868d75effSDimitry Andric     else
91968d75effSDimitry Andric       clock_gettime(CLOCK_MONOTONIC, &ts);
92068d75effSDimitry Andric   } else {
92168d75effSDimitry Andric     internal_clock_gettime(CLOCK_MONOTONIC, &ts);
92268d75effSDimitry Andric   }
92368d75effSDimitry Andric   return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec;
92468d75effSDimitry Andric }
92568d75effSDimitry Andric #  else
926fe6060f1SDimitry Andric // Non-glibc & Go always use the regular function.
MonotonicNanoTime()92768d75effSDimitry Andric u64 MonotonicNanoTime() {
92868d75effSDimitry Andric   timespec ts;
929fe6060f1SDimitry Andric   clock_gettime(CLOCK_MONOTONIC, &ts);
93068d75effSDimitry Andric   return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec;
93168d75effSDimitry Andric }
932fe6060f1SDimitry Andric #  endif  // SANITIZER_GLIBC && !SANITIZER_GO
93368d75effSDimitry Andric 
ReExec()93468d75effSDimitry Andric void ReExec() {
93568d75effSDimitry Andric   const char *pathname = "/proc/self/exe";
93668d75effSDimitry Andric 
93796fe7c8aSEd Maste #  if SANITIZER_FREEBSD
9384c9a0adaSDimitry Andric   for (const auto *aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) {
9394c9a0adaSDimitry Andric     if (aux->a_type == AT_EXECPATH) {
9404c9a0adaSDimitry Andric       pathname = static_cast<const char *>(aux->a_un.a_ptr);
9414c9a0adaSDimitry Andric       break;
9424c9a0adaSDimitry Andric     }
94396fe7c8aSEd Maste   }
94496fe7c8aSEd Maste #  elif SANITIZER_NETBSD
94568d75effSDimitry Andric   static const int name[] = {
94668d75effSDimitry Andric       CTL_KERN,
94768d75effSDimitry Andric       KERN_PROC_ARGS,
94868d75effSDimitry Andric       -1,
94968d75effSDimitry Andric       KERN_PROC_PATHNAME,
95068d75effSDimitry Andric   };
95168d75effSDimitry Andric   char path[400];
95268d75effSDimitry Andric   uptr len;
95368d75effSDimitry Andric 
95468d75effSDimitry Andric   len = sizeof(path);
95568d75effSDimitry Andric   if (internal_sysctl(name, ARRAY_SIZE(name), path, &len, NULL, 0) != -1)
95668d75effSDimitry Andric     pathname = path;
95768d75effSDimitry Andric #  elif SANITIZER_SOLARIS
95868d75effSDimitry Andric   pathname = getexecname();
95968d75effSDimitry Andric   CHECK_NE(pathname, NULL);
96068d75effSDimitry Andric #  elif SANITIZER_USE_GETAUXVAL
96168d75effSDimitry Andric   // Calling execve with /proc/self/exe sets that as $EXEC_ORIGIN. Binaries that
96268d75effSDimitry Andric   // rely on that will fail to load shared libraries. Query AT_EXECFN instead.
96368d75effSDimitry Andric   pathname = reinterpret_cast<const char *>(getauxval(AT_EXECFN));
96468d75effSDimitry Andric #  endif
96568d75effSDimitry Andric 
96668d75effSDimitry Andric   uptr rv = internal_execve(pathname, GetArgv(), GetEnviron());
96768d75effSDimitry Andric   int rverrno;
96868d75effSDimitry Andric   CHECK_EQ(internal_iserror(rv, &rverrno), true);
96968d75effSDimitry Andric   Printf("execve failed, errno %d\n", rverrno);
97068d75effSDimitry Andric   Die();
97168d75effSDimitry Andric }
972e8d8bef9SDimitry Andric 
UnmapFromTo(uptr from,uptr to)973e8d8bef9SDimitry Andric void UnmapFromTo(uptr from, uptr to) {
974e8d8bef9SDimitry Andric   if (to == from)
975e8d8bef9SDimitry Andric     return;
976e8d8bef9SDimitry Andric   CHECK(to >= from);
977e8d8bef9SDimitry Andric   uptr res = internal_munmap(reinterpret_cast<void *>(from), to - from);
978e8d8bef9SDimitry Andric   if (UNLIKELY(internal_iserror(res))) {
979e8d8bef9SDimitry Andric     Report("ERROR: %s failed to unmap 0x%zx (%zd) bytes at address %p\n",
980e8d8bef9SDimitry Andric            SanitizerToolName, to - from, to - from, (void *)from);
981e8d8bef9SDimitry Andric     CHECK("unable to unmap" && 0);
982e8d8bef9SDimitry Andric   }
983e8d8bef9SDimitry Andric }
984e8d8bef9SDimitry Andric 
MapDynamicShadow(uptr shadow_size_bytes,uptr shadow_scale,uptr min_shadow_base_alignment,UNUSED uptr & high_mem_end)985e8d8bef9SDimitry Andric uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
986e8d8bef9SDimitry Andric                       uptr min_shadow_base_alignment,
987e8d8bef9SDimitry Andric                       UNUSED uptr &high_mem_end) {
988e8d8bef9SDimitry Andric   const uptr granularity = GetMmapGranularity();
989e8d8bef9SDimitry Andric   const uptr alignment =
990e8d8bef9SDimitry Andric       Max<uptr>(granularity << shadow_scale, 1ULL << min_shadow_base_alignment);
991e8d8bef9SDimitry Andric   const uptr left_padding =
992e8d8bef9SDimitry Andric       Max<uptr>(granularity, 1ULL << min_shadow_base_alignment);
993e8d8bef9SDimitry Andric 
994e8d8bef9SDimitry Andric   const uptr shadow_size = RoundUpTo(shadow_size_bytes, granularity);
995e8d8bef9SDimitry Andric   const uptr map_size = shadow_size + left_padding + alignment;
996e8d8bef9SDimitry Andric 
997e8d8bef9SDimitry Andric   const uptr map_start = (uptr)MmapNoAccess(map_size);
998e8d8bef9SDimitry Andric   CHECK_NE(map_start, ~(uptr)0);
999e8d8bef9SDimitry Andric 
1000e8d8bef9SDimitry Andric   const uptr shadow_start = RoundUpTo(map_start + left_padding, alignment);
1001e8d8bef9SDimitry Andric 
1002e8d8bef9SDimitry Andric   UnmapFromTo(map_start, shadow_start - left_padding);
1003e8d8bef9SDimitry Andric   UnmapFromTo(shadow_start + shadow_size, map_start + map_size);
1004e8d8bef9SDimitry Andric 
1005e8d8bef9SDimitry Andric   return shadow_start;
1006e8d8bef9SDimitry Andric }
1007e8d8bef9SDimitry Andric 
MmapSharedNoReserve(uptr addr,uptr size)1008fe6060f1SDimitry Andric static uptr MmapSharedNoReserve(uptr addr, uptr size) {
1009fe6060f1SDimitry Andric   return internal_mmap(
1010fe6060f1SDimitry Andric       reinterpret_cast<void *>(addr), size, PROT_READ | PROT_WRITE,
1011fe6060f1SDimitry Andric       MAP_FIXED | MAP_SHARED | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
1012fe6060f1SDimitry Andric }
1013fe6060f1SDimitry Andric 
MremapCreateAlias(uptr base_addr,uptr alias_addr,uptr alias_size)1014fe6060f1SDimitry Andric static uptr MremapCreateAlias(uptr base_addr, uptr alias_addr,
1015fe6060f1SDimitry Andric                               uptr alias_size) {
1016fe6060f1SDimitry Andric #  if SANITIZER_LINUX
1017fe6060f1SDimitry Andric   return internal_mremap(reinterpret_cast<void *>(base_addr), 0, alias_size,
1018fe6060f1SDimitry Andric                          MREMAP_MAYMOVE | MREMAP_FIXED,
1019fe6060f1SDimitry Andric                          reinterpret_cast<void *>(alias_addr));
1020fe6060f1SDimitry Andric #  else
1021fe6060f1SDimitry Andric   CHECK(false && "mremap is not supported outside of Linux");
1022fe6060f1SDimitry Andric   return 0;
1023fe6060f1SDimitry Andric #  endif
1024fe6060f1SDimitry Andric }
1025fe6060f1SDimitry Andric 
CreateAliases(uptr start_addr,uptr alias_size,uptr num_aliases)1026fe6060f1SDimitry Andric static void CreateAliases(uptr start_addr, uptr alias_size, uptr num_aliases) {
1027fe6060f1SDimitry Andric   uptr total_size = alias_size * num_aliases;
1028fe6060f1SDimitry Andric   uptr mapped = MmapSharedNoReserve(start_addr, total_size);
1029fe6060f1SDimitry Andric   CHECK_EQ(mapped, start_addr);
1030fe6060f1SDimitry Andric 
1031fe6060f1SDimitry Andric   for (uptr i = 1; i < num_aliases; ++i) {
1032fe6060f1SDimitry Andric     uptr alias_addr = start_addr + i * alias_size;
1033fe6060f1SDimitry Andric     CHECK_EQ(MremapCreateAlias(start_addr, alias_addr, alias_size), alias_addr);
1034fe6060f1SDimitry Andric   }
1035fe6060f1SDimitry Andric }
1036fe6060f1SDimitry Andric 
MapDynamicShadowAndAliases(uptr shadow_size,uptr alias_size,uptr num_aliases,uptr ring_buffer_size)1037fe6060f1SDimitry Andric uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
1038fe6060f1SDimitry Andric                                 uptr num_aliases, uptr ring_buffer_size) {
1039fe6060f1SDimitry Andric   CHECK_EQ(alias_size & (alias_size - 1), 0);
1040fe6060f1SDimitry Andric   CHECK_EQ(num_aliases & (num_aliases - 1), 0);
1041fe6060f1SDimitry Andric   CHECK_EQ(ring_buffer_size & (ring_buffer_size - 1), 0);
1042fe6060f1SDimitry Andric 
1043fe6060f1SDimitry Andric   const uptr granularity = GetMmapGranularity();
1044fe6060f1SDimitry Andric   shadow_size = RoundUpTo(shadow_size, granularity);
1045fe6060f1SDimitry Andric   CHECK_EQ(shadow_size & (shadow_size - 1), 0);
1046fe6060f1SDimitry Andric 
1047fe6060f1SDimitry Andric   const uptr alias_region_size = alias_size * num_aliases;
1048fe6060f1SDimitry Andric   const uptr alignment =
1049fe6060f1SDimitry Andric       2 * Max(Max(shadow_size, alias_region_size), ring_buffer_size);
1050fe6060f1SDimitry Andric   const uptr left_padding = ring_buffer_size;
1051fe6060f1SDimitry Andric 
1052fe6060f1SDimitry Andric   const uptr right_size = alignment;
1053fe6060f1SDimitry Andric   const uptr map_size = left_padding + 2 * alignment;
1054fe6060f1SDimitry Andric 
1055fe6060f1SDimitry Andric   const uptr map_start = reinterpret_cast<uptr>(MmapNoAccess(map_size));
1056fe6060f1SDimitry Andric   CHECK_NE(map_start, static_cast<uptr>(-1));
1057fe6060f1SDimitry Andric   const uptr right_start = RoundUpTo(map_start + left_padding, alignment);
1058fe6060f1SDimitry Andric 
1059fe6060f1SDimitry Andric   UnmapFromTo(map_start, right_start - left_padding);
1060fe6060f1SDimitry Andric   UnmapFromTo(right_start + right_size, map_start + map_size);
1061fe6060f1SDimitry Andric 
1062fe6060f1SDimitry Andric   CreateAliases(right_start + right_size / 2, alias_size, num_aliases);
1063fe6060f1SDimitry Andric 
1064fe6060f1SDimitry Andric   return right_start;
1065fe6060f1SDimitry Andric }
1066fe6060f1SDimitry Andric 
InitializePlatformCommonFlags(CommonFlags * cf)1067e8d8bef9SDimitry Andric void InitializePlatformCommonFlags(CommonFlags *cf) {
1068e8d8bef9SDimitry Andric #  if SANITIZER_ANDROID
1069e8d8bef9SDimitry Andric   if (&__libc_get_static_tls_bounds == nullptr)
1070e8d8bef9SDimitry Andric     cf->detect_leaks = false;
1071e8d8bef9SDimitry Andric #  endif
1072e8d8bef9SDimitry Andric }
107368d75effSDimitry Andric 
107468d75effSDimitry Andric }  // namespace __sanitizer
107568d75effSDimitry Andric 
107668d75effSDimitry Andric #endif
1077