2012-06-04 22:27:50 +08:00
|
|
|
//===-- sanitizer_linux.cc ------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file is shared between AddressSanitizer and ThreadSanitizer
|
|
|
|
// run-time libraries and implements linux-specific functions from
|
|
|
|
// sanitizer_libc.h.
|
|
|
|
//===----------------------------------------------------------------------===//
|
2013-03-19 22:33:38 +08:00
|
|
|
|
|
|
|
#include "sanitizer_platform.h"
|
2015-10-01 07:52:54 +08:00
|
|
|
|
2014-03-07 18:03:54 +08:00
|
|
|
#if SANITIZER_FREEBSD || SANITIZER_LINUX
|
2012-06-04 22:27:50 +08:00
|
|
|
|
2012-06-07 14:15:12 +08:00
|
|
|
#include "sanitizer_common.h"
|
2014-01-31 21:10:07 +08:00
|
|
|
#include "sanitizer_flags.h"
|
2012-06-05 22:25:27 +08:00
|
|
|
#include "sanitizer_internal_defs.h"
|
2012-06-04 22:27:50 +08:00
|
|
|
#include "sanitizer_libc.h"
|
2013-02-27 19:22:40 +08:00
|
|
|
#include "sanitizer_linux.h"
|
2012-12-01 10:39:45 +08:00
|
|
|
#include "sanitizer_mutex.h"
|
2012-07-03 16:24:14 +08:00
|
|
|
#include "sanitizer_placement_new.h"
|
2012-06-07 14:15:12 +08:00
|
|
|
#include "sanitizer_procmaps.h"
|
2012-12-13 17:34:23 +08:00
|
|
|
#include "sanitizer_stacktrace.h"
|
2013-05-23 19:53:36 +08:00
|
|
|
#include "sanitizer_symbolizer.h"
|
2012-06-04 22:27:50 +08:00
|
|
|
|
2014-03-07 18:03:54 +08:00
|
|
|
#if !SANITIZER_FREEBSD
|
2013-05-20 23:57:44 +08:00
|
|
|
#include <asm/param.h>
|
2014-03-07 18:03:54 +08:00
|
|
|
#endif
|
|
|
|
|
2014-12-16 15:11:08 +08:00
|
|
|
// For mips64, syscall(__NR_stat) fills the buffer in the 'struct kernel_stat'
|
|
|
|
// format. Struct kernel_stat is defined as 'struct stat' in asm/stat.h. To
|
|
|
|
// access stat from asm/stat.h, without conflicting with definition in
|
|
|
|
// sys/stat.h, we use this trick.
|
|
|
|
#if defined(__mips64)
|
2015-05-06 13:38:21 +08:00
|
|
|
#include <asm/unistd.h>
|
2014-12-16 15:11:08 +08:00
|
|
|
#include <sys/types.h>
|
|
|
|
#define stat kernel_stat
|
|
|
|
#include <asm/stat.h>
|
|
|
|
#undef stat
|
|
|
|
#endif
|
|
|
|
|
2013-03-13 16:19:53 +08:00
|
|
|
#include <dlfcn.h>
|
2013-02-27 21:03:35 +08:00
|
|
|
#include <errno.h>
|
2012-06-05 15:05:10 +08:00
|
|
|
#include <fcntl.h>
|
2013-07-30 03:09:49 +08:00
|
|
|
#include <link.h>
|
2012-06-07 15:13:46 +08:00
|
|
|
#include <pthread.h>
|
2012-06-18 16:44:30 +08:00
|
|
|
#include <sched.h>
|
2012-06-04 22:27:50 +08:00
|
|
|
#include <sys/mman.h>
|
2013-02-27 19:22:40 +08:00
|
|
|
#include <sys/ptrace.h>
|
2012-06-07 15:13:46 +08:00
|
|
|
#include <sys/resource.h>
|
2012-06-05 15:05:10 +08:00
|
|
|
#include <sys/stat.h>
|
2012-06-04 22:27:50 +08:00
|
|
|
#include <sys/syscall.h>
|
2012-06-07 15:13:46 +08:00
|
|
|
#include <sys/time.h>
|
2012-06-04 22:27:50 +08:00
|
|
|
#include <sys/types.h>
|
2015-03-13 02:10:06 +08:00
|
|
|
#include <ucontext.h>
|
2012-06-04 22:27:50 +08:00
|
|
|
#include <unistd.h>
|
2013-02-27 21:03:35 +08:00
|
|
|
|
2014-03-07 18:03:54 +08:00
|
|
|
#if SANITIZER_FREEBSD
|
Retrieve command line arguments and environment correctly on FreeBSD
Summary:
Recently I saw the test `TestCases/Posix/print_cmdline.cc` failing on
FreeBSD, with "expected string not found in input". This is because
asan could not retrieve the command line arguments properly.
In `lib/sanitizer_common/sanitizer_linux.cc`, this is taken care of by
the `GetArgsAndEnv()` function, but it uses `__libc_stack_end` to get at
the required data. This variable does not exist on BSDs; the regular
way to retrieve the arguments and environment information is via the
`kern.ps_strings` sysctl.
I added this functionality in sanitizer_linux.cc, as a separate #ifdef
block in `GetArgsAndEnv()`. Also, `ReadNullSepFileToArray()` becomes
unused due to this change. (It won't work on FreeBSD anyway, since
`/proc` is not mounted by default.)
Reviewers: kcc, emaste, joerg, davide
Subscribers: llvm-commits, emaste
Differential Revision: http://reviews.llvm.org/D17832
llvm-svn: 263157
2016-03-11 04:22:02 +08:00
|
|
|
#include <sys/exec.h>
|
2014-05-29 20:12:42 +08:00
|
|
|
#include <sys/sysctl.h>
|
Retrieve command line arguments and environment correctly on FreeBSD
Summary:
Recently I saw the test `TestCases/Posix/print_cmdline.cc` failing on
FreeBSD, with "expected string not found in input". This is because
asan could not retrieve the command line arguments properly.
In `lib/sanitizer_common/sanitizer_linux.cc`, this is taken care of by
the `GetArgsAndEnv()` function, but it uses `__libc_stack_end` to get at
the required data. This variable does not exist on BSDs; the regular
way to retrieve the arguments and environment information is via the
`kern.ps_strings` sysctl.
I added this functionality in sanitizer_linux.cc, as a separate #ifdef
block in `GetArgsAndEnv()`. Also, `ReadNullSepFileToArray()` becomes
unused due to this change. (It won't work on FreeBSD anyway, since
`/proc` is not mounted by default.)
Reviewers: kcc, emaste, joerg, davide
Subscribers: llvm-commits, emaste
Differential Revision: http://reviews.llvm.org/D17832
llvm-svn: 263157
2016-03-11 04:22:02 +08:00
|
|
|
#include <vm/vm_param.h>
|
|
|
|
#include <vm/pmap.h>
|
2014-03-07 18:03:54 +08:00
|
|
|
#include <machine/atomic.h>
|
|
|
|
extern "C" {
|
|
|
|
// <sys/umtx.h> must be included after <errno.h> and <sys/types.h> on
|
|
|
|
// FreeBSD 9.2 and 10.0.
|
|
|
|
#include <sys/umtx.h>
|
|
|
|
}
|
2014-07-10 16:53:29 +08:00
|
|
|
extern char **environ; // provided by crt1
|
2014-03-07 18:03:54 +08:00
|
|
|
#endif // SANITIZER_FREEBSD
|
|
|
|
|
2013-03-19 22:33:38 +08:00
|
|
|
#if !SANITIZER_ANDROID
|
2013-02-27 21:03:35 +08:00
|
|
|
#include <sys/signal.h>
|
|
|
|
#endif
|
2013-01-30 22:39:27 +08:00
|
|
|
|
2014-03-07 18:03:54 +08:00
|
|
|
#if SANITIZER_LINUX
|
2013-03-21 14:24:31 +08:00
|
|
|
// <linux/time.h>
|
|
|
|
struct kernel_timeval {
|
|
|
|
long tv_sec;
|
|
|
|
long tv_usec;
|
|
|
|
};
|
|
|
|
|
2013-01-30 22:39:27 +08:00
|
|
|
// <linux/futex.h> is broken on some linux distributions.
|
|
|
|
const int FUTEX_WAIT = 0;
|
|
|
|
const int FUTEX_WAKE = 1;
|
2014-03-07 18:03:54 +08:00
|
|
|
#endif // SANITIZER_LINUX
|
2012-06-04 22:27:50 +08:00
|
|
|
|
2014-03-07 18:03:54 +08:00
|
|
|
// Are we using 32-bit or 64-bit Linux syscalls?
|
2012-11-21 20:38:58 +08:00
|
|
|
// x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32
|
2012-11-20 16:57:26 +08:00
|
|
|
// but it still needs to use 64-bit syscalls.
|
2015-12-09 05:54:39 +08:00
|
|
|
#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__powerpc64__) || \
|
|
|
|
SANITIZER_WORDSIZE == 64)
|
2012-11-19 15:53:36 +08:00
|
|
|
# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1
|
|
|
|
#else
|
|
|
|
# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0
|
|
|
|
#endif
|
|
|
|
|
2016-09-07 17:09:03 +08:00
|
|
|
#if defined(__x86_64__) || SANITIZER_MIPS64
|
[sanitizer][esan] Add internal_sigaction_syscall
Summary:
Adds a version of sigaction that uses a raw system call, to avoid circular
dependencies and support calling sigaction prior to setting up
interceptors. The new sigaction relies on an assembly sigreturn routine
for its restorer, which is Linux x86_64-only for now.
Uses the new sigaction to initialize the working set tool's shadow fault
handler prior to libc interceptor being set up. This is required to
support instrumentation invoked during interceptor setup, which happens
with an instrumented tcmalloc or other allocator compiled with esan.
Adds a test that emulates an instrumented allocator.
Reviewers: aizatsky
Subscribers: vitalybuka, tberghammer, zhaoqin, danalbert, kcc, srhines, eugenis, llvm-commits, kubabrecka
Differential Revision: http://reviews.llvm.org/D21083
llvm-svn: 272676
2016-06-14 23:15:38 +08:00
|
|
|
extern "C" {
|
|
|
|
extern void internal_sigreturn();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-06-04 22:27:50 +08:00
|
|
|
namespace __sanitizer {
|
|
|
|
|
2014-03-07 18:03:54 +08:00
|
|
|
#if SANITIZER_LINUX && defined(__x86_64__)
|
2013-05-08 22:43:49 +08:00
|
|
|
#include "sanitizer_syscall_linux_x86_64.inc"
|
2015-08-21 22:50:36 +08:00
|
|
|
#elif SANITIZER_LINUX && defined(__aarch64__)
|
|
|
|
#include "sanitizer_syscall_linux_aarch64.inc"
|
2013-05-08 22:43:49 +08:00
|
|
|
#else
|
|
|
|
#include "sanitizer_syscall_generic.inc"
|
|
|
|
#endif
|
|
|
|
|
2012-06-07 15:13:46 +08:00
|
|
|
// --------------- sanitizer_libc.h
|
2016-04-16 06:11:10 +08:00
|
|
|
#if !SANITIZER_S390
|
2014-12-24 20:58:09 +08:00
|
|
|
uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
|
2015-07-31 19:29:25 +08:00
|
|
|
OFF_T offset) {
|
2016-04-16 06:11:10 +08:00
|
|
|
#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd,
|
2013-11-07 01:47:39 +08:00
|
|
|
offset);
|
2012-06-04 22:27:50 +08:00
|
|
|
#else
|
2014-12-24 20:58:09 +08:00
|
|
|
// mmap2 specifies file offset in 4096-byte units.
|
|
|
|
CHECK(IsAligned(offset, 4096));
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(mmap2), addr, length, prot, flags, fd,
|
2014-12-24 20:58:09 +08:00
|
|
|
offset / 4096);
|
2012-06-04 22:27:50 +08:00
|
|
|
#endif
|
|
|
|
}
|
2016-04-16 06:11:10 +08:00
|
|
|
#endif // !SANITIZER_S390
|
2012-06-04 22:27:50 +08:00
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_munmap(void *addr, uptr length) {
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(munmap), (uptr)addr, length);
|
2012-06-05 17:49:25 +08:00
|
|
|
}
|
|
|
|
|
2015-04-10 23:02:19 +08:00
|
|
|
int internal_mprotect(void *addr, uptr length, int prot) {
|
2015-04-13 20:13:03 +08:00
|
|
|
return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot);
|
2015-04-10 23:02:19 +08:00
|
|
|
}
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_close(fd_t fd) {
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(close), fd);
|
2012-06-05 16:32:53 +08:00
|
|
|
}
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_open(const char *filename, int flags) {
|
2014-02-13 15:50:20 +08:00
|
|
|
#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags);
|
2014-02-13 15:50:20 +08:00
|
|
|
#else
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(open), (uptr)filename, flags);
|
2014-02-13 15:50:20 +08:00
|
|
|
#endif
|
2013-02-01 23:58:46 +08:00
|
|
|
}
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_open(const char *filename, int flags, u32 mode) {
|
2014-02-13 15:50:20 +08:00
|
|
|
#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags,
|
|
|
|
mode);
|
2014-02-13 15:50:20 +08:00
|
|
|
#else
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(open), (uptr)filename, flags, mode);
|
2014-02-13 15:50:20 +08:00
|
|
|
#endif
|
2013-02-01 23:58:46 +08:00
|
|
|
}
|
|
|
|
|
2012-06-05 16:32:53 +08:00
|
|
|
uptr internal_read(fd_t fd, void *buf, uptr count) {
|
2012-10-02 21:41:40 +08:00
|
|
|
sptr res;
|
2014-03-07 18:03:54 +08:00
|
|
|
HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf,
|
|
|
|
count));
|
2012-10-02 21:41:40 +08:00
|
|
|
return res;
|
2012-06-05 16:32:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
uptr internal_write(fd_t fd, const void *buf, uptr count) {
|
2012-10-02 21:41:40 +08:00
|
|
|
sptr res;
|
2014-03-07 18:03:54 +08:00
|
|
|
HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(write), fd, (uptr)buf,
|
|
|
|
count));
|
2012-10-02 21:41:40 +08:00
|
|
|
return res;
|
2012-06-05 16:32:53 +08:00
|
|
|
}
|
|
|
|
|
2014-05-27 20:37:52 +08:00
|
|
|
uptr internal_ftruncate(fd_t fd, uptr size) {
|
|
|
|
sptr res;
|
2015-03-24 03:44:35 +08:00
|
|
|
HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd,
|
|
|
|
(OFF_T)size));
|
2014-05-27 20:37:52 +08:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2014-03-07 18:03:54 +08:00
|
|
|
#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && !SANITIZER_FREEBSD
|
2013-05-07 20:47:04 +08:00
|
|
|
static void stat64_to_stat(struct stat64 *in, struct stat *out) {
|
|
|
|
internal_memset(out, 0, sizeof(*out));
|
|
|
|
out->st_dev = in->st_dev;
|
|
|
|
out->st_ino = in->st_ino;
|
|
|
|
out->st_mode = in->st_mode;
|
|
|
|
out->st_nlink = in->st_nlink;
|
|
|
|
out->st_uid = in->st_uid;
|
|
|
|
out->st_gid = in->st_gid;
|
|
|
|
out->st_rdev = in->st_rdev;
|
|
|
|
out->st_size = in->st_size;
|
|
|
|
out->st_blksize = in->st_blksize;
|
|
|
|
out->st_blocks = in->st_blocks;
|
|
|
|
out->st_atime = in->st_atime;
|
|
|
|
out->st_mtime = in->st_mtime;
|
|
|
|
out->st_ctime = in->st_ctime;
|
|
|
|
out->st_ino = in->st_ino;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-12-16 15:11:08 +08:00
|
|
|
#if defined(__mips64)
|
|
|
|
static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) {
|
|
|
|
internal_memset(out, 0, sizeof(*out));
|
|
|
|
out->st_dev = in->st_dev;
|
|
|
|
out->st_ino = in->st_ino;
|
|
|
|
out->st_mode = in->st_mode;
|
|
|
|
out->st_nlink = in->st_nlink;
|
|
|
|
out->st_uid = in->st_uid;
|
|
|
|
out->st_gid = in->st_gid;
|
|
|
|
out->st_rdev = in->st_rdev;
|
|
|
|
out->st_size = in->st_size;
|
|
|
|
out->st_blksize = in->st_blksize;
|
|
|
|
out->st_blocks = in->st_blocks;
|
|
|
|
out->st_atime = in->st_atime_nsec;
|
|
|
|
out->st_mtime = in->st_mtime_nsec;
|
|
|
|
out->st_ctime = in->st_ctime_nsec;
|
|
|
|
out->st_ino = in->st_ino;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_stat(const char *path, void *buf) {
|
2014-03-07 18:03:54 +08:00
|
|
|
#if SANITIZER_FREEBSD
|
|
|
|
return internal_syscall(SYSCALL(stat), path, buf);
|
|
|
|
#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
|
|
|
|
return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path,
|
|
|
|
(uptr)buf, 0);
|
2014-02-13 15:50:20 +08:00
|
|
|
#elif SANITIZER_LINUX_USES_64BIT_SYSCALLS
|
2014-12-16 15:11:08 +08:00
|
|
|
# if defined(__mips64)
|
|
|
|
// For mips64, stat syscall fills buffer in the format of kernel_stat
|
|
|
|
struct kernel_stat kbuf;
|
|
|
|
int res = internal_syscall(SYSCALL(stat), path, &kbuf);
|
|
|
|
kernel_stat_to_stat(&kbuf, (struct stat *)buf);
|
|
|
|
return res;
|
|
|
|
# else
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(stat), (uptr)path, (uptr)buf);
|
2014-12-16 15:11:08 +08:00
|
|
|
# endif
|
2013-02-04 18:16:50 +08:00
|
|
|
#else
|
2013-05-07 20:47:04 +08:00
|
|
|
struct stat64 buf64;
|
2014-03-07 18:03:54 +08:00
|
|
|
int res = internal_syscall(SYSCALL(stat64), path, &buf64);
|
2013-05-07 20:47:04 +08:00
|
|
|
stat64_to_stat(&buf64, (struct stat *)buf);
|
|
|
|
return res;
|
2013-02-04 18:16:50 +08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_lstat(const char *path, void *buf) {
|
2014-03-07 18:03:54 +08:00
|
|
|
#if SANITIZER_FREEBSD
|
|
|
|
return internal_syscall(SYSCALL(lstat), path, buf);
|
|
|
|
#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
|
|
|
|
return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path,
|
2014-02-13 15:50:20 +08:00
|
|
|
(uptr)buf, AT_SYMLINK_NOFOLLOW);
|
|
|
|
#elif SANITIZER_LINUX_USES_64BIT_SYSCALLS
|
2016-03-11 18:51:03 +08:00
|
|
|
# if SANITIZER_MIPS64
|
|
|
|
// For mips64, lstat syscall fills buffer in the format of kernel_stat
|
|
|
|
struct kernel_stat kbuf;
|
|
|
|
int res = internal_syscall(SYSCALL(lstat), path, &kbuf);
|
|
|
|
kernel_stat_to_stat(&kbuf, (struct stat *)buf);
|
|
|
|
return res;
|
|
|
|
# else
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(lstat), (uptr)path, (uptr)buf);
|
2016-03-11 18:51:03 +08:00
|
|
|
# endif
|
2013-02-04 18:16:50 +08:00
|
|
|
#else
|
2013-05-07 20:47:04 +08:00
|
|
|
struct stat64 buf64;
|
2014-03-07 18:03:54 +08:00
|
|
|
int res = internal_syscall(SYSCALL(lstat64), path, &buf64);
|
2013-05-07 20:47:04 +08:00
|
|
|
stat64_to_stat(&buf64, (struct stat *)buf);
|
|
|
|
return res;
|
2013-02-04 18:16:50 +08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_fstat(fd_t fd, void *buf) {
|
2014-03-07 18:03:54 +08:00
|
|
|
#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
|
2016-03-11 18:51:03 +08:00
|
|
|
# if SANITIZER_MIPS64
|
|
|
|
// For mips64, fstat syscall fills buffer in the format of kernel_stat
|
|
|
|
struct kernel_stat kbuf;
|
|
|
|
int res = internal_syscall(SYSCALL(fstat), fd, &kbuf);
|
|
|
|
kernel_stat_to_stat(&kbuf, (struct stat *)buf);
|
|
|
|
return res;
|
|
|
|
# else
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(fstat), fd, (uptr)buf);
|
2016-03-11 18:51:03 +08:00
|
|
|
# endif
|
2013-02-04 18:16:50 +08:00
|
|
|
#else
|
2013-05-07 20:47:04 +08:00
|
|
|
struct stat64 buf64;
|
2014-03-07 18:03:54 +08:00
|
|
|
int res = internal_syscall(SYSCALL(fstat64), fd, &buf64);
|
2013-05-07 20:47:04 +08:00
|
|
|
stat64_to_stat(&buf64, (struct stat *)buf);
|
|
|
|
return res;
|
2013-02-04 18:16:50 +08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-06-06 15:30:33 +08:00
|
|
|
uptr internal_filesize(fd_t fd) {
|
2012-07-03 16:24:14 +08:00
|
|
|
struct stat st;
|
2013-02-04 18:16:50 +08:00
|
|
|
if (internal_fstat(fd, &st))
|
|
|
|
return -1;
|
2012-06-06 15:30:33 +08:00
|
|
|
return (uptr)st.st_size;
|
|
|
|
}
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_dup2(int oldfd, int newfd) {
|
2014-02-13 15:50:20 +08:00
|
|
|
#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(dup3), oldfd, newfd, 0);
|
2014-02-13 15:50:20 +08:00
|
|
|
#else
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(dup2), oldfd, newfd);
|
2014-02-13 15:50:20 +08:00
|
|
|
#endif
|
2012-06-06 15:30:33 +08:00
|
|
|
}
|
|
|
|
|
2012-09-05 22:48:24 +08:00
|
|
|
uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
|
2014-02-13 15:50:20 +08:00
|
|
|
#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(readlinkat), AT_FDCWD,
|
|
|
|
(uptr)path, (uptr)buf, bufsize);
|
2014-02-13 15:50:20 +08:00
|
|
|
#else
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(readlink), (uptr)path, (uptr)buf, bufsize);
|
2014-02-13 15:50:20 +08:00
|
|
|
#endif
|
2012-09-05 22:48:24 +08:00
|
|
|
}
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_unlink(const char *path) {
|
2014-02-13 15:50:20 +08:00
|
|
|
#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(unlinkat), AT_FDCWD, (uptr)path, 0);
|
2014-02-13 15:50:20 +08:00
|
|
|
#else
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(unlink), (uptr)path);
|
2014-02-13 15:50:20 +08:00
|
|
|
#endif
|
2013-03-20 18:28:36 +08:00
|
|
|
}
|
|
|
|
|
2014-05-27 20:37:52 +08:00
|
|
|
uptr internal_rename(const char *oldpath, const char *newpath) {
|
|
|
|
#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
|
|
|
|
return internal_syscall(SYSCALL(renameat), AT_FDCWD, (uptr)oldpath, AT_FDCWD,
|
|
|
|
(uptr)newpath);
|
|
|
|
#else
|
|
|
|
return internal_syscall(SYSCALL(rename), (uptr)oldpath, (uptr)newpath);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_sched_yield() {
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(sched_yield));
|
2012-06-18 16:44:30 +08:00
|
|
|
}
|
|
|
|
|
2013-02-20 21:54:32 +08:00
|
|
|
void internal__exit(int exitcode) {
|
2014-03-07 18:03:54 +08:00
|
|
|
#if SANITIZER_FREEBSD
|
|
|
|
internal_syscall(SYSCALL(exit), exitcode);
|
|
|
|
#else
|
|
|
|
internal_syscall(SYSCALL(exit_group), exitcode);
|
|
|
|
#endif
|
2013-02-20 21:54:32 +08:00
|
|
|
Die(); // Unreachable.
|
|
|
|
}
|
|
|
|
|
2016-05-12 22:08:56 +08:00
|
|
|
unsigned int internal_sleep(unsigned int seconds) {
|
|
|
|
struct timespec ts;
|
|
|
|
ts.tv_sec = 1;
|
|
|
|
ts.tv_nsec = 0;
|
|
|
|
int res = internal_syscall(SYSCALL(nanosleep), &ts, &ts);
|
|
|
|
if (res) return ts.tv_sec;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_execve(const char *filename, char *const argv[],
|
|
|
|
char *const envp[]) {
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(execve), (uptr)filename, (uptr)argv,
|
|
|
|
(uptr)envp);
|
2013-05-08 22:43:49 +08:00
|
|
|
}
|
|
|
|
|
2012-06-07 15:13:46 +08:00
|
|
|
// ----------------- sanitizer_common.h
|
2012-11-09 22:45:30 +08:00
|
|
|
bool FileExists(const char *filename) {
|
2014-02-13 15:50:20 +08:00
|
|
|
struct stat st;
|
2014-11-21 21:55:19 +08:00
|
|
|
#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
|
2014-03-07 18:03:54 +08:00
|
|
|
if (internal_syscall(SYSCALL(newfstatat), AT_FDCWD, filename, &st, 0))
|
2014-02-13 15:50:20 +08:00
|
|
|
#else
|
2013-05-07 20:47:04 +08:00
|
|
|
if (internal_stat(filename, &st))
|
2014-11-21 21:55:19 +08:00
|
|
|
#endif
|
2012-11-09 22:45:30 +08:00
|
|
|
return false;
|
|
|
|
// Sanity check: filename is a regular file.
|
|
|
|
return S_ISREG(st.st_mode);
|
|
|
|
}
|
|
|
|
|
2012-10-02 20:58:14 +08:00
|
|
|
uptr GetTid() {
|
2014-03-07 18:03:54 +08:00
|
|
|
#if SANITIZER_FREEBSD
|
|
|
|
return (uptr)pthread_self();
|
|
|
|
#else
|
|
|
|
return internal_syscall(SYSCALL(gettid));
|
|
|
|
#endif
|
2012-10-02 20:58:14 +08:00
|
|
|
}
|
|
|
|
|
2013-03-21 14:24:31 +08:00
|
|
|
u64 NanoTime() {
|
2014-03-07 18:03:54 +08:00
|
|
|
#if SANITIZER_FREEBSD
|
|
|
|
timeval tv;
|
|
|
|
#else
|
2013-10-22 02:11:57 +08:00
|
|
|
kernel_timeval tv;
|
2014-03-07 18:03:54 +08:00
|
|
|
#endif
|
2013-10-22 02:11:57 +08:00
|
|
|
internal_memset(&tv, 0, sizeof(tv));
|
2014-03-07 18:03:54 +08:00
|
|
|
internal_syscall(SYSCALL(gettimeofday), (uptr)&tv, 0);
|
2013-03-21 14:24:31 +08:00
|
|
|
return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;
|
|
|
|
}
|
|
|
|
|
2014-07-10 16:53:29 +08:00
|
|
|
// Like getenv, but reads env directly from /proc (on Linux) or parses the
|
|
|
|
// 'environ' array (on FreeBSD) and does not use libc. This function should be
|
|
|
|
// called first inside __asan_init.
|
2012-06-14 22:07:21 +08:00
|
|
|
const char *GetEnv(const char *name) {
|
2014-07-10 16:53:29 +08:00
|
|
|
#if SANITIZER_FREEBSD
|
|
|
|
if (::environ != 0) {
|
|
|
|
uptr NameLen = internal_strlen(name);
|
|
|
|
for (char **Env = ::environ; *Env != 0; Env++) {
|
|
|
|
if (internal_strncmp(*Env, name, NameLen) == 0 && (*Env)[NameLen] == '=')
|
|
|
|
return (*Env) + NameLen + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0; // Not found.
|
|
|
|
#elif SANITIZER_LINUX
|
2012-06-14 22:07:21 +08:00
|
|
|
static char *environ;
|
|
|
|
static uptr len;
|
|
|
|
static bool inited;
|
|
|
|
if (!inited) {
|
|
|
|
inited = true;
|
|
|
|
uptr environ_size;
|
2015-07-18 07:50:08 +08:00
|
|
|
if (!ReadFileToBuffer("/proc/self/environ", &environ, &environ_size, &len))
|
|
|
|
environ = nullptr;
|
2012-06-14 22:07:21 +08:00
|
|
|
}
|
2015-10-01 07:52:54 +08:00
|
|
|
if (!environ || len == 0) return nullptr;
|
2012-06-14 22:07:21 +08:00
|
|
|
uptr namelen = internal_strlen(name);
|
|
|
|
const char *p = environ;
|
|
|
|
while (*p != '\0') { // will happen at the \0\0 that terminates the buffer
|
|
|
|
// proc file has the format NAME=value\0NAME=value\0NAME=value\0...
|
|
|
|
const char* endp =
|
|
|
|
(char*)internal_memchr(p, '\0', len - (p - environ));
|
2015-10-01 07:52:54 +08:00
|
|
|
if (!endp) // this entry isn't NUL terminated
|
|
|
|
return nullptr;
|
2012-06-14 22:07:21 +08:00
|
|
|
else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=') // Match.
|
|
|
|
return p + namelen + 1; // point after =
|
|
|
|
p = endp + 1;
|
|
|
|
}
|
2015-10-01 07:52:54 +08:00
|
|
|
return nullptr; // Not found.
|
2014-06-21 06:49:41 +08:00
|
|
|
#else
|
2014-07-10 16:53:29 +08:00
|
|
|
#error "Unsupported platform"
|
2014-06-21 06:49:41 +08:00
|
|
|
#endif
|
2014-07-10 16:53:29 +08:00
|
|
|
}
|
2012-06-14 22:07:21 +08:00
|
|
|
|
Retrieve command line arguments and environment correctly on FreeBSD
Summary:
Recently I saw the test `TestCases/Posix/print_cmdline.cc` failing on
FreeBSD, with "expected string not found in input". This is because
asan could not retrieve the command line arguments properly.
In `lib/sanitizer_common/sanitizer_linux.cc`, this is taken care of by
the `GetArgsAndEnv()` function, but it uses `__libc_stack_end` to get at
the required data. This variable does not exist on BSDs; the regular
way to retrieve the arguments and environment information is via the
`kern.ps_strings` sysctl.
I added this functionality in sanitizer_linux.cc, as a separate #ifdef
block in `GetArgsAndEnv()`. Also, `ReadNullSepFileToArray()` becomes
unused due to this change. (It won't work on FreeBSD anyway, since
`/proc` is not mounted by default.)
Reviewers: kcc, emaste, joerg, davide
Subscribers: llvm-commits, emaste
Differential Revision: http://reviews.llvm.org/D17832
llvm-svn: 263157
2016-03-11 04:22:02 +08:00
|
|
|
#if !SANITIZER_FREEBSD
|
2013-02-14 22:40:03 +08:00
|
|
|
extern "C" {
|
2013-08-13 19:42:45 +08:00
|
|
|
SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end;
|
2013-02-14 22:40:03 +08:00
|
|
|
}
|
Retrieve command line arguments and environment correctly on FreeBSD
Summary:
Recently I saw the test `TestCases/Posix/print_cmdline.cc` failing on
FreeBSD, with "expected string not found in input". This is because
asan could not retrieve the command line arguments properly.
In `lib/sanitizer_common/sanitizer_linux.cc`, this is taken care of by
the `GetArgsAndEnv()` function, but it uses `__libc_stack_end` to get at
the required data. This variable does not exist on BSDs; the regular
way to retrieve the arguments and environment information is via the
`kern.ps_strings` sysctl.
I added this functionality in sanitizer_linux.cc, as a separate #ifdef
block in `GetArgsAndEnv()`. Also, `ReadNullSepFileToArray()` becomes
unused due to this change. (It won't work on FreeBSD anyway, since
`/proc` is not mounted by default.)
Reviewers: kcc, emaste, joerg, davide
Subscribers: llvm-commits, emaste
Differential Revision: http://reviews.llvm.org/D17832
llvm-svn: 263157
2016-03-11 04:22:02 +08:00
|
|
|
#endif
|
2013-02-14 22:40:03 +08:00
|
|
|
|
Retrieve command line arguments and environment correctly on FreeBSD
Summary:
Recently I saw the test `TestCases/Posix/print_cmdline.cc` failing on
FreeBSD, with "expected string not found in input". This is because
asan could not retrieve the command line arguments properly.
In `lib/sanitizer_common/sanitizer_linux.cc`, this is taken care of by
the `GetArgsAndEnv()` function, but it uses `__libc_stack_end` to get at
the required data. This variable does not exist on BSDs; the regular
way to retrieve the arguments and environment information is via the
`kern.ps_strings` sysctl.
I added this functionality in sanitizer_linux.cc, as a separate #ifdef
block in `GetArgsAndEnv()`. Also, `ReadNullSepFileToArray()` becomes
unused due to this change. (It won't work on FreeBSD anyway, since
`/proc` is not mounted by default.)
Reviewers: kcc, emaste, joerg, davide
Subscribers: llvm-commits, emaste
Differential Revision: http://reviews.llvm.org/D17832
llvm-svn: 263157
2016-03-11 04:22:02 +08:00
|
|
|
#if !SANITIZER_GO && !SANITIZER_FREEBSD
|
2013-01-18 03:50:42 +08:00
|
|
|
static void ReadNullSepFileToArray(const char *path, char ***arr,
|
|
|
|
int arr_size) {
|
|
|
|
char *buff;
|
2015-07-18 07:50:08 +08:00
|
|
|
uptr buff_size;
|
|
|
|
uptr buff_len;
|
2013-01-18 03:50:42 +08:00
|
|
|
*arr = (char **)MmapOrDie(arr_size * sizeof(char *), "NullSepFileArray");
|
2015-07-18 07:50:08 +08:00
|
|
|
if (!ReadFileToBuffer(path, &buff, &buff_size, &buff_len, 1024 * 1024)) {
|
|
|
|
(*arr)[0] = nullptr;
|
|
|
|
return;
|
|
|
|
}
|
2013-01-18 03:50:42 +08:00
|
|
|
(*arr)[0] = buff;
|
|
|
|
int count, i;
|
|
|
|
for (count = 1, i = 1; ; i++) {
|
2012-09-17 17:12:39 +08:00
|
|
|
if (buff[i] == 0) {
|
|
|
|
if (buff[i+1] == 0) break;
|
2013-01-18 03:50:42 +08:00
|
|
|
(*arr)[count] = &buff[i+1];
|
|
|
|
CHECK_LE(count, arr_size - 1); // FIXME: make this more flexible.
|
|
|
|
count++;
|
2012-09-17 17:12:39 +08:00
|
|
|
}
|
|
|
|
}
|
2015-07-18 07:50:08 +08:00
|
|
|
(*arr)[count] = nullptr;
|
2013-01-18 03:50:42 +08:00
|
|
|
}
|
2014-12-12 00:12:45 +08:00
|
|
|
#endif
|
2014-12-09 09:22:59 +08:00
|
|
|
|
2016-01-18 15:55:12 +08:00
|
|
|
static void GetArgsAndEnv(char ***argv, char ***envp) {
|
Retrieve command line arguments and environment correctly on FreeBSD
Summary:
Recently I saw the test `TestCases/Posix/print_cmdline.cc` failing on
FreeBSD, with "expected string not found in input". This is because
asan could not retrieve the command line arguments properly.
In `lib/sanitizer_common/sanitizer_linux.cc`, this is taken care of by
the `GetArgsAndEnv()` function, but it uses `__libc_stack_end` to get at
the required data. This variable does not exist on BSDs; the regular
way to retrieve the arguments and environment information is via the
`kern.ps_strings` sysctl.
I added this functionality in sanitizer_linux.cc, as a separate #ifdef
block in `GetArgsAndEnv()`. Also, `ReadNullSepFileToArray()` becomes
unused due to this change. (It won't work on FreeBSD anyway, since
`/proc` is not mounted by default.)
Reviewers: kcc, emaste, joerg, davide
Subscribers: llvm-commits, emaste
Differential Revision: http://reviews.llvm.org/D17832
llvm-svn: 263157
2016-03-11 04:22:02 +08:00
|
|
|
#if !SANITIZER_FREEBSD
|
2013-05-20 22:25:32 +08:00
|
|
|
#if !SANITIZER_GO
|
|
|
|
if (&__libc_stack_end) {
|
|
|
|
#endif
|
|
|
|
uptr* stack_end = (uptr*)__libc_stack_end;
|
|
|
|
int argc = *stack_end;
|
|
|
|
*argv = (char**)(stack_end + 1);
|
|
|
|
*envp = (char**)(stack_end + argc + 2);
|
|
|
|
#if !SANITIZER_GO
|
|
|
|
} else {
|
|
|
|
static const int kMaxArgv = 2000, kMaxEnvp = 2000;
|
|
|
|
ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv);
|
|
|
|
ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp);
|
|
|
|
}
|
|
|
|
#endif
|
Retrieve command line arguments and environment correctly on FreeBSD
Summary:
Recently I saw the test `TestCases/Posix/print_cmdline.cc` failing on
FreeBSD, with "expected string not found in input". This is because
asan could not retrieve the command line arguments properly.
In `lib/sanitizer_common/sanitizer_linux.cc`, this is taken care of by
the `GetArgsAndEnv()` function, but it uses `__libc_stack_end` to get at
the required data. This variable does not exist on BSDs; the regular
way to retrieve the arguments and environment information is via the
`kern.ps_strings` sysctl.
I added this functionality in sanitizer_linux.cc, as a separate #ifdef
block in `GetArgsAndEnv()`. Also, `ReadNullSepFileToArray()` becomes
unused due to this change. (It won't work on FreeBSD anyway, since
`/proc` is not mounted by default.)
Reviewers: kcc, emaste, joerg, davide
Subscribers: llvm-commits, emaste
Differential Revision: http://reviews.llvm.org/D17832
llvm-svn: 263157
2016-03-11 04:22:02 +08:00
|
|
|
#else
|
|
|
|
// On FreeBSD, retrieving the argument and environment arrays is done via the
|
|
|
|
// kern.ps_strings sysctl, which returns a pointer to a structure containing
|
2016-04-14 22:17:42 +08:00
|
|
|
// this information. See also <sys/exec.h>.
|
Retrieve command line arguments and environment correctly on FreeBSD
Summary:
Recently I saw the test `TestCases/Posix/print_cmdline.cc` failing on
FreeBSD, with "expected string not found in input". This is because
asan could not retrieve the command line arguments properly.
In `lib/sanitizer_common/sanitizer_linux.cc`, this is taken care of by
the `GetArgsAndEnv()` function, but it uses `__libc_stack_end` to get at
the required data. This variable does not exist on BSDs; the regular
way to retrieve the arguments and environment information is via the
`kern.ps_strings` sysctl.
I added this functionality in sanitizer_linux.cc, as a separate #ifdef
block in `GetArgsAndEnv()`. Also, `ReadNullSepFileToArray()` becomes
unused due to this change. (It won't work on FreeBSD anyway, since
`/proc` is not mounted by default.)
Reviewers: kcc, emaste, joerg, davide
Subscribers: llvm-commits, emaste
Differential Revision: http://reviews.llvm.org/D17832
llvm-svn: 263157
2016-03-11 04:22:02 +08:00
|
|
|
ps_strings *pss;
|
|
|
|
size_t sz = sizeof(pss);
|
2016-04-14 22:17:42 +08:00
|
|
|
if (sysctlbyname("kern.ps_strings", &pss, &sz, NULL, 0) == -1) {
|
|
|
|
Printf("sysctl kern.ps_strings failed\n");
|
|
|
|
Die();
|
|
|
|
}
|
Retrieve command line arguments and environment correctly on FreeBSD
Summary:
Recently I saw the test `TestCases/Posix/print_cmdline.cc` failing on
FreeBSD, with "expected string not found in input". This is because
asan could not retrieve the command line arguments properly.
In `lib/sanitizer_common/sanitizer_linux.cc`, this is taken care of by
the `GetArgsAndEnv()` function, but it uses `__libc_stack_end` to get at
the required data. This variable does not exist on BSDs; the regular
way to retrieve the arguments and environment information is via the
`kern.ps_strings` sysctl.
I added this functionality in sanitizer_linux.cc, as a separate #ifdef
block in `GetArgsAndEnv()`. Also, `ReadNullSepFileToArray()` becomes
unused due to this change. (It won't work on FreeBSD anyway, since
`/proc` is not mounted by default.)
Reviewers: kcc, emaste, joerg, davide
Subscribers: llvm-commits, emaste
Differential Revision: http://reviews.llvm.org/D17832
llvm-svn: 263157
2016-03-11 04:22:02 +08:00
|
|
|
*argv = pss->ps_argvstr;
|
|
|
|
*envp = pss->ps_envstr;
|
|
|
|
#endif
|
2013-02-14 22:40:03 +08:00
|
|
|
}
|
|
|
|
|
2016-01-18 15:55:12 +08:00
|
|
|
char **GetArgv() {
|
|
|
|
char **argv, **envp;
|
|
|
|
GetArgsAndEnv(&argv, &envp);
|
|
|
|
return argv;
|
|
|
|
}
|
|
|
|
|
2013-02-14 22:40:03 +08:00
|
|
|
void ReExec() {
|
2013-01-18 03:50:42 +08:00
|
|
|
char **argv, **envp;
|
2013-02-14 22:40:03 +08:00
|
|
|
GetArgsAndEnv(&argv, &envp);
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr rv = internal_execve("/proc/self/exe", argv, envp);
|
|
|
|
int rverrno;
|
|
|
|
CHECK_EQ(internal_iserror(rv, &rverrno), true);
|
|
|
|
Printf("execve failed, errno %d\n", rverrno);
|
2013-02-19 19:09:29 +08:00
|
|
|
Die();
|
2012-09-17 17:12:39 +08:00
|
|
|
}
|
|
|
|
|
2013-01-14 15:51:39 +08:00
|
|
|
enum MutexState {
|
|
|
|
MtxUnlocked = 0,
|
|
|
|
MtxLocked = 1,
|
|
|
|
MtxSleeping = 2
|
|
|
|
};
|
|
|
|
|
2013-03-14 21:30:56 +08:00
|
|
|
BlockingMutex::BlockingMutex() {
|
|
|
|
internal_memset(this, 0, sizeof(*this));
|
|
|
|
}
|
|
|
|
|
2013-01-14 15:51:39 +08:00
|
|
|
void BlockingMutex::Lock() {
|
2015-01-30 14:20:43 +08:00
|
|
|
CHECK_EQ(owner_, 0);
|
2013-01-14 15:51:39 +08:00
|
|
|
atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
|
|
|
|
if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked)
|
|
|
|
return;
|
2014-03-07 18:03:54 +08:00
|
|
|
while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) {
|
|
|
|
#if SANITIZER_FREEBSD
|
|
|
|
_umtx_op(m, UMTX_OP_WAIT_UINT, MtxSleeping, 0, 0);
|
|
|
|
#else
|
|
|
|
internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAIT, MtxSleeping, 0, 0, 0);
|
|
|
|
#endif
|
|
|
|
}
|
2013-01-14 15:51:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void BlockingMutex::Unlock() {
|
|
|
|
atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
|
|
|
|
u32 v = atomic_exchange(m, MtxUnlocked, memory_order_relaxed);
|
2013-01-14 16:01:58 +08:00
|
|
|
CHECK_NE(v, MtxUnlocked);
|
2014-03-07 18:03:54 +08:00
|
|
|
if (v == MtxSleeping) {
|
|
|
|
#if SANITIZER_FREEBSD
|
|
|
|
_umtx_op(m, UMTX_OP_WAKE, 1, 0, 0);
|
|
|
|
#else
|
|
|
|
internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAKE, 1, 0, 0, 0);
|
|
|
|
#endif
|
|
|
|
}
|
2013-01-14 15:51:39 +08:00
|
|
|
}
|
|
|
|
|
2013-03-11 23:45:20 +08:00
|
|
|
void BlockingMutex::CheckLocked() {
|
|
|
|
atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
|
|
|
|
CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed));
|
|
|
|
}
|
|
|
|
|
2013-02-27 19:22:40 +08:00
|
|
|
// ----------------- sanitizer_linux.h
|
|
|
|
// The actual size of this structure is specified by d_reclen.
|
|
|
|
// Note that getdents64 uses a different structure format. We only provide the
|
|
|
|
// 32-bit syscall here.
|
|
|
|
struct linux_dirent {
|
2015-10-21 21:08:06 +08:00
|
|
|
#if SANITIZER_X32 || defined(__aarch64__)
|
2014-05-21 16:21:13 +08:00
|
|
|
u64 d_ino;
|
|
|
|
u64 d_off;
|
|
|
|
#else
|
2013-02-27 19:22:40 +08:00
|
|
|
unsigned long d_ino;
|
|
|
|
unsigned long d_off;
|
2014-05-21 16:21:13 +08:00
|
|
|
#endif
|
2013-02-27 19:22:40 +08:00
|
|
|
unsigned short d_reclen;
|
2015-10-21 21:08:06 +08:00
|
|
|
#ifdef __aarch64__
|
|
|
|
unsigned char d_type;
|
|
|
|
#endif
|
2013-02-27 19:22:40 +08:00
|
|
|
char d_name[256];
|
|
|
|
};
|
|
|
|
|
|
|
|
// Syscall wrappers.
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_ptrace(int request, int pid, void *addr, void *data) {
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr,
|
|
|
|
(uptr)data);
|
2013-05-08 22:43:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
uptr internal_waitpid(int pid, int *status, int options) {
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(wait4), pid, (uptr)status, options,
|
2013-11-07 01:47:39 +08:00
|
|
|
0 /* rusage */);
|
2013-02-27 19:22:40 +08:00
|
|
|
}
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_getpid() {
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(getpid));
|
2013-02-27 19:22:40 +08:00
|
|
|
}
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_getppid() {
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(getppid));
|
2013-02-27 19:22:40 +08:00
|
|
|
}
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
|
2014-02-13 15:50:20 +08:00
|
|
|
#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(getdents64), fd, (uptr)dirp, count);
|
2014-02-13 15:50:20 +08:00
|
|
|
#else
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(getdents), fd, (uptr)dirp, count);
|
2014-02-13 15:50:20 +08:00
|
|
|
#endif
|
2013-02-27 19:22:40 +08:00
|
|
|
}
|
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_lseek(fd_t fd, OFF_T offset, int whence) {
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(lseek), fd, offset, whence);
|
2013-02-27 19:22:40 +08:00
|
|
|
}
|
|
|
|
|
2014-03-07 18:03:54 +08:00
|
|
|
#if SANITIZER_LINUX
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) {
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(prctl), option, arg2, arg3, arg4, arg5);
|
2013-02-27 19:22:40 +08:00
|
|
|
}
|
2014-03-07 18:03:54 +08:00
|
|
|
#endif
|
2013-02-27 19:22:40 +08:00
|
|
|
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr internal_sigaltstack(const struct sigaltstack *ss,
|
2013-02-27 19:22:40 +08:00
|
|
|
struct sigaltstack *oss) {
|
2014-03-07 18:03:54 +08:00
|
|
|
return internal_syscall(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss);
|
2013-02-27 19:22:40 +08:00
|
|
|
}
|
|
|
|
|
2014-05-14 01:31:09 +08:00
|
|
|
int internal_fork() {
|
2014-05-27 07:44:55 +08:00
|
|
|
#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
|
|
|
|
return internal_syscall(SYSCALL(clone), SIGCHLD, 0);
|
|
|
|
#else
|
2014-05-14 00:17:54 +08:00
|
|
|
return internal_syscall(SYSCALL(fork));
|
2014-05-27 07:44:55 +08:00
|
|
|
#endif
|
2014-05-14 00:17:54 +08:00
|
|
|
}
|
|
|
|
|
2014-03-07 18:03:54 +08:00
|
|
|
#if SANITIZER_LINUX
|
2015-03-03 01:36:02 +08:00
|
|
|
#define SA_RESTORER 0x04000000
|
[sanitizer][esan] Add internal_sigaction_syscall
Summary:
Adds a version of sigaction that uses a raw system call, to avoid circular
dependencies and support calling sigaction prior to setting up
interceptors. The new sigaction relies on an assembly sigreturn routine
for its restorer, which is Linux x86_64-only for now.
Uses the new sigaction to initialize the working set tool's shadow fault
handler prior to libc interceptor being set up. This is required to
support instrumentation invoked during interceptor setup, which happens
with an instrumented tcmalloc or other allocator compiled with esan.
Adds a test that emulates an instrumented allocator.
Reviewers: aizatsky
Subscribers: vitalybuka, tberghammer, zhaoqin, danalbert, kcc, srhines, eugenis, llvm-commits, kubabrecka
Differential Revision: http://reviews.llvm.org/D21083
llvm-svn: 272676
2016-06-14 23:15:38 +08:00
|
|
|
// Doesn't set sa_restorer if the caller did not set it, so use with caution
|
|
|
|
//(see below).
|
2014-01-31 19:29:51 +08:00
|
|
|
int internal_sigaction_norestorer(int signum, const void *act, void *oldact) {
|
|
|
|
__sanitizer_kernel_sigaction_t k_act, k_oldact;
|
|
|
|
internal_memset(&k_act, 0, sizeof(__sanitizer_kernel_sigaction_t));
|
|
|
|
internal_memset(&k_oldact, 0, sizeof(__sanitizer_kernel_sigaction_t));
|
2014-11-14 06:40:59 +08:00
|
|
|
const __sanitizer_sigaction *u_act = (const __sanitizer_sigaction *)act;
|
2014-01-31 19:29:51 +08:00
|
|
|
__sanitizer_sigaction *u_oldact = (__sanitizer_sigaction *)oldact;
|
|
|
|
if (u_act) {
|
|
|
|
k_act.handler = u_act->handler;
|
|
|
|
k_act.sigaction = u_act->sigaction;
|
|
|
|
internal_memcpy(&k_act.sa_mask, &u_act->sa_mask,
|
|
|
|
sizeof(__sanitizer_kernel_sigset_t));
|
2015-03-03 01:36:02 +08:00
|
|
|
// Without SA_RESTORER kernel ignores the calls (probably returns EINVAL).
|
|
|
|
k_act.sa_flags = u_act->sa_flags | SA_RESTORER;
|
2014-01-31 19:29:51 +08:00
|
|
|
// FIXME: most often sa_restorer is unset, however the kernel requires it
|
|
|
|
// to point to a valid signal restorer that calls the rt_sigreturn syscall.
|
|
|
|
// If sa_restorer passed to the kernel is NULL, the program may crash upon
|
|
|
|
// signal delivery or fail to unwind the stack in the signal handler.
|
|
|
|
// libc implementation of sigaction() passes its own restorer to
|
|
|
|
// rt_sigaction, so we need to do the same (we'll need to reimplement the
|
|
|
|
// restorers; for x86_64 the restorer address can be obtained from
|
|
|
|
// oldact->sa_restorer upon a call to sigaction(xxx, NULL, oldact).
|
2016-03-16 16:23:10 +08:00
|
|
|
#if !SANITIZER_ANDROID || !SANITIZER_MIPS32
|
2014-01-31 19:29:51 +08:00
|
|
|
k_act.sa_restorer = u_act->sa_restorer;
|
2016-03-16 16:23:10 +08:00
|
|
|
#endif
|
2014-01-31 19:29:51 +08:00
|
|
|
}
|
|
|
|
|
2014-03-07 18:03:54 +08:00
|
|
|
uptr result = internal_syscall(SYSCALL(rt_sigaction), (uptr)signum,
|
2015-10-01 07:52:54 +08:00
|
|
|
(uptr)(u_act ? &k_act : nullptr),
|
|
|
|
(uptr)(u_oldact ? &k_oldact : nullptr),
|
2014-01-31 19:29:51 +08:00
|
|
|
(uptr)sizeof(__sanitizer_kernel_sigset_t));
|
|
|
|
|
|
|
|
if ((result == 0) && u_oldact) {
|
|
|
|
u_oldact->handler = k_oldact.handler;
|
|
|
|
u_oldact->sigaction = k_oldact.sigaction;
|
|
|
|
internal_memcpy(&u_oldact->sa_mask, &k_oldact.sa_mask,
|
|
|
|
sizeof(__sanitizer_kernel_sigset_t));
|
|
|
|
u_oldact->sa_flags = k_oldact.sa_flags;
|
2016-03-16 16:23:10 +08:00
|
|
|
#if !SANITIZER_ANDROID || !SANITIZER_MIPS32
|
2014-01-31 19:29:51 +08:00
|
|
|
u_oldact->sa_restorer = k_oldact.sa_restorer;
|
2016-03-16 16:23:10 +08:00
|
|
|
#endif
|
2014-01-31 19:29:51 +08:00
|
|
|
}
|
|
|
|
return result;
|
2013-10-15 19:31:51 +08:00
|
|
|
}
|
[sanitizer][esan] Add internal_sigaction_syscall
Summary:
Adds a version of sigaction that uses a raw system call, to avoid circular
dependencies and support calling sigaction prior to setting up
interceptors. The new sigaction relies on an assembly sigreturn routine
for its restorer, which is Linux x86_64-only for now.
Uses the new sigaction to initialize the working set tool's shadow fault
handler prior to libc interceptor being set up. This is required to
support instrumentation invoked during interceptor setup, which happens
with an instrumented tcmalloc or other allocator compiled with esan.
Adds a test that emulates an instrumented allocator.
Reviewers: aizatsky
Subscribers: vitalybuka, tberghammer, zhaoqin, danalbert, kcc, srhines, eugenis, llvm-commits, kubabrecka
Differential Revision: http://reviews.llvm.org/D21083
llvm-svn: 272676
2016-06-14 23:15:38 +08:00
|
|
|
|
|
|
|
// Invokes sigaction via a raw syscall with a restorer, but does not support
|
|
|
|
// all platforms yet.
|
|
|
|
// We disable for Go simply because we have not yet added to buildgo.sh.
|
2016-09-07 17:09:03 +08:00
|
|
|
#if (defined(__x86_64__) || SANITIZER_MIPS64) && !SANITIZER_GO
|
[sanitizer][esan] Add internal_sigaction_syscall
Summary:
Adds a version of sigaction that uses a raw system call, to avoid circular
dependencies and support calling sigaction prior to setting up
interceptors. The new sigaction relies on an assembly sigreturn routine
for its restorer, which is Linux x86_64-only for now.
Uses the new sigaction to initialize the working set tool's shadow fault
handler prior to libc interceptor being set up. This is required to
support instrumentation invoked during interceptor setup, which happens
with an instrumented tcmalloc or other allocator compiled with esan.
Adds a test that emulates an instrumented allocator.
Reviewers: aizatsky
Subscribers: vitalybuka, tberghammer, zhaoqin, danalbert, kcc, srhines, eugenis, llvm-commits, kubabrecka
Differential Revision: http://reviews.llvm.org/D21083
llvm-svn: 272676
2016-06-14 23:15:38 +08:00
|
|
|
int internal_sigaction_syscall(int signum, const void *act, void *oldact) {
|
2016-07-07 04:13:40 +08:00
|
|
|
if (act == nullptr)
|
|
|
|
return internal_sigaction_norestorer(signum, act, oldact);
|
[sanitizer][esan] Add internal_sigaction_syscall
Summary:
Adds a version of sigaction that uses a raw system call, to avoid circular
dependencies and support calling sigaction prior to setting up
interceptors. The new sigaction relies on an assembly sigreturn routine
for its restorer, which is Linux x86_64-only for now.
Uses the new sigaction to initialize the working set tool's shadow fault
handler prior to libc interceptor being set up. This is required to
support instrumentation invoked during interceptor setup, which happens
with an instrumented tcmalloc or other allocator compiled with esan.
Adds a test that emulates an instrumented allocator.
Reviewers: aizatsky
Subscribers: vitalybuka, tberghammer, zhaoqin, danalbert, kcc, srhines, eugenis, llvm-commits, kubabrecka
Differential Revision: http://reviews.llvm.org/D21083
llvm-svn: 272676
2016-06-14 23:15:38 +08:00
|
|
|
__sanitizer_sigaction u_adjust;
|
|
|
|
internal_memcpy(&u_adjust, act, sizeof(u_adjust));
|
|
|
|
#if !SANITIZER_ANDROID || !SANITIZER_MIPS32
|
|
|
|
if (u_adjust.sa_restorer == nullptr) {
|
|
|
|
u_adjust.sa_restorer = internal_sigreturn;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return internal_sigaction_norestorer(signum, (const void *)&u_adjust,
|
|
|
|
oldact);
|
|
|
|
}
|
|
|
|
#endif // defined(__x86_64__) && !SANITIZER_GO
|
2014-03-07 18:03:54 +08:00
|
|
|
#endif // SANITIZER_LINUX
|
2013-10-15 19:31:51 +08:00
|
|
|
|
2014-01-31 19:29:51 +08:00
|
|
|
uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
|
|
|
|
__sanitizer_sigset_t *oldset) {
|
2014-03-07 18:03:54 +08:00
|
|
|
#if SANITIZER_FREEBSD
|
|
|
|
return internal_syscall(SYSCALL(sigprocmask), how, set, oldset);
|
|
|
|
#else
|
2014-01-31 19:29:51 +08:00
|
|
|
__sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set;
|
|
|
|
__sanitizer_kernel_sigset_t *k_oldset = (__sanitizer_kernel_sigset_t *)oldset;
|
2014-05-21 15:49:03 +08:00
|
|
|
return internal_syscall(SYSCALL(rt_sigprocmask), (uptr)how,
|
|
|
|
(uptr)&k_set->sig[0], (uptr)&k_oldset->sig[0],
|
|
|
|
sizeof(__sanitizer_kernel_sigset_t));
|
2014-03-07 18:03:54 +08:00
|
|
|
#endif
|
2013-10-15 19:31:51 +08:00
|
|
|
}
|
|
|
|
|
2014-01-31 19:29:51 +08:00
|
|
|
void internal_sigfillset(__sanitizer_sigset_t *set) {
|
2013-10-15 19:31:51 +08:00
|
|
|
internal_memset(set, 0xff, sizeof(*set));
|
|
|
|
}
|
|
|
|
|
2016-07-07 05:04:48 +08:00
|
|
|
void internal_sigemptyset(__sanitizer_sigset_t *set) {
|
|
|
|
internal_memset(set, 0, sizeof(*set));
|
|
|
|
}
|
|
|
|
|
2014-03-07 18:03:54 +08:00
|
|
|
#if SANITIZER_LINUX
|
2014-01-31 19:29:51 +08:00
|
|
|
void internal_sigdelset(__sanitizer_sigset_t *set, int signum) {
|
2013-10-15 19:31:51 +08:00
|
|
|
signum -= 1;
|
|
|
|
CHECK_GE(signum, 0);
|
|
|
|
CHECK_LT(signum, sizeof(*set) * 8);
|
2014-01-31 19:29:51 +08:00
|
|
|
__sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set;
|
|
|
|
const uptr idx = signum / (sizeof(k_set->sig[0]) * 8);
|
|
|
|
const uptr bit = signum % (sizeof(k_set->sig[0]) * 8);
|
|
|
|
k_set->sig[idx] &= ~(1 << bit);
|
2013-10-15 19:31:51 +08:00
|
|
|
}
|
2016-07-07 05:04:48 +08:00
|
|
|
|
|
|
|
bool internal_sigismember(__sanitizer_sigset_t *set, int signum) {
|
|
|
|
signum -= 1;
|
|
|
|
CHECK_GE(signum, 0);
|
|
|
|
CHECK_LT(signum, sizeof(*set) * 8);
|
|
|
|
__sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set;
|
|
|
|
const uptr idx = signum / (sizeof(k_set->sig[0]) * 8);
|
|
|
|
const uptr bit = signum % (sizeof(k_set->sig[0]) * 8);
|
|
|
|
return k_set->sig[idx] & (1 << bit);
|
|
|
|
}
|
2014-03-07 18:03:54 +08:00
|
|
|
#endif // SANITIZER_LINUX
|
2013-10-15 19:31:51 +08:00
|
|
|
|
2013-02-27 19:22:40 +08:00
|
|
|
// ThreadLister implementation.
|
|
|
|
ThreadLister::ThreadLister(int pid)
|
|
|
|
: pid_(pid),
|
|
|
|
descriptor_(-1),
|
2013-04-05 15:41:21 +08:00
|
|
|
buffer_(4096),
|
2013-02-27 19:22:40 +08:00
|
|
|
error_(true),
|
2013-04-05 15:41:21 +08:00
|
|
|
entry_((struct linux_dirent *)buffer_.data()),
|
2013-02-27 19:22:40 +08:00
|
|
|
bytes_read_(0) {
|
|
|
|
char task_directory_path[80];
|
|
|
|
internal_snprintf(task_directory_path, sizeof(task_directory_path),
|
|
|
|
"/proc/%d/task/", pid);
|
2013-05-08 22:43:49 +08:00
|
|
|
uptr openrv = internal_open(task_directory_path, O_RDONLY | O_DIRECTORY);
|
|
|
|
if (internal_iserror(openrv)) {
|
2013-02-27 19:22:40 +08:00
|
|
|
error_ = true;
|
|
|
|
Report("Can't open /proc/%d/task for reading.\n", pid);
|
|
|
|
} else {
|
|
|
|
error_ = false;
|
2013-05-08 22:43:49 +08:00
|
|
|
descriptor_ = openrv;
|
2013-02-27 19:22:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int ThreadLister::GetNextTID() {
|
|
|
|
int tid = -1;
|
|
|
|
do {
|
|
|
|
if (error_)
|
|
|
|
return -1;
|
|
|
|
if ((char *)entry_ >= &buffer_[bytes_read_] && !GetDirectoryEntries())
|
|
|
|
return -1;
|
|
|
|
if (entry_->d_ino != 0 && entry_->d_name[0] >= '0' &&
|
|
|
|
entry_->d_name[0] <= '9') {
|
|
|
|
// Found a valid tid.
|
|
|
|
tid = (int)internal_atoll(entry_->d_name);
|
|
|
|
}
|
|
|
|
entry_ = (struct linux_dirent *)(((char *)entry_) + entry_->d_reclen);
|
|
|
|
} while (tid < 0);
|
|
|
|
return tid;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ThreadLister::Reset() {
|
|
|
|
if (error_ || descriptor_ < 0)
|
|
|
|
return;
|
|
|
|
internal_lseek(descriptor_, 0, SEEK_SET);
|
|
|
|
}
|
|
|
|
|
|
|
|
ThreadLister::~ThreadLister() {
|
|
|
|
if (descriptor_ >= 0)
|
|
|
|
internal_close(descriptor_);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ThreadLister::error() { return error_; }
|
|
|
|
|
|
|
|
bool ThreadLister::GetDirectoryEntries() {
|
|
|
|
CHECK_GE(descriptor_, 0);
|
|
|
|
CHECK_NE(error_, true);
|
|
|
|
bytes_read_ = internal_getdents(descriptor_,
|
2013-04-05 15:41:21 +08:00
|
|
|
(struct linux_dirent *)buffer_.data(),
|
|
|
|
buffer_.size());
|
2013-05-08 22:43:49 +08:00
|
|
|
if (internal_iserror(bytes_read_)) {
|
2013-02-27 19:22:40 +08:00
|
|
|
Report("Can't read directory entries from /proc/%d/task.\n", pid_);
|
|
|
|
error_ = true;
|
|
|
|
return false;
|
|
|
|
} else if (bytes_read_ == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
2013-04-05 15:41:21 +08:00
|
|
|
entry_ = (struct linux_dirent *)buffer_.data();
|
2013-02-27 19:22:40 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-05-21 01:05:29 +08:00
|
|
|
uptr GetPageSize() {
|
2016-01-26 03:25:20 +08:00
|
|
|
// Android post-M sysconf(_SC_PAGESIZE) crashes if called from .preinit_array.
|
2016-07-27 05:02:44 +08:00
|
|
|
#if SANITIZER_ANDROID
|
|
|
|
return 4096;
|
|
|
|
#elif SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__))
|
2013-05-21 01:05:29 +08:00
|
|
|
return EXEC_PAGESIZE;
|
2013-05-21 14:15:50 +08:00
|
|
|
#else
|
|
|
|
return sysconf(_SC_PAGESIZE); // EXEC_PAGESIZE may not be trustworthy.
|
|
|
|
#endif
|
2013-05-21 01:05:29 +08:00
|
|
|
}
|
|
|
|
|
2013-09-10 22:36:16 +08:00
|
|
|
uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
|
2014-05-29 20:12:42 +08:00
|
|
|
#if SANITIZER_FREEBSD
|
2015-06-04 15:29:43 +08:00
|
|
|
const int Mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
|
|
|
|
const char *default_module_name = "kern.proc.pathname";
|
2014-05-29 20:12:42 +08:00
|
|
|
size_t Size = buf_len;
|
2015-06-04 15:29:43 +08:00
|
|
|
bool IsErr = (sysctl(Mib, ARRAY_SIZE(Mib), buf, &Size, NULL, 0) != 0);
|
2014-05-29 20:12:42 +08:00
|
|
|
int readlink_error = IsErr ? errno : 0;
|
|
|
|
uptr module_name_len = Size;
|
|
|
|
#else
|
2015-06-04 15:29:43 +08:00
|
|
|
const char *default_module_name = "/proc/self/exe";
|
2013-09-10 22:36:16 +08:00
|
|
|
uptr module_name_len = internal_readlink(
|
2015-06-04 15:29:43 +08:00
|
|
|
default_module_name, buf, buf_len);
|
2013-09-10 22:36:16 +08:00
|
|
|
int readlink_error;
|
2014-05-29 20:12:42 +08:00
|
|
|
bool IsErr = internal_iserror(module_name_len, &readlink_error);
|
|
|
|
#endif
|
|
|
|
if (IsErr) {
|
2015-06-04 15:29:43 +08:00
|
|
|
// We can't read binary name for some reason, assume it's unknown.
|
|
|
|
Report("WARNING: reading executable name failed with errno %d, "
|
2014-05-29 05:23:53 +08:00
|
|
|
"some stack frames may not be symbolized\n", readlink_error);
|
2015-06-04 15:29:43 +08:00
|
|
|
module_name_len = internal_snprintf(buf, buf_len, "%s",
|
|
|
|
default_module_name);
|
2013-09-10 22:36:16 +08:00
|
|
|
CHECK_LT(module_name_len, buf_len);
|
|
|
|
}
|
|
|
|
return module_name_len;
|
|
|
|
}
|
|
|
|
|
2015-07-29 05:01:42 +08:00
|
|
|
uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) {
|
2015-07-29 04:27:51 +08:00
|
|
|
#if SANITIZER_LINUX
|
|
|
|
char *tmpbuf;
|
|
|
|
uptr tmpsize;
|
|
|
|
uptr tmplen;
|
|
|
|
if (ReadFileToBuffer("/proc/self/cmdline", &tmpbuf, &tmpsize, &tmplen,
|
|
|
|
1024 * 1024)) {
|
|
|
|
internal_strncpy(buf, tmpbuf, buf_len);
|
|
|
|
UnmapOrDie(tmpbuf, tmpsize);
|
|
|
|
return internal_strlen(buf);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return ReadBinaryName(buf, buf_len);
|
|
|
|
}
|
|
|
|
|
2013-05-14 21:24:46 +08:00
|
|
|
// Match full names of the form /path/to/base_name{-,.}*
|
|
|
|
bool LibraryNameIs(const char *full_name, const char *base_name) {
|
|
|
|
const char *name = full_name;
|
|
|
|
// Strip path.
|
|
|
|
while (*name != '\0') name++;
|
|
|
|
while (name > full_name && *name != '/') name--;
|
|
|
|
if (*name == '/') name++;
|
|
|
|
uptr base_name_length = internal_strlen(base_name);
|
|
|
|
if (internal_strncmp(name, base_name, base_name_length)) return false;
|
|
|
|
return (name[base_name_length] == '-' || name[base_name_length] == '.');
|
|
|
|
}
|
|
|
|
|
2013-07-30 16:39:16 +08:00
|
|
|
#if !SANITIZER_ANDROID
|
2013-07-30 03:09:49 +08:00
|
|
|
// Call cb for each region mapped by map.
|
|
|
|
void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
|
2015-01-30 20:43:52 +08:00
|
|
|
CHECK_NE(map, nullptr);
|
2014-03-07 18:03:54 +08:00
|
|
|
#if !SANITIZER_FREEBSD
|
2013-07-30 03:09:49 +08:00
|
|
|
typedef ElfW(Phdr) Elf_Phdr;
|
|
|
|
typedef ElfW(Ehdr) Elf_Ehdr;
|
2014-03-07 18:03:54 +08:00
|
|
|
#endif // !SANITIZER_FREEBSD
|
2013-07-30 03:09:49 +08:00
|
|
|
char *base = (char *)map->l_addr;
|
|
|
|
Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
|
|
|
|
char *phdrs = base + ehdr->e_phoff;
|
|
|
|
char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize;
|
|
|
|
|
|
|
|
// Find the segment with the minimum base so we can "relocate" the p_vaddr
|
|
|
|
// fields. Typically ET_DYN objects (DSOs) have base of zero and ET_EXEC
|
|
|
|
// objects have a non-zero base.
|
2013-07-30 04:13:41 +08:00
|
|
|
uptr preferred_base = (uptr)-1;
|
2013-07-30 03:09:49 +08:00
|
|
|
for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
|
|
|
|
Elf_Phdr *phdr = (Elf_Phdr *)iter;
|
|
|
|
if (phdr->p_type == PT_LOAD && preferred_base > (uptr)phdr->p_vaddr)
|
|
|
|
preferred_base = (uptr)phdr->p_vaddr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compute the delta from the real base to get a relocation delta.
|
|
|
|
sptr delta = (uptr)base - preferred_base;
|
|
|
|
// Now we can figure out what the loader really mapped.
|
|
|
|
for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
|
|
|
|
Elf_Phdr *phdr = (Elf_Phdr *)iter;
|
|
|
|
if (phdr->p_type == PT_LOAD) {
|
|
|
|
uptr seg_start = phdr->p_vaddr + delta;
|
|
|
|
uptr seg_end = seg_start + phdr->p_memsz;
|
|
|
|
// None of these values are aligned. We consider the ragged edges of the
|
|
|
|
// load command as defined, since they are mapped from the file.
|
|
|
|
seg_start = RoundDownTo(seg_start, GetPageSizeCached());
|
|
|
|
seg_end = RoundUpTo(seg_end, GetPageSizeCached());
|
|
|
|
cb((void *)seg_start, seg_end - seg_start);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-07-30 16:39:16 +08:00
|
|
|
#endif
|
2013-07-30 03:09:49 +08:00
|
|
|
|
2014-03-07 18:03:54 +08:00
|
|
|
#if defined(__x86_64__) && SANITIZER_LINUX
|
2013-09-02 19:36:19 +08:00
|
|
|
// We cannot use glibc's clone wrapper, because it messes with the child
|
|
|
|
// task's TLS. It writes the PID and TID of the child task to its thread
|
|
|
|
// descriptor, but in our case the child task shares the thread descriptor with
|
|
|
|
// the parent (because we don't know how to allocate a new thread
|
|
|
|
// descriptor to keep glibc happy). So the stock version of clone(), when
|
|
|
|
// used with CLONE_VM, would end up corrupting the parent's thread descriptor.
|
|
|
|
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
|
|
|
|
int *parent_tidptr, void *newtls, int *child_tidptr) {
|
|
|
|
long long res;
|
|
|
|
if (!fn || !child_stack)
|
|
|
|
return -EINVAL;
|
|
|
|
CHECK_EQ(0, (uptr)child_stack % 16);
|
2013-11-07 01:47:39 +08:00
|
|
|
child_stack = (char *)child_stack - 2 * sizeof(unsigned long long);
|
|
|
|
((unsigned long long *)child_stack)[0] = (uptr)fn;
|
|
|
|
((unsigned long long *)child_stack)[1] = (uptr)arg;
|
|
|
|
register void *r8 __asm__("r8") = newtls;
|
|
|
|
register int *r10 __asm__("r10") = child_tidptr;
|
2013-09-02 19:36:19 +08:00
|
|
|
__asm__ __volatile__(
|
2014-03-07 18:03:54 +08:00
|
|
|
/* %rax = syscall(%rax = SYSCALL(clone),
|
2013-09-02 19:36:19 +08:00
|
|
|
* %rdi = flags,
|
|
|
|
* %rsi = child_stack,
|
|
|
|
* %rdx = parent_tidptr,
|
|
|
|
* %r8 = new_tls,
|
|
|
|
* %r10 = child_tidptr)
|
|
|
|
*/
|
|
|
|
"syscall\n"
|
|
|
|
|
|
|
|
/* if (%rax != 0)
|
|
|
|
* return;
|
|
|
|
*/
|
|
|
|
"testq %%rax,%%rax\n"
|
|
|
|
"jnz 1f\n"
|
|
|
|
|
|
|
|
/* In the child. Terminate unwind chain. */
|
2013-10-09 00:38:39 +08:00
|
|
|
// XXX: We should also terminate the CFI unwind chain
|
|
|
|
// here. Unfortunately clang 3.2 doesn't support the
|
|
|
|
// necessary CFI directives, so we skip that part.
|
2013-09-02 19:36:19 +08:00
|
|
|
"xorq %%rbp,%%rbp\n"
|
|
|
|
|
|
|
|
/* Call "fn(arg)". */
|
|
|
|
"popq %%rax\n"
|
|
|
|
"popq %%rdi\n"
|
|
|
|
"call *%%rax\n"
|
|
|
|
|
|
|
|
/* Call _exit(%rax). */
|
|
|
|
"movq %%rax,%%rdi\n"
|
|
|
|
"movq %2,%%rax\n"
|
|
|
|
"syscall\n"
|
|
|
|
|
|
|
|
/* Return to parent. */
|
|
|
|
"1:\n"
|
|
|
|
: "=a" (res)
|
2014-03-07 18:03:54 +08:00
|
|
|
: "a"(SYSCALL(clone)), "i"(SYSCALL(exit)),
|
2013-09-02 19:36:19 +08:00
|
|
|
"S"(child_stack),
|
|
|
|
"D"(flags),
|
|
|
|
"d"(parent_tidptr),
|
2013-11-07 01:47:39 +08:00
|
|
|
"r"(r8),
|
|
|
|
"r"(r10)
|
|
|
|
: "rsp", "memory", "r11", "rcx");
|
2013-09-02 19:36:19 +08:00
|
|
|
return res;
|
|
|
|
}
|
2015-02-19 15:30:39 +08:00
|
|
|
#elif defined(__mips__)
|
|
|
|
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
|
|
|
|
int *parent_tidptr, void *newtls, int *child_tidptr) {
|
2015-05-06 13:38:21 +08:00
|
|
|
long long res;
|
|
|
|
if (!fn || !child_stack)
|
|
|
|
return -EINVAL;
|
|
|
|
CHECK_EQ(0, (uptr)child_stack % 16);
|
|
|
|
child_stack = (char *)child_stack - 2 * sizeof(unsigned long long);
|
|
|
|
((unsigned long long *)child_stack)[0] = (uptr)fn;
|
|
|
|
((unsigned long long *)child_stack)[1] = (uptr)arg;
|
|
|
|
register void *a3 __asm__("$7") = newtls;
|
|
|
|
register int *a4 __asm__("$8") = child_tidptr;
|
|
|
|
// We don't have proper CFI directives here because it requires alot of code
|
|
|
|
// for very marginal benefits.
|
|
|
|
__asm__ __volatile__(
|
|
|
|
/* $v0 = syscall($v0 = __NR_clone,
|
|
|
|
* $a0 = flags,
|
|
|
|
* $a1 = child_stack,
|
|
|
|
* $a2 = parent_tidptr,
|
|
|
|
* $a3 = new_tls,
|
|
|
|
* $a4 = child_tidptr)
|
|
|
|
*/
|
|
|
|
".cprestore 16;\n"
|
|
|
|
"move $4,%1;\n"
|
|
|
|
"move $5,%2;\n"
|
|
|
|
"move $6,%3;\n"
|
|
|
|
"move $7,%4;\n"
|
|
|
|
/* Store the fifth argument on stack
|
|
|
|
* if we are using 32-bit abi.
|
|
|
|
*/
|
|
|
|
#if SANITIZER_WORDSIZE == 32
|
|
|
|
"lw %5,16($29);\n"
|
|
|
|
#else
|
|
|
|
"move $8,%5;\n"
|
|
|
|
#endif
|
|
|
|
"li $2,%6;\n"
|
|
|
|
"syscall;\n"
|
|
|
|
|
|
|
|
/* if ($v0 != 0)
|
|
|
|
* return;
|
|
|
|
*/
|
|
|
|
"bnez $2,1f;\n"
|
|
|
|
|
|
|
|
/* Call "fn(arg)". */
|
2016-05-12 22:21:33 +08:00
|
|
|
#if SANITIZER_WORDSIZE == 32
|
|
|
|
#ifdef __BIG_ENDIAN__
|
|
|
|
"lw $25,4($29);\n"
|
|
|
|
"lw $4,12($29);\n"
|
|
|
|
#else
|
|
|
|
"lw $25,0($29);\n"
|
|
|
|
"lw $4,8($29);\n"
|
|
|
|
#endif
|
|
|
|
#else
|
2015-05-06 13:38:21 +08:00
|
|
|
"ld $25,0($29);\n"
|
|
|
|
"ld $4,8($29);\n"
|
2016-05-12 22:21:33 +08:00
|
|
|
#endif
|
2015-05-06 13:38:21 +08:00
|
|
|
"jal $25;\n"
|
|
|
|
|
|
|
|
/* Call _exit($v0). */
|
|
|
|
"move $4,$2;\n"
|
|
|
|
"li $2,%7;\n"
|
|
|
|
"syscall;\n"
|
|
|
|
|
|
|
|
/* Return to parent. */
|
|
|
|
"1:\n"
|
|
|
|
: "=r" (res)
|
|
|
|
: "r"(flags),
|
|
|
|
"r"(child_stack),
|
|
|
|
"r"(parent_tidptr),
|
|
|
|
"r"(a3),
|
|
|
|
"r"(a4),
|
|
|
|
"i"(__NR_clone),
|
|
|
|
"i"(__NR_exit)
|
|
|
|
: "memory", "$29" );
|
|
|
|
return res;
|
2015-02-19 15:30:39 +08:00
|
|
|
}
|
2015-08-05 23:17:59 +08:00
|
|
|
#elif defined(__aarch64__)
|
|
|
|
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
|
|
|
|
int *parent_tidptr, void *newtls, int *child_tidptr) {
|
|
|
|
long long res;
|
|
|
|
if (!fn || !child_stack)
|
|
|
|
return -EINVAL;
|
|
|
|
CHECK_EQ(0, (uptr)child_stack % 16);
|
|
|
|
child_stack = (char *)child_stack - 2 * sizeof(unsigned long long);
|
|
|
|
((unsigned long long *)child_stack)[0] = (uptr)fn;
|
|
|
|
((unsigned long long *)child_stack)[1] = (uptr)arg;
|
|
|
|
|
|
|
|
register int (*__fn)(void *) __asm__("x0") = fn;
|
|
|
|
register void *__stack __asm__("x1") = child_stack;
|
|
|
|
register int __flags __asm__("x2") = flags;
|
|
|
|
register void *__arg __asm__("x3") = arg;
|
|
|
|
register int *__ptid __asm__("x4") = parent_tidptr;
|
|
|
|
register void *__tls __asm__("x5") = newtls;
|
|
|
|
register int *__ctid __asm__("x6") = child_tidptr;
|
|
|
|
|
|
|
|
__asm__ __volatile__(
|
|
|
|
"mov x0,x2\n" /* flags */
|
|
|
|
"mov x2,x4\n" /* ptid */
|
|
|
|
"mov x3,x5\n" /* tls */
|
|
|
|
"mov x4,x6\n" /* ctid */
|
|
|
|
"mov x8,%9\n" /* clone */
|
|
|
|
|
|
|
|
"svc 0x0\n"
|
|
|
|
|
|
|
|
/* if (%r0 != 0)
|
|
|
|
* return %r0;
|
|
|
|
*/
|
|
|
|
"cmp x0, #0\n"
|
|
|
|
"bne 1f\n"
|
|
|
|
|
|
|
|
/* In the child, now. Call "fn(arg)". */
|
|
|
|
"ldp x1, x0, [sp], #16\n"
|
|
|
|
"blr x1\n"
|
|
|
|
|
|
|
|
/* Call _exit(%r0). */
|
|
|
|
"mov x8, %10\n"
|
|
|
|
"svc 0x0\n"
|
|
|
|
"1:\n"
|
|
|
|
|
|
|
|
: "=r" (res)
|
|
|
|
: "i"(-EINVAL),
|
|
|
|
"r"(__fn), "r"(__stack), "r"(__flags), "r"(__arg),
|
|
|
|
"r"(__ptid), "r"(__tls), "r"(__ctid),
|
|
|
|
"i"(__NR_clone), "i"(__NR_exit)
|
|
|
|
: "x30", "memory");
|
|
|
|
return res;
|
|
|
|
}
|
2015-12-09 05:54:39 +08:00
|
|
|
#elif defined(__powerpc64__)
|
|
|
|
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
|
|
|
|
int *parent_tidptr, void *newtls, int *child_tidptr) {
|
|
|
|
long long res;
|
|
|
|
/* Stack frame offsets. */
|
|
|
|
#if _CALL_ELF != 2
|
|
|
|
#define FRAME_MIN_SIZE 112
|
|
|
|
#define FRAME_TOC_SAVE 40
|
|
|
|
#else
|
|
|
|
#define FRAME_MIN_SIZE 32
|
|
|
|
#define FRAME_TOC_SAVE 24
|
|
|
|
#endif
|
|
|
|
if (!fn || !child_stack)
|
|
|
|
return -EINVAL;
|
|
|
|
CHECK_EQ(0, (uptr)child_stack % 16);
|
|
|
|
child_stack = (char *)child_stack - 2 * sizeof(unsigned long long);
|
|
|
|
((unsigned long long *)child_stack)[0] = (uptr)fn;
|
|
|
|
((unsigned long long *)child_stack)[1] = (uptr)arg;
|
|
|
|
|
|
|
|
register int (*__fn)(void *) __asm__("r3") = fn;
|
|
|
|
register void *__cstack __asm__("r4") = child_stack;
|
|
|
|
register int __flags __asm__("r5") = flags;
|
|
|
|
register void * __arg __asm__("r6") = arg;
|
|
|
|
register int * __ptidptr __asm__("r7") = parent_tidptr;
|
|
|
|
register void * __newtls __asm__("r8") = newtls;
|
|
|
|
register int * __ctidptr __asm__("r9") = child_tidptr;
|
|
|
|
|
|
|
|
__asm__ __volatile__(
|
|
|
|
/* fn, arg, child_stack are saved acrVoss the syscall */
|
|
|
|
"mr 28, %5\n\t"
|
|
|
|
"mr 29, %6\n\t"
|
|
|
|
"mr 27, %8\n\t"
|
|
|
|
|
|
|
|
/* syscall
|
|
|
|
r3 == flags
|
|
|
|
r4 == child_stack
|
|
|
|
r5 == parent_tidptr
|
|
|
|
r6 == newtls
|
|
|
|
r7 == child_tidptr */
|
|
|
|
"mr 3, %7\n\t"
|
|
|
|
"mr 5, %9\n\t"
|
|
|
|
"mr 6, %10\n\t"
|
|
|
|
"mr 7, %11\n\t"
|
|
|
|
"li 0, %3\n\t"
|
|
|
|
"sc\n\t"
|
|
|
|
|
|
|
|
/* Test if syscall was successful */
|
|
|
|
"cmpdi cr1, 3, 0\n\t"
|
|
|
|
"crandc cr1*4+eq, cr1*4+eq, cr0*4+so\n\t"
|
|
|
|
"bne- cr1, 1f\n\t"
|
|
|
|
|
|
|
|
/* Do the function call */
|
|
|
|
"std 2, %13(1)\n\t"
|
|
|
|
#if _CALL_ELF != 2
|
|
|
|
"ld 0, 0(28)\n\t"
|
|
|
|
"ld 2, 8(28)\n\t"
|
|
|
|
"mtctr 0\n\t"
|
|
|
|
#else
|
|
|
|
"mr 12, 28\n\t"
|
|
|
|
"mtctr 12\n\t"
|
|
|
|
#endif
|
|
|
|
"mr 3, 27\n\t"
|
|
|
|
"bctrl\n\t"
|
|
|
|
"ld 2, %13(1)\n\t"
|
|
|
|
|
|
|
|
/* Call _exit(r3) */
|
|
|
|
"li 0, %4\n\t"
|
|
|
|
"sc\n\t"
|
|
|
|
|
|
|
|
/* Return to parent */
|
|
|
|
"1:\n\t"
|
|
|
|
"mr %0, 3\n\t"
|
|
|
|
: "=r" (res)
|
|
|
|
: "0" (-1), "i" (EINVAL),
|
|
|
|
"i" (__NR_clone), "i" (__NR_exit),
|
|
|
|
"r" (__fn), "r" (__cstack), "r" (__flags),
|
|
|
|
"r" (__arg), "r" (__ptidptr), "r" (__newtls),
|
|
|
|
"r" (__ctidptr), "i" (FRAME_MIN_SIZE), "i" (FRAME_TOC_SAVE)
|
|
|
|
: "cr0", "cr1", "memory", "ctr",
|
|
|
|
"r0", "r29", "r27", "r28");
|
|
|
|
return res;
|
|
|
|
}
|
2014-03-07 18:03:54 +08:00
|
|
|
#endif // defined(__x86_64__) && SANITIZER_LINUX
|
2014-01-23 19:34:41 +08:00
|
|
|
|
|
|
|
#if SANITIZER_ANDROID
|
2015-05-07 02:55:31 +08:00
|
|
|
#if __ANDROID_API__ < 21
|
|
|
|
extern "C" __attribute__((weak)) int dl_iterate_phdr(
|
|
|
|
int (*)(struct dl_phdr_info *, size_t, void *), void *);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int dl_iterate_phdr_test_cb(struct dl_phdr_info *info, size_t size,
|
|
|
|
void *data) {
|
2015-06-30 04:28:55 +08:00
|
|
|
// Any name starting with "lib" indicates a bug in L where library base names
|
2015-05-07 02:55:31 +08:00
|
|
|
// are returned instead of paths.
|
|
|
|
if (info->dlpi_name && info->dlpi_name[0] == 'l' &&
|
|
|
|
info->dlpi_name[1] == 'i' && info->dlpi_name[2] == 'b') {
|
|
|
|
*(bool *)data = true;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static atomic_uint32_t android_api_level;
|
|
|
|
|
2015-06-30 04:28:55 +08:00
|
|
|
static AndroidApiLevel AndroidDetectApiLevel() {
|
2015-06-09 02:15:52 +08:00
|
|
|
if (!&dl_iterate_phdr)
|
2015-06-30 04:28:55 +08:00
|
|
|
return ANDROID_KITKAT; // K or lower
|
2015-05-07 02:55:31 +08:00
|
|
|
bool base_name_seen = false;
|
|
|
|
dl_iterate_phdr(dl_iterate_phdr_test_cb, &base_name_seen);
|
|
|
|
if (base_name_seen)
|
2015-06-30 04:28:55 +08:00
|
|
|
return ANDROID_LOLLIPOP_MR1; // L MR1
|
|
|
|
return ANDROID_POST_LOLLIPOP; // post-L
|
2015-05-07 02:55:31 +08:00
|
|
|
// Plain L (API level 21) is completely broken wrt ASan and not very
|
|
|
|
// interesting to detect.
|
|
|
|
}
|
|
|
|
|
2015-06-30 04:28:55 +08:00
|
|
|
AndroidApiLevel AndroidGetApiLevel() {
|
|
|
|
AndroidApiLevel level =
|
|
|
|
(AndroidApiLevel)atomic_load(&android_api_level, memory_order_relaxed);
|
2015-05-07 02:55:31 +08:00
|
|
|
if (level) return level;
|
|
|
|
level = AndroidDetectApiLevel();
|
|
|
|
atomic_store(&android_api_level, level, memory_order_relaxed);
|
|
|
|
return level;
|
|
|
|
}
|
|
|
|
|
2014-01-23 19:34:41 +08:00
|
|
|
#endif
|
|
|
|
|
2016-02-02 10:01:17 +08:00
|
|
|
bool IsHandledDeadlySignal(int signum) {
|
2015-05-06 05:38:50 +08:00
|
|
|
if (common_flags()->handle_abort && signum == SIGABRT)
|
|
|
|
return true;
|
2015-12-15 08:33:45 +08:00
|
|
|
if (common_flags()->handle_sigill && signum == SIGILL)
|
|
|
|
return true;
|
2015-08-07 01:52:54 +08:00
|
|
|
if (common_flags()->handle_sigfpe && signum == SIGFPE)
|
|
|
|
return true;
|
2015-01-12 21:46:37 +08:00
|
|
|
return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv;
|
2014-01-31 21:10:07 +08:00
|
|
|
}
|
|
|
|
|
2015-01-07 10:12:41 +08:00
|
|
|
#ifndef SANITIZER_GO
|
2014-12-17 03:13:01 +08:00
|
|
|
void *internal_start_thread(void(*func)(void *arg), void *arg) {
|
|
|
|
// Start the thread with signals blocked, otherwise it can steal user signals.
|
|
|
|
__sanitizer_sigset_t set, old;
|
|
|
|
internal_sigfillset(&set);
|
2015-06-27 07:39:23 +08:00
|
|
|
#if SANITIZER_LINUX && !SANITIZER_ANDROID
|
2015-04-23 17:33:27 +08:00
|
|
|
// Glibc uses SIGSETXID signal during setuid call. If this signal is blocked
|
|
|
|
// on any thread, setuid call hangs (see test/tsan/setuid.c).
|
|
|
|
internal_sigdelset(&set, 33);
|
2015-04-24 15:48:26 +08:00
|
|
|
#endif
|
2014-12-17 03:13:01 +08:00
|
|
|
internal_sigprocmask(SIG_SETMASK, &set, &old);
|
|
|
|
void *th;
|
2015-10-01 07:52:54 +08:00
|
|
|
real_pthread_create(&th, nullptr, (void*(*)(void *arg))func, arg);
|
|
|
|
internal_sigprocmask(SIG_SETMASK, &old, nullptr);
|
2014-12-17 03:13:01 +08:00
|
|
|
return th;
|
|
|
|
}
|
|
|
|
|
|
|
|
void internal_join_thread(void *th) {
|
2015-10-01 07:52:54 +08:00
|
|
|
real_pthread_join(th, nullptr);
|
2014-12-17 03:13:01 +08:00
|
|
|
}
|
2015-01-07 10:12:41 +08:00
|
|
|
#else
|
|
|
|
void *internal_start_thread(void (*func)(void *), void *arg) { return 0; }
|
|
|
|
|
|
|
|
void internal_join_thread(void *th) {}
|
|
|
|
#endif
|
2014-12-17 03:13:01 +08:00
|
|
|
|
2016-02-09 06:50:25 +08:00
|
|
|
#if defined(__aarch64__)
|
|
|
|
// Android headers in the older NDK releases miss this definition.
|
|
|
|
struct __sanitizer_esr_context {
|
|
|
|
struct _aarch64_ctx head;
|
|
|
|
uint64_t esr;
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) {
|
|
|
|
static const u32 kEsrMagic = 0x45535201;
|
|
|
|
u8 *aux = ucontext->uc_mcontext.__reserved;
|
|
|
|
while (true) {
|
|
|
|
_aarch64_ctx *ctx = (_aarch64_ctx *)aux;
|
|
|
|
if (ctx->size == 0) break;
|
|
|
|
if (ctx->magic == kEsrMagic) {
|
|
|
|
*esr = ((__sanitizer_esr_context *)ctx)->esr;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
aux += ctx->size;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
SignalContext::WriteFlag SignalContext::GetWriteFlag(void *context) {
|
|
|
|
ucontext_t *ucontext = (ucontext_t *)context;
|
2016-02-04 10:33:48 +08:00
|
|
|
#if defined(__x86_64__) || defined(__i386__)
|
2016-02-09 06:50:25 +08:00
|
|
|
static const uptr PF_WRITE = 1U << 1;
|
2016-02-08 01:40:45 +08:00
|
|
|
#if SANITIZER_FREEBSD
|
2016-02-09 06:50:25 +08:00
|
|
|
uptr err = ucontext->uc_mcontext.mc_err;
|
2016-02-08 01:40:45 +08:00
|
|
|
#else
|
2016-02-09 06:50:25 +08:00
|
|
|
uptr err = ucontext->uc_mcontext.gregs[REG_ERR];
|
2016-02-08 01:40:45 +08:00
|
|
|
#endif
|
2016-02-09 06:50:25 +08:00
|
|
|
return err & PF_WRITE ? WRITE : READ;
|
|
|
|
#elif defined(__arm__)
|
|
|
|
static const uptr FSR_WRITE = 1U << 11;
|
|
|
|
uptr fsr = ucontext->uc_mcontext.error_code;
|
|
|
|
return fsr & FSR_WRITE ? WRITE : READ;
|
|
|
|
#elif defined(__aarch64__)
|
|
|
|
static const u64 ESR_ELx_WNR = 1U << 6;
|
|
|
|
u64 esr;
|
|
|
|
if (!Aarch64GetESR(ucontext, &esr)) return UNKNOWN;
|
|
|
|
return esr & ESR_ELx_WNR ? WRITE : READ;
|
2016-02-04 10:33:48 +08:00
|
|
|
#else
|
2016-02-09 08:28:57 +08:00
|
|
|
(void)ucontext;
|
2016-02-09 06:50:25 +08:00
|
|
|
return UNKNOWN; // FIXME: Implement.
|
2016-02-04 10:33:48 +08:00
|
|
|
#endif
|
2016-02-04 10:02:09 +08:00
|
|
|
}
|
|
|
|
|
2015-03-03 01:36:02 +08:00
|
|
|
void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
|
|
|
|
#if defined(__arm__)
|
|
|
|
ucontext_t *ucontext = (ucontext_t*)context;
|
|
|
|
*pc = ucontext->uc_mcontext.arm_pc;
|
|
|
|
*bp = ucontext->uc_mcontext.arm_fp;
|
|
|
|
*sp = ucontext->uc_mcontext.arm_sp;
|
|
|
|
#elif defined(__aarch64__)
|
|
|
|
ucontext_t *ucontext = (ucontext_t*)context;
|
|
|
|
*pc = ucontext->uc_mcontext.pc;
|
|
|
|
*bp = ucontext->uc_mcontext.regs[29];
|
|
|
|
*sp = ucontext->uc_mcontext.sp;
|
|
|
|
#elif defined(__hppa__)
|
|
|
|
ucontext_t *ucontext = (ucontext_t*)context;
|
|
|
|
*pc = ucontext->uc_mcontext.sc_iaoq[0];
|
|
|
|
/* GCC uses %r3 whenever a frame pointer is needed. */
|
|
|
|
*bp = ucontext->uc_mcontext.sc_gr[3];
|
|
|
|
*sp = ucontext->uc_mcontext.sc_gr[30];
|
|
|
|
#elif defined(__x86_64__)
|
|
|
|
# if SANITIZER_FREEBSD
|
|
|
|
ucontext_t *ucontext = (ucontext_t*)context;
|
|
|
|
*pc = ucontext->uc_mcontext.mc_rip;
|
|
|
|
*bp = ucontext->uc_mcontext.mc_rbp;
|
|
|
|
*sp = ucontext->uc_mcontext.mc_rsp;
|
|
|
|
# else
|
|
|
|
ucontext_t *ucontext = (ucontext_t*)context;
|
|
|
|
*pc = ucontext->uc_mcontext.gregs[REG_RIP];
|
|
|
|
*bp = ucontext->uc_mcontext.gregs[REG_RBP];
|
|
|
|
*sp = ucontext->uc_mcontext.gregs[REG_RSP];
|
|
|
|
# endif
|
|
|
|
#elif defined(__i386__)
|
|
|
|
# if SANITIZER_FREEBSD
|
|
|
|
ucontext_t *ucontext = (ucontext_t*)context;
|
|
|
|
*pc = ucontext->uc_mcontext.mc_eip;
|
|
|
|
*bp = ucontext->uc_mcontext.mc_ebp;
|
|
|
|
*sp = ucontext->uc_mcontext.mc_esp;
|
|
|
|
# else
|
|
|
|
ucontext_t *ucontext = (ucontext_t*)context;
|
|
|
|
*pc = ucontext->uc_mcontext.gregs[REG_EIP];
|
|
|
|
*bp = ucontext->uc_mcontext.gregs[REG_EBP];
|
|
|
|
*sp = ucontext->uc_mcontext.gregs[REG_ESP];
|
|
|
|
# endif
|
|
|
|
#elif defined(__powerpc__) || defined(__powerpc64__)
|
|
|
|
ucontext_t *ucontext = (ucontext_t*)context;
|
|
|
|
*pc = ucontext->uc_mcontext.regs->nip;
|
|
|
|
*sp = ucontext->uc_mcontext.regs->gpr[PT_R1];
|
|
|
|
// The powerpc{,64}-linux ABIs do not specify r31 as the frame
|
|
|
|
// pointer, but GCC always uses r31 when we need a frame pointer.
|
|
|
|
*bp = ucontext->uc_mcontext.regs->gpr[PT_R31];
|
|
|
|
#elif defined(__sparc__)
|
|
|
|
ucontext_t *ucontext = (ucontext_t*)context;
|
|
|
|
uptr *stk_ptr;
|
|
|
|
# if defined (__arch64__)
|
|
|
|
*pc = ucontext->uc_mcontext.mc_gregs[MC_PC];
|
|
|
|
*sp = ucontext->uc_mcontext.mc_gregs[MC_O6];
|
|
|
|
stk_ptr = (uptr *) (*sp + 2047);
|
|
|
|
*bp = stk_ptr[15];
|
|
|
|
# else
|
|
|
|
*pc = ucontext->uc_mcontext.gregs[REG_PC];
|
|
|
|
*sp = ucontext->uc_mcontext.gregs[REG_O6];
|
|
|
|
stk_ptr = (uptr *) *sp;
|
|
|
|
*bp = stk_ptr[15];
|
|
|
|
# endif
|
|
|
|
#elif defined(__mips__)
|
|
|
|
ucontext_t *ucontext = (ucontext_t*)context;
|
2015-05-06 14:53:09 +08:00
|
|
|
*pc = ucontext->uc_mcontext.pc;
|
2015-03-03 01:36:02 +08:00
|
|
|
*bp = ucontext->uc_mcontext.gregs[30];
|
|
|
|
*sp = ucontext->uc_mcontext.gregs[29];
|
2016-04-15 05:17:19 +08:00
|
|
|
#elif defined(__s390__)
|
|
|
|
ucontext_t *ucontext = (ucontext_t*)context;
|
|
|
|
# if defined(__s390x__)
|
|
|
|
*pc = ucontext->uc_mcontext.psw.addr;
|
|
|
|
# else
|
|
|
|
*pc = ucontext->uc_mcontext.psw.addr & 0x7fffffff;
|
|
|
|
# endif
|
|
|
|
*bp = ucontext->uc_mcontext.gregs[11];
|
|
|
|
*sp = ucontext->uc_mcontext.gregs[15];
|
2015-03-03 01:36:02 +08:00
|
|
|
#else
|
|
|
|
# error "Unsupported arch"
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-12-03 18:39:43 +08:00
|
|
|
void MaybeReexec() {
|
|
|
|
// No need to re-exec on Linux.
|
|
|
|
}
|
|
|
|
|
2015-10-01 07:52:54 +08:00
|
|
|
} // namespace __sanitizer
|
2012-06-04 22:27:50 +08:00
|
|
|
|
2015-10-01 07:52:54 +08:00
|
|
|
#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
|