libsanitizer: Fix Solaris 11.3 compilation [PR105531]

The libsanitizer build has been broken on Solaris 11.3 by the latest
import.  An upstream patch to fix this has now been committed:

	[sanitizer_common] Support Solaris < 11.4 in GetStaticTlsBoundary
        https://reviews.llvm.org/D120059

I'd like to cherry-pick it into libsanitizer, too.

Bootstrapped without regressions on sparc-sun-solaris2.11,
i386-pc-solaris2.11 (both Solaris 11.3 and 11.4), and
x86_64-pc-linux-gnu.

2022-07-21  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>

	libsanitizer:
	PR sanitizer/105531
	* sanitizer_common/sanitizer_linux_libcdep.cpp,
	sanitizer_common/sanitizer_solaris.h:: Cherry-pick
	llvm-project revision 3776db9a4fd2080d23d6a5f52e405eea44558761.
This commit is contained in:
Rainer Orth 2022-07-22 13:18:14 +02:00
parent 03c0b06420
commit 786e51648b
2 changed files with 91 additions and 9 deletions

View file

@ -27,6 +27,7 @@
#include "sanitizer_linux.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_procmaps.h"
#include "sanitizer_solaris.h"
#if SANITIZER_NETBSD
#define _RTLD_SOURCE // for __lwp_gettcb_fast() / __lwp_getprivate_fast()
@ -62,6 +63,7 @@
#endif
#if SANITIZER_SOLARIS
#include <stddef.h>
#include <stdlib.h>
#include <thread.h>
#endif
@ -350,19 +352,43 @@ static uptr TlsGetOffset(uptr ti_module, uptr ti_offset) {
extern "C" void *__tls_get_addr(size_t *);
#endif
static size_t main_tls_modid;
static int CollectStaticTlsBlocks(struct dl_phdr_info *info, size_t size,
void *data) {
if (!info->dlpi_tls_modid)
size_t tls_modid;
#if SANITIZER_SOLARIS
// dlpi_tls_modid is only available since Solaris 11.4 SRU 10. Use
// dlinfo(RTLD_DI_LINKMAP) instead which works on all of Solaris 11.3,
// 11.4, and Illumos. The tlsmodid of the executable was changed to 1 in
// 11.4 to match other implementations.
if (size >= offsetof(dl_phdr_info_test, dlpi_tls_modid))
main_tls_modid = 1;
else
main_tls_modid = 0;
g_use_dlpi_tls_data = 0;
Rt_map *map;
dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &map);
tls_modid = map->rt_tlsmodid;
#else
main_tls_modid = 1;
tls_modid = info->dlpi_tls_modid;
#endif
if (tls_modid < main_tls_modid)
return 0;
uptr begin = (uptr)info->dlpi_tls_data;
uptr begin;
#if !SANITIZER_SOLARIS
begin = (uptr)info->dlpi_tls_data;
#endif
if (!g_use_dlpi_tls_data) {
// Call __tls_get_addr as a fallback. This forces TLS allocation on glibc
// and FreeBSD.
#ifdef __s390__
begin = (uptr)__builtin_thread_pointer() +
TlsGetOffset(info->dlpi_tls_modid, 0);
TlsGetOffset(tls_modid, 0);
#else
size_t mod_and_off[2] = {info->dlpi_tls_modid, 0};
size_t mod_and_off[2] = {tls_modid, 0};
begin = (uptr)__tls_get_addr(mod_and_off);
#endif
}
@ -370,7 +396,7 @@ static int CollectStaticTlsBlocks(struct dl_phdr_info *info, size_t size,
if (info->dlpi_phdr[i].p_type == PT_TLS) {
static_cast<InternalMmapVector<TlsBlock> *>(data)->push_back(
TlsBlock{begin, begin + info->dlpi_phdr[i].p_memsz,
info->dlpi_phdr[i].p_align, info->dlpi_tls_modid});
info->dlpi_phdr[i].p_align, tls_modid});
break;
}
return 0;
@ -382,11 +408,11 @@ __attribute__((unused)) static void GetStaticTlsBoundary(uptr *addr, uptr *size,
dl_iterate_phdr(CollectStaticTlsBlocks, &ranges);
uptr len = ranges.size();
Sort(ranges.begin(), len);
// Find the range with tls_modid=1. For glibc, because libc.so uses PT_TLS,
// this module is guaranteed to exist and is one of the initially loaded
// modules.
// Find the range with tls_modid == main_tls_modid. For glibc, because
// libc.so uses PT_TLS, this module is guaranteed to exist and is one of
// the initially loaded modules.
uptr one = 0;
while (one != len && ranges[one].tls_modid != 1) ++one;
while (one != len && ranges[one].tls_modid != main_tls_modid) ++one;
if (one == len) {
// This may happen with musl if no module uses PT_TLS.
*addr = 0;

View file

@ -0,0 +1,56 @@
//===-- sanitizer_solaris.h -------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file is a part of Sanitizer runtime. It contains Solaris-specific
// definitions.
//
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_SOLARIS_H
#define SANITIZER_SOLARIS_H
#include "sanitizer_internal_defs.h"
#if SANITIZER_SOLARIS
#include <link.h>
namespace __sanitizer {
// Beginning of declaration from OpenSolaris/Illumos
// $SRC/cmd/sgs/include/rtld.h.
struct Rt_map {
Link_map rt_public;
const char *rt_pathname;
ulong_t rt_padstart;
ulong_t rt_padimlen;
ulong_t rt_msize;
uint_t rt_flags;
uint_t rt_flags1;
ulong_t rt_tlsmodid;
};
// Structure matching the Solaris 11.4 struct dl_phdr_info used to determine
// presence of dlpi_tls_modid field at runtime. Cf. Solaris 11.4
// dl_iterate_phdr(3C), Example 2.
struct dl_phdr_info_test {
ElfW(Addr) dlpi_addr;
const char *dlpi_name;
const ElfW(Phdr) * dlpi_phdr;
ElfW(Half) dlpi_phnum;
u_longlong_t dlpi_adds;
u_longlong_t dlpi_subs;
size_t dlpi_tls_modid;
void *dlpi_tls_data;
};
} // namespace __sanitizer
#endif // SANITIZER_SOLARIS
#endif // SANITIZER_SOLARIS_H