diff options
Diffstat (limited to 'third_party/abseil-cpp/absl/debugging/internal')
19 files changed, 713 insertions, 132 deletions
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 6537606366..329c285f3b 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 fc615c3f58..93ae32796c 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}, @@ -151,7 +152,7 @@ static const AbbrevPair kSubstitutionList[] = { // frame, so every byte counts. typedef struct { int mangled_idx; // Cursor of mangled name. - int out_cur_idx; // Cursor of output std::string. + int out_cur_idx; // Cursor of output string. int prev_name_idx; // For constructors/destructors. signed int prev_name_length : 16; // For constructors/destructors. signed int nest_level : 15; // For nested names. @@ -172,8 +173,8 @@ static_assert(sizeof(ParseState) == 4 * sizeof(int), // Only one copy of this exists for each call to Demangle, so the size of this // struct is nearly inconsequential. typedef struct { - const char *mangled_begin; // Beginning of input std::string. - char *out; // Beginning of output std::string. + const char *mangled_begin; // Beginning of input string. + char *out; // Beginning of output string. int out_end_idx; // One past last allowed output character. int recursion_depth; // For stack exhaustion prevention. int steps; // Cap how much work we'll do, regardless of depth. @@ -385,30 +386,35 @@ static bool IsDigit(char c) { return c >= '0' && c <= '9'; } // by GCC 4.5.x and later versions (and our locally-modified version of GCC // 4.4.x) to indicate functions which have been cloned during optimization. // We treat any sequence (.<alpha>+.<digit>+)+ as a function clone suffix. +// Additionally, '_' is allowed along with the alphanumeric sequence. static bool IsFunctionCloneSuffix(const char *str) { size_t i = 0; while (str[i] != '\0') { - // Consume a single .<alpha>+.<digit>+ sequence. - if (str[i] != '.' || !IsAlpha(str[i + 1])) { - return false; + bool parsed = false; + // Consume a single [.<alpha> | _]*[.<digit>]* sequence. + if (str[i] == '.' && (IsAlpha(str[i + 1]) || str[i + 1] == '_')) { + parsed = true; + i += 2; + while (IsAlpha(str[i]) || str[i] == '_') { + ++i; + } } - i += 2; - while (IsAlpha(str[i])) { - ++i; + if (str[i] == '.' && IsDigit(str[i + 1])) { + parsed = true; + i += 2; + while (IsDigit(str[i])) { + ++i; + } } - if (str[i] != '.' || !IsDigit(str[i + 1])) { + if (!parsed) return false; - } - i += 2; - while (IsDigit(str[i])) { - ++i; - } } return true; // Consumed everything in "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 +427,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 +970,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 +989,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 +1086,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 +1156,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 +1223,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 +1277,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; } @@ -1564,6 +1617,7 @@ static bool ParseUnresolvedName(State *state) { // ::= <2-ary operator-name> <expression> <expression> // ::= <3-ary operator-name> <expression> <expression> <expression> // ::= cl <expression>+ E +// ::= cp <simple-id> <expression>* E # Clang-specific. // ::= cv <type> <expression> # type (expression) // ::= cv <type> _ <expression>* E # type (expr-list) // ::= st <type> @@ -1586,14 +1640,23 @@ static bool ParseExpression(State *state) { return true; } - // Object/function call expression. ParseState copy = state->parse_state; + + // Object/function call expression. if (ParseTwoCharToken(state, "cl") && OneOrMore(ParseExpression, state) && ParseOneCharToken(state, 'E')) { return true; } state->parse_state = copy; + // Clang-specific "cp <simple-id> <expression>* E" + // https://clang.llvm.org/doxygen/ItaniumMangle_8cpp_source.html#l04338 + if (ParseTwoCharToken(state, "cp") && ParseSimpleId(state) && + ZeroOrMore(ParseExpression, state) && ParseOneCharToken(state, 'E')) { + return true; + } + state->parse_state = copy; + // Function-param expression (level 0). if (ParseTwoCharToken(state, "fp") && Optional(ParseCVQualifiers(state)) && Optional(ParseNumber(state, nullptr)) && ParseOneCharToken(state, '_')) { @@ -1887,7 +1950,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 c6f1ce184c..6b142902ca 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" @@ -69,12 +70,34 @@ TEST(Demangle, Clones) { EXPECT_STREQ("Foo()", tmp); EXPECT_TRUE(Demangle("_ZL3Foov.isra.2.constprop.18", tmp, sizeof(tmp))); EXPECT_STREQ("Foo()", tmp); - // Invalid (truncated), should not demangle. - EXPECT_FALSE(Demangle("_ZL3Foov.clo", tmp, sizeof(tmp))); + // Demangle suffixes produced by -funique-internal-linkage-names. + EXPECT_TRUE(Demangle("_ZL3Foov.__uniq.12345", tmp, sizeof(tmp))); + EXPECT_STREQ("Foo()", tmp); + EXPECT_TRUE(Demangle("_ZL3Foov.__uniq.12345.isra.2.constprop.18", tmp, + sizeof(tmp))); + EXPECT_STREQ("Foo()", tmp); + // Suffixes without the number should also demangle. + EXPECT_TRUE(Demangle("_ZL3Foov.clo", tmp, sizeof(tmp))); + EXPECT_STREQ("Foo()", tmp); + // Suffixes with just the number should also demangle. + EXPECT_TRUE(Demangle("_ZL3Foov.123", tmp, sizeof(tmp))); + EXPECT_STREQ("Foo()", tmp); + // (.clone. followed by non-number), should also demangle. + EXPECT_TRUE(Demangle("_ZL3Foov.clone.foo", tmp, sizeof(tmp))); + EXPECT_STREQ("Foo()", tmp); + // (.clone. followed by multiple numbers), should also demangle. + EXPECT_TRUE(Demangle("_ZL3Foov.clone.123.456", tmp, sizeof(tmp))); + EXPECT_STREQ("Foo()", tmp); + // (a long valid suffix), should demangle. + EXPECT_TRUE(Demangle("_ZL3Foov.part.9.165493.constprop.775.31805", tmp, + sizeof(tmp))); + EXPECT_STREQ("Foo()", tmp); + // Invalid (. without anything else), should not demangle. + EXPECT_FALSE(Demangle("_ZL3Foov.", tmp, sizeof(tmp))); + // Invalid (. with mix of alpha and digits), should not demangle. + EXPECT_FALSE(Demangle("_ZL3Foov.abc123", tmp, sizeof(tmp))); // Invalid (.clone. not followed by number), should not demangle. EXPECT_FALSE(Demangle("_ZL3Foov.clone.", tmp, sizeof(tmp))); - // Invalid (.clone. followed by non-number), should not demangle. - EXPECT_FALSE(Demangle("_ZL3Foov.clone.foo", tmp, sizeof(tmp))); // Invalid (.constprop. not followed by number), should not demangle. EXPECT_FALSE(Demangle("_ZL3Foov.isra.2.constprop.", tmp, sizeof(tmp))); } @@ -82,9 +105,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/elf_mem_image.cc b/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.cc index 24cc01302d..29a281812b 100644 --- a/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.cc +++ b/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.cc @@ -22,6 +22,7 @@ #include <string.h> #include <cassert> #include <cstddef> +#include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" // From binutils/include/elf/common.h (this doesn't appear to be documented @@ -43,11 +44,11 @@ namespace debugging_internal { namespace { -#if __WORDSIZE == 32 +#if __SIZEOF_POINTER__ == 4 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 +#elif __SIZEOF_POINTER__ == 8 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); } @@ -175,17 +176,17 @@ void ElfMemImage::Init(const void *base) { } switch (base_as_char[EI_DATA]) { case ELFDATA2LSB: { - if (__LITTLE_ENDIAN != __BYTE_ORDER) { - assert(false); - return; - } +#ifndef ABSL_IS_LITTLE_ENDIAN + assert(false); + return; +#endif break; } case ELFDATA2MSB: { - if (__BIG_ENDIAN != __BYTE_ORDER) { - assert(false); - return; - } +#ifndef ABSL_IS_BIG_ENDIAN + assert(false); + return; +#endif break; } default: { @@ -221,7 +222,7 @@ void ElfMemImage::Init(const void *base) { reinterpret_cast<ElfW(Dyn) *>(dynamic_program_header->p_vaddr + relocation); for (; dynamic_entry->d_tag != DT_NULL; ++dynamic_entry) { - const ElfW(Xword) value = dynamic_entry->d_un.d_val + relocation; + const auto value = dynamic_entry->d_un.d_val + relocation; switch (dynamic_entry->d_tag) { case DT_HASH: hash_ = reinterpret_cast<ElfW(Word) *>(value); diff --git a/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.h b/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.h index 46bfade350..a894bd423e 100644 --- a/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.h +++ b/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.h @@ -31,8 +31,8 @@ #error ABSL_HAVE_ELF_MEM_IMAGE cannot be directly set #endif -#if defined(__ELF__) && defined(__GLIBC__) && !defined(__native_client__) && \ - !defined(__asmjs__) && !defined(__wasm__) +#if defined(__ELF__) && !defined(__native_client__) && !defined(__asmjs__) && \ + !defined(__wasm__) #define ABSL_HAVE_ELF_MEM_IMAGE 1 #endif @@ -40,6 +40,10 @@ #include <link.h> // for ElfW +#if defined(__FreeBSD__) && !defined(ElfW) +#define ElfW(x) __ElfN(x) +#endif + namespace absl { ABSL_NAMESPACE_BEGIN namespace debugging_internal { diff --git a/third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc b/third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc index a3dd893a9d..589a3ef367 100644 --- a/third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc +++ b/third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc @@ -20,6 +20,10 @@ #include <unistd.h> #endif +#ifdef __APPLE__ +#include <sys/ucontext.h> +#endif + #include <csignal> #include <cstdio> @@ -42,30 +46,72 @@ void* GetProgramCounter(void* vuc) { ucontext_t* context = reinterpret_cast<ucontext_t*>(vuc); #if defined(__aarch64__) return reinterpret_cast<void*>(context->uc_mcontext.pc); +#elif defined(__alpha__) + return reinterpret_cast<void*>(context->uc_mcontext.sc_pc); #elif defined(__arm__) return reinterpret_cast<void*>(context->uc_mcontext.arm_pc); +#elif defined(__hppa__) + return reinterpret_cast<void*>(context->uc_mcontext.sc_iaoq[0]); #elif defined(__i386__) if (14 < ABSL_ARRAYSIZE(context->uc_mcontext.gregs)) return reinterpret_cast<void*>(context->uc_mcontext.gregs[14]); +#elif defined(__ia64__) + return reinterpret_cast<void*>(context->uc_mcontext.sc_ip); +#elif defined(__m68k__) + return reinterpret_cast<void*>(context->uc_mcontext.gregs[16]); #elif defined(__mips__) return reinterpret_cast<void*>(context->uc_mcontext.pc); #elif defined(__powerpc64__) return reinterpret_cast<void*>(context->uc_mcontext.gp_regs[32]); #elif defined(__powerpc__) - return reinterpret_cast<void*>(context->uc_mcontext.regs->nip); + return reinterpret_cast<void*>(context->uc_mcontext.uc_regs->gregs[32]); #elif defined(__riscv) return reinterpret_cast<void*>(context->uc_mcontext.__gregs[REG_PC]); #elif defined(__s390__) && !defined(__s390x__) return reinterpret_cast<void*>(context->uc_mcontext.psw.addr & 0x7fffffff); #elif defined(__s390__) && defined(__s390x__) return reinterpret_cast<void*>(context->uc_mcontext.psw.addr); +#elif defined(__sh__) + return reinterpret_cast<void*>(context->uc_mcontext.pc); +#elif defined(__sparc__) && !defined(__arch64__) + return reinterpret_cast<void*>(context->uc_mcontext.gregs[19]); +#elif defined(__sparc__) && defined(__arch64__) + return reinterpret_cast<void*>(context->uc_mcontext.mc_gregs[19]); #elif defined(__x86_64__) if (16 < ABSL_ARRAYSIZE(context->uc_mcontext.gregs)) return reinterpret_cast<void*>(context->uc_mcontext.gregs[16]); +#elif defined(__e2k__) + return reinterpret_cast<void*>(context->uc_mcontext.cr0_hi); #else #error "Undefined Architecture." #endif } +#elif defined(__APPLE__) + if (vuc != nullptr) { + ucontext_t* signal_ucontext = reinterpret_cast<ucontext_t*>(vuc); +#if defined(__aarch64__) + return reinterpret_cast<void*>( + __darwin_arm_thread_state64_get_pc(signal_ucontext->uc_mcontext->__ss)); +#elif defined(__arm__) +#if __DARWIN_UNIX03 + return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->__ss.__pc); +#else + return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->ss.pc); +#endif +#elif defined(__i386__) +#if __DARWIN_UNIX03 + return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->__ss.__eip); +#else + return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->ss.eip); +#endif +#elif defined(__x86_64__) +#if __DARWIN_UNIX03 + return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->__ss.__rip); +#else + return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->ss.rip); +#endif +#endif + } #elif defined(__akaros__) auto* ctx = reinterpret_cast<struct user_context*>(vuc); return reinterpret_cast<void*>(get_user_ctx_pc(ctx)); 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 875ca6d91f..513486498a 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__) || defined(__riscv) 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 5e60ec4229..f41b64c39d 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__) || defined(__riscv)) #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 411ea308e9..f4859d7c21 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. @@ -74,6 +77,8 @@ static inline uintptr_t ComputeStackFrameSize(const T* low, // checks (the strictness of which is controlled by the boolean parameter // "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned. template<bool STRICT_UNWINDING, bool WITH_CONTEXT> +ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. +ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. static void **NextStackFrame(void **old_frame_pointer, const void *uc) { void **new_frame_pointer = reinterpret_cast<void**>(*old_frame_pointer); bool check_frame_size = true; @@ -123,6 +128,8 @@ static void **NextStackFrame(void **old_frame_pointer, const void *uc) { } template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> +ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. +ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, const void *ucp, int *min_dropped_frames) { #ifdef __GNUC__ diff --git a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_arm-inl.inc b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_arm-inl.inc index fffda968dd..2a1bf2e886 100644 --- a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_arm-inl.inc +++ b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_arm-inl.inc @@ -1,9 +1,18 @@ -// Copyright 2011 and onwards Google Inc. -// All rights reserved. +// Copyright 2017 The Abseil Authors. // -// Author: Doug Kwan -// This is inspired by Craig Silverstein's PowerPC stacktrace code. +// 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 +// +// https://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 is inspired by Craig Silverstein's PowerPC stacktrace code. #ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_ #define ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_ 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 d4e8480a8e..ff21b719a0 100644 --- a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_config.h +++ b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_config.h @@ -21,6 +21,8 @@ #ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_ #define ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_ +#include "absl/base/config.h" + #if defined(ABSL_STACKTRACE_INL_HEADER) #error ABSL_STACKTRACE_INL_HEADER cannot be directly set @@ -28,43 +30,58 @@ #define ABSL_STACKTRACE_INL_HEADER \ "absl/debugging/internal/stacktrace_win32-inl.inc" -#elif defined(__linux__) && !defined(__ANDROID__) - -#if !defined(NO_FRAME_POINTER) -# if defined(__i386__) || defined(__x86_64__) +#elif defined(__APPLE__) +#ifdef ABSL_HAVE_THREAD_LOCAL +// Thread local support required for UnwindImpl. #define ABSL_STACKTRACE_INL_HEADER \ - "absl/debugging/internal/stacktrace_x86-inl.inc" -# elif defined(__ppc__) || defined(__PPC__) + "absl/debugging/internal/stacktrace_generic-inl.inc" +#endif // defined(ABSL_HAVE_THREAD_LOCAL) + +#elif defined(__EMSCRIPTEN__) #define ABSL_STACKTRACE_INL_HEADER \ - "absl/debugging/internal/stacktrace_powerpc-inl.inc" -# elif defined(__aarch64__) + "absl/debugging/internal/stacktrace_emscripten-inl.inc" + +#elif defined(__linux__) && !defined(__ANDROID__) + +#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_aarch64-inl.inc" -# elif defined(__arm__) + "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 // __has_include(<execinfo.h>) +#elif defined(__i386__) || defined(__x86_64__) +#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_unimplemented-inl.inc" -# endif -#else // defined(NO_FRAME_POINTER) -# if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) + "absl/debugging/internal/stacktrace_powerpc-inl.inc" +#elif defined(__aarch64__) #define ABSL_STACKTRACE_INL_HEADER \ - "absl/debugging/internal/stacktrace_generic-inl.inc" -# elif defined(__ppc__) || defined(__PPC__) + "absl/debugging/internal/stacktrace_aarch64-inl.inc" +#elif defined(__riscv) #define ABSL_STACKTRACE_INL_HEADER \ - "absl/debugging/internal/stacktrace_generic-inl.inc" -# else + "absl/debugging/internal/stacktrace_riscv-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 // __has_include(<execinfo.h>) +#endif // defined(__has_include) + +#endif // defined(__linux__) && !defined(__ANDROID__) -#else +// 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/stacktrace_emscripten-inl.inc b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_emscripten-inl.inc new file mode 100644 index 0000000000..0f44451438 --- /dev/null +++ b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_emscripten-inl.inc @@ -0,0 +1,110 @@ +// 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 +// +// https://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. +// +// Portable implementation - just use glibc +// +// Note: The glibc implementation may cause a call to malloc. +// This can cause a deadlock in HeapProfiler. + +#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_EMSCRIPTEN_INL_H_ +#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_EMSCRIPTEN_INL_H_ + +#include <emscripten.h> + +#include <atomic> +#include <cstring> + +#include "absl/base/attributes.h" +#include "absl/debugging/stacktrace.h" + +extern "C" { +uintptr_t emscripten_stack_snapshot(); +uint32_t emscripten_stack_unwind_buffer(uintptr_t pc, void *buffer, + uint32_t depth); +} + +// Sometimes, we can try to get a stack trace from within a stack +// trace, which can cause a self-deadlock. +// Protect against such reentrant call by failing to get a stack trace. +// +// We use __thread here because the code here is extremely low level -- it is +// called while collecting stack traces from within malloc and mmap, and thus +// can not call anything which might call malloc or mmap itself. +static __thread int recursive = 0; + +// The stack trace function might be invoked very early in the program's +// execution (e.g. from the very first malloc). +// As such, we suppress usage of backtrace during this early stage of execution. +static std::atomic<bool> disable_stacktraces(true); // Disabled until healthy. +// Waiting until static initializers run seems to be late enough. +// This file is included into stacktrace.cc so this will only run once. +ABSL_ATTRIBUTE_UNUSED static int stacktraces_enabler = []() { + // Check if we can even create stacktraces. If not, bail early and leave + // disable_stacktraces set as-is. + // clang-format off + if (!EM_ASM_INT({ return (typeof wasmOffsetConverter !== 'undefined'); })) { + return 0; + } + // clang-format on + disable_stacktraces.store(false, std::memory_order_relaxed); + return 0; +}(); + +template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> +static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count, + const void *ucp, int *min_dropped_frames) { + if (recursive || disable_stacktraces.load(std::memory_order_relaxed)) { + return 0; + } + ++recursive; + + static_cast<void>(ucp); // Unused. + constexpr int kStackLength = 64; + void *stack[kStackLength]; + + int size; + uintptr_t pc = emscripten_stack_snapshot(); + size = emscripten_stack_unwind_buffer(pc, stack, kStackLength); + + int result_count = size - skip_count; + if (result_count < 0) result_count = 0; + if (result_count > max_depth) result_count = max_depth; + for (int i = 0; i < result_count; i++) result[i] = stack[i + skip_count]; + + if (IS_STACK_FRAMES) { + // No implementation for finding out the stack frame sizes yet. + memset(sizes, 0, sizeof(*sizes) * result_count); + } + if (min_dropped_frames != nullptr) { + if (size - skip_count - max_depth > 0) { + *min_dropped_frames = size - skip_count - max_depth; + } else { + *min_dropped_frames = 0; + } + } + + --recursive; + + return result_count; +} + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace debugging_internal { +bool StackTraceWorksForTest() { return true; } +} // namespace debugging_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_EMSCRIPTEN_INL_H_ diff --git a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_generic-inl.inc b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_generic-inl.inc index ac034c9f5b..b2792a1f3a 100644 --- a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_generic-inl.inc +++ b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_generic-inl.inc @@ -1,7 +1,16 @@ -// Copyright 2000 - 2007 Google Inc. -// All rights reserved. +// Copyright 2017 The Abseil Authors. // -// Author: Sanjay Ghemawat +// 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 +// +// https://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. // // Portable implementation - just use glibc // diff --git a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_powerpc-inl.inc b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_powerpc-inl.inc index 2e7c2f404f..cf8c05160c 100644 --- a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_powerpc-inl.inc +++ b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_powerpc-inl.inc @@ -131,7 +131,12 @@ static void **NextStackFrame(void **old_sp, const void *uc) { const ucontext_t* signal_context = reinterpret_cast<const ucontext_t*>(uc); void **const sp_before_signal = - reinterpret_cast<void**>(signal_context->uc_mcontext.gp_regs[PT_R1]); +#if defined(__PPC64__) + reinterpret_cast<void **>(signal_context->uc_mcontext.gp_regs[PT_R1]); +#else + reinterpret_cast<void **>( + signal_context->uc_mcontext.uc_regs->gregs[PT_R1]); +#endif // Check that alleged sp before signal is nonnull and is reasonably // aligned. if (sp_before_signal != nullptr && diff --git a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_riscv-inl.inc b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_riscv-inl.inc new file mode 100644 index 0000000000..8cbc78548c --- /dev/null +++ b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_riscv-inl.inc @@ -0,0 +1,234 @@ +// Copyright 2021 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 +// +// https://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_STACKTRACE_RISCV_INL_H_ +#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_RISCV_INL_H_ + +// Generate stack trace for riscv + +#include <sys/ucontext.h> + +#include "absl/base/config.h" +#if defined(__linux__) +#include <sys/mman.h> +#include <ucontext.h> +#include <unistd.h> +#endif + +#include <atomic> +#include <cassert> +#include <cstdint> +#include <iostream> + +#include "absl/base/attributes.h" +#include "absl/debugging/internal/address_is_readable.h" +#include "absl/debugging/internal/vdso_support.h" +#include "absl/debugging/stacktrace.h" + +static const uintptr_t kUnknownFrameSize = 0; + +#if defined(__linux__) +// Returns the address of the VDSO __kernel_rt_sigreturn function, if present. +static const unsigned char *GetKernelRtSigreturnAddress() { + constexpr uintptr_t kImpossibleAddress = 0; + ABSL_CONST_INIT static std::atomic<uintptr_t> memoized(kImpossibleAddress); + uintptr_t address = memoized.load(std::memory_order_relaxed); + if (address != kImpossibleAddress) { + return reinterpret_cast<const unsigned char *>(address); + } + + address = reinterpret_cast<uintptr_t>(nullptr); + +#if ABSL_HAVE_VDSO_SUPPORT + absl::debugging_internal::VDSOSupport vdso; + if (vdso.IsPresent()) { + absl::debugging_internal::VDSOSupport::SymbolInfo symbol_info; + // Symbol versioning pulled from arch/riscv/kernel/vdso/vdso.lds at v5.10. + auto lookup = [&](int type) { + return vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_4.15", 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. + assert(false && "VDSO is present, but doesn't have expected symbol"); + } else { + if (reinterpret_cast<uintptr_t>(symbol_info.address) != + kImpossibleAddress) { + address = reinterpret_cast<uintptr_t>(symbol_info.address); + } else { + assert(false && "VDSO returned invalid address"); + } + } + } +#endif + + memoized.store(address, std::memory_order_relaxed); + return reinterpret_cast<const unsigned char *>(address); +} +#endif // __linux__ + +// Compute the size of a stack frame in [low..high). We assume that low < high. +// Return size of kUnknownFrameSize. +template <typename T> +static inline uintptr_t ComputeStackFrameSize(const T *low, const T *high) { + const char *low_char_ptr = reinterpret_cast<const char *>(low); + const char *high_char_ptr = reinterpret_cast<const char *>(high); + return low < high ? high_char_ptr - low_char_ptr : kUnknownFrameSize; +} + +// Given a pointer to a stack frame, locate and return the calling stackframe, +// or return null if no stackframe can be found. Perform sanity checks (the +// strictness of which is controlled by the boolean parameter +// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned. +template <bool STRICT_UNWINDING, bool WITH_CONTEXT> +ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. +ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. +static void ** NextStackFrame(void **old_frame_pointer, const void *uc) { + // . + // . + // . + // +-> +----------------+ + // | | return address | + // | | previous fp | + // | | ... | + // | +----------------+ <-+ + // | | return address | | + // +---|- previous fp | | + // | ... | | + // $fp ->|----------------+ | + // | return address | | + // | previous fp -|---+ + // $sp ->| ... | + // +----------------+ + void **new_frame_pointer = reinterpret_cast<void **>(old_frame_pointer[-2]); + bool check_frame_size = true; + +#if defined(__linux__) + if (WITH_CONTEXT && uc != nullptr) { + // Check to see if next frame's return address is __kernel_rt_sigreturn. + if (old_frame_pointer[-1] == GetKernelRtSigreturnAddress()) { + const ucontext_t *ucv = static_cast<const ucontext_t *>(uc); + // old_frame_pointer is not suitable for unwinding, look at ucontext to + // discover frame pointer before signal. + // + // RISCV ELF psABI has the frame pointer at x8/fp/s0. + // -- RISCV psABI Table 18.2 + void **const pre_signal_frame_pointer = + reinterpret_cast<void **>(ucv->uc_mcontext.__gregs[8]); + + // Check the alleged frame pointer is actually readable. This is to + // prevent "double fault" in case we hit the first fault due to stack + // corruption. + if (!absl::debugging_internal::AddressIsReadable( + pre_signal_frame_pointer)) + return nullptr; + + // Alleged frame pointer is readable, use it for further unwinding. + new_frame_pointer = pre_signal_frame_pointer; + + // Skip frame size check if we return from a signal. We may be using an + // alterate stack for signals. + check_frame_size = false; + } + } +#endif + + // The RISCV ELF psABI mandates that the stack pointer is always 16-byte + // aligned. + // FIXME(abdulras) this doesn't hold for ILP32E which only mandates a 4-byte + // alignment. + if ((reinterpret_cast<uintptr_t>(new_frame_pointer) & 15) != 0) + return nullptr; + + // Check frame size. In strict mode, we assume frames to be under 100,000 + // bytes. In non-strict mode, we relax the limit to 1MB. + if (check_frame_size) { + const uintptr_t max_size = STRICT_UNWINDING ? 100000 : 1000000; + const uintptr_t frame_size = + ComputeStackFrameSize(old_frame_pointer, new_frame_pointer); + if (frame_size == kUnknownFrameSize || frame_size > max_size) + return nullptr; + } + + return new_frame_pointer; +} + +template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> +ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. +ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. +static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count, + const void *ucp, int *min_dropped_frames) { +#if defined(__GNUC__) + void **frame_pointer = reinterpret_cast<void **>(__builtin_frame_address(0)); +#else +#error reading stack pointer not yet supported on this platform +#endif + + skip_count++; // Skip the frame for this function. + int n = 0; + + // The `frame_pointer` that is computed here points to the top of the frame. + // The two words preceding the address are the return address and the previous + // frame pointer. To find a PC value associated with the current frame, we + // need to go down a level in the call chain. So we remember the return + // address of the last frame seen. This does not work for the first stack + // frame, which belongs to `UnwindImp()` but we skip the frame for + // `UnwindImp()` anyway. + void *prev_return_address = nullptr; + + while (frame_pointer && n < max_depth) { + // The absl::GetStackFrames routine si called when we are in some + // informational context (the failure signal handler for example). Use the + // non-strict unwinding rules to produce a stack trace that is as complete + // as possible (even if it contains a few bogus entries in some rare cases). + void **next_frame_pointer = + NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(frame_pointer, ucp); + + if (skip_count > 0) { + skip_count--; + } else { + result[n] = prev_return_address; + if (IS_STACK_FRAMES) { + sizes[n] = ComputeStackFrameSize(frame_pointer, next_frame_pointer); + } + n++; + } + prev_return_address = frame_pointer[-1]; + frame_pointer = next_frame_pointer; + } + if (min_dropped_frames != nullptr) { + // Implementation detail: we clamp the max of frames we are willing to + // count, so as not to spend too much time in the loop below. + const int kMaxUnwind = 200; + int j = 0; + for (; frame_pointer != nullptr && j < kMaxUnwind; j++) { + frame_pointer = + NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(frame_pointer, ucp); + } + *min_dropped_frames = j; + } + return n; +} + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace debugging_internal { +bool StackTraceWorksForTest() { return true; } +} // namespace debugging_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif diff --git a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_win32-inl.inc b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_win32-inl.inc index 9c2c558044..1c666c8b56 100644 --- a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_win32-inl.inc +++ b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_win32-inl.inc @@ -46,11 +46,19 @@ typedef USHORT NTAPI RtlCaptureStackBackTrace_Function( OUT PVOID *backtrace, OUT PULONG backtrace_hash); +// It is not possible to load RtlCaptureStackBackTrace at static init time in +// UWP. CaptureStackBackTrace is the public version of RtlCaptureStackBackTrace +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \ + !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn = + &::CaptureStackBackTrace; +#else // Load the function we need at static init time, where we don't have // to worry about someone else holding the loader's lock. static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn = - (RtlCaptureStackBackTrace_Function*) - GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace"); + (RtlCaptureStackBackTrace_Function*)GetProcAddress( + GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace"); +#endif // WINAPI_PARTITION_APP && !WINAPI_PARTITION_DESKTOP template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, diff --git a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_x86-inl.inc b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_x86-inl.inc index bc320ff75b..847a547359 100644 --- a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_x86-inl.inc +++ b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_x86-inl.inc @@ -27,6 +27,7 @@ #include <cassert> #include <cstdint> +#include <limits> #include "absl/base/macros.h" #include "absl/base/port.h" @@ -132,9 +133,8 @@ static uintptr_t GetFP(const void *vuc) { const uintptr_t bp = 0; const uintptr_t sp = 0; #endif - // Sanity-check that the base pointer is valid. It should be as long as - // SHRINK_WRAP_FRAME_POINTER is not set, but it's possible that some code in - // the process is compiled with --copt=-fomit-frame-pointer or + // Sanity-check that the base pointer is valid. It's possible that some + // code in the process is compiled with --copt=-fomit-frame-pointer or // --copt=-momit-leaf-frame-pointer. // // TODO(bcmills): -momit-leaf-frame-pointer is currently the default @@ -159,7 +159,8 @@ static uintptr_t GetFP(const void *vuc) { template <bool STRICT_UNWINDING, bool WITH_CONTEXT> ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. -static void **NextStackFrame(void **old_fp, const void *uc) { +static void **NextStackFrame(void **old_fp, const void *uc, + size_t stack_low, size_t stack_high) { void **new_fp = (void **)*old_fp; #if defined(__linux__) && defined(__i386__) @@ -247,7 +248,7 @@ static void **NextStackFrame(void **old_fp, const void *uc) { // using an alternate signal stack. // // TODO(bcmills): The GetFP call should be completely unnecessary when - // SHRINK_WRAP_FRAME_POINTER is set (because we should be back in the thread's + // ENABLE_COMBINED_UNWINDER is set (because we should be back in the thread's // stack by this point), but it is empirically still needed (e.g. when the // stack includes a call to abort). unw_get_reg returns UNW_EBADREG for some // frames. Figure out why GetValidFrameAddr and/or libunwind isn't doing what @@ -258,6 +259,18 @@ static void **NextStackFrame(void **old_fp, const void *uc) { // at a greater address that the current one. if (new_fp_u <= old_fp_u) return nullptr; if (new_fp_u - old_fp_u > kMaxFrameBytes) return nullptr; + + if (stack_low < old_fp_u && old_fp_u <= stack_high) { + // Old BP was in the expected stack region... + if (!(stack_low < new_fp_u && new_fp_u <= stack_high)) { + // ... but new BP is outside of expected stack region. + // It is most likely bogus. + return nullptr; + } + } else { + // We may be here if we are executing in a co-routine with a + // separate stack. We can't do safety checks in this case. + } } else { if (new_fp == nullptr) return nullptr; // skip AddressIsReadable() below // In the non-strict mode, allow discontiguous stack frames. @@ -297,13 +310,17 @@ static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count, int n = 0; void **fp = reinterpret_cast<void **>(__builtin_frame_address(0)); + size_t stack_low = getpagesize(); // Assume that the first page is not stack. + size_t stack_high = std::numeric_limits<size_t>::max() - sizeof(void *); + while (fp && n < max_depth) { if (*(fp + 1) == reinterpret_cast<void *>(0)) { // In 64-bit code, we often see a frame that // points to itself and has a return address of 0. break; } - void **next_fp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(fp, ucp); + void **next_fp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>( + fp, ucp, stack_low, stack_high); if (skip_count > 0) { skip_count--; } else { @@ -326,7 +343,8 @@ static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count, const int kMaxUnwind = 1000; int j = 0; for (; fp != nullptr && j < kMaxUnwind; j++) { - fp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(fp, ucp); + fp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(fp, ucp, stack_low, + stack_high); } *min_dropped_frames = j; } diff --git a/third_party/abseil-cpp/absl/debugging/internal/symbolize.h b/third_party/abseil-cpp/absl/debugging/internal/symbolize.h index 5d0858b5c7..27d5e6521e 100644 --- a/third_party/abseil-cpp/absl/debugging/internal/symbolize.h +++ b/third_party/abseil-cpp/absl/debugging/internal/symbolize.h @@ -18,15 +18,18 @@ #ifndef ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_ #define ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_ +#ifdef __cplusplus + #include <cstddef> #include <cstdint> #include "absl/base/config.h" +#include "absl/strings/string_view.h" #ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE #error ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE cannot be directly set -#elif defined(__ELF__) && defined(__GLIBC__) && !defined(__native_client__) && \ - !defined(__asmjs__) && !defined(__wasm__) +#elif defined(__ELF__) && defined(__GLIBC__) && !defined(__native_client__) \ + && !defined(__asmjs__) && !defined(__wasm__) #define ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE 1 #include <elf.h> @@ -45,7 +48,7 @@ namespace debugging_internal { // // This is not async-signal-safe. bool ForEachSection(int fd, - const std::function<bool(const std::string& name, + const std::function<bool(absl::string_view name, const ElfW(Shdr) &)>& callback); // Gets the section header for the given name, if it exists. Returns true on @@ -59,6 +62,18 @@ ABSL_NAMESPACE_END #endif // ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE +#ifdef ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE +#error ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE cannot be directly set +#elif defined(__APPLE__) +#define ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE 1 +#endif + +#ifdef ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE +#error ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE cannot be directly set +#elif defined(__EMSCRIPTEN__) +#define ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE 1 +#endif + namespace absl { ABSL_NAMESPACE_BEGIN namespace debugging_internal { @@ -109,20 +124,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 1e8a78ac9c..977a9f6b3c 100644 --- a/third_party/abseil-cpp/absl/debugging/internal/vdso_support.cc +++ b/third_party/abseil-cpp/absl/debugging/internal/vdso_support.cc @@ -20,12 +20,25 @@ #ifdef ABSL_HAVE_VDSO_SUPPORT // defined in vdso_support.h +#if !defined(__has_include) +#define __has_include(header) 0 +#endif + #include <errno.h> #include <fcntl.h> +#if __has_include(<syscall.h>) +#include <syscall.h> +#elif __has_include(<sys/syscall.h>) #include <sys/syscall.h> +#endif #include <unistd.h> -#if __GLIBC_PREREQ(2, 16) // GLIBC-2.16 implements getauxval. +#if defined(__GLIBC__) && \ + (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 16)) +#define ABSL_HAVE_GETAUXVAL +#endif + +#ifdef ABSL_HAVE_GETAUXVAL #include <sys/auxv.h> #endif @@ -37,6 +50,11 @@ #define AT_SYSINFO_EHDR 33 // for crosstoolv10 #endif +#if defined(__FreeBSD__) +using Elf64_auxv_t = Elf64_Auxinfo; +using Elf32_auxv_t = Elf32_Auxinfo; +#endif + namespace absl { ABSL_NAMESPACE_BEGIN namespace debugging_internal { @@ -65,7 +83,7 @@ VDSOSupport::VDSOSupport() // the operation should be idempotent. const void *VDSOSupport::Init() { const auto kInvalidBase = debugging_internal::ElfMemImage::kInvalidBase; -#if __GLIBC_PREREQ(2, 16) +#ifdef ABSL_HAVE_GETAUXVAL if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) { errno = 0; const void *const sysinfo_ehdr = @@ -74,17 +92,8 @@ const void *VDSOSupport::Init() { vdso_base_.store(sysinfo_ehdr, std::memory_order_relaxed); } } -#endif // __GLIBC_PREREQ(2, 16) +#endif // ABSL_HAVE_GETAUXVAL 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 +184,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 |