2019-07-31 18:51:27 +00:00
|
|
|
//===-- sanitizer_linux.cpp -----------------------------------------------===//
|
2012-06-04 14:27:50 +00:00
|
|
|
//
|
2019-01-19 08:50:56 +00: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
|
2012-06-04 14:27:50 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file is shared between AddressSanitizer and ThreadSanitizer
|
|
|
|
// run-time libraries and implements linux-specific functions from
|
|
|
|
// sanitizer_libc.h.
|
|
|
|
//===----------------------------------------------------------------------===//
|
2013-03-19 14:33:38 +00:00
|
|
|
|
|
|
|
#include "sanitizer_platform.h"
|
2015-09-30 23:52:54 +00:00
|
|
|
|
[sanitizer] Split Symbolizer/StackTraces from core RTSanitizerCommon
Summary:
Host symbolizer & stacktraces related code in their own RT:
`RTSanitizerCommonSymbolizer`, which is "libcdep" by nature. Symbolizer &
stacktraces specific code that used to live in common files is moved to a new
file `sanitizer_symbolizer_report.cc` as is.
The purpose of this is the enforce a separation between code that relies on
symbolization and code that doesn't. This saves the inclusion of spurious code
due to the interface functions with default visibility, and the extra data
associated.
The following sanitizers makefiles were modified & tested locally:
- dfsan: doesn't require the new symbolizer RT
- esan: requires it
- hwasan: requires it
- lsan: requires it
- msan: requires it
- safestack: doesn't require it
- xray: doesn't require it
- tsan: requires it
- ubsan: requires it
- ubsan_minimal: doesn't require it
- scudo: requires it (but not for Fuchsia that has a minimal runtime)
This was tested locally on Linux, Android, Fuchsia.
Reviewers: alekseyshl, eugenis, dberris, kubamracek, vitalybuka, dvyukov, mcgrathr
Reviewed By: alekseyshl, vitalybuka
Subscribers: srhines, kubamracek, mgorny, krytarowski, delcypher, llvm-commits, #sanitizers
Differential Revision: https://reviews.llvm.org/D45457
llvm-svn: 330131
2018-04-16 16:32:19 +00:00
|
|
|
#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
|
2025-04-11 16:21:00 -04:00
|
|
|
SANITIZER_SOLARIS || SANITIZER_HAIKU
|
2012-06-04 14:27:50 +00:00
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# include "sanitizer_common.h"
|
|
|
|
# include "sanitizer_flags.h"
|
|
|
|
# include "sanitizer_getauxval.h"
|
|
|
|
# include "sanitizer_internal_defs.h"
|
|
|
|
# include "sanitizer_libc.h"
|
|
|
|
# include "sanitizer_linux.h"
|
|
|
|
# include "sanitizer_mutex.h"
|
|
|
|
# include "sanitizer_placement_new.h"
|
|
|
|
# include "sanitizer_procmaps.h"
|
|
|
|
|
|
|
|
# if SANITIZER_LINUX && !SANITIZER_GO
|
|
|
|
# include <asm/param.h>
|
|
|
|
# endif
|
2014-03-07 10:03:54 +00:00
|
|
|
|
2014-12-16 07:11:08 +00: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
|
2024-07-30 09:03:00 +02:00
|
|
|
// sys/stat.h, we use this trick. sparc64 is similar, using
|
|
|
|
// syscall(__NR_stat64) and struct kernel_stat64.
|
2024-07-30 10:06:45 +02:00
|
|
|
# if SANITIZER_LINUX && (SANITIZER_MIPS64 || SANITIZER_SPARC64)
|
2023-11-27 23:17:03 +01:00
|
|
|
# include <asm/unistd.h>
|
|
|
|
# include <sys/types.h>
|
|
|
|
# define stat kernel_stat
|
2024-07-30 09:03:00 +02:00
|
|
|
# if SANITIZER_SPARC64
|
|
|
|
# define stat64 kernel_stat64
|
|
|
|
# endif
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_GO
|
|
|
|
# undef st_atime
|
|
|
|
# undef st_mtime
|
|
|
|
# undef st_ctime
|
|
|
|
# define st_atime st_atim
|
|
|
|
# define st_mtime st_mtim
|
|
|
|
# define st_ctime st_ctim
|
|
|
|
# endif
|
|
|
|
# include <asm/stat.h>
|
|
|
|
# undef stat
|
2024-07-30 09:03:00 +02:00
|
|
|
# undef stat64
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2014-12-16 07:11:08 +00:00
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# include <dlfcn.h>
|
|
|
|
# include <errno.h>
|
|
|
|
# include <fcntl.h>
|
|
|
|
# include <link.h>
|
|
|
|
# include <pthread.h>
|
|
|
|
# include <sched.h>
|
|
|
|
# include <signal.h>
|
|
|
|
# include <sys/mman.h>
|
2025-04-11 16:21:00 -04:00
|
|
|
# if !SANITIZER_SOLARIS && !SANITIZER_HAIKU
|
2023-11-27 23:17:03 +01:00
|
|
|
# include <sys/ptrace.h>
|
|
|
|
# endif
|
|
|
|
# include <sys/resource.h>
|
|
|
|
# include <sys/stat.h>
|
2025-04-11 16:21:00 -04:00
|
|
|
# if !SANITIZER_HAIKU
|
|
|
|
# include <sys/syscall.h>
|
|
|
|
# include <ucontext.h>
|
|
|
|
# endif
|
2023-11-27 23:17:03 +01:00
|
|
|
# include <sys/time.h>
|
|
|
|
# include <sys/types.h>
|
|
|
|
# include <unistd.h>
|
2017-07-06 17:45:01 +00:00
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_LINUX
|
|
|
|
# include <sys/utsname.h>
|
|
|
|
# endif
|
2017-07-06 17:45:01 +00:00
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_LINUX && !SANITIZER_ANDROID
|
|
|
|
# include <sys/personality.h>
|
|
|
|
# endif
|
|
|
|
|
2025-02-07 00:40:22 +07:00
|
|
|
# if SANITIZER_ANDROID && __ANDROID_API__ < 35
|
|
|
|
// The weak `strerrorname_np` (introduced in API level 35) definition,
|
|
|
|
// allows for checking the API level at runtime.
|
|
|
|
extern "C" SANITIZER_WEAK_ATTRIBUTE const char *strerrorname_np(int);
|
|
|
|
# endif
|
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_LINUX && defined(__loongarch__)
|
|
|
|
# include <sys/sysmacros.h>
|
|
|
|
# endif
|
2022-07-20 00:58:40 -07:00
|
|
|
|
2025-04-11 06:23:26 +09:00
|
|
|
# if SANITIZER_LINUX && defined(__powerpc64__)
|
|
|
|
# include <asm/ptrace.h>
|
|
|
|
# endif
|
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_FREEBSD
|
|
|
|
# include <machine/atomic.h>
|
|
|
|
# include <sys/exec.h>
|
|
|
|
# include <sys/procctl.h>
|
|
|
|
# include <sys/sysctl.h>
|
2014-03-07 10:03:54 +00:00
|
|
|
extern "C" {
|
|
|
|
// <sys/umtx.h> must be included after <errno.h> and <sys/types.h> on
|
|
|
|
// FreeBSD 9.2 and 10.0.
|
2023-11-27 23:17:03 +01:00
|
|
|
# include <sys/umtx.h>
|
2014-03-07 10:03:54 +00:00
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# include <sys/thr.h>
|
|
|
|
# endif // SANITIZER_FREEBSD
|
2014-03-07 10:03:54 +00:00
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_NETBSD
|
|
|
|
# include <limits.h> // For NAME_MAX
|
|
|
|
# include <sys/exec.h>
|
|
|
|
# include <sys/sysctl.h>
|
2017-10-25 17:09:05 +00:00
|
|
|
extern struct ps_strings *__ps_strings;
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif // SANITIZER_NETBSD
|
2017-08-08 20:36:10 +00:00
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_SOLARIS
|
2024-09-24 09:33:17 +02:00
|
|
|
# include <stddef.h>
|
2023-11-27 23:17:03 +01:00
|
|
|
# include <stdlib.h>
|
2024-09-24 09:33:17 +02:00
|
|
|
# include <sys/frame.h>
|
2023-11-27 23:17:03 +01:00
|
|
|
# include <thread.h>
|
|
|
|
# define environ _environ
|
|
|
|
# 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-14 20:14:29 +00:00
|
|
|
|
2025-04-11 16:21:00 -04:00
|
|
|
# if SANITIZER_HAIKU
|
|
|
|
# include <OS.h>
|
|
|
|
# include <elf.h>
|
|
|
|
# include <image.h>
|
|
|
|
extern "C" char **__libc_argv;
|
|
|
|
# endif
|
|
|
|
|
2018-03-21 07:50:02 +00:00
|
|
|
extern char **environ;
|
2018-03-19 20:44:06 +00:00
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_LINUX
|
2013-03-21 06:24:31 +00:00
|
|
|
// <linux/time.h>
|
|
|
|
struct kernel_timeval {
|
|
|
|
long tv_sec;
|
|
|
|
long tv_usec;
|
|
|
|
};
|
|
|
|
|
2013-01-30 14:39:27 +00:00
|
|
|
// <linux/futex.h> is broken on some linux distributions.
|
|
|
|
const int FUTEX_WAIT = 0;
|
|
|
|
const int FUTEX_WAKE = 1;
|
2018-08-20 14:57:58 +00:00
|
|
|
const int FUTEX_PRIVATE_FLAG = 128;
|
|
|
|
const int FUTEX_WAIT_PRIVATE = FUTEX_WAIT | FUTEX_PRIVATE_FLAG;
|
|
|
|
const int FUTEX_WAKE_PRIVATE = FUTEX_WAKE | FUTEX_PRIVATE_FLAG;
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif // SANITIZER_LINUX
|
2012-06-04 14:27:50 +00:00
|
|
|
|
2014-03-07 10:03:54 +00:00
|
|
|
// Are we using 32-bit or 64-bit Linux syscalls?
|
2012-11-21 12:38:58 +00:00
|
|
|
// x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32
|
2012-11-20 08:57:26 +00:00
|
|
|
// but it still needs to use 64-bit syscalls.
|
2025-01-27 22:49:44 +01:00
|
|
|
# if SANITIZER_LINUX && \
|
|
|
|
(defined(__x86_64__) || defined(__powerpc64__) || \
|
|
|
|
SANITIZER_WORDSIZE == 64 || \
|
|
|
|
(defined(__mips__) && defined(_ABIN32) && _MIPS_SIM == _ABIN32))
|
2023-11-27 23:17:03 +01:00
|
|
|
# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1
|
|
|
|
# else
|
|
|
|
# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0
|
|
|
|
# endif
|
2012-11-19 07:53:36 +00:00
|
|
|
|
2023-12-29 05:10:13 -05:00
|
|
|
// Note : FreeBSD implemented both Linux and OpenBSD apis.
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_LINUX && defined(__NR_getrandom)
|
|
|
|
# if !defined(GRND_NONBLOCK)
|
|
|
|
# define GRND_NONBLOCK 1
|
|
|
|
# endif
|
|
|
|
# define SANITIZER_USE_GETRANDOM 1
|
|
|
|
# else
|
|
|
|
# define SANITIZER_USE_GETRANDOM 0
|
|
|
|
# endif // SANITIZER_LINUX && defined(__NR_getrandom)
|
|
|
|
|
2023-12-29 05:10:13 -05:00
|
|
|
# if SANITIZER_FREEBSD
|
2023-11-27 23:17:03 +01:00
|
|
|
# define SANITIZER_USE_GETENTROPY 1
|
2024-08-02 14:52:31 -07:00
|
|
|
extern "C" void *__sys_mmap(void *addr, size_t len, int prot, int flags, int fd,
|
|
|
|
off_t offset);
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2018-04-09 22:46:40 +00:00
|
|
|
|
2012-06-04 14:27:50 +00:00
|
|
|
namespace __sanitizer {
|
|
|
|
|
2023-09-26 21:10:10 -07:00
|
|
|
void SetSigProcMask(__sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) {
|
|
|
|
CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, set, oldset));
|
|
|
|
}
|
|
|
|
|
2024-11-14 10:35:35 -08:00
|
|
|
# if SANITIZER_LINUX
|
|
|
|
// Deletes the specified signal from newset, if it is not present in oldset
|
|
|
|
// Equivalently: newset[signum] = newset[signum] & oldset[signum]
|
|
|
|
static void KeepUnblocked(__sanitizer_sigset_t &newset,
|
|
|
|
__sanitizer_sigset_t &oldset, int signum) {
|
|
|
|
// FIXME: https://github.com/google/sanitizers/issues/1816
|
|
|
|
if (SANITIZER_ANDROID || !internal_sigismember(&oldset, signum))
|
|
|
|
internal_sigdelset(&newset, signum);
|
|
|
|
}
|
|
|
|
# endif
|
|
|
|
|
2024-07-10 13:02:41 -07:00
|
|
|
// Block asynchronous signals
|
2023-09-26 21:10:10 -07:00
|
|
|
void BlockSignals(__sanitizer_sigset_t *oldset) {
|
2024-11-14 10:35:35 -08:00
|
|
|
__sanitizer_sigset_t newset;
|
|
|
|
internal_sigfillset(&newset);
|
|
|
|
|
|
|
|
# if SANITIZER_LINUX
|
|
|
|
__sanitizer_sigset_t currentset;
|
|
|
|
|
|
|
|
# if !SANITIZER_ANDROID
|
|
|
|
// FIXME: https://github.com/google/sanitizers/issues/1816
|
|
|
|
SetSigProcMask(NULL, ¤tset);
|
|
|
|
|
2023-09-26 21:10:10 -07:00
|
|
|
// Glibc uses SIGSETXID signal during setuid call. If this signal is blocked
|
|
|
|
// on any thread, setuid call hangs.
|
|
|
|
// See test/sanitizer_common/TestCases/Linux/setuid.c.
|
2024-11-14 10:35:35 -08:00
|
|
|
KeepUnblocked(newset, currentset, 33);
|
|
|
|
# endif // !SANITIZER_ANDROID
|
|
|
|
|
2023-09-26 21:10:10 -07:00
|
|
|
// Seccomp-BPF-sandboxed processes rely on SIGSYS to handle trapped syscalls.
|
|
|
|
// If this signal is blocked, such calls cannot be handled and the process may
|
|
|
|
// hang.
|
2024-11-14 10:35:35 -08:00
|
|
|
KeepUnblocked(newset, currentset, 31);
|
2024-07-10 13:02:41 -07:00
|
|
|
|
2024-11-14 10:35:35 -08:00
|
|
|
# if !SANITIZER_ANDROID
|
2024-07-10 13:02:41 -07:00
|
|
|
// Don't block synchronous signals
|
2024-11-14 10:35:35 -08:00
|
|
|
// but also don't unblock signals that the user had deliberately blocked.
|
|
|
|
// FIXME: https://github.com/google/sanitizers/issues/1816
|
|
|
|
KeepUnblocked(newset, currentset, SIGSEGV);
|
|
|
|
KeepUnblocked(newset, currentset, SIGBUS);
|
|
|
|
KeepUnblocked(newset, currentset, SIGILL);
|
|
|
|
KeepUnblocked(newset, currentset, SIGTRAP);
|
|
|
|
KeepUnblocked(newset, currentset, SIGABRT);
|
|
|
|
KeepUnblocked(newset, currentset, SIGFPE);
|
|
|
|
KeepUnblocked(newset, currentset, SIGPIPE);
|
|
|
|
# endif //! SANITIZER_ANDROID
|
|
|
|
|
|
|
|
# endif // SANITIZER_LINUX
|
2024-07-10 13:02:41 -07:00
|
|
|
|
2024-11-14 10:35:35 -08:00
|
|
|
SetSigProcMask(&newset, oldset);
|
2023-09-26 21:10:10 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
ScopedBlockSignals::ScopedBlockSignals(__sanitizer_sigset_t *copy) {
|
|
|
|
BlockSignals(&saved_);
|
|
|
|
if (copy)
|
|
|
|
internal_memcpy(copy, &saved_, sizeof(saved_));
|
|
|
|
}
|
|
|
|
|
|
|
|
ScopedBlockSignals::~ScopedBlockSignals() { SetSigProcMask(&saved_, nullptr); }
|
|
|
|
|
2021-11-11 23:32:58 -08:00
|
|
|
# if SANITIZER_LINUX && defined(__x86_64__)
|
|
|
|
# include "sanitizer_syscall_linux_x86_64.inc"
|
|
|
|
# elif SANITIZER_LINUX && SANITIZER_RISCV64
|
|
|
|
# include "sanitizer_syscall_linux_riscv64.inc"
|
|
|
|
# elif SANITIZER_LINUX && defined(__aarch64__)
|
|
|
|
# include "sanitizer_syscall_linux_aarch64.inc"
|
|
|
|
# elif SANITIZER_LINUX && defined(__arm__)
|
|
|
|
# include "sanitizer_syscall_linux_arm.inc"
|
2021-08-17 14:38:38 -07:00
|
|
|
# elif SANITIZER_LINUX && defined(__hexagon__)
|
|
|
|
# include "sanitizer_syscall_linux_hexagon.inc"
|
2022-07-20 00:58:40 -07:00
|
|
|
# elif SANITIZER_LINUX && SANITIZER_LOONGARCH64
|
|
|
|
# include "sanitizer_syscall_linux_loongarch64.inc"
|
2021-08-17 14:38:38 -07:00
|
|
|
# else
|
|
|
|
# include "sanitizer_syscall_generic.inc"
|
|
|
|
# endif
|
2013-05-08 14:43:49 +00:00
|
|
|
|
2012-06-07 07:13:46 +00:00
|
|
|
// --------------- sanitizer_libc.h
|
2025-04-11 16:21:00 -04:00
|
|
|
# if !SANITIZER_SOLARIS && !SANITIZER_NETBSD && !SANITIZER_HAIKU
|
2023-11-27 23:17:03 +01:00
|
|
|
# if !SANITIZER_S390
|
2014-12-24 12:58:09 +00:00
|
|
|
uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
|
2020-01-10 13:18:55 -08:00
|
|
|
u64 offset) {
|
2024-08-02 14:52:31 -07:00
|
|
|
# if SANITIZER_FREEBSD
|
|
|
|
return (uptr)__sys_mmap(addr, length, prot, flags, fd, offset);
|
|
|
|
# elif SANITIZER_LINUX_USES_64BIT_SYSCALLS
|
2014-03-07 10:03:54 +00:00
|
|
|
return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd,
|
2013-11-06 17:47:39 +00:00
|
|
|
offset);
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2014-12-24 12:58:09 +00:00
|
|
|
// mmap2 specifies file offset in 4096-byte units.
|
|
|
|
CHECK(IsAligned(offset, 4096));
|
2014-03-07 10:03:54 +00:00
|
|
|
return internal_syscall(SYSCALL(mmap2), addr, length, prot, flags, fd,
|
2024-07-30 09:02:05 +02:00
|
|
|
(OFF_T)(offset / 4096));
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2012-06-04 14:27:50 +00:00
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif // !SANITIZER_S390
|
2012-06-04 14:27:50 +00:00
|
|
|
|
2013-05-08 14:43:49 +00:00
|
|
|
uptr internal_munmap(void *addr, uptr length) {
|
2018-10-08 18:04:46 +00:00
|
|
|
return internal_syscall(SYSCALL(munmap), (uptr)addr, length);
|
2012-06-05 09:49:25 +00:00
|
|
|
}
|
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_LINUX
|
2021-03-23 11:21:08 -07:00
|
|
|
uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
|
|
|
|
void *new_address) {
|
|
|
|
return internal_syscall(SYSCALL(mremap), (uptr)old_address, old_size,
|
|
|
|
new_size, flags, (uptr)new_address);
|
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2021-03-23 11:21:08 -07:00
|
|
|
|
2015-04-10 15:02:19 +00:00
|
|
|
int internal_mprotect(void *addr, uptr length, int prot) {
|
2018-10-08 18:04:46 +00:00
|
|
|
return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot);
|
2015-04-10 15:02:19 +00:00
|
|
|
}
|
2020-08-12 19:32:15 -07:00
|
|
|
|
|
|
|
int internal_madvise(uptr addr, uptr length, int advice) {
|
|
|
|
return internal_syscall(SYSCALL(madvise), addr, length, advice);
|
|
|
|
}
|
2015-04-10 15:02:19 +00:00
|
|
|
|
2024-10-31 21:20:46 -05:00
|
|
|
# if SANITIZER_FREEBSD
|
|
|
|
uptr internal_close_range(fd_t lowfd, fd_t highfd, int flags) {
|
|
|
|
return internal_syscall(SYSCALL(close_range), lowfd, highfd, flags);
|
|
|
|
}
|
|
|
|
# endif
|
2023-11-27 23:17:03 +01:00
|
|
|
uptr internal_close(fd_t fd) { return internal_syscall(SYSCALL(close), fd); }
|
2012-06-05 08:32:53 +00:00
|
|
|
|
2013-05-08 14:43:49 +00:00
|
|
|
uptr internal_open(const char *filename, int flags) {
|
2022-04-21 15:17:29 -07:00
|
|
|
# if SANITIZER_LINUX
|
2014-03-07 10:03:54 +00:00
|
|
|
return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags);
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2018-10-08 18:04:46 +00:00
|
|
|
return internal_syscall(SYSCALL(open), (uptr)filename, flags);
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2013-02-01 15:58:46 +00:00
|
|
|
}
|
|
|
|
|
2013-05-08 14:43:49 +00:00
|
|
|
uptr internal_open(const char *filename, int flags, u32 mode) {
|
2022-04-21 15:17:29 -07:00
|
|
|
# if SANITIZER_LINUX
|
2014-03-07 10:03:54 +00:00
|
|
|
return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags,
|
|
|
|
mode);
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2018-10-08 18:04:46 +00:00
|
|
|
return internal_syscall(SYSCALL(open), (uptr)filename, flags, mode);
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2013-02-01 15:58:46 +00:00
|
|
|
}
|
|
|
|
|
2012-06-05 08:32:53 +00:00
|
|
|
uptr internal_read(fd_t fd, void *buf, uptr count) {
|
2012-10-02 13:41:40 +00:00
|
|
|
sptr res;
|
2018-10-08 18:04:46 +00:00
|
|
|
HANDLE_EINTR(res,
|
|
|
|
(sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf, count));
|
2012-10-02 13:41:40 +00:00
|
|
|
return res;
|
2012-06-05 08:32:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uptr internal_write(fd_t fd, const void *buf, uptr count) {
|
2012-10-02 13:41:40 +00:00
|
|
|
sptr res;
|
2018-10-08 18:04:46 +00:00
|
|
|
HANDLE_EINTR(res,
|
|
|
|
(sptr)internal_syscall(SYSCALL(write), fd, (uptr)buf, count));
|
2012-10-02 13:41:40 +00:00
|
|
|
return res;
|
2012-06-05 08:32:53 +00:00
|
|
|
}
|
|
|
|
|
2014-05-27 12:37:52 +00:00
|
|
|
uptr internal_ftruncate(fd_t fd, uptr size) {
|
|
|
|
sptr res;
|
2023-11-27 23:17:03 +01:00
|
|
|
HANDLE_EINTR(res,
|
|
|
|
(sptr)internal_syscall(SYSCALL(ftruncate), fd, (OFF_T)size));
|
2014-05-27 12:37:52 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2024-07-30 09:03:00 +02:00
|
|
|
# if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX
|
2013-05-07 12:47:04 +00: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;
|
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2013-05-07 12:47:04 +00:00
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_LINUX && defined(__loongarch__)
|
2022-07-20 00:58:40 -07:00
|
|
|
static void statx_to_stat(struct statx *in, struct stat *out) {
|
|
|
|
internal_memset(out, 0, sizeof(*out));
|
|
|
|
out->st_dev = makedev(in->stx_dev_major, in->stx_dev_minor);
|
|
|
|
out->st_ino = in->stx_ino;
|
|
|
|
out->st_mode = in->stx_mode;
|
|
|
|
out->st_nlink = in->stx_nlink;
|
|
|
|
out->st_uid = in->stx_uid;
|
|
|
|
out->st_gid = in->stx_gid;
|
|
|
|
out->st_rdev = makedev(in->stx_rdev_major, in->stx_rdev_minor);
|
|
|
|
out->st_size = in->stx_size;
|
|
|
|
out->st_blksize = in->stx_blksize;
|
|
|
|
out->st_blocks = in->stx_blocks;
|
|
|
|
out->st_atime = in->stx_atime.tv_sec;
|
|
|
|
out->st_atim.tv_nsec = in->stx_atime.tv_nsec;
|
|
|
|
out->st_mtime = in->stx_mtime.tv_sec;
|
|
|
|
out->st_mtim.tv_nsec = in->stx_mtime.tv_nsec;
|
|
|
|
out->st_ctime = in->stx_ctime.tv_sec;
|
|
|
|
out->st_ctim.tv_nsec = in->stx_ctime.tv_nsec;
|
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2022-07-20 00:58:40 -07:00
|
|
|
|
2024-07-30 09:03:00 +02:00
|
|
|
# if SANITIZER_MIPS64 || SANITIZER_SPARC64
|
|
|
|
# if SANITIZER_MIPS64
|
|
|
|
typedef struct kernel_stat kstat_t;
|
|
|
|
# else
|
|
|
|
typedef struct kernel_stat64 kstat_t;
|
|
|
|
# endif
|
2017-09-15 15:18:51 +00:00
|
|
|
// Undefine compatibility macros from <sys/stat.h>
|
|
|
|
// so that they would not clash with the kernel_stat
|
|
|
|
// st_[a|m|c]time fields
|
2023-11-27 23:17:03 +01:00
|
|
|
# if !SANITIZER_GO
|
|
|
|
# undef st_atime
|
|
|
|
# undef st_mtime
|
|
|
|
# undef st_ctime
|
|
|
|
# endif
|
|
|
|
# if defined(SANITIZER_ANDROID)
|
2017-09-15 15:18:51 +00:00
|
|
|
// Bionic sys/stat.h defines additional macros
|
|
|
|
// for compatibility with the old NDKs and
|
|
|
|
// they clash with the kernel_stat structure
|
|
|
|
// st_[a|m|c]time_nsec fields.
|
2023-11-27 23:17:03 +01:00
|
|
|
# undef st_atime_nsec
|
|
|
|
# undef st_mtime_nsec
|
|
|
|
# undef st_ctime_nsec
|
|
|
|
# endif
|
2024-07-30 09:03:00 +02:00
|
|
|
static void kernel_stat_to_stat(kstat_t *in, struct stat *out) {
|
2014-12-16 07:11:08 +00:00
|
|
|
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;
|
2023-11-27 23:17:03 +01:00
|
|
|
# if defined(__USE_MISC) || defined(__USE_XOPEN2K8) || \
|
|
|
|
defined(SANITIZER_ANDROID)
|
2017-09-15 15:18:51 +00:00
|
|
|
out->st_atim.tv_sec = in->st_atime;
|
|
|
|
out->st_atim.tv_nsec = in->st_atime_nsec;
|
|
|
|
out->st_mtim.tv_sec = in->st_mtime;
|
|
|
|
out->st_mtim.tv_nsec = in->st_mtime_nsec;
|
|
|
|
out->st_ctim.tv_sec = in->st_ctime;
|
|
|
|
out->st_ctim.tv_nsec = in->st_ctime_nsec;
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2017-09-15 15:18:51 +00:00
|
|
|
out->st_atime = in->st_atime;
|
|
|
|
out->st_atimensec = in->st_atime_nsec;
|
|
|
|
out->st_mtime = in->st_mtime;
|
|
|
|
out->st_mtimensec = in->st_mtime_nsec;
|
|
|
|
out->st_ctime = in->st_ctime;
|
|
|
|
out->st_atimensec = in->st_ctime_nsec;
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2014-12-16 07:11:08 +00:00
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2014-12-16 07:11:08 +00:00
|
|
|
|
2013-05-08 14:43:49 +00:00
|
|
|
uptr internal_stat(const char *path, void *buf) {
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_FREEBSD
|
2018-10-08 18:04:46 +00:00
|
|
|
return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, 0);
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif SANITIZER_LINUX
|
|
|
|
# if defined(__loongarch__)
|
2022-07-20 00:58:40 -07:00
|
|
|
struct statx bufx;
|
|
|
|
int res = internal_syscall(SYSCALL(statx), AT_FDCWD, (uptr)path,
|
|
|
|
AT_NO_AUTOMOUNT, STATX_BASIC_STATS, (uptr)&bufx);
|
|
|
|
statx_to_stat(&bufx, (struct stat *)buf);
|
|
|
|
return res;
|
2025-01-27 22:49:44 +01:00
|
|
|
# elif ( \
|
|
|
|
SANITIZER_WORDSIZE == 64 || SANITIZER_X32 || \
|
|
|
|
(defined(__mips__) && defined(_ABIN32) && _MIPS_SIM == _ABIN32)) && \
|
2023-11-27 23:17:03 +01:00
|
|
|
!SANITIZER_SPARC
|
2018-03-19 23:12:14 +00:00
|
|
|
return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf,
|
|
|
|
0);
|
2024-07-30 09:03:00 +02:00
|
|
|
# elif SANITIZER_SPARC64
|
|
|
|
kstat_t buf64;
|
|
|
|
int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
|
|
|
|
(uptr)&buf64, 0);
|
|
|
|
kernel_stat_to_stat(&buf64, (struct stat *)buf);
|
|
|
|
return res;
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2022-04-21 15:17:29 -07:00
|
|
|
struct stat64 buf64;
|
|
|
|
int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
|
|
|
|
(uptr)&buf64, 0);
|
|
|
|
stat64_to_stat(&buf64, (struct stat *)buf);
|
2014-12-16 07:11:08 +00:00
|
|
|
return res;
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
|
|
|
# else
|
2013-05-07 12:47:04 +00:00
|
|
|
struct stat64 buf64;
|
2014-03-07 10:03:54 +00:00
|
|
|
int res = internal_syscall(SYSCALL(stat64), path, &buf64);
|
2013-05-07 12:47:04 +00:00
|
|
|
stat64_to_stat(&buf64, (struct stat *)buf);
|
|
|
|
return res;
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2013-02-04 10:16:50 +00:00
|
|
|
}
|
|
|
|
|
2013-05-08 14:43:49 +00:00
|
|
|
uptr internal_lstat(const char *path, void *buf) {
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_FREEBSD
|
2018-03-19 23:12:14 +00:00
|
|
|
return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf,
|
|
|
|
AT_SYMLINK_NOFOLLOW);
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif SANITIZER_LINUX
|
|
|
|
# if defined(__loongarch__)
|
2022-07-20 00:58:40 -07:00
|
|
|
struct statx bufx;
|
|
|
|
int res = internal_syscall(SYSCALL(statx), AT_FDCWD, (uptr)path,
|
|
|
|
AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT,
|
|
|
|
STATX_BASIC_STATS, (uptr)&bufx);
|
|
|
|
statx_to_stat(&bufx, (struct stat *)buf);
|
|
|
|
return res;
|
2025-01-27 22:49:44 +01:00
|
|
|
# elif ( \
|
|
|
|
defined(_LP64) || SANITIZER_X32 || \
|
|
|
|
(defined(__mips__) && defined(_ABIN32) && _MIPS_SIM == _ABIN32)) && \
|
2023-11-27 23:17:03 +01:00
|
|
|
!SANITIZER_SPARC
|
2018-03-19 23:12:14 +00:00
|
|
|
return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf,
|
|
|
|
AT_SYMLINK_NOFOLLOW);
|
2024-07-30 09:03:00 +02:00
|
|
|
# elif SANITIZER_SPARC64
|
|
|
|
kstat_t buf64;
|
|
|
|
int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
|
|
|
|
(uptr)&buf64, AT_SYMLINK_NOFOLLOW);
|
|
|
|
kernel_stat_to_stat(&buf64, (struct stat *)buf);
|
|
|
|
return res;
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2022-04-21 15:17:29 -07:00
|
|
|
struct stat64 buf64;
|
|
|
|
int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
|
|
|
|
(uptr)&buf64, AT_SYMLINK_NOFOLLOW);
|
|
|
|
stat64_to_stat(&buf64, (struct stat *)buf);
|
2016-03-11 10:51:03 +00:00
|
|
|
return res;
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
|
|
|
# else
|
2013-05-07 12:47:04 +00:00
|
|
|
struct stat64 buf64;
|
2014-03-07 10:03:54 +00:00
|
|
|
int res = internal_syscall(SYSCALL(lstat64), path, &buf64);
|
2013-05-07 12:47:04 +00:00
|
|
|
stat64_to_stat(&buf64, (struct stat *)buf);
|
|
|
|
return res;
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2013-02-04 10:16:50 +00:00
|
|
|
}
|
|
|
|
|
2013-05-08 14:43:49 +00:00
|
|
|
uptr internal_fstat(fd_t fd, void *buf) {
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
|
|
|
|
# if SANITIZER_MIPS64
|
2016-03-11 10:51:03 +00:00
|
|
|
// For mips64, fstat syscall fills buffer in the format of kernel_stat
|
2024-07-30 09:03:00 +02:00
|
|
|
kstat_t kbuf;
|
2016-03-11 10:51:03 +00:00
|
|
|
int res = internal_syscall(SYSCALL(fstat), fd, &kbuf);
|
|
|
|
kernel_stat_to_stat(&kbuf, (struct stat *)buf);
|
|
|
|
return res;
|
2024-07-30 09:03:00 +02:00
|
|
|
# elif SANITIZER_LINUX && SANITIZER_SPARC64
|
|
|
|
// For sparc64, fstat64 syscall fills buffer in the format of kernel_stat64
|
|
|
|
kstat_t kbuf;
|
|
|
|
int res = internal_syscall(SYSCALL(fstat64), fd, &kbuf);
|
|
|
|
kernel_stat_to_stat(&kbuf, (struct stat *)buf);
|
|
|
|
return res;
|
2022-07-20 00:58:40 -07:00
|
|
|
# elif SANITIZER_LINUX && defined(__loongarch__)
|
|
|
|
struct statx bufx;
|
2022-11-22 22:08:47 +08:00
|
|
|
int res = internal_syscall(SYSCALL(statx), fd, "", AT_EMPTY_PATH,
|
2022-07-20 00:58:40 -07:00
|
|
|
STATX_BASIC_STATS, (uptr)&bufx);
|
|
|
|
statx_to_stat(&bufx, (struct stat *)buf);
|
|
|
|
return res;
|
|
|
|
# else
|
2018-10-08 18:04:46 +00:00
|
|
|
return internal_syscall(SYSCALL(fstat), fd, (uptr)buf);
|
2022-07-20 00:58:40 -07:00
|
|
|
# endif
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2013-05-07 12:47:04 +00:00
|
|
|
struct stat64 buf64;
|
2014-03-07 10:03:54 +00:00
|
|
|
int res = internal_syscall(SYSCALL(fstat64), fd, &buf64);
|
2013-05-07 12:47:04 +00:00
|
|
|
stat64_to_stat(&buf64, (struct stat *)buf);
|
|
|
|
return res;
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2013-02-04 10:16:50 +00:00
|
|
|
}
|
|
|
|
|
2012-06-06 07:30:33 +00:00
|
|
|
uptr internal_filesize(fd_t fd) {
|
2012-07-03 08:24:14 +00:00
|
|
|
struct stat st;
|
2013-02-04 10:16:50 +00:00
|
|
|
if (internal_fstat(fd, &st))
|
|
|
|
return -1;
|
2012-06-06 07:30:33 +00:00
|
|
|
return (uptr)st.st_size;
|
|
|
|
}
|
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
uptr internal_dup(int oldfd) { return internal_syscall(SYSCALL(dup), oldfd); }
|
2018-12-20 20:36:33 +00:00
|
|
|
|
2013-05-08 14:43:49 +00:00
|
|
|
uptr internal_dup2(int oldfd, int newfd) {
|
2022-04-21 15:17:29 -07:00
|
|
|
# if SANITIZER_LINUX
|
2014-03-07 10:03:54 +00:00
|
|
|
return internal_syscall(SYSCALL(dup3), oldfd, newfd, 0);
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2014-03-07 10:03:54 +00:00
|
|
|
return internal_syscall(SYSCALL(dup2), oldfd, newfd);
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2012-06-06 07:30:33 +00:00
|
|
|
}
|
|
|
|
|
2012-09-05 14:48:24 +00:00
|
|
|
uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
|
2022-04-21 15:17:29 -07:00
|
|
|
# if SANITIZER_LINUX
|
2018-03-19 23:12:14 +00:00
|
|
|
return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, (uptr)buf,
|
|
|
|
bufsize);
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2019-02-28 19:34:01 +00:00
|
|
|
return internal_syscall(SYSCALL(readlink), (uptr)path, (uptr)buf, bufsize);
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2012-09-05 14:48:24 +00:00
|
|
|
}
|
|
|
|
|
2013-05-08 14:43:49 +00:00
|
|
|
uptr internal_unlink(const char *path) {
|
2022-04-21 15:17:29 -07:00
|
|
|
# if SANITIZER_LINUX
|
2014-03-07 10:03:54 +00:00
|
|
|
return internal_syscall(SYSCALL(unlinkat), AT_FDCWD, (uptr)path, 0);
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2018-10-08 18:04:46 +00:00
|
|
|
return internal_syscall(SYSCALL(unlink), (uptr)path);
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2013-03-20 10:28:36 +00:00
|
|
|
}
|
|
|
|
|
2014-05-27 12:37:52 +00:00
|
|
|
uptr internal_rename(const char *oldpath, const char *newpath) {
|
2023-11-27 23:17:03 +01:00
|
|
|
# if (defined(__riscv) || defined(__loongarch__)) && defined(__linux__)
|
[Sanitizers] Add support for RISC-V 64-bit
Summary:
This has been tested with gcc trunk on openSUSE Tumbleweed on the HiFive Unleashed.
Patch by Andreas Schwab (schwab)
Reviewers: luismarques
Reviewed By: luismarques
Subscribers: mhorne, emaste, luismarques, asb, mgorny, fedor.sergeev, simoncook, kito-cheng, shiva0217, rogfer01, rkruppe, lenary, s.egerton, #sanitizers, llvm-commits
Tags: #llvm, #sanitizers
Differential Revision: https://reviews.llvm.org/D66870
2019-10-23 14:10:43 +01:00
|
|
|
return internal_syscall(SYSCALL(renameat2), AT_FDCWD, (uptr)oldpath, AT_FDCWD,
|
|
|
|
(uptr)newpath, 0);
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif SANITIZER_LINUX
|
2014-05-27 12:37:52 +00:00
|
|
|
return internal_syscall(SYSCALL(renameat), AT_FDCWD, (uptr)oldpath, AT_FDCWD,
|
|
|
|
(uptr)newpath);
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2018-10-08 18:04:46 +00:00
|
|
|
return internal_syscall(SYSCALL(rename), (uptr)oldpath, (uptr)newpath);
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2014-05-27 12:37:52 +00:00
|
|
|
}
|
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
uptr internal_sched_yield() { return internal_syscall(SYSCALL(sched_yield)); }
|
2012-06-18 08:44:30 +00:00
|
|
|
|
2021-07-09 20:21:52 +02:00
|
|
|
void internal_usleep(u64 useconds) {
|
2016-05-12 14:08:56 +00:00
|
|
|
struct timespec ts;
|
2021-07-09 20:21:52 +02:00
|
|
|
ts.tv_sec = useconds / 1000000;
|
|
|
|
ts.tv_nsec = (useconds % 1000000) * 1000;
|
|
|
|
internal_syscall(SYSCALL(nanosleep), &ts, &ts);
|
2016-05-12 14:08:56 +00:00
|
|
|
}
|
|
|
|
|
2013-05-08 14:43:49 +00:00
|
|
|
uptr internal_execve(const char *filename, char *const argv[],
|
|
|
|
char *const envp[]) {
|
2018-10-08 18:04:46 +00:00
|
|
|
return internal_syscall(SYSCALL(execve), (uptr)filename, (uptr)argv,
|
|
|
|
(uptr)envp);
|
2013-05-08 14:43:49 +00:00
|
|
|
}
|
2025-04-12 00:49:23 -04:00
|
|
|
# endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD && !SANITIZER_HAIKU
|
2013-05-08 14:43:49 +00:00
|
|
|
|
2025-04-11 16:21:00 -04:00
|
|
|
# if !SANITIZER_NETBSD && !SANITIZER_HAIKU
|
2020-09-30 16:30:18 +02:00
|
|
|
void internal__exit(int exitcode) {
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_FREEBSD || SANITIZER_SOLARIS
|
2020-09-30 16:30:18 +02:00
|
|
|
internal_syscall(SYSCALL(exit), exitcode);
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2020-09-30 16:30:18 +02:00
|
|
|
internal_syscall(SYSCALL(exit_group), exitcode);
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2020-09-30 16:30:18 +02:00
|
|
|
Die(); // Unreachable.
|
|
|
|
}
|
2025-04-12 00:49:23 -04:00
|
|
|
# endif // !SANITIZER_NETBSD && !SANITIZER_HAIKU
|
2020-09-30 16:30:18 +02:00
|
|
|
|
2012-06-07 07:13:46 +00:00
|
|
|
// ----------------- sanitizer_common.h
|
2012-11-09 14:45:30 +00:00
|
|
|
bool FileExists(const char *filename) {
|
2019-01-08 01:07:34 +00:00
|
|
|
if (ShouldMockFailureToOpen(filename))
|
|
|
|
return false;
|
2014-02-13 07:50:20 +00:00
|
|
|
struct stat st;
|
2013-05-07 12:47:04 +00:00
|
|
|
if (internal_stat(filename, &st))
|
2012-11-09 14:45:30 +00:00
|
|
|
return false;
|
|
|
|
// Sanity check: filename is a regular file.
|
|
|
|
return S_ISREG(st.st_mode);
|
|
|
|
}
|
|
|
|
|
2022-02-10 15:42:38 -08:00
|
|
|
bool DirExists(const char *path) {
|
|
|
|
struct stat st;
|
|
|
|
if (internal_stat(path, &st))
|
|
|
|
return false;
|
|
|
|
return S_ISDIR(st.st_mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
# if !SANITIZER_NETBSD
|
2017-04-17 18:17:38 +00:00
|
|
|
tid_t GetTid() {
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_FREEBSD
|
2018-03-03 11:50:58 +00:00
|
|
|
long Tid;
|
|
|
|
thr_self(&Tid);
|
|
|
|
return Tid;
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif SANITIZER_SOLARIS
|
2018-03-03 11:50:58 +00:00
|
|
|
return thr_self();
|
2025-04-11 16:21:00 -04:00
|
|
|
# elif SANITIZER_HAIKU
|
|
|
|
return find_thread(NULL);
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2014-03-07 10:03:54 +00:00
|
|
|
return internal_syscall(SYSCALL(gettid));
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2012-10-02 12:58:14 +00:00
|
|
|
}
|
|
|
|
|
2018-08-14 20:28:58 +00:00
|
|
|
int TgKill(pid_t pid, tid_t tid, int sig) {
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_LINUX
|
2018-08-14 20:28:58 +00:00
|
|
|
return internal_syscall(SYSCALL(tgkill), pid, tid, sig);
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif SANITIZER_FREEBSD
|
2018-08-14 20:28:58 +00:00
|
|
|
return internal_syscall(SYSCALL(thr_kill2), pid, tid, sig);
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif SANITIZER_SOLARIS
|
2018-08-16 15:54:38 +00:00
|
|
|
(void)pid;
|
2024-07-16 15:50:51 +02:00
|
|
|
errno = thr_kill(tid, sig);
|
|
|
|
// TgKill is expected to return -1 on error, not an errno.
|
|
|
|
return errno != 0 ? -1 : 0;
|
2025-04-11 16:21:00 -04:00
|
|
|
# elif SANITIZER_HAIKU
|
|
|
|
return kill_thread(tid);
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2018-08-14 20:28:58 +00:00
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2018-08-14 20:28:58 +00:00
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_GLIBC
|
2013-03-21 06:24:31 +00:00
|
|
|
u64 NanoTime() {
|
2013-10-21 18:11:57 +00:00
|
|
|
kernel_timeval tv;
|
|
|
|
internal_memset(&tv, 0, sizeof(tv));
|
2018-10-08 18:04:46 +00:00
|
|
|
internal_syscall(SYSCALL(gettimeofday), &tv, 0);
|
2021-03-10 23:02:51 -08:00
|
|
|
return (u64)tv.tv_sec * 1000 * 1000 * 1000 + tv.tv_usec * 1000;
|
2013-03-21 06:24:31 +00:00
|
|
|
}
|
2021-03-10 23:02:51 -08:00
|
|
|
// Used by real_clock_gettime.
|
2017-12-13 16:23:54 +00:00
|
|
|
uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) {
|
2018-10-08 18:04:46 +00:00
|
|
|
return internal_syscall(SYSCALL(clock_gettime), clk_id, tp);
|
2017-12-13 16:23:54 +00:00
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif !SANITIZER_SOLARIS && !SANITIZER_NETBSD
|
2021-03-10 23:02:51 -08:00
|
|
|
u64 NanoTime() {
|
|
|
|
struct timespec ts;
|
|
|
|
clock_gettime(CLOCK_REALTIME, &ts);
|
|
|
|
return (u64)ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
|
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2017-12-13 16:23:54 +00:00
|
|
|
|
2014-07-10 08:53:29 +00:00
|
|
|
// Like getenv, but reads env directly from /proc (on Linux) or parses the
|
[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-14 20:14:29 +00:00
|
|
|
// 'environ' array (on some others) and does not use libc. This function
|
|
|
|
// should be called first inside __asan_init.
|
2012-06-14 14:07:21 +00:00
|
|
|
const char *GetEnv(const char *name) {
|
2025-04-11 16:21:00 -04:00
|
|
|
# if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_SOLARIS || \
|
|
|
|
SANITIZER_HAIKU
|
2014-07-10 08:53:29 +00:00
|
|
|
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.
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif SANITIZER_LINUX
|
2012-06-14 14:07:21 +00:00
|
|
|
static char *environ;
|
|
|
|
static uptr len;
|
|
|
|
static bool inited;
|
|
|
|
if (!inited) {
|
|
|
|
inited = true;
|
|
|
|
uptr environ_size;
|
2015-07-17 23:50:08 +00:00
|
|
|
if (!ReadFileToBuffer("/proc/self/environ", &environ, &environ_size, &len))
|
|
|
|
environ = nullptr;
|
2012-06-14 14:07:21 +00:00
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
if (!environ || len == 0)
|
|
|
|
return nullptr;
|
2012-06-14 14:07:21 +00: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...
|
2023-11-27 23:17:03 +01:00
|
|
|
const char *endp = (char *)internal_memchr(p, '\0', len - (p - environ));
|
2015-09-30 23:52:54 +00:00
|
|
|
if (!endp) // this entry isn't NUL terminated
|
|
|
|
return nullptr;
|
2012-06-14 14:07:21 +00:00
|
|
|
else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=') // Match.
|
|
|
|
return p + namelen + 1; // point after =
|
|
|
|
p = endp + 1;
|
|
|
|
}
|
2015-09-30 23:52:54 +00:00
|
|
|
return nullptr; // Not found.
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
|
|
|
# error "Unsupported platform"
|
|
|
|
# endif
|
2014-07-10 08:53:29 +00:00
|
|
|
}
|
2012-06-14 14:07:21 +00:00
|
|
|
|
2025-04-11 16:21:00 -04:00
|
|
|
# if !SANITIZER_HAIKU && !SANITIZER_FREEBSD && !SANITIZER_NETBSD && \
|
|
|
|
!SANITIZER_GO
|
2013-02-14 14:40:03 +00:00
|
|
|
extern "C" {
|
2018-03-19 23:12:14 +00:00
|
|
|
SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end;
|
2013-02-14 14:40:03 +00:00
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2013-02-14 14:40:03 +00:00
|
|
|
|
2025-04-11 16:21:00 -04:00
|
|
|
# if !SANITIZER_HAIKU && !SANITIZER_FREEBSD && !SANITIZER_NETBSD
|
2013-01-17 19:50:42 +00:00
|
|
|
static void ReadNullSepFileToArray(const char *path, char ***arr,
|
|
|
|
int arr_size) {
|
|
|
|
char *buff;
|
2015-07-17 23:50:08 +00:00
|
|
|
uptr buff_size;
|
|
|
|
uptr buff_len;
|
2013-01-17 19:50:42 +00:00
|
|
|
*arr = (char **)MmapOrDie(arr_size * sizeof(char *), "NullSepFileArray");
|
2015-07-17 23:50:08 +00:00
|
|
|
if (!ReadFileToBuffer(path, &buff, &buff_size, &buff_len, 1024 * 1024)) {
|
|
|
|
(*arr)[0] = nullptr;
|
|
|
|
return;
|
|
|
|
}
|
2013-01-17 19:50:42 +00:00
|
|
|
(*arr)[0] = buff;
|
|
|
|
int count, i;
|
2023-11-27 23:17:03 +01:00
|
|
|
for (count = 1, i = 1;; i++) {
|
2012-09-17 09:12:39 +00:00
|
|
|
if (buff[i] == 0) {
|
2023-11-27 23:17:03 +01:00
|
|
|
if (buff[i + 1] == 0)
|
|
|
|
break;
|
|
|
|
(*arr)[count] = &buff[i + 1];
|
2013-01-17 19:50:42 +00:00
|
|
|
CHECK_LE(count, arr_size - 1); // FIXME: make this more flexible.
|
|
|
|
count++;
|
2012-09-17 09:12:39 +00:00
|
|
|
}
|
|
|
|
}
|
2015-07-17 23:50:08 +00:00
|
|
|
(*arr)[count] = nullptr;
|
2013-01-17 19:50:42 +00:00
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2014-12-09 01:22:59 +00:00
|
|
|
|
2016-01-18 07:55:12 +00:00
|
|
|
static void GetArgsAndEnv(char ***argv, char ***envp) {
|
2025-04-11 16:21:00 -04:00
|
|
|
# if SANITIZER_HAIKU
|
|
|
|
*argv = __libc_argv;
|
|
|
|
*envp = environ;
|
|
|
|
# elif SANITIZER_FREEBSD
|
2017-10-25 17:09:05 +00:00
|
|
|
// On FreeBSD, retrieving the argument and environment arrays is done via the
|
|
|
|
// kern.ps_strings sysctl, which returns a pointer to a structure containing
|
|
|
|
// this information. See also <sys/exec.h>.
|
|
|
|
ps_strings *pss;
|
2018-10-08 12:18:19 +00:00
|
|
|
uptr sz = sizeof(pss);
|
2018-10-05 06:58:02 +00:00
|
|
|
if (internal_sysctlbyname("kern.ps_strings", &pss, &sz, NULL, 0) == -1) {
|
2017-10-25 17:09:05 +00:00
|
|
|
Printf("sysctl kern.ps_strings failed\n");
|
|
|
|
Die();
|
|
|
|
}
|
|
|
|
*argv = pss->ps_argvstr;
|
|
|
|
*envp = pss->ps_envstr;
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif SANITIZER_NETBSD
|
2017-10-25 17:09:05 +00:00
|
|
|
*argv = __ps_strings->ps_argvstr;
|
2018-02-07 14:05:57 +00:00
|
|
|
*envp = __ps_strings->ps_envstr;
|
2023-11-27 23:17:03 +01:00
|
|
|
# else // SANITIZER_FREEBSD
|
|
|
|
# if !SANITIZER_GO
|
2013-05-20 14:25:32 +00:00
|
|
|
if (&__libc_stack_end) {
|
2023-11-27 23:17:03 +01:00
|
|
|
uptr *stack_end = (uptr *)__libc_stack_end;
|
2024-09-24 09:36:40 +02:00
|
|
|
// Linux/sparc64 needs an adjustment, cf. glibc
|
|
|
|
// sysdeps/sparc/sparc{32,64}/dl-machine.h (DL_STACK_END).
|
|
|
|
# if SANITIZER_LINUX && defined(__sparc__)
|
|
|
|
stack_end = &stack_end[16];
|
|
|
|
# endif
|
2020-04-08 14:25:20 +02:00
|
|
|
// Normally argc can be obtained from *stack_end, however, on ARM glibc's
|
|
|
|
// _start clobbers it:
|
|
|
|
// https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/arm/start.S;hb=refs/heads/release/2.31/master#l75
|
|
|
|
// Do not special-case ARM and infer argc from argv everywhere.
|
|
|
|
int argc = 0;
|
|
|
|
while (stack_end[argc + 1]) argc++;
|
2023-11-27 23:17:03 +01:00
|
|
|
*argv = (char **)(stack_end + 1);
|
|
|
|
*envp = (char **)(stack_end + argc + 2);
|
2013-05-20 14:25:32 +00:00
|
|
|
} else {
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif // !SANITIZER_GO
|
2013-05-20 14:25:32 +00:00
|
|
|
static const int kMaxArgv = 2000, kMaxEnvp = 2000;
|
|
|
|
ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv);
|
|
|
|
ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp);
|
2023-11-27 23:17:03 +01:00
|
|
|
# if !SANITIZER_GO
|
2013-05-20 14:25:32 +00:00
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif // !SANITIZER_GO
|
2025-04-12 00:49:23 -04:00
|
|
|
# endif // SANITIZER_HAIKU
|
2013-02-14 14:40:03 +00:00
|
|
|
}
|
|
|
|
|
2016-01-18 07:55:12 +00:00
|
|
|
char **GetArgv() {
|
|
|
|
char **argv, **envp;
|
|
|
|
GetArgsAndEnv(&argv, &envp);
|
|
|
|
return argv;
|
|
|
|
}
|
|
|
|
|
2018-11-06 19:23:12 +00:00
|
|
|
char **GetEnviron() {
|
2013-01-17 19:50:42 +00:00
|
|
|
char **argv, **envp;
|
2018-11-06 19:23:12 +00:00
|
|
|
GetArgsAndEnv(&argv, &envp);
|
|
|
|
return envp;
|
|
|
|
}
|
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if !SANITIZER_SOLARIS
|
2021-07-15 17:15:48 +02:00
|
|
|
void FutexWait(atomic_uint32_t *p, u32 cmp) {
|
|
|
|
# if SANITIZER_FREEBSD
|
|
|
|
_umtx_op(p, UMTX_OP_WAIT_UINT, cmp, 0, 0);
|
2025-04-11 16:21:00 -04:00
|
|
|
# elif SANITIZER_NETBSD || SANITIZER_HAIKU
|
2023-11-27 23:17:03 +01:00
|
|
|
sched_yield(); /* No userspace futex-like synchronization */
|
2021-07-15 17:15:48 +02:00
|
|
|
# else
|
|
|
|
internal_syscall(SYSCALL(futex), (uptr)p, FUTEX_WAIT_PRIVATE, cmp, 0, 0, 0);
|
|
|
|
# endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void FutexWake(atomic_uint32_t *p, u32 count) {
|
|
|
|
# if SANITIZER_FREEBSD
|
2021-07-18 07:02:21 +01:00
|
|
|
_umtx_op(p, UMTX_OP_WAKE, count, 0, 0);
|
2025-04-11 16:21:00 -04:00
|
|
|
# elif SANITIZER_NETBSD || SANITIZER_HAIKU
|
2023-11-27 23:17:03 +01:00
|
|
|
/* No userspace futex-like synchronization */
|
2021-07-15 17:15:48 +02:00
|
|
|
# else
|
|
|
|
internal_syscall(SYSCALL(futex), (uptr)p, FUTEX_WAKE_PRIVATE, count, 0, 0, 0);
|
|
|
|
# endif
|
|
|
|
}
|
|
|
|
|
2021-07-09 19:29:41 +02:00
|
|
|
# endif // !SANITIZER_SOLARIS
|
2013-03-11 15:45:20 +00:00
|
|
|
|
2013-02-27 11:22:40 +00: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.
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_NETBSD
|
Switch syscall(2)/__syscall(2) calls to libc calls on NetBSD
Summary:
When possible, switch syscall(2)/__syscall(2) calls
to direct calls of internal libc symbols.
Add a new function to detect address of a libc
symbol of a function that could be intercepted.
With the address detector in GetRealLibcAddress(),
an optional interceptor of libc call will be bypassed.
The original approach with syscall(2)/__syscall(2)
wasn't portable across supported ABIs and CPU
architectures. The indirect syscall interface is
also a candidate for removal in future revisions
of NetBSD, as the C language ABI is not a good
domain for serialization of arbitrary functions
arguments.
Switch the following functions to libc calls:
- internal_mmap()
- internal_munmap()
- internal_mprotect()
- internal_close()
- internal_open()
- internal_read()
- internal_write()
- internal_ftruncate()
- internal_stat()
- internal_lstat()
- internal_fstat()
- internal_dup2()
- internal_readlink()
- internal_unlink()
- internal_rename()
- internal_sched_yield()
- internal__exit()
- internal_sleep()
- internal_execve()
- NanoTime()
- internal_clock_gettime()
- internal_waitpid()
- internal_getpid()
- internal_getppid()
- internal_getdents()
- internal_lseek()
- internal_sigaltstack()
- internal_fork()
- internal_sigprocmask()
- internal_sysctl()
- internal_sigemptyset()
- internal_sigfillset()
- GetTid()
- TgKill()
This revision leaves room for refactoring in subsequent commits.
Reviewers: vitalybuka, kcc, joerg
Reviewed By: vitalybuka
Subscribers: mgorny, fedor.sergeev, jfb, loverszhaokai, devnexen, kubamracek, llvm-commits, ro, #sanitizers
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D51419
llvm-svn: 343523
2018-10-01 19:50:12 +00:00
|
|
|
// Not used
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2013-02-27 11:22:40 +00:00
|
|
|
struct linux_dirent {
|
2022-04-21 15:17:29 -07:00
|
|
|
# if SANITIZER_X32 || SANITIZER_LINUX
|
2014-05-21 08:21:13 +00:00
|
|
|
u64 d_ino;
|
|
|
|
u64 d_off;
|
2022-04-21 15:17:29 -07:00
|
|
|
# else
|
2023-11-27 23:17:03 +01:00
|
|
|
unsigned long d_ino;
|
|
|
|
unsigned long d_off;
|
2022-04-21 15:17:29 -07:00
|
|
|
# endif
|
2023-11-27 23:17:03 +01:00
|
|
|
unsigned short d_reclen;
|
2022-04-21 15:17:29 -07:00
|
|
|
# if SANITIZER_LINUX
|
2023-11-27 23:17:03 +01:00
|
|
|
unsigned char d_type;
|
2022-04-21 15:17:29 -07:00
|
|
|
# endif
|
2023-11-27 23:17:03 +01:00
|
|
|
char d_name[256];
|
2013-02-27 11:22:40 +00:00
|
|
|
};
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2013-02-27 11:22:40 +00:00
|
|
|
|
2025-04-11 16:21:00 -04:00
|
|
|
# if !SANITIZER_SOLARIS && !SANITIZER_NETBSD && !SANITIZER_HAIKU
|
2013-02-27 11:22:40 +00:00
|
|
|
// Syscall wrappers.
|
2013-05-08 14:43:49 +00:00
|
|
|
uptr internal_ptrace(int request, int pid, void *addr, void *data) {
|
2014-03-07 10:03:54 +00:00
|
|
|
return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr,
|
|
|
|
(uptr)data);
|
2013-05-08 14:43:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uptr internal_waitpid(int pid, int *status, int options) {
|
2018-10-08 18:04:46 +00:00
|
|
|
return internal_syscall(SYSCALL(wait4), pid, (uptr)status, options,
|
2013-11-06 17:47:39 +00:00
|
|
|
0 /* rusage */);
|
2013-02-27 11:22:40 +00:00
|
|
|
}
|
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
uptr internal_getpid() { return internal_syscall(SYSCALL(getpid)); }
|
2013-02-27 11:22:40 +00:00
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
uptr internal_getppid() { return internal_syscall(SYSCALL(getppid)); }
|
2013-02-27 11:22:40 +00:00
|
|
|
|
[Sanitizers] Get link map on FreeBSD and NetBSD via documented API
Summary:
Instead of hand-crafting an offset into the structure returned by
dlopen(3) to get at the link map, use the documented API. This is
described in dlinfo(3): by calling it with `RTLD_DI_LINKMAP`, the
dynamic linker ensures the right address is returned.
This is a recommit of 92e267a94dc4272511be674062f8a3e8897b7083, with
dlinfo(3) expliclity being referenced only for FreeBSD, non-Android
Linux, NetBSD and Solaris. Other OSes will have to add their own
implementation.
Reviewers: devnexen, emaste, MaskRay, krytarowski
Reviewed By: krytarowski
Subscribers: krytarowski, vitalybuka, #sanitizers, llvm-commits
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D73990
2020-02-10 23:43:12 +01:00
|
|
|
int internal_dlinfo(void *handle, int request, void *p) {
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_FREEBSD
|
[Sanitizers] Get link map on FreeBSD and NetBSD via documented API
Summary:
Instead of hand-crafting an offset into the structure returned by
dlopen(3) to get at the link map, use the documented API. This is
described in dlinfo(3): by calling it with `RTLD_DI_LINKMAP`, the
dynamic linker ensures the right address is returned.
This is a recommit of 92e267a94dc4272511be674062f8a3e8897b7083, with
dlinfo(3) expliclity being referenced only for FreeBSD, non-Android
Linux, NetBSD and Solaris. Other OSes will have to add their own
implementation.
Reviewers: devnexen, emaste, MaskRay, krytarowski
Reviewed By: krytarowski
Subscribers: krytarowski, vitalybuka, #sanitizers, llvm-commits
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D73990
2020-02-10 23:43:12 +01:00
|
|
|
return dlinfo(handle, request, p);
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
[Sanitizers] Get link map on FreeBSD and NetBSD via documented API
Summary:
Instead of hand-crafting an offset into the structure returned by
dlopen(3) to get at the link map, use the documented API. This is
described in dlinfo(3): by calling it with `RTLD_DI_LINKMAP`, the
dynamic linker ensures the right address is returned.
This is a recommit of 92e267a94dc4272511be674062f8a3e8897b7083, with
dlinfo(3) expliclity being referenced only for FreeBSD, non-Android
Linux, NetBSD and Solaris. Other OSes will have to add their own
implementation.
Reviewers: devnexen, emaste, MaskRay, krytarowski
Reviewed By: krytarowski
Subscribers: krytarowski, vitalybuka, #sanitizers, llvm-commits
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D73990
2020-02-10 23:43:12 +01:00
|
|
|
UNIMPLEMENTED();
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
[Sanitizers] Get link map on FreeBSD and NetBSD via documented API
Summary:
Instead of hand-crafting an offset into the structure returned by
dlopen(3) to get at the link map, use the documented API. This is
described in dlinfo(3): by calling it with `RTLD_DI_LINKMAP`, the
dynamic linker ensures the right address is returned.
This is a recommit of 92e267a94dc4272511be674062f8a3e8897b7083, with
dlinfo(3) expliclity being referenced only for FreeBSD, non-Android
Linux, NetBSD and Solaris. Other OSes will have to add their own
implementation.
Reviewers: devnexen, emaste, MaskRay, krytarowski
Reviewed By: krytarowski
Subscribers: krytarowski, vitalybuka, #sanitizers, llvm-commits
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D73990
2020-02-10 23:43:12 +01:00
|
|
|
}
|
|
|
|
|
2013-05-08 14:43:49 +00:00
|
|
|
uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_FREEBSD
|
Adjust sanitizers for FreeBSD 64-bit inode update
Summary:
Very recently, FreeBSD 12 has been updated to use 64-bit inode numbers:
<https://svnweb.freebsd.org/changeset/base/318737>. This entails many
user-visible changes, but for the sanitizers the modifications are
limited in scope:
* The `stat` and `lstat` syscalls were removed, and should be replaced
with calls to `fstatat`.
* The `getdents` syscall was removed, and should be replaced with calls
to `getdirentries`.
* The layout of `struct dirent` was changed to accomodate 64-bit inode
numbers, and a new `d_off` field was added.
* The system header <sys/_types.h> now contains a macro `__INO64` to
determine whether the system uses 64-bit inode numbers.
I tested these changes on both FreeBSD 12.0-CURRENT (after r318959,
which adds the `__INO64` macro), and FreeBSD 11.0-STABLE (which still
uses 32-bit inode numbers).
Reviewers: emaste, kcc, vitalybuka, kubamracek
Reviewed By: vitalybuka
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D33600
llvm-svn: 304658
2017-06-03 11:11:36 +00:00
|
|
|
return internal_syscall(SYSCALL(getdirentries), fd, (uptr)dirp, count, NULL);
|
2022-04-21 15:17:29 -07:00
|
|
|
# elif SANITIZER_LINUX
|
2014-03-07 10:03:54 +00:00
|
|
|
return internal_syscall(SYSCALL(getdents64), fd, (uptr)dirp, count);
|
2022-04-21 15:17:29 -07:00
|
|
|
# else
|
2018-10-08 18:04:46 +00:00
|
|
|
return internal_syscall(SYSCALL(getdents), fd, (uptr)dirp, count);
|
2022-04-21 15:17:29 -07:00
|
|
|
# endif
|
2013-02-27 11:22:40 +00:00
|
|
|
}
|
|
|
|
|
2013-05-08 14:43:49 +00:00
|
|
|
uptr internal_lseek(fd_t fd, OFF_T offset, int whence) {
|
2014-03-07 10:03:54 +00:00
|
|
|
return internal_syscall(SYSCALL(lseek), fd, offset, whence);
|
2013-02-27 11:22:40 +00:00
|
|
|
}
|
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_LINUX
|
2013-05-08 14:43:49 +00:00
|
|
|
uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) {
|
2014-03-07 10:03:54 +00:00
|
|
|
return internal_syscall(SYSCALL(prctl), option, arg2, arg3, arg4, arg5);
|
2013-02-27 11:22:40 +00:00
|
|
|
}
|
2022-07-14 10:26:45 -07:00
|
|
|
# if defined(__x86_64__)
|
|
|
|
# include <asm/unistd_64.h>
|
2022-07-13 19:04:38 -07:00
|
|
|
// Currently internal_arch_prctl() is only needed on x86_64.
|
|
|
|
uptr internal_arch_prctl(int option, uptr arg2) {
|
|
|
|
return internal_syscall(__NR_arch_prctl, option, arg2);
|
|
|
|
}
|
2022-07-14 10:26:45 -07:00
|
|
|
# endif
|
|
|
|
# endif
|
2013-02-27 11:22:40 +00:00
|
|
|
|
2017-07-13 21:59:01 +00:00
|
|
|
uptr internal_sigaltstack(const void *ss, void *oss) {
|
2018-10-08 18:04:46 +00:00
|
|
|
return internal_syscall(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss);
|
2013-02-27 11:22:40 +00:00
|
|
|
}
|
|
|
|
|
2024-07-30 08:57:25 +02:00
|
|
|
extern "C" pid_t __fork(void);
|
|
|
|
|
2014-05-13 17:31:09 +00:00
|
|
|
int internal_fork() {
|
2022-04-21 15:17:29 -07:00
|
|
|
# if SANITIZER_LINUX
|
|
|
|
# if SANITIZER_S390
|
|
|
|
return internal_syscall(SYSCALL(clone), 0, SIGCHLD);
|
2024-07-30 08:57:25 +02:00
|
|
|
# elif SANITIZER_SPARC
|
|
|
|
// The clone syscall interface on SPARC differs massively from the rest,
|
|
|
|
// so fall back to __fork.
|
|
|
|
return __fork();
|
2022-04-21 15:17:29 -07:00
|
|
|
# else
|
2014-05-26 23:44:55 +00:00
|
|
|
return internal_syscall(SYSCALL(clone), SIGCHLD, 0);
|
2022-04-21 15:17:29 -07:00
|
|
|
# endif
|
|
|
|
# else
|
2014-05-13 16:17:54 +00:00
|
|
|
return internal_syscall(SYSCALL(fork));
|
2022-04-21 15:17:29 -07:00
|
|
|
# endif
|
2014-05-13 16:17:54 +00:00
|
|
|
}
|
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_FREEBSD
|
2018-08-31 08:10:06 +00:00
|
|
|
int internal_sysctl(const int *name, unsigned int namelen, void *oldp,
|
|
|
|
uptr *oldlenp, const void *newp, uptr newlen) {
|
2018-12-04 19:17:26 +00:00
|
|
|
return internal_syscall(SYSCALL(__sysctl), name, namelen, oldp,
|
|
|
|
(size_t *)oldlenp, newp, (size_t)newlen);
|
2018-08-31 08:10:06 +00:00
|
|
|
}
|
2018-10-05 06:58:02 +00:00
|
|
|
|
|
|
|
int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp,
|
|
|
|
const void *newp, uptr newlen) {
|
2020-09-01 10:46:35 +01:00
|
|
|
// Note: this function can be called during startup, so we need to avoid
|
|
|
|
// calling any interceptable functions. On FreeBSD >= 1300045 sysctlbyname()
|
|
|
|
// is a real syscall, but for older versions it calls sysctlnametomib()
|
|
|
|
// followed by sysctl(). To avoid calling the intercepted version and
|
|
|
|
// asserting if this happens during startup, call the real sysctlnametomib()
|
|
|
|
// followed by internal_sysctl() if the syscall is not available.
|
2023-11-27 23:17:03 +01:00
|
|
|
# ifdef SYS___sysctlbyname
|
2020-09-01 10:46:35 +01:00
|
|
|
return internal_syscall(SYSCALL(__sysctlbyname), sname,
|
|
|
|
internal_strlen(sname), oldp, (size_t *)oldlenp, newp,
|
|
|
|
(size_t)newlen);
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2020-09-01 10:46:35 +01:00
|
|
|
static decltype(sysctlnametomib) *real_sysctlnametomib = nullptr;
|
|
|
|
if (!real_sysctlnametomib)
|
|
|
|
real_sysctlnametomib =
|
|
|
|
(decltype(sysctlnametomib) *)dlsym(RTLD_NEXT, "sysctlnametomib");
|
|
|
|
CHECK(real_sysctlnametomib);
|
|
|
|
|
|
|
|
int oid[CTL_MAXNAME];
|
|
|
|
size_t len = CTL_MAXNAME;
|
|
|
|
if (real_sysctlnametomib(sname, oid, &len) == -1)
|
|
|
|
return (-1);
|
|
|
|
return internal_sysctl(oid, len, oldp, oldlenp, newp, newlen);
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2018-10-05 06:58:02 +00:00
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2018-08-31 08:10:06 +00:00
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_LINUX
|
|
|
|
# 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 15:15:38 +00:00
|
|
|
// Doesn't set sa_restorer if the caller did not set it, so use with caution
|
|
|
|
//(see below).
|
2014-01-31 11:29:51 +00: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-13 22:40:59 +00:00
|
|
|
const __sanitizer_sigaction *u_act = (const __sanitizer_sigaction *)act;
|
2014-01-31 11:29:51 +00: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-02 17:36:02 +00:00
|
|
|
// Without SA_RESTORER kernel ignores the calls (probably returns EINVAL).
|
|
|
|
k_act.sa_flags = u_act->sa_flags | SA_RESTORER;
|
2014-01-31 11:29:51 +00: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).
|
2023-11-27 23:17:03 +01:00
|
|
|
# if !SANITIZER_ANDROID || !SANITIZER_MIPS32
|
2014-01-31 11:29:51 +00:00
|
|
|
k_act.sa_restorer = u_act->sa_restorer;
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2014-01-31 11:29:51 +00:00
|
|
|
}
|
|
|
|
|
2014-03-07 10:03:54 +00:00
|
|
|
uptr result = internal_syscall(SYSCALL(rt_sigaction), (uptr)signum,
|
2023-11-27 23:17:03 +01:00
|
|
|
(uptr)(u_act ? &k_act : nullptr),
|
|
|
|
(uptr)(u_oldact ? &k_oldact : nullptr),
|
|
|
|
(uptr)sizeof(__sanitizer_kernel_sigset_t));
|
2014-01-31 11:29:51 +00:00
|
|
|
|
|
|
|
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;
|
2023-11-27 23:17:03 +01:00
|
|
|
# if !SANITIZER_ANDROID || !SANITIZER_MIPS32
|
2014-01-31 11:29:51 +00:00
|
|
|
u_oldact->sa_restorer = k_oldact.sa_restorer;
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2014-01-31 11:29:51 +00:00
|
|
|
}
|
|
|
|
return result;
|
2013-10-15 11:31:51 +00:00
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif // SANITIZER_LINUX
|
2013-10-15 11:31:51 +00:00
|
|
|
|
2014-01-31 11:29:51 +00:00
|
|
|
uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
|
2018-03-19 23:12:14 +00:00
|
|
|
__sanitizer_sigset_t *oldset) {
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_FREEBSD
|
2018-10-08 18:04:46 +00:00
|
|
|
return internal_syscall(SYSCALL(sigprocmask), how, set, oldset);
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2014-01-31 11:29:51 +00:00
|
|
|
__sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set;
|
|
|
|
__sanitizer_kernel_sigset_t *k_oldset = (__sanitizer_kernel_sigset_t *)oldset;
|
2020-06-11 00:16:09 -07:00
|
|
|
return internal_syscall(SYSCALL(rt_sigprocmask), (uptr)how, (uptr)k_set,
|
|
|
|
(uptr)k_oldset, sizeof(__sanitizer_kernel_sigset_t));
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2013-10-15 11:31:51 +00:00
|
|
|
}
|
|
|
|
|
2014-01-31 11:29:51 +00:00
|
|
|
void internal_sigfillset(__sanitizer_sigset_t *set) {
|
2013-10-15 11:31:51 +00:00
|
|
|
internal_memset(set, 0xff, sizeof(*set));
|
|
|
|
}
|
|
|
|
|
2016-07-06 21:04:48 +00:00
|
|
|
void internal_sigemptyset(__sanitizer_sigset_t *set) {
|
|
|
|
internal_memset(set, 0, sizeof(*set));
|
|
|
|
}
|
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_LINUX
|
2014-01-31 11:29:51 +00:00
|
|
|
void internal_sigdelset(__sanitizer_sigset_t *set, int signum) {
|
2013-10-15 11:31:51 +00:00
|
|
|
signum -= 1;
|
|
|
|
CHECK_GE(signum, 0);
|
|
|
|
CHECK_LT(signum, sizeof(*set) * 8);
|
2014-01-31 11:29:51 +00: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);
|
2021-07-02 02:42:38 +02:00
|
|
|
k_set->sig[idx] &= ~((uptr)1 << bit);
|
2013-10-15 11:31:51 +00:00
|
|
|
}
|
2016-07-06 21:04:48 +00: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);
|
2021-07-02 02:42:38 +02:00
|
|
|
return k_set->sig[idx] & ((uptr)1 << bit);
|
2016-07-06 21:04:48 +00:00
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif SANITIZER_FREEBSD
|
2022-06-08 08:55:10 +01:00
|
|
|
uptr internal_procctl(int type, int id, int cmd, void *data) {
|
|
|
|
return internal_syscall(SYSCALL(procctl), type, id, cmd, data);
|
|
|
|
}
|
|
|
|
|
2018-10-04 20:58:18 +00:00
|
|
|
void internal_sigdelset(__sanitizer_sigset_t *set, int signum) {
|
|
|
|
sigset_t *rset = reinterpret_cast<sigset_t *>(set);
|
|
|
|
sigdelset(rset, signum);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool internal_sigismember(__sanitizer_sigset_t *set, int signum) {
|
|
|
|
sigset_t *rset = reinterpret_cast<sigset_t *>(set);
|
|
|
|
return sigismember(rset, signum);
|
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
|
|
|
# endif // !SANITIZER_SOLARIS
|
2013-10-15 11:31:51 +00:00
|
|
|
|
2025-04-11 16:21:00 -04:00
|
|
|
# if !SANITIZER_NETBSD && !SANITIZER_HAIKU
|
2013-02-27 11:22:40 +00:00
|
|
|
// ThreadLister implementation.
|
2024-10-10 11:23:11 -07:00
|
|
|
ThreadLister::ThreadLister(pid_t pid) : buffer_(4096) {
|
|
|
|
task_path_.AppendF("/proc/%d/task", pid);
|
2013-02-27 11:22:40 +00:00
|
|
|
}
|
|
|
|
|
2018-05-10 04:02:59 +00:00
|
|
|
ThreadLister::Result ThreadLister::ListThreads(
|
|
|
|
InternalMmapVector<tid_t> *threads) {
|
2024-10-10 11:23:11 -07:00
|
|
|
int descriptor = internal_open(task_path_.data(), O_RDONLY | O_DIRECTORY);
|
|
|
|
if (internal_iserror(descriptor)) {
|
|
|
|
Report("Can't open %s for reading.\n", task_path_.data());
|
2018-05-10 04:02:59 +00:00
|
|
|
return Error;
|
2024-10-10 11:23:11 -07:00
|
|
|
}
|
2024-10-10 13:25:46 -07:00
|
|
|
auto cleanup = at_scope_exit([&] { internal_close(descriptor); });
|
2018-05-07 23:29:48 +00:00
|
|
|
threads->clear();
|
|
|
|
|
2018-05-10 04:02:59 +00:00
|
|
|
Result result = Ok;
|
|
|
|
for (bool first_read = true;; first_read = false) {
|
|
|
|
CHECK_GE(buffer_.size(), 4096);
|
|
|
|
uptr read = internal_getdents(
|
2024-10-10 11:23:11 -07:00
|
|
|
descriptor, (struct linux_dirent *)buffer_.data(), buffer_.size());
|
2018-05-10 04:02:59 +00:00
|
|
|
if (!read)
|
|
|
|
return result;
|
2018-05-07 23:29:48 +00:00
|
|
|
if (internal_iserror(read)) {
|
2024-10-10 11:23:11 -07:00
|
|
|
Report("Can't read directory entries from %s.\n", task_path_.data());
|
2018-05-10 04:02:59 +00:00
|
|
|
return Error;
|
2013-02-27 11:22:40 +00:00
|
|
|
}
|
|
|
|
|
2018-05-07 23:29:48 +00:00
|
|
|
for (uptr begin = (uptr)buffer_.data(), end = begin + read; begin < end;) {
|
|
|
|
struct linux_dirent *entry = (struct linux_dirent *)begin;
|
|
|
|
begin += entry->d_reclen;
|
2018-05-10 04:02:59 +00:00
|
|
|
if (entry->d_ino == 1) {
|
|
|
|
// Inode 1 is for bad blocks and also can be a reason for early return.
|
|
|
|
// Should be emitted if kernel tried to output terminating thread.
|
|
|
|
// See proc_task_readdir implementation in Linux.
|
|
|
|
result = Incomplete;
|
2018-05-07 23:29:48 +00:00
|
|
|
}
|
2018-05-10 04:02:59 +00:00
|
|
|
if (entry->d_ino && *entry->d_name >= '0' && *entry->d_name <= '9')
|
|
|
|
threads->push_back(internal_atoll(entry->d_name));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now we are going to detect short-read or early EOF. In such cases Linux
|
|
|
|
// can return inconsistent list with missing alive threads.
|
2018-05-10 04:21:41 +00:00
|
|
|
// Code will just remember that the list can be incomplete but it will
|
2018-05-10 04:02:59 +00:00
|
|
|
// continue reads to return as much as possible.
|
|
|
|
if (!first_read) {
|
|
|
|
// The first one was a short-read by definition.
|
|
|
|
result = Incomplete;
|
|
|
|
} else if (read > buffer_.size() - 1024) {
|
|
|
|
// Read was close to the buffer size. So double the size and assume the
|
|
|
|
// worst.
|
|
|
|
buffer_.resize(buffer_.size() * 2);
|
|
|
|
result = Incomplete;
|
|
|
|
} else if (!threads->empty() && !IsAlive(threads->back())) {
|
|
|
|
// Maybe Linux early returned from read on terminated thread (!pid_alive)
|
|
|
|
// and failed to restore read position.
|
|
|
|
// See next_tid and proc_task_instantiate in Linux.
|
|
|
|
result = Incomplete;
|
2018-05-07 23:29:48 +00:00
|
|
|
}
|
|
|
|
}
|
2018-05-10 04:02:59 +00:00
|
|
|
}
|
|
|
|
|
2024-10-10 20:56:25 -07:00
|
|
|
const char *ThreadLister::LoadStatus(tid_t tid) {
|
2024-10-10 20:57:34 -07:00
|
|
|
status_path_.clear();
|
|
|
|
status_path_.AppendF("%s/%llu/status", task_path_.data(), tid);
|
2024-10-10 14:52:50 -07:00
|
|
|
auto cleanup = at_scope_exit([&] {
|
|
|
|
// Resize back to capacity if it is downsized by `ReadFileToVector`.
|
|
|
|
buffer_.resize(buffer_.capacity());
|
|
|
|
});
|
|
|
|
if (!ReadFileToVector(status_path_.data(), &buffer_) || buffer_.empty())
|
|
|
|
return nullptr;
|
|
|
|
buffer_.push_back('\0');
|
|
|
|
return buffer_.data();
|
|
|
|
}
|
|
|
|
|
2024-10-10 20:56:25 -07:00
|
|
|
bool ThreadLister::IsAlive(tid_t tid) {
|
2018-05-10 04:02:59 +00:00
|
|
|
// /proc/%d/task/%d/status uses same call to detect alive threads as
|
|
|
|
// proc_task_readdir. See task_state implementation in Linux.
|
|
|
|
static const char kPrefix[] = "\nPPid:";
|
2024-10-10 14:52:50 -07:00
|
|
|
const char *status = LoadStatus(tid);
|
|
|
|
if (!status)
|
|
|
|
return false;
|
|
|
|
const char *field = internal_strstr(status, kPrefix);
|
2018-05-10 04:02:59 +00:00
|
|
|
if (!field)
|
|
|
|
return false;
|
|
|
|
field += internal_strlen(kPrefix);
|
|
|
|
return (int)internal_atoll(field) != 0;
|
2013-02-27 11:22:40 +00:00
|
|
|
}
|
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2013-02-27 11:22:40 +00:00
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_WORDSIZE == 32
|
2017-07-06 17:17:50 +00:00
|
|
|
// Take care of unusable kernel area in top gigabyte.
|
|
|
|
static uptr GetKernelAreaSize() {
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_LINUX && !SANITIZER_X32
|
2017-07-06 17:17:50 +00:00
|
|
|
const uptr gbyte = 1UL << 30;
|
|
|
|
|
|
|
|
// Firstly check if there are writable segments
|
|
|
|
// mapped to top gigabyte (e.g. stack).
|
2023-11-27 23:17:03 +01:00
|
|
|
MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
|
2019-01-08 01:07:34 +00:00
|
|
|
if (proc_maps.Error())
|
|
|
|
return 0;
|
2017-07-11 18:54:00 +00:00
|
|
|
MemoryMappedSegment segment;
|
|
|
|
while (proc_maps.Next(&segment)) {
|
2023-11-27 23:17:03 +01:00
|
|
|
if ((segment.end >= 3 * gbyte) && segment.IsWritable())
|
|
|
|
return 0;
|
2017-07-06 17:17:50 +00:00
|
|
|
}
|
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if !SANITIZER_ANDROID
|
2017-07-06 17:17:50 +00:00
|
|
|
// Even if nothing is mapped, top Gb may still be accessible
|
|
|
|
// if we are running on 64-bit kernel.
|
|
|
|
// Uname may report misleading results if personality type
|
|
|
|
// is modified (e.g. under schroot) so check this as well.
|
|
|
|
struct utsname uname_info;
|
|
|
|
int pers = personality(0xffffffffUL);
|
2020-03-26 13:35:09 +01:00
|
|
|
if (!(pers & PER_MASK) && internal_uname(&uname_info) == 0 &&
|
|
|
|
internal_strstr(uname_info.machine, "64"))
|
2017-07-06 17:17:50 +00:00
|
|
|
return 0;
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif // SANITIZER_ANDROID
|
2017-07-06 17:17:50 +00:00
|
|
|
|
|
|
|
// Top gigabyte is reserved for kernel.
|
|
|
|
return gbyte;
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2017-07-06 17:17:50 +00:00
|
|
|
return 0;
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif // SANITIZER_LINUX && !SANITIZER_X32
|
2017-07-06 17:17:50 +00:00
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif // SANITIZER_WORDSIZE == 32
|
2017-07-06 17:17:50 +00:00
|
|
|
|
2017-11-20 17:41:57 +00:00
|
|
|
uptr GetMaxVirtualAddress() {
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_NETBSD && defined(__x86_64__)
|
2017-08-08 20:36:10 +00:00
|
|
|
return 0x7f7ffffff000ULL; // (0x00007f8000000000 - PAGE_SIZE)
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif SANITIZER_WORDSIZE == 64
|
2024-07-18 18:02:50 +08:00
|
|
|
# if defined(__powerpc64__) || defined(__aarch64__) || \
|
|
|
|
defined(__loongarch__) || SANITIZER_RISCV64
|
2017-07-06 17:13:40 +00:00
|
|
|
// On PowerPC64 we have two different address space layouts: 44- and 46-bit.
|
|
|
|
// We somehow need to figure out which one we are using now and choose
|
|
|
|
// one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
|
|
|
|
// Note that with 'ulimit -s unlimited' the stack is moved away from the top
|
|
|
|
// of the address space, so simply checking the stack address is not enough.
|
|
|
|
// This should (does) work for both PowerPC64 Endian modes.
|
|
|
|
// Similarly, aarch64 has multiple address space layouts: 39, 42 and 47-bit.
|
2022-11-10 13:32:24 +08:00
|
|
|
// loongarch64 also has multiple address space layouts: default is 47-bit.
|
2024-07-18 18:02:50 +08:00
|
|
|
// RISC-V 64 also has multiple address space layouts: 39, 48 and 57-bit.
|
2017-07-06 17:13:40 +00:00
|
|
|
return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1;
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif SANITIZER_MIPS64
|
2017-07-06 17:13:40 +00:00
|
|
|
return (1ULL << 40) - 1; // 0x000000ffffffffffUL;
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif defined(__s390x__)
|
2017-07-06 17:13:40 +00:00
|
|
|
return (1ULL << 53) - 1; // 0x001fffffffffffffUL;
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif defined(__sparc__)
|
SanitizerCommon: 64-bit SPARC/Linux port
Summary:
This patch contains the bits required to make the common 32-bit allocator work on SPARC64/Linux.
Patch by Eric Botcazou.
Reviewers: #sanitizers, vitalybuka
Reviewed By: #sanitizers, vitalybuka
Subscribers: krytarowski, vitalybuka, ro, jyknight, kubamracek, fedor.sergeev, jdoerfert, llvm-commits, #sanitizers
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D58432
llvm-svn: 355978
2019-03-12 21:02:04 +00:00
|
|
|
return ~(uptr)0;
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2017-07-06 17:13:40 +00:00
|
|
|
return (1ULL << 47) - 1; // 0x00007fffffffffffUL;
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
|
|
|
# else // SANITIZER_WORDSIZE == 32
|
|
|
|
# if defined(__s390__)
|
2017-07-06 17:13:40 +00:00
|
|
|
return (1ULL << 31) - 1; // 0x7fffffff;
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2017-11-20 17:41:57 +00:00
|
|
|
return (1ULL << 32) - 1; // 0xffffffff;
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
|
|
|
# endif // SANITIZER_WORDSIZE
|
2017-07-06 17:13:40 +00:00
|
|
|
}
|
|
|
|
|
2017-11-20 17:41:57 +00:00
|
|
|
uptr GetMaxUserVirtualAddress() {
|
|
|
|
uptr addr = GetMaxVirtualAddress();
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_WORDSIZE == 32 && !defined(__s390__)
|
2017-11-20 17:41:57 +00:00
|
|
|
if (!common_flags()->full_address_space)
|
|
|
|
addr -= GetKernelAreaSize();
|
|
|
|
CHECK_LT(reinterpret_cast<uptr>(&addr), addr);
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2017-11-20 17:41:57 +00:00
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
2024-06-17 15:04:57 -07:00
|
|
|
# if !SANITIZER_ANDROID || defined(__aarch64__)
|
2013-05-20 17:05:29 +00:00
|
|
|
uptr GetPageSize() {
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) && \
|
|
|
|
defined(EXEC_PAGESIZE)
|
2013-05-20 17:05:29 +00:00
|
|
|
return EXEC_PAGESIZE;
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif SANITIZER_FREEBSD || SANITIZER_NETBSD
|
|
|
|
// Use sysctl as sysconf can trigger interceptors internally.
|
2018-12-04 19:00:38 +00:00
|
|
|
int pz = 0;
|
|
|
|
uptr pzl = sizeof(pz);
|
|
|
|
int mib[2] = {CTL_HW, HW_PAGESIZE};
|
|
|
|
int rv = internal_sysctl(mib, 2, &pz, &pzl, nullptr, 0);
|
|
|
|
CHECK_EQ(rv, 0);
|
|
|
|
return (uptr)pz;
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif SANITIZER_USE_GETAUXVAL
|
2025-02-07 00:40:22 +07:00
|
|
|
# if SANITIZER_ANDROID && __ANDROID_API__ < 35
|
|
|
|
// The 16 KB page size was introduced in Android 15 (API level 35), while
|
|
|
|
// earlier versions of Android always used a 4 KB page size.
|
|
|
|
// We are checking the weak definition of `strerrorname_np` (introduced in API
|
|
|
|
// level 35) because some earlier API levels crashed when
|
|
|
|
// `getauxval(AT_PAGESZ)` was called from the `.preinit_array`.
|
|
|
|
if (!strerrorname_np)
|
|
|
|
return 4096;
|
|
|
|
# endif
|
|
|
|
|
2019-09-12 18:57:58 +00:00
|
|
|
return getauxval(AT_PAGESZ);
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2013-05-21 06:15:50 +00:00
|
|
|
return sysconf(_SC_PAGESIZE); // EXEC_PAGESIZE may not be trustworthy.
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2013-05-20 17:05:29 +00:00
|
|
|
}
|
2024-06-17 15:04:57 -07:00
|
|
|
# endif
|
2013-05-20 17:05:29 +00:00
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
uptr ReadBinaryName(/*out*/ char *buf, uptr buf_len) {
|
2025-04-11 16:21:00 -04:00
|
|
|
# if SANITIZER_HAIKU
|
|
|
|
int cookie = 0;
|
|
|
|
image_info info;
|
|
|
|
const char *argv0 = "<UNKNOWN>";
|
|
|
|
while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) {
|
|
|
|
if (info.type != B_APP_IMAGE)
|
|
|
|
continue;
|
|
|
|
argv0 = info.name;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
internal_strncpy(buf, argv0, buf_len);
|
|
|
|
return internal_strlen(buf);
|
|
|
|
# elif SANITIZER_SOLARIS
|
[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-14 20:14:29 +00:00
|
|
|
const char *default_module_name = getexecname();
|
|
|
|
CHECK_NE(default_module_name, NULL);
|
|
|
|
return internal_snprintf(buf, buf_len, "%s", default_module_name);
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
|
|
|
# if SANITIZER_FREEBSD || SANITIZER_NETBSD
|
|
|
|
# if SANITIZER_FREEBSD
|
2017-08-08 20:36:10 +00:00
|
|
|
const int Mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2017-08-08 20:36:10 +00:00
|
|
|
const int Mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME};
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2015-06-04 07:29:43 +00:00
|
|
|
const char *default_module_name = "kern.proc.pathname";
|
2018-08-31 08:10:06 +00:00
|
|
|
uptr Size = buf_len;
|
|
|
|
bool IsErr =
|
|
|
|
(internal_sysctl(Mib, ARRAY_SIZE(Mib), buf, &Size, NULL, 0) != 0);
|
2014-05-29 12:12:42 +00:00
|
|
|
int readlink_error = IsErr ? errno : 0;
|
|
|
|
uptr module_name_len = Size;
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2015-06-04 07:29:43 +00:00
|
|
|
const char *default_module_name = "/proc/self/exe";
|
2023-11-27 23:17:03 +01:00
|
|
|
uptr module_name_len = internal_readlink(default_module_name, buf, buf_len);
|
2013-09-10 14:36:16 +00:00
|
|
|
int readlink_error;
|
2014-05-29 12:12:42 +00:00
|
|
|
bool IsErr = internal_iserror(module_name_len, &readlink_error);
|
2024-06-20 13:32:08 -07:00
|
|
|
# endif
|
2014-05-29 12:12:42 +00:00
|
|
|
if (IsErr) {
|
2015-06-04 07:29:43 +00:00
|
|
|
// We can't read binary name for some reason, assume it's unknown.
|
2023-11-27 23:17:03 +01:00
|
|
|
Report(
|
|
|
|
"WARNING: reading executable name failed with errno %d, "
|
|
|
|
"some stack frames may not be symbolized\n",
|
|
|
|
readlink_error);
|
|
|
|
module_name_len =
|
|
|
|
internal_snprintf(buf, buf_len, "%s", default_module_name);
|
2013-09-10 14:36:16 +00:00
|
|
|
CHECK_LT(module_name_len, buf_len);
|
|
|
|
}
|
|
|
|
return module_name_len;
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2013-09-10 14:36:16 +00:00
|
|
|
}
|
|
|
|
|
2015-07-28 21:01:42 +00:00
|
|
|
uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) {
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_LINUX
|
2015-07-28 20:27:51 +00:00
|
|
|
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);
|
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2015-07-28 20:27:51 +00:00
|
|
|
return ReadBinaryName(buf, buf_len);
|
|
|
|
}
|
|
|
|
|
2013-05-14 13:24:46 +00: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--;
|
2023-11-27 23:17:03 +01:00
|
|
|
if (*name == '/')
|
|
|
|
name++;
|
2013-05-14 13:24:46 +00:00
|
|
|
uptr base_name_length = internal_strlen(base_name);
|
2023-11-27 23:17:03 +01:00
|
|
|
if (internal_strncmp(name, base_name, base_name_length))
|
|
|
|
return false;
|
2013-05-14 13:24:46 +00:00
|
|
|
return (name[base_name_length] == '-' || name[base_name_length] == '.');
|
|
|
|
}
|
|
|
|
|
2025-04-11 16:21:00 -04:00
|
|
|
# if !SANITIZER_ANDROID && !SANITIZER_HAIKU
|
2013-07-29 19:09:49 +00:00
|
|
|
// Call cb for each region mapped by map.
|
|
|
|
void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
|
2015-01-30 12:43:52 +00:00
|
|
|
CHECK_NE(map, nullptr);
|
2025-04-11 16:21:00 -04:00
|
|
|
# if !SANITIZER_FREEBSD && !SANITIZER_HAIKU
|
2013-07-29 19:09:49 +00:00
|
|
|
typedef ElfW(Phdr) Elf_Phdr;
|
|
|
|
typedef ElfW(Ehdr) Elf_Ehdr;
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif // !SANITIZER_FREEBSD
|
2013-07-29 19:09:49 +00: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-29 20:13:41 +00:00
|
|
|
uptr preferred_base = (uptr)-1;
|
2013-07-29 19:09:49 +00: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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2013-07-29 19:09:49 +00:00
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_LINUX
|
|
|
|
# if defined(__x86_64__)
|
2013-09-02 11:36:19 +00: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-06 17:47:39 +00: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 11:36:19 +00:00
|
|
|
__asm__ __volatile__(
|
2023-11-27 23:17:03 +01:00
|
|
|
/* %rax = syscall(%rax = SYSCALL(clone),
|
|
|
|
* %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. */
|
|
|
|
// 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.
|
|
|
|
"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)
|
|
|
|
: "a"(SYSCALL(clone)), "i"(SYSCALL(exit)), "S"(child_stack), "D"(flags),
|
|
|
|
"d"(parent_tidptr), "r"(r8), "r"(r10)
|
|
|
|
: "memory", "r11", "rcx");
|
2013-09-02 11:36:19 +00:00
|
|
|
return res;
|
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif defined(__mips__)
|
2015-02-19 07:30:39 +00:00
|
|
|
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
|
|
|
|
int *parent_tidptr, void *newtls, int *child_tidptr) {
|
2015-05-06 05:38:21 +00: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__(
|
2023-11-27 23:17:03 +01:00
|
|
|
/* $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)". */
|
|
|
|
# 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
|
|
|
|
"ld $25,0($29);\n"
|
|
|
|
"ld $4,8($29);\n"
|
|
|
|
# endif
|
|
|
|
"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");
|
2015-05-06 05:38:21 +00:00
|
|
|
return res;
|
2015-02-19 07:30:39 +00:00
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif SANITIZER_RISCV64
|
2020-09-22 22:10:13 -07:00
|
|
|
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
|
|
|
|
int *parent_tidptr, void *newtls, int *child_tidptr) {
|
|
|
|
if (!fn || !child_stack)
|
|
|
|
return -EINVAL;
|
2021-03-08 22:28:19 +00:00
|
|
|
|
2020-09-22 22:10:13 -07:00
|
|
|
CHECK_EQ(0, (uptr)child_stack % 16);
|
|
|
|
|
2021-03-08 22:28:19 +00:00
|
|
|
register int res __asm__("a0");
|
|
|
|
register int __flags __asm__("a0") = flags;
|
|
|
|
register void *__stack __asm__("a1") = child_stack;
|
|
|
|
register int *__ptid __asm__("a2") = parent_tidptr;
|
|
|
|
register void *__tls __asm__("a3") = newtls;
|
|
|
|
register int *__ctid __asm__("a4") = child_tidptr;
|
|
|
|
register int (*__fn)(void *) __asm__("a5") = fn;
|
|
|
|
register void *__arg __asm__("a6") = arg;
|
|
|
|
register int nr_clone __asm__("a7") = __NR_clone;
|
|
|
|
|
|
|
|
__asm__ __volatile__(
|
|
|
|
"ecall\n"
|
|
|
|
|
|
|
|
/* if (a0 != 0)
|
|
|
|
* return a0;
|
|
|
|
*/
|
|
|
|
"bnez a0, 1f\n"
|
|
|
|
|
|
|
|
// In the child, now. Call "fn(arg)".
|
|
|
|
"mv a0, a6\n"
|
|
|
|
"jalr a5\n"
|
|
|
|
|
|
|
|
// Call _exit(a0).
|
|
|
|
"addi a7, zero, %9\n"
|
|
|
|
"ecall\n"
|
|
|
|
"1:\n"
|
|
|
|
|
|
|
|
: "=r"(res)
|
|
|
|
: "0"(__flags), "r"(__stack), "r"(__ptid), "r"(__tls), "r"(__ctid),
|
|
|
|
"r"(__fn), "r"(__arg), "r"(nr_clone), "i"(__NR_exit)
|
|
|
|
: "memory");
|
|
|
|
return res;
|
2020-09-22 22:10:13 -07:00
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif defined(__aarch64__)
|
2015-08-05 15:17:59 +00:00
|
|
|
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
|
|
|
|
int *parent_tidptr, void *newtls, int *child_tidptr) {
|
2021-11-14 09:45:40 +09:00
|
|
|
register long long res __asm__("x0");
|
2015-08-05 15:17:59 +00:00
|
|
|
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;
|
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
register int (*__fn)(void *) __asm__("x0") = fn;
|
2015-08-05 15:17:59 +00:00
|
|
|
register void *__stack __asm__("x1") = child_stack;
|
2023-11-27 23:17:03 +01:00
|
|
|
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;
|
2015-08-05 15:17:59 +00:00
|
|
|
|
|
|
|
__asm__ __volatile__(
|
2023-11-27 23:17:03 +01:00
|
|
|
"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");
|
2015-08-05 15:17:59 +00:00
|
|
|
return res;
|
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif SANITIZER_LOONGARCH64
|
2022-12-08 10:08:45 +08:00
|
|
|
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
|
|
|
|
int *parent_tidptr, void *newtls, int *child_tidptr) {
|
|
|
|
if (!fn || !child_stack)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
CHECK_EQ(0, (uptr)child_stack % 16);
|
|
|
|
|
|
|
|
register int res __asm__("$a0");
|
|
|
|
register int __flags __asm__("$a0") = flags;
|
|
|
|
register void *__stack __asm__("$a1") = child_stack;
|
|
|
|
register int *__ptid __asm__("$a2") = parent_tidptr;
|
2022-12-10 11:50:35 +08:00
|
|
|
register int *__ctid __asm__("$a3") = child_tidptr;
|
|
|
|
register void *__tls __asm__("$a4") = newtls;
|
2022-12-08 10:08:45 +08:00
|
|
|
register int (*__fn)(void *) __asm__("$a5") = fn;
|
|
|
|
register void *__arg __asm__("$a6") = arg;
|
|
|
|
register int nr_clone __asm__("$a7") = __NR_clone;
|
|
|
|
|
|
|
|
__asm__ __volatile__(
|
|
|
|
"syscall 0\n"
|
|
|
|
|
|
|
|
// if ($a0 != 0)
|
|
|
|
// return $a0;
|
|
|
|
"bnez $a0, 1f\n"
|
|
|
|
|
|
|
|
// In the child, now. Call "fn(arg)".
|
|
|
|
"move $a0, $a6\n"
|
2022-12-10 11:50:35 +08:00
|
|
|
"jirl $ra, $a5, 0\n"
|
2022-12-08 10:08:45 +08:00
|
|
|
|
|
|
|
// Call _exit($a0).
|
|
|
|
"addi.d $a7, $zero, %9\n"
|
|
|
|
"syscall 0\n"
|
2022-12-10 11:50:35 +08:00
|
|
|
|
2022-12-08 10:08:45 +08:00
|
|
|
"1:\n"
|
|
|
|
|
|
|
|
: "=r"(res)
|
2022-12-10 11:50:35 +08:00
|
|
|
: "0"(__flags), "r"(__stack), "r"(__ptid), "r"(__ctid), "r"(__tls),
|
2022-12-08 10:08:45 +08:00
|
|
|
"r"(__fn), "r"(__arg), "r"(nr_clone), "i"(__NR_exit)
|
2023-11-27 23:17:03 +01:00
|
|
|
: "memory", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7",
|
|
|
|
"$t8");
|
2022-12-08 10:08:45 +08:00
|
|
|
return res;
|
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif defined(__powerpc64__)
|
2015-12-08 21:54:39 +00:00
|
|
|
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
|
2023-11-27 23:17:03 +01:00
|
|
|
int *parent_tidptr, void *newtls, int *child_tidptr) {
|
2015-12-08 21:54:39 +00:00
|
|
|
long long res;
|
2017-04-10 23:24:50 +00:00
|
|
|
// Stack frame structure.
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_PPC64V1
|
|
|
|
// Back chain == 0 (SP + 112)
|
|
|
|
// Frame (112 bytes):
|
|
|
|
// Parameter save area (SP + 48), 8 doublewords
|
|
|
|
// TOC save area (SP + 40)
|
|
|
|
// Link editor doubleword (SP + 32)
|
|
|
|
// Compiler doubleword (SP + 24)
|
|
|
|
// LR save area (SP + 16)
|
|
|
|
// CR save area (SP + 8)
|
|
|
|
// Back chain (SP + 0)
|
|
|
|
# define FRAME_SIZE 112
|
|
|
|
# define FRAME_TOC_SAVE_OFFSET 40
|
|
|
|
# elif SANITIZER_PPC64V2
|
|
|
|
// Back chain == 0 (SP + 32)
|
|
|
|
// Frame (32 bytes):
|
|
|
|
// TOC save area (SP + 24)
|
|
|
|
// LR save area (SP + 16)
|
|
|
|
// CR save area (SP + 8)
|
|
|
|
// Back chain (SP + 0)
|
|
|
|
# define FRAME_SIZE 32
|
|
|
|
# define FRAME_TOC_SAVE_OFFSET 24
|
|
|
|
# else
|
|
|
|
# error "Unsupported PPC64 ABI"
|
|
|
|
# endif
|
2015-12-08 21:54:39 +00:00
|
|
|
if (!fn || !child_stack)
|
|
|
|
return -EINVAL;
|
|
|
|
CHECK_EQ(0, (uptr)child_stack % 16);
|
|
|
|
|
|
|
|
register int (*__fn)(void *) __asm__("r3") = fn;
|
2023-11-27 23:17:03 +01:00
|
|
|
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 and arg are saved across the syscall */
|
|
|
|
"mr 28, %5\n\t"
|
|
|
|
"mr 27, %8\n\t"
|
|
|
|
|
|
|
|
/* syscall
|
|
|
|
r0 == __NR_clone
|
|
|
|
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"
|
|
|
|
|
|
|
|
/* Set up stack frame */
|
|
|
|
"li 29, 0\n\t"
|
|
|
|
"stdu 29, -8(1)\n\t"
|
|
|
|
"stdu 1, -%12(1)\n\t"
|
|
|
|
/* Do the function call */
|
|
|
|
"std 2, %13(1)\n\t"
|
|
|
|
# if SANITIZER_PPC64V1
|
|
|
|
"ld 0, 0(28)\n\t"
|
|
|
|
"ld 2, 8(28)\n\t"
|
|
|
|
"mtctr 0\n\t"
|
|
|
|
# elif SANITIZER_PPC64V2
|
|
|
|
"mr 12, 28\n\t"
|
|
|
|
"mtctr 12\n\t"
|
|
|
|
# else
|
|
|
|
# error "Unsupported PPC64 ABI"
|
|
|
|
# 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_SIZE), "i"(FRAME_TOC_SAVE_OFFSET)
|
|
|
|
: "cr0", "cr1", "memory", "ctr", "r0", "r27", "r28", "r29");
|
2015-12-08 21:54:39 +00:00
|
|
|
return res;
|
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif defined(__i386__)
|
2017-01-31 07:15:37 +00:00
|
|
|
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
|
|
|
|
int *parent_tidptr, void *newtls, int *child_tidptr) {
|
|
|
|
int res;
|
|
|
|
if (!fn || !child_stack)
|
|
|
|
return -EINVAL;
|
|
|
|
CHECK_EQ(0, (uptr)child_stack % 16);
|
|
|
|
child_stack = (char *)child_stack - 7 * sizeof(unsigned int);
|
|
|
|
((unsigned int *)child_stack)[0] = (uptr)flags;
|
|
|
|
((unsigned int *)child_stack)[1] = (uptr)0;
|
|
|
|
((unsigned int *)child_stack)[2] = (uptr)fn;
|
|
|
|
((unsigned int *)child_stack)[3] = (uptr)arg;
|
|
|
|
__asm__ __volatile__(
|
2023-11-27 23:17:03 +01:00
|
|
|
/* %eax = syscall(%eax = SYSCALL(clone),
|
|
|
|
* %ebx = flags,
|
|
|
|
* %ecx = child_stack,
|
|
|
|
* %edx = parent_tidptr,
|
|
|
|
* %esi = new_tls,
|
|
|
|
* %edi = child_tidptr)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Obtain flags */
|
|
|
|
"movl (%%ecx), %%ebx\n"
|
|
|
|
/* Do the system call */
|
|
|
|
"pushl %%ebx\n"
|
|
|
|
"pushl %%esi\n"
|
|
|
|
"pushl %%edi\n"
|
|
|
|
/* Remember the flag value. */
|
|
|
|
"movl %%ebx, (%%ecx)\n"
|
|
|
|
"int $0x80\n"
|
|
|
|
"popl %%edi\n"
|
|
|
|
"popl %%esi\n"
|
|
|
|
"popl %%ebx\n"
|
|
|
|
|
|
|
|
/* if (%eax != 0)
|
|
|
|
* return;
|
|
|
|
*/
|
|
|
|
|
|
|
|
"test %%eax,%%eax\n"
|
|
|
|
"jnz 1f\n"
|
|
|
|
|
|
|
|
/* terminate the stack frame */
|
|
|
|
"xorl %%ebp,%%ebp\n"
|
|
|
|
/* Call FN. */
|
|
|
|
"call *%%ebx\n"
|
|
|
|
# ifdef PIC
|
|
|
|
"call here\n"
|
|
|
|
"here:\n"
|
|
|
|
"popl %%ebx\n"
|
|
|
|
"addl $_GLOBAL_OFFSET_TABLE_+[.-here], %%ebx\n"
|
|
|
|
# endif
|
|
|
|
/* Call exit */
|
|
|
|
"movl %%eax, %%ebx\n"
|
|
|
|
"movl %2, %%eax\n"
|
|
|
|
"int $0x80\n"
|
|
|
|
"1:\n"
|
|
|
|
: "=a"(res)
|
|
|
|
: "a"(SYSCALL(clone)), "i"(SYSCALL(exit)), "c"(child_stack),
|
|
|
|
"d"(parent_tidptr), "S"(newtls), "D"(child_tidptr)
|
|
|
|
: "memory");
|
2017-01-31 07:15:37 +00:00
|
|
|
return res;
|
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif defined(__arm__)
|
2017-04-11 14:58:26 +00:00
|
|
|
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
|
|
|
|
int *parent_tidptr, void *newtls, int *child_tidptr) {
|
|
|
|
unsigned int res;
|
|
|
|
if (!fn || !child_stack)
|
|
|
|
return -EINVAL;
|
|
|
|
child_stack = (char *)child_stack - 2 * sizeof(unsigned int);
|
|
|
|
((unsigned int *)child_stack)[0] = (uptr)fn;
|
|
|
|
((unsigned int *)child_stack)[1] = (uptr)arg;
|
|
|
|
register int r0 __asm__("r0") = flags;
|
|
|
|
register void *r1 __asm__("r1") = child_stack;
|
|
|
|
register int *r2 __asm__("r2") = parent_tidptr;
|
|
|
|
register void *r3 __asm__("r3") = newtls;
|
|
|
|
register int *r4 __asm__("r4") = child_tidptr;
|
|
|
|
register int r7 __asm__("r7") = __NR_clone;
|
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if __ARM_ARCH > 4 || defined(__ARM_ARCH_4T__)
|
|
|
|
# define ARCH_HAS_BX
|
|
|
|
# endif
|
|
|
|
# if __ARM_ARCH > 4
|
|
|
|
# define ARCH_HAS_BLX
|
|
|
|
# endif
|
2017-04-11 14:58:26 +00:00
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# ifdef ARCH_HAS_BX
|
|
|
|
# ifdef ARCH_HAS_BLX
|
|
|
|
# define BLX(R) "blx " #R "\n"
|
|
|
|
# else
|
|
|
|
# define BLX(R) "mov lr, pc; bx " #R "\n"
|
|
|
|
# endif
|
|
|
|
# else
|
|
|
|
# define BLX(R) "mov lr, pc; mov pc," #R "\n"
|
|
|
|
# endif
|
2017-04-11 14:58:26 +00:00
|
|
|
|
|
|
|
__asm__ __volatile__(
|
2023-11-27 23:17:03 +01:00
|
|
|
/* %r0 = syscall(%r7 = SYSCALL(clone),
|
|
|
|
* %r0 = flags,
|
|
|
|
* %r1 = child_stack,
|
|
|
|
* %r2 = parent_tidptr,
|
|
|
|
* %r3 = new_tls,
|
|
|
|
* %r4 = child_tidptr)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Do the system call */
|
|
|
|
"swi 0x0\n"
|
|
|
|
|
|
|
|
/* if (%r0 != 0)
|
|
|
|
* return %r0;
|
|
|
|
*/
|
|
|
|
"cmp r0, #0\n"
|
|
|
|
"bne 1f\n"
|
|
|
|
|
|
|
|
/* In the child, now. Call "fn(arg)". */
|
|
|
|
"ldr r0, [sp, #4]\n"
|
|
|
|
"ldr ip, [sp], #8\n" BLX(ip)
|
|
|
|
/* Call _exit(%r0). */
|
|
|
|
"mov r7, %7\n"
|
|
|
|
"swi 0x0\n"
|
|
|
|
"1:\n"
|
|
|
|
"mov %0, r0\n"
|
|
|
|
: "=r"(res)
|
|
|
|
: "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r7), "i"(__NR_exit)
|
|
|
|
: "memory");
|
2017-04-11 14:58:26 +00:00
|
|
|
return res;
|
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
|
|
|
# endif // SANITIZER_LINUX
|
2014-01-23 11:34:41 +00:00
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_LINUX
|
2020-03-26 13:35:09 +01:00
|
|
|
int internal_uname(struct utsname *buf) {
|
|
|
|
return internal_syscall(SYSCALL(uname), buf);
|
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2020-03-26 13:35:09 +01:00
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_ANDROID
|
2015-05-06 18:55:31 +00:00
|
|
|
static int dl_iterate_phdr_test_cb(struct dl_phdr_info *info, size_t size,
|
|
|
|
void *data) {
|
2015-06-29 20:28:55 +00:00
|
|
|
// Any name starting with "lib" indicates a bug in L where library base names
|
2015-05-06 18:55:31 +00: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;
|
|
|
|
|
2018-09-26 23:48:13 +00:00
|
|
|
static AndroidApiLevel AndroidDetectApiLevelStatic() {
|
2025-01-23 13:00:39 -05:00
|
|
|
# if __ANDROID_API__ <= 22
|
2018-09-26 23:48:13 +00:00
|
|
|
return ANDROID_LOLLIPOP_MR1;
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2018-09-26 23:48:13 +00:00
|
|
|
return ANDROID_POST_LOLLIPOP;
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2018-09-26 23:48:13 +00:00
|
|
|
}
|
|
|
|
|
2015-06-29 20:28:55 +00:00
|
|
|
static AndroidApiLevel AndroidDetectApiLevel() {
|
2015-05-06 18:55:31 +00:00
|
|
|
bool base_name_seen = false;
|
|
|
|
dl_iterate_phdr(dl_iterate_phdr_test_cb, &base_name_seen);
|
|
|
|
if (base_name_seen)
|
2023-11-27 23:17:03 +01:00
|
|
|
return ANDROID_LOLLIPOP_MR1; // L MR1
|
2015-06-29 20:28:55 +00:00
|
|
|
return ANDROID_POST_LOLLIPOP; // post-L
|
2015-05-06 18:55:31 +00:00
|
|
|
// Plain L (API level 21) is completely broken wrt ASan and not very
|
|
|
|
// interesting to detect.
|
|
|
|
}
|
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
extern "C" __attribute__((weak)) void *_DYNAMIC;
|
2018-09-26 23:48:13 +00:00
|
|
|
|
2015-06-29 20:28:55 +00:00
|
|
|
AndroidApiLevel AndroidGetApiLevel() {
|
|
|
|
AndroidApiLevel level =
|
|
|
|
(AndroidApiLevel)atomic_load(&android_api_level, memory_order_relaxed);
|
2023-11-27 23:17:03 +01:00
|
|
|
if (level)
|
|
|
|
return level;
|
2018-09-26 23:48:13 +00:00
|
|
|
level = &_DYNAMIC == nullptr ? AndroidDetectApiLevelStatic()
|
|
|
|
: AndroidDetectApiLevel();
|
2015-05-06 18:55:31 +00:00
|
|
|
atomic_store(&android_api_level, level, memory_order_relaxed);
|
|
|
|
return level;
|
|
|
|
}
|
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2014-01-23 11:34:41 +00:00
|
|
|
|
2017-06-15 00:19:13 +00:00
|
|
|
static HandleSignalMode GetHandleSignalModeImpl(int signum) {
|
2017-05-18 23:13:22 +00:00
|
|
|
switch (signum) {
|
|
|
|
case SIGABRT:
|
|
|
|
return common_flags()->handle_abort;
|
|
|
|
case SIGILL:
|
|
|
|
return common_flags()->handle_sigill;
|
2018-02-21 19:52:23 +00:00
|
|
|
case SIGTRAP:
|
|
|
|
return common_flags()->handle_sigtrap;
|
2017-05-18 23:13:22 +00:00
|
|
|
case SIGFPE:
|
|
|
|
return common_flags()->handle_sigfpe;
|
|
|
|
case SIGSEGV:
|
|
|
|
return common_flags()->handle_segv;
|
|
|
|
case SIGBUS:
|
|
|
|
return common_flags()->handle_sigbus;
|
|
|
|
}
|
2017-05-25 23:42:33 +00:00
|
|
|
return kHandleSignalNo;
|
2014-01-31 13:10:07 +00:00
|
|
|
}
|
|
|
|
|
2017-06-15 00:19:13 +00:00
|
|
|
HandleSignalMode GetHandleSignalMode(int signum) {
|
|
|
|
HandleSignalMode result = GetHandleSignalModeImpl(signum);
|
|
|
|
if (result == kHandleSignalYes && !common_flags()->allow_user_segv_handler)
|
|
|
|
return kHandleSignalExclusive;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if !SANITIZER_GO
|
2020-01-23 13:01:08 -08:00
|
|
|
void *internal_start_thread(void *(*func)(void *arg), void *arg) {
|
2024-06-25 09:42:01 -07:00
|
|
|
if (&internal_pthread_create == 0)
|
2021-11-23 20:05:25 -08:00
|
|
|
return nullptr;
|
2014-12-16 19:13:01 +00:00
|
|
|
// Start the thread with signals blocked, otherwise it can steal user signals.
|
2021-11-08 18:45:22 -08:00
|
|
|
ScopedBlockSignals block(nullptr);
|
2014-12-16 19:13:01 +00:00
|
|
|
void *th;
|
2024-06-25 09:42:01 -07:00
|
|
|
internal_pthread_create(&th, nullptr, func, arg);
|
2014-12-16 19:13:01 +00:00
|
|
|
return th;
|
|
|
|
}
|
|
|
|
|
|
|
|
void internal_join_thread(void *th) {
|
2024-06-25 09:42:01 -07:00
|
|
|
if (&internal_pthread_join)
|
|
|
|
internal_pthread_join(th, nullptr);
|
2014-12-16 19:13:01 +00:00
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2020-01-23 13:01:08 -08:00
|
|
|
void *internal_start_thread(void *(*func)(void *), void *arg) { return 0; }
|
2015-01-07 02:12:41 +00:00
|
|
|
|
|
|
|
void internal_join_thread(void *th) {}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2014-12-16 19:13:01 +00:00
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_LINUX && defined(__aarch64__)
|
2016-02-08 22:50:25 +00:00
|
|
|
// 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;
|
2021-11-06 22:26:05 -08:00
|
|
|
u8 *aux = reinterpret_cast<u8 *>(ucontext->uc_mcontext.__reserved);
|
2016-02-08 22:50:25 +00:00
|
|
|
while (true) {
|
|
|
|
_aarch64_ctx *ctx = (_aarch64_ctx *)aux;
|
2023-11-27 23:17:03 +01:00
|
|
|
if (ctx->size == 0)
|
|
|
|
break;
|
2016-02-08 22:50:25 +00:00
|
|
|
if (ctx->magic == kEsrMagic) {
|
|
|
|
*esr = ((__sanitizer_esr_context *)ctx)->esr;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
aux += ctx->size;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif SANITIZER_FREEBSD && defined(__aarch64__)
|
2022-05-16 16:58:45 +01:00
|
|
|
// FreeBSD doesn't provide ESR in the ucontext.
|
2023-11-27 23:17:03 +01:00
|
|
|
static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) { return false; }
|
|
|
|
# endif
|
2016-02-08 22:50:25 +00:00
|
|
|
|
2018-03-23 00:15:10 +00:00
|
|
|
using Context = ucontext_t;
|
2018-03-22 20:42:28 +00:00
|
|
|
|
2017-09-14 02:48:41 +00:00
|
|
|
SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
|
2018-03-23 00:15:10 +00:00
|
|
|
Context *ucontext = (Context *)context;
|
2023-11-27 23:17:03 +01:00
|
|
|
# if defined(__x86_64__) || defined(__i386__)
|
2025-04-11 16:21:00 -04:00
|
|
|
# if !SANITIZER_HAIKU
|
2016-02-08 22:50:25 +00:00
|
|
|
static const uptr PF_WRITE = 1U << 1;
|
2025-04-11 16:21:00 -04:00
|
|
|
# endif
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_FREEBSD
|
2016-02-08 22:50:25 +00:00
|
|
|
uptr err = ucontext->uc_mcontext.mc_err;
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif SANITIZER_NETBSD
|
2017-08-08 20:36:10 +00:00
|
|
|
uptr err = ucontext->uc_mcontext.__gregs[_REG_ERR];
|
2025-04-11 16:21:00 -04:00
|
|
|
# elif SANITIZER_HAIKU
|
|
|
|
uptr err = ucontext->uc_mcontext.r13;
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif SANITIZER_SOLARIS && defined(__i386__)
|
2018-03-22 20:42:28 +00:00
|
|
|
const int Err = 13;
|
|
|
|
uptr err = ucontext->uc_mcontext.gregs[Err];
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2016-02-08 22:50:25 +00:00
|
|
|
uptr err = ucontext->uc_mcontext.gregs[REG_ERR];
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif // SANITIZER_FREEBSD
|
2022-02-02 15:06:01 +01:00
|
|
|
return err & PF_WRITE ? Write : Read;
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif defined(__mips__)
|
2018-04-25 16:21:00 +00:00
|
|
|
uint32_t *exception_source;
|
|
|
|
uint32_t faulty_instruction;
|
|
|
|
uint32_t op_code;
|
|
|
|
|
|
|
|
exception_source = (uint32_t *)ucontext->uc_mcontext.pc;
|
|
|
|
faulty_instruction = (uint32_t)(*exception_source);
|
|
|
|
|
|
|
|
op_code = (faulty_instruction >> 26) & 0x3f;
|
|
|
|
|
|
|
|
// FIXME: Add support for FPU, microMIPS, DSP, MSA memory instructions.
|
|
|
|
switch (op_code) {
|
|
|
|
case 0x28: // sb
|
|
|
|
case 0x29: // sh
|
|
|
|
case 0x2b: // sw
|
|
|
|
case 0x3f: // sd
|
2023-11-27 23:17:03 +01:00
|
|
|
# if __mips_isa_rev < 6
|
2018-04-25 16:21:00 +00:00
|
|
|
case 0x2c: // sdl
|
|
|
|
case 0x2d: // sdr
|
|
|
|
case 0x2a: // swl
|
|
|
|
case 0x2e: // swr
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2022-02-02 15:06:01 +01:00
|
|
|
return SignalContext::Write;
|
2018-04-25 16:21:00 +00:00
|
|
|
|
|
|
|
case 0x20: // lb
|
|
|
|
case 0x24: // lbu
|
|
|
|
case 0x21: // lh
|
|
|
|
case 0x25: // lhu
|
|
|
|
case 0x23: // lw
|
|
|
|
case 0x27: // lwu
|
|
|
|
case 0x37: // ld
|
2023-11-27 23:17:03 +01:00
|
|
|
# if __mips_isa_rev < 6
|
2018-04-25 16:21:00 +00:00
|
|
|
case 0x1a: // ldl
|
|
|
|
case 0x1b: // ldr
|
|
|
|
case 0x22: // lwl
|
|
|
|
case 0x26: // lwr
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2022-02-02 15:06:01 +01:00
|
|
|
return SignalContext::Read;
|
2023-11-27 23:17:03 +01:00
|
|
|
# if __mips_isa_rev == 6
|
2018-04-25 16:21:00 +00:00
|
|
|
case 0x3b: // pcrel
|
|
|
|
op_code = (faulty_instruction >> 19) & 0x3;
|
|
|
|
switch (op_code) {
|
|
|
|
case 0x1: // lwpc
|
|
|
|
case 0x2: // lwupc
|
2022-02-02 15:06:01 +01:00
|
|
|
return SignalContext::Read;
|
2018-04-25 16:21:00 +00:00
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2018-04-25 16:21:00 +00:00
|
|
|
}
|
2022-02-02 15:06:01 +01:00
|
|
|
return SignalContext::Unknown;
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif defined(__arm__)
|
2016-02-08 22:50:25 +00:00
|
|
|
static const uptr FSR_WRITE = 1U << 11;
|
|
|
|
uptr fsr = ucontext->uc_mcontext.error_code;
|
2022-02-02 15:06:01 +01:00
|
|
|
return fsr & FSR_WRITE ? Write : Read;
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif defined(__aarch64__)
|
2016-02-08 22:50:25 +00:00
|
|
|
static const u64 ESR_ELx_WNR = 1U << 6;
|
|
|
|
u64 esr;
|
2023-11-27 23:17:03 +01:00
|
|
|
if (!Aarch64GetESR(ucontext, &esr))
|
|
|
|
return Unknown;
|
2022-02-02 15:06:01 +01:00
|
|
|
return esr & ESR_ELx_WNR ? Write : Read;
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif defined(__loongarch__)
|
2024-09-14 11:19:34 +08:00
|
|
|
// In the musl environment, the Linux kernel uapi sigcontext.h is not
|
|
|
|
// included in signal.h. To avoid missing the SC_ADDRERR_{RD,WR} macros,
|
|
|
|
// copy them here. The LoongArch Linux kernel uapi is already stable,
|
|
|
|
// so there's no need to worry about the value changing.
|
|
|
|
# ifndef SC_ADDRERR_RD
|
|
|
|
// Address error was due to memory load
|
|
|
|
# define SC_ADDRERR_RD (1 << 30)
|
|
|
|
# endif
|
|
|
|
# ifndef SC_ADDRERR_WR
|
|
|
|
// Address error was due to memory store
|
|
|
|
# define SC_ADDRERR_WR (1 << 31)
|
|
|
|
# endif
|
2022-11-10 13:34:19 +08:00
|
|
|
u32 flags = ucontext->uc_mcontext.__flags;
|
|
|
|
if (flags & SC_ADDRERR_RD)
|
|
|
|
return SignalContext::Read;
|
|
|
|
if (flags & SC_ADDRERR_WR)
|
|
|
|
return SignalContext::Write;
|
|
|
|
return SignalContext::Unknown;
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif defined(__sparc__)
|
[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-14 20:14:29 +00:00
|
|
|
// Decode the instruction to determine the access type.
|
|
|
|
// From OpenSolaris $SRC/uts/sun4/os/trap.c (get_accesstype).
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_SOLARIS
|
[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-14 20:14:29 +00:00
|
|
|
uptr pc = ucontext->uc_mcontext.gregs[REG_PC];
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
SanitizerCommon: fixes for unwinding & backtrace on SPARC
Summary:
This patch contains various fixes for the unwinding and backtrace machinery on the SPARC, which doesn't work correctly in various cases. It was tested with GCC on SPARC/Solaris and SPARC/Linux.
Patch by Eric Botcazou.
Reviewers: #sanitizers, vitalybuka
Reviewed By: #sanitizers, vitalybuka
Subscribers: jrtc27, delcypher, vitalybuka, ro, jyknight, kubamracek, fedor.sergeev, jdoerfert, llvm-commits, #sanitizers
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D58431
llvm-svn: 355965
2019-03-12 20:31:53 +00:00
|
|
|
// Historical BSDism here.
|
|
|
|
struct sigcontext *scontext = (struct sigcontext *)context;
|
2023-11-27 23:17:03 +01:00
|
|
|
# if defined(__arch64__)
|
SanitizerCommon: fixes for unwinding & backtrace on SPARC
Summary:
This patch contains various fixes for the unwinding and backtrace machinery on the SPARC, which doesn't work correctly in various cases. It was tested with GCC on SPARC/Solaris and SPARC/Linux.
Patch by Eric Botcazou.
Reviewers: #sanitizers, vitalybuka
Reviewed By: #sanitizers, vitalybuka
Subscribers: jrtc27, delcypher, vitalybuka, ro, jyknight, kubamracek, fedor.sergeev, jdoerfert, llvm-commits, #sanitizers
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D58431
llvm-svn: 355965
2019-03-12 20:31:53 +00:00
|
|
|
uptr pc = scontext->sigc_regs.tpc;
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
SanitizerCommon: fixes for unwinding & backtrace on SPARC
Summary:
This patch contains various fixes for the unwinding and backtrace machinery on the SPARC, which doesn't work correctly in various cases. It was tested with GCC on SPARC/Solaris and SPARC/Linux.
Patch by Eric Botcazou.
Reviewers: #sanitizers, vitalybuka
Reviewed By: #sanitizers, vitalybuka
Subscribers: jrtc27, delcypher, vitalybuka, ro, jyknight, kubamracek, fedor.sergeev, jdoerfert, llvm-commits, #sanitizers
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D58431
llvm-svn: 355965
2019-03-12 20:31:53 +00:00
|
|
|
uptr pc = scontext->si_regs.pc;
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
|
|
|
# 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-14 20:14:29 +00:00
|
|
|
u32 instr = *(u32 *)pc;
|
2023-11-27 23:17:03 +01:00
|
|
|
return (instr >> 21) & 1 ? Write : Read;
|
|
|
|
# elif defined(__riscv)
|
|
|
|
# if SANITIZER_FREEBSD
|
2021-08-26 11:11:56 +01:00
|
|
|
unsigned long pc = ucontext->uc_mcontext.mc_gpregs.gp_sepc;
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2020-03-26 19:54:29 +00:00
|
|
|
unsigned long pc = ucontext->uc_mcontext.__gregs[REG_PC];
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2020-03-26 19:54:29 +00:00
|
|
|
unsigned faulty_instruction = *(uint16_t *)pc;
|
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if defined(__riscv_compressed)
|
2020-03-26 19:54:29 +00:00
|
|
|
if ((faulty_instruction & 0x3) != 0x3) { // it's a compressed instruction
|
|
|
|
// set op_bits to the instruction bits [1, 0, 15, 14, 13]
|
|
|
|
unsigned op_bits =
|
|
|
|
((faulty_instruction & 0x3) << 3) | (faulty_instruction >> 13);
|
|
|
|
unsigned rd = faulty_instruction & 0xF80; // bits 7-11, inclusive
|
|
|
|
switch (op_bits) {
|
|
|
|
case 0b10'010: // c.lwsp (rd != x0)
|
2023-11-27 23:17:03 +01:00
|
|
|
# if __riscv_xlen == 64
|
2020-03-26 19:54:29 +00:00
|
|
|
case 0b10'011: // c.ldsp (rd != x0)
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2022-02-02 15:06:01 +01:00
|
|
|
return rd ? SignalContext::Read : SignalContext::Unknown;
|
2020-03-26 19:54:29 +00:00
|
|
|
case 0b00'010: // c.lw
|
2023-11-27 23:17:03 +01:00
|
|
|
# if __riscv_flen >= 32 && __riscv_xlen == 32
|
2020-03-26 19:54:29 +00:00
|
|
|
case 0b10'011: // c.flwsp
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
|
|
|
# if __riscv_flen >= 32 || __riscv_xlen == 64
|
2020-03-26 19:54:29 +00:00
|
|
|
case 0b00'011: // c.flw / c.ld
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
|
|
|
# if __riscv_flen == 64
|
2020-03-26 19:54:29 +00:00
|
|
|
case 0b00'001: // c.fld
|
|
|
|
case 0b10'001: // c.fldsp
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2022-02-02 15:06:01 +01:00
|
|
|
return SignalContext::Read;
|
2020-03-26 19:54:29 +00:00
|
|
|
case 0b00'110: // c.sw
|
|
|
|
case 0b10'110: // c.swsp
|
2023-11-27 23:17:03 +01:00
|
|
|
# if __riscv_flen >= 32 || __riscv_xlen == 64
|
2020-03-26 19:54:29 +00:00
|
|
|
case 0b00'111: // c.fsw / c.sd
|
|
|
|
case 0b10'111: // c.fswsp / c.sdsp
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
|
|
|
# if __riscv_flen == 64
|
2020-03-26 19:54:29 +00:00
|
|
|
case 0b00'101: // c.fsd
|
|
|
|
case 0b10'101: // c.fsdsp
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2022-02-02 15:06:01 +01:00
|
|
|
return SignalContext::Write;
|
2020-03-26 19:54:29 +00:00
|
|
|
default:
|
2022-02-02 15:06:01 +01:00
|
|
|
return SignalContext::Unknown;
|
2020-03-26 19:54:29 +00:00
|
|
|
}
|
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2020-03-26 19:54:29 +00:00
|
|
|
|
|
|
|
unsigned opcode = faulty_instruction & 0x7f; // lower 7 bits
|
|
|
|
unsigned funct3 = (faulty_instruction >> 12) & 0x7; // bits 12-14, inclusive
|
|
|
|
switch (opcode) {
|
|
|
|
case 0b0000011: // loads
|
|
|
|
switch (funct3) {
|
|
|
|
case 0b000: // lb
|
|
|
|
case 0b001: // lh
|
|
|
|
case 0b010: // lw
|
2023-11-27 23:17:03 +01:00
|
|
|
# if __riscv_xlen == 64
|
2020-03-26 19:54:29 +00:00
|
|
|
case 0b011: // ld
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2020-03-26 19:54:29 +00:00
|
|
|
case 0b100: // lbu
|
|
|
|
case 0b101: // lhu
|
2022-02-02 15:06:01 +01:00
|
|
|
return SignalContext::Read;
|
2020-03-26 19:54:29 +00:00
|
|
|
default:
|
2022-02-02 15:06:01 +01:00
|
|
|
return SignalContext::Unknown;
|
2020-03-26 19:54:29 +00:00
|
|
|
}
|
|
|
|
case 0b0100011: // stores
|
|
|
|
switch (funct3) {
|
|
|
|
case 0b000: // sb
|
|
|
|
case 0b001: // sh
|
|
|
|
case 0b010: // sw
|
2023-11-27 23:17:03 +01:00
|
|
|
# if __riscv_xlen == 64
|
2020-03-26 19:54:29 +00:00
|
|
|
case 0b011: // sd
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2022-02-02 15:06:01 +01:00
|
|
|
return SignalContext::Write;
|
2020-03-26 19:54:29 +00:00
|
|
|
default:
|
2022-02-02 15:06:01 +01:00
|
|
|
return SignalContext::Unknown;
|
2020-03-26 19:54:29 +00:00
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# if __riscv_flen >= 32
|
2020-03-26 19:54:29 +00:00
|
|
|
case 0b0000111: // floating-point loads
|
|
|
|
switch (funct3) {
|
|
|
|
case 0b010: // flw
|
2023-11-27 23:17:03 +01:00
|
|
|
# if __riscv_flen == 64
|
2020-03-26 19:54:29 +00:00
|
|
|
case 0b011: // fld
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2022-02-02 15:06:01 +01:00
|
|
|
return SignalContext::Read;
|
2020-03-26 19:54:29 +00:00
|
|
|
default:
|
2022-02-02 15:06:01 +01:00
|
|
|
return SignalContext::Unknown;
|
2020-03-26 19:54:29 +00:00
|
|
|
}
|
|
|
|
case 0b0100111: // floating-point stores
|
|
|
|
switch (funct3) {
|
|
|
|
case 0b010: // fsw
|
2023-11-27 23:17:03 +01:00
|
|
|
# if __riscv_flen == 64
|
2020-03-26 19:54:29 +00:00
|
|
|
case 0b011: // fsd
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2022-02-02 15:06:01 +01:00
|
|
|
return SignalContext::Write;
|
2020-03-26 19:54:29 +00:00
|
|
|
default:
|
2022-02-02 15:06:01 +01:00
|
|
|
return SignalContext::Unknown;
|
2020-03-26 19:54:29 +00:00
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2020-03-26 19:54:29 +00:00
|
|
|
default:
|
2022-02-02 15:06:01 +01:00
|
|
|
return SignalContext::Unknown;
|
2020-03-26 19:54:29 +00:00
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2016-02-09 00:28:57 +00:00
|
|
|
(void)ucontext;
|
2022-02-02 15:06:01 +01:00
|
|
|
return Unknown; // FIXME: Implement.
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2016-02-04 02:02:09 +00:00
|
|
|
}
|
|
|
|
|
2019-10-10 17:19:58 +00:00
|
|
|
bool SignalContext::IsTrueFaultingAddress() const {
|
|
|
|
auto si = static_cast<const siginfo_t *>(siginfo);
|
|
|
|
// SIGSEGV signals without a true fault address have si_code set to 128.
|
|
|
|
return si->si_signo == SIGSEGV && si->si_code != 128;
|
|
|
|
}
|
|
|
|
|
2024-07-19 02:51:45 +03:00
|
|
|
UNUSED
|
|
|
|
static const char *RegNumToRegName(int reg) {
|
|
|
|
switch (reg) {
|
2024-07-30 07:40:37 +01:00
|
|
|
# if SANITIZER_LINUX && SANITIZER_GLIBC || SANITIZER_NETBSD
|
2024-07-19 21:22:33 +01:00
|
|
|
# if defined(__x86_64__)
|
2024-07-30 07:40:37 +01:00
|
|
|
# if SANITIZER_NETBSD
|
|
|
|
# define REG_RAX _REG_RAX
|
|
|
|
# define REG_RBX _REG_RBX
|
|
|
|
# define REG_RCX _REG_RCX
|
|
|
|
# define REG_RDX _REG_RDX
|
|
|
|
# define REG_RDI _REG_RDI
|
|
|
|
# define REG_RSI _REG_RSI
|
|
|
|
# define REG_RBP _REG_RBP
|
|
|
|
# define REG_RSP _REG_RSP
|
|
|
|
# define REG_R8 _REG_R8
|
|
|
|
# define REG_R9 _REG_R9
|
|
|
|
# define REG_R10 _REG_R10
|
|
|
|
# define REG_R11 _REG_R11
|
|
|
|
# define REG_R12 _REG_R12
|
|
|
|
# define REG_R13 _REG_R13
|
|
|
|
# define REG_R14 _REG_R14
|
|
|
|
# define REG_R15 _REG_R15
|
|
|
|
# endif
|
2024-07-19 02:51:45 +03:00
|
|
|
case REG_RAX:
|
|
|
|
return "rax";
|
|
|
|
case REG_RBX:
|
|
|
|
return "rbx";
|
|
|
|
case REG_RCX:
|
|
|
|
return "rcx";
|
|
|
|
case REG_RDX:
|
|
|
|
return "rdx";
|
|
|
|
case REG_RDI:
|
|
|
|
return "rdi";
|
|
|
|
case REG_RSI:
|
|
|
|
return "rsi";
|
|
|
|
case REG_RBP:
|
|
|
|
return "rbp";
|
|
|
|
case REG_RSP:
|
|
|
|
return "rsp";
|
|
|
|
case REG_R8:
|
|
|
|
return "r8";
|
|
|
|
case REG_R9:
|
|
|
|
return "r9";
|
|
|
|
case REG_R10:
|
|
|
|
return "r10";
|
|
|
|
case REG_R11:
|
|
|
|
return "r11";
|
|
|
|
case REG_R12:
|
|
|
|
return "r12";
|
|
|
|
case REG_R13:
|
|
|
|
return "r13";
|
|
|
|
case REG_R14:
|
|
|
|
return "r14";
|
|
|
|
case REG_R15:
|
|
|
|
return "r15";
|
2024-07-19 21:22:33 +01:00
|
|
|
# elif defined(__i386__)
|
2024-07-30 07:40:37 +01:00
|
|
|
# if SANITIZER_NETBSD
|
|
|
|
# define REG_EAX _REG_EAX
|
|
|
|
# define REG_EBX _REG_EBX
|
|
|
|
# define REG_ECX _REG_ECX
|
|
|
|
# define REG_EDX _REG_EDX
|
|
|
|
# define REG_EDI _REG_EDI
|
|
|
|
# define REG_ESI _REG_ESI
|
|
|
|
# define REG_EBP _REG_EBP
|
|
|
|
# define REG_ESP _REG_ESP
|
|
|
|
# endif
|
2024-07-19 02:51:45 +03:00
|
|
|
case REG_EAX:
|
|
|
|
return "eax";
|
|
|
|
case REG_EBX:
|
|
|
|
return "ebx";
|
|
|
|
case REG_ECX:
|
|
|
|
return "ecx";
|
|
|
|
case REG_EDX:
|
|
|
|
return "edx";
|
|
|
|
case REG_EDI:
|
|
|
|
return "edi";
|
|
|
|
case REG_ESI:
|
|
|
|
return "esi";
|
|
|
|
case REG_EBP:
|
|
|
|
return "ebp";
|
|
|
|
case REG_ESP:
|
|
|
|
return "esp";
|
2024-07-25 03:06:32 +03:00
|
|
|
# elif defined(__arm__)
|
|
|
|
# ifdef MAKE_CASE
|
|
|
|
# undef MAKE_CASE
|
|
|
|
# endif
|
|
|
|
# define REG_STR(reg) #reg
|
|
|
|
# define MAKE_CASE(N) \
|
|
|
|
case REG_R##N: \
|
|
|
|
return REG_STR(r##N)
|
|
|
|
MAKE_CASE(0);
|
|
|
|
MAKE_CASE(1);
|
|
|
|
MAKE_CASE(2);
|
|
|
|
MAKE_CASE(3);
|
|
|
|
MAKE_CASE(4);
|
|
|
|
MAKE_CASE(5);
|
|
|
|
MAKE_CASE(6);
|
|
|
|
MAKE_CASE(7);
|
|
|
|
MAKE_CASE(8);
|
|
|
|
MAKE_CASE(9);
|
|
|
|
MAKE_CASE(10);
|
|
|
|
MAKE_CASE(11);
|
|
|
|
MAKE_CASE(12);
|
|
|
|
case REG_R13:
|
|
|
|
return "sp";
|
|
|
|
case REG_R14:
|
|
|
|
return "lr";
|
|
|
|
case REG_R15:
|
|
|
|
return "pc";
|
|
|
|
# elif defined(__aarch64__)
|
|
|
|
# define REG_STR(reg) #reg
|
|
|
|
# define MAKE_CASE(N) \
|
|
|
|
case N: \
|
|
|
|
return REG_STR(x##N)
|
|
|
|
MAKE_CASE(0);
|
|
|
|
MAKE_CASE(1);
|
|
|
|
MAKE_CASE(2);
|
|
|
|
MAKE_CASE(3);
|
|
|
|
MAKE_CASE(4);
|
|
|
|
MAKE_CASE(5);
|
|
|
|
MAKE_CASE(6);
|
|
|
|
MAKE_CASE(7);
|
|
|
|
MAKE_CASE(8);
|
|
|
|
MAKE_CASE(9);
|
|
|
|
MAKE_CASE(10);
|
|
|
|
MAKE_CASE(11);
|
|
|
|
MAKE_CASE(12);
|
|
|
|
MAKE_CASE(13);
|
|
|
|
MAKE_CASE(14);
|
|
|
|
MAKE_CASE(15);
|
|
|
|
MAKE_CASE(16);
|
|
|
|
MAKE_CASE(17);
|
|
|
|
MAKE_CASE(18);
|
|
|
|
MAKE_CASE(19);
|
|
|
|
MAKE_CASE(20);
|
|
|
|
MAKE_CASE(21);
|
|
|
|
MAKE_CASE(22);
|
|
|
|
MAKE_CASE(23);
|
|
|
|
MAKE_CASE(24);
|
|
|
|
MAKE_CASE(25);
|
|
|
|
MAKE_CASE(26);
|
|
|
|
MAKE_CASE(27);
|
|
|
|
MAKE_CASE(28);
|
|
|
|
case 29:
|
|
|
|
return "fp";
|
|
|
|
case 30:
|
|
|
|
return "lr";
|
|
|
|
case 31:
|
|
|
|
return "sp";
|
2024-07-19 21:22:33 +01:00
|
|
|
# endif
|
2024-07-30 09:18:01 +03:00
|
|
|
# endif // SANITIZER_LINUX && SANITIZER_GLIBC
|
2024-07-19 02:51:45 +03:00
|
|
|
default:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2024-08-26 10:07:01 +01:00
|
|
|
# if ((SANITIZER_LINUX && SANITIZER_GLIBC) || SANITIZER_NETBSD) && \
|
2024-07-30 09:18:01 +03:00
|
|
|
(defined(__arm__) || defined(__aarch64__))
|
2024-07-25 03:06:32 +03:00
|
|
|
static uptr GetArmRegister(ucontext_t *ctx, int RegNum) {
|
|
|
|
switch (RegNum) {
|
2024-08-26 10:07:01 +01:00
|
|
|
# if defined(__arm__) && !SANITIZER_NETBSD
|
2024-07-25 03:06:32 +03:00
|
|
|
# ifdef MAKE_CASE
|
|
|
|
# undef MAKE_CASE
|
|
|
|
# endif
|
|
|
|
# define MAKE_CASE(N) \
|
|
|
|
case REG_R##N: \
|
|
|
|
return ctx->uc_mcontext.arm_r##N
|
|
|
|
MAKE_CASE(0);
|
|
|
|
MAKE_CASE(1);
|
|
|
|
MAKE_CASE(2);
|
|
|
|
MAKE_CASE(3);
|
|
|
|
MAKE_CASE(4);
|
|
|
|
MAKE_CASE(5);
|
|
|
|
MAKE_CASE(6);
|
|
|
|
MAKE_CASE(7);
|
|
|
|
MAKE_CASE(8);
|
|
|
|
MAKE_CASE(9);
|
|
|
|
MAKE_CASE(10);
|
|
|
|
case REG_R11:
|
|
|
|
return ctx->uc_mcontext.arm_fp;
|
|
|
|
case REG_R12:
|
|
|
|
return ctx->uc_mcontext.arm_ip;
|
|
|
|
case REG_R13:
|
|
|
|
return ctx->uc_mcontext.arm_sp;
|
|
|
|
case REG_R14:
|
|
|
|
return ctx->uc_mcontext.arm_lr;
|
|
|
|
case REG_R15:
|
|
|
|
return ctx->uc_mcontext.arm_pc;
|
|
|
|
# elif defined(__aarch64__)
|
2024-08-26 10:07:01 +01:00
|
|
|
# if SANITIZER_LINUX
|
2024-07-25 03:06:32 +03:00
|
|
|
case 0 ... 30:
|
|
|
|
return ctx->uc_mcontext.regs[RegNum];
|
|
|
|
case 31:
|
|
|
|
return ctx->uc_mcontext.sp;
|
2024-08-26 10:07:01 +01:00
|
|
|
# elif SANITIZER_NETBSD
|
|
|
|
case 0 ... 31:
|
|
|
|
return ctx->uc_mcontext.__gregs[RegNum];
|
|
|
|
# endif
|
2024-07-25 03:06:32 +03:00
|
|
|
# endif
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2024-07-30 09:18:01 +03:00
|
|
|
# endif // SANITIZER_LINUX && SANITIZER_GLIBC && (defined(__arm__) ||
|
|
|
|
// defined(__aarch64__))
|
2024-07-25 03:06:32 +03:00
|
|
|
|
2024-07-19 02:51:45 +03:00
|
|
|
UNUSED
|
|
|
|
static void DumpSingleReg(ucontext_t *ctx, int RegNum) {
|
|
|
|
const char *RegName = RegNumToRegName(RegNum);
|
2024-07-30 08:27:51 +01:00
|
|
|
# if SANITIZER_LINUX && SANITIZER_GLIBC || SANITIZER_NETBSD
|
|
|
|
# if defined(__x86_64__)
|
2024-07-19 02:51:45 +03:00
|
|
|
Printf("%s%s = 0x%016llx ", internal_strlen(RegName) == 2 ? " " : "",
|
2024-07-30 07:40:37 +01:00
|
|
|
RegName,
|
2024-07-30 08:27:51 +01:00
|
|
|
# if SANITIZER_LINUX
|
2024-07-30 07:40:37 +01:00
|
|
|
ctx->uc_mcontext.gregs[RegNum]
|
2024-07-30 08:27:51 +01:00
|
|
|
# elif SANITIZER_NETBSD
|
2024-07-30 07:40:37 +01:00
|
|
|
ctx->uc_mcontext.__gregs[RegNum]
|
2024-07-30 08:27:51 +01:00
|
|
|
# endif
|
2024-07-30 07:40:37 +01:00
|
|
|
);
|
2024-07-30 08:27:51 +01:00
|
|
|
# elif defined(__i386__)
|
2024-07-30 07:40:37 +01:00
|
|
|
Printf("%s = 0x%08x ", RegName,
|
2024-07-30 08:27:51 +01:00
|
|
|
# if SANITIZER_LINUX
|
2024-07-30 07:40:37 +01:00
|
|
|
ctx->uc_mcontext.gregs[RegNum]
|
2024-07-30 08:27:51 +01:00
|
|
|
# elif SANITIZER_NETBSD
|
2024-07-30 07:40:37 +01:00
|
|
|
ctx->uc_mcontext.__gregs[RegNum]
|
2024-07-30 08:27:51 +01:00
|
|
|
# endif
|
2024-07-30 07:40:37 +01:00
|
|
|
);
|
2024-07-30 08:27:51 +01:00
|
|
|
# elif defined(__arm__)
|
2024-07-25 03:06:32 +03:00
|
|
|
Printf("%s%s = 0x%08zx ", internal_strlen(RegName) == 2 ? " " : "", RegName,
|
|
|
|
GetArmRegister(ctx, RegNum));
|
2024-07-30 08:27:51 +01:00
|
|
|
# elif defined(__aarch64__)
|
2024-07-25 03:06:32 +03:00
|
|
|
Printf("%s%s = 0x%016zx ", internal_strlen(RegName) == 2 ? " " : "", RegName,
|
|
|
|
GetArmRegister(ctx, RegNum));
|
2024-07-30 08:27:51 +01:00
|
|
|
# else
|
|
|
|
(void)RegName;
|
|
|
|
# endif
|
2024-07-25 03:06:32 +03:00
|
|
|
# else
|
2024-07-18 18:38:42 -07:00
|
|
|
(void)RegName;
|
2024-07-24 16:44:25 +02:00
|
|
|
# endif
|
2024-07-25 03:06:32 +03:00
|
|
|
}
|
2024-07-19 02:51:45 +03:00
|
|
|
|
2016-11-26 00:50:08 +00:00
|
|
|
void SignalContext::DumpAllRegisters(void *context) {
|
2024-07-19 02:51:45 +03:00
|
|
|
ucontext_t *ucontext = (ucontext_t *)context;
|
2024-07-30 07:40:37 +01:00
|
|
|
# if SANITIZER_LINUX && SANITIZER_GLIBC || SANITIZER_NETBSD
|
2024-07-19 02:51:45 +03:00
|
|
|
# if defined(__x86_64__)
|
|
|
|
Report("Register values:\n");
|
|
|
|
DumpSingleReg(ucontext, REG_RAX);
|
|
|
|
DumpSingleReg(ucontext, REG_RBX);
|
|
|
|
DumpSingleReg(ucontext, REG_RCX);
|
|
|
|
DumpSingleReg(ucontext, REG_RDX);
|
|
|
|
Printf("\n");
|
|
|
|
DumpSingleReg(ucontext, REG_RDI);
|
|
|
|
DumpSingleReg(ucontext, REG_RSI);
|
|
|
|
DumpSingleReg(ucontext, REG_RBP);
|
|
|
|
DumpSingleReg(ucontext, REG_RSP);
|
|
|
|
Printf("\n");
|
|
|
|
DumpSingleReg(ucontext, REG_R8);
|
|
|
|
DumpSingleReg(ucontext, REG_R9);
|
|
|
|
DumpSingleReg(ucontext, REG_R10);
|
|
|
|
DumpSingleReg(ucontext, REG_R11);
|
|
|
|
Printf("\n");
|
|
|
|
DumpSingleReg(ucontext, REG_R12);
|
|
|
|
DumpSingleReg(ucontext, REG_R13);
|
|
|
|
DumpSingleReg(ucontext, REG_R14);
|
|
|
|
DumpSingleReg(ucontext, REG_R15);
|
|
|
|
Printf("\n");
|
|
|
|
# elif defined(__i386__)
|
|
|
|
// Duplication of this report print is caused by partial support
|
|
|
|
// of register values dumping. In case of unsupported yet architecture let's
|
|
|
|
// avoid printing 'Register values:' without actual values in the following
|
|
|
|
// output.
|
|
|
|
Report("Register values:\n");
|
|
|
|
DumpSingleReg(ucontext, REG_EAX);
|
|
|
|
DumpSingleReg(ucontext, REG_EBX);
|
|
|
|
DumpSingleReg(ucontext, REG_ECX);
|
|
|
|
DumpSingleReg(ucontext, REG_EDX);
|
|
|
|
Printf("\n");
|
|
|
|
DumpSingleReg(ucontext, REG_EDI);
|
|
|
|
DumpSingleReg(ucontext, REG_ESI);
|
|
|
|
DumpSingleReg(ucontext, REG_EBP);
|
|
|
|
DumpSingleReg(ucontext, REG_ESP);
|
|
|
|
Printf("\n");
|
2024-07-30 07:40:37 +01:00
|
|
|
# elif defined(__arm__) && !SANITIZER_NETBSD
|
2024-07-25 03:06:32 +03:00
|
|
|
Report("Register values:\n");
|
|
|
|
DumpSingleReg(ucontext, REG_R0);
|
|
|
|
DumpSingleReg(ucontext, REG_R1);
|
|
|
|
DumpSingleReg(ucontext, REG_R2);
|
|
|
|
DumpSingleReg(ucontext, REG_R3);
|
|
|
|
Printf("\n");
|
|
|
|
DumpSingleReg(ucontext, REG_R4);
|
|
|
|
DumpSingleReg(ucontext, REG_R5);
|
|
|
|
DumpSingleReg(ucontext, REG_R6);
|
|
|
|
DumpSingleReg(ucontext, REG_R7);
|
|
|
|
Printf("\n");
|
|
|
|
DumpSingleReg(ucontext, REG_R8);
|
|
|
|
DumpSingleReg(ucontext, REG_R9);
|
|
|
|
DumpSingleReg(ucontext, REG_R10);
|
|
|
|
DumpSingleReg(ucontext, REG_R11);
|
|
|
|
Printf("\n");
|
|
|
|
DumpSingleReg(ucontext, REG_R12);
|
|
|
|
DumpSingleReg(ucontext, REG_R13);
|
|
|
|
DumpSingleReg(ucontext, REG_R14);
|
|
|
|
DumpSingleReg(ucontext, REG_R15);
|
|
|
|
Printf("\n");
|
2024-08-26 10:07:01 +01:00
|
|
|
# elif defined(__aarch64__)
|
2024-07-25 03:06:32 +03:00
|
|
|
Report("Register values:\n");
|
|
|
|
for (int i = 0; i <= 31; ++i) {
|
|
|
|
DumpSingleReg(ucontext, i);
|
|
|
|
if (i % 4 == 3)
|
|
|
|
Printf("\n");
|
|
|
|
}
|
2024-07-19 21:22:33 +01:00
|
|
|
# else
|
|
|
|
(void)ucontext;
|
2024-07-19 02:51:45 +03:00
|
|
|
# endif
|
2024-07-19 21:22:33 +01:00
|
|
|
# elif SANITIZER_FREEBSD
|
|
|
|
# if defined(__x86_64__)
|
|
|
|
Report("Register values:\n");
|
2024-07-29 22:00:07 +02:00
|
|
|
Printf("rax = 0x%016lx ", ucontext->uc_mcontext.mc_rax);
|
|
|
|
Printf("rbx = 0x%016lx ", ucontext->uc_mcontext.mc_rbx);
|
|
|
|
Printf("rcx = 0x%016lx ", ucontext->uc_mcontext.mc_rcx);
|
|
|
|
Printf("rdx = 0x%016lx ", ucontext->uc_mcontext.mc_rdx);
|
2024-07-19 21:22:33 +01:00
|
|
|
Printf("\n");
|
2024-07-29 22:00:07 +02:00
|
|
|
Printf("rdi = 0x%016lx ", ucontext->uc_mcontext.mc_rdi);
|
|
|
|
Printf("rsi = 0x%016lx ", ucontext->uc_mcontext.mc_rsi);
|
|
|
|
Printf("rbp = 0x%016lx ", ucontext->uc_mcontext.mc_rbp);
|
|
|
|
Printf("rsp = 0x%016lx ", ucontext->uc_mcontext.mc_rsp);
|
2024-07-19 21:22:33 +01:00
|
|
|
Printf("\n");
|
2024-07-29 22:00:07 +02:00
|
|
|
Printf(" r8 = 0x%016lx ", ucontext->uc_mcontext.mc_r8);
|
|
|
|
Printf(" r9 = 0x%016lx ", ucontext->uc_mcontext.mc_r9);
|
|
|
|
Printf("r10 = 0x%016lx ", ucontext->uc_mcontext.mc_r10);
|
|
|
|
Printf("r11 = 0x%016lx ", ucontext->uc_mcontext.mc_r11);
|
2024-07-19 21:22:33 +01:00
|
|
|
Printf("\n");
|
2024-07-29 22:00:07 +02:00
|
|
|
Printf("r12 = 0x%016lx ", ucontext->uc_mcontext.mc_r12);
|
|
|
|
Printf("r13 = 0x%016lx ", ucontext->uc_mcontext.mc_r13);
|
|
|
|
Printf("r14 = 0x%016lx ", ucontext->uc_mcontext.mc_r14);
|
|
|
|
Printf("r15 = 0x%016lx ", ucontext->uc_mcontext.mc_r15);
|
2024-07-19 21:22:33 +01:00
|
|
|
Printf("\n");
|
2024-07-19 22:38:01 +01:00
|
|
|
# elif defined(__i386__)
|
|
|
|
Report("Register values:\n");
|
|
|
|
Printf("eax = 0x%08x ", ucontext->uc_mcontext.mc_eax);
|
|
|
|
Printf("ebx = 0x%08x ", ucontext->uc_mcontext.mc_ebx);
|
|
|
|
Printf("ecx = 0x%08x ", ucontext->uc_mcontext.mc_ecx);
|
|
|
|
Printf("edx = 0x%08x ", ucontext->uc_mcontext.mc_edx);
|
|
|
|
Printf("\n");
|
|
|
|
Printf("edi = 0x%08x ", ucontext->uc_mcontext.mc_edi);
|
|
|
|
Printf("esi = 0x%08x ", ucontext->uc_mcontext.mc_esi);
|
|
|
|
Printf("ebp = 0x%08x ", ucontext->uc_mcontext.mc_ebp);
|
|
|
|
Printf("esp = 0x%08x ", ucontext->uc_mcontext.mc_esp);
|
|
|
|
Printf("\n");
|
2024-07-19 21:22:33 +01:00
|
|
|
# else
|
2024-07-19 02:51:45 +03:00
|
|
|
(void)ucontext;
|
2024-07-19 21:22:33 +01:00
|
|
|
# endif
|
2024-07-30 08:27:51 +01:00
|
|
|
# else
|
|
|
|
(void)ucontext;
|
2024-07-19 02:51:45 +03:00
|
|
|
# endif
|
|
|
|
// FIXME: Implement this for other OSes and architectures.
|
2016-11-26 00:50:08 +00:00
|
|
|
}
|
|
|
|
|
2017-09-14 02:48:41 +00:00
|
|
|
static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_NETBSD
|
Recognize all NetBSD architectures in UBSan
Summary:
Use uniform accessors for Program Pointer,
Stack Pointer and Frame Pointer.
Remove CPU check in UBSan supported platforms
and rely only on the OS type.
This adds NetBSD support in GetPcSpBp() for:
- ARM
- ARM64
- HPPA
- PowerPC/PowerPC64
- SPARC/SPARC64
- MIPS
- DEC Alpha AXP
- DEC VAX
- M68K and M68010
- SH3
- IA64
- OR1K
- RISCV
Sponsored by <The NetBSD Foundation>
Reviewers: joerg, vitalybuka, ro
Reviewed By: vitalybuka
Subscribers: aemerson, jyknight, sdardis, kubamracek, arichardson, llvm-commits, kristof.beyls, fedor.sergeev, #sanitizers
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D43021
llvm-svn: 325431
2018-02-17 13:35:09 +00:00
|
|
|
// This covers all NetBSD architectures
|
|
|
|
ucontext_t *ucontext = (ucontext_t *)context;
|
|
|
|
*pc = _UC_MACHINE_PC(ucontext);
|
|
|
|
*bp = _UC_MACHINE_FP(ucontext);
|
|
|
|
*sp = _UC_MACHINE_SP(ucontext);
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif defined(__arm__)
|
|
|
|
ucontext_t *ucontext = (ucontext_t *)context;
|
2015-03-02 17:36:02 +00:00
|
|
|
*pc = ucontext->uc_mcontext.arm_pc;
|
|
|
|
*bp = ucontext->uc_mcontext.arm_fp;
|
|
|
|
*sp = ucontext->uc_mcontext.arm_sp;
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif defined(__aarch64__)
|
|
|
|
# if SANITIZER_FREEBSD
|
|
|
|
ucontext_t *ucontext = (ucontext_t *)context;
|
2022-05-16 16:58:45 +01:00
|
|
|
*pc = ucontext->uc_mcontext.mc_gpregs.gp_elr;
|
|
|
|
*bp = ucontext->uc_mcontext.mc_gpregs.gp_x[29];
|
|
|
|
*sp = ucontext->uc_mcontext.mc_gpregs.gp_sp;
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
|
|
|
ucontext_t *ucontext = (ucontext_t *)context;
|
2015-03-02 17:36:02 +00:00
|
|
|
*pc = ucontext->uc_mcontext.pc;
|
|
|
|
*bp = ucontext->uc_mcontext.regs[29];
|
|
|
|
*sp = ucontext->uc_mcontext.sp;
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
|
|
|
# elif defined(__hppa__)
|
|
|
|
ucontext_t *ucontext = (ucontext_t *)context;
|
2015-03-02 17:36:02 +00:00
|
|
|
*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];
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif defined(__x86_64__)
|
|
|
|
# if SANITIZER_FREEBSD
|
|
|
|
ucontext_t *ucontext = (ucontext_t *)context;
|
2015-03-02 17:36:02 +00:00
|
|
|
*pc = ucontext->uc_mcontext.mc_rip;
|
|
|
|
*bp = ucontext->uc_mcontext.mc_rbp;
|
|
|
|
*sp = ucontext->uc_mcontext.mc_rsp;
|
2025-04-11 16:21:00 -04:00
|
|
|
# elif SANITIZER_HAIKU
|
|
|
|
ucontext_t *ucontext = (ucontext_t *)context;
|
|
|
|
*pc = ucontext->uc_mcontext.rip;
|
|
|
|
*bp = ucontext->uc_mcontext.rbp;
|
|
|
|
*sp = ucontext->uc_mcontext.rsp;
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
|
|
|
ucontext_t *ucontext = (ucontext_t *)context;
|
2015-03-02 17:36:02 +00:00
|
|
|
*pc = ucontext->uc_mcontext.gregs[REG_RIP];
|
|
|
|
*bp = ucontext->uc_mcontext.gregs[REG_RBP];
|
|
|
|
*sp = ucontext->uc_mcontext.gregs[REG_RSP];
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
|
|
|
# elif defined(__i386__)
|
|
|
|
# if SANITIZER_FREEBSD
|
|
|
|
ucontext_t *ucontext = (ucontext_t *)context;
|
2015-03-02 17:36:02 +00:00
|
|
|
*pc = ucontext->uc_mcontext.mc_eip;
|
|
|
|
*bp = ucontext->uc_mcontext.mc_ebp;
|
|
|
|
*sp = ucontext->uc_mcontext.mc_esp;
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
|
|
|
ucontext_t *ucontext = (ucontext_t *)context;
|
|
|
|
# if SANITIZER_SOLARIS
|
[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-14 20:14:29 +00:00
|
|
|
/* Use the numeric values: the symbolic ones are undefined by llvm
|
|
|
|
include/llvm/Support/Solaris.h. */
|
2023-11-27 23:17:03 +01:00
|
|
|
# ifndef REG_EIP
|
|
|
|
# define REG_EIP 14 // REG_PC
|
|
|
|
# endif
|
|
|
|
# ifndef REG_EBP
|
|
|
|
# define REG_EBP 6 // REG_FP
|
|
|
|
# endif
|
|
|
|
# ifndef REG_UESP
|
|
|
|
# define REG_UESP 17 // REG_SP
|
|
|
|
# endif
|
|
|
|
# endif
|
2015-03-02 17:36:02 +00:00
|
|
|
*pc = ucontext->uc_mcontext.gregs[REG_EIP];
|
|
|
|
*bp = ucontext->uc_mcontext.gregs[REG_EBP];
|
2020-07-14 12:56:18 +02:00
|
|
|
*sp = ucontext->uc_mcontext.gregs[REG_UESP];
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
|
|
|
# elif defined(__powerpc__) || defined(__powerpc64__)
|
2022-04-18 04:53:01 -05:00
|
|
|
# if SANITIZER_FREEBSD
|
|
|
|
ucontext_t *ucontext = (ucontext_t *)context;
|
|
|
|
*pc = ucontext->uc_mcontext.mc_srr0;
|
|
|
|
*sp = ucontext->uc_mcontext.mc_frame[1];
|
|
|
|
*bp = ucontext->uc_mcontext.mc_frame[31];
|
|
|
|
# else
|
2023-11-27 23:17:03 +01:00
|
|
|
ucontext_t *ucontext = (ucontext_t *)context;
|
2015-03-02 17:36:02 +00:00
|
|
|
*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];
|
2022-04-18 04:53:01 -05:00
|
|
|
# endif
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif defined(__sparc__)
|
|
|
|
# if defined(__arch64__) || defined(__sparcv9)
|
|
|
|
# define STACK_BIAS 2047
|
|
|
|
# else
|
|
|
|
# define STACK_BIAS 0
|
|
|
|
# endif
|
|
|
|
# if SANITIZER_SOLARIS
|
SanitizerCommon: fixes for unwinding & backtrace on SPARC
Summary:
This patch contains various fixes for the unwinding and backtrace machinery on the SPARC, which doesn't work correctly in various cases. It was tested with GCC on SPARC/Solaris and SPARC/Linux.
Patch by Eric Botcazou.
Reviewers: #sanitizers, vitalybuka
Reviewed By: #sanitizers, vitalybuka
Subscribers: jrtc27, delcypher, vitalybuka, ro, jyknight, kubamracek, fedor.sergeev, jdoerfert, llvm-commits, #sanitizers
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D58431
llvm-svn: 355965
2019-03-12 20:31:53 +00:00
|
|
|
ucontext_t *ucontext = (ucontext_t *)context;
|
2015-03-02 17:36:02 +00:00
|
|
|
*pc = ucontext->uc_mcontext.gregs[REG_PC];
|
2024-09-24 09:33:17 +02:00
|
|
|
*sp = ucontext->uc_mcontext.gregs[REG_SP] + STACK_BIAS;
|
|
|
|
// Avoid SEGV when dereferencing sp on stack overflow with non-faulting load.
|
|
|
|
// This requires a SPARC V9 CPU. Cannot use #ASI_PNF here: only supported
|
|
|
|
// since clang-19.
|
|
|
|
# if defined(__sparcv9)
|
|
|
|
asm("ldxa [%[fp]] 0x82, %[bp]"
|
|
|
|
# else
|
|
|
|
asm("lduwa [%[fp]] 0x82, %[bp]"
|
|
|
|
# endif
|
|
|
|
: [bp] "=r"(*bp)
|
|
|
|
: [fp] "r"(&((struct frame *)*sp)->fr_savfp));
|
|
|
|
if (*bp)
|
|
|
|
*bp += STACK_BIAS;
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
SanitizerCommon: fixes for unwinding & backtrace on SPARC
Summary:
This patch contains various fixes for the unwinding and backtrace machinery on the SPARC, which doesn't work correctly in various cases. It was tested with GCC on SPARC/Solaris and SPARC/Linux.
Patch by Eric Botcazou.
Reviewers: #sanitizers, vitalybuka
Reviewed By: #sanitizers, vitalybuka
Subscribers: jrtc27, delcypher, vitalybuka, ro, jyknight, kubamracek, fedor.sergeev, jdoerfert, llvm-commits, #sanitizers
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D58431
llvm-svn: 355965
2019-03-12 20:31:53 +00:00
|
|
|
// Historical BSDism here.
|
|
|
|
struct sigcontext *scontext = (struct sigcontext *)context;
|
2023-11-27 23:17:03 +01:00
|
|
|
# if defined(__arch64__)
|
SanitizerCommon: fixes for unwinding & backtrace on SPARC
Summary:
This patch contains various fixes for the unwinding and backtrace machinery on the SPARC, which doesn't work correctly in various cases. It was tested with GCC on SPARC/Solaris and SPARC/Linux.
Patch by Eric Botcazou.
Reviewers: #sanitizers, vitalybuka
Reviewed By: #sanitizers, vitalybuka
Subscribers: jrtc27, delcypher, vitalybuka, ro, jyknight, kubamracek, fedor.sergeev, jdoerfert, llvm-commits, #sanitizers
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D58431
llvm-svn: 355965
2019-03-12 20:31:53 +00:00
|
|
|
*pc = scontext->sigc_regs.tpc;
|
|
|
|
*sp = scontext->sigc_regs.u_regs[14] + STACK_BIAS;
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
SanitizerCommon: fixes for unwinding & backtrace on SPARC
Summary:
This patch contains various fixes for the unwinding and backtrace machinery on the SPARC, which doesn't work correctly in various cases. It was tested with GCC on SPARC/Solaris and SPARC/Linux.
Patch by Eric Botcazou.
Reviewers: #sanitizers, vitalybuka
Reviewed By: #sanitizers, vitalybuka
Subscribers: jrtc27, delcypher, vitalybuka, ro, jyknight, kubamracek, fedor.sergeev, jdoerfert, llvm-commits, #sanitizers
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D58431
llvm-svn: 355965
2019-03-12 20:31:53 +00:00
|
|
|
*pc = scontext->si_regs.pc;
|
|
|
|
*sp = scontext->si_regs.u_regs[14];
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
SanitizerCommon: fixes for unwinding & backtrace on SPARC
Summary:
This patch contains various fixes for the unwinding and backtrace machinery on the SPARC, which doesn't work correctly in various cases. It was tested with GCC on SPARC/Solaris and SPARC/Linux.
Patch by Eric Botcazou.
Reviewers: #sanitizers, vitalybuka
Reviewed By: #sanitizers, vitalybuka
Subscribers: jrtc27, delcypher, vitalybuka, ro, jyknight, kubamracek, fedor.sergeev, jdoerfert, llvm-commits, #sanitizers
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D58431
llvm-svn: 355965
2019-03-12 20:31:53 +00:00
|
|
|
*bp = (uptr)((uhwptr *)*sp)[14] + STACK_BIAS;
|
2024-09-24 09:33:17 +02:00
|
|
|
# endif
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif defined(__mips__)
|
|
|
|
ucontext_t *ucontext = (ucontext_t *)context;
|
2015-05-06 06:53:09 +00:00
|
|
|
*pc = ucontext->uc_mcontext.pc;
|
2015-03-02 17:36:02 +00:00
|
|
|
*bp = ucontext->uc_mcontext.gregs[30];
|
|
|
|
*sp = ucontext->uc_mcontext.gregs[29];
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif defined(__s390__)
|
|
|
|
ucontext_t *ucontext = (ucontext_t *)context;
|
|
|
|
# if defined(__s390x__)
|
2016-04-14 21:17:19 +00:00
|
|
|
*pc = ucontext->uc_mcontext.psw.addr;
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2016-04-14 21:17:19 +00:00
|
|
|
*pc = ucontext->uc_mcontext.psw.addr & 0x7fffffff;
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2016-04-14 21:17:19 +00:00
|
|
|
*bp = ucontext->uc_mcontext.gregs[11];
|
|
|
|
*sp = ucontext->uc_mcontext.gregs[15];
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif defined(__riscv)
|
|
|
|
ucontext_t *ucontext = (ucontext_t *)context;
|
2021-08-26 11:11:56 +01:00
|
|
|
# if SANITIZER_FREEBSD
|
|
|
|
*pc = ucontext->uc_mcontext.mc_gpregs.gp_sepc;
|
|
|
|
*bp = ucontext->uc_mcontext.mc_gpregs.gp_s[0];
|
|
|
|
*sp = ucontext->uc_mcontext.mc_gpregs.gp_sp;
|
|
|
|
# else
|
[Sanitizers] Add support for RISC-V 64-bit
Summary:
This has been tested with gcc trunk on openSUSE Tumbleweed on the HiFive Unleashed.
Patch by Andreas Schwab (schwab)
Reviewers: luismarques
Reviewed By: luismarques
Subscribers: mhorne, emaste, luismarques, asb, mgorny, fedor.sergeev, simoncook, kito-cheng, shiva0217, rogfer01, rkruppe, lenary, s.egerton, #sanitizers, llvm-commits
Tags: #llvm, #sanitizers
Differential Revision: https://reviews.llvm.org/D66870
2019-10-23 14:10:43 +01:00
|
|
|
*pc = ucontext->uc_mcontext.__gregs[REG_PC];
|
|
|
|
*bp = ucontext->uc_mcontext.__gregs[REG_S0];
|
|
|
|
*sp = ucontext->uc_mcontext.__gregs[REG_SP];
|
2021-08-26 11:11:56 +01:00
|
|
|
# endif
|
2021-08-17 14:38:38 -07:00
|
|
|
# elif defined(__hexagon__)
|
|
|
|
ucontext_t *ucontext = (ucontext_t *)context;
|
|
|
|
*pc = ucontext->uc_mcontext.pc;
|
|
|
|
*bp = ucontext->uc_mcontext.r30;
|
|
|
|
*sp = ucontext->uc_mcontext.r29;
|
2022-07-20 00:58:40 -07:00
|
|
|
# elif defined(__loongarch__)
|
|
|
|
ucontext_t *ucontext = (ucontext_t *)context;
|
|
|
|
*pc = ucontext->uc_mcontext.__pc;
|
|
|
|
*bp = ucontext->uc_mcontext.__gregs[22];
|
|
|
|
*sp = ucontext->uc_mcontext.__gregs[3];
|
2021-08-17 14:38:38 -07:00
|
|
|
# else
|
|
|
|
# error "Unsupported arch"
|
|
|
|
# endif
|
2015-03-02 17:36:02 +00:00
|
|
|
}
|
|
|
|
|
2017-09-14 02:48:41 +00:00
|
|
|
void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); }
|
|
|
|
|
2024-09-18 16:19:35 -07:00
|
|
|
void InitializePlatformEarly() { InitTlsSize(); }
|
2018-11-06 19:55:19 +00:00
|
|
|
|
2018-06-05 07:29:23 +00:00
|
|
|
void CheckASLR() {
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_NETBSD
|
2018-06-05 07:29:23 +00:00
|
|
|
int mib[3];
|
|
|
|
int paxflags;
|
2018-08-31 08:10:06 +00:00
|
|
|
uptr len = sizeof(paxflags);
|
2018-06-05 07:29:23 +00:00
|
|
|
|
|
|
|
mib[0] = CTL_PROC;
|
|
|
|
mib[1] = internal_getpid();
|
|
|
|
mib[2] = PROC_PID_PAXFLAGS;
|
|
|
|
|
2018-08-31 08:10:06 +00:00
|
|
|
if (UNLIKELY(internal_sysctl(mib, 3, &paxflags, &len, NULL, 0) == -1)) {
|
2018-06-05 07:29:23 +00:00
|
|
|
Printf("sysctl failed\n");
|
|
|
|
Die();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_ASLR)) {
|
2023-11-27 23:17:03 +01:00
|
|
|
Printf(
|
|
|
|
"This sanitizer is not compatible with enabled ASLR.\n"
|
|
|
|
"To disable ASLR, please run \"paxctl +a %s\" and try again.\n",
|
|
|
|
GetArgv()[0]);
|
2018-06-05 07:29:23 +00:00
|
|
|
Die();
|
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# elif SANITIZER_FREEBSD
|
2022-01-17 17:36:45 -05:00
|
|
|
int aslr_status;
|
2022-06-08 08:55:10 +01:00
|
|
|
int r = internal_procctl(P_PID, 0, PROC_ASLR_STATUS, &aslr_status);
|
|
|
|
if (UNLIKELY(r == -1)) {
|
2019-08-22 21:36:35 +00:00
|
|
|
// We're making things less 'dramatic' here since
|
2022-01-17 17:36:45 -05:00
|
|
|
// the cmd is not necessarily guaranteed to be here
|
2019-08-22 21:36:35 +00:00
|
|
|
// just yet regarding FreeBSD release
|
|
|
|
return;
|
|
|
|
}
|
2022-01-17 17:36:45 -05:00
|
|
|
if ((aslr_status & PROC_ASLR_ACTIVE) != 0) {
|
2023-11-27 23:17:03 +01:00
|
|
|
VReport(1,
|
|
|
|
"This sanitizer is not compatible with enabled ASLR "
|
|
|
|
"and binaries compiled with PIE\n"
|
|
|
|
"ASLR will be disabled and the program re-executed.\n");
|
2023-11-27 22:43:33 +01:00
|
|
|
int aslr_ctl = PROC_ASLR_FORCE_DISABLE;
|
|
|
|
CHECK_NE(internal_procctl(P_PID, 0, PROC_ASLR_CTL, &aslr_ctl), -1);
|
|
|
|
ReExec();
|
2019-08-22 21:36:35 +00:00
|
|
|
}
|
2022-04-18 04:53:01 -05:00
|
|
|
# elif SANITIZER_PPC64V2
|
|
|
|
// Disable ASLR for Linux PPC64LE.
|
|
|
|
int old_personality = personality(0xffffffff);
|
|
|
|
if (old_personality != -1 && (old_personality & ADDR_NO_RANDOMIZE) == 0) {
|
|
|
|
VReport(1,
|
|
|
|
"WARNING: Program is being run with address space layout "
|
|
|
|
"randomization (ASLR) enabled which prevents the thread and "
|
|
|
|
"memory sanitizers from working on powerpc64le.\n"
|
|
|
|
"ASLR will be disabled and the program re-executed.\n");
|
|
|
|
CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);
|
|
|
|
ReExec();
|
|
|
|
}
|
|
|
|
# else
|
2018-06-05 07:29:23 +00:00
|
|
|
// Do nothing
|
2022-04-18 04:53:01 -05:00
|
|
|
# endif
|
2018-06-05 07:29:23 +00:00
|
|
|
}
|
|
|
|
|
2018-12-23 15:09:28 +00:00
|
|
|
void CheckMPROTECT() {
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_NETBSD
|
2018-12-23 15:09:28 +00:00
|
|
|
int mib[3];
|
|
|
|
int paxflags;
|
|
|
|
uptr len = sizeof(paxflags);
|
|
|
|
|
|
|
|
mib[0] = CTL_PROC;
|
|
|
|
mib[1] = internal_getpid();
|
|
|
|
mib[2] = PROC_PID_PAXFLAGS;
|
|
|
|
|
|
|
|
if (UNLIKELY(internal_sysctl(mib, 3, &paxflags, &len, NULL, 0) == -1)) {
|
|
|
|
Printf("sysctl failed\n");
|
|
|
|
Die();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_MPROTECT)) {
|
|
|
|
Printf("This sanitizer is not compatible with enabled MPROTECT\n");
|
|
|
|
Die();
|
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# else
|
2018-12-23 15:09:28 +00:00
|
|
|
// Do nothing
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2018-12-23 15:09:28 +00:00
|
|
|
}
|
|
|
|
|
2017-03-09 10:47:38 +00:00
|
|
|
void CheckNoDeepBind(const char *filename, int flag) {
|
2023-11-27 23:17:03 +01:00
|
|
|
# ifdef RTLD_DEEPBIND
|
2017-03-09 10:47:38 +00:00
|
|
|
if (flag & RTLD_DEEPBIND) {
|
|
|
|
Report(
|
|
|
|
"You are trying to dlopen a %s shared library with RTLD_DEEPBIND flag"
|
2020-07-08 20:42:22 -07:00
|
|
|
" which is incompatible with sanitizer runtime "
|
2017-03-09 10:47:38 +00:00
|
|
|
"(see https://github.com/google/sanitizers/issues/611 for details"
|
|
|
|
"). If you want to run %s library under sanitizers please remove "
|
|
|
|
"RTLD_DEEPBIND from dlopen flags.\n",
|
|
|
|
filename, filename);
|
|
|
|
Die();
|
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif
|
2017-03-09 10:47:38 +00:00
|
|
|
}
|
|
|
|
|
2017-07-12 23:29:21 +00:00
|
|
|
uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
|
2018-02-26 18:33:21 +00:00
|
|
|
uptr *largest_gap_found,
|
|
|
|
uptr *max_occupied_addr) {
|
2016-10-05 20:33:59 +00:00
|
|
|
UNREACHABLE("FindAvailableMemoryRange is not available");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-08-14 14:53:47 +00:00
|
|
|
bool GetRandom(void *buffer, uptr length, bool blocking) {
|
[sanitizer] Add a function to gather random bytes
Summary:
AFAICT compiler-rt doesn't have a function that would return 'good' random
bytes to seed a PRNG. Currently, the `SizeClassAllocator64` uses addresses
returned by `mmap` to seed its PRNG, which is not ideal, and
`SizeClassAllocator32` doesn't benefit from the entropy offered by its 64-bit
counterpart address space, so right now it has nothing. This function aims at
solving this, allowing to implement good 32-bit chunk randomization. Scudo also
has a function that does this for Cookie purposes, which would go away in a
later CL once this lands.
This function will try the `getrandom` syscall if available, and fallback to
`/dev/urandom` if not.
Unfortunately, I do not have a way to implement and test a Mac and Windows
version, so those are unimplemented as of now. Note that `kRandomShuffleChunks`
is only used on Linux for now.
Reviewers: alekseyshl
Reviewed By: alekseyshl
Subscribers: zturner, rnk, llvm-commits, kubamracek
Differential Revision: https://reviews.llvm.org/D34412
llvm-svn: 305922
2017-06-21 15:56:03 +00:00
|
|
|
if (!buffer || !length || length > 256)
|
|
|
|
return false;
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_USE_GETENTROPY
|
2018-04-09 22:46:40 +00:00
|
|
|
uptr rnd = getentropy(buffer, length);
|
|
|
|
int rverrno = 0;
|
|
|
|
if (internal_iserror(rnd, &rverrno) && rverrno == EFAULT)
|
|
|
|
return false;
|
|
|
|
else if (rnd == 0)
|
|
|
|
return true;
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif // SANITIZER_USE_GETENTROPY
|
2018-04-09 22:46:40 +00:00
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
# if SANITIZER_USE_GETRANDOM
|
[sanitizer] Add a function to gather random bytes
Summary:
AFAICT compiler-rt doesn't have a function that would return 'good' random
bytes to seed a PRNG. Currently, the `SizeClassAllocator64` uses addresses
returned by `mmap` to seed its PRNG, which is not ideal, and
`SizeClassAllocator32` doesn't benefit from the entropy offered by its 64-bit
counterpart address space, so right now it has nothing. This function aims at
solving this, allowing to implement good 32-bit chunk randomization. Scudo also
has a function that does this for Cookie purposes, which would go away in a
later CL once this lands.
This function will try the `getrandom` syscall if available, and fallback to
`/dev/urandom` if not.
Unfortunately, I do not have a way to implement and test a Mac and Windows
version, so those are unimplemented as of now. Note that `kRandomShuffleChunks`
is only used on Linux for now.
Reviewers: alekseyshl
Reviewed By: alekseyshl
Subscribers: zturner, rnk, llvm-commits, kubamracek
Differential Revision: https://reviews.llvm.org/D34412
llvm-svn: 305922
2017-06-21 15:56:03 +00:00
|
|
|
static atomic_uint8_t skip_getrandom_syscall;
|
|
|
|
if (!atomic_load_relaxed(&skip_getrandom_syscall)) {
|
|
|
|
// Up to 256 bytes, getrandom will not be interrupted.
|
2017-08-14 14:53:47 +00:00
|
|
|
uptr res = internal_syscall(SYSCALL(getrandom), buffer, length,
|
|
|
|
blocking ? 0 : GRND_NONBLOCK);
|
[sanitizer] Add a function to gather random bytes
Summary:
AFAICT compiler-rt doesn't have a function that would return 'good' random
bytes to seed a PRNG. Currently, the `SizeClassAllocator64` uses addresses
returned by `mmap` to seed its PRNG, which is not ideal, and
`SizeClassAllocator32` doesn't benefit from the entropy offered by its 64-bit
counterpart address space, so right now it has nothing. This function aims at
solving this, allowing to implement good 32-bit chunk randomization. Scudo also
has a function that does this for Cookie purposes, which would go away in a
later CL once this lands.
This function will try the `getrandom` syscall if available, and fallback to
`/dev/urandom` if not.
Unfortunately, I do not have a way to implement and test a Mac and Windows
version, so those are unimplemented as of now. Note that `kRandomShuffleChunks`
is only used on Linux for now.
Reviewers: alekseyshl
Reviewed By: alekseyshl
Subscribers: zturner, rnk, llvm-commits, kubamracek
Differential Revision: https://reviews.llvm.org/D34412
llvm-svn: 305922
2017-06-21 15:56:03 +00:00
|
|
|
int rverrno = 0;
|
|
|
|
if (internal_iserror(res, &rverrno) && rverrno == ENOSYS)
|
|
|
|
atomic_store_relaxed(&skip_getrandom_syscall, 1);
|
|
|
|
else if (res == length)
|
|
|
|
return true;
|
|
|
|
}
|
2023-11-27 23:17:03 +01:00
|
|
|
# endif // SANITIZER_USE_GETRANDOM
|
2017-08-14 14:53:47 +00:00
|
|
|
// Up to 256 bytes, a read off /dev/urandom will not be interrupted.
|
|
|
|
// blocking is moot here, O_NONBLOCK has no effect when opening /dev/urandom.
|
[sanitizer] Add a function to gather random bytes
Summary:
AFAICT compiler-rt doesn't have a function that would return 'good' random
bytes to seed a PRNG. Currently, the `SizeClassAllocator64` uses addresses
returned by `mmap` to seed its PRNG, which is not ideal, and
`SizeClassAllocator32` doesn't benefit from the entropy offered by its 64-bit
counterpart address space, so right now it has nothing. This function aims at
solving this, allowing to implement good 32-bit chunk randomization. Scudo also
has a function that does this for Cookie purposes, which would go away in a
later CL once this lands.
This function will try the `getrandom` syscall if available, and fallback to
`/dev/urandom` if not.
Unfortunately, I do not have a way to implement and test a Mac and Windows
version, so those are unimplemented as of now. Note that `kRandomShuffleChunks`
is only used on Linux for now.
Reviewers: alekseyshl
Reviewed By: alekseyshl
Subscribers: zturner, rnk, llvm-commits, kubamracek
Differential Revision: https://reviews.llvm.org/D34412
llvm-svn: 305922
2017-06-21 15:56:03 +00:00
|
|
|
uptr fd = internal_open("/dev/urandom", O_RDONLY);
|
|
|
|
if (internal_iserror(fd))
|
|
|
|
return false;
|
|
|
|
uptr res = internal_read(fd, buffer, length);
|
|
|
|
if (internal_iserror(res))
|
|
|
|
return false;
|
|
|
|
internal_close(fd);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-11-27 23:17:03 +01:00
|
|
|
} // namespace __sanitizer
|
2012-06-04 14:27:50 +00:00
|
|
|
|
2018-03-19 23:12:14 +00:00
|
|
|
#endif
|