merge(3p/absl): subtree merge of Abseil up to e19260f
... notably, this includes Abseil's own StatusOr type, which conflicted with our implementation (that was taken from TensorFlow). Change-Id: Ie7d6764b64055caaeb8dc7b6b9d066291e6b538f
This commit is contained in:
parent
cc27324d02
commit
082c006c04
854 changed files with 11260 additions and 5296 deletions
|
@ -26,7 +26,7 @@ package(
|
|||
default_visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
licenses(["notice"]) # Apache 2.0
|
||||
licenses(["notice"])
|
||||
|
||||
cc_library(
|
||||
name = "stacktrace",
|
||||
|
@ -97,6 +97,7 @@ cc_test(
|
|||
":stack_consumption",
|
||||
":symbolize",
|
||||
"//absl/base",
|
||||
"//absl/base:config",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/base:raw_logging_internal",
|
||||
"//absl/memory",
|
||||
|
@ -148,6 +149,7 @@ cc_test(
|
|||
copts = ABSL_TEST_COPTS,
|
||||
linkopts = select({
|
||||
"//absl:windows": [],
|
||||
"//absl:wasm": [],
|
||||
"//conditions:default": ["-pthread"],
|
||||
}) + ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
|
@ -203,6 +205,7 @@ cc_test(
|
|||
deps = [
|
||||
":demangle_internal",
|
||||
":stack_consumption",
|
||||
"//absl/base:config",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/base:raw_logging_internal",
|
||||
"//absl/memory",
|
||||
|
@ -236,7 +239,7 @@ cc_library(
|
|||
# These targets exists for use in tests only, explicitly configuring the
|
||||
# LEAK_SANITIZER macro. It must be linked with -fsanitize=leak for lsan.
|
||||
ABSL_LSAN_LINKOPTS = select({
|
||||
"//absl:llvm_compiler": ["-fsanitize=leak"],
|
||||
"//absl:clang_compiler": ["-fsanitize=leak"],
|
||||
"//conditions:default": [],
|
||||
})
|
||||
|
||||
|
@ -246,7 +249,7 @@ cc_library(
|
|||
srcs = ["leak_check.cc"],
|
||||
hdrs = ["leak_check.h"],
|
||||
copts = select({
|
||||
"//absl:llvm_compiler": ["-DLEAK_SANITIZER"],
|
||||
"//absl:clang_compiler": ["-DLEAK_SANITIZER"],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
|
@ -273,7 +276,7 @@ cc_test(
|
|||
name = "leak_check_test",
|
||||
srcs = ["leak_check_test.cc"],
|
||||
copts = select({
|
||||
"//absl:llvm_compiler": ["-DABSL_EXPECT_LEAK_SANITIZER"],
|
||||
"//absl:clang_compiler": ["-DABSL_EXPECT_LEAK_SANITIZER"],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
linkopts = ABSL_LSAN_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
|
||||
|
|
|
@ -82,6 +82,7 @@ absl_cc_test(
|
|||
absl::stack_consumption
|
||||
absl::symbolize
|
||||
absl::base
|
||||
absl::config
|
||||
absl::core_headers
|
||||
absl::memory
|
||||
absl::raw_logging_internal
|
||||
|
@ -189,6 +190,7 @@ absl_cc_test(
|
|||
DEPS
|
||||
absl::demangle_internal
|
||||
absl::stack_consumption
|
||||
absl::config
|
||||
absl::core_headers
|
||||
absl::memory
|
||||
absl::raw_logging_internal
|
||||
|
|
|
@ -136,8 +136,8 @@ static bool SetupAlternateStackOnce() {
|
|||
const size_t page_mask = sysconf(_SC_PAGESIZE) - 1;
|
||||
#endif
|
||||
size_t stack_size = (std::max(SIGSTKSZ, 65536) + page_mask) & ~page_mask;
|
||||
#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
|
||||
defined(THREAD_SANITIZER)
|
||||
#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \
|
||||
defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER)
|
||||
// Account for sanitizer instrumentation requiring additional stack space.
|
||||
stack_size *= 5;
|
||||
#endif
|
||||
|
|
|
@ -68,6 +68,7 @@ static void Unpack(uint64_t x, int *pid, int *read_fd, int *write_fd) {
|
|||
// 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) {
|
||||
absl::base_internal::ErrnoSaver errno_saver;
|
||||
// We test whether a byte is readable by using write(). Normally, this would
|
||||
|
@ -86,7 +87,7 @@ bool AddressIsReadable(const void *addr) {
|
|||
int pid;
|
||||
int read_fd;
|
||||
int write_fd;
|
||||
uint64_t local_pid_and_fds = pid_and_fds.load(std::memory_order_relaxed);
|
||||
uint64_t local_pid_and_fds = pid_and_fds.load(std::memory_order_acquire);
|
||||
Unpack(local_pid_and_fds, &pid, &read_fd, &write_fd);
|
||||
while (current_pid != pid) {
|
||||
int p[2];
|
||||
|
@ -98,13 +99,13 @@ bool AddressIsReadable(const void *addr) {
|
|||
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,
|
||||
local_pid_and_fds, new_pid_and_fds, std::memory_order_release,
|
||||
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);
|
||||
local_pid_and_fds = pid_and_fds.load(std::memory_order_acquire);
|
||||
}
|
||||
Unpack(local_pid_and_fds, &pid, &read_fd, &write_fd);
|
||||
}
|
||||
|
@ -124,7 +125,7 @@ bool AddressIsReadable(const void *addr) {
|
|||
// 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_release,
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
} while (errno == EBADF);
|
||||
|
|
|
@ -126,6 +126,7 @@ static const AbbrevPair kBuiltinTypeList[] = {
|
|||
{"Dn", "std::nullptr_t", 0}, // i.e., decltype(nullptr)
|
||||
{"Df", "decimal32", 0}, // IEEE 754r decimal floating point (32 bits)
|
||||
{"Di", "char32_t", 0},
|
||||
{"Du", "char8_t", 0},
|
||||
{"Ds", "char16_t", 0},
|
||||
{"Dh", "float16", 0}, // IEEE 754r half-precision float (16 bits)
|
||||
{nullptr, nullptr, 0},
|
||||
|
@ -409,6 +410,7 @@ static bool IsFunctionCloneSuffix(const char *str) {
|
|||
|
||||
static bool EndsWith(State *state, const char chr) {
|
||||
return state->parse_state.out_cur_idx > 0 &&
|
||||
state->parse_state.out_cur_idx < state->out_end_idx &&
|
||||
chr == state->out[state->parse_state.out_cur_idx - 1];
|
||||
}
|
||||
|
||||
|
@ -421,8 +423,10 @@ static void MaybeAppendWithLength(State *state, const char *const str,
|
|||
if (str[0] == '<' && EndsWith(state, '<')) {
|
||||
Append(state, " ", 1);
|
||||
}
|
||||
// Remember the last identifier name for ctors/dtors.
|
||||
if (IsAlpha(str[0]) || str[0] == '_') {
|
||||
// Remember the last identifier name for ctors/dtors,
|
||||
// but only if we haven't yet overflown the buffer.
|
||||
if (state->parse_state.out_cur_idx < state->out_end_idx &&
|
||||
(IsAlpha(str[0]) || str[0] == '_')) {
|
||||
state->parse_state.prev_name_idx = state->parse_state.out_cur_idx;
|
||||
state->parse_state.prev_name_length = length;
|
||||
}
|
||||
|
@ -962,6 +966,7 @@ static bool ParseOperatorName(State *state, int *arity) {
|
|||
// ::= TT <type>
|
||||
// ::= TI <type>
|
||||
// ::= TS <type>
|
||||
// ::= TH <type> # thread-local
|
||||
// ::= Tc <call-offset> <call-offset> <(base) encoding>
|
||||
// ::= GV <(object) name>
|
||||
// ::= T <call-offset> <(base) encoding>
|
||||
|
@ -980,7 +985,7 @@ static bool ParseSpecialName(State *state) {
|
|||
ComplexityGuard guard(state);
|
||||
if (guard.IsTooComplex()) return false;
|
||||
ParseState copy = state->parse_state;
|
||||
if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "VTIS") &&
|
||||
if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "VTISH") &&
|
||||
ParseType(state)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -1077,20 +1082,28 @@ static bool ParseVOffset(State *state) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// <ctor-dtor-name> ::= C1 | C2 | C3
|
||||
// <ctor-dtor-name> ::= C1 | C2 | C3 | CI1 <base-class-type> | CI2
|
||||
// <base-class-type>
|
||||
// ::= D0 | D1 | D2
|
||||
// # GCC extensions: "unified" constructor/destructor. See
|
||||
// # https://github.com/gcc-mirror/gcc/blob/7ad17b583c3643bd4557f29b8391ca7ef08391f5/gcc/cp/mangle.c#L1847
|
||||
// #
|
||||
// https://github.com/gcc-mirror/gcc/blob/7ad17b583c3643bd4557f29b8391ca7ef08391f5/gcc/cp/mangle.c#L1847
|
||||
// ::= C4 | D4
|
||||
static bool ParseCtorDtorName(State *state) {
|
||||
ComplexityGuard guard(state);
|
||||
if (guard.IsTooComplex()) return false;
|
||||
ParseState copy = state->parse_state;
|
||||
if (ParseOneCharToken(state, 'C') && ParseCharClass(state, "1234")) {
|
||||
const char *const prev_name = state->out + state->parse_state.prev_name_idx;
|
||||
MaybeAppendWithLength(state, prev_name,
|
||||
state->parse_state.prev_name_length);
|
||||
return true;
|
||||
if (ParseOneCharToken(state, 'C')) {
|
||||
if (ParseCharClass(state, "1234")) {
|
||||
const char *const prev_name =
|
||||
state->out + state->parse_state.prev_name_idx;
|
||||
MaybeAppendWithLength(state, prev_name,
|
||||
state->parse_state.prev_name_length);
|
||||
return true;
|
||||
} else if (ParseOneCharToken(state, 'I') && ParseCharClass(state, "12") &&
|
||||
ParseClassEnumType(state)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
state->parse_state = copy;
|
||||
|
||||
|
@ -1139,6 +1152,7 @@ static bool ParseDecltype(State *state) {
|
|||
// ::= <decltype>
|
||||
// ::= <substitution>
|
||||
// ::= Dp <type> # pack expansion of (C++0x)
|
||||
// ::= Dv <num-elems> _ # GNU vector extension
|
||||
//
|
||||
static bool ParseType(State *state) {
|
||||
ComplexityGuard guard(state);
|
||||
|
@ -1205,6 +1219,12 @@ static bool ParseType(State *state) {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (ParseTwoCharToken(state, "Dv") && ParseNumber(state, nullptr) &&
|
||||
ParseOneCharToken(state, '_')) {
|
||||
return true;
|
||||
}
|
||||
state->parse_state = copy;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1253,13 +1273,42 @@ static bool ParseBuiltinType(State *state) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// <function-type> ::= F [Y] <bare-function-type> E
|
||||
// <exception-spec> ::= Do # non-throwing
|
||||
// exception-specification (e.g.,
|
||||
// noexcept, throw())
|
||||
// ::= DO <expression> E # computed (instantiation-dependent)
|
||||
// noexcept
|
||||
// ::= Dw <type>+ E # dynamic exception specification
|
||||
// with instantiation-dependent types
|
||||
static bool ParseExceptionSpec(State *state) {
|
||||
ComplexityGuard guard(state);
|
||||
if (guard.IsTooComplex()) return false;
|
||||
|
||||
if (ParseTwoCharToken(state, "Do")) return true;
|
||||
|
||||
ParseState copy = state->parse_state;
|
||||
if (ParseTwoCharToken(state, "DO") && ParseExpression(state) &&
|
||||
ParseOneCharToken(state, 'E')) {
|
||||
return true;
|
||||
}
|
||||
state->parse_state = copy;
|
||||
if (ParseTwoCharToken(state, "Dw") && OneOrMore(ParseType, state) &&
|
||||
ParseOneCharToken(state, 'E')) {
|
||||
return true;
|
||||
}
|
||||
state->parse_state = copy;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// <function-type> ::= [exception-spec] F [Y] <bare-function-type> [O] E
|
||||
static bool ParseFunctionType(State *state) {
|
||||
ComplexityGuard guard(state);
|
||||
if (guard.IsTooComplex()) return false;
|
||||
ParseState copy = state->parse_state;
|
||||
if (ParseOneCharToken(state, 'F') &&
|
||||
if (Optional(ParseExceptionSpec(state)) && ParseOneCharToken(state, 'F') &&
|
||||
Optional(ParseOneCharToken(state, 'Y')) && ParseBareFunctionType(state) &&
|
||||
Optional(ParseOneCharToken(state, 'O')) &&
|
||||
ParseOneCharToken(state, 'E')) {
|
||||
return true;
|
||||
}
|
||||
|
@ -1887,7 +1936,8 @@ static bool Overflowed(const State *state) {
|
|||
bool Demangle(const char *mangled, char *out, int out_size) {
|
||||
State state;
|
||||
InitState(&state, mangled, out, out_size);
|
||||
return ParseTopLevelMangledName(&state) && !Overflowed(&state);
|
||||
return ParseTopLevelMangledName(&state) && !Overflowed(&state) &&
|
||||
state.parse_state.out_cur_idx > 0;
|
||||
}
|
||||
|
||||
} // namespace debugging_internal
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <string>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
#include "absl/debugging/internal/stack_consumption.h"
|
||||
#include "absl/memory/memory.h"
|
||||
|
@ -82,9 +83,10 @@ TEST(Demangle, Clones) {
|
|||
// Tests that verify that Demangle footprint is within some limit.
|
||||
// They are not to be run under sanitizers as the sanitizers increase
|
||||
// stack consumption by about 4x.
|
||||
#if defined(ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION) && \
|
||||
!defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) && \
|
||||
!defined(THREAD_SANITIZER)
|
||||
#if defined(ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION) && \
|
||||
!defined(ABSL_HAVE_ADDRESS_SANITIZER) && \
|
||||
!defined(ABSL_HAVE_MEMORY_SANITIZER) && \
|
||||
!defined(ABSL_HAVE_THREAD_SANITIZER)
|
||||
|
||||
static const char *g_mangled;
|
||||
static char g_demangle_buffer[4096];
|
||||
|
|
|
@ -42,7 +42,8 @@ namespace {
|
|||
// one of them is null, the results of p<q, p>q, p<=q, and p>=q are
|
||||
// unspecified. Therefore, instead we hardcode the direction of the
|
||||
// stack on platforms we know about.
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__)
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || \
|
||||
defined(__aarch64__)
|
||||
constexpr bool kStackGrowsDown = true;
|
||||
#else
|
||||
#error Need to define kStackGrowsDown
|
||||
|
|
|
@ -24,8 +24,9 @@
|
|||
// Use this feature test macro to detect its availability.
|
||||
#ifdef ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
|
||||
#error ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION cannot be set directly
|
||||
#elif !defined(__APPLE__) && !defined(_WIN32) && \
|
||||
(defined(__i386__) || defined(__x86_64__) || defined(__ppc__))
|
||||
#elif !defined(__APPLE__) && !defined(_WIN32) && \
|
||||
(defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || \
|
||||
defined(__aarch64__))
|
||||
#define ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION 1
|
||||
|
||||
namespace absl {
|
||||
|
|
|
@ -37,8 +37,11 @@ static const unsigned char* GetKernelRtSigreturnAddress() {
|
|||
absl::debugging_internal::VDSOSupport vdso;
|
||||
if (vdso.IsPresent()) {
|
||||
absl::debugging_internal::VDSOSupport::SymbolInfo symbol_info;
|
||||
if (!vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.6.39", STT_FUNC,
|
||||
&symbol_info) ||
|
||||
auto lookup = [&](int type) {
|
||||
return vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.6.39", type,
|
||||
&symbol_info);
|
||||
};
|
||||
if ((!lookup(STT_FUNC) && !lookup(STT_NOTYPE)) ||
|
||||
symbol_info.address == nullptr) {
|
||||
// Unexpected: VDSO is present, yet the expected symbol is missing
|
||||
// or null.
|
||||
|
|
|
@ -44,48 +44,46 @@
|
|||
!(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0)
|
||||
#define ABSL_STACKTRACE_INL_HEADER \
|
||||
"absl/debugging/internal/stacktrace_generic-inl.inc"
|
||||
#else
|
||||
#define ABSL_STACKTRACE_INL_HEADER \
|
||||
"absl/debugging/internal/stacktrace_unimplemented-inl.inc"
|
||||
#endif
|
||||
|
||||
#elif defined(__linux__) && !defined(__ANDROID__)
|
||||
|
||||
#if !defined(NO_FRAME_POINTER)
|
||||
# if defined(__i386__) || defined(__x86_64__)
|
||||
#if defined(NO_FRAME_POINTER) && \
|
||||
(defined(__i386__) || defined(__x86_64__) || defined(__aarch64__))
|
||||
// Note: The libunwind-based implementation is not available to open-source
|
||||
// users.
|
||||
#define ABSL_STACKTRACE_INL_HEADER \
|
||||
"absl/debugging/internal/stacktrace_x86-inl.inc"
|
||||
# elif defined(__ppc__) || defined(__PPC__)
|
||||
#define ABSL_STACKTRACE_INL_HEADER \
|
||||
"absl/debugging/internal/stacktrace_powerpc-inl.inc"
|
||||
# elif defined(__aarch64__)
|
||||
#define ABSL_STACKTRACE_INL_HEADER \
|
||||
"absl/debugging/internal/stacktrace_aarch64-inl.inc"
|
||||
#elif defined(__arm__) && defined(__GLIBC__)
|
||||
"absl/debugging/internal/stacktrace_libunwind-inl.inc"
|
||||
#define STACKTRACE_USES_LIBUNWIND 1
|
||||
#elif defined(NO_FRAME_POINTER) && defined(__has_include)
|
||||
#if __has_include(<execinfo.h>)
|
||||
// Note: When using glibc this may require -funwind-tables to function properly.
|
||||
#define ABSL_STACKTRACE_INL_HEADER \
|
||||
"absl/debugging/internal/stacktrace_generic-inl.inc"
|
||||
# else
|
||||
#endif
|
||||
#elif defined(__i386__) || defined(__x86_64__)
|
||||
#define ABSL_STACKTRACE_INL_HEADER \
|
||||
"absl/debugging/internal/stacktrace_unimplemented-inl.inc"
|
||||
# endif
|
||||
#else // defined(NO_FRAME_POINTER)
|
||||
# if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
|
||||
"absl/debugging/internal/stacktrace_x86-inl.inc"
|
||||
#elif defined(__ppc__) || defined(__PPC__)
|
||||
#define ABSL_STACKTRACE_INL_HEADER \
|
||||
"absl/debugging/internal/stacktrace_generic-inl.inc"
|
||||
# elif defined(__ppc__) || defined(__PPC__)
|
||||
"absl/debugging/internal/stacktrace_powerpc-inl.inc"
|
||||
#elif defined(__aarch64__)
|
||||
#define ABSL_STACKTRACE_INL_HEADER \
|
||||
"absl/debugging/internal/stacktrace_generic-inl.inc"
|
||||
# else
|
||||
"absl/debugging/internal/stacktrace_aarch64-inl.inc"
|
||||
#elif defined(__has_include)
|
||||
#if __has_include(<execinfo.h>)
|
||||
// Note: When using glibc this may require -funwind-tables to function properly.
|
||||
#define ABSL_STACKTRACE_INL_HEADER \
|
||||
"absl/debugging/internal/stacktrace_unimplemented-inl.inc"
|
||||
# endif
|
||||
#endif // NO_FRAME_POINTER
|
||||
|
||||
#else
|
||||
#define ABSL_STACKTRACE_INL_HEADER \
|
||||
"absl/debugging/internal/stacktrace_unimplemented-inl.inc"
|
||||
"absl/debugging/internal/stacktrace_generic-inl.inc"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// Fallback to the empty implementation.
|
||||
#if !defined(ABSL_STACKTRACE_INL_HEADER)
|
||||
#define ABSL_STACKTRACE_INL_HEADER \
|
||||
"absl/debugging/internal/stacktrace_unimplemented-inl.inc"
|
||||
#endif
|
||||
|
||||
#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#ifndef ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_
|
||||
#define ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
|
@ -116,20 +118,30 @@ bool RemoveAllSymbolDecorators(void);
|
|||
// filename != nullptr
|
||||
//
|
||||
// Returns true if the file was successfully registered.
|
||||
bool RegisterFileMappingHint(
|
||||
const void* start, const void* end, uint64_t offset, const char* filename);
|
||||
bool RegisterFileMappingHint(const void* start, const void* end,
|
||||
uint64_t offset, const char* filename);
|
||||
|
||||
// Looks up the file mapping registered by RegisterFileMappingHint for an
|
||||
// address range. If there is one, the file name is stored in *filename and
|
||||
// *start and *end are modified to reflect the registered mapping. Returns
|
||||
// whether any hint was found.
|
||||
bool GetFileMappingHint(const void** start,
|
||||
const void** end,
|
||||
uint64_t * offset,
|
||||
bool GetFileMappingHint(const void** start, const void** end, uint64_t* offset,
|
||||
const char** filename);
|
||||
|
||||
} // namespace debugging_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif // __cplusplus
|
||||
|
||||
bool
|
||||
AbslInternalGetFileMappingHint(const void** start, const void** end,
|
||||
uint64_t* offset, const char** filename);
|
||||
|
||||
#endif // ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_
|
||||
|
|
|
@ -76,15 +76,6 @@ const void *VDSOSupport::Init() {
|
|||
}
|
||||
#endif // __GLIBC_PREREQ(2, 16)
|
||||
if (vdso_base_.load(std::memory_order_relaxed) == 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.
|
||||
|
@ -175,18 +166,6 @@ int GetCPU() {
|
|||
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 debugging_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
|
|
@ -14,9 +14,18 @@
|
|||
|
||||
#include "absl/debugging/symbolize.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winapifamily.h>
|
||||
#if !(WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)) || \
|
||||
WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
||||
// UWP doesn't have access to win32 APIs.
|
||||
#define ABSL_INTERNAL_HAVE_SYMBOLIZE_WIN32
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE)
|
||||
#include "absl/debugging/symbolize_elf.inc"
|
||||
#elif defined(_WIN32)
|
||||
#elif defined(ABSL_INTERNAL_HAVE_SYMBOLIZE_WIN32)
|
||||
// The Windows Symbolizer only works if PDB files containing the debug info
|
||||
// are available to the program at runtime.
|
||||
#include "absl/debugging/symbolize_win32.inc"
|
||||
|
|
|
@ -77,8 +77,8 @@ bool Symbolize(const void* pc, char* out, int out_size) {
|
|||
|
||||
char tmp_buf[1024];
|
||||
if (debugging_internal::Demangle(symbol.c_str(), tmp_buf, sizeof(tmp_buf))) {
|
||||
int len = strlen(tmp_buf);
|
||||
if (len + 1 <= out_size) { // +1 for '\0'
|
||||
size_t len = strlen(tmp_buf);
|
||||
if (len + 1 <= static_cast<size_t>(out_size)) { // +1 for '\0'
|
||||
assert(len < sizeof(tmp_buf));
|
||||
memmove(out, tmp_buf, len + 1);
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cerrno>
|
||||
#include <cinttypes>
|
||||
|
@ -83,6 +84,12 @@ ABSL_NAMESPACE_BEGIN
|
|||
static char *argv0_value = nullptr;
|
||||
|
||||
void InitializeSymbolizer(const char *argv0) {
|
||||
#ifdef ABSL_HAVE_VDSO_SUPPORT
|
||||
// We need to make sure VDSOSupport::Init() is called before any setuid or
|
||||
// chroot calls, so InitializeSymbolizer() should be called very early in the
|
||||
// life of a program.
|
||||
absl::debugging_internal::VDSOSupport::Init();
|
||||
#endif
|
||||
if (argv0_value != nullptr) {
|
||||
free(argv0_value);
|
||||
argv0_value = nullptr;
|
||||
|
@ -178,6 +185,7 @@ struct ObjFile {
|
|||
fd(-1),
|
||||
elf_type(-1) {
|
||||
SafeMemZero(&elf_header, sizeof(elf_header));
|
||||
SafeMemZero(&phdr[0], sizeof(phdr));
|
||||
}
|
||||
|
||||
char *filename;
|
||||
|
@ -190,6 +198,10 @@ struct ObjFile {
|
|||
int fd;
|
||||
int elf_type;
|
||||
ElfW(Ehdr) elf_header;
|
||||
|
||||
// PT_LOAD program header describing executable code.
|
||||
// Normally we expect just one, but SWIFT binaries have two.
|
||||
std::array<ElfW(Phdr), 2> phdr;
|
||||
};
|
||||
|
||||
// Build 4-way associative cache for symbols. Within each cache line, symbols
|
||||
|
@ -1266,6 +1278,36 @@ static bool MaybeInitializeObjFile(ObjFile *obj) {
|
|||
ABSL_RAW_LOG(WARNING, "%s: failed to read elf header", obj->filename);
|
||||
return false;
|
||||
}
|
||||
const int phnum = obj->elf_header.e_phnum;
|
||||
const int phentsize = obj->elf_header.e_phentsize;
|
||||
size_t phoff = obj->elf_header.e_phoff;
|
||||
size_t num_executable_load_segments = 0;
|
||||
for (int j = 0; j < phnum; j++) {
|
||||
ElfW(Phdr) phdr;
|
||||
if (!ReadFromOffsetExact(obj->fd, &phdr, sizeof(phdr), phoff)) {
|
||||
ABSL_RAW_LOG(WARNING, "%s: failed to read program header %d",
|
||||
obj->filename, j);
|
||||
return false;
|
||||
}
|
||||
phoff += phentsize;
|
||||
constexpr int rx = PF_X | PF_R;
|
||||
if (phdr.p_type != PT_LOAD || (phdr.p_flags & rx) != rx) {
|
||||
// Not a LOAD segment, or not executable code.
|
||||
continue;
|
||||
}
|
||||
if (num_executable_load_segments < obj->phdr.size()) {
|
||||
memcpy(&obj->phdr[num_executable_load_segments++], &phdr, sizeof(phdr));
|
||||
} else {
|
||||
ABSL_RAW_LOG(WARNING, "%s: too many executable LOAD segments",
|
||||
obj->filename);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (num_executable_load_segments == 0) {
|
||||
// This object has no "r-x" LOAD segments. That's unexpected.
|
||||
ABSL_RAW_LOG(WARNING, "%s: no executable LOAD segments", obj->filename);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1289,23 +1331,52 @@ const char *Symbolizer::GetSymbol(const void *const pc) {
|
|||
int fd = -1;
|
||||
if (obj != nullptr) {
|
||||
if (MaybeInitializeObjFile(obj)) {
|
||||
if (obj->elf_type == ET_DYN &&
|
||||
reinterpret_cast<uint64_t>(obj->start_addr) >= obj->offset) {
|
||||
const size_t start_addr = reinterpret_cast<size_t>(obj->start_addr);
|
||||
if (obj->elf_type == ET_DYN && start_addr >= obj->offset) {
|
||||
// This object was relocated.
|
||||
//
|
||||
// For obj->offset > 0, adjust the relocation since a mapping at offset
|
||||
// X in the file will have a start address of [true relocation]+X.
|
||||
relocation = reinterpret_cast<ptrdiff_t>(obj->start_addr) - obj->offset;
|
||||
relocation = start_addr - obj->offset;
|
||||
|
||||
// Note: some binaries have multiple "rx" LOAD segments. We must
|
||||
// find the right one.
|
||||
ElfW(Phdr) *phdr = nullptr;
|
||||
for (size_t j = 0; j < obj->phdr.size(); j++) {
|
||||
ElfW(Phdr) &p = obj->phdr[j];
|
||||
if (p.p_type != PT_LOAD) {
|
||||
// We only expect PT_LOADs. This must be PT_NULL that we didn't
|
||||
// write over (i.e. we exhausted all interesting PT_LOADs).
|
||||
ABSL_RAW_CHECK(p.p_type == PT_NULL, "unexpected p_type");
|
||||
break;
|
||||
}
|
||||
if (pc < reinterpret_cast<void *>(start_addr + p.p_memsz)) {
|
||||
phdr = &p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (phdr == nullptr) {
|
||||
// That's unexpected. Hope for the best.
|
||||
ABSL_RAW_LOG(
|
||||
WARNING,
|
||||
"%s: unable to find LOAD segment for pc: %p, start_addr: %zx",
|
||||
obj->filename, pc, start_addr);
|
||||
} else {
|
||||
// Adjust relocation in case phdr.p_vaddr != 0.
|
||||
// This happens for binaries linked with `lld --rosegment`, and for
|
||||
// binaries linked with BFD `ld -z separate-code`.
|
||||
relocation -= phdr->p_vaddr - phdr->p_offset;
|
||||
}
|
||||
}
|
||||
|
||||
fd = obj->fd;
|
||||
}
|
||||
if (GetSymbolFromObjectFile(*obj, pc, relocation, symbol_buf_,
|
||||
sizeof(symbol_buf_), tmp_buf_,
|
||||
sizeof(tmp_buf_)) == SYMBOL_FOUND) {
|
||||
// Only try to demangle the symbol name if it fit into symbol_buf_.
|
||||
DemangleInplace(symbol_buf_, sizeof(symbol_buf_), tmp_buf_,
|
||||
sizeof(tmp_buf_));
|
||||
if (GetSymbolFromObjectFile(*obj, pc, relocation, symbol_buf_,
|
||||
sizeof(symbol_buf_), tmp_buf_,
|
||||
sizeof(tmp_buf_)) == SYMBOL_FOUND) {
|
||||
// Only try to demangle the symbol name if it fit into symbol_buf_.
|
||||
DemangleInplace(symbol_buf_, sizeof(symbol_buf_), tmp_buf_,
|
||||
sizeof(tmp_buf_));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#if ABSL_HAVE_VDSO_SUPPORT
|
||||
|
@ -1376,7 +1447,7 @@ int InstallSymbolDecorator(SymbolDecorator decorator, void *arg) {
|
|||
|
||||
if (!g_decorators_mu.TryLock()) {
|
||||
// Someone else is using decorators. Get out.
|
||||
return false;
|
||||
return -2;
|
||||
}
|
||||
int ret = ticket;
|
||||
if (g_num_decorators >= kMaxDecorators) {
|
||||
|
@ -1455,7 +1526,7 @@ bool GetFileMappingHint(const void **start, const void **end, uint64_t *offset,
|
|||
|
||||
bool Symbolize(const void *pc, char *out, int out_size) {
|
||||
// Symbolization is very slow under tsan.
|
||||
ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
|
||||
ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
|
||||
SAFE_ASSERT(out_size >= 0);
|
||||
debugging_internal::Symbolizer *s = debugging_internal::AllocateSymbolizer();
|
||||
const char *name = s->GetSymbol(pc);
|
||||
|
@ -1474,9 +1545,16 @@ bool Symbolize(const void *pc, char *out, int out_size) {
|
|||
}
|
||||
}
|
||||
debugging_internal::FreeSymbolizer(s);
|
||||
ANNOTATE_IGNORE_READS_AND_WRITES_END();
|
||||
ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END();
|
||||
return ok;
|
||||
}
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
extern "C" bool AbslInternalGetFileMappingHint(const void **start,
|
||||
const void **end, uint64_t *offset,
|
||||
const char **filename) {
|
||||
return absl::debugging_internal::GetFileMappingHint(start, end, offset,
|
||||
filename);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "gtest/gtest.h"
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/casts.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/per_thread_tls.h"
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
#include "absl/base/optimization.h"
|
||||
|
@ -220,8 +221,8 @@ static const char *SymbolizeStackConsumption(void *pc, int *stack_consumed) {
|
|||
static int GetStackConsumptionUpperLimit() {
|
||||
// Symbolize stack consumption should be within 2kB.
|
||||
int stack_consumption_upper_limit = 2048;
|
||||
#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
|
||||
defined(THREAD_SANITIZER)
|
||||
#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \
|
||||
defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER)
|
||||
// Account for sanitizer instrumentation requiring additional stack space.
|
||||
stack_consumption_upper_limit *= 5;
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue