2013-05-20 23:57:44 +08:00
|
|
|
//===-- sanitizer_linux_libcdep.cc ----------------------------------------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// 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
|
2013-05-20 23:57:44 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file is shared between AddressSanitizer and ThreadSanitizer
|
|
|
|
// run-time libraries and implements linux-specific functions from
|
|
|
|
// sanitizer_libc.h.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "sanitizer_platform.h"
|
2015-10-01 07:52:54 +08:00
|
|
|
|
2018-03-20 07:12:14 +08:00
|
|
|
#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
|
|
|
|
SANITIZER_OPENBSD || SANITIZER_SOLARIS
|
2013-05-20 23:57:44 +08:00
|
|
|
|
2015-07-24 06:05:20 +08:00
|
|
|
#include "sanitizer_allocator_internal.h"
|
2015-04-02 01:56:29 +08:00
|
|
|
#include "sanitizer_atomic.h"
|
2013-05-20 23:57:44 +08:00
|
|
|
#include "sanitizer_common.h"
|
2017-07-22 09:46:40 +08:00
|
|
|
#include "sanitizer_file.h"
|
2013-10-15 22:12:26 +08:00
|
|
|
#include "sanitizer_flags.h"
|
2014-07-25 20:29:04 +08:00
|
|
|
#include "sanitizer_freebsd.h"
|
2018-11-07 03:23:22 +08:00
|
|
|
#include "sanitizer_getauxval.h"
|
2013-09-10 22:36:16 +08:00
|
|
|
#include "sanitizer_linux.h"
|
|
|
|
#include "sanitizer_placement_new.h"
|
2013-05-20 23:57:44 +08:00
|
|
|
#include "sanitizer_procmaps.h"
|
|
|
|
|
2014-09-01 23:38:16 +08:00
|
|
|
#include <dlfcn.h> // for dlsym()
|
2015-04-29 02:50:32 +08:00
|
|
|
#include <link.h>
|
2013-05-20 23:57:44 +08:00
|
|
|
#include <pthread.h>
|
2014-01-31 21:10:07 +08:00
|
|
|
#include <signal.h>
|
2013-05-20 23:57:44 +08:00
|
|
|
#include <sys/resource.h>
|
2016-09-08 07:19:16 +08:00
|
|
|
#include <syslog.h>
|
2013-05-20 23:57:44 +08:00
|
|
|
|
2014-03-07 19:47:32 +08:00
|
|
|
#if SANITIZER_FREEBSD
|
|
|
|
#include <pthread_np.h>
|
2014-07-25 20:29:04 +08:00
|
|
|
#include <osreldate.h>
|
2017-11-22 05:14:00 +08:00
|
|
|
#include <sys/sysctl.h>
|
2014-03-07 19:47:32 +08:00
|
|
|
#define pthread_getattr_np pthread_attr_get_np
|
|
|
|
#endif
|
|
|
|
|
2018-03-20 07:12:14 +08:00
|
|
|
#if SANITIZER_OPENBSD
|
|
|
|
#include <pthread_np.h>
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
#endif
|
|
|
|
|
2017-11-22 05:14:00 +08:00
|
|
|
#if SANITIZER_NETBSD
|
|
|
|
#include <sys/sysctl.h>
|
2017-12-09 10:23:33 +08:00
|
|
|
#include <sys/tls.h>
|
2017-11-22 05:14:00 +08:00
|
|
|
#endif
|
|
|
|
|
[Sanitizers] Basic sanitizer Solaris support (PR 33274)
Summary:
This is the first mostly working version of the Sanitizer port to 32-bit Solaris/x86.
It is currently based on Solaris 11.4 Beta.
This part was initially developed inside libsanitizer in the GCC tree and should apply to
both. Subsequent parts will address changes to clang, the compiler-rt build system
and testsuite.
I'm not yet sure what the right patch granularity is: if it's profitable to split the patch
up, I'd like to get guidance on how to do so.
Most of the changes are probably straightforward with a few exceptions:
* The Solaris syscall interface isn't stable, undocumented and can change within an
OS release. The stable interface is the libc interface, which I'm using here, if possible
using the internal _-prefixed names.
* While the patch primarily target 32-bit x86, I've left a few sparc changes in. They
cannot currently be used with clang due to a backend limitation, but have worked
fine inside the gcc tree.
* Some functions (e.g. largefile versions of functions like open64) only exist in 32-bit
Solaris, so I've introduced a separate SANITIZER_SOLARIS32 to check for that.
The patch (with the subsequent ones to be submitted shortly) was tested
on i386-pc-solaris2.11. Only a few failures remain, some of them analyzed, some
still TBD:
AddressSanitizer-i386-sunos :: TestCases/Posix/concurrent_overflow.cc
AddressSanitizer-i386-sunos :: TestCases/init-order-atexit.cc
AddressSanitizer-i386-sunos :: TestCases/log-path_test.cc
AddressSanitizer-i386-sunos :: TestCases/malloc-no-intercept.c
AddressSanitizer-i386-sunos-dynamic :: TestCases/Posix/concurrent_overflow.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/Posix/start-deactivated.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/default_options.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/init-order-atexit.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/log-path_test.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/malloc-no-intercept.c
SanitizerCommon-Unit :: ./Sanitizer-i386-Test/MemoryMappingLayout.DumpListOfModules
SanitizerCommon-Unit :: ./Sanitizer-i386-Test/SanitizerCommon.PthreadDestructorIterations
Maybe this is good enough the get the ball rolling.
Reviewers: kcc, alekseyshl
Reviewed By: alekseyshl
Subscribers: srhines, jyknight, kubamracek, krytarowski, fedor.sergeev, llvm-commits, #sanitizers
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D40898
llvm-svn: 320740
2017-12-15 04:14:29 +08:00
|
|
|
#if SANITIZER_SOLARIS
|
2019-04-05 16:40:08 +08:00
|
|
|
#include <stdlib.h>
|
[Sanitizers] Basic sanitizer Solaris support (PR 33274)
Summary:
This is the first mostly working version of the Sanitizer port to 32-bit Solaris/x86.
It is currently based on Solaris 11.4 Beta.
This part was initially developed inside libsanitizer in the GCC tree and should apply to
both. Subsequent parts will address changes to clang, the compiler-rt build system
and testsuite.
I'm not yet sure what the right patch granularity is: if it's profitable to split the patch
up, I'd like to get guidance on how to do so.
Most of the changes are probably straightforward with a few exceptions:
* The Solaris syscall interface isn't stable, undocumented and can change within an
OS release. The stable interface is the libc interface, which I'm using here, if possible
using the internal _-prefixed names.
* While the patch primarily target 32-bit x86, I've left a few sparc changes in. They
cannot currently be used with clang due to a backend limitation, but have worked
fine inside the gcc tree.
* Some functions (e.g. largefile versions of functions like open64) only exist in 32-bit
Solaris, so I've introduced a separate SANITIZER_SOLARIS32 to check for that.
The patch (with the subsequent ones to be submitted shortly) was tested
on i386-pc-solaris2.11. Only a few failures remain, some of them analyzed, some
still TBD:
AddressSanitizer-i386-sunos :: TestCases/Posix/concurrent_overflow.cc
AddressSanitizer-i386-sunos :: TestCases/init-order-atexit.cc
AddressSanitizer-i386-sunos :: TestCases/log-path_test.cc
AddressSanitizer-i386-sunos :: TestCases/malloc-no-intercept.c
AddressSanitizer-i386-sunos-dynamic :: TestCases/Posix/concurrent_overflow.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/Posix/start-deactivated.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/default_options.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/init-order-atexit.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/log-path_test.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/malloc-no-intercept.c
SanitizerCommon-Unit :: ./Sanitizer-i386-Test/MemoryMappingLayout.DumpListOfModules
SanitizerCommon-Unit :: ./Sanitizer-i386-Test/SanitizerCommon.PthreadDestructorIterations
Maybe this is good enough the get the ball rolling.
Reviewers: kcc, alekseyshl
Reviewed By: alekseyshl
Subscribers: srhines, jyknight, kubamracek, krytarowski, fedor.sergeev, llvm-commits, #sanitizers
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D40898
llvm-svn: 320740
2017-12-15 04:14:29 +08:00
|
|
|
#include <thread.h>
|
|
|
|
#endif
|
|
|
|
|
2015-04-29 02:50:32 +08:00
|
|
|
#if SANITIZER_ANDROID
|
|
|
|
#include <android/api-level.h>
|
2017-11-22 05:14:00 +08:00
|
|
|
#if !defined(CPU_COUNT) && !defined(__aarch64__)
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
struct __sanitizer::linux_dirent {
|
|
|
|
long d_ino;
|
|
|
|
off_t d_off;
|
|
|
|
unsigned short d_reclen;
|
|
|
|
char d_name[];
|
|
|
|
};
|
|
|
|
#endif
|
2015-04-29 02:50:32 +08:00
|
|
|
#endif
|
|
|
|
|
2013-09-10 22:36:16 +08:00
|
|
|
#if !SANITIZER_ANDROID
|
|
|
|
#include <elf.h>
|
2014-02-04 12:09:38 +08:00
|
|
|
#include <unistd.h>
|
2013-09-10 22:36:16 +08:00
|
|
|
#endif
|
|
|
|
|
2014-02-05 23:06:32 +08:00
|
|
|
namespace __sanitizer {
|
|
|
|
|
|
|
|
SANITIZER_WEAK_ATTRIBUTE int
|
|
|
|
real_sigaction(int signum, const void *act, void *oldact);
|
2014-01-31 21:10:07 +08:00
|
|
|
|
|
|
|
int internal_sigaction(int signum, const void *act, void *oldact) {
|
2015-01-31 07:04:57 +08:00
|
|
|
#if !SANITIZER_GO
|
2015-02-03 04:37:26 +08:00
|
|
|
if (&real_sigaction)
|
2014-02-05 23:06:32 +08:00
|
|
|
return real_sigaction(signum, act, oldact);
|
2015-01-31 07:04:57 +08:00
|
|
|
#endif
|
2014-11-14 06:40:59 +08:00
|
|
|
return sigaction(signum, (const struct sigaction *)act,
|
|
|
|
(struct sigaction *)oldact);
|
2014-01-31 21:10:07 +08:00
|
|
|
}
|
|
|
|
|
2013-05-20 23:57:44 +08:00
|
|
|
void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
|
|
|
|
uptr *stack_bottom) {
|
|
|
|
CHECK(stack_top);
|
|
|
|
CHECK(stack_bottom);
|
|
|
|
if (at_initialization) {
|
|
|
|
// This is the main thread. Libpthread may not be initialized yet.
|
|
|
|
struct rlimit rl;
|
|
|
|
CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
|
|
|
|
|
|
|
|
// Find the mapping that contains a stack variable.
|
|
|
|
MemoryMappingLayout proc_maps(/*cache_enabled*/true);
|
2019-01-08 09:07:34 +08:00
|
|
|
if (proc_maps.Error()) {
|
|
|
|
*stack_top = *stack_bottom = 0;
|
|
|
|
return;
|
|
|
|
}
|
2017-07-12 02:54:00 +08:00
|
|
|
MemoryMappedSegment segment;
|
2013-05-20 23:57:44 +08:00
|
|
|
uptr prev_end = 0;
|
2017-07-12 02:54:00 +08:00
|
|
|
while (proc_maps.Next(&segment)) {
|
|
|
|
if ((uptr)&rl < segment.end) break;
|
|
|
|
prev_end = segment.end;
|
2013-05-20 23:57:44 +08:00
|
|
|
}
|
2017-07-12 02:54:00 +08:00
|
|
|
CHECK((uptr)&rl >= segment.start && (uptr)&rl < segment.end);
|
2013-05-20 23:57:44 +08:00
|
|
|
|
|
|
|
// Get stacksize from rlimit, but clip it so that it does not overlap
|
|
|
|
// with other mappings.
|
|
|
|
uptr stacksize = rl.rlim_cur;
|
2017-07-12 02:54:00 +08:00
|
|
|
if (stacksize > segment.end - prev_end) stacksize = segment.end - prev_end;
|
2013-05-20 23:57:44 +08:00
|
|
|
// When running with unlimited stack size, we still want to set some limit.
|
|
|
|
// The unlimited stack size is caused by 'ulimit -s unlimited'.
|
|
|
|
// Also, for some reason, GNU make spawns subprocesses with unlimited stack.
|
|
|
|
if (stacksize > kMaxThreadStackSize)
|
|
|
|
stacksize = kMaxThreadStackSize;
|
2017-07-12 02:54:00 +08:00
|
|
|
*stack_top = segment.end;
|
|
|
|
*stack_bottom = segment.end - stacksize;
|
2013-05-20 23:57:44 +08:00
|
|
|
return;
|
|
|
|
}
|
[Sanitizers] Basic sanitizer Solaris support (PR 33274)
Summary:
This is the first mostly working version of the Sanitizer port to 32-bit Solaris/x86.
It is currently based on Solaris 11.4 Beta.
This part was initially developed inside libsanitizer in the GCC tree and should apply to
both. Subsequent parts will address changes to clang, the compiler-rt build system
and testsuite.
I'm not yet sure what the right patch granularity is: if it's profitable to split the patch
up, I'd like to get guidance on how to do so.
Most of the changes are probably straightforward with a few exceptions:
* The Solaris syscall interface isn't stable, undocumented and can change within an
OS release. The stable interface is the libc interface, which I'm using here, if possible
using the internal _-prefixed names.
* While the patch primarily target 32-bit x86, I've left a few sparc changes in. They
cannot currently be used with clang due to a backend limitation, but have worked
fine inside the gcc tree.
* Some functions (e.g. largefile versions of functions like open64) only exist in 32-bit
Solaris, so I've introduced a separate SANITIZER_SOLARIS32 to check for that.
The patch (with the subsequent ones to be submitted shortly) was tested
on i386-pc-solaris2.11. Only a few failures remain, some of them analyzed, some
still TBD:
AddressSanitizer-i386-sunos :: TestCases/Posix/concurrent_overflow.cc
AddressSanitizer-i386-sunos :: TestCases/init-order-atexit.cc
AddressSanitizer-i386-sunos :: TestCases/log-path_test.cc
AddressSanitizer-i386-sunos :: TestCases/malloc-no-intercept.c
AddressSanitizer-i386-sunos-dynamic :: TestCases/Posix/concurrent_overflow.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/Posix/start-deactivated.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/default_options.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/init-order-atexit.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/log-path_test.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/malloc-no-intercept.c
SanitizerCommon-Unit :: ./Sanitizer-i386-Test/MemoryMappingLayout.DumpListOfModules
SanitizerCommon-Unit :: ./Sanitizer-i386-Test/SanitizerCommon.PthreadDestructorIterations
Maybe this is good enough the get the ball rolling.
Reviewers: kcc, alekseyshl
Reviewed By: alekseyshl
Subscribers: srhines, jyknight, kubamracek, krytarowski, fedor.sergeev, llvm-commits, #sanitizers
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D40898
llvm-svn: 320740
2017-12-15 04:14:29 +08:00
|
|
|
uptr stacksize = 0;
|
|
|
|
void *stackaddr = nullptr;
|
|
|
|
#if SANITIZER_SOLARIS
|
|
|
|
stack_t ss;
|
|
|
|
CHECK_EQ(thr_stksegment(&ss), 0);
|
|
|
|
stacksize = ss.ss_size;
|
|
|
|
stackaddr = (char *)ss.ss_sp - stacksize;
|
2018-03-20 07:12:14 +08:00
|
|
|
#elif SANITIZER_OPENBSD
|
|
|
|
stack_t sattr;
|
|
|
|
CHECK_EQ(pthread_stackseg_np(pthread_self(), &sattr), 0);
|
|
|
|
stackaddr = sattr.ss_sp;
|
|
|
|
stacksize = sattr.ss_size;
|
|
|
|
#else // !SANITIZER_SOLARIS
|
2013-05-20 23:57:44 +08:00
|
|
|
pthread_attr_t attr;
|
2014-03-24 18:01:54 +08:00
|
|
|
pthread_attr_init(&attr);
|
2013-05-20 23:57:44 +08:00
|
|
|
CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
|
2015-11-03 22:33:39 +08:00
|
|
|
my_pthread_attr_getstack(&attr, &stackaddr, &stacksize);
|
2013-05-20 23:57:44 +08:00
|
|
|
pthread_attr_destroy(&attr);
|
[Sanitizers] Basic sanitizer Solaris support (PR 33274)
Summary:
This is the first mostly working version of the Sanitizer port to 32-bit Solaris/x86.
It is currently based on Solaris 11.4 Beta.
This part was initially developed inside libsanitizer in the GCC tree and should apply to
both. Subsequent parts will address changes to clang, the compiler-rt build system
and testsuite.
I'm not yet sure what the right patch granularity is: if it's profitable to split the patch
up, I'd like to get guidance on how to do so.
Most of the changes are probably straightforward with a few exceptions:
* The Solaris syscall interface isn't stable, undocumented and can change within an
OS release. The stable interface is the libc interface, which I'm using here, if possible
using the internal _-prefixed names.
* While the patch primarily target 32-bit x86, I've left a few sparc changes in. They
cannot currently be used with clang due to a backend limitation, but have worked
fine inside the gcc tree.
* Some functions (e.g. largefile versions of functions like open64) only exist in 32-bit
Solaris, so I've introduced a separate SANITIZER_SOLARIS32 to check for that.
The patch (with the subsequent ones to be submitted shortly) was tested
on i386-pc-solaris2.11. Only a few failures remain, some of them analyzed, some
still TBD:
AddressSanitizer-i386-sunos :: TestCases/Posix/concurrent_overflow.cc
AddressSanitizer-i386-sunos :: TestCases/init-order-atexit.cc
AddressSanitizer-i386-sunos :: TestCases/log-path_test.cc
AddressSanitizer-i386-sunos :: TestCases/malloc-no-intercept.c
AddressSanitizer-i386-sunos-dynamic :: TestCases/Posix/concurrent_overflow.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/Posix/start-deactivated.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/default_options.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/init-order-atexit.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/log-path_test.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/malloc-no-intercept.c
SanitizerCommon-Unit :: ./Sanitizer-i386-Test/MemoryMappingLayout.DumpListOfModules
SanitizerCommon-Unit :: ./Sanitizer-i386-Test/SanitizerCommon.PthreadDestructorIterations
Maybe this is good enough the get the ball rolling.
Reviewers: kcc, alekseyshl
Reviewed By: alekseyshl
Subscribers: srhines, jyknight, kubamracek, krytarowski, fedor.sergeev, llvm-commits, #sanitizers
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D40898
llvm-svn: 320740
2017-12-15 04:14:29 +08:00
|
|
|
#endif // SANITIZER_SOLARIS
|
2013-05-20 23:57:44 +08:00
|
|
|
|
|
|
|
*stack_top = (uptr)stackaddr + stacksize;
|
|
|
|
*stack_bottom = (uptr)stackaddr;
|
|
|
|
}
|
|
|
|
|
2015-01-31 09:27:18 +08:00
|
|
|
#if !SANITIZER_GO
|
|
|
|
bool SetEnv(const char *name, const char *value) {
|
|
|
|
void *f = dlsym(RTLD_NEXT, "setenv");
|
2015-10-01 07:52:54 +08:00
|
|
|
if (!f)
|
2015-01-31 09:27:18 +08:00
|
|
|
return false;
|
|
|
|
typedef int(*setenv_ft)(const char *name, const char *value, int overwrite);
|
|
|
|
setenv_ft setenv_f;
|
|
|
|
CHECK_EQ(sizeof(setenv_f), sizeof(f));
|
|
|
|
internal_memcpy(&setenv_f, &f, sizeof(f));
|
|
|
|
return setenv_f(name, value, 1) == 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-06-18 13:55:44 +08:00
|
|
|
__attribute__((unused)) static bool GetLibcVersion(int *major, int *minor,
|
|
|
|
int *patch) {
|
2018-06-18 01:58:08 +08:00
|
|
|
#ifdef _CS_GNU_LIBC_VERSION
|
|
|
|
char buf[64];
|
|
|
|
uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf));
|
|
|
|
if (len >= sizeof(buf))
|
|
|
|
return false;
|
|
|
|
buf[len] = 0;
|
|
|
|
static const char kGLibC[] = "glibc ";
|
|
|
|
if (internal_strncmp(buf, kGLibC, sizeof(kGLibC) - 1) != 0)
|
|
|
|
return false;
|
|
|
|
const char *p = buf + sizeof(kGLibC) - 1;
|
|
|
|
*major = internal_simple_strtoll(p, &p, 10);
|
|
|
|
*minor = (*p == '.') ? internal_simple_strtoll(p + 1, &p, 10) : 0;
|
|
|
|
*patch = (*p == '.') ? internal_simple_strtoll(p + 1, &p, 10) : 0;
|
|
|
|
return true;
|
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-03-20 07:12:14 +08:00
|
|
|
#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO && \
|
|
|
|
!SANITIZER_NETBSD && !SANITIZER_OPENBSD && !SANITIZER_SOLARIS
|
2013-05-20 23:57:44 +08:00
|
|
|
static uptr g_tls_size;
|
|
|
|
|
|
|
|
#ifdef __i386__
|
2018-06-10 19:17:47 +08:00
|
|
|
# ifndef __GLIBC_PREREQ
|
|
|
|
# define CHECK_GET_TLS_STATIC_INFO_VERSION 1
|
|
|
|
# else
|
|
|
|
# define CHECK_GET_TLS_STATIC_INFO_VERSION (!__GLIBC_PREREQ(2, 27))
|
|
|
|
# endif
|
|
|
|
#else
|
|
|
|
# define CHECK_GET_TLS_STATIC_INFO_VERSION 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if CHECK_GET_TLS_STATIC_INFO_VERSION
|
2013-05-20 23:57:44 +08:00
|
|
|
# define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
|
|
|
|
#else
|
|
|
|
# define DL_INTERNAL_FUNCTION
|
|
|
|
#endif
|
|
|
|
|
2018-06-10 19:17:47 +08:00
|
|
|
namespace {
|
|
|
|
struct GetTlsStaticInfoCall {
|
|
|
|
typedef void (*get_tls_func)(size_t*, size_t*);
|
|
|
|
};
|
|
|
|
struct GetTlsStaticInfoRegparmCall {
|
|
|
|
typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void CallGetTls(void* ptr, size_t* size, size_t* align) {
|
|
|
|
typename T::get_tls_func get_tls;
|
|
|
|
CHECK_EQ(sizeof(get_tls), sizeof(ptr));
|
|
|
|
internal_memcpy(&get_tls, &ptr, sizeof(ptr));
|
|
|
|
CHECK_NE(get_tls, 0);
|
|
|
|
get_tls(size, align);
|
|
|
|
}
|
2018-06-18 01:31:22 +08:00
|
|
|
|
|
|
|
bool CmpLibcVersion(int major, int minor, int patch) {
|
|
|
|
int ma;
|
|
|
|
int mi;
|
|
|
|
int pa;
|
|
|
|
if (!GetLibcVersion(&ma, &mi, &pa))
|
|
|
|
return false;
|
|
|
|
if (ma > major)
|
|
|
|
return true;
|
|
|
|
if (ma < major)
|
|
|
|
return false;
|
|
|
|
if (mi > minor)
|
|
|
|
return true;
|
|
|
|
if (mi < minor)
|
|
|
|
return false;
|
|
|
|
return pa >= patch;
|
|
|
|
}
|
|
|
|
|
2018-06-10 19:17:47 +08:00
|
|
|
} // namespace
|
|
|
|
|
2013-05-20 23:57:44 +08:00
|
|
|
void InitTlsSize() {
|
2018-03-20 07:12:14 +08:00
|
|
|
// all current supported platforms have 16 bytes stack alignment
|
2015-08-05 23:17:59 +08:00
|
|
|
const size_t kStackAlign = 16;
|
2013-05-20 23:57:44 +08:00
|
|
|
void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
|
|
|
|
size_t tls_size = 0;
|
|
|
|
size_t tls_align = 0;
|
2018-06-10 19:17:47 +08:00
|
|
|
// On i?86, _dl_get_tls_static_info used to be internal_function, i.e.
|
|
|
|
// __attribute__((regparm(3), stdcall)) before glibc 2.27 and is normal
|
|
|
|
// function in 2.27 and later.
|
2018-06-18 01:31:22 +08:00
|
|
|
if (CHECK_GET_TLS_STATIC_INFO_VERSION && !CmpLibcVersion(2, 27, 0))
|
2018-06-10 19:17:47 +08:00
|
|
|
CallGetTls<GetTlsStaticInfoRegparmCall>(get_tls_static_info_ptr,
|
|
|
|
&tls_size, &tls_align);
|
|
|
|
else
|
|
|
|
CallGetTls<GetTlsStaticInfoCall>(get_tls_static_info_ptr,
|
|
|
|
&tls_size, &tls_align);
|
2015-08-05 23:17:59 +08:00
|
|
|
if (tls_align < kStackAlign)
|
|
|
|
tls_align = kStackAlign;
|
|
|
|
g_tls_size = RoundUpTo(tls_size, tls_align);
|
2013-05-20 23:57:44 +08:00
|
|
|
}
|
2016-03-16 16:23:10 +08:00
|
|
|
#else
|
|
|
|
void InitTlsSize() { }
|
2017-08-05 06:32:46 +08:00
|
|
|
#endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO &&
|
[Sanitizers] Basic sanitizer Solaris support (PR 33274)
Summary:
This is the first mostly working version of the Sanitizer port to 32-bit Solaris/x86.
It is currently based on Solaris 11.4 Beta.
This part was initially developed inside libsanitizer in the GCC tree and should apply to
both. Subsequent parts will address changes to clang, the compiler-rt build system
and testsuite.
I'm not yet sure what the right patch granularity is: if it's profitable to split the patch
up, I'd like to get guidance on how to do so.
Most of the changes are probably straightforward with a few exceptions:
* The Solaris syscall interface isn't stable, undocumented and can change within an
OS release. The stable interface is the libc interface, which I'm using here, if possible
using the internal _-prefixed names.
* While the patch primarily target 32-bit x86, I've left a few sparc changes in. They
cannot currently be used with clang due to a backend limitation, but have worked
fine inside the gcc tree.
* Some functions (e.g. largefile versions of functions like open64) only exist in 32-bit
Solaris, so I've introduced a separate SANITIZER_SOLARIS32 to check for that.
The patch (with the subsequent ones to be submitted shortly) was tested
on i386-pc-solaris2.11. Only a few failures remain, some of them analyzed, some
still TBD:
AddressSanitizer-i386-sunos :: TestCases/Posix/concurrent_overflow.cc
AddressSanitizer-i386-sunos :: TestCases/init-order-atexit.cc
AddressSanitizer-i386-sunos :: TestCases/log-path_test.cc
AddressSanitizer-i386-sunos :: TestCases/malloc-no-intercept.c
AddressSanitizer-i386-sunos-dynamic :: TestCases/Posix/concurrent_overflow.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/Posix/start-deactivated.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/default_options.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/init-order-atexit.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/log-path_test.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/malloc-no-intercept.c
SanitizerCommon-Unit :: ./Sanitizer-i386-Test/MemoryMappingLayout.DumpListOfModules
SanitizerCommon-Unit :: ./Sanitizer-i386-Test/SanitizerCommon.PthreadDestructorIterations
Maybe this is good enough the get the ball rolling.
Reviewers: kcc, alekseyshl
Reviewed By: alekseyshl
Subscribers: srhines, jyknight, kubamracek, krytarowski, fedor.sergeev, llvm-commits, #sanitizers
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D40898
llvm-svn: 320740
2017-12-15 04:14:29 +08:00
|
|
|
// !SANITIZER_NETBSD && !SANITIZER_SOLARIS
|
2013-05-20 23:57:44 +08:00
|
|
|
|
2018-03-20 07:12:14 +08:00
|
|
|
#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) || \
|
|
|
|
defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) || \
|
|
|
|
defined(__arm__)) && \
|
|
|
|
SANITIZER_LINUX && !SANITIZER_ANDROID
|
2015-11-11 23:37:47 +08:00
|
|
|
// sizeof(struct pthread) from glibc.
|
[sanitizer] Minor refactor of ThreadDescriptorSize
Summary:
While I was sifting through dead code findings, I stumbled on this function.
First, for `__s390__` it always returned 0 for the 1st call, which doesn't seem
right. 2nd call & beyond would return the correct value though.
Then it duplicated the `atomic_store` multiple times, sometimes with a `if`,
sometimes without. Finally it used a capitalized variable name starting with `k`
which indicates a constant, and it is not.
So:
- rename the static global variable;
- change the atomic functions to their relaxed version;
- move the store to the end, and make sure we return `val` all the time.
Reviewers: alekseyshl, eugenis, koriakin
Reviewed By: alekseyshl
Subscribers: kubamracek, delcypher, llvm-commits, #sanitizers
Differential Revision: https://reviews.llvm.org/D45725
llvm-svn: 330268
2018-04-18 23:30:08 +08:00
|
|
|
static atomic_uintptr_t thread_descriptor_size;
|
2013-05-20 23:57:44 +08:00
|
|
|
|
|
|
|
uptr ThreadDescriptorSize() {
|
[sanitizer] Minor refactor of ThreadDescriptorSize
Summary:
While I was sifting through dead code findings, I stumbled on this function.
First, for `__s390__` it always returned 0 for the 1st call, which doesn't seem
right. 2nd call & beyond would return the correct value though.
Then it duplicated the `atomic_store` multiple times, sometimes with a `if`,
sometimes without. Finally it used a capitalized variable name starting with `k`
which indicates a constant, and it is not.
So:
- rename the static global variable;
- change the atomic functions to their relaxed version;
- move the store to the end, and make sure we return `val` all the time.
Reviewers: alekseyshl, eugenis, koriakin
Reviewed By: alekseyshl
Subscribers: kubamracek, delcypher, llvm-commits, #sanitizers
Differential Revision: https://reviews.llvm.org/D45725
llvm-svn: 330268
2018-04-18 23:30:08 +08:00
|
|
|
uptr val = atomic_load_relaxed(&thread_descriptor_size);
|
2014-02-04 12:09:38 +08:00
|
|
|
if (val)
|
|
|
|
return val;
|
2017-04-11 22:58:26 +08:00
|
|
|
#if defined(__x86_64__) || defined(__i386__) || defined(__arm__)
|
2018-06-18 01:31:22 +08:00
|
|
|
int major;
|
|
|
|
int minor;
|
|
|
|
int patch;
|
|
|
|
if (GetLibcVersion(&major, &minor, &patch) && major == 2) {
|
|
|
|
/* sizeof(struct pthread) values from various glibc versions. */
|
|
|
|
if (SANITIZER_X32)
|
|
|
|
val = 1728; // Assume only one particular version for x32.
|
|
|
|
// For ARM sizeof(struct pthread) changed in Glibc 2.23.
|
|
|
|
else if (SANITIZER_ARM)
|
|
|
|
val = minor <= 22 ? 1120 : 1216;
|
|
|
|
else if (minor <= 3)
|
|
|
|
val = FIRST_32_SECOND_64(1104, 1696);
|
|
|
|
else if (minor == 4)
|
|
|
|
val = FIRST_32_SECOND_64(1120, 1728);
|
|
|
|
else if (minor == 5)
|
|
|
|
val = FIRST_32_SECOND_64(1136, 1728);
|
|
|
|
else if (minor <= 9)
|
|
|
|
val = FIRST_32_SECOND_64(1136, 1712);
|
|
|
|
else if (minor == 10)
|
|
|
|
val = FIRST_32_SECOND_64(1168, 1776);
|
|
|
|
else if (minor == 11 || (minor == 12 && patch == 1))
|
|
|
|
val = FIRST_32_SECOND_64(1168, 2288);
|
2018-08-02 02:29:51 +08:00
|
|
|
else if (minor <= 14)
|
2018-06-18 01:31:22 +08:00
|
|
|
val = FIRST_32_SECOND_64(1168, 2304);
|
|
|
|
else
|
|
|
|
val = FIRST_32_SECOND_64(1216, 2304);
|
2014-02-04 12:09:38 +08:00
|
|
|
}
|
2015-02-19 15:30:39 +08:00
|
|
|
#elif defined(__mips__)
|
|
|
|
// TODO(sagarthakur): add more values as per different glibc versions.
|
|
|
|
val = FIRST_32_SECOND_64(1152, 1776);
|
2015-08-05 23:17:59 +08:00
|
|
|
#elif defined(__aarch64__)
|
|
|
|
// The sizeof (struct pthread) is the same from GLIBC 2.17 to 2.22.
|
|
|
|
val = 1776;
|
2015-11-11 23:37:47 +08:00
|
|
|
#elif defined(__powerpc64__)
|
|
|
|
val = 1776; // from glibc.ppc64le 2.20-8.fc21
|
2016-06-18 04:24:32 +08:00
|
|
|
#elif defined(__s390__)
|
|
|
|
val = FIRST_32_SECOND_64(1152, 1776); // valid for glibc 2.22
|
2014-02-04 12:09:38 +08:00
|
|
|
#endif
|
[sanitizer] Minor refactor of ThreadDescriptorSize
Summary:
While I was sifting through dead code findings, I stumbled on this function.
First, for `__s390__` it always returned 0 for the 1st call, which doesn't seem
right. 2nd call & beyond would return the correct value though.
Then it duplicated the `atomic_store` multiple times, sometimes with a `if`,
sometimes without. Finally it used a capitalized variable name starting with `k`
which indicates a constant, and it is not.
So:
- rename the static global variable;
- change the atomic functions to their relaxed version;
- move the store to the end, and make sure we return `val` all the time.
Reviewers: alekseyshl, eugenis, koriakin
Reviewed By: alekseyshl
Subscribers: kubamracek, delcypher, llvm-commits, #sanitizers
Differential Revision: https://reviews.llvm.org/D45725
llvm-svn: 330268
2018-04-18 23:30:08 +08:00
|
|
|
if (val)
|
|
|
|
atomic_store_relaxed(&thread_descriptor_size, val);
|
|
|
|
return val;
|
2013-05-20 23:57:44 +08:00
|
|
|
}
|
2013-05-29 21:07:42 +08:00
|
|
|
|
|
|
|
// The offset at which pointer to self is located in the thread descriptor.
|
|
|
|
const uptr kThreadSelfOffset = FIRST_32_SECOND_64(8, 16);
|
|
|
|
|
|
|
|
uptr ThreadSelfOffset() {
|
|
|
|
return kThreadSelfOffset;
|
|
|
|
}
|
|
|
|
|
2016-03-16 16:23:10 +08:00
|
|
|
#if defined(__mips__) || defined(__powerpc64__)
|
|
|
|
// TlsPreTcbSize includes size of struct pthread_descr and size of tcb
|
|
|
|
// head structure. It lies before the static tls blocks.
|
|
|
|
static uptr TlsPreTcbSize() {
|
|
|
|
# if defined(__mips__)
|
|
|
|
const uptr kTcbHead = 16; // sizeof (tcbhead_t)
|
|
|
|
# elif defined(__powerpc64__)
|
|
|
|
const uptr kTcbHead = 88; // sizeof (tcbhead_t)
|
|
|
|
# endif
|
|
|
|
const uptr kTlsAlign = 16;
|
|
|
|
const uptr kTlsPreTcbSize =
|
2017-01-31 09:53:36 +08:00
|
|
|
RoundUpTo(ThreadDescriptorSize() + kTcbHead, kTlsAlign);
|
2016-03-16 16:23:10 +08:00
|
|
|
return kTlsPreTcbSize;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-05-29 21:07:42 +08:00
|
|
|
uptr ThreadSelf() {
|
|
|
|
uptr descr_addr;
|
2014-03-07 19:47:32 +08:00
|
|
|
# if defined(__i386__)
|
2013-05-29 21:07:42 +08:00
|
|
|
asm("mov %%gs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
|
2014-03-07 19:47:32 +08:00
|
|
|
# elif defined(__x86_64__)
|
2013-05-29 21:07:42 +08:00
|
|
|
asm("mov %%fs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
|
2015-02-19 15:30:39 +08:00
|
|
|
# elif defined(__mips__)
|
|
|
|
// MIPS uses TLS variant I. The thread pointer (in hardware register $29)
|
|
|
|
// points to the end of the TCB + 0x7000. The pthread_descr structure is
|
|
|
|
// immediately in front of the TCB. TlsPreTcbSize() includes the size of the
|
|
|
|
// TCB and the size of pthread_descr.
|
|
|
|
const uptr kTlsTcbOffset = 0x7000;
|
|
|
|
uptr thread_pointer;
|
|
|
|
asm volatile(".set push;\
|
|
|
|
.set mips64r2;\
|
|
|
|
rdhwr %0,$29;\
|
|
|
|
.set pop" : "=r" (thread_pointer));
|
|
|
|
descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize();
|
2017-04-11 22:58:26 +08:00
|
|
|
# elif defined(__aarch64__) || defined(__arm__)
|
2016-09-28 18:15:15 +08:00
|
|
|
descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
|
|
|
|
ThreadDescriptorSize();
|
|
|
|
# elif defined(__s390__)
|
2015-08-05 23:17:59 +08:00
|
|
|
descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer());
|
2015-11-11 23:37:47 +08:00
|
|
|
# elif defined(__powerpc64__)
|
|
|
|
// PPC64LE uses TLS variant I. The thread pointer (in GPR 13)
|
|
|
|
// points to the end of the TCB + 0x7000. The pthread_descr structure is
|
|
|
|
// immediately in front of the TCB. TlsPreTcbSize() includes the size of the
|
|
|
|
// TCB and the size of pthread_descr.
|
|
|
|
const uptr kTlsTcbOffset = 0x7000;
|
|
|
|
uptr thread_pointer;
|
|
|
|
asm("addi %0,13,%1" : "=r"(thread_pointer) : "I"(-kTlsTcbOffset));
|
|
|
|
descr_addr = thread_pointer - TlsPreTcbSize();
|
2014-03-07 19:47:32 +08:00
|
|
|
# else
|
|
|
|
# error "unsupported CPU arch"
|
|
|
|
# endif
|
2013-05-29 21:07:42 +08:00
|
|
|
return descr_addr;
|
|
|
|
}
|
2015-02-20 09:45:51 +08:00
|
|
|
#endif // (x86_64 || i386 || MIPS) && SANITIZER_LINUX
|
2014-03-07 19:47:32 +08:00
|
|
|
|
2017-12-09 10:23:33 +08:00
|
|
|
#if SANITIZER_FREEBSD
|
2014-03-07 19:47:32 +08:00
|
|
|
static void **ThreadSelfSegbase() {
|
|
|
|
void **segbase = 0;
|
|
|
|
# if defined(__i386__)
|
|
|
|
// sysarch(I386_GET_GSBASE, segbase);
|
|
|
|
__asm __volatile("mov %%gs:0, %0" : "=r" (segbase));
|
|
|
|
# elif defined(__x86_64__)
|
|
|
|
// sysarch(AMD64_GET_FSBASE, segbase);
|
|
|
|
__asm __volatile("movq %%fs:0, %0" : "=r" (segbase));
|
|
|
|
# else
|
2017-11-17 01:54:14 +08:00
|
|
|
# error "unsupported CPU arch"
|
2014-03-07 19:47:32 +08:00
|
|
|
# endif
|
|
|
|
return segbase;
|
|
|
|
}
|
|
|
|
|
|
|
|
uptr ThreadSelf() {
|
|
|
|
return (uptr)ThreadSelfSegbase()[2];
|
|
|
|
}
|
2017-12-09 10:23:33 +08:00
|
|
|
#endif // SANITIZER_FREEBSD
|
|
|
|
|
|
|
|
#if SANITIZER_NETBSD
|
|
|
|
static struct tls_tcb * ThreadSelfTlsTcb() {
|
|
|
|
struct tls_tcb * tcb;
|
|
|
|
# ifdef __HAVE___LWP_GETTCB_FAST
|
|
|
|
tcb = (struct tls_tcb *)__lwp_gettcb_fast();
|
|
|
|
# elif defined(__HAVE___LWP_GETPRIVATE_FAST)
|
|
|
|
tcb = (struct tls_tcb *)__lwp_getprivate_fast();
|
|
|
|
# endif
|
|
|
|
return tcb;
|
|
|
|
}
|
|
|
|
|
|
|
|
uptr ThreadSelf() {
|
|
|
|
return (uptr)ThreadSelfTlsTcb()->tcb_pthread;
|
|
|
|
}
|
|
|
|
|
|
|
|
int GetSizeFromHdr(struct dl_phdr_info *info, size_t size, void *data) {
|
|
|
|
const Elf_Phdr *hdr = info->dlpi_phdr;
|
|
|
|
const Elf_Phdr *last_hdr = hdr + info->dlpi_phnum;
|
|
|
|
|
|
|
|
for (; hdr != last_hdr; ++hdr) {
|
|
|
|
if (hdr->p_type == PT_TLS && info->dlpi_tls_modid == 1) {
|
|
|
|
*(uptr*)data = hdr->p_memsz;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif // SANITIZER_NETBSD
|
2014-03-07 19:47:32 +08:00
|
|
|
|
2015-01-31 07:04:57 +08:00
|
|
|
#if !SANITIZER_GO
|
2014-03-07 19:47:32 +08:00
|
|
|
static void GetTls(uptr *addr, uptr *size) {
|
2015-08-22 08:47:12 +08:00
|
|
|
#if SANITIZER_LINUX && !SANITIZER_ANDROID
|
2016-06-18 04:24:32 +08:00
|
|
|
# if defined(__x86_64__) || defined(__i386__) || defined(__s390__)
|
2014-03-07 19:47:32 +08:00
|
|
|
*addr = ThreadSelf();
|
|
|
|
*size = GetTlsSize();
|
|
|
|
*addr -= *size;
|
|
|
|
*addr += ThreadDescriptorSize();
|
2017-04-11 22:58:26 +08:00
|
|
|
# elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) \
|
|
|
|
|| defined(__arm__)
|
2015-02-19 15:30:39 +08:00
|
|
|
*addr = ThreadSelf();
|
|
|
|
*size = GetTlsSize();
|
2014-03-07 19:47:32 +08:00
|
|
|
# else
|
|
|
|
*addr = 0;
|
|
|
|
*size = 0;
|
|
|
|
# endif
|
2017-12-09 10:23:33 +08:00
|
|
|
#elif SANITIZER_FREEBSD
|
2014-03-07 19:47:32 +08:00
|
|
|
void** segbase = ThreadSelfSegbase();
|
|
|
|
*addr = 0;
|
|
|
|
*size = 0;
|
|
|
|
if (segbase != 0) {
|
|
|
|
// tcbalign = 16
|
|
|
|
// tls_size = round(tls_static_space, tcbalign);
|
|
|
|
// dtv = segbase[1];
|
|
|
|
// dtv[2] = segbase - tls_static_space;
|
|
|
|
void **dtv = (void**) segbase[1];
|
|
|
|
*addr = (uptr) dtv[2];
|
|
|
|
*size = (*addr == 0) ? 0 : ((uptr) segbase[0] - (uptr) dtv[2]);
|
|
|
|
}
|
2017-12-09 10:23:33 +08:00
|
|
|
#elif SANITIZER_NETBSD
|
|
|
|
struct tls_tcb * const tcb = ThreadSelfTlsTcb();
|
|
|
|
*addr = 0;
|
|
|
|
*size = 0;
|
|
|
|
if (tcb != 0) {
|
|
|
|
// Find size (p_memsz) of dlpi_tls_modid 1 (TLS block of the main program).
|
|
|
|
// ld.elf_so hardcodes the index 1.
|
|
|
|
dl_iterate_phdr(GetSizeFromHdr, size);
|
|
|
|
|
|
|
|
if (*size != 0) {
|
|
|
|
// The block has been found and tcb_dtv[1] contains the base address
|
|
|
|
*addr = (uptr)tcb->tcb_dtv[1];
|
|
|
|
}
|
|
|
|
}
|
2018-03-20 07:12:14 +08:00
|
|
|
#elif SANITIZER_OPENBSD
|
|
|
|
*addr = 0;
|
|
|
|
*size = 0;
|
2017-11-17 01:54:14 +08:00
|
|
|
#elif SANITIZER_ANDROID
|
2015-08-22 08:47:12 +08:00
|
|
|
*addr = 0;
|
|
|
|
*size = 0;
|
[Sanitizers] Basic sanitizer Solaris support (PR 33274)
Summary:
This is the first mostly working version of the Sanitizer port to 32-bit Solaris/x86.
It is currently based on Solaris 11.4 Beta.
This part was initially developed inside libsanitizer in the GCC tree and should apply to
both. Subsequent parts will address changes to clang, the compiler-rt build system
and testsuite.
I'm not yet sure what the right patch granularity is: if it's profitable to split the patch
up, I'd like to get guidance on how to do so.
Most of the changes are probably straightforward with a few exceptions:
* The Solaris syscall interface isn't stable, undocumented and can change within an
OS release. The stable interface is the libc interface, which I'm using here, if possible
using the internal _-prefixed names.
* While the patch primarily target 32-bit x86, I've left a few sparc changes in. They
cannot currently be used with clang due to a backend limitation, but have worked
fine inside the gcc tree.
* Some functions (e.g. largefile versions of functions like open64) only exist in 32-bit
Solaris, so I've introduced a separate SANITIZER_SOLARIS32 to check for that.
The patch (with the subsequent ones to be submitted shortly) was tested
on i386-pc-solaris2.11. Only a few failures remain, some of them analyzed, some
still TBD:
AddressSanitizer-i386-sunos :: TestCases/Posix/concurrent_overflow.cc
AddressSanitizer-i386-sunos :: TestCases/init-order-atexit.cc
AddressSanitizer-i386-sunos :: TestCases/log-path_test.cc
AddressSanitizer-i386-sunos :: TestCases/malloc-no-intercept.c
AddressSanitizer-i386-sunos-dynamic :: TestCases/Posix/concurrent_overflow.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/Posix/start-deactivated.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/default_options.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/init-order-atexit.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/log-path_test.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/malloc-no-intercept.c
SanitizerCommon-Unit :: ./Sanitizer-i386-Test/MemoryMappingLayout.DumpListOfModules
SanitizerCommon-Unit :: ./Sanitizer-i386-Test/SanitizerCommon.PthreadDestructorIterations
Maybe this is good enough the get the ball rolling.
Reviewers: kcc, alekseyshl
Reviewed By: alekseyshl
Subscribers: srhines, jyknight, kubamracek, krytarowski, fedor.sergeev, llvm-commits, #sanitizers
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D40898
llvm-svn: 320740
2017-12-15 04:14:29 +08:00
|
|
|
#elif SANITIZER_SOLARIS
|
|
|
|
// FIXME
|
|
|
|
*addr = 0;
|
|
|
|
*size = 0;
|
2014-03-07 19:47:32 +08:00
|
|
|
#else
|
|
|
|
# error "Unknown OS"
|
|
|
|
#endif
|
|
|
|
}
|
2015-01-31 07:04:57 +08:00
|
|
|
#endif
|
2013-05-20 23:57:44 +08:00
|
|
|
|
2015-02-16 22:35:51 +08:00
|
|
|
#if !SANITIZER_GO
|
2014-03-24 18:01:54 +08:00
|
|
|
uptr GetTlsSize() {
|
2018-03-20 07:12:14 +08:00
|
|
|
#if SANITIZER_FREEBSD || SANITIZER_ANDROID || SANITIZER_NETBSD || \
|
|
|
|
SANITIZER_OPENBSD || SANITIZER_SOLARIS
|
2014-03-24 18:01:54 +08:00
|
|
|
uptr addr, size;
|
|
|
|
GetTls(&addr, &size);
|
|
|
|
return size;
|
2017-01-31 09:53:36 +08:00
|
|
|
#elif defined(__mips__) || defined(__powerpc64__)
|
|
|
|
return RoundUpTo(g_tls_size + TlsPreTcbSize(), 16);
|
2014-03-24 18:01:54 +08:00
|
|
|
#else
|
|
|
|
return g_tls_size;
|
|
|
|
#endif
|
|
|
|
}
|
2015-02-16 22:35:51 +08:00
|
|
|
#endif
|
2014-03-24 18:01:54 +08:00
|
|
|
|
2013-05-20 23:57:44 +08:00
|
|
|
void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
|
|
|
|
uptr *tls_addr, uptr *tls_size) {
|
2015-01-31 07:04:57 +08:00
|
|
|
#if SANITIZER_GO
|
|
|
|
// Stub implementation for Go.
|
|
|
|
*stk_addr = *stk_size = *tls_addr = *tls_size = 0;
|
|
|
|
#else
|
2014-03-07 19:47:32 +08:00
|
|
|
GetTls(tls_addr, tls_size);
|
2013-05-20 23:57:44 +08:00
|
|
|
|
|
|
|
uptr stack_top, stack_bottom;
|
|
|
|
GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
|
|
|
|
*stk_addr = stack_bottom;
|
|
|
|
*stk_size = stack_top - stack_bottom;
|
|
|
|
|
|
|
|
if (!main) {
|
|
|
|
// If stack and tls intersect, make them non-intersecting.
|
|
|
|
if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) {
|
|
|
|
CHECK_GT(*tls_addr + *tls_size, *stk_addr);
|
|
|
|
CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size);
|
|
|
|
*stk_size -= *tls_size;
|
|
|
|
*tls_addr = *stk_addr + *stk_size;
|
|
|
|
}
|
|
|
|
}
|
2015-01-31 07:04:57 +08:00
|
|
|
#endif
|
2013-05-20 23:57:44 +08:00
|
|
|
}
|
|
|
|
|
2018-03-20 07:12:14 +08:00
|
|
|
#if !SANITIZER_FREEBSD && !SANITIZER_OPENBSD
|
2013-09-10 22:36:16 +08:00
|
|
|
typedef ElfW(Phdr) Elf_Phdr;
|
2018-03-20 07:12:14 +08:00
|
|
|
#elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001 // v9.2
|
|
|
|
#define Elf_Phdr XElf32_Phdr
|
|
|
|
#define dl_phdr_info xdl_phdr_info
|
|
|
|
#define dl_iterate_phdr(c, b) xdl_iterate_phdr((c), (b))
|
|
|
|
#endif // !SANITIZER_FREEBSD && !SANITIZER_OPENBSD
|
2013-09-10 22:36:16 +08:00
|
|
|
|
|
|
|
struct DlIteratePhdrData {
|
2017-09-30 04:55:06 +08:00
|
|
|
InternalMmapVectorNoCtor<LoadedModule> *modules;
|
2013-09-10 22:36:16 +08:00
|
|
|
bool first;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
|
|
|
|
DlIteratePhdrData *data = (DlIteratePhdrData*)arg;
|
2014-12-03 06:20:11 +08:00
|
|
|
InternalScopedString module_name(kMaxPathLength);
|
2013-09-10 22:36:16 +08:00
|
|
|
if (data->first) {
|
|
|
|
data->first = false;
|
|
|
|
// First module is the binary itself.
|
2015-06-29 23:58:16 +08:00
|
|
|
ReadBinaryNameCached(module_name.data(), module_name.size());
|
2013-09-10 22:36:16 +08:00
|
|
|
} else if (info->dlpi_name) {
|
2014-12-03 06:20:11 +08:00
|
|
|
module_name.append("%s", info->dlpi_name);
|
2013-09-10 22:36:16 +08:00
|
|
|
}
|
2014-12-03 06:20:11 +08:00
|
|
|
if (module_name[0] == '\0')
|
2013-09-10 22:36:16 +08:00
|
|
|
return 0;
|
2016-02-23 02:52:51 +08:00
|
|
|
LoadedModule cur_module;
|
|
|
|
cur_module.set(module_name.data(), info->dlpi_addr);
|
2018-06-14 12:51:26 +08:00
|
|
|
for (int i = 0; i < (int)info->dlpi_phnum; i++) {
|
2013-09-10 22:36:16 +08:00
|
|
|
const Elf_Phdr *phdr = &info->dlpi_phdr[i];
|
|
|
|
if (phdr->p_type == PT_LOAD) {
|
|
|
|
uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
|
|
|
|
uptr cur_end = cur_beg + phdr->p_memsz;
|
2014-06-11 18:11:51 +08:00
|
|
|
bool executable = phdr->p_flags & PF_X;
|
2017-05-19 21:34:02 +08:00
|
|
|
bool writable = phdr->p_flags & PF_W;
|
2017-04-18 00:34:38 +08:00
|
|
|
cur_module.addAddressRange(cur_beg, cur_end, executable,
|
2017-05-19 21:34:02 +08:00
|
|
|
writable);
|
2013-09-10 22:36:16 +08:00
|
|
|
}
|
|
|
|
}
|
2016-02-23 02:52:51 +08:00
|
|
|
data->modules->push_back(cur_module);
|
2013-09-10 22:36:16 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-29 02:50:32 +08:00
|
|
|
#if SANITIZER_ANDROID && __ANDROID_API__ < 21
|
|
|
|
extern "C" __attribute__((weak)) int dl_iterate_phdr(
|
|
|
|
int (*)(struct dl_phdr_info *, size_t, void *), void *);
|
|
|
|
#endif
|
|
|
|
|
2017-09-29 23:06:47 +08:00
|
|
|
static bool requiresProcmaps() {
|
2015-08-01 05:35:15 +08:00
|
|
|
#if SANITIZER_ANDROID && __ANDROID_API__ <= 22
|
2015-05-07 02:55:31 +08:00
|
|
|
// Fall back to /proc/maps if dl_iterate_phdr is unavailable or broken.
|
2015-04-29 02:50:32 +08:00
|
|
|
// The runtime check allows the same library to work with
|
|
|
|
// both K and L (and future) Android releases.
|
2017-09-29 23:06:47 +08:00
|
|
|
return AndroidGetApiLevel() <= ANDROID_LOLLIPOP_MR1;
|
|
|
|
#else
|
|
|
|
return false;
|
2017-09-29 03:37:17 +08:00
|
|
|
#endif
|
2017-09-29 23:06:47 +08:00
|
|
|
}
|
|
|
|
|
2017-09-30 04:55:06 +08:00
|
|
|
static void procmapsInit(InternalMmapVectorNoCtor<LoadedModule> *modules) {
|
2017-10-03 04:22:16 +08:00
|
|
|
MemoryMappingLayout memory_mapping(/*cache_enabled*/true);
|
2017-09-29 23:06:47 +08:00
|
|
|
memory_mapping.DumpListOfModules(modules);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ListOfModules::init() {
|
2017-09-30 04:55:06 +08:00
|
|
|
clearOrInit();
|
2017-09-29 23:06:47 +08:00
|
|
|
if (requiresProcmaps()) {
|
|
|
|
procmapsInit(&modules_);
|
|
|
|
} else {
|
|
|
|
DlIteratePhdrData data = {&modules_, true};
|
|
|
|
dl_iterate_phdr(dl_iterate_phdr_cb, &data);
|
|
|
|
}
|
2013-09-10 22:36:16 +08:00
|
|
|
}
|
|
|
|
|
2017-10-03 04:22:16 +08:00
|
|
|
// When a custom loader is used, dl_iterate_phdr may not contain the full
|
|
|
|
// list of modules. Allow callers to fall back to using procmaps.
|
|
|
|
void ListOfModules::fallbackInit() {
|
|
|
|
if (!requiresProcmaps()) {
|
|
|
|
clearOrInit();
|
|
|
|
procmapsInit(&modules_);
|
|
|
|
} else {
|
|
|
|
clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-29 10:54:39 +08:00
|
|
|
// getrusage does not give us the current RSS, only the max RSS.
|
|
|
|
// Still, this is better than nothing if /proc/self/statm is not available
|
|
|
|
// for some reason, e.g. due to a sandbox.
|
|
|
|
static uptr GetRSSFromGetrusage() {
|
|
|
|
struct rusage usage;
|
|
|
|
if (getrusage(RUSAGE_SELF, &usage)) // Failed, probably due to a sandbox.
|
|
|
|
return 0;
|
|
|
|
return usage.ru_maxrss << 10; // ru_maxrss is in Kb.
|
|
|
|
}
|
|
|
|
|
|
|
|
uptr GetRSS() {
|
|
|
|
if (!common_flags()->can_use_proc_maps_statm)
|
|
|
|
return GetRSSFromGetrusage();
|
2015-04-09 00:03:22 +08:00
|
|
|
fd_t fd = OpenFile("/proc/self/statm", RdOnly);
|
|
|
|
if (fd == kInvalidFd)
|
2015-01-29 10:54:39 +08:00
|
|
|
return GetRSSFromGetrusage();
|
|
|
|
char buf[64];
|
|
|
|
uptr len = internal_read(fd, buf, sizeof(buf) - 1);
|
|
|
|
internal_close(fd);
|
|
|
|
if ((sptr)len <= 0)
|
|
|
|
return 0;
|
|
|
|
buf[len] = 0;
|
|
|
|
// The format of the file is:
|
|
|
|
// 1084 89 69 11 0 79 0
|
|
|
|
// We need the second number which is RSS in pages.
|
|
|
|
char *pos = buf;
|
|
|
|
// Skip the first number.
|
|
|
|
while (*pos >= '0' && *pos <= '9')
|
|
|
|
pos++;
|
|
|
|
// Skip whitespaces.
|
|
|
|
while (!(*pos >= '0' && *pos <= '9') && *pos != 0)
|
|
|
|
pos++;
|
|
|
|
// Read the number.
|
|
|
|
uptr rss = 0;
|
|
|
|
while (*pos >= '0' && *pos <= '9')
|
|
|
|
rss = rss * 10 + *pos++ - '0';
|
|
|
|
return rss * GetPageSizeCached();
|
|
|
|
}
|
|
|
|
|
[Sanitizers] Basic sanitizer Solaris support (PR 33274)
Summary:
This is the first mostly working version of the Sanitizer port to 32-bit Solaris/x86.
It is currently based on Solaris 11.4 Beta.
This part was initially developed inside libsanitizer in the GCC tree and should apply to
both. Subsequent parts will address changes to clang, the compiler-rt build system
and testsuite.
I'm not yet sure what the right patch granularity is: if it's profitable to split the patch
up, I'd like to get guidance on how to do so.
Most of the changes are probably straightforward with a few exceptions:
* The Solaris syscall interface isn't stable, undocumented and can change within an
OS release. The stable interface is the libc interface, which I'm using here, if possible
using the internal _-prefixed names.
* While the patch primarily target 32-bit x86, I've left a few sparc changes in. They
cannot currently be used with clang due to a backend limitation, but have worked
fine inside the gcc tree.
* Some functions (e.g. largefile versions of functions like open64) only exist in 32-bit
Solaris, so I've introduced a separate SANITIZER_SOLARIS32 to check for that.
The patch (with the subsequent ones to be submitted shortly) was tested
on i386-pc-solaris2.11. Only a few failures remain, some of them analyzed, some
still TBD:
AddressSanitizer-i386-sunos :: TestCases/Posix/concurrent_overflow.cc
AddressSanitizer-i386-sunos :: TestCases/init-order-atexit.cc
AddressSanitizer-i386-sunos :: TestCases/log-path_test.cc
AddressSanitizer-i386-sunos :: TestCases/malloc-no-intercept.c
AddressSanitizer-i386-sunos-dynamic :: TestCases/Posix/concurrent_overflow.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/Posix/start-deactivated.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/default_options.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/init-order-atexit.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/log-path_test.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/malloc-no-intercept.c
SanitizerCommon-Unit :: ./Sanitizer-i386-Test/MemoryMappingLayout.DumpListOfModules
SanitizerCommon-Unit :: ./Sanitizer-i386-Test/SanitizerCommon.PthreadDestructorIterations
Maybe this is good enough the get the ball rolling.
Reviewers: kcc, alekseyshl
Reviewed By: alekseyshl
Subscribers: srhines, jyknight, kubamracek, krytarowski, fedor.sergeev, llvm-commits, #sanitizers
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D40898
llvm-svn: 320740
2017-12-15 04:14:29 +08:00
|
|
|
// sysconf(_SC_NPROCESSORS_{CONF,ONLN}) cannot be used on most platforms as
|
|
|
|
// they allocate memory.
|
2017-11-22 05:14:00 +08:00
|
|
|
u32 GetNumberOfCPUs() {
|
2018-03-20 07:12:14 +08:00
|
|
|
#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD
|
2017-11-22 05:14:00 +08:00
|
|
|
u32 ncpu;
|
|
|
|
int req[2];
|
2018-08-31 16:10:06 +08:00
|
|
|
uptr len = sizeof(ncpu);
|
2017-11-22 05:14:00 +08:00
|
|
|
req[0] = CTL_HW;
|
|
|
|
req[1] = HW_NCPU;
|
2018-08-31 16:10:06 +08:00
|
|
|
CHECK_EQ(internal_sysctl(req, 2, &ncpu, &len, NULL, 0), 0);
|
2017-11-22 05:14:00 +08:00
|
|
|
return ncpu;
|
|
|
|
#elif SANITIZER_ANDROID && !defined(CPU_COUNT) && !defined(__aarch64__)
|
|
|
|
// Fall back to /sys/devices/system/cpu on Android when cpu_set_t doesn't
|
|
|
|
// exist in sched.h. That is the case for toolchains generated with older
|
|
|
|
// NDKs.
|
|
|
|
// This code doesn't work on AArch64 because internal_getdents makes use of
|
|
|
|
// the 64bit getdents syscall, but cpu_set_t seems to always exist on AArch64.
|
|
|
|
uptr fd = internal_open("/sys/devices/system/cpu", O_RDONLY | O_DIRECTORY);
|
|
|
|
if (internal_iserror(fd))
|
|
|
|
return 0;
|
2018-05-07 13:56:36 +08:00
|
|
|
InternalMmapVector<u8> buffer(4096);
|
2017-11-22 05:14:00 +08:00
|
|
|
uptr bytes_read = buffer.size();
|
|
|
|
uptr n_cpus = 0;
|
|
|
|
u8 *d_type;
|
|
|
|
struct linux_dirent *entry = (struct linux_dirent *)&buffer[bytes_read];
|
|
|
|
while (true) {
|
|
|
|
if ((u8 *)entry >= &buffer[bytes_read]) {
|
|
|
|
bytes_read = internal_getdents(fd, (struct linux_dirent *)buffer.data(),
|
|
|
|
buffer.size());
|
|
|
|
if (internal_iserror(bytes_read) || !bytes_read)
|
|
|
|
break;
|
|
|
|
entry = (struct linux_dirent *)buffer.data();
|
|
|
|
}
|
|
|
|
d_type = (u8 *)entry + entry->d_reclen - 1;
|
|
|
|
if (d_type >= &buffer[bytes_read] ||
|
|
|
|
(u8 *)&entry->d_name[3] >= &buffer[bytes_read])
|
|
|
|
break;
|
|
|
|
if (entry->d_ino != 0 && *d_type == DT_DIR) {
|
|
|
|
if (entry->d_name[0] == 'c' && entry->d_name[1] == 'p' &&
|
|
|
|
entry->d_name[2] == 'u' &&
|
|
|
|
entry->d_name[3] >= '0' && entry->d_name[3] <= '9')
|
|
|
|
n_cpus++;
|
|
|
|
}
|
|
|
|
entry = (struct linux_dirent *)(((u8 *)entry) + entry->d_reclen);
|
|
|
|
}
|
|
|
|
internal_close(fd);
|
|
|
|
return n_cpus;
|
[Sanitizers] Basic sanitizer Solaris support (PR 33274)
Summary:
This is the first mostly working version of the Sanitizer port to 32-bit Solaris/x86.
It is currently based on Solaris 11.4 Beta.
This part was initially developed inside libsanitizer in the GCC tree and should apply to
both. Subsequent parts will address changes to clang, the compiler-rt build system
and testsuite.
I'm not yet sure what the right patch granularity is: if it's profitable to split the patch
up, I'd like to get guidance on how to do so.
Most of the changes are probably straightforward with a few exceptions:
* The Solaris syscall interface isn't stable, undocumented and can change within an
OS release. The stable interface is the libc interface, which I'm using here, if possible
using the internal _-prefixed names.
* While the patch primarily target 32-bit x86, I've left a few sparc changes in. They
cannot currently be used with clang due to a backend limitation, but have worked
fine inside the gcc tree.
* Some functions (e.g. largefile versions of functions like open64) only exist in 32-bit
Solaris, so I've introduced a separate SANITIZER_SOLARIS32 to check for that.
The patch (with the subsequent ones to be submitted shortly) was tested
on i386-pc-solaris2.11. Only a few failures remain, some of them analyzed, some
still TBD:
AddressSanitizer-i386-sunos :: TestCases/Posix/concurrent_overflow.cc
AddressSanitizer-i386-sunos :: TestCases/init-order-atexit.cc
AddressSanitizer-i386-sunos :: TestCases/log-path_test.cc
AddressSanitizer-i386-sunos :: TestCases/malloc-no-intercept.c
AddressSanitizer-i386-sunos-dynamic :: TestCases/Posix/concurrent_overflow.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/Posix/start-deactivated.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/default_options.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/init-order-atexit.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/log-path_test.cc
AddressSanitizer-i386-sunos-dynamic :: TestCases/malloc-no-intercept.c
SanitizerCommon-Unit :: ./Sanitizer-i386-Test/MemoryMappingLayout.DumpListOfModules
SanitizerCommon-Unit :: ./Sanitizer-i386-Test/SanitizerCommon.PthreadDestructorIterations
Maybe this is good enough the get the ball rolling.
Reviewers: kcc, alekseyshl
Reviewed By: alekseyshl
Subscribers: srhines, jyknight, kubamracek, krytarowski, fedor.sergeev, llvm-commits, #sanitizers
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D40898
llvm-svn: 320740
2017-12-15 04:14:29 +08:00
|
|
|
#elif SANITIZER_SOLARIS
|
|
|
|
return sysconf(_SC_NPROCESSORS_ONLN);
|
2017-11-22 05:14:00 +08:00
|
|
|
#else
|
|
|
|
cpu_set_t CPUs;
|
|
|
|
CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0);
|
|
|
|
return CPU_COUNT(&CPUs);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-07-28 08:29:47 +08:00
|
|
|
#if SANITIZER_LINUX
|
2015-09-04 09:15:25 +08:00
|
|
|
|
2017-11-21 00:39:49 +08:00
|
|
|
# if SANITIZER_ANDROID
|
2015-07-24 06:05:20 +08:00
|
|
|
static atomic_uint8_t android_log_initialized;
|
|
|
|
|
|
|
|
void AndroidLogInit() {
|
2016-09-08 06:56:02 +08:00
|
|
|
openlog(GetProcessName(), 0, LOG_USER);
|
2015-07-24 06:05:20 +08:00
|
|
|
atomic_store(&android_log_initialized, 1, memory_order_release);
|
|
|
|
}
|
|
|
|
|
2016-01-07 07:15:01 +08:00
|
|
|
static bool ShouldLogAfterPrintf() {
|
2015-07-24 06:05:20 +08:00
|
|
|
return atomic_load(&android_log_initialized, memory_order_acquire);
|
|
|
|
}
|
2017-11-17 00:19:44 +08:00
|
|
|
|
2017-11-21 00:39:49 +08:00
|
|
|
extern "C" SANITIZER_WEAK_ATTRIBUTE
|
|
|
|
int async_safe_write_log(int pri, const char* tag, const char* msg);
|
|
|
|
extern "C" SANITIZER_WEAK_ATTRIBUTE
|
|
|
|
int __android_log_write(int prio, const char* tag, const char* msg);
|
|
|
|
|
|
|
|
// ANDROID_LOG_INFO is 4, but can't be resolved at runtime.
|
|
|
|
#define SANITIZER_ANDROID_LOG_INFO 4
|
2017-11-17 00:19:44 +08:00
|
|
|
|
2017-11-21 00:39:49 +08:00
|
|
|
// async_safe_write_log is a new public version of __libc_write_log that is
|
|
|
|
// used behind syslog. It is preferable to syslog as it will not do any dynamic
|
|
|
|
// memory allocation or formatting.
|
|
|
|
// If the function is not available, syslog is preferred for L+ (it was broken
|
|
|
|
// pre-L) as __android_log_write triggers a racey behavior with the strncpy
|
|
|
|
// interceptor. Fallback to __android_log_write pre-L.
|
2017-11-17 02:53:18 +08:00
|
|
|
void WriteOneLineToSyslog(const char *s) {
|
2017-11-21 00:39:49 +08:00
|
|
|
if (&async_safe_write_log) {
|
|
|
|
async_safe_write_log(SANITIZER_ANDROID_LOG_INFO, GetProcessName(), s);
|
|
|
|
} else if (AndroidGetApiLevel() > ANDROID_KITKAT) {
|
|
|
|
syslog(LOG_INFO, "%s", s);
|
|
|
|
} else {
|
|
|
|
CHECK(&__android_log_write);
|
|
|
|
__android_log_write(SANITIZER_ANDROID_LOG_INFO, nullptr, s);
|
|
|
|
}
|
2017-11-17 02:53:18 +08:00
|
|
|
}
|
2017-11-17 00:19:44 +08:00
|
|
|
|
2017-11-21 00:39:49 +08:00
|
|
|
extern "C" SANITIZER_WEAK_ATTRIBUTE
|
|
|
|
void android_set_abort_message(const char *);
|
2017-06-24 07:38:20 +08:00
|
|
|
|
2017-11-17 02:53:18 +08:00
|
|
|
void SetAbortMessage(const char *str) {
|
2017-11-21 00:39:49 +08:00
|
|
|
if (&android_set_abort_message)
|
|
|
|
android_set_abort_message(str);
|
2017-11-17 02:53:18 +08:00
|
|
|
}
|
2017-11-21 00:39:49 +08:00
|
|
|
# else
|
|
|
|
void AndroidLogInit() {}
|
|
|
|
|
|
|
|
static bool ShouldLogAfterPrintf() { return true; }
|
|
|
|
|
|
|
|
void WriteOneLineToSyslog(const char *s) { syslog(LOG_INFO, "%s", s); }
|
|
|
|
|
2017-11-17 02:53:18 +08:00
|
|
|
void SetAbortMessage(const char *str) {}
|
2017-11-21 00:39:49 +08:00
|
|
|
# endif // SANITIZER_ANDROID
|
|
|
|
|
|
|
|
void LogMessageOnPrintf(const char *str) {
|
|
|
|
if (common_flags()->log_to_syslog && ShouldLogAfterPrintf())
|
|
|
|
WriteToSyslog(str);
|
|
|
|
}
|
2017-11-17 02:53:18 +08:00
|
|
|
|
2017-11-21 00:39:49 +08:00
|
|
|
#endif // SANITIZER_LINUX
|
2015-07-24 06:05:20 +08:00
|
|
|
|
2017-12-14 00:23:54 +08:00
|
|
|
#if SANITIZER_LINUX && !SANITIZER_GO
|
|
|
|
// glibc crashes when using clock_gettime from a preinit_array function as the
|
|
|
|
// vDSO function pointers haven't been initialized yet. __progname is
|
|
|
|
// initialized after the vDSO function pointers, so if it exists, is not null
|
|
|
|
// and is not empty, we can use clock_gettime.
|
|
|
|
extern "C" SANITIZER_WEAK_ATTRIBUTE char *__progname;
|
|
|
|
INLINE bool CanUseVDSO() {
|
|
|
|
// Bionic is safe, it checks for the vDSO function pointers to be initialized.
|
|
|
|
if (SANITIZER_ANDROID)
|
|
|
|
return true;
|
|
|
|
if (&__progname && __progname && *__progname)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// MonotonicNanoTime is a timing function that can leverage the vDSO by calling
|
|
|
|
// clock_gettime. real_clock_gettime only exists if clock_gettime is
|
2018-10-30 09:20:01 +08:00
|
|
|
// intercepted, so define it weakly and use it if available.
|
2017-12-14 00:23:54 +08:00
|
|
|
extern "C" SANITIZER_WEAK_ATTRIBUTE
|
|
|
|
int real_clock_gettime(u32 clk_id, void *tp);
|
|
|
|
u64 MonotonicNanoTime() {
|
|
|
|
timespec ts;
|
2018-10-30 09:20:01 +08:00
|
|
|
if (CanUseVDSO()) {
|
2017-12-14 00:23:54 +08:00
|
|
|
if (&real_clock_gettime)
|
|
|
|
real_clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
|
|
else
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
|
|
} else {
|
|
|
|
internal_clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
|
|
}
|
|
|
|
return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
// Non-Linux & Go always use the syscall.
|
|
|
|
u64 MonotonicNanoTime() {
|
|
|
|
timespec ts;
|
|
|
|
internal_clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
|
|
return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec;
|
|
|
|
}
|
|
|
|
#endif // SANITIZER_LINUX && !SANITIZER_GO
|
|
|
|
|
2018-11-07 03:23:22 +08:00
|
|
|
#if !SANITIZER_OPENBSD
|
|
|
|
void ReExec() {
|
|
|
|
const char *pathname = "/proc/self/exe";
|
|
|
|
|
|
|
|
#if SANITIZER_NETBSD
|
|
|
|
static const int name[] = {
|
|
|
|
CTL_KERN,
|
|
|
|
KERN_PROC_ARGS,
|
|
|
|
-1,
|
|
|
|
KERN_PROC_PATHNAME,
|
|
|
|
};
|
|
|
|
char path[400];
|
|
|
|
uptr len;
|
|
|
|
|
|
|
|
len = sizeof(path);
|
|
|
|
if (internal_sysctl(name, ARRAY_SIZE(name), path, &len, NULL, 0) != -1)
|
|
|
|
pathname = path;
|
|
|
|
#elif SANITIZER_SOLARIS
|
|
|
|
pathname = getexecname();
|
|
|
|
CHECK_NE(pathname, NULL);
|
|
|
|
#elif SANITIZER_USE_GETAUXVAL
|
|
|
|
// Calling execve with /proc/self/exe sets that as $EXEC_ORIGIN. Binaries that
|
|
|
|
// rely on that will fail to load shared libraries. Query AT_EXECFN instead.
|
|
|
|
pathname = reinterpret_cast<const char *>(getauxval(AT_EXECFN));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
uptr rv = internal_execve(pathname, GetArgv(), GetEnviron());
|
|
|
|
int rverrno;
|
|
|
|
CHECK_EQ(internal_iserror(rv, &rverrno), true);
|
|
|
|
Printf("execve failed, errno %d\n", rverrno);
|
|
|
|
Die();
|
|
|
|
}
|
|
|
|
#endif // !SANITIZER_OPENBSD
|
|
|
|
|
2015-10-01 07:52:54 +08:00
|
|
|
} // namespace __sanitizer
|
2013-05-20 23:57:44 +08:00
|
|
|
|
2018-03-20 07:12:14 +08:00
|
|
|
#endif
|