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));
57*0fca6ea1SDimitry Andric extern "C" int __sys_sigaction(int signum, const struct sigaction *act,
58*0fca6ea1SDimitry Andric struct sigaction *oldact);
5968d75effSDimitry Andric # endif
6068d75effSDimitry Andric
6168d75effSDimitry Andric # if SANITIZER_NETBSD
625f757f3fSDimitry Andric # include <lwp.h>
6368d75effSDimitry Andric # include <sys/sysctl.h>
6468d75effSDimitry Andric # include <sys/tls.h>
6568d75effSDimitry Andric # endif
6668d75effSDimitry Andric
6768d75effSDimitry Andric # if SANITIZER_SOLARIS
68fcaf7f86SDimitry Andric # include <stddef.h>
6968d75effSDimitry Andric # include <stdlib.h>
7068d75effSDimitry Andric # include <thread.h>
7168d75effSDimitry Andric # endif
7268d75effSDimitry Andric
7368d75effSDimitry Andric # if SANITIZER_ANDROID
7468d75effSDimitry Andric # include <android/api-level.h>
7568d75effSDimitry Andric # if !defined(CPU_COUNT) && !defined(__aarch64__)
7668d75effSDimitry Andric # include <dirent.h>
7768d75effSDimitry Andric # include <fcntl.h>
7868d75effSDimitry Andric struct __sanitizer::linux_dirent {
7968d75effSDimitry Andric long d_ino;
8068d75effSDimitry Andric off_t d_off;
8168d75effSDimitry Andric unsigned short d_reclen;
8268d75effSDimitry Andric char d_name[];
8368d75effSDimitry Andric };
8468d75effSDimitry Andric # endif
8568d75effSDimitry Andric # endif
8668d75effSDimitry Andric
8768d75effSDimitry Andric # if !SANITIZER_ANDROID
8868d75effSDimitry Andric # include <elf.h>
8968d75effSDimitry Andric # include <unistd.h>
9068d75effSDimitry Andric # endif
9168d75effSDimitry Andric
9268d75effSDimitry Andric namespace __sanitizer {
9368d75effSDimitry Andric
945f757f3fSDimitry Andric SANITIZER_WEAK_ATTRIBUTE int real_sigaction(int signum, const void *act,
955f757f3fSDimitry Andric void *oldact);
9668d75effSDimitry Andric
internal_sigaction(int signum,const void * act,void * oldact)9768d75effSDimitry Andric int internal_sigaction(int signum, const void *act, void *oldact) {
98*0fca6ea1SDimitry Andric # if SANITIZER_FREEBSD
99*0fca6ea1SDimitry Andric // On FreeBSD, call the sigaction syscall directly (part of libsys in FreeBSD
100*0fca6ea1SDimitry Andric // 15) since the libc version goes via a global interposing table. Due to
101*0fca6ea1SDimitry Andric // library initialization order the table can be relocated after the call to
102*0fca6ea1SDimitry Andric // InitializeDeadlySignals() which then crashes when dereferencing the
103*0fca6ea1SDimitry Andric // uninitialized pointer in libc.
104*0fca6ea1SDimitry Andric return __sys_sigaction(signum, (const struct sigaction *)act,
105*0fca6ea1SDimitry Andric (struct sigaction *)oldact);
106*0fca6ea1SDimitry Andric # else
10768d75effSDimitry Andric # if !SANITIZER_GO
10868d75effSDimitry Andric if (&real_sigaction)
10968d75effSDimitry Andric return real_sigaction(signum, act, oldact);
11068d75effSDimitry Andric # endif
11168d75effSDimitry Andric return sigaction(signum, (const struct sigaction *)act,
11268d75effSDimitry Andric (struct sigaction *)oldact);
113*0fca6ea1SDimitry Andric # endif
11468d75effSDimitry Andric }
11568d75effSDimitry Andric
GetThreadStackTopAndBottom(bool at_initialization,uptr * stack_top,uptr * stack_bottom)11668d75effSDimitry Andric void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
11768d75effSDimitry Andric uptr *stack_bottom) {
11868d75effSDimitry Andric CHECK(stack_top);
11968d75effSDimitry Andric CHECK(stack_bottom);
12068d75effSDimitry Andric if (at_initialization) {
12168d75effSDimitry Andric // This is the main thread. Libpthread may not be initialized yet.
12268d75effSDimitry Andric struct rlimit rl;
12368d75effSDimitry Andric CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
12468d75effSDimitry Andric
12568d75effSDimitry Andric // Find the mapping that contains a stack variable.
12668d75effSDimitry Andric MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
12768d75effSDimitry Andric if (proc_maps.Error()) {
12868d75effSDimitry Andric *stack_top = *stack_bottom = 0;
12968d75effSDimitry Andric return;
13068d75effSDimitry Andric }
13168d75effSDimitry Andric MemoryMappedSegment segment;
13268d75effSDimitry Andric uptr prev_end = 0;
13368d75effSDimitry Andric while (proc_maps.Next(&segment)) {
1345f757f3fSDimitry Andric if ((uptr)&rl < segment.end)
1355f757f3fSDimitry Andric break;
13668d75effSDimitry Andric prev_end = segment.end;
13768d75effSDimitry Andric }
13868d75effSDimitry Andric CHECK((uptr)&rl >= segment.start && (uptr)&rl < segment.end);
13968d75effSDimitry Andric
14068d75effSDimitry Andric // Get stacksize from rlimit, but clip it so that it does not overlap
14168d75effSDimitry Andric // with other mappings.
14268d75effSDimitry Andric uptr stacksize = rl.rlim_cur;
1435f757f3fSDimitry Andric if (stacksize > segment.end - prev_end)
1445f757f3fSDimitry Andric stacksize = segment.end - prev_end;
14568d75effSDimitry Andric // When running with unlimited stack size, we still want to set some limit.
14668d75effSDimitry Andric // The unlimited stack size is caused by 'ulimit -s unlimited'.
14768d75effSDimitry Andric // Also, for some reason, GNU make spawns subprocesses with unlimited stack.
14868d75effSDimitry Andric if (stacksize > kMaxThreadStackSize)
14968d75effSDimitry Andric stacksize = kMaxThreadStackSize;
15068d75effSDimitry Andric *stack_top = segment.end;
15168d75effSDimitry Andric *stack_bottom = segment.end - stacksize;
152*0fca6ea1SDimitry Andric
153*0fca6ea1SDimitry Andric uptr maxAddr = GetMaxUserVirtualAddress();
154*0fca6ea1SDimitry Andric // Edge case: the stack mapping on some systems may be off-by-one e.g.,
155*0fca6ea1SDimitry Andric // fffffffdf000-1000000000000 rw-p 00000000 00:00 0 [stack]
156*0fca6ea1SDimitry Andric // instead of:
157*0fca6ea1SDimitry Andric // fffffffdf000- ffffffffffff
158*0fca6ea1SDimitry Andric // The out-of-range stack_top can result in an invalid shadow address
159*0fca6ea1SDimitry Andric // calculation, since those usually assume the parameters are in range.
160*0fca6ea1SDimitry Andric if (*stack_top == maxAddr + 1)
161*0fca6ea1SDimitry Andric *stack_top = maxAddr;
162*0fca6ea1SDimitry Andric else
163*0fca6ea1SDimitry Andric CHECK_LE(*stack_top, maxAddr);
164*0fca6ea1SDimitry Andric
16568d75effSDimitry Andric return;
16668d75effSDimitry Andric }
16768d75effSDimitry Andric uptr stacksize = 0;
16868d75effSDimitry Andric void *stackaddr = nullptr;
16968d75effSDimitry Andric # if SANITIZER_SOLARIS
17068d75effSDimitry Andric stack_t ss;
17168d75effSDimitry Andric CHECK_EQ(thr_stksegment(&ss), 0);
17268d75effSDimitry Andric stacksize = ss.ss_size;
17368d75effSDimitry Andric stackaddr = (char *)ss.ss_sp - stacksize;
17468d75effSDimitry Andric # else // !SANITIZER_SOLARIS
17568d75effSDimitry Andric pthread_attr_t attr;
17668d75effSDimitry Andric pthread_attr_init(&attr);
17768d75effSDimitry Andric CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
17806c3fb27SDimitry Andric internal_pthread_attr_getstack(&attr, &stackaddr, &stacksize);
17968d75effSDimitry Andric pthread_attr_destroy(&attr);
18068d75effSDimitry Andric # endif // SANITIZER_SOLARIS
18168d75effSDimitry Andric
18268d75effSDimitry Andric *stack_top = (uptr)stackaddr + stacksize;
18368d75effSDimitry Andric *stack_bottom = (uptr)stackaddr;
18468d75effSDimitry Andric }
18568d75effSDimitry Andric
18668d75effSDimitry Andric # if !SANITIZER_GO
SetEnv(const char * name,const char * value)18768d75effSDimitry Andric bool SetEnv(const char *name, const char *value) {
18868d75effSDimitry Andric void *f = dlsym(RTLD_NEXT, "setenv");
18968d75effSDimitry Andric if (!f)
19068d75effSDimitry Andric return false;
19168d75effSDimitry Andric typedef int (*setenv_ft)(const char *name, const char *value, int overwrite);
19268d75effSDimitry Andric setenv_ft setenv_f;
19368d75effSDimitry Andric CHECK_EQ(sizeof(setenv_f), sizeof(f));
19468d75effSDimitry Andric internal_memcpy(&setenv_f, &f, sizeof(f));
19568d75effSDimitry Andric return setenv_f(name, value, 1) == 0;
19668d75effSDimitry Andric }
19768d75effSDimitry Andric # endif
19868d75effSDimitry Andric
GetLibcVersion(int * major,int * minor,int * patch)19968d75effSDimitry Andric __attribute__((unused)) static bool GetLibcVersion(int *major, int *minor,
20068d75effSDimitry Andric int *patch) {
20168d75effSDimitry Andric # ifdef _CS_GNU_LIBC_VERSION
20268d75effSDimitry Andric char buf[64];
20368d75effSDimitry Andric uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf));
20468d75effSDimitry Andric if (len >= sizeof(buf))
20568d75effSDimitry Andric return false;
20668d75effSDimitry Andric buf[len] = 0;
20768d75effSDimitry Andric static const char kGLibC[] = "glibc ";
20868d75effSDimitry Andric if (internal_strncmp(buf, kGLibC, sizeof(kGLibC) - 1) != 0)
20968d75effSDimitry Andric return false;
21068d75effSDimitry Andric const char *p = buf + sizeof(kGLibC) - 1;
21168d75effSDimitry Andric *major = internal_simple_strtoll(p, &p, 10);
21268d75effSDimitry Andric *minor = (*p == '.') ? internal_simple_strtoll(p + 1, &p, 10) : 0;
21368d75effSDimitry Andric *patch = (*p == '.') ? internal_simple_strtoll(p + 1, &p, 10) : 0;
21468d75effSDimitry Andric return true;
21568d75effSDimitry Andric # else
21668d75effSDimitry Andric return false;
21768d75effSDimitry Andric # endif
21868d75effSDimitry Andric }
21968d75effSDimitry Andric
220fe6060f1SDimitry Andric // True if we can use dlpi_tls_data. glibc before 2.25 may leave NULL (BZ
221fe6060f1SDimitry Andric // #19826) so dlpi_tls_data cannot be used.
222fe6060f1SDimitry Andric //
223fe6060f1SDimitry Andric // musl before 1.2.3 and FreeBSD as of 12.2 incorrectly set dlpi_tls_data to
224fe6060f1SDimitry Andric // the TLS initialization image
225fe6060f1SDimitry Andric // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=254774
226fe6060f1SDimitry Andric __attribute__((unused)) static int g_use_dlpi_tls_data;
227fe6060f1SDimitry Andric
228e8d8bef9SDimitry Andric # if SANITIZER_GLIBC && !SANITIZER_GO
229fe6060f1SDimitry Andric __attribute__((unused)) static size_t g_tls_size;
InitTlsSize()23068d75effSDimitry Andric void InitTlsSize() {
231fe6060f1SDimitry Andric int major, minor, patch;
232fe6060f1SDimitry Andric g_use_dlpi_tls_data =
233fe6060f1SDimitry Andric GetLibcVersion(&major, &minor, &patch) && major == 2 && minor >= 25;
234fe6060f1SDimitry Andric
2355f757f3fSDimitry Andric # if defined(__aarch64__) || defined(__x86_64__) || \
2365f757f3fSDimitry Andric defined(__powerpc64__) || defined(__loongarch__)
237fe6060f1SDimitry Andric void *get_tls_static_info = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
238fe6060f1SDimitry Andric size_t tls_align;
239fe6060f1SDimitry Andric ((void (*)(size_t *, size_t *))get_tls_static_info)(&g_tls_size, &tls_align);
240fe6060f1SDimitry Andric # endif
24168d75effSDimitry Andric }
24268d75effSDimitry Andric # else
InitTlsSize()24368d75effSDimitry Andric void InitTlsSize() {}
244e8d8bef9SDimitry Andric # endif // SANITIZER_GLIBC && !SANITIZER_GO
24568d75effSDimitry Andric
246fe6060f1SDimitry Andric // On glibc x86_64, ThreadDescriptorSize() needs to be precise due to the usage
247fe6060f1SDimitry Andric // of g_tls_size. On other targets, ThreadDescriptorSize() is only used by lsan
248fe6060f1SDimitry Andric // to get the pointer to thread-specific data keys in the thread control block.
24981ad6265SDimitry Andric # if (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_SOLARIS) && \
25081ad6265SDimitry Andric !SANITIZER_ANDROID && !SANITIZER_GO
25168d75effSDimitry Andric // sizeof(struct pthread) from glibc.
25268d75effSDimitry Andric static atomic_uintptr_t thread_descriptor_size;
25368d75effSDimitry Andric
ThreadDescriptorSizeFallback()254d56accc7SDimitry Andric static uptr ThreadDescriptorSizeFallback() {
255d56accc7SDimitry Andric uptr val = 0;
25668d75effSDimitry Andric # if defined(__x86_64__) || defined(__i386__) || defined(__arm__)
25768d75effSDimitry Andric int major;
25868d75effSDimitry Andric int minor;
25968d75effSDimitry Andric int patch;
26068d75effSDimitry Andric if (GetLibcVersion(&major, &minor, &patch) && major == 2) {
26168d75effSDimitry Andric /* sizeof(struct pthread) values from various glibc versions. */
26268d75effSDimitry Andric if (SANITIZER_X32)
26368d75effSDimitry Andric val = 1728; // Assume only one particular version for x32.
26468d75effSDimitry Andric // For ARM sizeof(struct pthread) changed in Glibc 2.23.
26568d75effSDimitry Andric else if (SANITIZER_ARM)
26668d75effSDimitry Andric val = minor <= 22 ? 1120 : 1216;
26768d75effSDimitry Andric else if (minor <= 3)
26868d75effSDimitry Andric val = FIRST_32_SECOND_64(1104, 1696);
26968d75effSDimitry Andric else if (minor == 4)
27068d75effSDimitry Andric val = FIRST_32_SECOND_64(1120, 1728);
27168d75effSDimitry Andric else if (minor == 5)
27268d75effSDimitry Andric val = FIRST_32_SECOND_64(1136, 1728);
27368d75effSDimitry Andric else if (minor <= 9)
27468d75effSDimitry Andric val = FIRST_32_SECOND_64(1136, 1712);
27568d75effSDimitry Andric else if (minor == 10)
27668d75effSDimitry Andric val = FIRST_32_SECOND_64(1168, 1776);
27768d75effSDimitry Andric else if (minor == 11 || (minor == 12 && patch == 1))
27868d75effSDimitry Andric val = FIRST_32_SECOND_64(1168, 2288);
27968d75effSDimitry Andric else if (minor <= 14)
28068d75effSDimitry Andric val = FIRST_32_SECOND_64(1168, 2304);
281e8d8bef9SDimitry Andric else if (minor < 32) // Unknown version
28268d75effSDimitry Andric val = FIRST_32_SECOND_64(1216, 2304);
283e8d8bef9SDimitry Andric else // minor == 32
284e8d8bef9SDimitry Andric val = FIRST_32_SECOND_64(1344, 2496);
28568d75effSDimitry Andric }
286fe6060f1SDimitry Andric # elif defined(__s390__) || defined(__sparc__)
287fe6060f1SDimitry Andric // The size of a prefix of TCB including pthread::{specific_1stblock,specific}
288fe6060f1SDimitry Andric // suffices. Just return offsetof(struct pthread, specific_used), which hasn't
289fe6060f1SDimitry Andric // changed since 2007-05. Technically this applies to i386/x86_64 as well but
290fe6060f1SDimitry Andric // we call _dl_get_tls_static_info and need the precise size of struct
291fe6060f1SDimitry Andric // pthread.
292fe6060f1SDimitry Andric return FIRST_32_SECOND_64(524, 1552);
29368d75effSDimitry Andric # elif defined(__mips__)
29468d75effSDimitry Andric // TODO(sagarthakur): add more values as per different glibc versions.
29568d75effSDimitry Andric val = FIRST_32_SECOND_64(1152, 1776);
296bdd1243dSDimitry Andric # elif SANITIZER_LOONGARCH64
297bdd1243dSDimitry Andric val = 1856; // from glibc 2.36
298e8d8bef9SDimitry Andric # elif SANITIZER_RISCV64
299e8d8bef9SDimitry Andric int major;
300e8d8bef9SDimitry Andric int minor;
301e8d8bef9SDimitry Andric int patch;
302e8d8bef9SDimitry Andric if (GetLibcVersion(&major, &minor, &patch) && major == 2) {
303e8d8bef9SDimitry Andric // TODO: consider adding an optional runtime check for an unknown (untested)
304e8d8bef9SDimitry Andric // glibc version
305e8d8bef9SDimitry Andric if (minor <= 28) // WARNING: the highest tested version is 2.29
306e8d8bef9SDimitry Andric val = 1772; // no guarantees for this one
307e8d8bef9SDimitry Andric else if (minor <= 31)
308e8d8bef9SDimitry Andric val = 1772; // tested against glibc 2.29, 2.31
309e8d8bef9SDimitry Andric else
310e8d8bef9SDimitry Andric val = 1936; // tested against glibc 2.32
311e8d8bef9SDimitry Andric }
312e8d8bef9SDimitry Andric
31368d75effSDimitry Andric # elif defined(__aarch64__)
31468d75effSDimitry Andric // The sizeof (struct pthread) is the same from GLIBC 2.17 to 2.22.
31568d75effSDimitry Andric val = 1776;
31668d75effSDimitry Andric # elif defined(__powerpc64__)
31768d75effSDimitry Andric val = 1776; // from glibc.ppc64le 2.20-8.fc21
31868d75effSDimitry Andric # endif
319d56accc7SDimitry Andric return val;
320d56accc7SDimitry Andric }
321d56accc7SDimitry Andric
ThreadDescriptorSize()322d56accc7SDimitry Andric uptr ThreadDescriptorSize() {
323d56accc7SDimitry Andric uptr val = atomic_load_relaxed(&thread_descriptor_size);
32468d75effSDimitry Andric if (val)
325d56accc7SDimitry Andric return val;
326d56accc7SDimitry Andric // _thread_db_sizeof_pthread is a GLIBC_PRIVATE symbol that is exported in
327d56accc7SDimitry Andric // glibc 2.34 and later.
328d56accc7SDimitry Andric if (unsigned *psizeof = static_cast<unsigned *>(
329d56accc7SDimitry Andric dlsym(RTLD_DEFAULT, "_thread_db_sizeof_pthread")))
330d56accc7SDimitry Andric val = *psizeof;
331d56accc7SDimitry Andric if (!val)
332d56accc7SDimitry Andric val = ThreadDescriptorSizeFallback();
33368d75effSDimitry Andric atomic_store_relaxed(&thread_descriptor_size, val);
33468d75effSDimitry Andric return val;
33568d75effSDimitry Andric }
33668d75effSDimitry Andric
337bdd1243dSDimitry Andric # if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64 || \
338bdd1243dSDimitry Andric SANITIZER_LOONGARCH64
33968d75effSDimitry Andric // TlsPreTcbSize includes size of struct pthread_descr and size of tcb
34068d75effSDimitry Andric // head structure. It lies before the static tls blocks.
TlsPreTcbSize()34168d75effSDimitry Andric static uptr TlsPreTcbSize() {
34268d75effSDimitry Andric # if defined(__mips__)
34368d75effSDimitry Andric const uptr kTcbHead = 16; // sizeof (tcbhead_t)
34468d75effSDimitry Andric # elif defined(__powerpc64__)
34568d75effSDimitry Andric const uptr kTcbHead = 88; // sizeof (tcbhead_t)
346e8d8bef9SDimitry Andric # elif SANITIZER_RISCV64
347e8d8bef9SDimitry Andric const uptr kTcbHead = 16; // sizeof (tcbhead_t)
348bdd1243dSDimitry Andric # elif SANITIZER_LOONGARCH64
349bdd1243dSDimitry Andric const uptr kTcbHead = 16; // sizeof (tcbhead_t)
35068d75effSDimitry Andric # endif
35168d75effSDimitry Andric const uptr kTlsAlign = 16;
35268d75effSDimitry Andric const uptr kTlsPreTcbSize =
35368d75effSDimitry Andric RoundUpTo(ThreadDescriptorSize() + kTcbHead, kTlsAlign);
35468d75effSDimitry Andric return kTlsPreTcbSize;
35568d75effSDimitry Andric }
35668d75effSDimitry Andric # endif
35768d75effSDimitry Andric
358fe6060f1SDimitry Andric namespace {
359fe6060f1SDimitry Andric struct TlsBlock {
360fe6060f1SDimitry Andric uptr begin, end, align;
361fe6060f1SDimitry Andric size_t tls_modid;
operator <__sanitizer::__anon97c5c1cd0111::TlsBlock362fe6060f1SDimitry Andric bool operator<(const TlsBlock &rhs) const { return begin < rhs.begin; }
363fe6060f1SDimitry Andric };
364fe6060f1SDimitry Andric } // namespace
36568d75effSDimitry Andric
366fe6060f1SDimitry Andric # ifdef __s390__
367fe6060f1SDimitry Andric extern "C" uptr __tls_get_offset(void *arg);
368fe6060f1SDimitry Andric
TlsGetOffset(uptr ti_module,uptr ti_offset)369fe6060f1SDimitry Andric static uptr TlsGetOffset(uptr ti_module, uptr ti_offset) {
370fe6060f1SDimitry Andric // The __tls_get_offset ABI requires %r12 to point to GOT and %r2 to be an
371fe6060f1SDimitry Andric // offset of a struct tls_index inside GOT. We don't possess either of the
372fe6060f1SDimitry Andric // two, so violate the letter of the "ELF Handling For Thread-Local
373fe6060f1SDimitry Andric // Storage" document and assume that the implementation just dereferences
374fe6060f1SDimitry Andric // %r2 + %r12.
375fe6060f1SDimitry Andric uptr tls_index[2] = {ti_module, ti_offset};
376fe6060f1SDimitry Andric register uptr r2 asm("2") = 0;
377fe6060f1SDimitry Andric register void *r12 asm("12") = tls_index;
378fe6060f1SDimitry Andric asm("basr %%r14, %[__tls_get_offset]"
379fe6060f1SDimitry Andric : "+r"(r2)
380fe6060f1SDimitry Andric : [__tls_get_offset] "r"(__tls_get_offset), "r"(r12)
381fe6060f1SDimitry Andric : "memory", "cc", "0", "1", "3", "4", "5", "14");
382fe6060f1SDimitry Andric return r2;
383fe6060f1SDimitry Andric }
38468d75effSDimitry Andric # else
385fe6060f1SDimitry Andric extern "C" void *__tls_get_addr(size_t *);
38668d75effSDimitry Andric # endif
387fe6060f1SDimitry Andric
388fcaf7f86SDimitry Andric static size_t main_tls_modid;
389fcaf7f86SDimitry Andric
CollectStaticTlsBlocks(struct dl_phdr_info * info,size_t size,void * data)390fe6060f1SDimitry Andric static int CollectStaticTlsBlocks(struct dl_phdr_info *info, size_t size,
391fe6060f1SDimitry Andric void *data) {
392fcaf7f86SDimitry Andric size_t tls_modid;
393fcaf7f86SDimitry Andric # if SANITIZER_SOLARIS
394fcaf7f86SDimitry Andric // dlpi_tls_modid is only available since Solaris 11.4 SRU 10. Use
395fcaf7f86SDimitry Andric // dlinfo(RTLD_DI_LINKMAP) instead which works on all of Solaris 11.3,
396fcaf7f86SDimitry Andric // 11.4, and Illumos. The tlsmodid of the executable was changed to 1 in
397fcaf7f86SDimitry Andric // 11.4 to match other implementations.
398fcaf7f86SDimitry Andric if (size >= offsetof(dl_phdr_info_test, dlpi_tls_modid))
399fcaf7f86SDimitry Andric main_tls_modid = 1;
400fcaf7f86SDimitry Andric else
401fcaf7f86SDimitry Andric main_tls_modid = 0;
402fcaf7f86SDimitry Andric g_use_dlpi_tls_data = 0;
403fcaf7f86SDimitry Andric Rt_map *map;
404fcaf7f86SDimitry Andric dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &map);
405fcaf7f86SDimitry Andric tls_modid = map->rt_tlsmodid;
406fcaf7f86SDimitry Andric # else
407fcaf7f86SDimitry Andric main_tls_modid = 1;
408fcaf7f86SDimitry Andric tls_modid = info->dlpi_tls_modid;
409fcaf7f86SDimitry Andric # endif
410fcaf7f86SDimitry Andric
411fcaf7f86SDimitry Andric if (tls_modid < main_tls_modid)
412fe6060f1SDimitry Andric return 0;
413fcaf7f86SDimitry Andric uptr begin;
414fcaf7f86SDimitry Andric # if !SANITIZER_SOLARIS
415fcaf7f86SDimitry Andric begin = (uptr)info->dlpi_tls_data;
416fcaf7f86SDimitry Andric # endif
417fe6060f1SDimitry Andric if (!g_use_dlpi_tls_data) {
418fe6060f1SDimitry Andric // Call __tls_get_addr as a fallback. This forces TLS allocation on glibc
419fe6060f1SDimitry Andric // and FreeBSD.
420fe6060f1SDimitry Andric # ifdef __s390__
4215f757f3fSDimitry Andric begin = (uptr)__builtin_thread_pointer() + TlsGetOffset(tls_modid, 0);
422fe6060f1SDimitry Andric # else
423fcaf7f86SDimitry Andric size_t mod_and_off[2] = {tls_modid, 0};
424fe6060f1SDimitry Andric begin = (uptr)__tls_get_addr(mod_and_off);
425fe6060f1SDimitry Andric # endif
426fe6060f1SDimitry Andric }
427fe6060f1SDimitry Andric for (unsigned i = 0; i != info->dlpi_phnum; ++i)
428fe6060f1SDimitry Andric if (info->dlpi_phdr[i].p_type == PT_TLS) {
429fe6060f1SDimitry Andric static_cast<InternalMmapVector<TlsBlock> *>(data)->push_back(
430fe6060f1SDimitry Andric TlsBlock{begin, begin + info->dlpi_phdr[i].p_memsz,
431fcaf7f86SDimitry Andric info->dlpi_phdr[i].p_align, tls_modid});
432fe6060f1SDimitry Andric break;
433fe6060f1SDimitry Andric }
434fe6060f1SDimitry Andric return 0;
43568d75effSDimitry Andric }
43668d75effSDimitry Andric
GetStaticTlsBoundary(uptr * addr,uptr * size,uptr * align)437fe6060f1SDimitry Andric __attribute__((unused)) static void GetStaticTlsBoundary(uptr *addr, uptr *size,
438fe6060f1SDimitry Andric uptr *align) {
439fe6060f1SDimitry Andric InternalMmapVector<TlsBlock> ranges;
440fe6060f1SDimitry Andric dl_iterate_phdr(CollectStaticTlsBlocks, &ranges);
441fe6060f1SDimitry Andric uptr len = ranges.size();
442fe6060f1SDimitry Andric Sort(ranges.begin(), len);
443fcaf7f86SDimitry Andric // Find the range with tls_modid == main_tls_modid. For glibc, because
444fcaf7f86SDimitry Andric // libc.so uses PT_TLS, this module is guaranteed to exist and is one of
445fcaf7f86SDimitry Andric // the initially loaded modules.
446fe6060f1SDimitry Andric uptr one = 0;
447fcaf7f86SDimitry Andric while (one != len && ranges[one].tls_modid != main_tls_modid) ++one;
448fe6060f1SDimitry Andric if (one == len) {
449fe6060f1SDimitry Andric // This may happen with musl if no module uses PT_TLS.
450fe6060f1SDimitry Andric *addr = 0;
451fe6060f1SDimitry Andric *size = 0;
452fe6060f1SDimitry Andric *align = 1;
453fe6060f1SDimitry Andric return;
45468d75effSDimitry Andric }
455fe6060f1SDimitry Andric // Find the maximum consecutive ranges. We consider two modules consecutive if
456fcaf7f86SDimitry Andric // the gap is smaller than the alignment of the latter range. The dynamic
457fcaf7f86SDimitry Andric // loader places static TLS blocks this way not to waste space.
458fe6060f1SDimitry Andric uptr l = one;
459fe6060f1SDimitry Andric *align = ranges[l].align;
460fcaf7f86SDimitry Andric while (l != 0 && ranges[l].begin < ranges[l - 1].end + ranges[l].align)
461fe6060f1SDimitry Andric *align = Max(*align, ranges[--l].align);
462fe6060f1SDimitry Andric uptr r = one + 1;
463fcaf7f86SDimitry Andric while (r != len && ranges[r].begin < ranges[r - 1].end + ranges[r].align)
464fe6060f1SDimitry Andric *align = Max(*align, ranges[r++].align);
465fe6060f1SDimitry Andric *addr = ranges[l].begin;
466fe6060f1SDimitry Andric *size = ranges[r - 1].end - ranges[l].begin;
467fe6060f1SDimitry Andric }
468fe6060f1SDimitry Andric # endif // (x86_64 || i386 || mips || ...) && (SANITIZER_FREEBSD ||
469d56accc7SDimitry Andric // SANITIZER_LINUX) && !SANITIZER_ANDROID && !SANITIZER_GO
47068d75effSDimitry Andric
47168d75effSDimitry Andric # if SANITIZER_NETBSD
ThreadSelfTlsTcb()47268d75effSDimitry Andric static struct tls_tcb *ThreadSelfTlsTcb() {
473e8d8bef9SDimitry Andric struct tls_tcb *tcb = nullptr;
474e8d8bef9SDimitry Andric # ifdef __HAVE___LWP_GETTCB_FAST
475e8d8bef9SDimitry Andric tcb = (struct tls_tcb *)__lwp_gettcb_fast();
476e8d8bef9SDimitry Andric # elif defined(__HAVE___LWP_GETPRIVATE_FAST)
477e8d8bef9SDimitry Andric tcb = (struct tls_tcb *)__lwp_getprivate_fast();
478e8d8bef9SDimitry Andric # endif
479e8d8bef9SDimitry Andric return tcb;
48068d75effSDimitry Andric }
48168d75effSDimitry Andric
ThreadSelf()4825f757f3fSDimitry Andric uptr ThreadSelf() { return (uptr)ThreadSelfTlsTcb()->tcb_pthread; }
48368d75effSDimitry Andric
GetSizeFromHdr(struct dl_phdr_info * info,size_t size,void * data)48468d75effSDimitry Andric int GetSizeFromHdr(struct dl_phdr_info *info, size_t size, void *data) {
48568d75effSDimitry Andric const Elf_Phdr *hdr = info->dlpi_phdr;
48668d75effSDimitry Andric const Elf_Phdr *last_hdr = hdr + info->dlpi_phnum;
48768d75effSDimitry Andric
48868d75effSDimitry Andric for (; hdr != last_hdr; ++hdr) {
48968d75effSDimitry Andric if (hdr->p_type == PT_TLS && info->dlpi_tls_modid == 1) {
49068d75effSDimitry Andric *(uptr *)data = hdr->p_memsz;
49168d75effSDimitry Andric break;
49268d75effSDimitry Andric }
49368d75effSDimitry Andric }
49468d75effSDimitry Andric return 0;
49568d75effSDimitry Andric }
49668d75effSDimitry Andric # endif // SANITIZER_NETBSD
49768d75effSDimitry Andric
498e8d8bef9SDimitry Andric # if SANITIZER_ANDROID
499e8d8bef9SDimitry Andric // Bionic provides this API since S.
500e8d8bef9SDimitry Andric extern "C" SANITIZER_WEAK_ATTRIBUTE void __libc_get_static_tls_bounds(void **,
501e8d8bef9SDimitry Andric void **);
502e8d8bef9SDimitry Andric # endif
503e8d8bef9SDimitry Andric
50468d75effSDimitry Andric # if !SANITIZER_GO
GetTls(uptr * addr,uptr * size)50568d75effSDimitry Andric static void GetTls(uptr *addr, uptr *size) {
506e8d8bef9SDimitry Andric # if SANITIZER_ANDROID
507e8d8bef9SDimitry Andric if (&__libc_get_static_tls_bounds) {
508e8d8bef9SDimitry Andric void *start_addr;
509e8d8bef9SDimitry Andric void *end_addr;
510e8d8bef9SDimitry Andric __libc_get_static_tls_bounds(&start_addr, &end_addr);
511e8d8bef9SDimitry Andric *addr = reinterpret_cast<uptr>(start_addr);
512e8d8bef9SDimitry Andric *size =
513e8d8bef9SDimitry Andric reinterpret_cast<uptr>(end_addr) - reinterpret_cast<uptr>(start_addr);
514e8d8bef9SDimitry Andric } else {
515e8d8bef9SDimitry Andric *addr = 0;
516e8d8bef9SDimitry Andric *size = 0;
517e8d8bef9SDimitry Andric }
518fe6060f1SDimitry Andric # elif SANITIZER_GLIBC && defined(__x86_64__)
519fe6060f1SDimitry Andric // For aarch64 and x86-64, use an O(1) approach which requires relatively
520fe6060f1SDimitry Andric // precise ThreadDescriptorSize. g_tls_size was initialized in InitTlsSize.
52181ad6265SDimitry Andric # if SANITIZER_X32
52281ad6265SDimitry Andric asm("mov %%fs:8,%0" : "=r"(*addr));
52381ad6265SDimitry Andric # else
524fe6060f1SDimitry Andric asm("mov %%fs:16,%0" : "=r"(*addr));
52581ad6265SDimitry Andric # endif
526fe6060f1SDimitry Andric *size = g_tls_size;
52768d75effSDimitry Andric *addr -= *size;
52868d75effSDimitry Andric *addr += ThreadDescriptorSize();
529fe6060f1SDimitry Andric # elif SANITIZER_GLIBC && defined(__aarch64__)
530fe6060f1SDimitry Andric *addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
531fe6060f1SDimitry Andric ThreadDescriptorSize();
532fe6060f1SDimitry Andric *size = g_tls_size + ThreadDescriptorSize();
533bdd1243dSDimitry Andric # elif SANITIZER_GLIBC && defined(__loongarch__)
534bdd1243dSDimitry Andric # ifdef __clang__
535bdd1243dSDimitry Andric *addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
536bdd1243dSDimitry Andric ThreadDescriptorSize();
537bdd1243dSDimitry Andric # else
538bdd1243dSDimitry Andric asm("or %0,$tp,$zero" : "=r"(*addr));
539bdd1243dSDimitry Andric *addr -= ThreadDescriptorSize();
540bdd1243dSDimitry Andric # endif
541bdd1243dSDimitry Andric *size = g_tls_size + ThreadDescriptorSize();
542fe6060f1SDimitry Andric # elif SANITIZER_GLIBC && defined(__powerpc64__)
543fe6060f1SDimitry Andric // Workaround for glibc<2.25(?). 2.27 is known to not need this.
544fe6060f1SDimitry Andric uptr tp;
545fe6060f1SDimitry Andric asm("addi %0,13,-0x7000" : "=r"(tp));
546fe6060f1SDimitry Andric const uptr pre_tcb_size = TlsPreTcbSize();
547fe6060f1SDimitry Andric *addr = tp - pre_tcb_size;
548fe6060f1SDimitry Andric *size = g_tls_size + pre_tcb_size;
54981ad6265SDimitry Andric # elif SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_SOLARIS
550fe6060f1SDimitry Andric uptr align;
551fe6060f1SDimitry Andric GetStaticTlsBoundary(addr, size, &align);
552fe6060f1SDimitry Andric # if defined(__x86_64__) || defined(__i386__) || defined(__s390__) || \
553fe6060f1SDimitry Andric defined(__sparc__)
554fe6060f1SDimitry Andric if (SANITIZER_GLIBC) {
555fe6060f1SDimitry Andric # if defined(__x86_64__) || defined(__i386__)
556fe6060f1SDimitry Andric align = Max<uptr>(align, 64);
55768d75effSDimitry Andric # else
558fe6060f1SDimitry Andric align = Max<uptr>(align, 16);
55968d75effSDimitry Andric # endif
56068d75effSDimitry Andric }
561fe6060f1SDimitry Andric const uptr tp = RoundUpTo(*addr + *size, align);
562fe6060f1SDimitry Andric
563fe6060f1SDimitry Andric // lsan requires the range to additionally cover the static TLS surplus
564fe6060f1SDimitry Andric // (elf/dl-tls.c defines 1664). Otherwise there may be false positives for
565fe6060f1SDimitry Andric // allocations only referenced by tls in dynamically loaded modules.
566fe6060f1SDimitry Andric if (SANITIZER_GLIBC)
567fe6060f1SDimitry Andric *size += 1644;
568fe6060f1SDimitry Andric else if (SANITIZER_FREEBSD)
569fe6060f1SDimitry Andric *size += 128; // RTLD_STATIC_TLS_EXTRA
570fe6060f1SDimitry Andric
571fe6060f1SDimitry Andric // Extend the range to include the thread control block. On glibc, lsan needs
572fe6060f1SDimitry Andric // the range to include pthread::{specific_1stblock,specific} so that
573fe6060f1SDimitry Andric // allocations only referenced by pthread_setspecific can be scanned. This may
574fe6060f1SDimitry Andric // underestimate by at most TLS_TCB_ALIGN-1 bytes but it should be fine
575fe6060f1SDimitry Andric // because the number of bytes after pthread::specific is larger.
576fe6060f1SDimitry Andric *addr = tp - RoundUpTo(*size, align);
577fe6060f1SDimitry Andric *size = tp - *addr + ThreadDescriptorSize();
578fe6060f1SDimitry Andric # else
579fe6060f1SDimitry Andric if (SANITIZER_GLIBC)
580fe6060f1SDimitry Andric *size += 1664;
581fe6060f1SDimitry Andric else if (SANITIZER_FREEBSD)
582fe6060f1SDimitry Andric *size += 128; // RTLD_STATIC_TLS_EXTRA
583fe6060f1SDimitry Andric # if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
584fe6060f1SDimitry Andric const uptr pre_tcb_size = TlsPreTcbSize();
585fe6060f1SDimitry Andric *addr -= pre_tcb_size;
586fe6060f1SDimitry Andric *size += pre_tcb_size;
587fe6060f1SDimitry Andric # else
588fe6060f1SDimitry Andric // arm and aarch64 reserve two words at TP, so this underestimates the range.
589fe6060f1SDimitry Andric // However, this is sufficient for the purpose of finding the pointers to
590fe6060f1SDimitry Andric // thread-specific data keys.
591fe6060f1SDimitry Andric const uptr tcb_size = ThreadDescriptorSize();
592fe6060f1SDimitry Andric *addr -= tcb_size;
593fe6060f1SDimitry Andric *size += tcb_size;
594fe6060f1SDimitry Andric # endif
595fe6060f1SDimitry Andric # endif
59668d75effSDimitry Andric # elif SANITIZER_NETBSD
59768d75effSDimitry Andric struct tls_tcb *const tcb = ThreadSelfTlsTcb();
59868d75effSDimitry Andric *addr = 0;
59968d75effSDimitry Andric *size = 0;
60068d75effSDimitry Andric if (tcb != 0) {
60168d75effSDimitry Andric // Find size (p_memsz) of dlpi_tls_modid 1 (TLS block of the main program).
60268d75effSDimitry Andric // ld.elf_so hardcodes the index 1.
60368d75effSDimitry Andric dl_iterate_phdr(GetSizeFromHdr, size);
60468d75effSDimitry Andric
60568d75effSDimitry Andric if (*size != 0) {
60668d75effSDimitry Andric // The block has been found and tcb_dtv[1] contains the base address
60768d75effSDimitry Andric *addr = (uptr)tcb->tcb_dtv[1];
60868d75effSDimitry Andric }
60968d75effSDimitry Andric }
6101ac55f4cSDimitry Andric # else
61168d75effSDimitry Andric # error "Unknown OS"
61268d75effSDimitry Andric # endif
61368d75effSDimitry Andric }
61468d75effSDimitry Andric # endif
61568d75effSDimitry Andric
61668d75effSDimitry Andric # if !SANITIZER_GO
GetTlsSize()61768d75effSDimitry Andric uptr GetTlsSize() {
618fe6060f1SDimitry Andric # if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
619e8d8bef9SDimitry Andric SANITIZER_SOLARIS
62068d75effSDimitry Andric uptr addr, size;
62168d75effSDimitry Andric GetTls(&addr, &size);
62268d75effSDimitry Andric return size;
623e8d8bef9SDimitry Andric # else
624e8d8bef9SDimitry Andric return 0;
625e8d8bef9SDimitry Andric # endif
62668d75effSDimitry Andric }
62768d75effSDimitry Andric # endif
62868d75effSDimitry Andric
GetThreadStackAndTls(bool main,uptr * stk_addr,uptr * stk_size,uptr * tls_addr,uptr * tls_size)62968d75effSDimitry Andric void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
63068d75effSDimitry Andric uptr *tls_addr, uptr *tls_size) {
63168d75effSDimitry Andric # if SANITIZER_GO
63268d75effSDimitry Andric // Stub implementation for Go.
63368d75effSDimitry Andric *stk_addr = *stk_size = *tls_addr = *tls_size = 0;
63468d75effSDimitry Andric # else
63568d75effSDimitry Andric GetTls(tls_addr, tls_size);
63668d75effSDimitry Andric
63768d75effSDimitry Andric uptr stack_top, stack_bottom;
63868d75effSDimitry Andric GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
63968d75effSDimitry Andric *stk_addr = stack_bottom;
64068d75effSDimitry Andric *stk_size = stack_top - stack_bottom;
64168d75effSDimitry Andric
64268d75effSDimitry Andric if (!main) {
64368d75effSDimitry Andric // If stack and tls intersect, make them non-intersecting.
64468d75effSDimitry Andric if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) {
645fe6060f1SDimitry Andric if (*stk_addr + *stk_size < *tls_addr + *tls_size)
646fe6060f1SDimitry Andric *tls_size = *stk_addr + *stk_size - *tls_addr;
647fe6060f1SDimitry Andric *stk_size = *tls_addr - *stk_addr;
64868d75effSDimitry Andric }
64968d75effSDimitry Andric }
65068d75effSDimitry Andric # endif
65168d75effSDimitry Andric }
65268d75effSDimitry Andric
653e8d8bef9SDimitry Andric # if !SANITIZER_FREEBSD
65468d75effSDimitry Andric typedef ElfW(Phdr) Elf_Phdr;
655647cbc5dSDimitry Andric # endif
65668d75effSDimitry Andric
65768d75effSDimitry Andric struct DlIteratePhdrData {
65868d75effSDimitry Andric InternalMmapVectorNoCtor<LoadedModule> *modules;
65968d75effSDimitry Andric bool first;
66068d75effSDimitry Andric };
66168d75effSDimitry Andric
AddModuleSegments(const char * module_name,dl_phdr_info * info,InternalMmapVectorNoCtor<LoadedModule> * modules)662fe6060f1SDimitry Andric static int AddModuleSegments(const char *module_name, dl_phdr_info *info,
663fe6060f1SDimitry Andric InternalMmapVectorNoCtor<LoadedModule> *modules) {
66468d75effSDimitry Andric if (module_name[0] == '\0')
66568d75effSDimitry Andric return 0;
66668d75effSDimitry Andric LoadedModule cur_module;
667fe6060f1SDimitry Andric cur_module.set(module_name, info->dlpi_addr);
66868d75effSDimitry Andric for (int i = 0; i < (int)info->dlpi_phnum; i++) {
66968d75effSDimitry Andric const Elf_Phdr *phdr = &info->dlpi_phdr[i];
67068d75effSDimitry Andric if (phdr->p_type == PT_LOAD) {
67168d75effSDimitry Andric uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
67268d75effSDimitry Andric uptr cur_end = cur_beg + phdr->p_memsz;
67368d75effSDimitry Andric bool executable = phdr->p_flags & PF_X;
67468d75effSDimitry Andric bool writable = phdr->p_flags & PF_W;
6755f757f3fSDimitry Andric cur_module.addAddressRange(cur_beg, cur_end, executable, writable);
6760eae32dcSDimitry Andric } else if (phdr->p_type == PT_NOTE) {
67704eeddc0SDimitry Andric # ifdef NT_GNU_BUILD_ID
6780eae32dcSDimitry Andric uptr off = 0;
67904eeddc0SDimitry Andric while (off + sizeof(ElfW(Nhdr)) < phdr->p_memsz) {
6800eae32dcSDimitry Andric auto *nhdr = reinterpret_cast<const ElfW(Nhdr) *>(info->dlpi_addr +
6810eae32dcSDimitry Andric phdr->p_vaddr + off);
6820eae32dcSDimitry Andric constexpr auto kGnuNamesz = 4; // "GNU" with NUL-byte.
6830eae32dcSDimitry Andric static_assert(kGnuNamesz % 4 == 0, "kGnuNameSize is aligned to 4.");
6840eae32dcSDimitry Andric if (nhdr->n_type == NT_GNU_BUILD_ID && nhdr->n_namesz == kGnuNamesz) {
6850eae32dcSDimitry Andric if (off + sizeof(ElfW(Nhdr)) + nhdr->n_namesz + nhdr->n_descsz >
6860eae32dcSDimitry Andric phdr->p_memsz) {
6870eae32dcSDimitry Andric // Something is very wrong, bail out instead of reading potentially
6880eae32dcSDimitry Andric // arbitrary memory.
6890eae32dcSDimitry Andric break;
6900eae32dcSDimitry Andric }
6910eae32dcSDimitry Andric const char *name =
6920eae32dcSDimitry Andric reinterpret_cast<const char *>(nhdr) + sizeof(*nhdr);
6930eae32dcSDimitry Andric if (internal_memcmp(name, "GNU", 3) == 0) {
6940eae32dcSDimitry Andric const char *value = reinterpret_cast<const char *>(nhdr) +
6950eae32dcSDimitry Andric sizeof(*nhdr) + kGnuNamesz;
6960eae32dcSDimitry Andric cur_module.setUuid(value, nhdr->n_descsz);
6970eae32dcSDimitry Andric break;
6980eae32dcSDimitry Andric }
6990eae32dcSDimitry Andric }
7000eae32dcSDimitry Andric off += sizeof(*nhdr) + RoundUpTo(nhdr->n_namesz, 4) +
7010eae32dcSDimitry Andric RoundUpTo(nhdr->n_descsz, 4);
7020eae32dcSDimitry Andric }
70304eeddc0SDimitry Andric # endif
70468d75effSDimitry Andric }
70568d75effSDimitry Andric }
706fe6060f1SDimitry Andric modules->push_back(cur_module);
707fe6060f1SDimitry Andric return 0;
708fe6060f1SDimitry Andric }
709fe6060f1SDimitry Andric
dl_iterate_phdr_cb(dl_phdr_info * info,size_t size,void * arg)710fe6060f1SDimitry Andric static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
711fe6060f1SDimitry Andric DlIteratePhdrData *data = (DlIteratePhdrData *)arg;
712fe6060f1SDimitry Andric if (data->first) {
713fe6060f1SDimitry Andric InternalMmapVector<char> module_name(kMaxPathLength);
714fe6060f1SDimitry Andric data->first = false;
715fe6060f1SDimitry Andric // First module is the binary itself.
716fe6060f1SDimitry Andric ReadBinaryNameCached(module_name.data(), module_name.size());
717fe6060f1SDimitry Andric return AddModuleSegments(module_name.data(), info, data->modules);
718fe6060f1SDimitry Andric }
719fe6060f1SDimitry Andric
7205f757f3fSDimitry Andric if (info->dlpi_name)
7215f757f3fSDimitry Andric return AddModuleSegments(info->dlpi_name, info, data->modules);
722fe6060f1SDimitry Andric
72368d75effSDimitry Andric return 0;
72468d75effSDimitry Andric }
72568d75effSDimitry Andric
72668d75effSDimitry Andric # if SANITIZER_ANDROID && __ANDROID_API__ < 21
72768d75effSDimitry Andric extern "C" __attribute__((weak)) int dl_iterate_phdr(
72868d75effSDimitry Andric int (*)(struct dl_phdr_info *, size_t, void *), void *);
72968d75effSDimitry Andric # endif
73068d75effSDimitry Andric
requiresProcmaps()73168d75effSDimitry Andric static bool requiresProcmaps() {
73268d75effSDimitry Andric # if SANITIZER_ANDROID && __ANDROID_API__ <= 22
73368d75effSDimitry Andric // Fall back to /proc/maps if dl_iterate_phdr is unavailable or broken.
73468d75effSDimitry Andric // The runtime check allows the same library to work with
73568d75effSDimitry Andric // both K and L (and future) Android releases.
73668d75effSDimitry Andric return AndroidGetApiLevel() <= ANDROID_LOLLIPOP_MR1;
73768d75effSDimitry Andric # else
73868d75effSDimitry Andric return false;
73968d75effSDimitry Andric # endif
74068d75effSDimitry Andric }
74168d75effSDimitry Andric
procmapsInit(InternalMmapVectorNoCtor<LoadedModule> * modules)74268d75effSDimitry Andric static void procmapsInit(InternalMmapVectorNoCtor<LoadedModule> *modules) {
74368d75effSDimitry Andric MemoryMappingLayout memory_mapping(/*cache_enabled*/ true);
74468d75effSDimitry Andric memory_mapping.DumpListOfModules(modules);
74568d75effSDimitry Andric }
74668d75effSDimitry Andric
init()74768d75effSDimitry Andric void ListOfModules::init() {
74868d75effSDimitry Andric clearOrInit();
74968d75effSDimitry Andric if (requiresProcmaps()) {
75068d75effSDimitry Andric procmapsInit(&modules_);
75168d75effSDimitry Andric } else {
75268d75effSDimitry Andric DlIteratePhdrData data = {&modules_, true};
75368d75effSDimitry Andric dl_iterate_phdr(dl_iterate_phdr_cb, &data);
75468d75effSDimitry Andric }
75568d75effSDimitry Andric }
75668d75effSDimitry Andric
75768d75effSDimitry Andric // When a custom loader is used, dl_iterate_phdr may not contain the full
75868d75effSDimitry Andric // list of modules. Allow callers to fall back to using procmaps.
fallbackInit()75968d75effSDimitry Andric void ListOfModules::fallbackInit() {
76068d75effSDimitry Andric if (!requiresProcmaps()) {
76168d75effSDimitry Andric clearOrInit();
76268d75effSDimitry Andric procmapsInit(&modules_);
76368d75effSDimitry Andric } else {
76468d75effSDimitry Andric clear();
76568d75effSDimitry Andric }
76668d75effSDimitry Andric }
76768d75effSDimitry Andric
76868d75effSDimitry Andric // getrusage does not give us the current RSS, only the max RSS.
76968d75effSDimitry Andric // Still, this is better than nothing if /proc/self/statm is not available
77068d75effSDimitry Andric // for some reason, e.g. due to a sandbox.
GetRSSFromGetrusage()77168d75effSDimitry Andric static uptr GetRSSFromGetrusage() {
77268d75effSDimitry Andric struct rusage usage;
77368d75effSDimitry Andric if (getrusage(RUSAGE_SELF, &usage)) // Failed, probably due to a sandbox.
77468d75effSDimitry Andric return 0;
77568d75effSDimitry Andric return usage.ru_maxrss << 10; // ru_maxrss is in Kb.
77668d75effSDimitry Andric }
77768d75effSDimitry Andric
GetRSS()77868d75effSDimitry Andric uptr GetRSS() {
77968d75effSDimitry Andric if (!common_flags()->can_use_proc_maps_statm)
78068d75effSDimitry Andric return GetRSSFromGetrusage();
78168d75effSDimitry Andric fd_t fd = OpenFile("/proc/self/statm", RdOnly);
78268d75effSDimitry Andric if (fd == kInvalidFd)
78368d75effSDimitry Andric return GetRSSFromGetrusage();
78468d75effSDimitry Andric char buf[64];
78568d75effSDimitry Andric uptr len = internal_read(fd, buf, sizeof(buf) - 1);
78668d75effSDimitry Andric internal_close(fd);
78768d75effSDimitry Andric if ((sptr)len <= 0)
78868d75effSDimitry Andric return 0;
78968d75effSDimitry Andric buf[len] = 0;
79068d75effSDimitry Andric // The format of the file is:
79168d75effSDimitry Andric // 1084 89 69 11 0 79 0
79268d75effSDimitry Andric // We need the second number which is RSS in pages.
79368d75effSDimitry Andric char *pos = buf;
79468d75effSDimitry Andric // Skip the first number.
7955f757f3fSDimitry Andric while (*pos >= '0' && *pos <= '9') pos++;
79668d75effSDimitry Andric // Skip whitespaces.
7975f757f3fSDimitry Andric while (!(*pos >= '0' && *pos <= '9') && *pos != 0) pos++;
79868d75effSDimitry Andric // Read the number.
79968d75effSDimitry Andric uptr rss = 0;
8005f757f3fSDimitry Andric while (*pos >= '0' && *pos <= '9') rss = rss * 10 + *pos++ - '0';
80168d75effSDimitry Andric return rss * GetPageSizeCached();
80268d75effSDimitry Andric }
80368d75effSDimitry Andric
80468d75effSDimitry Andric // sysconf(_SC_NPROCESSORS_{CONF,ONLN}) cannot be used on most platforms as
80568d75effSDimitry Andric // they allocate memory.
GetNumberOfCPUs()80668d75effSDimitry Andric u32 GetNumberOfCPUs() {
807e8d8bef9SDimitry Andric # if SANITIZER_FREEBSD || SANITIZER_NETBSD
80868d75effSDimitry Andric u32 ncpu;
80968d75effSDimitry Andric int req[2];
81068d75effSDimitry Andric uptr len = sizeof(ncpu);
81168d75effSDimitry Andric req[0] = CTL_HW;
81268d75effSDimitry Andric req[1] = HW_NCPU;
81368d75effSDimitry Andric CHECK_EQ(internal_sysctl(req, 2, &ncpu, &len, NULL, 0), 0);
81468d75effSDimitry Andric return ncpu;
81568d75effSDimitry Andric # elif SANITIZER_ANDROID && !defined(CPU_COUNT) && !defined(__aarch64__)
81668d75effSDimitry Andric // Fall back to /sys/devices/system/cpu on Android when cpu_set_t doesn't
81768d75effSDimitry Andric // exist in sched.h. That is the case for toolchains generated with older
81868d75effSDimitry Andric // NDKs.
81968d75effSDimitry Andric // This code doesn't work on AArch64 because internal_getdents makes use of
82068d75effSDimitry Andric // the 64bit getdents syscall, but cpu_set_t seems to always exist on AArch64.
82168d75effSDimitry Andric uptr fd = internal_open("/sys/devices/system/cpu", O_RDONLY | O_DIRECTORY);
82268d75effSDimitry Andric if (internal_iserror(fd))
82368d75effSDimitry Andric return 0;
82468d75effSDimitry Andric InternalMmapVector<u8> buffer(4096);
82568d75effSDimitry Andric uptr bytes_read = buffer.size();
82668d75effSDimitry Andric uptr n_cpus = 0;
82768d75effSDimitry Andric u8 *d_type;
82868d75effSDimitry Andric struct linux_dirent *entry = (struct linux_dirent *)&buffer[bytes_read];
82968d75effSDimitry Andric while (true) {
83068d75effSDimitry Andric if ((u8 *)entry >= &buffer[bytes_read]) {
83168d75effSDimitry Andric bytes_read = internal_getdents(fd, (struct linux_dirent *)buffer.data(),
83268d75effSDimitry Andric buffer.size());
83368d75effSDimitry Andric if (internal_iserror(bytes_read) || !bytes_read)
83468d75effSDimitry Andric break;
83568d75effSDimitry Andric entry = (struct linux_dirent *)buffer.data();
83668d75effSDimitry Andric }
83768d75effSDimitry Andric d_type = (u8 *)entry + entry->d_reclen - 1;
83868d75effSDimitry Andric if (d_type >= &buffer[bytes_read] ||
83968d75effSDimitry Andric (u8 *)&entry->d_name[3] >= &buffer[bytes_read])
84068d75effSDimitry Andric break;
84168d75effSDimitry Andric if (entry->d_ino != 0 && *d_type == DT_DIR) {
84268d75effSDimitry Andric if (entry->d_name[0] == 'c' && entry->d_name[1] == 'p' &&
8435f757f3fSDimitry Andric entry->d_name[2] == 'u' && entry->d_name[3] >= '0' &&
8445f757f3fSDimitry Andric entry->d_name[3] <= '9')
84568d75effSDimitry Andric n_cpus++;
84668d75effSDimitry Andric }
84768d75effSDimitry Andric entry = (struct linux_dirent *)(((u8 *)entry) + entry->d_reclen);
84868d75effSDimitry Andric }
84968d75effSDimitry Andric internal_close(fd);
85068d75effSDimitry Andric return n_cpus;
85168d75effSDimitry Andric # elif SANITIZER_SOLARIS
85268d75effSDimitry Andric return sysconf(_SC_NPROCESSORS_ONLN);
85368d75effSDimitry Andric # else
85468d75effSDimitry Andric cpu_set_t CPUs;
85568d75effSDimitry Andric CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0);
85668d75effSDimitry Andric return CPU_COUNT(&CPUs);
85768d75effSDimitry Andric # endif
85868d75effSDimitry Andric }
85968d75effSDimitry Andric
86068d75effSDimitry Andric # if SANITIZER_LINUX
86168d75effSDimitry Andric
86268d75effSDimitry Andric # if SANITIZER_ANDROID
86368d75effSDimitry Andric static atomic_uint8_t android_log_initialized;
86468d75effSDimitry Andric
AndroidLogInit()86568d75effSDimitry Andric void AndroidLogInit() {
86668d75effSDimitry Andric openlog(GetProcessName(), 0, LOG_USER);
86768d75effSDimitry Andric atomic_store(&android_log_initialized, 1, memory_order_release);
86868d75effSDimitry Andric }
86968d75effSDimitry Andric
ShouldLogAfterPrintf()87068d75effSDimitry Andric static bool ShouldLogAfterPrintf() {
87168d75effSDimitry Andric return atomic_load(&android_log_initialized, memory_order_acquire);
87268d75effSDimitry Andric }
87368d75effSDimitry Andric
8745f757f3fSDimitry Andric extern "C" SANITIZER_WEAK_ATTRIBUTE int async_safe_write_log(int pri,
8755f757f3fSDimitry Andric const char *tag,
8765f757f3fSDimitry Andric const char *msg);
8775f757f3fSDimitry Andric extern "C" SANITIZER_WEAK_ATTRIBUTE int __android_log_write(int prio,
8785f757f3fSDimitry Andric const char *tag,
8795f757f3fSDimitry Andric const char *msg);
88068d75effSDimitry Andric
88168d75effSDimitry Andric // ANDROID_LOG_INFO is 4, but can't be resolved at runtime.
88268d75effSDimitry Andric # define SANITIZER_ANDROID_LOG_INFO 4
88368d75effSDimitry Andric
88468d75effSDimitry Andric // async_safe_write_log is a new public version of __libc_write_log that is
88568d75effSDimitry Andric // used behind syslog. It is preferable to syslog as it will not do any dynamic
88668d75effSDimitry Andric // memory allocation or formatting.
88768d75effSDimitry Andric // If the function is not available, syslog is preferred for L+ (it was broken
88868d75effSDimitry Andric // pre-L) as __android_log_write triggers a racey behavior with the strncpy
88968d75effSDimitry Andric // interceptor. Fallback to __android_log_write pre-L.
WriteOneLineToSyslog(const char * s)89068d75effSDimitry Andric void WriteOneLineToSyslog(const char *s) {
89168d75effSDimitry Andric if (&async_safe_write_log) {
89268d75effSDimitry Andric async_safe_write_log(SANITIZER_ANDROID_LOG_INFO, GetProcessName(), s);
89368d75effSDimitry Andric } else if (AndroidGetApiLevel() > ANDROID_KITKAT) {
89468d75effSDimitry Andric syslog(LOG_INFO, "%s", s);
89568d75effSDimitry Andric } else {
89668d75effSDimitry Andric CHECK(&__android_log_write);
89768d75effSDimitry Andric __android_log_write(SANITIZER_ANDROID_LOG_INFO, nullptr, s);
89868d75effSDimitry Andric }
89968d75effSDimitry Andric }
90068d75effSDimitry Andric
9015f757f3fSDimitry Andric extern "C" SANITIZER_WEAK_ATTRIBUTE void android_set_abort_message(
9025f757f3fSDimitry Andric const char *);
90368d75effSDimitry Andric
SetAbortMessage(const char * str)90468d75effSDimitry Andric void SetAbortMessage(const char *str) {
90568d75effSDimitry Andric if (&android_set_abort_message)
90668d75effSDimitry Andric android_set_abort_message(str);
90768d75effSDimitry Andric }
90868d75effSDimitry Andric # else
AndroidLogInit()90968d75effSDimitry Andric void AndroidLogInit() {}
91068d75effSDimitry Andric
ShouldLogAfterPrintf()91168d75effSDimitry Andric static bool ShouldLogAfterPrintf() { return true; }
91268d75effSDimitry Andric
WriteOneLineToSyslog(const char * s)91368d75effSDimitry Andric void WriteOneLineToSyslog(const char *s) { syslog(LOG_INFO, "%s", s); }
91468d75effSDimitry Andric
SetAbortMessage(const char * str)91568d75effSDimitry Andric void SetAbortMessage(const char *str) {}
91668d75effSDimitry Andric # endif // SANITIZER_ANDROID
91768d75effSDimitry Andric
LogMessageOnPrintf(const char * str)91868d75effSDimitry Andric void LogMessageOnPrintf(const char *str) {
91968d75effSDimitry Andric if (common_flags()->log_to_syslog && ShouldLogAfterPrintf())
92068d75effSDimitry Andric WriteToSyslog(str);
92168d75effSDimitry Andric }
92268d75effSDimitry Andric
92368d75effSDimitry Andric # endif // SANITIZER_LINUX
92468d75effSDimitry Andric
925fe6060f1SDimitry Andric # if SANITIZER_GLIBC && !SANITIZER_GO
92668d75effSDimitry Andric // glibc crashes when using clock_gettime from a preinit_array function as the
92768d75effSDimitry Andric // vDSO function pointers haven't been initialized yet. __progname is
92868d75effSDimitry Andric // initialized after the vDSO function pointers, so if it exists, is not null
92968d75effSDimitry Andric // and is not empty, we can use clock_gettime.
93068d75effSDimitry Andric extern "C" SANITIZER_WEAK_ATTRIBUTE char *__progname;
CanUseVDSO()931fe6060f1SDimitry Andric inline bool CanUseVDSO() { return &__progname && __progname && *__progname; }
93268d75effSDimitry Andric
93368d75effSDimitry Andric // MonotonicNanoTime is a timing function that can leverage the vDSO by calling
93468d75effSDimitry Andric // clock_gettime. real_clock_gettime only exists if clock_gettime is
93568d75effSDimitry Andric // intercepted, so define it weakly and use it if available.
9365f757f3fSDimitry Andric extern "C" SANITIZER_WEAK_ATTRIBUTE int real_clock_gettime(u32 clk_id,
9375f757f3fSDimitry Andric void *tp);
MonotonicNanoTime()93868d75effSDimitry Andric u64 MonotonicNanoTime() {
93968d75effSDimitry Andric timespec ts;
94068d75effSDimitry Andric if (CanUseVDSO()) {
94168d75effSDimitry Andric if (&real_clock_gettime)
94268d75effSDimitry Andric real_clock_gettime(CLOCK_MONOTONIC, &ts);
94368d75effSDimitry Andric else
94468d75effSDimitry Andric clock_gettime(CLOCK_MONOTONIC, &ts);
94568d75effSDimitry Andric } else {
94668d75effSDimitry Andric internal_clock_gettime(CLOCK_MONOTONIC, &ts);
94768d75effSDimitry Andric }
94868d75effSDimitry Andric return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec;
94968d75effSDimitry Andric }
95068d75effSDimitry Andric # else
951fe6060f1SDimitry Andric // Non-glibc & Go always use the regular function.
MonotonicNanoTime()95268d75effSDimitry Andric u64 MonotonicNanoTime() {
95368d75effSDimitry Andric timespec ts;
954fe6060f1SDimitry Andric clock_gettime(CLOCK_MONOTONIC, &ts);
95568d75effSDimitry Andric return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec;
95668d75effSDimitry Andric }
957fe6060f1SDimitry Andric # endif // SANITIZER_GLIBC && !SANITIZER_GO
95868d75effSDimitry Andric
ReExec()95968d75effSDimitry Andric void ReExec() {
96068d75effSDimitry Andric const char *pathname = "/proc/self/exe";
96168d75effSDimitry Andric
96296fe7c8aSEd Maste # if SANITIZER_FREEBSD
9634c9a0adaSDimitry Andric for (const auto *aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) {
9644c9a0adaSDimitry Andric if (aux->a_type == AT_EXECPATH) {
9654c9a0adaSDimitry Andric pathname = static_cast<const char *>(aux->a_un.a_ptr);
9664c9a0adaSDimitry Andric break;
9674c9a0adaSDimitry Andric }
96896fe7c8aSEd Maste }
96996fe7c8aSEd Maste # elif SANITIZER_NETBSD
97068d75effSDimitry Andric static const int name[] = {
97168d75effSDimitry Andric CTL_KERN,
97268d75effSDimitry Andric KERN_PROC_ARGS,
97368d75effSDimitry Andric -1,
97468d75effSDimitry Andric KERN_PROC_PATHNAME,
97568d75effSDimitry Andric };
97668d75effSDimitry Andric char path[400];
97768d75effSDimitry Andric uptr len;
97868d75effSDimitry Andric
97968d75effSDimitry Andric len = sizeof(path);
98068d75effSDimitry Andric if (internal_sysctl(name, ARRAY_SIZE(name), path, &len, NULL, 0) != -1)
98168d75effSDimitry Andric pathname = path;
98268d75effSDimitry Andric # elif SANITIZER_SOLARIS
98368d75effSDimitry Andric pathname = getexecname();
98468d75effSDimitry Andric CHECK_NE(pathname, NULL);
98568d75effSDimitry Andric # elif SANITIZER_USE_GETAUXVAL
98668d75effSDimitry Andric // Calling execve with /proc/self/exe sets that as $EXEC_ORIGIN. Binaries that
98768d75effSDimitry Andric // rely on that will fail to load shared libraries. Query AT_EXECFN instead.
98868d75effSDimitry Andric pathname = reinterpret_cast<const char *>(getauxval(AT_EXECFN));
98968d75effSDimitry Andric # endif
99068d75effSDimitry Andric
99168d75effSDimitry Andric uptr rv = internal_execve(pathname, GetArgv(), GetEnviron());
99268d75effSDimitry Andric int rverrno;
99368d75effSDimitry Andric CHECK_EQ(internal_iserror(rv, &rverrno), true);
99468d75effSDimitry Andric Printf("execve failed, errno %d\n", rverrno);
99568d75effSDimitry Andric Die();
99668d75effSDimitry Andric }
997e8d8bef9SDimitry Andric
UnmapFromTo(uptr from,uptr to)998e8d8bef9SDimitry Andric void UnmapFromTo(uptr from, uptr to) {
999e8d8bef9SDimitry Andric if (to == from)
1000e8d8bef9SDimitry Andric return;
1001e8d8bef9SDimitry Andric CHECK(to >= from);
1002e8d8bef9SDimitry Andric uptr res = internal_munmap(reinterpret_cast<void *>(from), to - from);
1003e8d8bef9SDimitry Andric if (UNLIKELY(internal_iserror(res))) {
1004e8d8bef9SDimitry Andric Report("ERROR: %s failed to unmap 0x%zx (%zd) bytes at address %p\n",
1005e8d8bef9SDimitry Andric SanitizerToolName, to - from, to - from, (void *)from);
1006e8d8bef9SDimitry Andric CHECK("unable to unmap" && 0);
1007e8d8bef9SDimitry Andric }
1008e8d8bef9SDimitry Andric }
1009e8d8bef9SDimitry Andric
MapDynamicShadow(uptr shadow_size_bytes,uptr shadow_scale,uptr min_shadow_base_alignment,UNUSED uptr & high_mem_end,uptr granularity)1010e8d8bef9SDimitry Andric uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
1011*0fca6ea1SDimitry Andric uptr min_shadow_base_alignment, UNUSED uptr &high_mem_end,
1012*0fca6ea1SDimitry Andric uptr granularity) {
1013e8d8bef9SDimitry Andric const uptr alignment =
1014e8d8bef9SDimitry Andric Max<uptr>(granularity << shadow_scale, 1ULL << min_shadow_base_alignment);
1015e8d8bef9SDimitry Andric const uptr left_padding =
1016e8d8bef9SDimitry Andric Max<uptr>(granularity, 1ULL << min_shadow_base_alignment);
1017e8d8bef9SDimitry Andric
1018e8d8bef9SDimitry Andric const uptr shadow_size = RoundUpTo(shadow_size_bytes, granularity);
1019e8d8bef9SDimitry Andric const uptr map_size = shadow_size + left_padding + alignment;
1020e8d8bef9SDimitry Andric
1021e8d8bef9SDimitry Andric const uptr map_start = (uptr)MmapNoAccess(map_size);
1022e8d8bef9SDimitry Andric CHECK_NE(map_start, ~(uptr)0);
1023e8d8bef9SDimitry Andric
1024e8d8bef9SDimitry Andric const uptr shadow_start = RoundUpTo(map_start + left_padding, alignment);
1025e8d8bef9SDimitry Andric
1026e8d8bef9SDimitry Andric UnmapFromTo(map_start, shadow_start - left_padding);
1027e8d8bef9SDimitry Andric UnmapFromTo(shadow_start + shadow_size, map_start + map_size);
1028e8d8bef9SDimitry Andric
1029e8d8bef9SDimitry Andric return shadow_start;
1030e8d8bef9SDimitry Andric }
1031e8d8bef9SDimitry Andric
MmapSharedNoReserve(uptr addr,uptr size)1032fe6060f1SDimitry Andric static uptr MmapSharedNoReserve(uptr addr, uptr size) {
1033fe6060f1SDimitry Andric return internal_mmap(
1034fe6060f1SDimitry Andric reinterpret_cast<void *>(addr), size, PROT_READ | PROT_WRITE,
1035fe6060f1SDimitry Andric MAP_FIXED | MAP_SHARED | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
1036fe6060f1SDimitry Andric }
1037fe6060f1SDimitry Andric
MremapCreateAlias(uptr base_addr,uptr alias_addr,uptr alias_size)1038fe6060f1SDimitry Andric static uptr MremapCreateAlias(uptr base_addr, uptr alias_addr,
1039fe6060f1SDimitry Andric uptr alias_size) {
1040fe6060f1SDimitry Andric # if SANITIZER_LINUX
1041fe6060f1SDimitry Andric return internal_mremap(reinterpret_cast<void *>(base_addr), 0, alias_size,
1042fe6060f1SDimitry Andric MREMAP_MAYMOVE | MREMAP_FIXED,
1043fe6060f1SDimitry Andric reinterpret_cast<void *>(alias_addr));
1044fe6060f1SDimitry Andric # else
1045fe6060f1SDimitry Andric CHECK(false && "mremap is not supported outside of Linux");
1046fe6060f1SDimitry Andric return 0;
1047fe6060f1SDimitry Andric # endif
1048fe6060f1SDimitry Andric }
1049fe6060f1SDimitry Andric
CreateAliases(uptr start_addr,uptr alias_size,uptr num_aliases)1050fe6060f1SDimitry Andric static void CreateAliases(uptr start_addr, uptr alias_size, uptr num_aliases) {
1051fe6060f1SDimitry Andric uptr total_size = alias_size * num_aliases;
1052fe6060f1SDimitry Andric uptr mapped = MmapSharedNoReserve(start_addr, total_size);
1053fe6060f1SDimitry Andric CHECK_EQ(mapped, start_addr);
1054fe6060f1SDimitry Andric
1055fe6060f1SDimitry Andric for (uptr i = 1; i < num_aliases; ++i) {
1056fe6060f1SDimitry Andric uptr alias_addr = start_addr + i * alias_size;
1057fe6060f1SDimitry Andric CHECK_EQ(MremapCreateAlias(start_addr, alias_addr, alias_size), alias_addr);
1058fe6060f1SDimitry Andric }
1059fe6060f1SDimitry Andric }
1060fe6060f1SDimitry Andric
MapDynamicShadowAndAliases(uptr shadow_size,uptr alias_size,uptr num_aliases,uptr ring_buffer_size)1061fe6060f1SDimitry Andric uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
1062fe6060f1SDimitry Andric uptr num_aliases, uptr ring_buffer_size) {
1063fe6060f1SDimitry Andric CHECK_EQ(alias_size & (alias_size - 1), 0);
1064fe6060f1SDimitry Andric CHECK_EQ(num_aliases & (num_aliases - 1), 0);
1065fe6060f1SDimitry Andric CHECK_EQ(ring_buffer_size & (ring_buffer_size - 1), 0);
1066fe6060f1SDimitry Andric
1067fe6060f1SDimitry Andric const uptr granularity = GetMmapGranularity();
1068fe6060f1SDimitry Andric shadow_size = RoundUpTo(shadow_size, granularity);
1069fe6060f1SDimitry Andric CHECK_EQ(shadow_size & (shadow_size - 1), 0);
1070fe6060f1SDimitry Andric
1071fe6060f1SDimitry Andric const uptr alias_region_size = alias_size * num_aliases;
1072fe6060f1SDimitry Andric const uptr alignment =
1073fe6060f1SDimitry Andric 2 * Max(Max(shadow_size, alias_region_size), ring_buffer_size);
1074fe6060f1SDimitry Andric const uptr left_padding = ring_buffer_size;
1075fe6060f1SDimitry Andric
1076fe6060f1SDimitry Andric const uptr right_size = alignment;
1077fe6060f1SDimitry Andric const uptr map_size = left_padding + 2 * alignment;
1078fe6060f1SDimitry Andric
1079fe6060f1SDimitry Andric const uptr map_start = reinterpret_cast<uptr>(MmapNoAccess(map_size));
1080fe6060f1SDimitry Andric CHECK_NE(map_start, static_cast<uptr>(-1));
1081fe6060f1SDimitry Andric const uptr right_start = RoundUpTo(map_start + left_padding, alignment);
1082fe6060f1SDimitry Andric
1083fe6060f1SDimitry Andric UnmapFromTo(map_start, right_start - left_padding);
1084fe6060f1SDimitry Andric UnmapFromTo(right_start + right_size, map_start + map_size);
1085fe6060f1SDimitry Andric
1086fe6060f1SDimitry Andric CreateAliases(right_start + right_size / 2, alias_size, num_aliases);
1087fe6060f1SDimitry Andric
1088fe6060f1SDimitry Andric return right_start;
1089fe6060f1SDimitry Andric }
1090fe6060f1SDimitry Andric
InitializePlatformCommonFlags(CommonFlags * cf)1091e8d8bef9SDimitry Andric void InitializePlatformCommonFlags(CommonFlags *cf) {
1092e8d8bef9SDimitry Andric # if SANITIZER_ANDROID
1093e8d8bef9SDimitry Andric if (&__libc_get_static_tls_bounds == nullptr)
1094e8d8bef9SDimitry Andric cf->detect_leaks = false;
1095e8d8bef9SDimitry Andric # endif
1096e8d8bef9SDimitry Andric }
109768d75effSDimitry Andric
109868d75effSDimitry Andric } // namespace __sanitizer
109968d75effSDimitry Andric
110068d75effSDimitry Andric #endif
1101