diff options
Diffstat (limited to 'third_party/abseil_cpp/absl/debugging')
16 files changed, 242 insertions, 102 deletions
diff --git a/third_party/abseil_cpp/absl/debugging/BUILD.bazel b/third_party/abseil_cpp/absl/debugging/BUILD.bazel index d336246777fa..cd6e45439657 100644 --- a/third_party/abseil_cpp/absl/debugging/BUILD.bazel +++ b/third_party/abseil_cpp/absl/debugging/BUILD.bazel @@ -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, diff --git a/third_party/abseil_cpp/absl/debugging/CMakeLists.txt b/third_party/abseil_cpp/absl/debugging/CMakeLists.txt index c597df86b0b5..074b44cf1781 100644 --- a/third_party/abseil_cpp/absl/debugging/CMakeLists.txt +++ b/third_party/abseil_cpp/absl/debugging/CMakeLists.txt @@ -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 diff --git a/third_party/abseil_cpp/absl/debugging/failure_signal_handler.cc b/third_party/abseil_cpp/absl/debugging/failure_signal_handler.cc index 1f69bfa84dd9..5d13bdbbbd13 100644 --- a/third_party/abseil_cpp/absl/debugging/failure_signal_handler.cc +++ b/third_party/abseil_cpp/absl/debugging/failure_signal_handler.cc @@ -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 diff --git a/third_party/abseil_cpp/absl/debugging/internal/address_is_readable.cc b/third_party/abseil_cpp/absl/debugging/internal/address_is_readable.cc index 65376063669f..329c285f3b58 100644 --- a/third_party/abseil_cpp/absl/debugging/internal/address_is_readable.cc +++ b/third_party/abseil_cpp/absl/debugging/internal/address_is_readable.cc @@ -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); diff --git a/third_party/abseil_cpp/absl/debugging/internal/demangle.cc b/third_party/abseil_cpp/absl/debugging/internal/demangle.cc index fc262e50ae50..46cdb67b1fbf 100644 --- a/third_party/abseil_cpp/absl/debugging/internal/demangle.cc +++ b/third_party/abseil_cpp/absl/debugging/internal/demangle.cc @@ -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 diff --git a/third_party/abseil_cpp/absl/debugging/internal/demangle_test.cc b/third_party/abseil_cpp/absl/debugging/internal/demangle_test.cc index c6f1ce184c10..0bed7359d8b4 100644 --- a/third_party/abseil_cpp/absl/debugging/internal/demangle_test.cc +++ b/third_party/abseil_cpp/absl/debugging/internal/demangle_test.cc @@ -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]; diff --git a/third_party/abseil_cpp/absl/debugging/internal/stack_consumption.cc b/third_party/abseil_cpp/absl/debugging/internal/stack_consumption.cc index 875ca6d91f7f..e3dd51c355ad 100644 --- a/third_party/abseil_cpp/absl/debugging/internal/stack_consumption.cc +++ b/third_party/abseil_cpp/absl/debugging/internal/stack_consumption.cc @@ -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 diff --git a/third_party/abseil_cpp/absl/debugging/internal/stack_consumption.h b/third_party/abseil_cpp/absl/debugging/internal/stack_consumption.h index 5e60ec422916..2b5e7151667c 100644 --- a/third_party/abseil_cpp/absl/debugging/internal/stack_consumption.h +++ b/third_party/abseil_cpp/absl/debugging/internal/stack_consumption.h @@ -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 { diff --git a/third_party/abseil_cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc b/third_party/abseil_cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc index 14a76f1eb5b3..f4859d7c210a 100644 --- a/third_party/abseil_cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc +++ b/third_party/abseil_cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc @@ -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. diff --git a/third_party/abseil_cpp/absl/debugging/internal/stacktrace_config.h b/third_party/abseil_cpp/absl/debugging/internal/stacktrace_config.h index d5cc17401396..90af852818e7 100644 --- a/third_party/abseil_cpp/absl/debugging/internal/stacktrace_config.h +++ b/third_party/abseil_cpp/absl/debugging/internal/stacktrace_config.h @@ -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__) -#define ABSL_STACKTRACE_INL_HEADER \ - "absl/debugging/internal/stacktrace_x86-inl.inc" -# elif defined(__ppc__) || defined(__PPC__) +#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_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 + "absl/debugging/internal/stacktrace_generic-inl.inc" +#endif +#endif -#else +#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_ diff --git a/third_party/abseil_cpp/absl/debugging/internal/symbolize.h b/third_party/abseil_cpp/absl/debugging/internal/symbolize.h index 663d774d42fa..4f26130fbb71 100644 --- a/third_party/abseil_cpp/absl/debugging/internal/symbolize.h +++ b/third_party/abseil_cpp/absl/debugging/internal/symbolize.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_ diff --git a/third_party/abseil_cpp/absl/debugging/internal/vdso_support.cc b/third_party/abseil_cpp/absl/debugging/internal/vdso_support.cc index 1e8a78ac9c1f..6be16d907275 100644 --- a/third_party/abseil_cpp/absl/debugging/internal/vdso_support.cc +++ b/third_party/abseil_cpp/absl/debugging/internal/vdso_support.cc @@ -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 diff --git a/third_party/abseil_cpp/absl/debugging/symbolize.cc b/third_party/abseil_cpp/absl/debugging/symbolize.cc index eec7a6e86118..5e4a25d69dce 100644 --- a/third_party/abseil_cpp/absl/debugging/symbolize.cc +++ b/third_party/abseil_cpp/absl/debugging/symbolize.cc @@ -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" diff --git a/third_party/abseil_cpp/absl/debugging/symbolize_darwin.inc b/third_party/abseil_cpp/absl/debugging/symbolize_darwin.inc index cdadd40e97d1..443ce9efc4ce 100644 --- a/third_party/abseil_cpp/absl/debugging/symbolize_darwin.inc +++ b/third_party/abseil_cpp/absl/debugging/symbolize_darwin.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); } diff --git a/third_party/abseil_cpp/absl/debugging/symbolize_elf.inc b/third_party/abseil_cpp/absl/debugging/symbolize_elf.inc index c05424e05b7d..f4d5727bdeb5 100644 --- a/third_party/abseil_cpp/absl/debugging/symbolize_elf.inc +++ b/third_party/abseil_cpp/absl/debugging/symbolize_elf.inc @@ -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); +} diff --git a/third_party/abseil_cpp/absl/debugging/symbolize_test.cc b/third_party/abseil_cpp/absl/debugging/symbolize_test.cc index 43f655493afb..a2dd4956c497 100644 --- a/third_party/abseil_cpp/absl/debugging/symbolize_test.cc +++ b/third_party/abseil_cpp/absl/debugging/symbolize_test.cc @@ -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 |