2017-10-14 05:13:47 +08:00
|
|
|
// Copyright 2017 The Abseil Authors.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
//
|
|
|
|
|
|
|
|
#ifndef ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
|
|
|
|
#define ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
|
|
|
|
|
|
|
|
namespace absl {
|
|
|
|
namespace debug_internal {
|
|
|
|
|
|
|
|
// Return whether the byte at *addr is readable, without faulting.
|
|
|
|
// Save and restores errno.
|
|
|
|
bool AddressIsReadable(const void *addr);
|
|
|
|
|
|
|
|
} // namespace debug_internal
|
|
|
|
} // namespace absl
|
|
|
|
|
|
|
|
#endif // ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
|
|
|
|
/*
|
|
|
|
* Copyright 2017 The Abseil Authors.
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Allow dynamic symbol lookup for in-memory Elf images.
|
|
|
|
|
|
|
|
#ifndef ABSL_DEBUGGING_INTERNAL_ELF_MEM_IMAGE_H_
|
|
|
|
#define ABSL_DEBUGGING_INTERNAL_ELF_MEM_IMAGE_H_
|
|
|
|
|
|
|
|
// Including this will define the __GLIBC__ macro if glibc is being
|
|
|
|
// used.
|
|
|
|
#include <climits>
|
|
|
|
|
|
|
|
// Maybe one day we can rewrite this file not to require the elf
|
|
|
|
// symbol extensions in glibc, but for right now we need them.
|
|
|
|
#ifdef ABSL_HAVE_ELF_MEM_IMAGE
|
|
|
|
#error ABSL_HAVE_ELF_MEM_IMAGE cannot be directly set
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(__ELF__) && defined(__GLIBC__) && !defined(__native_client__) && \
|
|
|
|
!defined(__asmjs__)
|
|
|
|
#define ABSL_HAVE_ELF_MEM_IMAGE 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if ABSL_HAVE_ELF_MEM_IMAGE
|
|
|
|
|
|
|
|
#include <link.h> // for ElfW
|
|
|
|
|
|
|
|
namespace absl {
|
|
|
|
namespace debug_internal {
|
|
|
|
|
|
|
|
// An in-memory ELF image (may not exist on disk).
|
|
|
|
class ElfMemImage {
|
|
|
|
public:
|
|
|
|
// Sentinel: there could never be an elf image at this address.
|
|
|
|
static const void *const kInvalidBase;
|
|
|
|
|
|
|
|
// Information about a single vdso symbol.
|
|
|
|
// All pointers are into .dynsym, .dynstr, or .text of the VDSO.
|
|
|
|
// Do not free() them or modify through them.
|
|
|
|
struct SymbolInfo {
|
|
|
|
const char *name; // E.g. "__vdso_getcpu"
|
|
|
|
const char *version; // E.g. "LINUX_2.6", could be ""
|
|
|
|
// for unversioned symbol.
|
|
|
|
const void *address; // Relocated symbol address.
|
|
|
|
const ElfW(Sym) *symbol; // Symbol in the dynamic symbol table.
|
|
|
|
};
|
|
|
|
|
|
|
|
// Supports iteration over all dynamic symbols.
|
|
|
|
class SymbolIterator {
|
|
|
|
public:
|
|
|
|
friend class ElfMemImage;
|
|
|
|
const SymbolInfo *operator->() const;
|
|
|
|
const SymbolInfo &operator*() const;
|
|
|
|
SymbolIterator& operator++();
|
|
|
|
bool operator!=(const SymbolIterator &rhs) const;
|
|
|
|
bool operator==(const SymbolIterator &rhs) const;
|
|
|
|
private:
|
|
|
|
SymbolIterator(const void *const image, int index);
|
|
|
|
void Update(int incr);
|
|
|
|
SymbolInfo info_;
|
|
|
|
int index_;
|
|
|
|
const void *const image_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
explicit ElfMemImage(const void *base);
|
|
|
|
void Init(const void *base);
|
|
|
|
bool IsPresent() const { return ehdr_ != nullptr; }
|
|
|
|
const ElfW(Phdr)* GetPhdr(int index) const;
|
|
|
|
const ElfW(Sym)* GetDynsym(int index) const;
|
|
|
|
const ElfW(Versym)* GetVersym(int index) const;
|
|
|
|
const ElfW(Verdef)* GetVerdef(int index) const;
|
|
|
|
const ElfW(Verdaux)* GetVerdefAux(const ElfW(Verdef) *verdef) const;
|
|
|
|
const char* GetDynstr(ElfW(Word) offset) const;
|
|
|
|
const void* GetSymAddr(const ElfW(Sym) *sym) const;
|
|
|
|
const char* GetVerstr(ElfW(Word) offset) const;
|
|
|
|
int GetNumSymbols() const;
|
|
|
|
|
|
|
|
SymbolIterator begin() const;
|
|
|
|
SymbolIterator end() const;
|
|
|
|
|
|
|
|
// Look up versioned dynamic symbol in the image.
|
|
|
|
// Returns false if image is not present, or doesn't contain given
|
|
|
|
// symbol/version/type combination.
|
|
|
|
// If info_out is non-null, additional details are filled in.
|
|
|
|
bool LookupSymbol(const char *name, const char *version,
|
|
|
|
int symbol_type, SymbolInfo *info_out) const;
|
|
|
|
|
|
|
|
// Find info about symbol (if any) which overlaps given address.
|
|
|
|
// Returns true if symbol was found; false if image isn't present
|
|
|
|
// or doesn't have a symbol overlapping given address.
|
|
|
|
// If info_out is non-null, additional details are filled in.
|
|
|
|
bool LookupSymbolByAddress(const void *address, SymbolInfo *info_out) const;
|
|
|
|
|
|
|
|
private:
|
|
|
|
const ElfW(Ehdr) *ehdr_;
|
|
|
|
const ElfW(Sym) *dynsym_;
|
|
|
|
const ElfW(Versym) *versym_;
|
|
|
|
const ElfW(Verdef) *verdef_;
|
|
|
|
const ElfW(Word) *hash_;
|
|
|
|
const char *dynstr_;
|
|
|
|
size_t strsize_;
|
|
|
|
size_t verdefnum_;
|
|
|
|
ElfW(Addr) link_base_; // Link-time base (p_vaddr of first PT_LOAD).
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace debug_internal
|
|
|
|
} // namespace absl
|
|
|
|
|
|
|
|
#endif // ABSL_HAVE_ELF_MEM_IMAGE
|
|
|
|
|
|
|
|
#endif // ABSL_DEBUGGING_INTERNAL_ELF_MEM_IMAGE_H_
|
|
|
|
/*
|
|
|
|
* Copyright 2017 The Abseil Authors.
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
|
|
|
|
* Defines ABSL_STACKTRACE_INL_HEADER to the *-inl.h containing
|
|
|
|
* actual unwinder implementation.
|
|
|
|
* This header is "private" to stacktrace.cc.
|
|
|
|
* DO NOT include it into any other files.
|
|
|
|
*/
|
|
|
|
#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
|
|
|
|
#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
|
|
|
|
|
|
|
|
// First, test platforms which only support a stub.
|
|
|
|
#if ABSL_STACKTRACE_INL_HEADER
|
|
|
|
#error ABSL_STACKTRACE_INL_HEADER cannot be directly set
|
|
|
|
#elif defined(__native_client__) || defined(__APPLE__) || \
|
|
|
|
defined(__ANDROID__) || defined(__myriad2__) || defined(asmjs__) || \
|
|
|
|
defined(__Fuchsia__)
|
|
|
|
#define ABSL_STACKTRACE_INL_HEADER \
|
|
|
|
"stacktrace_internal/stacktrace_unimplemented-inl.inc"
|
|
|
|
|
|
|
|
// Next, test for Mips and Windows.
|
|
|
|
// TODO(marmstrong): Mips case, remove the check for ABSL_STACKTRACE_INL_HEADER
|
|
|
|
#elif defined(__mips__) && !defined(ABSL_STACKTRACE_INL_HEADER)
|
|
|
|
#define ABSL_STACKTRACE_INL_HEADER \
|
|
|
|
"stacktrace_internal/stacktrace_unimplemented-inl.inc"
|
|
|
|
#elif defined(_WIN32) // windows
|
|
|
|
#define ABSL_STACKTRACE_INL_HEADER \
|
|
|
|
"stacktrace_internal/stacktrace_win32-inl.inc"
|
|
|
|
|
|
|
|
// Finally, test NO_FRAME_POINTER.
|
|
|
|
#elif !defined(NO_FRAME_POINTER)
|
|
|
|
# if defined(__i386__) || defined(__x86_64__)
|
|
|
|
#define ABSL_STACKTRACE_INL_HEADER \
|
|
|
|
"stacktrace_internal/stacktrace_x86-inl.inc"
|
|
|
|
# elif defined(__ppc__) || defined(__PPC__)
|
|
|
|
#define ABSL_STACKTRACE_INL_HEADER \
|
|
|
|
"stacktrace_internal/stacktrace_powerpc-inl.inc"
|
|
|
|
# elif defined(__aarch64__)
|
|
|
|
#define ABSL_STACKTRACE_INL_HEADER \
|
|
|
|
"stacktrace_internal/stacktrace_aarch64-inl.inc"
|
|
|
|
# elif defined(__arm__)
|
|
|
|
#define ABSL_STACKTRACE_INL_HEADER \
|
|
|
|
"stacktrace_internal/stacktrace_arm-inl.inc"
|
|
|
|
# endif
|
|
|
|
#else // defined(NO_FRAME_POINTER)
|
|
|
|
# if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
|
|
|
|
#define ABSL_STACKTRACE_INL_HEADER \
|
|
|
|
"stacktrace_internal/stacktrace_unimplemented-inl.inc"
|
|
|
|
# elif defined(__ppc__) || defined(__PPC__)
|
|
|
|
// Use glibc's backtrace.
|
|
|
|
#define ABSL_STACKTRACE_INL_HEADER \
|
|
|
|
"stacktrace_internal/stacktrace_generic-inl.inc"
|
|
|
|
# elif defined(__arm__)
|
|
|
|
# error stacktrace without frame pointer is not supported on ARM
|
|
|
|
# endif
|
|
|
|
#endif // NO_FRAME_POINTER
|
|
|
|
|
|
|
|
#if !defined(ABSL_STACKTRACE_INL_HEADER)
|
|
|
|
#error Not supported yet
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
|
|
|
|
//
|
|
|
|
// Copyright 2017 The Abseil Authors.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
//
|
|
|
|
|
|
|
|
// Allow dynamic symbol lookup in the kernel VDSO page.
|
|
|
|
//
|
|
|
|
// VDSO stands for "Virtual Dynamic Shared Object" -- a page of
|
|
|
|
// executable code, which looks like a shared library, but doesn't
|
|
|
|
// necessarily exist anywhere on disk, and which gets mmap()ed into
|
|
|
|
// every process by kernels which support VDSO, such as 2.6.x for 32-bit
|
|
|
|
// executables, and 2.6.24 and above for 64-bit executables.
|
|
|
|
//
|
|
|
|
// More details could be found here:
|
|
|
|
// http://www.trilithium.com/johan/2005/08/linux-gate/
|
|
|
|
//
|
|
|
|
// VDSOSupport -- a class representing kernel VDSO (if present).
|
|
|
|
//
|
|
|
|
// Example usage:
|
|
|
|
// VDSOSupport vdso;
|
|
|
|
// VDSOSupport::SymbolInfo info;
|
|
|
|
// typedef (*FN)(unsigned *, void *, void *);
|
|
|
|
// FN fn = nullptr;
|
|
|
|
// if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) {
|
|
|
|
// fn = reinterpret_cast<FN>(info.address);
|
|
|
|
// }
|
|
|
|
|
|
|
|
#ifndef ABSL_DEBUGGING_INTERNAL_VDSO_SUPPORT_H_
|
|
|
|
#define ABSL_DEBUGGING_INTERNAL_VDSO_SUPPORT_H_
|
|
|
|
|
|
|
|
#include <atomic>
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef ABSL_HAVE_ELF_MEM_IMAGE
|
|
|
|
|
|
|
|
#ifdef ABSL_HAVE_VDSO_SUPPORT
|
|
|
|
#error ABSL_HAVE_VDSO_SUPPORT cannot be directly set
|
|
|
|
#else
|
|
|
|
#define ABSL_HAVE_VDSO_SUPPORT 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace absl {
|
|
|
|
namespace debug_internal {
|
|
|
|
|
|
|
|
// NOTE: this class may be used from within tcmalloc, and can not
|
|
|
|
// use any memory allocation routines.
|
|
|
|
class VDSOSupport {
|
|
|
|
public:
|
|
|
|
VDSOSupport();
|
|
|
|
|
|
|
|
typedef ElfMemImage::SymbolInfo SymbolInfo;
|
|
|
|
typedef ElfMemImage::SymbolIterator SymbolIterator;
|
|
|
|
|
|
|
|
// On PowerPC64 VDSO symbols can either be of type STT_FUNC or STT_NOTYPE
|
|
|
|
// depending on how the kernel is built. The kernel is normally built with
|
|
|
|
// STT_NOTYPE type VDSO symbols. Let's make things simpler first by using a
|
|
|
|
// compile-time constant.
|
|
|
|
#ifdef __powerpc64__
|
|
|
|
enum { kVDSOSymbolType = STT_NOTYPE };
|
|
|
|
#else
|
|
|
|
enum { kVDSOSymbolType = STT_FUNC };
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Answers whether we have a vdso at all.
|
|
|
|
bool IsPresent() const { return image_.IsPresent(); }
|
|
|
|
|
|
|
|
// Allow to iterate over all VDSO symbols.
|
|
|
|
SymbolIterator begin() const { return image_.begin(); }
|
|
|
|
SymbolIterator end() const { return image_.end(); }
|
|
|
|
|
|
|
|
// Look up versioned dynamic symbol in the kernel VDSO.
|
|
|
|
// Returns false if VDSO is not present, or doesn't contain given
|
|
|
|
// symbol/version/type combination.
|
|
|
|
// If info_out != nullptr, additional details are filled in.
|
|
|
|
bool LookupSymbol(const char *name, const char *version,
|
|
|
|
int symbol_type, SymbolInfo *info_out) const;
|
|
|
|
|
|
|
|
// Find info about symbol (if any) which overlaps given address.
|
|
|
|
// Returns true if symbol was found; false if VDSO isn't present
|
|
|
|
// or doesn't have a symbol overlapping given address.
|
|
|
|
// If info_out != nullptr, additional details are filled in.
|
|
|
|
bool LookupSymbolByAddress(const void *address, SymbolInfo *info_out) const;
|
|
|
|
|
|
|
|
// Used only for testing. Replace real VDSO base with a mock.
|
|
|
|
// Returns previous value of vdso_base_. After you are done testing,
|
|
|
|
// you are expected to call SetBase() with previous value, in order to
|
|
|
|
// reset state to the way it was.
|
|
|
|
const void *SetBase(const void *s);
|
|
|
|
|
|
|
|
// Computes vdso_base_ and returns it. Should be called as early as
|
|
|
|
// possible; before any thread creation, chroot or setuid.
|
|
|
|
static const void *Init();
|
|
|
|
|
|
|
|
private:
|
|
|
|
// image_ represents VDSO ELF image in memory.
|
|
|
|
// image_.ehdr_ == nullptr implies there is no VDSO.
|
|
|
|
ElfMemImage image_;
|
|
|
|
|
|
|
|
// Cached value of auxv AT_SYSINFO_EHDR, computed once.
|
|
|
|
// This is a tri-state:
|
|
|
|
// kInvalidBase => value hasn't been determined yet.
|
|
|
|
// 0 => there is no VDSO.
|
|
|
|
// else => vma of VDSO Elf{32,64}_Ehdr.
|
|
|
|
//
|
|
|
|
// When testing with mock VDSO, low bit is set.
|
|
|
|
// The low bit is always available because vdso_base_ is
|
|
|
|
// page-aligned.
|
|
|
|
static std::atomic<const void *> vdso_base_;
|
|
|
|
|
|
|
|
// NOLINT on 'long' because these routines mimic kernel api.
|
|
|
|
// The 'cache' parameter may be used by some versions of the kernel,
|
|
|
|
// and should be nullptr or point to a static buffer containing at
|
|
|
|
// least two 'long's.
|
|
|
|
static long InitAndGetCPU(unsigned *cpu, void *cache, // NOLINT 'long'.
|
|
|
|
void *unused);
|
|
|
|
static long GetCPUViaSyscall(unsigned *cpu, void *cache, // NOLINT 'long'.
|
|
|
|
void *unused);
|
|
|
|
typedef long (*GetCpuFn)(unsigned *cpu, void *cache, // NOLINT 'long'.
|
|
|
|
void *unused);
|
|
|
|
|
|
|
|
// This function pointer may point to InitAndGetCPU,
|
|
|
|
// GetCPUViaSyscall, or __vdso_getcpu at different stages of initialization.
|
|
|
|
static std::atomic<GetCpuFn> getcpu_fn_;
|
|
|
|
|
|
|
|
friend int GetCPU(void); // Needs access to getcpu_fn_.
|
|
|
|
|
|
|
|
VDSOSupport(const VDSOSupport&) = delete;
|
|
|
|
VDSOSupport& operator=(const VDSOSupport&) = delete;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Same as sched_getcpu() on later glibc versions.
|
|
|
|
// Return current CPU, using (fast) __vdso_getcpu@LINUX_2.6 if present,
|
|
|
|
// otherwise use syscall(SYS_getcpu,...).
|
|
|
|
// May return -1 with errno == ENOSYS if the kernel doesn't
|
|
|
|
// support SYS_getcpu.
|
|
|
|
int GetCPU();
|
|
|
|
|
|
|
|
} // namespace debug_internal
|
|
|
|
} // namespace absl
|
|
|
|
|
|
|
|
#endif // ABSL_HAVE_ELF_MEM_IMAGE
|
|
|
|
|
|
|
|
#endif // ABSL_DEBUGGING_INTERNAL_VDSO_SUPPORT_H_
|
|
|
|
// Copyright 2017 The Abseil Authors.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
//
|
|
|
|
// This header file defines macros for declaring attributes for functions,
|
|
|
|
// types, and variables.
|
|
|
|
//
|
|
|
|
// These macros are used within Abseil and allow the compiler to optimize, where
|
|
|
|
// applicable, certain function calls.
|
|
|
|
//
|
|
|
|
// This file is used for both C and C++!
|
|
|
|
//
|
|
|
|
// Most macros here are exposing GCC or Clang features, and are stubbed out for
|
|
|
|
// other compilers.
|
|
|
|
//
|
|
|
|
// GCC attributes documentation:
|
|
|
|
// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html
|
|
|
|
// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Variable-Attributes.html
|
|
|
|
// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Type-Attributes.html
|
|
|
|
//
|
|
|
|
// Most attributes in this file are already supported by GCC 4.7. However, some
|
|
|
|
// of them are not supported in older version of Clang. Thus, we check
|
|
|
|
// `__has_attribute()` first. If the check fails, we check if we are on GCC and
|
|
|
|
// assume the attribute exists on GCC (which is verified on GCC 4.7).
|
|
|
|
//
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Sanitizer Attributes
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Sanitizer-related attributes are not "defined" in this file (and indeed
|
|
|
|
// are not defined as such in any file). To utilize the following
|
|
|
|
// sanitizer-related attributes within your builds, define the following macros
|
|
|
|
// within your build using a `-D` flag, along with the given value for
|
|
|
|
// `-fsanitize`:
|
|
|
|
//
|
|
|
|
// * `ADDRESS_SANITIZER` + `-fsanitize=address` (Clang, GCC 4.8)
|
|
|
|
// * `MEMORY_SANITIZER` + `-fsanitize=memory` (Clang-only)
|
|
|
|
// * `THREAD_SANITIZER + `-fsanitize=thread` (Clang, GCC 4.8+)
|
|
|
|
// * `UNDEFINED_BEHAVIOR_SANITIZER` + `-fsanitize=undefined` (Clang, GCC 4.9+)
|
|
|
|
// * `CONTROL_FLOW_INTEGRITY` + -fsanitize=cfi (Clang-only)
|
|
|
|
//
|
|
|
|
// Example:
|
|
|
|
//
|
|
|
|
// // Enable branches in the Abseil code that are tagged for ASan:
|
|
|
|
// $ bazel -D ADDRESS_SANITIZER -fsanitize=address *target*
|
|
|
|
//
|
|
|
|
// Since these macro names are only supported by GCC and Clang, we only check
|
|
|
|
// for `__GNUC__` (GCC or Clang) and the above macros.
|
|
|
|
#ifndef ABSL_BASE_ATTRIBUTES_H_
|
|
|
|
#define ABSL_BASE_ATTRIBUTES_H_
|
|
|
|
|
|
|
|
// ABSL_HAVE_ATTRIBUTE
|
|
|
|
//
|
|
|
|
// A function-like feature checking macro that is a wrapper around
|
|
|
|
// `__has_attribute`, which is defined by GCC 5+ and Clang and evaluates to a
|
|
|
|
// nonzero constant integer if the attribute is supported or 0 if not.
|
|
|
|
//
|
|
|
|
// It evaluates to zero if `__has_attribute` is not defined by the compiler.
|
|
|
|
//
|
|
|
|
// GCC: https://gcc.gnu.org/gcc-5/changes.html
|
|
|
|
// Clang: https://clang.llvm.org/docs/LanguageExtensions.html
|
|
|
|
#ifdef __has_attribute
|
|
|
|
#define ABSL_HAVE_ATTRIBUTE(x) __has_attribute(x)
|
|
|
|
#else
|
|
|
|
#define ABSL_HAVE_ATTRIBUTE(x) 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_HAVE_CPP_ATTRIBUTE
|
|
|
|
//
|
|
|
|
// A function-like feature checking macro that accepts C++11 style attributes.
|
|
|
|
// It's a wrapper around `__has_cpp_attribute`, defined by ISO C++ SD-6
|
|
|
|
// (http://en.cppreference.com/w/cpp/experimental/feature_test). If we don't
|
|
|
|
// find `__has_cpp_attribute`, will evaluate to 0.
|
|
|
|
#if defined(__cplusplus) && defined(__has_cpp_attribute)
|
|
|
|
// NOTE: requiring __cplusplus above should not be necessary, but
|
|
|
|
// works around https://bugs.llvm.org/show_bug.cgi?id=23435.
|
|
|
|
#define ABSL_HAVE_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
|
|
|
|
#else
|
|
|
|
#define ABSL_HAVE_CPP_ATTRIBUTE(x) 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Function Attributes
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// GCC: https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
|
|
|
|
// Clang: https://clang.llvm.org/docs/AttributeReference.html
|
|
|
|
|
|
|
|
// ABSL_PRINTF_ATTRIBUTE
|
|
|
|
// ABSL_SCANF_ATTRIBUTE
|
|
|
|
//
|
|
|
|
// Tells the compiler to perform `printf` format std::string checking if the
|
|
|
|
// compiler supports it; see the 'format' attribute in
|
|
|
|
// <http://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html>.
|
|
|
|
//
|
|
|
|
// Note: As the GCC manual states, "[s]ince non-static C++ methods
|
|
|
|
// have an implicit 'this' argument, the arguments of such methods
|
|
|
|
// should be counted from two, not one."
|
|
|
|
#if ABSL_HAVE_ATTRIBUTE(format) || (defined(__GNUC__) && !defined(__clang__))
|
|
|
|
#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check) \
|
|
|
|
__attribute__((__format__(__printf__, string_index, first_to_check)))
|
|
|
|
#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check) \
|
|
|
|
__attribute__((__format__(__scanf__, string_index, first_to_check)))
|
|
|
|
#else
|
|
|
|
#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check)
|
|
|
|
#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_ATTRIBUTE_ALWAYS_INLINE
|
|
|
|
// ABSL_ATTRIBUTE_NOINLINE
|
|
|
|
//
|
|
|
|
// Forces functions to either inline or not inline. Introduced in gcc 3.1.
|
|
|
|
#if ABSL_HAVE_ATTRIBUTE(always_inline) || \
|
|
|
|
(defined(__GNUC__) && !defined(__clang__))
|
|
|
|
#define ABSL_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline))
|
|
|
|
#define ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE 1
|
|
|
|
#else
|
|
|
|
#define ABSL_ATTRIBUTE_ALWAYS_INLINE
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if ABSL_HAVE_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__))
|
|
|
|
#define ABSL_ATTRIBUTE_NOINLINE __attribute__((noinline))
|
|
|
|
#define ABSL_HAVE_ATTRIBUTE_NOINLINE 1
|
|
|
|
#else
|
|
|
|
#define ABSL_ATTRIBUTE_NOINLINE
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_ATTRIBUTE_NO_TAIL_CALL
|
|
|
|
//
|
|
|
|
// Prevents the compiler from optimizing away stack frames for functions which
|
|
|
|
// end in a call to another function.
|
|
|
|
#if ABSL_HAVE_ATTRIBUTE(disable_tail_calls)
|
|
|
|
#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
|
|
|
|
#define ABSL_ATTRIBUTE_NO_TAIL_CALL __attribute__((disable_tail_calls))
|
|
|
|
#elif defined(__GNUC__) && !defined(__clang__)
|
|
|
|
#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
|
|
|
|
#define ABSL_ATTRIBUTE_NO_TAIL_CALL \
|
|
|
|
__attribute__((optimize("no-optimize-sibling-calls")))
|
|
|
|
#else
|
|
|
|
#define ABSL_ATTRIBUTE_NO_TAIL_CALL
|
|
|
|
#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_ATTRIBUTE_WEAK
|
|
|
|
//
|
|
|
|
// Tags a function as weak for the purposes of compilation and linking.
|
|
|
|
#if ABSL_HAVE_ATTRIBUTE(weak) || (defined(__GNUC__) && !defined(__clang__))
|
|
|
|
#undef ABSL_ATTRIBUTE_WEAK
|
|
|
|
#define ABSL_ATTRIBUTE_WEAK __attribute__((weak))
|
|
|
|
#define ABSL_HAVE_ATTRIBUTE_WEAK 1
|
|
|
|
#else
|
|
|
|
#define ABSL_ATTRIBUTE_WEAK
|
|
|
|
#define ABSL_HAVE_ATTRIBUTE_WEAK 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_ATTRIBUTE_NONNULL
|
|
|
|
//
|
|
|
|
// Tells the compiler either (a) that a particular function parameter
|
|
|
|
// should be a non-null pointer, or (b) that all pointer arguments should
|
|
|
|
// be non-null.
|
|
|
|
//
|
|
|
|
// Note: As the GCC manual states, "[s]ince non-static C++ methods
|
|
|
|
// have an implicit 'this' argument, the arguments of such methods
|
|
|
|
// should be counted from two, not one."
|
|
|
|
//
|
|
|
|
// Args are indexed starting at 1.
|
|
|
|
//
|
|
|
|
// For non-static class member functions, the implicit `this` argument
|
|
|
|
// is arg 1, and the first explicit argument is arg 2. For static class member
|
|
|
|
// functions, there is no implicit `this`, and the first explicit argument is
|
|
|
|
// arg 1.
|
|
|
|
//
|
|
|
|
// Example:
|
|
|
|
//
|
|
|
|
// /* arg_a cannot be null, but arg_b can */
|
|
|
|
// void Function(void* arg_a, void* arg_b) ABSL_ATTRIBUTE_NONNULL(1);
|
|
|
|
//
|
|
|
|
// class C {
|
|
|
|
// /* arg_a cannot be null, but arg_b can */
|
|
|
|
// void Method(void* arg_a, void* arg_b) ABSL_ATTRIBUTE_NONNULL(2);
|
|
|
|
//
|
|
|
|
// /* arg_a cannot be null, but arg_b can */
|
|
|
|
// static void StaticMethod(void* arg_a, void* arg_b)
|
|
|
|
// ABSL_ATTRIBUTE_NONNULL(1);
|
|
|
|
// };
|
|
|
|
//
|
|
|
|
// If no arguments are provided, then all pointer arguments should be non-null.
|
|
|
|
//
|
|
|
|
// /* No pointer arguments may be null. */
|
|
|
|
// void Function(void* arg_a, void* arg_b, int arg_c) ABSL_ATTRIBUTE_NONNULL();
|
|
|
|
//
|
|
|
|
// NOTE: The GCC nonnull attribute actually accepts a list of arguments, but
|
|
|
|
// ABSL_ATTRIBUTE_NONNULL does not.
|
|
|
|
#if ABSL_HAVE_ATTRIBUTE(nonnull) || (defined(__GNUC__) && !defined(__clang__))
|
|
|
|
#define ABSL_ATTRIBUTE_NONNULL(arg_index) __attribute__((nonnull(arg_index)))
|
|
|
|
#else
|
|
|
|
#define ABSL_ATTRIBUTE_NONNULL(...)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_ATTRIBUTE_NORETURN
|
|
|
|
//
|
|
|
|
// Tells the compiler that a given function never returns.
|
|
|
|
#if ABSL_HAVE_ATTRIBUTE(noreturn) || (defined(__GNUC__) && !defined(__clang__))
|
|
|
|
#define ABSL_ATTRIBUTE_NORETURN __attribute__((noreturn))
|
|
|
|
#elif defined(_MSC_VER)
|
|
|
|
#define ABSL_ATTRIBUTE_NORETURN __declspec(noreturn)
|
|
|
|
#else
|
|
|
|
#define ABSL_ATTRIBUTE_NORETURN
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
|
|
|
|
//
|
|
|
|
// Tells the AddressSanitizer (or other memory testing tools) to ignore a given
|
|
|
|
// function. Useful for cases when a function reads random locations on stack,
|
|
|
|
// calls _exit from a cloned subprocess, deliberately accesses buffer
|
|
|
|
// out of bounds or does other scary things with memory.
|
|
|
|
// NOTE: GCC supports AddressSanitizer(asan) since 4.8.
|
|
|
|
// https://gcc.gnu.org/gcc-4.8/changes.html
|
|
|
|
#if defined(__GNUC__) && defined(ADDRESS_SANITIZER)
|
|
|
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
|
|
|
|
#else
|
|
|
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
|
|
|
|
//
|
|
|
|
// Tells the MemorySanitizer to relax the handling of a given function. All
|
|
|
|
// "Use of uninitialized value" warnings from such functions will be suppressed,
|
|
|
|
// and all values loaded from memory will be considered fully initialized.
|
|
|
|
// This attribute is similar to the ADDRESS_SANITIZER attribute above, but deals
|
|
|
|
// with initialized-ness rather than addressability issues.
|
|
|
|
// NOTE: MemorySanitizer(msan) is supported by Clang but not GCC.
|
|
|
|
#if defined(__GNUC__) && defined(MEMORY_SANITIZER)
|
|
|
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
|
|
|
|
#else
|
|
|
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_ATTRIBUTE_NO_SANITIZE_THREAD
|
|
|
|
//
|
|
|
|
// Tells the ThreadSanitizer to not instrument a given function.
|
|
|
|
// NOTE: GCC supports ThreadSanitizer(tsan) since 4.8.
|
|
|
|
// https://gcc.gnu.org/gcc-4.8/changes.html
|
|
|
|
#if defined(__GNUC__) && defined(THREAD_SANITIZER)
|
|
|
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
|
|
|
|
#else
|
|
|
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED
|
|
|
|
//
|
|
|
|
// Tells the UndefinedSanitizer to ignore a given function. Useful for cases
|
|
|
|
// where certain behavior (eg. devision by zero) is being used intentionally.
|
|
|
|
// NOTE: GCC supports UndefinedBehaviorSanitizer(ubsan) since 4.9.
|
|
|
|
// https://gcc.gnu.org/gcc-4.9/changes.html
|
|
|
|
#if defined(__GNUC__) && \
|
|
|
|
(defined(UNDEFINED_BEHAVIOR_SANITIZER) || defined(ADDRESS_SANITIZER))
|
|
|
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \
|
|
|
|
__attribute__((no_sanitize("undefined")))
|
|
|
|
#else
|
|
|
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_ATTRIBUTE_NO_SANITIZE_CFI
|
|
|
|
//
|
|
|
|
// Tells the ControlFlowIntegrity sanitizer to not instrument a given function.
|
|
|
|
// See https://clang.llvm.org/docs/ControlFlowIntegrity.html for details.
|
|
|
|
#if defined(__GNUC__) && defined(CONTROL_FLOW_INTEGRITY)
|
|
|
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi")))
|
|
|
|
#else
|
|
|
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_HAVE_ATTRIBUTE_SECTION
|
|
|
|
//
|
|
|
|
// Indicates whether labeled sections are supported. Labeled sections are not
|
|
|
|
// supported on Darwin/iOS.
|
|
|
|
#ifdef ABSL_HAVE_ATTRIBUTE_SECTION
|
|
|
|
#error ABSL_HAVE_ATTRIBUTE_SECTION cannot be directly set
|
|
|
|
#elif (ABSL_HAVE_ATTRIBUTE(section) || \
|
|
|
|
(defined(__GNUC__) && !defined(__clang__))) && \
|
|
|
|
!defined(__APPLE__)
|
|
|
|
#define ABSL_HAVE_ATTRIBUTE_SECTION 1
|
|
|
|
|
|
|
|
// ABSL_ATTRIBUTE_SECTION
|
|
|
|
//
|
|
|
|
// Tells the compiler/linker to put a given function into a section and define
|
|
|
|
// `__start_ ## name` and `__stop_ ## name` symbols to bracket the section.
|
|
|
|
// This functionality is supported by GNU linker. Any function annotated with
|
|
|
|
// `ABSL_ATTRIBUTE_SECTION` must not be inlined, or it will be placed into
|
|
|
|
// whatever section its caller is placed into.
|
|
|
|
//
|
|
|
|
#ifndef ABSL_ATTRIBUTE_SECTION
|
|
|
|
#define ABSL_ATTRIBUTE_SECTION(name) \
|
|
|
|
__attribute__((section(#name))) __attribute__((noinline))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_ATTRIBUTE_SECTION_VARIABLE
|
|
|
|
//
|
|
|
|
// Tells the compiler/linker to put a given variable into a section and define
|
|
|
|
// `__start_ ## name` and `__stop_ ## name` symbols to bracket the section.
|
|
|
|
// This functionality is supported by GNU linker.
|
|
|
|
#ifndef ABSL_ATTRIBUTE_SECTION_VARIABLE
|
|
|
|
#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name) __attribute__((section(#name)))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_DECLARE_ATTRIBUTE_SECTION_VARS
|
|
|
|
//
|
|
|
|
// A weak section declaration to be used as a global declaration
|
|
|
|
// for ABSL_ATTRIBUTE_SECTION_START|STOP(name) to compile and link
|
|
|
|
// even without functions with ABSL_ATTRIBUTE_SECTION(name).
|
|
|
|
// ABSL_DEFINE_ATTRIBUTE_SECTION should be in the exactly one file; it's
|
|
|
|
// a no-op on ELF but not on Mach-O.
|
|
|
|
//
|
|
|
|
#ifndef ABSL_DECLARE_ATTRIBUTE_SECTION_VARS
|
|
|
|
#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) \
|
|
|
|
extern char __start_##name[] ABSL_ATTRIBUTE_WEAK; \
|
|
|
|
extern char __stop_##name[] ABSL_ATTRIBUTE_WEAK
|
|
|
|
#endif
|
|
|
|
#ifndef ABSL_DEFINE_ATTRIBUTE_SECTION_VARS
|
|
|
|
#define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name)
|
|
|
|
#define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_ATTRIBUTE_SECTION_START
|
|
|
|
//
|
|
|
|
// Returns `void*` pointers to start/end of a section of code with
|
|
|
|
// functions having ABSL_ATTRIBUTE_SECTION(name).
|
|
|
|
// Returns 0 if no such functions exist.
|
|
|
|
// One must ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) for this to compile and
|
|
|
|
// link.
|
|
|
|
//
|
|
|
|
#define ABSL_ATTRIBUTE_SECTION_START(name) \
|
|
|
|
(reinterpret_cast<void *>(__start_##name))
|
|
|
|
#define ABSL_ATTRIBUTE_SECTION_STOP(name) \
|
|
|
|
(reinterpret_cast<void *>(__stop_##name))
|
|
|
|
#else // !ABSL_HAVE_ATTRIBUTE_SECTION
|
|
|
|
|
|
|
|
#define ABSL_HAVE_ATTRIBUTE_SECTION 0
|
|
|
|
|
|
|
|
// provide dummy definitions
|
|
|
|
#define ABSL_ATTRIBUTE_SECTION(name)
|
|
|
|
#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name)
|
|
|
|
#define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name)
|
|
|
|
#define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name)
|
|
|
|
#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name)
|
|
|
|
#define ABSL_ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void *>(0))
|
|
|
|
#define ABSL_ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void *>(0))
|
|
|
|
#endif // ABSL_ATTRIBUTE_SECTION
|
|
|
|
|
|
|
|
// ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
|
|
|
|
//
|
|
|
|
// Support for aligning the stack on 32-bit x86.
|
|
|
|
#if ABSL_HAVE_ATTRIBUTE(force_align_arg_pointer) || \
|
|
|
|
(defined(__GNUC__) && !defined(__clang__))
|
|
|
|
#if defined(__i386__)
|
|
|
|
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC \
|
|
|
|
__attribute__((force_align_arg_pointer))
|
|
|
|
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
|
|
|
|
#elif defined(__x86_64__)
|
|
|
|
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (1)
|
|
|
|
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
|
|
|
|
#else // !__i386__ && !__x86_64
|
|
|
|
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
|
|
|
|
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
|
|
|
|
#endif // __i386__
|
|
|
|
#else
|
|
|
|
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
|
|
|
|
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_MUST_USE_RESULT
|
|
|
|
//
|
|
|
|
// Tells the compiler to warn about unused return values for functions declared
|
|
|
|
// with this macro. The macro must appear as the very first part of a function
|
|
|
|
// declaration or definition:
|
|
|
|
//
|
|
|
|
// Example:
|
|
|
|
//
|
|
|
|
// ABSL_MUST_USE_RESULT Sprocket* AllocateSprocket();
|
|
|
|
//
|
|
|
|
// This placement has the broadest compatibility with GCC, Clang, and MSVC, with
|
|
|
|
// both defs and decls, and with GCC-style attributes, MSVC declspec, C++11
|
|
|
|
// and C++17 attributes.
|
|
|
|
//
|
|
|
|
// ABSL_MUST_USE_RESULT allows using cast-to-void to suppress the unused result
|
|
|
|
// warning. For that, warn_unused_result is used only for clang but not for gcc.
|
|
|
|
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425
|
|
|
|
//
|
|
|
|
// Note: past advice was to place the macro after the argument list.
|
|
|
|
#if ABSL_HAVE_ATTRIBUTE(nodiscard)
|
|
|
|
#define ABSL_MUST_USE_RESULT [[nodiscard]]
|
|
|
|
#elif defined(__clang__) && ABSL_HAVE_ATTRIBUTE(warn_unused_result)
|
|
|
|
#define ABSL_MUST_USE_RESULT __attribute__((warn_unused_result))
|
|
|
|
#else
|
|
|
|
#define ABSL_MUST_USE_RESULT
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_ATTRIBUTE_HOT, ABSL_ATTRIBUTE_COLD
|
|
|
|
//
|
|
|
|
// Tells GCC that a function is hot or cold. GCC can use this information to
|
|
|
|
// improve static analysis, i.e. a conditional branch to a cold function
|
|
|
|
// is likely to be not-taken.
|
|
|
|
// This annotation is used for function declarations.
|
|
|
|
//
|
|
|
|
// Example:
|
|
|
|
//
|
|
|
|
// int foo() ABSL_ATTRIBUTE_HOT;
|
|
|
|
#if ABSL_HAVE_ATTRIBUTE(hot) || (defined(__GNUC__) && !defined(__clang__))
|
|
|
|
#define ABSL_ATTRIBUTE_HOT __attribute__((hot))
|
|
|
|
#else
|
|
|
|
#define ABSL_ATTRIBUTE_HOT
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if ABSL_HAVE_ATTRIBUTE(cold) || (defined(__GNUC__) && !defined(__clang__))
|
|
|
|
#define ABSL_ATTRIBUTE_COLD __attribute__((cold))
|
|
|
|
#else
|
|
|
|
#define ABSL_ATTRIBUTE_COLD
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_XRAY_ALWAYS_INSTRUMENT, ABSL_XRAY_NEVER_INSTRUMENT, ABSL_XRAY_LOG_ARGS
|
|
|
|
//
|
|
|
|
// We define the ABSL_XRAY_ALWAYS_INSTRUMENT and ABSL_XRAY_NEVER_INSTRUMENT
|
|
|
|
// macro used as an attribute to mark functions that must always or never be
|
|
|
|
// instrumented by XRay. Currently, this is only supported in Clang/LLVM.
|
|
|
|
//
|
|
|
|
// For reference on the LLVM XRay instrumentation, see
|
|
|
|
// http://llvm.org/docs/XRay.html.
|
|
|
|
//
|
|
|
|
// A function with the XRAY_ALWAYS_INSTRUMENT macro attribute in its declaration
|
|
|
|
// will always get the XRay instrumentation sleds. These sleds may introduce
|
|
|
|
// some binary size and runtime overhead and must be used sparingly.
|
|
|
|
//
|
|
|
|
// These attributes only take effect when the following conditions are met:
|
|
|
|
//
|
|
|
|
// * The file/target is built in at least C++11 mode, with a Clang compiler
|
|
|
|
// that supports XRay attributes.
|
|
|
|
// * The file/target is built with the -fxray-instrument flag set for the
|
|
|
|
// Clang/LLVM compiler.
|
|
|
|
// * The function is defined in the translation unit (the compiler honors the
|
|
|
|
// attribute in either the definition or the declaration, and must match).
|
|
|
|
//
|
|
|
|
// There are cases when, even when building with XRay instrumentation, users
|
|
|
|
// might want to control specifically which functions are instrumented for a
|
|
|
|
// particular build using special-case lists provided to the compiler. These
|
|
|
|
// special case lists are provided to Clang via the
|
|
|
|
// -fxray-always-instrument=... and -fxray-never-instrument=... flags. The
|
|
|
|
// attributes in source take precedence over these special-case lists.
|
|
|
|
//
|
|
|
|
// To disable the XRay attributes at build-time, users may define
|
|
|
|
// ABSL_NO_XRAY_ATTRIBUTES. Do NOT define ABSL_NO_XRAY_ATTRIBUTES on specific
|
|
|
|
// packages/targets, as this may lead to conflicting definitions of functions at
|
|
|
|
// link-time.
|
|
|
|
//
|
|
|
|
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_always_instrument) && \
|
|
|
|
!defined(ABSL_NO_XRAY_ATTRIBUTES)
|
|
|
|
#define ABSL_XRAY_ALWAYS_INSTRUMENT [[clang::xray_always_instrument]]
|
|
|
|
#define ABSL_XRAY_NEVER_INSTRUMENT [[clang::xray_never_instrument]]
|
|
|
|
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_log_args)
|
|
|
|
#define ABSL_XRAY_LOG_ARGS(N) \
|
|
|
|
[[clang::xray_always_instrument, clang::xray_log_args(N)]]
|
|
|
|
#else
|
|
|
|
#define ABSL_XRAY_LOG_ARGS(N) [[clang::xray_always_instrument]]
|
|
|
|
#endif
|
|
|
|
#else
|
|
|
|
#define ABSL_XRAY_ALWAYS_INSTRUMENT
|
|
|
|
#define ABSL_XRAY_NEVER_INSTRUMENT
|
|
|
|
#define ABSL_XRAY_LOG_ARGS(N)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Variable Attributes
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// ABSL_ATTRIBUTE_UNUSED
|
|
|
|
//
|
|
|
|
// Prevents the compiler from complaining about or optimizing away variables
|
|
|
|
// that appear unused.
|
|
|
|
#if ABSL_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__))
|
|
|
|
#undef ABSL_ATTRIBUTE_UNUSED
|
|
|
|
#define ABSL_ATTRIBUTE_UNUSED __attribute__((__unused__))
|
|
|
|
#else
|
|
|
|
#define ABSL_ATTRIBUTE_UNUSED
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_ATTRIBUTE_INITIAL_EXEC
|
|
|
|
//
|
|
|
|
// Tells the compiler to use "initial-exec" mode for a thread-local variable.
|
|
|
|
// See http://people.redhat.com/drepper/tls.pdf for the gory details.
|
|
|
|
#if ABSL_HAVE_ATTRIBUTE(tls_model) || (defined(__GNUC__) && !defined(__clang__))
|
|
|
|
#define ABSL_ATTRIBUTE_INITIAL_EXEC __attribute__((tls_model("initial-exec")))
|
|
|
|
#else
|
|
|
|
#define ABSL_ATTRIBUTE_INITIAL_EXEC
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_ATTRIBUTE_PACKED
|
|
|
|
//
|
|
|
|
// Prevents the compiler from padding a structure to natural alignment
|
|
|
|
#if ABSL_HAVE_ATTRIBUTE(packed) || (defined(__GNUC__) && !defined(__clang__))
|
|
|
|
#define ABSL_ATTRIBUTE_PACKED __attribute__((__packed__))
|
|
|
|
#else
|
|
|
|
#define ABSL_ATTRIBUTE_PACKED
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_CONST_INIT
|
|
|
|
//
|
|
|
|
// A variable declaration annotated with the `ABSL_CONST_INIT` attribute will
|
|
|
|
// not compile (on supported platforms) unless the variable has a constant
|
|
|
|
// initializer. This is useful for variables with static and thread storage
|
|
|
|
// duration, because it guarantees that they will not suffer from the so-called
|
|
|
|
// "static init order fiasco".
|
|
|
|
//
|
|
|
|
// Example:
|
|
|
|
//
|
|
|
|
// ABSL_CONST_INIT static MyType my_var = MakeMyType(...);
|
|
|
|
//
|
|
|
|
// Note that this attribute is redundant if the variable is declared constexpr.
|
|
|
|
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
|
|
|
|
// NOLINTNEXTLINE(whitespace/braces)
|
|
|
|
#define ABSL_CONST_INIT [[clang::require_constant_initialization]]
|
|
|
|
#else
|
|
|
|
#define ABSL_CONST_INIT
|
|
|
|
#endif // ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
|
|
|
|
|
|
|
|
#endif // ABSL_BASE_ATTRIBUTES_H_
|
|
|
|
//
|
|
|
|
// Copyright 2017 The Abseil Authors.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
//
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// File: config.h
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// This header file defines a set of macros for checking the presence of
|
|
|
|
// important compiler and platform features. Such macros can be used to
|
|
|
|
// produce portable code by parameterizing compilation based on the presence or
|
|
|
|
// lack of a given feature.
|
|
|
|
//
|
|
|
|
// We define a "feature" as some interface we wish to program to: for example,
|
|
|
|
// a library function or system call. A value of `1` indicates support for
|
|
|
|
// that feature; any other value indicates the feature support is undefined.
|
|
|
|
//
|
|
|
|
// Example:
|
|
|
|
//
|
|
|
|
// Suppose a programmer wants to write a program that uses the 'mmap()' system
|
|
|
|
// call. The Abseil macro for that feature (`ABSL_HAVE_MMAP`) allows you to
|
|
|
|
// selectively include the `mmap.h` header and bracket code using that feature
|
|
|
|
// in the macro:
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// #ifdef ABSL_HAVE_MMAP
|
|
|
|
// #include "sys/mman.h"
|
|
|
|
// #endif //ABSL_HAVE_MMAP
|
|
|
|
//
|
|
|
|
// ...
|
|
|
|
// #ifdef ABSL_HAVE_MMAP
|
|
|
|
// void *ptr = mmap(...);
|
|
|
|
// ...
|
|
|
|
// #endif // ABSL_HAVE_MMAP
|
|
|
|
|
|
|
|
#ifndef ABSL_BASE_CONFIG_H_
|
|
|
|
#define ABSL_BASE_CONFIG_H_
|
|
|
|
|
|
|
|
// Included for the __GLIBC__ macro (or similar macros on other systems).
|
|
|
|
#include <limits.h>
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
// Included for __GLIBCXX__, _LIBCPP_VERSION
|
|
|
|
#include <cstddef>
|
|
|
|
#endif // __cplusplus
|
|
|
|
|
|
|
|
#if defined(__APPLE__)
|
|
|
|
// Included for TARGET_OS_IPHONE, __IPHONE_OS_VERSION_MIN_REQUIRED,
|
|
|
|
// __IPHONE_8_0.
|
|
|
|
#include <Availability.h>
|
|
|
|
#include <TargetConditionals.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Compiler Feature Checks
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// ABSL_HAVE_BUILTIN()
|
|
|
|
//
|
|
|
|
// Checks whether the compiler supports a Clang Feature Checking Macro, and if
|
|
|
|
// so, checks whether it supports the provided builtin function "x" where x
|
|
|
|
// is one of the functions noted in
|
|
|
|
// https://clang.llvm.org/docs/LanguageExtensions.html
|
|
|
|
//
|
|
|
|
// Note: Use this macro to avoid an extra level of #ifdef __has_builtin check.
|
|
|
|
// http://releases.llvm.org/3.3/tools/clang/docs/LanguageExtensions.html
|
|
|
|
#ifdef __has_builtin
|
|
|
|
#define ABSL_HAVE_BUILTIN(x) __has_builtin(x)
|
|
|
|
#else
|
|
|
|
#define ABSL_HAVE_BUILTIN(x) 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_HAVE_TLS is defined to 1 when __thread should be supported.
|
|
|
|
// We assume __thread is supported on Linux when compiled with Clang or compiled
|
|
|
|
// against libstdc++ with _GLIBCXX_HAVE_TLS defined.
|
|
|
|
#ifdef ABSL_HAVE_TLS
|
|
|
|
#error ABSL_HAVE_TLS cannot be directly set
|
|
|
|
#elif defined(__linux__) && (defined(__clang__) || defined(_GLIBCXX_HAVE_TLS))
|
|
|
|
#define ABSL_HAVE_TLS 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// There are platforms for which TLS should not be used even though the compiler
|
|
|
|
// makes it seem like it's supported (Android NDK < r12b for example).
|
|
|
|
// This is primarily because of linker problems and toolchain misconfiguration:
|
|
|
|
// Abseil does not intend to support this indefinitely. Currently, the newest
|
|
|
|
// toolchain that we intend to support that requires this behavior is the
|
|
|
|
// r11 NDK - allowing for a 5 year support window on that means this option
|
|
|
|
// is likely to be removed around June of 2021.
|
|
|
|
#if defined(__ANDROID__) && defined(__clang__)
|
|
|
|
#if __has_include(<android/ndk-version.h>)
|
|
|
|
#include <android/ndk-version.h>
|
|
|
|
#endif
|
|
|
|
// TLS isn't supported until NDK r12b per
|
|
|
|
// https://developer.android.com/ndk/downloads/revision_history.html
|
|
|
|
// Since NDK r16, `__NDK_MAJOR__` and `__NDK_MINOR__` are defined in
|
|
|
|
// <android/ndk-version.h>. For NDK < r16, users should define these macros,
|
|
|
|
// e.g. `-D__NDK_MAJOR__=11 -D__NKD_MINOR__=0` for NDK r11.
|
|
|
|
#if defined(__NDK_MAJOR__) && defined(__NDK_MINOR__) && \
|
|
|
|
((__NDK_MAJOR__ < 12) || ((__NDK_MAJOR__ == 12) && (__NDK_MINOR__ < 1)))
|
|
|
|
#undef ABSL_HAVE_TLS
|
|
|
|
#endif
|
|
|
|
#endif // defined(__ANDROID__) && defined(__clang__)
|
|
|
|
|
|
|
|
// ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
|
|
|
|
//
|
|
|
|
// Checks whether `std::is_trivially_destructible<T>` is supported.
|
|
|
|
//
|
|
|
|
// Notes: All supported compilers using libc++ support this feature, as does
|
|
|
|
// gcc >= 4.8.1 using libstdc++, and Visual Studio.
|
|
|
|
#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
|
|
|
|
#error ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE cannot be directly set
|
|
|
|
#elif defined(_LIBCPP_VERSION) || \
|
|
|
|
(!defined(__clang__) && defined(__GNUC__) && defined(__GLIBCXX__) && \
|
|
|
|
(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || \
|
|
|
|
defined(_MSC_VER)
|
|
|
|
#define ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
|
|
|
|
//
|
|
|
|
// Checks whether `std::is_trivially_default_constructible<T>` and
|
|
|
|
// `std::is_trivially_copy_constructible<T>` are supported.
|
|
|
|
|
|
|
|
// ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
|
|
|
|
//
|
|
|
|
// Checks whether `std::is_trivially_copy_assignable<T>` is supported.
|
|
|
|
|
|
|
|
// Notes: Clang with libc++ supports these features, as does gcc >= 5.1 with
|
|
|
|
// either libc++ or libstdc++, and Visual Studio.
|
|
|
|
#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE)
|
|
|
|
#error ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE cannot be directly set
|
|
|
|
#elif defined(ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE)
|
|
|
|
#error ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE cannot directly set
|
|
|
|
#elif (defined(__clang__) && defined(_LIBCPP_VERSION)) || \
|
|
|
|
(!defined(__clang__) && defined(__GNUC__) && \
|
|
|
|
(__GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)) && \
|
|
|
|
(defined(_LIBCPP_VERSION) || defined(__GLIBCXX__))) || \
|
|
|
|
defined(_MSC_VER)
|
|
|
|
#define ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1
|
|
|
|
#define ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_HAVE_THREAD_LOCAL
|
|
|
|
//
|
|
|
|
// Checks whether C++11's `thread_local` storage duration specifier is
|
|
|
|
// supported.
|
|
|
|
#ifdef ABSL_HAVE_THREAD_LOCAL
|
|
|
|
#error ABSL_HAVE_THREAD_LOCAL cannot be directly set
|
|
|
|
#elif !defined(__apple_build_version__) || \
|
|
|
|
((__apple_build_version__ >= 8000042) && \
|
|
|
|
!(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0))
|
|
|
|
// Notes: Xcode's clang did not support `thread_local` until version
|
|
|
|
// 8, and even then not for all iOS < 9.0.
|
|
|
|
#define ABSL_HAVE_THREAD_LOCAL 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_HAVE_INTRINSIC_INT128
|
|
|
|
//
|
|
|
|
// Checks whether the __int128 compiler extension for a 128-bit integral type is
|
|
|
|
// supported.
|
|
|
|
//
|
|
|
|
// Notes: __SIZEOF_INT128__ is defined by Clang and GCC when __int128 is
|
|
|
|
// supported, except on ppc64 and aarch64 where __int128 exists but has exhibits
|
|
|
|
// a sporadic compiler crashing bug. Nvidia's nvcc also defines __GNUC__ and
|
|
|
|
// __SIZEOF_INT128__ but not all versions actually support __int128.
|
|
|
|
#ifdef ABSL_HAVE_INTRINSIC_INT128
|
|
|
|
#error ABSL_HAVE_INTRINSIC_INT128 cannot be directly set
|
|
|
|
#elif (defined(__clang__) && defined(__SIZEOF_INT128__) && \
|
|
|
|
!defined(__ppc64__) && !defined(__aarch64__)) || \
|
|
|
|
(defined(__CUDACC__) && defined(__SIZEOF_INT128__) && \
|
|
|
|
__CUDACC_VER__ >= 70000) || \
|
|
|
|
(!defined(__clang__) && !defined(__CUDACC__) && defined(__GNUC__) && \
|
|
|
|
defined(__SIZEOF_INT128__))
|
|
|
|
#define ABSL_HAVE_INTRINSIC_INT128 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_HAVE_EXCEPTIONS
|
|
|
|
//
|
|
|
|
// Checks whether the compiler both supports and enables exceptions. Many
|
|
|
|
// compilers support a "no exceptions" mode that disables exceptions.
|
|
|
|
//
|
|
|
|
// Generally, when ABSL_HAVE_EXCEPTIONS is not defined:
|
|
|
|
//
|
|
|
|
// * Code using `throw` and `try` may not compile.
|
|
|
|
// * The `noexcept` specifier will still compile and behave as normal.
|
|
|
|
// * The `noexcept` operator may still return `false`.
|
|
|
|
//
|
|
|
|
// For further details, consult the compiler's documentation.
|
|
|
|
#ifdef ABSL_HAVE_EXCEPTIONS
|
|
|
|
#error ABSL_HAVE_EXCEPTIONS cannot be directly set.
|
|
|
|
|
|
|
|
#elif defined(__clang__)
|
|
|
|
// TODO(calabrese)
|
|
|
|
// Switch to using __cpp_exceptions when we no longer support versions < 3.6.
|
|
|
|
// For details on this check, see:
|
|
|
|
// http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro
|
|
|
|
#if defined(__EXCEPTIONS) && __has_feature(cxx_exceptions)
|
|
|
|
#define ABSL_HAVE_EXCEPTIONS 1
|
|
|
|
#endif // defined(__EXCEPTIONS) && __has_feature(cxx_exceptions)
|
|
|
|
|
|
|
|
// Handle remaining special cases and default to exceptions being supported.
|
|
|
|
#elif !(defined(__GNUC__) && (__GNUC__ < 5) && !defined(__EXCEPTIONS)) && \
|
|
|
|
!(defined(__GNUC__) && (__GNUC__ >= 5) && !defined(__cpp_exceptions)) && \
|
|
|
|
!(defined(_MSC_VER) && !defined(_CPPUNWIND))
|
|
|
|
#define ABSL_HAVE_EXCEPTIONS 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Platform Feature Checks
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// Currently supported operating systems and associated preprocessor
|
|
|
|
// symbols:
|
|
|
|
//
|
|
|
|
// Linux and Linux-derived __linux__
|
|
|
|
// Android __ANDROID__ (implies __linux__)
|
|
|
|
// Linux (non-Android) __linux__ && !__ANDROID__
|
|
|
|
// Darwin (Mac OS X and iOS) __APPLE__
|
|
|
|
// Akaros (http://akaros.org) __ros__
|
|
|
|
// Windows _WIN32
|
|
|
|
// NaCL __native_client__
|
|
|
|
// AsmJS __asmjs__
|
|
|
|
// Fuschia __Fuchsia__
|
|
|
|
//
|
|
|
|
// Note that since Android defines both __ANDROID__ and __linux__, one
|
|
|
|
// may probe for either Linux or Android by simply testing for __linux__.
|
|
|
|
|
|
|
|
// ABSL_HAVE_MMAP
|
|
|
|
//
|
|
|
|
// Checks whether the platform has an mmap(2) implementation as defined in
|
|
|
|
// POSIX.1-2001.
|
|
|
|
#ifdef ABSL_HAVE_MMAP
|
|
|
|
#error ABSL_HAVE_MMAP cannot be directly set
|
|
|
|
#elif defined(__linux__) || defined(__APPLE__) || defined(__ros__) || \
|
|
|
|
defined(__native_client__) || defined(__asmjs__) || defined(__Fuchsia__)
|
|
|
|
#define ABSL_HAVE_MMAP 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_HAVE_PTHREAD_GETSCHEDPARAM
|
|
|
|
//
|
|
|
|
// Checks whether the platform implements the pthread_(get|set)schedparam(3)
|
|
|
|
// functions as defined in POSIX.1-2001.
|
|
|
|
#ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM
|
|
|
|
#error ABSL_HAVE_PTHREAD_GETSCHEDPARAM cannot be directly set
|
|
|
|
#elif defined(__linux__) || defined(__APPLE__) || defined(__ros__)
|
|
|
|
#define ABSL_HAVE_PTHREAD_GETSCHEDPARAM 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_HAVE_SCHED_YIELD
|
|
|
|
//
|
|
|
|
// Checks whether the platform implements sched_yield(2) as defined in
|
|
|
|
// POSIX.1-2001.
|
|
|
|
#ifdef ABSL_HAVE_SCHED_YIELD
|
|
|
|
#error ABSL_HAVE_SCHED_YIELD cannot be directly set
|
|
|
|
#elif defined(__linux__) || defined(__ros__) || defined(__native_client__)
|
|
|
|
#define ABSL_HAVE_SCHED_YIELD 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_HAVE_SEMAPHORE_H
|
|
|
|
//
|
|
|
|
// Checks whether the platform supports the <semaphore.h> header and sem_open(3)
|
|
|
|
// family of functions as standardized in POSIX.1-2001.
|
|
|
|
//
|
|
|
|
// Note: While Apple provides <semaphore.h> for both iOS and macOS, it is
|
2018-04-20 01:49:22 +08:00
|
|
|
// explicitly deprecated and will cause build failures if enabled for those
|
2017-10-14 05:13:47 +08:00
|
|
|
// platforms. We side-step the issue by not defining it here for Apple
|
|
|
|
// platforms.
|
|
|
|
#ifdef ABSL_HAVE_SEMAPHORE_H
|
|
|
|
#error ABSL_HAVE_SEMAPHORE_H cannot be directly set
|
|
|
|
#elif defined(__linux__) || defined(__ros__)
|
|
|
|
#define ABSL_HAVE_SEMAPHORE_H 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_HAVE_ALARM
|
|
|
|
//
|
|
|
|
// Checks whether the platform supports the <signal.h> header and alarm(2)
|
|
|
|
// function as standardized in POSIX.1-2001.
|
|
|
|
#ifdef ABSL_HAVE_ALARM
|
|
|
|
#error ABSL_HAVE_ALARM cannot be directly set
|
|
|
|
#elif defined(__GOOGLE_GRTE_VERSION__)
|
|
|
|
// feature tests for Google's GRTE
|
|
|
|
#define ABSL_HAVE_ALARM 1
|
|
|
|
#elif defined(__GLIBC__)
|
|
|
|
// feature test for glibc
|
|
|
|
#define ABSL_HAVE_ALARM 1
|
|
|
|
#elif defined(_MSC_VER)
|
|
|
|
// feature tests for Microsoft's library
|
|
|
|
#elif defined(__native_client__)
|
|
|
|
#else
|
|
|
|
// other standard libraries
|
|
|
|
#define ABSL_HAVE_ALARM 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_IS_LITTLE_ENDIAN
|
|
|
|
// ABSL_IS_BIG_ENDIAN
|
|
|
|
//
|
|
|
|
// Checks the endianness of the platform.
|
|
|
|
//
|
|
|
|
// Notes: uses the built in endian macros provided by GCC (since 4.6) and
|
|
|
|
// Clang (since 3.2); see
|
|
|
|
// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html.
|
|
|
|
// Otherwise, if _WIN32, assume little endian. Otherwise, bail with an error.
|
|
|
|
#if defined(ABSL_IS_BIG_ENDIAN)
|
|
|
|
#error "ABSL_IS_BIG_ENDIAN cannot be directly set."
|
|
|
|
#endif
|
|
|
|
#if defined(ABSL_IS_LITTLE_ENDIAN)
|
|
|
|
#error "ABSL_IS_LITTLE_ENDIAN cannot be directly set."
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
|
|
|
|
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
|
|
|
#define ABSL_IS_LITTLE_ENDIAN 1
|
|
|
|
#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
|
|
|
|
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
|
|
|
#define ABSL_IS_BIG_ENDIAN 1
|
|
|
|
#elif defined(_WIN32)
|
|
|
|
#define ABSL_IS_LITTLE_ENDIAN 1
|
|
|
|
#else
|
|
|
|
#error "absl endian detection needs to be set up for your compiler"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_HAVE_STD_ANY
|
|
|
|
//
|
2018-04-20 01:49:22 +08:00
|
|
|
// Checks whether C++17 std::any is available by checking whether <any> exists.
|
2017-10-14 05:13:47 +08:00
|
|
|
#ifdef ABSL_HAVE_STD_ANY
|
|
|
|
#error "ABSL_HAVE_STD_ANY cannot be directly set."
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef __has_include
|
|
|
|
#if __has_include(<any>) && __cplusplus >= 201703L
|
|
|
|
#define ABSL_HAVE_STD_ANY 1
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_HAVE_STD_OPTIONAL
|
|
|
|
//
|
|
|
|
// Checks whether C++17 std::optional is available.
|
|
|
|
#ifdef ABSL_HAVE_STD_OPTIONAL
|
|
|
|
#error "ABSL_HAVE_STD_OPTIONAL cannot be directly set."
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef __has_include
|
|
|
|
#if __has_include(<optional>) && __cplusplus >= 201703L
|
|
|
|
#define ABSL_HAVE_STD_OPTIONAL 1
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_HAVE_STD_STRING_VIEW
|
|
|
|
//
|
|
|
|
// Checks whether C++17 std::string_view is available.
|
|
|
|
#ifdef ABSL_HAVE_STD_STRING_VIEW
|
|
|
|
#error "ABSL_HAVE_STD_STRING_VIEW cannot be directly set."
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef __has_include
|
|
|
|
#if __has_include(<string_view>) && __cplusplus >= 201703L
|
|
|
|
#define ABSL_HAVE_STD_STRING_VIEW 1
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif // ABSL_BASE_CONFIG_H_
|
|
|
|
//
|
|
|
|
// Copyright 2017 The Abseil Authors.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
//
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// File: optimization.h
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// This header file defines portable macros for performance optimization.
|
|
|
|
|
|
|
|
#ifndef ABSL_BASE_OPTIMIZATION_H_
|
|
|
|
#define ABSL_BASE_OPTIMIZATION_H_
|
|
|
|
|
|
|
|
|
|
|
|
// ABSL_BLOCK_TAIL_CALL_OPTIMIZATION
|
|
|
|
//
|
|
|
|
// Instructs the compiler to avoid optimizing tail-call recursion. Use of this
|
|
|
|
// macro is useful when you wish to preserve the existing function order within
|
|
|
|
// a stack trace for logging, debugging, or profiling purposes.
|
|
|
|
//
|
|
|
|
// Example:
|
|
|
|
//
|
|
|
|
// int f() {
|
|
|
|
// int result = g();
|
|
|
|
// ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
|
|
|
|
// return result;
|
|
|
|
// }
|
|
|
|
#if defined(__pnacl__)
|
|
|
|
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; }
|
|
|
|
#elif defined(__clang__)
|
|
|
|
// Clang will not tail call given inline volatile assembly.
|
|
|
|
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
|
|
|
|
#elif defined(__GNUC__)
|
|
|
|
// GCC will not tail call given inline volatile assembly.
|
|
|
|
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
|
|
|
|
#elif defined(_MSC_VER)
|
|
|
|
#include <intrin.h>
|
|
|
|
// The __nop() intrinsic blocks the optimisation.
|
|
|
|
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __nop()
|
|
|
|
#else
|
|
|
|
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; }
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_CACHELINE_SIZE
|
|
|
|
//
|
|
|
|
// Explicitly defines the size of the L1 cache for purposes of alignment.
|
|
|
|
// Setting the cacheline size allows you to specify that certain objects be
|
|
|
|
// aligned on a cacheline boundary with `ABSL_CACHELINE_ALIGNED` declarations.
|
|
|
|
// (See below.)
|
|
|
|
//
|
|
|
|
// NOTE: this macro should be replaced with the following C++17 features, when
|
|
|
|
// those are generally available:
|
|
|
|
//
|
|
|
|
// * `std::hardware_constructive_interference_size`
|
|
|
|
// * `std::hardware_destructive_interference_size`
|
|
|
|
//
|
|
|
|
// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
|
|
|
|
// for more information.
|
|
|
|
#if defined(__GNUC__)
|
|
|
|
// Cache line alignment
|
|
|
|
#if defined(__i386__) || defined(__x86_64__)
|
|
|
|
#define ABSL_CACHELINE_SIZE 64
|
|
|
|
#elif defined(__powerpc64__)
|
|
|
|
#define ABSL_CACHELINE_SIZE 128
|
|
|
|
#elif defined(__aarch64__)
|
|
|
|
// We would need to read special register ctr_el0 to find out L1 dcache size.
|
|
|
|
// This value is a good estimate based on a real aarch64 machine.
|
|
|
|
#define ABSL_CACHELINE_SIZE 64
|
|
|
|
#elif defined(__arm__)
|
|
|
|
// Cache line sizes for ARM: These values are not strictly correct since
|
|
|
|
// cache line sizes depend on implementations, not architectures. There
|
|
|
|
// are even implementations with cache line sizes configurable at boot
|
|
|
|
// time.
|
|
|
|
#if defined(__ARM_ARCH_5T__)
|
|
|
|
#define ABSL_CACHELINE_SIZE 32
|
|
|
|
#elif defined(__ARM_ARCH_7A__)
|
|
|
|
#define ABSL_CACHELINE_SIZE 64
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef ABSL_CACHELINE_SIZE
|
|
|
|
// A reasonable default guess. Note that overestimates tend to waste more
|
|
|
|
// space, while underestimates tend to waste more time.
|
|
|
|
#define ABSL_CACHELINE_SIZE 64
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_CACHELINE_ALIGNED
|
|
|
|
//
|
|
|
|
// Indicates that the declared object be cache aligned using
|
|
|
|
// `ABSL_CACHELINE_SIZE` (see above). Cacheline aligning objects allows you to
|
|
|
|
// load a set of related objects in the L1 cache for performance improvements.
|
|
|
|
// Cacheline aligning objects properly allows constructive memory sharing and
|
|
|
|
// prevents destructive (or "false") memory sharing.
|
|
|
|
//
|
|
|
|
// NOTE: this macro should be replaced with usage of `alignas()` using
|
|
|
|
// `std::hardware_constructive_interference_size` and/or
|
|
|
|
// `std::hardware_destructive_interference_size` when available within C++17.
|
|
|
|
//
|
|
|
|
// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
|
|
|
|
// for more information.
|
|
|
|
//
|
|
|
|
// On some compilers, `ABSL_CACHELINE_ALIGNED` expands to
|
|
|
|
// `__attribute__((aligned(ABSL_CACHELINE_SIZE)))`. For compilers where this is
|
|
|
|
// not known to work, the macro expands to nothing.
|
|
|
|
//
|
|
|
|
// No further guarantees are made here. The result of applying the macro
|
|
|
|
// to variables and types is always implementation-defined.
|
|
|
|
//
|
|
|
|
// WARNING: It is easy to use this attribute incorrectly, even to the point
|
|
|
|
// of causing bugs that are difficult to diagnose, crash, etc. It does not
|
|
|
|
// of itself guarantee that objects are aligned to a cache line.
|
|
|
|
//
|
|
|
|
// Recommendations:
|
|
|
|
//
|
|
|
|
// 1) Consult compiler documentation; this comment is not kept in sync as
|
|
|
|
// toolchains evolve.
|
|
|
|
// 2) Verify your use has the intended effect. This often requires inspecting
|
|
|
|
// the generated machine code.
|
|
|
|
// 3) Prefer applying this attribute to individual variables. Avoid
|
|
|
|
// applying it to types. This tends to localize the effect.
|
|
|
|
#define ABSL_CACHELINE_ALIGNED __attribute__((aligned(ABSL_CACHELINE_SIZE)))
|
|
|
|
|
|
|
|
#else // not GCC
|
|
|
|
#define ABSL_CACHELINE_SIZE 64
|
|
|
|
#define ABSL_CACHELINE_ALIGNED
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_PREDICT_TRUE, ABSL_PREDICT_FALSE
|
|
|
|
//
|
|
|
|
// Enables the compiler to prioritize compilation using static analysis for
|
|
|
|
// likely paths within a boolean branch.
|
|
|
|
//
|
|
|
|
// Example:
|
|
|
|
//
|
|
|
|
// if (ABSL_PREDICT_TRUE(expression)) {
|
|
|
|
// return result; // Faster if more likely
|
|
|
|
// } else {
|
|
|
|
// return 0;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// Compilers can use the information that a certain branch is not likely to be
|
|
|
|
// taken (for instance, a CHECK failure) to optimize for the common case in
|
|
|
|
// the absence of better information (ie. compiling gcc with `-fprofile-arcs`).
|
|
|
|
#if ABSL_HAVE_BUILTIN(__builtin_expect) || \
|
|
|
|
(defined(__GNUC__) && !defined(__clang__))
|
|
|
|
#define ABSL_PREDICT_FALSE(x) (__builtin_expect(x, 0))
|
|
|
|
#define ABSL_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
|
|
|
|
#else
|
|
|
|
#define ABSL_PREDICT_FALSE(x) x
|
|
|
|
#define ABSL_PREDICT_TRUE(x) x
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif // ABSL_BASE_OPTIMIZATION_H_
|
|
|
|
//
|
|
|
|
// Copyright 2017 The Abseil Authors.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
//
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// File: macros.h
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// This header file defines the set of language macros used within Abseil code.
|
|
|
|
// For the set of macros used to determine supported compilers and platforms,
|
|
|
|
// see absl/base/config.h instead.
|
|
|
|
//
|
|
|
|
// This code is compiled directly on many platforms, including client
|
|
|
|
// platforms like Windows, Mac, and embedded systems. Before making
|
|
|
|
// any changes here, make sure that you're not breaking any platforms.
|
|
|
|
//
|
|
|
|
|
|
|
|
#ifndef ABSL_BASE_MACROS_H_
|
|
|
|
#define ABSL_BASE_MACROS_H_
|
|
|
|
|
|
|
|
#include <cstddef>
|
|
|
|
|
|
|
|
|
|
|
|
// ABSL_ARRAYSIZE()
|
|
|
|
//
|
|
|
|
// Returns the # of elements in an array as a compile-time constant, which can
|
|
|
|
// be used in defining new arrays. If you use this macro on a pointer by
|
|
|
|
// mistake, you will get a compile-time error.
|
|
|
|
//
|
|
|
|
// Note: this template function declaration is used in defining arraysize.
|
|
|
|
// Note that the function doesn't need an implementation, as we only
|
|
|
|
// use its type.
|
|
|
|
namespace absl {
|
|
|
|
namespace macros_internal {
|
|
|
|
template <typename T, size_t N>
|
|
|
|
char (&ArraySizeHelper(T (&array)[N]))[N];
|
|
|
|
} // namespace macros_internal
|
|
|
|
} // namespace absl
|
|
|
|
#define ABSL_ARRAYSIZE(array) \
|
|
|
|
(sizeof(::absl::macros_internal::ArraySizeHelper(array)))
|
|
|
|
|
|
|
|
// kLinkerInitialized
|
|
|
|
//
|
|
|
|
// An enum used only as a constructor argument to indicate that a variable has
|
|
|
|
// static storage duration, and that the constructor should do nothing to its
|
|
|
|
// state. Use of this macro indicates to the reader that it is legal to
|
|
|
|
// declare a static instance of the class, provided the constructor is given
|
|
|
|
// the absl::base_internal::kLinkerInitialized argument.
|
|
|
|
//
|
|
|
|
// Normally, it is unsafe to declare a static variable that has a constructor or
|
|
|
|
// a destructor because invocation order is undefined. However, if the type can
|
|
|
|
// be zero-initialized (which the loader does for static variables) into a valid
|
|
|
|
// state and the type's destructor does not affect storage, then a constructor
|
|
|
|
// for static initialization can be declared.
|
|
|
|
//
|
|
|
|
// Example:
|
|
|
|
// // Declaration
|
|
|
|
// explicit MyClass(absl::base_internal:LinkerInitialized x) {}
|
|
|
|
//
|
|
|
|
// // Invocation
|
|
|
|
// static MyClass my_global(absl::base_internal::kLinkerInitialized);
|
|
|
|
namespace absl {
|
|
|
|
namespace base_internal {
|
|
|
|
enum LinkerInitialized {
|
|
|
|
kLinkerInitialized = 0,
|
|
|
|
};
|
|
|
|
} // namespace base_internal
|
|
|
|
} // namespace absl
|
|
|
|
|
|
|
|
// ABSL_FALLTHROUGH_INTENDED
|
|
|
|
//
|
|
|
|
// Annotates implicit fall-through between switch labels, allowing a case to
|
|
|
|
// indicate intentional fallthrough and turn off warnings about any lack of a
|
|
|
|
// `break` statement. The ABSL_FALLTHROUGH_INTENDED macro should be followed by
|
|
|
|
// a semicolon and can be used in most places where `break` can, provided that
|
|
|
|
// no statements exist between it and the next switch label.
|
|
|
|
//
|
|
|
|
// Example:
|
|
|
|
//
|
|
|
|
// switch (x) {
|
|
|
|
// case 40:
|
|
|
|
// case 41:
|
|
|
|
// if (truth_is_out_there) {
|
|
|
|
// ++x;
|
|
|
|
// ABSL_FALLTHROUGH_INTENDED; // Use instead of/along with annotations
|
|
|
|
// // in comments
|
|
|
|
// } else {
|
|
|
|
// return x;
|
|
|
|
// }
|
|
|
|
// case 42:
|
|
|
|
// ...
|
|
|
|
//
|
|
|
|
// Notes: when compiled with clang in C++11 mode, the ABSL_FALLTHROUGH_INTENDED
|
|
|
|
// macro is expanded to the [[clang::fallthrough]] attribute, which is analysed
|
|
|
|
// when performing switch labels fall-through diagnostic
|
|
|
|
// (`-Wimplicit-fallthrough`). See clang documentation on language extensions
|
|
|
|
// for details:
|
|
|
|
// http://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough
|
|
|
|
//
|
|
|
|
// When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro
|
|
|
|
// has no effect on diagnostics. In any case this macro has no effect on runtime
|
|
|
|
// behavior and performance of code.
|
|
|
|
#ifdef ABSL_FALLTHROUGH_INTENDED
|
|
|
|
#error "ABSL_FALLTHROUGH_INTENDED should not be defined."
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// TODO(zhangxy): Use c++17 standard [[fallthrough]] macro, when supported.
|
|
|
|
#if defined(__clang__) && defined(__has_warning)
|
|
|
|
#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
|
|
|
|
#define ABSL_FALLTHROUGH_INTENDED [[clang::fallthrough]]
|
|
|
|
#endif
|
|
|
|
#elif defined(__GNUC__) && __GNUC__ >= 7
|
|
|
|
#define ABSL_FALLTHROUGH_INTENDED [[gnu::fallthrough]]
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef ABSL_FALLTHROUGH_INTENDED
|
|
|
|
#define ABSL_FALLTHROUGH_INTENDED \
|
|
|
|
do { \
|
|
|
|
} while (0)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_DEPRECATED()
|
|
|
|
//
|
|
|
|
// Marks a deprecated class, struct, enum, function, method and variable
|
|
|
|
// declarations. The macro argument is used as a custom diagnostic message (e.g.
|
|
|
|
// suggestion of a better alternative).
|
|
|
|
//
|
|
|
|
// Example:
|
|
|
|
//
|
|
|
|
// class ABSL_DEPRECATED("Use Bar instead") Foo {...};
|
|
|
|
// ABSL_DEPRECATED("Use Baz instead") void Bar() {...}
|
|
|
|
//
|
|
|
|
// Every usage of a deprecated entity will trigger a warning when compiled with
|
|
|
|
// clang's `-Wdeprecated-declarations` option. This option is turned off by
|
|
|
|
// default, but the warnings will be reported by clang-tidy.
|
|
|
|
#if defined(__clang__) && __cplusplus >= 201103L && defined(__has_warning)
|
|
|
|
#define ABSL_DEPRECATED(message) __attribute__((deprecated(message)))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef ABSL_DEPRECATED
|
|
|
|
#define ABSL_DEPRECATED(message)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_BAD_CALL_IF()
|
|
|
|
//
|
|
|
|
// Used on a function overload to trap bad calls: any call that matches the
|
|
|
|
// overload will cause a compile-time error. This macro uses a clang-specific
|
|
|
|
// "enable_if" attribute, as described at
|
|
|
|
// http://clang.llvm.org/docs/AttributeReference.html#enable-if
|
|
|
|
//
|
|
|
|
// Overloads which use this macro should be bracketed by
|
|
|
|
// `#ifdef ABSL_BAD_CALL_IF`.
|
|
|
|
//
|
|
|
|
// Example:
|
|
|
|
//
|
|
|
|
// int isdigit(int c);
|
|
|
|
// #ifdef ABSL_BAD_CALL_IF
|
|
|
|
// int isdigit(int c)
|
|
|
|
// ABSL_BAD_CALL_IF(c <= -1 || c > 255,
|
|
|
|
// "'c' must have the value of an unsigned char or EOF");
|
|
|
|
// #endif // ABSL_BAD_CALL_IF
|
|
|
|
|
|
|
|
#if defined(__clang__)
|
|
|
|
# if __has_attribute(enable_if)
|
|
|
|
# define ABSL_BAD_CALL_IF(expr, msg) \
|
|
|
|
__attribute__((enable_if(expr, "Bad call trap"), unavailable(msg)))
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ABSL_ASSERT()
|
|
|
|
//
|
|
|
|
// In C++11, `assert` can't be used portably within constexpr functions.
|
|
|
|
// ABSL_ASSERT functions as a runtime assert but works in C++11 constexpr
|
|
|
|
// functions. Example:
|
|
|
|
//
|
|
|
|
// constexpr double Divide(double a, double b) {
|
|
|
|
// return ABSL_ASSERT(b != 0), a / b;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// This macro is inspired by
|
|
|
|
// https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/
|
|
|
|
#if defined(NDEBUG)
|
|
|
|
#define ABSL_ASSERT(expr) (false ? (void)(expr) : (void)0)
|
|
|
|
#else
|
|
|
|
#define ABSL_ASSERT(expr) \
|
|
|
|
(ABSL_PREDICT_TRUE((expr)) ? (void)0 : [] { assert(false && #expr); }())
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif // ABSL_BASE_MACROS_H_
|
|
|
|
/*
|
|
|
|
* Copyright 2017 The Abseil Authors.
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
/* This file defines dynamic annotations for use with dynamic analysis
|
|
|
|
tool such as valgrind, PIN, etc.
|
|
|
|
|
|
|
|
Dynamic annotation is a source code annotation that affects
|
|
|
|
the generated code (that is, the annotation is not a comment).
|
|
|
|
Each such annotation is attached to a particular
|
|
|
|
instruction and/or to a particular object (address) in the program.
|
|
|
|
|
|
|
|
The annotations that should be used by users are macros in all upper-case
|
|
|
|
(e.g., ANNOTATE_THREAD_NAME).
|
|
|
|
|
|
|
|
Actual implementation of these macros may differ depending on the
|
|
|
|
dynamic analysis tool being used.
|
|
|
|
|
|
|
|
This file supports the following configurations:
|
|
|
|
- Dynamic Annotations enabled (with static thread-safety warnings disabled).
|
|
|
|
In this case, macros expand to functions implemented by Thread Sanitizer,
|
|
|
|
when building with TSan. When not provided an external implementation,
|
|
|
|
dynamic_annotations.cc provides no-op implementations.
|
|
|
|
|
|
|
|
- Static Clang thread-safety warnings enabled.
|
|
|
|
When building with a Clang compiler that supports thread-safety warnings,
|
|
|
|
a subset of annotations can be statically-checked at compile-time. We
|
|
|
|
expand these macros to static-inline functions that can be analyzed for
|
|
|
|
thread-safety, but afterwards elided when building the final binary.
|
|
|
|
|
|
|
|
- All annotations are disabled.
|
|
|
|
If neither Dynamic Annotations nor Clang thread-safety warnings are
|
|
|
|
enabled, then all annotation-macros expand to empty. */
|
|
|
|
|
|
|
|
#ifndef ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
|
|
|
|
#define ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
|
|
|
|
|
|
|
|
#ifndef DYNAMIC_ANNOTATIONS_ENABLED
|
|
|
|
# define DYNAMIC_ANNOTATIONS_ENABLED 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(__native_client__)
|
|
|
|
#include "nacl/dynamic_annotations.h"
|
|
|
|
|
|
|
|
// Stub out the macros missing from the NaCl version.
|
|
|
|
#ifndef ANNOTATE_CONTIGUOUS_CONTAINER
|
|
|
|
#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid)
|
|
|
|
#endif
|
|
|
|
#ifndef ANNOTATE_RWLOCK_CREATE_STATIC
|
|
|
|
#define ANNOTATE_RWLOCK_CREATE_STATIC(lock)
|
|
|
|
#endif
|
|
|
|
#ifndef ADDRESS_SANITIZER_REDZONE
|
|
|
|
#define ADDRESS_SANITIZER_REDZONE(name)
|
|
|
|
#endif
|
|
|
|
#ifndef ANNOTATE_MEMORY_IS_UNINITIALIZED
|
|
|
|
#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#else /* !__native_client__ */
|
|
|
|
|
|
|
|
#if DYNAMIC_ANNOTATIONS_ENABLED != 0
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------
|
|
|
|
Annotations that suppress errors. It is usually better to express the
|
|
|
|
program's synchronization using the other annotations, but these can
|
|
|
|
be used when all else fails. */
|
|
|
|
|
|
|
|
/* Report that we may have a benign race at "pointer", with size
|
|
|
|
"sizeof(*(pointer))". "pointer" must be a non-void* pointer. Insert at the
|
|
|
|
point where "pointer" has been allocated, preferably close to the point
|
|
|
|
where the race happens. See also ANNOTATE_BENIGN_RACE_STATIC. */
|
|
|
|
#define ANNOTATE_BENIGN_RACE(pointer, description) \
|
|
|
|
AnnotateBenignRaceSized(__FILE__, __LINE__, pointer, \
|
|
|
|
sizeof(*(pointer)), description)
|
|
|
|
|
|
|
|
/* Same as ANNOTATE_BENIGN_RACE(address, description), but applies to
|
|
|
|
the memory range [address, address+size). */
|
|
|
|
#define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
|
|
|
|
AnnotateBenignRaceSized(__FILE__, __LINE__, address, size, description)
|
|
|
|
|
|
|
|
/* Enable (enable!=0) or disable (enable==0) race detection for all threads.
|
|
|
|
This annotation could be useful if you want to skip expensive race analysis
|
|
|
|
during some period of program execution, e.g. during initialization. */
|
|
|
|
#define ANNOTATE_ENABLE_RACE_DETECTION(enable) \
|
|
|
|
AnnotateEnableRaceDetection(__FILE__, __LINE__, enable)
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------
|
|
|
|
Annotations useful for debugging. */
|
|
|
|
|
|
|
|
/* Report the current thread name to a race detector. */
|
|
|
|
#define ANNOTATE_THREAD_NAME(name) \
|
|
|
|
AnnotateThreadName(__FILE__, __LINE__, name)
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------
|
|
|
|
Annotations useful when implementing locks. They are not
|
|
|
|
normally needed by modules that merely use locks.
|
|
|
|
The "lock" argument is a pointer to the lock object. */
|
|
|
|
|
|
|
|
/* Report that a lock has been created at address "lock". */
|
|
|
|
#define ANNOTATE_RWLOCK_CREATE(lock) \
|
|
|
|
AnnotateRWLockCreate(__FILE__, __LINE__, lock)
|
|
|
|
|
|
|
|
/* Report that a linker initialized lock has been created at address "lock".
|
|
|
|
*/
|
|
|
|
#ifdef THREAD_SANITIZER
|
|
|
|
#define ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
|
|
|
|
AnnotateRWLockCreateStatic(__FILE__, __LINE__, lock)
|
|
|
|
#else
|
|
|
|
#define ANNOTATE_RWLOCK_CREATE_STATIC(lock) ANNOTATE_RWLOCK_CREATE(lock)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Report that the lock at address "lock" is about to be destroyed. */
|
|
|
|
#define ANNOTATE_RWLOCK_DESTROY(lock) \
|
|
|
|
AnnotateRWLockDestroy(__FILE__, __LINE__, lock)
|
|
|
|
|
|
|
|
/* Report that the lock at address "lock" has been acquired.
|
|
|
|
is_w=1 for writer lock, is_w=0 for reader lock. */
|
|
|
|
#define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \
|
|
|
|
AnnotateRWLockAcquired(__FILE__, __LINE__, lock, is_w)
|
|
|
|
|
|
|
|
/* Report that the lock at address "lock" is about to be released. */
|
|
|
|
#define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
|
|
|
|
AnnotateRWLockReleased(__FILE__, __LINE__, lock, is_w)
|
|
|
|
|
|
|
|
#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */
|
|
|
|
|
|
|
|
#define ANNOTATE_RWLOCK_CREATE(lock) /* empty */
|
|
|
|
#define ANNOTATE_RWLOCK_CREATE_STATIC(lock) /* empty */
|
|
|
|
#define ANNOTATE_RWLOCK_DESTROY(lock) /* empty */
|
|
|
|
#define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) /* empty */
|
|
|
|
#define ANNOTATE_RWLOCK_RELEASED(lock, is_w) /* empty */
|
|
|
|
#define ANNOTATE_BENIGN_RACE(address, description) /* empty */
|
|
|
|
#define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) /* empty */
|
|
|
|
#define ANNOTATE_THREAD_NAME(name) /* empty */
|
|
|
|
#define ANNOTATE_ENABLE_RACE_DETECTION(enable) /* empty */
|
|
|
|
|
|
|
|
#endif /* DYNAMIC_ANNOTATIONS_ENABLED */
|
|
|
|
|
|
|
|
/* These annotations are also made available to LLVM's Memory Sanitizer */
|
|
|
|
#if DYNAMIC_ANNOTATIONS_ENABLED == 1 || defined(MEMORY_SANITIZER)
|
|
|
|
#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
|
|
|
|
AnnotateMemoryIsInitialized(__FILE__, __LINE__, address, size)
|
|
|
|
|
|
|
|
#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
|
|
|
|
AnnotateMemoryIsUninitialized(__FILE__, __LINE__, address, size)
|
|
|
|
#else
|
|
|
|
#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) /* empty */
|
|
|
|
#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) /* empty */
|
|
|
|
#endif /* DYNAMIC_ANNOTATIONS_ENABLED || MEMORY_SANITIZER */
|
|
|
|
/* TODO(delesley) -- Replace __CLANG_SUPPORT_DYN_ANNOTATION__ with the
|
|
|
|
appropriate feature ID. */
|
|
|
|
#if defined(__clang__) && (!defined(SWIG)) \
|
|
|
|
&& defined(__CLANG_SUPPORT_DYN_ANNOTATION__)
|
|
|
|
|
|
|
|
#if DYNAMIC_ANNOTATIONS_ENABLED == 0
|
|
|
|
#define ANNOTALYSIS_ENABLED
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* When running in opt-mode, GCC will issue a warning, if these attributes are
|
|
|
|
compiled. Only include them when compiling using Clang. */
|
|
|
|
#define ATTRIBUTE_IGNORE_READS_BEGIN \
|
|
|
|
__attribute((exclusive_lock_function("*")))
|
|
|
|
#define ATTRIBUTE_IGNORE_READS_END \
|
|
|
|
__attribute((unlock_function("*")))
|
|
|
|
#else
|
|
|
|
#define ATTRIBUTE_IGNORE_READS_BEGIN /* empty */
|
|
|
|
#define ATTRIBUTE_IGNORE_READS_END /* empty */
|
|
|
|
#endif /* defined(__clang__) && ... */
|
|
|
|
|
|
|
|
#if (DYNAMIC_ANNOTATIONS_ENABLED != 0) || defined(ANNOTALYSIS_ENABLED)
|
|
|
|
#define ANNOTATIONS_ENABLED
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if (DYNAMIC_ANNOTATIONS_ENABLED != 0)
|
|
|
|
|
|
|
|
/* Request the analysis tool to ignore all reads in the current thread
|
|
|
|
until ANNOTATE_IGNORE_READS_END is called.
|
|
|
|
Useful to ignore intentional racey reads, while still checking
|
|
|
|
other reads and all writes.
|
|
|
|
See also ANNOTATE_UNPROTECTED_READ. */
|
|
|
|
#define ANNOTATE_IGNORE_READS_BEGIN() \
|
|
|
|
AnnotateIgnoreReadsBegin(__FILE__, __LINE__)
|
|
|
|
|
|
|
|
/* Stop ignoring reads. */
|
|
|
|
#define ANNOTATE_IGNORE_READS_END() \
|
|
|
|
AnnotateIgnoreReadsEnd(__FILE__, __LINE__)
|
|
|
|
|
|
|
|
/* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead. */
|
|
|
|
#define ANNOTATE_IGNORE_WRITES_BEGIN() \
|
|
|
|
AnnotateIgnoreWritesBegin(__FILE__, __LINE__)
|
|
|
|
|
|
|
|
/* Stop ignoring writes. */
|
|
|
|
#define ANNOTATE_IGNORE_WRITES_END() \
|
|
|
|
AnnotateIgnoreWritesEnd(__FILE__, __LINE__)
|
|
|
|
|
|
|
|
/* Clang provides limited support for static thread-safety analysis
|
|
|
|
through a feature called Annotalysis. We configure macro-definitions
|
|
|
|
according to whether Annotalysis support is available. */
|
|
|
|
#elif defined(ANNOTALYSIS_ENABLED)
|
|
|
|
|
|
|
|
#define ANNOTATE_IGNORE_READS_BEGIN() \
|
|
|
|
StaticAnnotateIgnoreReadsBegin(__FILE__, __LINE__)
|
|
|
|
|
|
|
|
#define ANNOTATE_IGNORE_READS_END() \
|
|
|
|
StaticAnnotateIgnoreReadsEnd(__FILE__, __LINE__)
|
|
|
|
|
|
|
|
#define ANNOTATE_IGNORE_WRITES_BEGIN() \
|
|
|
|
StaticAnnotateIgnoreWritesBegin(__FILE__, __LINE__)
|
|
|
|
|
|
|
|
#define ANNOTATE_IGNORE_WRITES_END() \
|
|
|
|
StaticAnnotateIgnoreWritesEnd(__FILE__, __LINE__)
|
|
|
|
|
|
|
|
#else
|
|
|
|
#define ANNOTATE_IGNORE_READS_BEGIN() /* empty */
|
|
|
|
#define ANNOTATE_IGNORE_READS_END() /* empty */
|
|
|
|
#define ANNOTATE_IGNORE_WRITES_BEGIN() /* empty */
|
|
|
|
#define ANNOTATE_IGNORE_WRITES_END() /* empty */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Implement the ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more
|
|
|
|
primitive annotations defined above. */
|
|
|
|
#if defined(ANNOTATIONS_ENABLED)
|
|
|
|
|
|
|
|
/* Start ignoring all memory accesses (both reads and writes). */
|
|
|
|
#define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
|
|
|
|
do { \
|
|
|
|
ANNOTATE_IGNORE_READS_BEGIN(); \
|
|
|
|
ANNOTATE_IGNORE_WRITES_BEGIN(); \
|
|
|
|
}while (0)
|
|
|
|
|
|
|
|
/* Stop ignoring both reads and writes. */
|
|
|
|
#define ANNOTATE_IGNORE_READS_AND_WRITES_END() \
|
|
|
|
do { \
|
|
|
|
ANNOTATE_IGNORE_WRITES_END(); \
|
|
|
|
ANNOTATE_IGNORE_READS_END(); \
|
|
|
|
}while (0)
|
|
|
|
|
|
|
|
#else
|
|
|
|
#define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() /* empty */
|
|
|
|
#define ANNOTATE_IGNORE_READS_AND_WRITES_END() /* empty */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Use the macros above rather than using these functions directly. */
|
|
|
|
#include <stddef.h>
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
void AnnotateRWLockCreate(const char *file, int line,
|
|
|
|
const volatile void *lock);
|
|
|
|
void AnnotateRWLockCreateStatic(const char *file, int line,
|
|
|
|
const volatile void *lock);
|
|
|
|
void AnnotateRWLockDestroy(const char *file, int line,
|
|
|
|
const volatile void *lock);
|
|
|
|
void AnnotateRWLockAcquired(const char *file, int line,
|
|
|
|
const volatile void *lock, long is_w); /* NOLINT */
|
|
|
|
void AnnotateRWLockReleased(const char *file, int line,
|
|
|
|
const volatile void *lock, long is_w); /* NOLINT */
|
|
|
|
void AnnotateBenignRace(const char *file, int line,
|
|
|
|
const volatile void *address,
|
|
|
|
const char *description);
|
|
|
|
void AnnotateBenignRaceSized(const char *file, int line,
|
|
|
|
const volatile void *address,
|
|
|
|
size_t size,
|
|
|
|
const char *description);
|
|
|
|
void AnnotateThreadName(const char *file, int line,
|
|
|
|
const char *name);
|
|
|
|
void AnnotateEnableRaceDetection(const char *file, int line, int enable);
|
|
|
|
void AnnotateMemoryIsInitialized(const char *file, int line,
|
|
|
|
const volatile void *mem, size_t size);
|
|
|
|
void AnnotateMemoryIsUninitialized(const char *file, int line,
|
|
|
|
const volatile void *mem, size_t size);
|
|
|
|
|
|
|
|
/* Annotations expand to these functions, when Dynamic Annotations are enabled.
|
|
|
|
These functions are either implemented as no-op calls, if no Sanitizer is
|
|
|
|
attached, or provided with externally-linked implementations by a library
|
|
|
|
like ThreadSanitizer. */
|
|
|
|
void AnnotateIgnoreReadsBegin(const char *file, int line)
|
|
|
|
ATTRIBUTE_IGNORE_READS_BEGIN;
|
|
|
|
void AnnotateIgnoreReadsEnd(const char *file, int line)
|
|
|
|
ATTRIBUTE_IGNORE_READS_END;
|
|
|
|
void AnnotateIgnoreWritesBegin(const char *file, int line);
|
|
|
|
void AnnotateIgnoreWritesEnd(const char *file, int line);
|
|
|
|
|
|
|
|
#if defined(ANNOTALYSIS_ENABLED)
|
|
|
|
/* When Annotalysis is enabled without Dynamic Annotations, the use of
|
|
|
|
static-inline functions allows the annotations to be read at compile-time,
|
|
|
|
while still letting the compiler elide the functions from the final build.
|
|
|
|
|
|
|
|
TODO(delesley) -- The exclusive lock here ignores writes as well, but
|
|
|
|
allows IGNORE_READS_AND_WRITES to work properly. */
|
|
|
|
#pragma GCC diagnostic push
|
|
|
|
#pragma GCC diagnostic ignored "-Wunused-function"
|
|
|
|
static inline void StaticAnnotateIgnoreReadsBegin(const char *file, int line)
|
|
|
|
ATTRIBUTE_IGNORE_READS_BEGIN { (void)file; (void)line; }
|
|
|
|
static inline void StaticAnnotateIgnoreReadsEnd(const char *file, int line)
|
|
|
|
ATTRIBUTE_IGNORE_READS_END { (void)file; (void)line; }
|
|
|
|
static inline void StaticAnnotateIgnoreWritesBegin(
|
|
|
|
const char *file, int line) { (void)file; (void)line; }
|
|
|
|
static inline void StaticAnnotateIgnoreWritesEnd(
|
|
|
|
const char *file, int line) { (void)file; (void)line; }
|
|
|
|
#pragma GCC diagnostic pop
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Return non-zero value if running under valgrind.
|
|
|
|
|
|
|
|
If "valgrind.h" is included into dynamic_annotations.cc,
|
|
|
|
the regular valgrind mechanism will be used.
|
|
|
|
See http://valgrind.org/docs/manual/manual-core-adv.html about
|
|
|
|
RUNNING_ON_VALGRIND and other valgrind "client requests".
|
|
|
|
The file "valgrind.h" may be obtained by doing
|
|
|
|
svn co svn://svn.valgrind.org/valgrind/trunk/include
|
|
|
|
|
|
|
|
If for some reason you can't use "valgrind.h" or want to fake valgrind,
|
|
|
|
there are two ways to make this function return non-zero:
|
|
|
|
- Use environment variable: export RUNNING_ON_VALGRIND=1
|
|
|
|
- Make your tool intercept the function RunningOnValgrind() and
|
|
|
|
change its return value.
|
|
|
|
*/
|
|
|
|
int RunningOnValgrind(void);
|
|
|
|
|
|
|
|
/* ValgrindSlowdown returns:
|
|
|
|
* 1.0, if (RunningOnValgrind() == 0)
|
|
|
|
* 50.0, if (RunningOnValgrind() != 0 && getenv("VALGRIND_SLOWDOWN") == NULL)
|
|
|
|
* atof(getenv("VALGRIND_SLOWDOWN")) otherwise
|
|
|
|
This function can be used to scale timeout values:
|
|
|
|
EXAMPLE:
|
|
|
|
for (;;) {
|
|
|
|
DoExpensiveBackgroundTask();
|
|
|
|
SleepForSeconds(5 * ValgrindSlowdown());
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
double ValgrindSlowdown(void);
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
|
|
|
|
|
|
|
|
Instead of doing
|
|
|
|
ANNOTATE_IGNORE_READS_BEGIN();
|
|
|
|
... = x;
|
|
|
|
ANNOTATE_IGNORE_READS_END();
|
|
|
|
one can use
|
|
|
|
... = ANNOTATE_UNPROTECTED_READ(x); */
|
|
|
|
#if defined(__cplusplus) && defined(ANNOTATIONS_ENABLED)
|
|
|
|
template <typename T>
|
|
|
|
inline T ANNOTATE_UNPROTECTED_READ(const volatile T &x) { /* NOLINT */
|
|
|
|
ANNOTATE_IGNORE_READS_BEGIN();
|
|
|
|
T res = x;
|
|
|
|
ANNOTATE_IGNORE_READS_END();
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#define ANNOTATE_UNPROTECTED_READ(x) (x)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus)
|
|
|
|
/* Apply ANNOTATE_BENIGN_RACE_SIZED to a static variable. */
|
|
|
|
#define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \
|
|
|
|
namespace { \
|
|
|
|
class static_var ## _annotator { \
|
|
|
|
public: \
|
|
|
|
static_var ## _annotator() { \
|
|
|
|
ANNOTATE_BENIGN_RACE_SIZED(&static_var, \
|
|
|
|
sizeof(static_var), \
|
|
|
|
# static_var ": " description); \
|
|
|
|
} \
|
|
|
|
}; \
|
|
|
|
static static_var ## _annotator the ## static_var ## _annotator;\
|
|
|
|
} // namespace
|
|
|
|
#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */
|
|
|
|
#define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) /* empty */
|
|
|
|
#endif /* DYNAMIC_ANNOTATIONS_ENABLED */
|
|
|
|
|
|
|
|
#ifdef ADDRESS_SANITIZER
|
|
|
|
/* Describe the current state of a contiguous container such as e.g.
|
|
|
|
* std::vector or std::string. For more details see
|
|
|
|
* sanitizer/common_interface_defs.h, which is provided by the compiler. */
|
|
|
|
#include <sanitizer/common_interface_defs.h>
|
|
|
|
#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \
|
|
|
|
__sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid)
|
|
|
|
#define ADDRESS_SANITIZER_REDZONE(name) \
|
|
|
|
struct { char x[8] __attribute__ ((aligned (8))); } name
|
|
|
|
#else
|
|
|
|
#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid)
|
|
|
|
#define ADDRESS_SANITIZER_REDZONE(name)
|
|
|
|
#endif // ADDRESS_SANITIZER
|
|
|
|
|
|
|
|
/* Undefine the macros intended only in this file. */
|
|
|
|
#undef ANNOTALYSIS_ENABLED
|
|
|
|
#undef ANNOTATIONS_ENABLED
|
|
|
|
#undef ATTRIBUTE_IGNORE_READS_BEGIN
|
|
|
|
#undef ATTRIBUTE_IGNORE_READS_END
|
|
|
|
|
|
|
|
#endif /* !__native_client__ */
|
|
|
|
|
|
|
|
#endif /* ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ */
|
|
|
|
|
|
|
|
#define ABSL_RAW_CHECK(cond, msg) assert((cond) && (msg))
|
|
|
|
#define ABSL_RAW_LOG(sev, ...) do {} while(0)
|
|
|
|
|
|
|
|
// Copyright 2017 The Abseil Authors.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
// Produce stack trace.
|
|
|
|
//
|
|
|
|
// There are three different ways we can try to get the stack trace:
|
|
|
|
//
|
|
|
|
// 1) Our hand-coded stack-unwinder. This depends on a certain stack
|
|
|
|
// layout, which is used by gcc (and those systems using a
|
|
|
|
// gcc-compatible ABI) on x86 systems, at least since gcc 2.95.
|
|
|
|
// It uses the frame pointer to do its work.
|
|
|
|
//
|
|
|
|
// 2) The libunwind library. This is still in development, and as a
|
|
|
|
// separate library adds a new dependency, but doesn't need a frame
|
|
|
|
// pointer. It also doesn't call malloc.
|
|
|
|
//
|
|
|
|
// 3) The gdb unwinder -- also the one used by the c++ exception code.
|
|
|
|
// It's obviously well-tested, but has a fatal flaw: it can call
|
|
|
|
// malloc() from the unwinder. This is a problem because we're
|
|
|
|
// trying to use the unwinder to instrument malloc().
|
|
|
|
//
|
|
|
|
// Note: if you add a new implementation here, make sure it works
|
|
|
|
// correctly when absl::GetStackTrace() is called with max_depth == 0.
|
|
|
|
// Some code may do that.
|
|
|
|
|
|
|
|
|
|
|
|
#include <atomic>
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(ABSL_STACKTRACE_INL_HEADER)
|
|
|
|
#include ABSL_STACKTRACE_INL_HEADER
|
|
|
|
#else
|
|
|
|
# error Cannot calculate stack trace: will need to write for your environment
|
|
|
|
# include "stacktrace_internal/stacktrace_aarch64-inl.inc"
|
|
|
|
# include "stacktrace_internal/stacktrace_arm-inl.inc"
|
|
|
|
# include "stacktrace_internal/stacktrace_generic-inl.inc"
|
|
|
|
# include "stacktrace_internal/stacktrace_powerpc-inl.inc"
|
|
|
|
# include "stacktrace_internal/stacktrace_unimplemented-inl.inc"
|
|
|
|
# include "stacktrace_internal/stacktrace_win32-inl.inc"
|
|
|
|
# include "stacktrace_internal/stacktrace_x86-inl.inc"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace absl {
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
typedef int (*Unwinder)(void**, int*, int, int, const void*, int*);
|
|
|
|
std::atomic<Unwinder> custom;
|
|
|
|
|
|
|
|
template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
|
|
|
|
ABSL_ATTRIBUTE_ALWAYS_INLINE inline int Unwind(void** result, int* sizes,
|
|
|
|
int max_depth, int skip_count,
|
|
|
|
const void* uc,
|
|
|
|
int* min_dropped_frames) {
|
|
|
|
Unwinder f = &UnwindImpl<IS_STACK_FRAMES, IS_WITH_CONTEXT>;
|
|
|
|
Unwinder g = custom.load(std::memory_order_acquire);
|
|
|
|
if (g != nullptr) f = g;
|
|
|
|
|
|
|
|
// Add 1 to skip count for the unwinder function itself
|
|
|
|
int size = (*f)(result, sizes, max_depth, skip_count + 1, uc,
|
|
|
|
min_dropped_frames);
|
|
|
|
// To disable tail call to (*f)(...)
|
|
|
|
ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
int GetStackFrames(void** result, int* sizes, int max_depth, int skip_count) {
|
|
|
|
return Unwind<true, false>(result, sizes, max_depth, skip_count, nullptr,
|
|
|
|
nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
int GetStackFramesWithContext(void** result, int* sizes, int max_depth,
|
|
|
|
int skip_count, const void* uc,
|
|
|
|
int* min_dropped_frames) {
|
|
|
|
return Unwind<true, true>(result, sizes, max_depth, skip_count, uc,
|
|
|
|
min_dropped_frames);
|
|
|
|
}
|
|
|
|
|
|
|
|
int GetStackTrace(void** result, int max_depth, int skip_count) {
|
|
|
|
return Unwind<false, false>(result, nullptr, max_depth, skip_count, nullptr,
|
|
|
|
nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
int GetStackTraceWithContext(void** result, int max_depth, int skip_count,
|
|
|
|
const void* uc, int* min_dropped_frames) {
|
|
|
|
return Unwind<false, true>(result, nullptr, max_depth, skip_count, uc,
|
|
|
|
min_dropped_frames);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetStackUnwinder(Unwinder w) {
|
|
|
|
custom.store(w, std::memory_order_release);
|
|
|
|
}
|
|
|
|
|
|
|
|
int DefaultStackUnwinder(void** pcs, int* sizes, int depth, int skip,
|
|
|
|
const void* uc, int* min_dropped_frames) {
|
|
|
|
skip++; // For this function
|
|
|
|
Unwinder f = nullptr;
|
|
|
|
if (sizes == nullptr) {
|
|
|
|
if (uc == nullptr) {
|
|
|
|
f = &UnwindImpl<false, false>;
|
|
|
|
} else {
|
|
|
|
f = &UnwindImpl<false, true>;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (uc == nullptr) {
|
|
|
|
f = &UnwindImpl<true, false>;
|
|
|
|
} else {
|
|
|
|
f = &UnwindImpl<true, true>;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
volatile int x = 0;
|
|
|
|
int n = (*f)(pcs, sizes, depth, skip, uc, min_dropped_frames);
|
|
|
|
x = 1; (void) x; // To disable tail call to (*f)(...)
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace absl
|
|
|
|
// Copyright 2017 The Abseil Authors.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
// base::AddressIsReadable() probes an address to see whether it is readable,
|
|
|
|
// without faulting.
|
|
|
|
|
|
|
|
|
|
|
|
#if !defined(__linux__) || defined(__ANDROID__)
|
|
|
|
|
|
|
|
namespace absl {
|
|
|
|
namespace debug_internal {
|
|
|
|
|
|
|
|
// On platforms other than Linux, just return true.
|
|
|
|
bool AddressIsReadable(const void* /* addr */) { return true; }
|
|
|
|
|
|
|
|
} // namespace debug_internal
|
|
|
|
} // namespace absl
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/syscall.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <atomic>
|
|
|
|
#include <cerrno>
|
|
|
|
#include <cstdint>
|
|
|
|
|
|
|
|
|
|
|
|
namespace absl {
|
|
|
|
namespace debug_internal {
|
|
|
|
|
|
|
|
// Pack a pid and two file descriptors into a 64-bit word,
|
|
|
|
// using 16, 24, and 24 bits for each respectively.
|
|
|
|
static uint64_t Pack(uint64_t pid, uint64_t read_fd, uint64_t write_fd) {
|
|
|
|
ABSL_RAW_CHECK((read_fd >> 24) == 0 && (write_fd >> 24) == 0,
|
|
|
|
"fd out of range");
|
|
|
|
return (pid << 48) | ((read_fd & 0xffffff) << 24) | (write_fd & 0xffffff);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unpack x into a pid and two file descriptors, where x was created with
|
|
|
|
// Pack().
|
|
|
|
static void Unpack(uint64_t x, int *pid, int *read_fd, int *write_fd) {
|
|
|
|
*pid = x >> 48;
|
|
|
|
*read_fd = (x >> 24) & 0xffffff;
|
|
|
|
*write_fd = x & 0xffffff;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return whether the byte at *addr is readable, without faulting.
|
|
|
|
// Save and restores errno. Returns true on systems where
|
|
|
|
// unimplemented.
|
|
|
|
// This is a namespace-scoped variable for correct zero-initialization.
|
|
|
|
static std::atomic<uint64_t> pid_and_fds; // initially 0, an invalid pid.
|
|
|
|
bool AddressIsReadable(const void *addr) {
|
|
|
|
int save_errno = errno;
|
|
|
|
// We test whether a byte is readable by using write(). Normally, this would
|
|
|
|
// be done via a cached file descriptor to /dev/null, but linux fails to
|
|
|
|
// check whether the byte is readable when the destination is /dev/null, so
|
|
|
|
// we use a cached pipe. We store the pid of the process that created the
|
|
|
|
// pipe to handle the case where a process forks, and the child closes all
|
|
|
|
// the file descriptors and then calls this routine. This is not perfect:
|
|
|
|
// the child could use the routine, then close all file descriptors and then
|
|
|
|
// use this routine again. But the likely use of this routine is when
|
|
|
|
// crashing, to test the validity of pages when dumping the stack. Beware
|
|
|
|
// that we may leak file descriptors, but we're unlikely to leak many.
|
|
|
|
int bytes_written;
|
|
|
|
int current_pid = getpid() & 0xffff; // we use only the low order 16 bits
|
|
|
|
do { // until we do not get EBADF trying to use file descriptors
|
|
|
|
int pid;
|
|
|
|
int read_fd;
|
|
|
|
int write_fd;
|
|
|
|
uint64_t local_pid_and_fds = pid_and_fds.load(std::memory_order_relaxed);
|
|
|
|
Unpack(local_pid_and_fds, &pid, &read_fd, &write_fd);
|
|
|
|
while (current_pid != pid) {
|
|
|
|
int p[2];
|
|
|
|
// new pipe
|
|
|
|
if (pipe(p) != 0) {
|
|
|
|
ABSL_RAW_LOG(FATAL, "Failed to create pipe, errno=%d", errno);
|
|
|
|
}
|
|
|
|
fcntl(p[0], F_SETFD, FD_CLOEXEC);
|
|
|
|
fcntl(p[1], F_SETFD, FD_CLOEXEC);
|
|
|
|
uint64_t new_pid_and_fds = Pack(current_pid, p[0], p[1]);
|
|
|
|
if (pid_and_fds.compare_exchange_strong(
|
|
|
|
local_pid_and_fds, new_pid_and_fds, std::memory_order_relaxed,
|
|
|
|
std::memory_order_relaxed)) {
|
|
|
|
local_pid_and_fds = new_pid_and_fds; // fds exposed to other threads
|
|
|
|
} else { // fds not exposed to other threads; we can close them.
|
|
|
|
close(p[0]);
|
|
|
|
close(p[1]);
|
|
|
|
local_pid_and_fds = pid_and_fds.load(std::memory_order_relaxed);
|
|
|
|
}
|
|
|
|
Unpack(local_pid_and_fds, &pid, &read_fd, &write_fd);
|
|
|
|
}
|
|
|
|
errno = 0;
|
|
|
|
// Use syscall(SYS_write, ...) instead of write() to prevent ASAN
|
|
|
|
// and other checkers from complaining about accesses to arbitrary
|
|
|
|
// memory.
|
|
|
|
do {
|
|
|
|
bytes_written = syscall(SYS_write, write_fd, addr, 1);
|
|
|
|
} while (bytes_written == -1 && errno == EINTR);
|
|
|
|
if (bytes_written == 1) { // remove the byte from the pipe
|
|
|
|
char c;
|
|
|
|
while (read(read_fd, &c, 1) == -1 && errno == EINTR) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (errno == EBADF) { // Descriptors invalid.
|
|
|
|
// If pid_and_fds contains the problematic file descriptors we just used,
|
|
|
|
// this call will forget them, and the loop will try again.
|
|
|
|
pid_and_fds.compare_exchange_strong(local_pid_and_fds, 0,
|
|
|
|
std::memory_order_relaxed,
|
|
|
|
std::memory_order_relaxed);
|
|
|
|
}
|
|
|
|
} while (errno == EBADF);
|
|
|
|
errno = save_errno;
|
|
|
|
return bytes_written == 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace debug_internal
|
|
|
|
} // namespace absl
|
|
|
|
|
|
|
|
#endif
|
|
|
|
// Copyright 2017 The Abseil Authors.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
// Allow dynamic symbol lookup in an in-memory Elf image.
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef ABSL_HAVE_ELF_MEM_IMAGE // defined in elf_mem_image.h
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstddef>
|
|
|
|
|
|
|
|
// From binutils/include/elf/common.h (this doesn't appear to be documented
|
|
|
|
// anywhere else).
|
|
|
|
//
|
|
|
|
// /* This flag appears in a Versym structure. It means that the symbol
|
|
|
|
// is hidden, and is only visible with an explicit version number.
|
|
|
|
// This is a GNU extension. */
|
|
|
|
// #define VERSYM_HIDDEN 0x8000
|
|
|
|
//
|
|
|
|
// /* This is the mask for the rest of the Versym information. */
|
|
|
|
// #define VERSYM_VERSION 0x7fff
|
|
|
|
|
|
|
|
#define VERSYM_VERSION 0x7fff
|
|
|
|
|
|
|
|
namespace absl {
|
|
|
|
namespace debug_internal {
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
#if __WORDSIZE == 32
|
|
|
|
const int kElfClass = ELFCLASS32;
|
|
|
|
int ElfBind(const ElfW(Sym) *symbol) { return ELF32_ST_BIND(symbol->st_info); }
|
|
|
|
int ElfType(const ElfW(Sym) *symbol) { return ELF32_ST_TYPE(symbol->st_info); }
|
|
|
|
#elif __WORDSIZE == 64
|
|
|
|
const int kElfClass = ELFCLASS64;
|
|
|
|
int ElfBind(const ElfW(Sym) *symbol) { return ELF64_ST_BIND(symbol->st_info); }
|
|
|
|
int ElfType(const ElfW(Sym) *symbol) { return ELF64_ST_TYPE(symbol->st_info); }
|
|
|
|
#else
|
|
|
|
const int kElfClass = -1;
|
|
|
|
int ElfBind(const ElfW(Sym) *) {
|
|
|
|
ABSL_RAW_LOG(FATAL, "Unexpected word size");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
int ElfType(const ElfW(Sym) *) {
|
|
|
|
ABSL_RAW_LOG(FATAL, "Unexpected word size");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Extract an element from one of the ELF tables, cast it to desired type.
|
|
|
|
// This is just a simple arithmetic and a glorified cast.
|
|
|
|
// Callers are responsible for bounds checking.
|
|
|
|
template <typename T>
|
|
|
|
const T *GetTableElement(const ElfW(Ehdr) * ehdr, ElfW(Off) table_offset,
|
|
|
|
ElfW(Word) element_size, size_t index) {
|
|
|
|
return reinterpret_cast<const T*>(reinterpret_cast<const char *>(ehdr)
|
|
|
|
+ table_offset
|
|
|
|
+ index * element_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
const void *const ElfMemImage::kInvalidBase =
|
|
|
|
reinterpret_cast<const void *>(~0L);
|
|
|
|
|
|
|
|
ElfMemImage::ElfMemImage(const void *base) {
|
|
|
|
ABSL_RAW_CHECK(base != kInvalidBase, "bad pointer");
|
|
|
|
Init(base);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ElfMemImage::GetNumSymbols() const {
|
|
|
|
if (!hash_) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// See http://www.caldera.com/developers/gabi/latest/ch5.dynamic.html#hash
|
|
|
|
return hash_[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
const ElfW(Sym) *ElfMemImage::GetDynsym(int index) const {
|
|
|
|
ABSL_RAW_CHECK(index < GetNumSymbols(), "index out of range");
|
|
|
|
return dynsym_ + index;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ElfW(Versym) *ElfMemImage::GetVersym(int index) const {
|
|
|
|
ABSL_RAW_CHECK(index < GetNumSymbols(), "index out of range");
|
|
|
|
return versym_ + index;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ElfW(Phdr) *ElfMemImage::GetPhdr(int index) const {
|
|
|
|
ABSL_RAW_CHECK(index < ehdr_->e_phnum, "index out of range");
|
|
|
|
return GetTableElement<ElfW(Phdr)>(ehdr_,
|
|
|
|
ehdr_->e_phoff,
|
|
|
|
ehdr_->e_phentsize,
|
|
|
|
index);
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *ElfMemImage::GetDynstr(ElfW(Word) offset) const {
|
|
|
|
ABSL_RAW_CHECK(offset < strsize_, "offset out of range");
|
|
|
|
return dynstr_ + offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
const void *ElfMemImage::GetSymAddr(const ElfW(Sym) *sym) const {
|
|
|
|
if (sym->st_shndx == SHN_UNDEF || sym->st_shndx >= SHN_LORESERVE) {
|
|
|
|
// Symbol corresponds to "special" (e.g. SHN_ABS) section.
|
|
|
|
return reinterpret_cast<const void *>(sym->st_value);
|
|
|
|
}
|
|
|
|
ABSL_RAW_CHECK(link_base_ < sym->st_value, "symbol out of range");
|
|
|
|
return GetTableElement<char>(ehdr_, 0, 1, sym->st_value) - link_base_;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ElfW(Verdef) *ElfMemImage::GetVerdef(int index) const {
|
|
|
|
ABSL_RAW_CHECK(0 <= index && static_cast<size_t>(index) <= verdefnum_,
|
|
|
|
"index out of range");
|
|
|
|
const ElfW(Verdef) *version_definition = verdef_;
|
|
|
|
while (version_definition->vd_ndx < index && version_definition->vd_next) {
|
|
|
|
const char *const version_definition_as_char =
|
|
|
|
reinterpret_cast<const char *>(version_definition);
|
|
|
|
version_definition =
|
|
|
|
reinterpret_cast<const ElfW(Verdef) *>(version_definition_as_char +
|
|
|
|
version_definition->vd_next);
|
|
|
|
}
|
|
|
|
return version_definition->vd_ndx == index ? version_definition : nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ElfW(Verdaux) *ElfMemImage::GetVerdefAux(
|
|
|
|
const ElfW(Verdef) *verdef) const {
|
|
|
|
return reinterpret_cast<const ElfW(Verdaux) *>(verdef+1);
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *ElfMemImage::GetVerstr(ElfW(Word) offset) const {
|
|
|
|
ABSL_RAW_CHECK(offset < strsize_, "offset out of range");
|
|
|
|
return dynstr_ + offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ElfMemImage::Init(const void *base) {
|
|
|
|
ehdr_ = nullptr;
|
|
|
|
dynsym_ = nullptr;
|
|
|
|
dynstr_ = nullptr;
|
|
|
|
versym_ = nullptr;
|
|
|
|
verdef_ = nullptr;
|
|
|
|
hash_ = nullptr;
|
|
|
|
strsize_ = 0;
|
|
|
|
verdefnum_ = 0;
|
|
|
|
link_base_ = ~0L; // Sentinel: PT_LOAD .p_vaddr can't possibly be this.
|
|
|
|
if (!base) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const intptr_t base_as_uintptr_t = reinterpret_cast<uintptr_t>(base);
|
|
|
|
// Fake VDSO has low bit set.
|
|
|
|
const bool fake_vdso = ((base_as_uintptr_t & 1) != 0);
|
|
|
|
base = reinterpret_cast<const void *>(base_as_uintptr_t & ~1);
|
|
|
|
const char *const base_as_char = reinterpret_cast<const char *>(base);
|
|
|
|
if (base_as_char[EI_MAG0] != ELFMAG0 || base_as_char[EI_MAG1] != ELFMAG1 ||
|
|
|
|
base_as_char[EI_MAG2] != ELFMAG2 || base_as_char[EI_MAG3] != ELFMAG3) {
|
|
|
|
assert(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int elf_class = base_as_char[EI_CLASS];
|
|
|
|
if (elf_class != kElfClass) {
|
|
|
|
assert(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch (base_as_char[EI_DATA]) {
|
|
|
|
case ELFDATA2LSB: {
|
|
|
|
if (__LITTLE_ENDIAN != __BYTE_ORDER) {
|
|
|
|
assert(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ELFDATA2MSB: {
|
|
|
|
if (__BIG_ENDIAN != __BYTE_ORDER) {
|
|
|
|
assert(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
assert(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ehdr_ = reinterpret_cast<const ElfW(Ehdr) *>(base);
|
|
|
|
const ElfW(Phdr) *dynamic_program_header = nullptr;
|
|
|
|
for (int i = 0; i < ehdr_->e_phnum; ++i) {
|
|
|
|
const ElfW(Phdr) *const program_header = GetPhdr(i);
|
|
|
|
switch (program_header->p_type) {
|
|
|
|
case PT_LOAD:
|
|
|
|
if (!~link_base_) {
|
|
|
|
link_base_ = program_header->p_vaddr;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PT_DYNAMIC:
|
|
|
|
dynamic_program_header = program_header;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!~link_base_ || !dynamic_program_header) {
|
|
|
|
assert(false);
|
|
|
|
// Mark this image as not present. Can not recur infinitely.
|
|
|
|
Init(nullptr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ptrdiff_t relocation =
|
|
|
|
base_as_char - reinterpret_cast<const char *>(link_base_);
|
|
|
|
ElfW(Dyn) *dynamic_entry =
|
|
|
|
reinterpret_cast<ElfW(Dyn) *>(dynamic_program_header->p_vaddr +
|
|
|
|
relocation);
|
|
|
|
for (; dynamic_entry->d_tag != DT_NULL; ++dynamic_entry) {
|
|
|
|
ElfW(Xword) value = dynamic_entry->d_un.d_val;
|
|
|
|
if (fake_vdso) {
|
|
|
|
// A complication: in the real VDSO, dynamic entries are not relocated
|
|
|
|
// (it wasn't loaded by a dynamic loader). But when testing with a
|
|
|
|
// "fake" dlopen()ed vdso library, the loader relocates some (but
|
|
|
|
// not all!) of them before we get here.
|
|
|
|
if (dynamic_entry->d_tag == DT_VERDEF) {
|
|
|
|
// The only dynamic entry (of the ones we care about) libc-2.3.6
|
|
|
|
// loader doesn't relocate.
|
|
|
|
value += relocation;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Real VDSO. Everything needs to be relocated.
|
|
|
|
value += relocation;
|
|
|
|
}
|
|
|
|
switch (dynamic_entry->d_tag) {
|
|
|
|
case DT_HASH:
|
|
|
|
hash_ = reinterpret_cast<ElfW(Word) *>(value);
|
|
|
|
break;
|
|
|
|
case DT_SYMTAB:
|
|
|
|
dynsym_ = reinterpret_cast<ElfW(Sym) *>(value);
|
|
|
|
break;
|
|
|
|
case DT_STRTAB:
|
|
|
|
dynstr_ = reinterpret_cast<const char *>(value);
|
|
|
|
break;
|
|
|
|
case DT_VERSYM:
|
|
|
|
versym_ = reinterpret_cast<ElfW(Versym) *>(value);
|
|
|
|
break;
|
|
|
|
case DT_VERDEF:
|
|
|
|
verdef_ = reinterpret_cast<ElfW(Verdef) *>(value);
|
|
|
|
break;
|
|
|
|
case DT_VERDEFNUM:
|
|
|
|
verdefnum_ = dynamic_entry->d_un.d_val;
|
|
|
|
break;
|
|
|
|
case DT_STRSZ:
|
|
|
|
strsize_ = dynamic_entry->d_un.d_val;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// Unrecognized entries explicitly ignored.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!hash_ || !dynsym_ || !dynstr_ || !versym_ ||
|
|
|
|
!verdef_ || !verdefnum_ || !strsize_) {
|
|
|
|
assert(false); // invalid VDSO
|
|
|
|
// Mark this image as not present. Can not recur infinitely.
|
|
|
|
Init(nullptr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ElfMemImage::LookupSymbol(const char *name,
|
|
|
|
const char *version,
|
|
|
|
int type,
|
|
|
|
SymbolInfo *info_out) const {
|
|
|
|
for (const SymbolInfo& info : *this) {
|
|
|
|
if (strcmp(info.name, name) == 0 && strcmp(info.version, version) == 0 &&
|
|
|
|
ElfType(info.symbol) == type) {
|
|
|
|
if (info_out) {
|
|
|
|
*info_out = info;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ElfMemImage::LookupSymbolByAddress(const void *address,
|
|
|
|
SymbolInfo *info_out) const {
|
|
|
|
for (const SymbolInfo& info : *this) {
|
|
|
|
const char *const symbol_start =
|
|
|
|
reinterpret_cast<const char *>(info.address);
|
|
|
|
const char *const symbol_end = symbol_start + info.symbol->st_size;
|
|
|
|
if (symbol_start <= address && address < symbol_end) {
|
|
|
|
if (info_out) {
|
|
|
|
// Client wants to know details for that symbol (the usual case).
|
|
|
|
if (ElfBind(info.symbol) == STB_GLOBAL) {
|
|
|
|
// Strong symbol; just return it.
|
|
|
|
*info_out = info;
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
// Weak or local. Record it, but keep looking for a strong one.
|
|
|
|
*info_out = info;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Client only cares if there is an overlapping symbol.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ElfMemImage::SymbolIterator::SymbolIterator(const void *const image, int index)
|
|
|
|
: index_(index), image_(image) {
|
|
|
|
}
|
|
|
|
|
|
|
|
const ElfMemImage::SymbolInfo *ElfMemImage::SymbolIterator::operator->() const {
|
|
|
|
return &info_;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ElfMemImage::SymbolInfo& ElfMemImage::SymbolIterator::operator*() const {
|
|
|
|
return info_;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ElfMemImage::SymbolIterator::operator==(const SymbolIterator &rhs) const {
|
|
|
|
return this->image_ == rhs.image_ && this->index_ == rhs.index_;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ElfMemImage::SymbolIterator::operator!=(const SymbolIterator &rhs) const {
|
|
|
|
return !(*this == rhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
ElfMemImage::SymbolIterator &ElfMemImage::SymbolIterator::operator++() {
|
|
|
|
this->Update(1);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
ElfMemImage::SymbolIterator ElfMemImage::begin() const {
|
|
|
|
SymbolIterator it(this, 0);
|
|
|
|
it.Update(0);
|
|
|
|
return it;
|
|
|
|
}
|
|
|
|
|
|
|
|
ElfMemImage::SymbolIterator ElfMemImage::end() const {
|
|
|
|
return SymbolIterator(this, GetNumSymbols());
|
|
|
|
}
|
|
|
|
|
|
|
|
void ElfMemImage::SymbolIterator::Update(int increment) {
|
|
|
|
const ElfMemImage *image = reinterpret_cast<const ElfMemImage *>(image_);
|
|
|
|
ABSL_RAW_CHECK(image->IsPresent() || increment == 0, "");
|
|
|
|
if (!image->IsPresent()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
index_ += increment;
|
|
|
|
if (index_ >= image->GetNumSymbols()) {
|
|
|
|
index_ = image->GetNumSymbols();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const ElfW(Sym) *symbol = image->GetDynsym(index_);
|
|
|
|
const ElfW(Versym) *version_symbol = image->GetVersym(index_);
|
|
|
|
ABSL_RAW_CHECK(symbol && version_symbol, "");
|
|
|
|
const char *const symbol_name = image->GetDynstr(symbol->st_name);
|
|
|
|
const ElfW(Versym) version_index = version_symbol[0] & VERSYM_VERSION;
|
|
|
|
const ElfW(Verdef) *version_definition = nullptr;
|
|
|
|
const char *version_name = "";
|
|
|
|
if (symbol->st_shndx == SHN_UNDEF) {
|
|
|
|
// Undefined symbols reference DT_VERNEED, not DT_VERDEF, and
|
|
|
|
// version_index could well be greater than verdefnum_, so calling
|
|
|
|
// GetVerdef(version_index) may trigger assertion.
|
|
|
|
} else {
|
|
|
|
version_definition = image->GetVerdef(version_index);
|
|
|
|
}
|
|
|
|
if (version_definition) {
|
|
|
|
// I am expecting 1 or 2 auxiliary entries: 1 for the version itself,
|
|
|
|
// optional 2nd if the version has a parent.
|
|
|
|
ABSL_RAW_CHECK(
|
|
|
|
version_definition->vd_cnt == 1 || version_definition->vd_cnt == 2,
|
|
|
|
"wrong number of entries");
|
|
|
|
const ElfW(Verdaux) *version_aux = image->GetVerdefAux(version_definition);
|
|
|
|
version_name = image->GetVerstr(version_aux->vda_name);
|
|
|
|
}
|
|
|
|
info_.name = symbol_name;
|
|
|
|
info_.version = version_name;
|
|
|
|
info_.address = image->GetSymAddr(symbol);
|
|
|
|
info_.symbol = symbol;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace debug_internal
|
|
|
|
} // namespace absl
|
|
|
|
|
|
|
|
#endif // ABSL_HAVE_ELF_MEM_IMAGE
|
|
|
|
// Copyright 2017 The Abseil Authors.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
// Allow dynamic symbol lookup in the kernel VDSO page.
|
|
|
|
//
|
|
|
|
// VDSOSupport -- a class representing kernel VDSO (if present).
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef ABSL_HAVE_VDSO_SUPPORT // defined in vdso_support.h
|
|
|
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/syscall.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef AT_SYSINFO_EHDR
|
|
|
|
#define AT_SYSINFO_EHDR 33 // for crosstoolv10
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace absl {
|
|
|
|
namespace debug_internal {
|
|
|
|
|
|
|
|
std::atomic<const void *> VDSOSupport::vdso_base_(
|
|
|
|
debug_internal::ElfMemImage::kInvalidBase);
|
|
|
|
std::atomic<VDSOSupport::GetCpuFn> VDSOSupport::getcpu_fn_(&InitAndGetCPU);
|
|
|
|
VDSOSupport::VDSOSupport()
|
|
|
|
// If vdso_base_ is still set to kInvalidBase, we got here
|
|
|
|
// before VDSOSupport::Init has been called. Call it now.
|
|
|
|
: image_(vdso_base_.load(std::memory_order_relaxed) ==
|
|
|
|
debug_internal::ElfMemImage::kInvalidBase
|
|
|
|
? Init()
|
|
|
|
: vdso_base_.load(std::memory_order_relaxed)) {}
|
|
|
|
|
|
|
|
// NOTE: we can't use GoogleOnceInit() below, because we can be
|
|
|
|
// called by tcmalloc, and none of the *once* stuff may be functional yet.
|
|
|
|
//
|
|
|
|
// In addition, we hope that the VDSOSupportHelper constructor
|
|
|
|
// causes this code to run before there are any threads, and before
|
|
|
|
// InitGoogle() has executed any chroot or setuid calls.
|
|
|
|
//
|
|
|
|
// Finally, even if there is a race here, it is harmless, because
|
|
|
|
// the operation should be idempotent.
|
|
|
|
const void *VDSOSupport::Init() {
|
|
|
|
if (vdso_base_.load(std::memory_order_relaxed) ==
|
|
|
|
debug_internal::ElfMemImage::kInvalidBase) {
|
|
|
|
{
|
|
|
|
// Valgrind zaps AT_SYSINFO_EHDR and friends from the auxv[]
|
|
|
|
// on stack, and so glibc works as if VDSO was not present.
|
|
|
|
// But going directly to kernel via /proc/self/auxv below bypasses
|
|
|
|
// Valgrind zapping. So we check for Valgrind separately.
|
|
|
|
if (RunningOnValgrind()) {
|
|
|
|
vdso_base_.store(nullptr, std::memory_order_relaxed);
|
|
|
|
getcpu_fn_.store(&GetCPUViaSyscall, std::memory_order_relaxed);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
int fd = open("/proc/self/auxv", O_RDONLY);
|
|
|
|
if (fd == -1) {
|
|
|
|
// Kernel too old to have a VDSO.
|
|
|
|
vdso_base_.store(nullptr, std::memory_order_relaxed);
|
|
|
|
getcpu_fn_.store(&GetCPUViaSyscall, std::memory_order_relaxed);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
ElfW(auxv_t) aux;
|
|
|
|
while (read(fd, &aux, sizeof(aux)) == sizeof(aux)) {
|
|
|
|
if (aux.a_type == AT_SYSINFO_EHDR) {
|
|
|
|
vdso_base_.store(reinterpret_cast<void *>(aux.a_un.a_val),
|
|
|
|
std::memory_order_relaxed);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
if (vdso_base_.load(std::memory_order_relaxed) ==
|
|
|
|
debug_internal::ElfMemImage::kInvalidBase) {
|
|
|
|
// Didn't find AT_SYSINFO_EHDR in auxv[].
|
|
|
|
vdso_base_.store(nullptr, std::memory_order_relaxed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
GetCpuFn fn = &GetCPUViaSyscall; // default if VDSO not present.
|
|
|
|
if (vdso_base_.load(std::memory_order_relaxed)) {
|
|
|
|
VDSOSupport vdso;
|
|
|
|
SymbolInfo info;
|
|
|
|
if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) {
|
|
|
|
fn = reinterpret_cast<GetCpuFn>(const_cast<void *>(info.address));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Subtle: this code runs outside of any locks; prevent compiler
|
|
|
|
// from assigning to getcpu_fn_ more than once.
|
|
|
|
getcpu_fn_.store(fn, std::memory_order_relaxed);
|
|
|
|
return vdso_base_.load(std::memory_order_relaxed);
|
|
|
|
}
|
|
|
|
|
|
|
|
const void *VDSOSupport::SetBase(const void *base) {
|
|
|
|
ABSL_RAW_CHECK(base != debug_internal::ElfMemImage::kInvalidBase,
|
|
|
|
"internal error");
|
|
|
|
const void *old_base = vdso_base_.load(std::memory_order_relaxed);
|
|
|
|
vdso_base_.store(base, std::memory_order_relaxed);
|
|
|
|
image_.Init(base);
|
|
|
|
// Also reset getcpu_fn_, so GetCPU could be tested with simulated VDSO.
|
|
|
|
getcpu_fn_.store(&InitAndGetCPU, std::memory_order_relaxed);
|
|
|
|
return old_base;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VDSOSupport::LookupSymbol(const char *name,
|
|
|
|
const char *version,
|
|
|
|
int type,
|
|
|
|
SymbolInfo *info) const {
|
|
|
|
return image_.LookupSymbol(name, version, type, info);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VDSOSupport::LookupSymbolByAddress(const void *address,
|
|
|
|
SymbolInfo *info_out) const {
|
|
|
|
return image_.LookupSymbolByAddress(address, info_out);
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOLINT on 'long' because this routine mimics kernel api.
|
|
|
|
long VDSOSupport::GetCPUViaSyscall(unsigned *cpu, // NOLINT(runtime/int)
|
|
|
|
void *, void *) {
|
|
|
|
#ifdef SYS_getcpu
|
|
|
|
return syscall(SYS_getcpu, cpu, nullptr, nullptr);
|
|
|
|
#else
|
|
|
|
// x86_64 never implemented sys_getcpu(), except as a VDSO call.
|
|
|
|
errno = ENOSYS;
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
// Use fast __vdso_getcpu if available.
|
|
|
|
long VDSOSupport::InitAndGetCPU(unsigned *cpu, // NOLINT(runtime/int)
|
|
|
|
void *x, void *y) {
|
|
|
|
Init();
|
|
|
|
GetCpuFn fn = getcpu_fn_.load(std::memory_order_relaxed);
|
|
|
|
ABSL_RAW_CHECK(fn != &InitAndGetCPU, "Init() did not set getcpu_fn_");
|
|
|
|
return (*fn)(cpu, x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This function must be very fast, and may be called from very
|
|
|
|
// low level (e.g. tcmalloc). Hence I avoid things like
|
|
|
|
// GoogleOnceInit() and ::operator new.
|
|
|
|
ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
|
|
|
|
int GetCPU() {
|
|
|
|
unsigned cpu;
|
|
|
|
int ret_code = (*VDSOSupport::getcpu_fn_)(&cpu, nullptr, nullptr);
|
|
|
|
return ret_code == 0 ? cpu : ret_code;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We need to make sure VDSOSupport::Init() is called before
|
|
|
|
// InitGoogle() does any setuid or chroot calls. If VDSOSupport
|
|
|
|
// is used in any global constructor, this will happen, since
|
|
|
|
// VDSOSupport's constructor calls Init. But if not, we need to
|
|
|
|
// ensure it here, with a global constructor of our own. This
|
|
|
|
// is an allowed exception to the normal rule against non-trivial
|
|
|
|
// global constructors.
|
|
|
|
static class VDSOInitHelper {
|
|
|
|
public:
|
|
|
|
VDSOInitHelper() { VDSOSupport::Init(); }
|
|
|
|
} vdso_init_helper;
|
|
|
|
|
|
|
|
} // namespace debug_internal
|
|
|
|
} // namespace absl
|
|
|
|
|
|
|
|
#endif // ABSL_HAVE_VDSO_SUPPORT
|
|
|
|
// Copyright 2017 The Abseil Authors.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef __has_feature
|
|
|
|
#define __has_feature(x) 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Compiler-based ThreadSanitizer defines
|
|
|
|
DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL = 1
|
|
|
|
and provides its own definitions of the functions. */
|
|
|
|
|
|
|
|
#ifndef DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL
|
|
|
|
# define DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Each function is empty and called (via a macro) only in debug mode.
|
|
|
|
The arguments are captured by dynamic tools at runtime. */
|
|
|
|
|
2020-04-25 08:07:50 +08:00
|
|
|
#if DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 && !defined(__native_client__) && !__has_feature(thread_sanitizer)
|
2017-10-14 05:13:47 +08:00
|
|
|
|
|
|
|
#if __has_feature(memory_sanitizer)
|
|
|
|
#include <sanitizer/msan_interface.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void AnnotateRWLockCreate(const char *, int,
|
|
|
|
const volatile void *){}
|
|
|
|
void AnnotateRWLockDestroy(const char *, int,
|
|
|
|
const volatile void *){}
|
|
|
|
void AnnotateRWLockAcquired(const char *, int,
|
|
|
|
const volatile void *, long){}
|
|
|
|
void AnnotateRWLockReleased(const char *, int,
|
|
|
|
const volatile void *, long){}
|
|
|
|
void AnnotateBenignRace(const char *, int,
|
|
|
|
const volatile void *,
|
|
|
|
const char *){}
|
|
|
|
void AnnotateBenignRaceSized(const char *, int,
|
|
|
|
const volatile void *,
|
|
|
|
size_t,
|
|
|
|
const char *) {}
|
|
|
|
void AnnotateThreadName(const char *, int,
|
|
|
|
const char *){}
|
|
|
|
void AnnotateIgnoreReadsBegin(const char *, int){}
|
|
|
|
void AnnotateIgnoreReadsEnd(const char *, int){}
|
|
|
|
void AnnotateIgnoreWritesBegin(const char *, int){}
|
|
|
|
void AnnotateIgnoreWritesEnd(const char *, int){}
|
|
|
|
void AnnotateEnableRaceDetection(const char *, int, int){}
|
|
|
|
void AnnotateMemoryIsInitialized(const char *, int,
|
|
|
|
const volatile void *mem, size_t size) {
|
|
|
|
#if __has_feature(memory_sanitizer)
|
|
|
|
__msan_unpoison(mem, size);
|
|
|
|
#else
|
|
|
|
(void)mem;
|
|
|
|
(void)size;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnnotateMemoryIsUninitialized(const char *, int,
|
|
|
|
const volatile void *mem, size_t size) {
|
|
|
|
#if __has_feature(memory_sanitizer)
|
|
|
|
__msan_allocated_memory(mem, size);
|
|
|
|
#else
|
|
|
|
(void)mem;
|
|
|
|
(void)size;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static int GetRunningOnValgrind(void) {
|
|
|
|
#ifdef RUNNING_ON_VALGRIND
|
|
|
|
if (RUNNING_ON_VALGRIND) return 1;
|
|
|
|
#endif
|
|
|
|
char *running_on_valgrind_str = getenv("RUNNING_ON_VALGRIND");
|
|
|
|
if (running_on_valgrind_str) {
|
|
|
|
return strcmp(running_on_valgrind_str, "0") != 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See the comments in dynamic_annotations.h */
|
|
|
|
int RunningOnValgrind(void) {
|
|
|
|
static volatile int running_on_valgrind = -1;
|
|
|
|
int local_running_on_valgrind = running_on_valgrind;
|
|
|
|
/* C doesn't have thread-safe initialization of statics, and we
|
|
|
|
don't want to depend on pthread_once here, so hack it. */
|
|
|
|
ANNOTATE_BENIGN_RACE(&running_on_valgrind, "safe hack");
|
|
|
|
if (local_running_on_valgrind == -1)
|
|
|
|
running_on_valgrind = local_running_on_valgrind = GetRunningOnValgrind();
|
|
|
|
return local_running_on_valgrind;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See the comments in dynamic_annotations.h */
|
|
|
|
double ValgrindSlowdown(void) {
|
|
|
|
/* Same initialization hack as in RunningOnValgrind(). */
|
|
|
|
static volatile double slowdown = 0.0;
|
|
|
|
double local_slowdown = slowdown;
|
|
|
|
ANNOTATE_BENIGN_RACE(&slowdown, "safe hack");
|
|
|
|
if (RunningOnValgrind() == 0) {
|
|
|
|
return 1.0;
|
|
|
|
}
|
|
|
|
if (local_slowdown == 0.0) {
|
|
|
|
char *env = getenv("VALGRIND_SLOWDOWN");
|
|
|
|
slowdown = local_slowdown = env ? atof(env) : 50.0;
|
|
|
|
}
|
|
|
|
return local_slowdown;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
} // extern "C"
|
|
|
|
#endif
|
|
|
|
#endif /* DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 */
|