diff options
Diffstat (limited to 'absl/debugging')
21 files changed, 283 insertions, 159 deletions
diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel index edbb3698..42124bfb 100644 --- a/absl/debugging/BUILD.bazel +++ b/absl/debugging/BUILD.bazel @@ -49,6 +49,7 @@ cc_library( ":debugging_internal", "//absl/base:config", "//absl/base:core_headers", + "//absl/base:dynamic_annotations", "//absl/base:raw_logging_internal", ], ) @@ -83,6 +84,10 @@ cc_library( linkopts = ABSL_DEFAULT_LINKOPTS + select({ "//absl:msvc_compiler": ["-DEFAULTLIB:dbghelp.lib"], "//absl:clang-cl_compiler": ["-DEFAULTLIB:dbghelp.lib"], + "//absl:mingw_compiler": [ + "-DEFAULTLIB:dbghelp.lib", + "-ldbghelp", + ], "//conditions:default": [], }), deps = [ @@ -117,7 +122,8 @@ cc_test( "//absl/base", "//absl/base:config", "//absl/base:core_headers", - "//absl/base:raw_logging_internal", + "//absl/log", + "//absl/log:check", "//absl/memory", "//absl/strings", "@com_google_googletest//:gtest", @@ -175,6 +181,7 @@ cc_test( ":stacktrace", ":symbolize", "//absl/base:raw_logging_internal", + "//absl/log:check", "//absl/strings", "@com_google_googletest//:gtest", ], @@ -228,7 +235,7 @@ cc_test( ":stack_consumption", "//absl/base:config", "//absl/base:core_headers", - "//absl/base:raw_logging_internal", + "//absl/log", "//absl/memory", "@com_google_googletest//:gtest_main", ], @@ -255,7 +262,7 @@ cc_test( deps = [ ":leak_check", "//absl/base:config", - "//absl/base:raw_logging_internal", + "//absl/log", "@com_google_googletest//:gtest_main", ], ) @@ -272,7 +279,7 @@ cc_binary( linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":leak_check", - "//absl/base:raw_logging_internal", + "//absl/log", "@com_google_googletest//:gtest_main", ], ) @@ -301,7 +308,7 @@ cc_test( deps = [ ":stack_consumption", "//absl/base:core_headers", - "//absl/base:raw_logging_internal", + "//absl/log", "@com_google_googletest//:gtest_main", ], ) diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt index 8f29cc07..65e2af88 100644 --- a/absl/debugging/CMakeLists.txt +++ b/absl/debugging/CMakeLists.txt @@ -41,6 +41,7 @@ absl_cc_library( absl::debugging_internal absl::config absl::core_headers + absl::dynamic_annotations absl::raw_logging_internal PUBLIC ) @@ -100,14 +101,15 @@ absl_cc_test( LINKOPTS $<$<BOOL:${MSVC}>:-DEBUG> DEPS - absl::stack_consumption - absl::symbolize absl::base + absl::check absl::config absl::core_headers + absl::log absl::memory - absl::raw_logging_internal + absl::stack_consumption absl::strings + absl::symbolize GTest::gmock ) @@ -156,6 +158,7 @@ absl_cc_test( COPTS ${ABSL_TEST_COPTS} DEPS + absl::check absl::failure_signal_handler absl::stacktrace absl::symbolize @@ -215,8 +218,8 @@ absl_cc_test( absl::stack_consumption absl::config absl::core_headers + absl::log absl::memory - absl::raw_logging_internal GTest::gmock_main ) @@ -247,6 +250,7 @@ absl_cc_test( DEPS absl::leak_check absl::base + absl::log GTest::gmock_main ) @@ -277,7 +281,7 @@ absl_cc_test( DEPS absl::stack_consumption absl::core_headers - absl::raw_logging_internal + absl::log GTest::gmock_main ) diff --git a/absl/debugging/failure_signal_handler.cc b/absl/debugging/failure_signal_handler.cc index ef8ab9e5..992c89c3 100644 --- a/absl/debugging/failure_signal_handler.cc +++ b/absl/debugging/failure_signal_handler.cc @@ -31,6 +31,13 @@ #ifdef ABSL_HAVE_MMAP #include <sys/mman.h> +#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) +#define MAP_ANONYMOUS MAP_ANON +#endif +#endif + +#ifdef __linux__ +#include <sys/prctl.h> #endif #include <algorithm> @@ -77,10 +84,10 @@ struct FailureSignalData { struct sigaction previous_action; // StructSigaction is used to silence -Wmissing-field-initializers. using StructSigaction = struct sigaction; - #define FSD_PREVIOUS_INIT FailureSignalData::StructSigaction() +#define FSD_PREVIOUS_INIT FailureSignalData::StructSigaction() #else void (*previous_handler)(int); - #define FSD_PREVIOUS_INIT SIG_DFL +#define FSD_PREVIOUS_INIT SIG_DFL #endif }; @@ -132,7 +139,7 @@ const char* FailureSignalToString(int signo) { #ifdef ABSL_HAVE_SIGALTSTACK static bool SetupAlternateStackOnce() { -#if defined(__wasm__) || defined (__asjms__) +#if defined(__wasm__) || defined(__asjms__) const size_t page_mask = getpagesize() - 1; #else const size_t page_mask = static_cast<size_t>(sysconf(_SC_PAGESIZE)) - 1; @@ -154,9 +161,6 @@ static bool SetupAlternateStackOnce() { #ifndef MAP_STACK #define MAP_STACK 0 #endif -#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) -#define MAP_ANONYMOUS MAP_ANON -#endif sigstk.ss_sp = mmap(nullptr, sigstk.ss_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); if (sigstk.ss_sp == MAP_FAILED) { @@ -172,6 +176,20 @@ static bool SetupAlternateStackOnce() { if (sigaltstack(&sigstk, nullptr) != 0) { ABSL_RAW_LOG(FATAL, "sigaltstack() failed with errno=%d", errno); } + +#ifdef __linux__ +#if defined(PR_SET_VMA) && defined(PR_SET_VMA_ANON_NAME) + // Make a best-effort attempt to name the allocated region in + // /proc/$PID/smaps. + // + // The call to prctl() may fail if the kernel was not configured with the + // CONFIG_ANON_VMA_NAME kernel option. This is OK since the call is + // primarily a debugging aid. + prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, sigstk.ss_sp, sigstk.ss_size, + "absl-signalstack"); +#endif +#endif // __linux__ + return true; } @@ -218,10 +236,6 @@ static void InstallOneFailureHandler(FailureSignalData* data, #endif -static void WriteToStderr(const char* data) { - absl::raw_log_internal::AsyncSignalSafeWriteToStderr(data, strlen(data)); -} - static void WriteSignalMessage(int signo, int cpu, void (*writerfn)(const char*)) { char buf[96]; @@ -234,7 +248,7 @@ static void WriteSignalMessage(int signo, int cpu, if (signal_string != nullptr && signal_string[0] != '\0') { snprintf(buf, sizeof(buf), "*** %s received at time=%ld%s ***\n", signal_string, - static_cast<long>(time(nullptr)), // NOLINT(runtime/int) + static_cast<long>(time(nullptr)), // NOLINT(runtime/int) on_cpu); } else { snprintf(buf, sizeof(buf), "*** Signal %d received at time=%ld%s ***\n", @@ -297,7 +311,8 @@ static void PortableSleepForSeconds(int seconds) { struct timespec sleep_time; sleep_time.tv_sec = seconds; sleep_time.tv_nsec = 0; - while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) {} + while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) { + } #endif } @@ -307,9 +322,7 @@ static void PortableSleepForSeconds(int seconds) { // set amount of time. If AbslFailureSignalHandler() hangs for more than // the alarm timeout, ImmediateAbortSignalHandler() will abort the // program. -static void ImmediateAbortSignalHandler(int) { - RaiseToDefaultHandler(SIGABRT); -} +static void ImmediateAbortSignalHandler(int) { RaiseToDefaultHandler(SIGABRT); } #endif // absl::base_internal::GetTID() returns pid_t on most platforms, but @@ -362,7 +375,10 @@ static void AbslFailureSignalHandler(int signo, siginfo_t*, void* ucontext) { #endif // First write to stderr. - WriteFailureInfo(signo, ucontext, my_cpu, WriteToStderr); + WriteFailureInfo( + signo, ucontext, my_cpu, +[](const char* data) { + absl::raw_log_internal::AsyncSignalSafeWriteError(data, strlen(data)); + }); // Riskier code (because it is less likely to be async-signal-safe) // goes after this point. diff --git a/absl/debugging/failure_signal_handler.h b/absl/debugging/failure_signal_handler.h index 500115c0..5e034785 100644 --- a/absl/debugging/failure_signal_handler.h +++ b/absl/debugging/failure_signal_handler.h @@ -62,7 +62,7 @@ struct FailureSignalHandlerOptions { // If true, try to run signal handlers on an alternate stack (if supported on // the given platform). An alternate stack is useful for program crashes due // to a stack overflow; by running on a alternate stack, the signal handler - // may run even when normal stack space has been exausted. The downside of + // may run even when normal stack space has been exhausted. The downside of // using an alternate stack is that extra memory for the alternate stack needs // to be pre-allocated. bool use_alternate_stack = true; diff --git a/absl/debugging/failure_signal_handler_test.cc b/absl/debugging/failure_signal_handler_test.cc index 6a62428b..72816a3e 100644 --- a/absl/debugging/failure_signal_handler_test.cc +++ b/absl/debugging/failure_signal_handler_test.cc @@ -22,11 +22,12 @@ #include <cstring> #include <fstream> -#include "gtest/gtest.h" #include "gmock/gmock.h" +#include "gtest/gtest.h" #include "absl/base/internal/raw_logging.h" #include "absl/debugging/stacktrace.h" #include "absl/debugging/symbolize.h" +#include "absl/log/check.h" #include "absl/strings/match.h" #include "absl/strings/str_cat.h" @@ -87,7 +88,7 @@ std::string GetTmpDir() { // This function runs in a fork()ed process on most systems. void InstallHandlerWithWriteToFileAndRaise(const char* file, int signo) { error_file = fopen(file, "w"); - ABSL_RAW_CHECK(error_file != nullptr, "Failed create error_file"); + CHECK_NE(error_file, nullptr) << "Failed create error_file"; absl::FailureSignalHandlerOptions options; options.writerfn = WriteToErrorFile; absl::InstallFailureSignalHandler(options); diff --git a/absl/debugging/internal/demangle_test.cc b/absl/debugging/internal/demangle_test.cc index 8463a2b7..faec72b5 100644 --- a/absl/debugging/internal/demangle_test.cc +++ b/absl/debugging/internal/demangle_test.cc @@ -19,8 +19,8 @@ #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/log/log.h" #include "absl/memory/memory.h" namespace absl { @@ -38,7 +38,7 @@ static const char *DemangleIt(const char * const mangled) { } } -// Test corner cases of bounary conditions. +// Test corner cases of boundary conditions. TEST(Demangle, CornerCases) { char tmp[10]; EXPECT_TRUE(Demangle("_Z6foobarv", tmp, sizeof(tmp))); @@ -151,7 +151,7 @@ static const char *DemangleStackConsumption(const char *mangled, int *stack_consumed) { g_mangled = mangled; *stack_consumed = GetSignalHandlerStackConsumption(DemangleSignalHandler); - ABSL_RAW_LOG(INFO, "Stack consumption of Demangle: %d", *stack_consumed); + LOG(INFO) << "Stack consumption of Demangle: " << *stack_consumed; return g_demangle_result; } diff --git a/absl/debugging/internal/elf_mem_image.h b/absl/debugging/internal/elf_mem_image.h index 113071a9..e7fe6ab0 100644 --- a/absl/debugging/internal/elf_mem_image.h +++ b/absl/debugging/internal/elf_mem_image.h @@ -33,7 +33,8 @@ #if defined(__ELF__) && !defined(__OpenBSD__) && !defined(__QNX__) && \ !defined(__native_client__) && !defined(__asmjs__) && \ - !defined(__wasm__) && !defined(__HAIKU__) + !defined(__wasm__) && !defined(__HAIKU__) && !defined(__sun) && \ + !defined(__VXWORKS__) && !defined(__hexagon__) #define ABSL_HAVE_ELF_MEM_IMAGE 1 #endif diff --git a/absl/debugging/internal/examine_stack.cc b/absl/debugging/internal/examine_stack.cc index 57863228..3dd6ba1a 100644 --- a/absl/debugging/internal/examine_stack.cc +++ b/absl/debugging/internal/examine_stack.cc @@ -24,6 +24,9 @@ #ifdef ABSL_HAVE_MMAP #include <sys/mman.h> +#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) +#define MAP_ANONYMOUS MAP_ANON +#endif #endif #if defined(__linux__) || defined(__APPLE__) diff --git a/absl/debugging/internal/stack_consumption.cc b/absl/debugging/internal/stack_consumption.cc index 51348649..3f40beac 100644 --- a/absl/debugging/internal/stack_consumption.cc +++ b/absl/debugging/internal/stack_consumption.cc @@ -18,14 +18,17 @@ #ifdef ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION #include <signal.h> +#include <string.h> #include <sys/mman.h> #include <unistd.h> -#include <string.h> - #include "absl/base/attributes.h" #include "absl/base/internal/raw_logging.h" +#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) +#define MAP_ANONYMOUS MAP_ANON +#endif + namespace absl { ABSL_NAMESPACE_BEGIN namespace debugging_internal { @@ -162,7 +165,7 @@ int GetSignalHandlerStackConsumption(void (*signal_handler)(int)) { // versions of musl have a bug that rejects ss_size==0. Work around this by // setting ss_size to MINSIGSTKSZ, which should be ignored by the kernel // when SS_DISABLE is set. - old_sigstk.ss_size = MINSIGSTKSZ; + old_sigstk.ss_size = static_cast<size_t>(MINSIGSTKSZ); } ABSL_RAW_CHECK(sigaltstack(&old_sigstk, nullptr) == 0, "sigaltstack() failed"); diff --git a/absl/debugging/internal/stack_consumption_test.cc b/absl/debugging/internal/stack_consumption_test.cc index 80445bf4..0255ac8f 100644 --- a/absl/debugging/internal/stack_consumption_test.cc +++ b/absl/debugging/internal/stack_consumption_test.cc @@ -20,7 +20,7 @@ #include <string.h> #include "gtest/gtest.h" -#include "absl/base/internal/raw_logging.h" +#include "absl/log/log.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -33,7 +33,7 @@ static void SimpleSignalHandler(int signo) { // Never true, but prevents compiler from optimizing buf out. if (signo == 0) { - ABSL_RAW_LOG(INFO, "%p", static_cast<void*>(buf)); + LOG(INFO) << static_cast<void*>(buf); } } diff --git a/absl/debugging/internal/stacktrace_aarch64-inl.inc b/absl/debugging/internal/stacktrace_aarch64-inl.inc index 71cdaf09..3f087162 100644 --- a/absl/debugging/internal/stacktrace_aarch64-inl.inc +++ b/absl/debugging/internal/stacktrace_aarch64-inl.inc @@ -13,6 +13,7 @@ #include <cassert> #include <cstdint> #include <iostream> +#include <limits> #include "absl/base/attributes.h" #include "absl/debugging/internal/address_is_readable.h" @@ -20,6 +21,10 @@ #include "absl/debugging/stacktrace.h" static const size_t kUnknownFrameSize = 0; +// Stack end to use when we don't know the actual stack end +// (effectively just the end of address space). +constexpr uintptr_t kUnknownStackEnd = + std::numeric_limits<size_t>::max() - sizeof(void *); #if defined(__linux__) // Returns the address of the VDSO __kernel_rt_sigreturn function, if present. @@ -79,8 +84,9 @@ static inline size_t ComputeStackFrameSize(const T* low, // "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) { +ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. +static void **NextStackFrame(void **old_frame_pointer, const void *uc, + size_t stack_low, size_t stack_high) { void **new_frame_pointer = reinterpret_cast<void**>(*old_frame_pointer); bool check_frame_size = true; @@ -94,16 +100,21 @@ static void **NextStackFrame(void **old_frame_pointer, const void *uc) { void **const pre_signal_frame_pointer = reinterpret_cast<void **>(ucv->uc_mcontext.regs[29]); + // The most recent signal always needs special handling to find the frame + // pointer, but a nested signal does not. If pre_signal_frame_pointer is + // earlier in the stack than the old_frame_pointer, then use it. If it is + // later, then we have already unwound through it and it needs no special + // handling. + if (pre_signal_frame_pointer >= old_frame_pointer) { + new_frame_pointer = pre_signal_frame_pointer; + } // Check that alleged frame pointer is actually readable. This is to // prevent "double fault" in case we hit the first fault due to e.g. // stack corruption. if (!absl::debugging_internal::AddressIsReadable( - pre_signal_frame_pointer)) + new_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 a // an alternate stack for signals. check_frame_size = false; @@ -121,8 +132,26 @@ static void **NextStackFrame(void **old_frame_pointer, const void *uc) { const size_t max_size = STRICT_UNWINDING ? 100000 : 1000000; const size_t frame_size = ComputeStackFrameSize(old_frame_pointer, new_frame_pointer); - if (frame_size == kUnknownFrameSize || frame_size > max_size) - return nullptr; + if (frame_size == kUnknownFrameSize) + return nullptr; + // A very large frame may mean corrupt memory or an erroneous frame + // pointer. But also maybe just a plain-old large frame. Assume that if the + // frame is within the known stack, then it is valid. + if (frame_size > max_size) { + if (stack_high < kUnknownStackEnd && + static_cast<size_t>(getpagesize()) < stack_low) { + const uintptr_t new_fp_u = + reinterpret_cast<uintptr_t>(new_frame_pointer); + // Stack bounds are known. + if (!(stack_low < new_fp_u && new_fp_u <= stack_high)) { + // new_frame_pointer is not within the known stack. + return nullptr; + } + } else { + // Stack bounds are unknown, prefer truncated stack to possible crash. + return nullptr; + } + } } return new_frame_pointer; @@ -138,42 +167,49 @@ static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, #else # error reading stack point not yet supported on this platform. #endif - skip_count++; // Skip the frame for this function. int n = 0; + // Assume that the first page is not stack. + size_t stack_low = static_cast<size_t>(getpagesize()); + size_t stack_high = kUnknownStackEnd; + // The frame pointer points to low address of a frame. The first 64-bit // word of a frame points to the next frame up the call chain, which normally // is just after the high address of the current frame. The second word of - // a frame contains return adress of to the caller. To find a pc value + // a frame contains return address of to the caller. To find a pc value // associated with the current frame, we need to go down a level in the call // chain. So we remember return the 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; + // The nth frame size is the difference between the nth frame pointer and the + // the frame pointer below it in the call chain. There is no frame below the + // leaf frame, but this function is the leaf anyway, and we skip it. + void** prev_frame_pointer = nullptr; - while (frame_pointer && n < max_depth) { - // The absl::GetStackFrames routine is 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); - + while (frame_pointer && n < max_depth) { if (skip_count > 0) { skip_count--; } else { result[n] = prev_return_address; if (IS_STACK_FRAMES) { sizes[n] = static_cast<int>( - ComputeStackFrameSize(frame_pointer, next_frame_pointer)); + ComputeStackFrameSize(prev_frame_pointer, frame_pointer)); } n++; } prev_return_address = frame_pointer[1]; - frame_pointer = next_frame_pointer; + prev_frame_pointer = frame_pointer; + // The absl::GetStackFrames routine is 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). + frame_pointer = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>( + frame_pointer, ucp, stack_low, stack_high); } + 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. @@ -185,8 +221,8 @@ static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, } else { num_dropped_frames++; } - frame_pointer = - NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(frame_pointer, ucp); + frame_pointer = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>( + frame_pointer, ucp, stack_low, stack_high); } *min_dropped_frames = num_dropped_frames; } diff --git a/absl/debugging/internal/stacktrace_powerpc-inl.inc b/absl/debugging/internal/stacktrace_powerpc-inl.inc index 085cef67..a49ed2f7 100644 --- a/absl/debugging/internal/stacktrace_powerpc-inl.inc +++ b/absl/debugging/internal/stacktrace_powerpc-inl.inc @@ -57,7 +57,7 @@ static inline void *StacktracePowerPCGetLR(void **sp) { // This check is in case the compiler doesn't define _CALL_SYSV. return *(sp+1); #else -#error Need to specify the PPC ABI for your archiecture. +#error Need to specify the PPC ABI for your architecture. #endif } diff --git a/absl/debugging/internal/stacktrace_x86-inl.inc b/absl/debugging/internal/stacktrace_x86-inl.inc index 7b26464e..1975ba74 100644 --- a/absl/debugging/internal/stacktrace_x86-inl.inc +++ b/absl/debugging/internal/stacktrace_x86-inl.inc @@ -40,7 +40,7 @@ using absl::debugging_internal::AddressIsReadable; #if defined(__linux__) && defined(__i386__) // Count "push %reg" instructions in VDSO __kernel_vsyscall(), -// preceeding "syscall" or "sysenter". +// preceding "syscall" or "sysenter". // If __kernel_vsyscall uses frame pointer, answer 0. // // kMaxBytes tells how many instruction bytes of __kernel_vsyscall diff --git a/absl/debugging/internal/symbolize.h b/absl/debugging/internal/symbolize.h index 27d5e652..5593fde6 100644 --- a/absl/debugging/internal/symbolize.h +++ b/absl/debugging/internal/symbolize.h @@ -115,7 +115,7 @@ bool RemoveSymbolDecorator(int ticket); // Remove all installed decorators. Returns true if successful, false if // symbolization is currently in progress. -bool RemoveAllSymbolDecorators(void); +bool RemoveAllSymbolDecorators(); // Registers an address range to a file mapping. // diff --git a/absl/debugging/leak_check.cc b/absl/debugging/leak_check.cc index 195e82bf..fdb8798b 100644 --- a/absl/debugging/leak_check.cc +++ b/absl/debugging/leak_check.cc @@ -65,8 +65,8 @@ bool LeakCheckerIsActive() { return false; } void DoIgnoreLeak(const void*) { } void RegisterLivePointers(const void*, size_t) { } void UnRegisterLivePointers(const void*, size_t) { } -LeakCheckDisabler::LeakCheckDisabler() { } -LeakCheckDisabler::~LeakCheckDisabler() { } +LeakCheckDisabler::LeakCheckDisabler() = default; +LeakCheckDisabler::~LeakCheckDisabler() = default; ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/debugging/leak_check_fail_test.cc b/absl/debugging/leak_check_fail_test.cc index c49b81a9..46e9fb62 100644 --- a/absl/debugging/leak_check_fail_test.cc +++ b/absl/debugging/leak_check_fail_test.cc @@ -13,9 +13,10 @@ // limitations under the License. #include <memory> + #include "gtest/gtest.h" -#include "absl/base/internal/raw_logging.h" #include "absl/debugging/leak_check.h" +#include "absl/log/log.h" namespace { @@ -25,7 +26,7 @@ TEST(LeakCheckTest, LeakMemory) { // failed exit code. char* foo = strdup("lsan should complain about this leaked string"); - ABSL_RAW_LOG(INFO, "Should detect leaked string %s", foo); + LOG(INFO) << "Should detect leaked string " << foo; } TEST(LeakCheckTest, LeakMemoryAfterDisablerScope) { @@ -34,8 +35,7 @@ TEST(LeakCheckTest, LeakMemoryAfterDisablerScope) { // failed exit code. { absl::LeakCheckDisabler disabler; } char* foo = strdup("lsan should also complain about this leaked string"); - ABSL_RAW_LOG(INFO, "Re-enabled leak detection.Should detect leaked string %s", - foo); + LOG(INFO) << "Re-enabled leak detection.Should detect leaked string " << foo; } } // namespace diff --git a/absl/debugging/leak_check_test.cc b/absl/debugging/leak_check_test.cc index 6a42e31b..6f0135ed 100644 --- a/absl/debugging/leak_check_test.cc +++ b/absl/debugging/leak_check_test.cc @@ -16,8 +16,8 @@ #include "gtest/gtest.h" #include "absl/base/config.h" -#include "absl/base/internal/raw_logging.h" #include "absl/debugging/leak_check.h" +#include "absl/log/log.h" namespace { @@ -26,7 +26,7 @@ TEST(LeakCheckTest, IgnoreLeakSuppressesLeakedMemoryErrors) { GTEST_SKIP() << "LeakChecker is not active"; } auto foo = absl::IgnoreLeak(new std::string("some ignored leaked string")); - ABSL_RAW_LOG(INFO, "Ignoring leaked string %s", foo->c_str()); + LOG(INFO) << "Ignoring leaked string " << foo; } TEST(LeakCheckTest, LeakCheckDisablerIgnoresLeak) { @@ -35,7 +35,7 @@ TEST(LeakCheckTest, LeakCheckDisablerIgnoresLeak) { } absl::LeakCheckDisabler disabler; auto foo = new std::string("some string leaked while checks are disabled"); - ABSL_RAW_LOG(INFO, "Ignoring leaked string %s", foo->c_str()); + LOG(INFO) << "Ignoring leaked string " << foo; } } // namespace diff --git a/absl/debugging/stacktrace_test.cc b/absl/debugging/stacktrace_test.cc index 78ce7ad0..31f7723c 100644 --- a/absl/debugging/stacktrace_test.cc +++ b/absl/debugging/stacktrace_test.cc @@ -20,8 +20,8 @@ namespace { -// This test is currently only known to pass on linux/x86_64. -#if defined(__linux__) && defined(__x86_64__) +// This test is currently only known to pass on Linux x86_64/aarch64. +#if defined(__linux__) && (defined(__x86_64__) || defined(__aarch64__)) ABSL_ATTRIBUTE_NOINLINE void Unwind(void* p) { ABSL_ATTRIBUTE_UNUSED static void* volatile sink = p; constexpr int kSize = 16; diff --git a/absl/debugging/symbolize_elf.inc b/absl/debugging/symbolize_elf.inc index ffb4eecf..30638cb2 100644 --- a/absl/debugging/symbolize_elf.inc +++ b/absl/debugging/symbolize_elf.inc @@ -532,6 +532,11 @@ bool ForEachSection(int fd, return false; } + // Technically it can be larger, but in practice this never happens. + if (elf_header.e_shentsize != sizeof(ElfW(Shdr))) { + return false; + } + ElfW(Shdr) shstrtab; off_t shstrtab_offset = static_cast<off_t>(elf_header.e_shoff) + elf_header.e_shentsize * elf_header.e_shstrndx; @@ -584,6 +589,11 @@ bool GetSectionHeaderByName(int fd, const char *name, size_t name_len, return false; } + // Technically it can be larger, but in practice this never happens. + if (elf_header.e_shentsize != sizeof(ElfW(Shdr))) { + return false; + } + ElfW(Shdr) shstrtab; off_t shstrtab_offset = static_cast<off_t>(elf_header.e_shoff) + elf_header.e_shentsize * elf_header.e_shstrndx; @@ -648,8 +658,10 @@ static bool ShouldPickFirstSymbol(const ElfW(Sym) & symbol1, } // Return true if an address is inside a section. -static bool InSection(const void *address, const ElfW(Shdr) * section) { - const char *start = reinterpret_cast<const char *>(section->sh_addr); +static bool InSection(const void *address, ptrdiff_t relocation, + const ElfW(Shdr) * section) { + const char *start = reinterpret_cast<const char *>( + section->sh_addr + static_cast<ElfW(Addr)>(relocation)); size_t size = static_cast<size_t>(section->sh_size); return start <= address && address < (start + size); } @@ -689,8 +701,8 @@ static ABSL_ATTRIBUTE_NOINLINE FindSymbolResult FindSymbol( // starting address. However, we do not always want to use the real // starting address because we sometimes want to symbolize a function // pointer into the .opd section, e.g. FindSymbol(&foo,...). - const bool pc_in_opd = - kPlatformUsesOPDSections && opd != nullptr && InSection(pc, opd); + const bool pc_in_opd = kPlatformUsesOPDSections && opd != nullptr && + InSection(pc, relocation, opd); const bool deref_function_descriptor_pointer = kPlatformUsesOPDSections && opd != nullptr && !pc_in_opd; @@ -730,7 +742,7 @@ static ABSL_ATTRIBUTE_NOINLINE FindSymbolResult FindSymbol( #endif if (deref_function_descriptor_pointer && - InSection(original_start_address, opd)) { + InSection(original_start_address, /*relocation=*/0, opd)) { // The opd section is mapped into memory. Just dereference // start_address to get the first double word, which points to the // function entry. @@ -1326,7 +1338,7 @@ static bool MaybeInitializeObjFile(ObjFile *obj) { const int phnum = obj->elf_header.e_phnum; const int phentsize = obj->elf_header.e_phentsize; auto phoff = static_cast<off_t>(obj->elf_header.e_phoff); - size_t num_executable_load_segments = 0; + size_t num_interesting_load_segments = 0; for (int j = 0; j < phnum; j++) { ElfW(Phdr) phdr; if (!ReadFromOffsetExact(obj->fd, &phdr, sizeof(phdr), phoff)) { @@ -1335,23 +1347,35 @@ static bool MaybeInitializeObjFile(ObjFile *obj) { 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. + +#if defined(__powerpc__) && !(_CALL_ELF > 1) + // On the PowerPC ELF v1 ABI, function pointers actually point to function + // descriptors. These descriptors are stored in an .opd section, which is + // mapped read-only. We thus need to look at all readable segments, not + // just the executable ones. + constexpr int interesting = PF_R; +#else + constexpr int interesting = PF_X | PF_R; +#endif + + if (phdr.p_type != PT_LOAD + || (phdr.p_flags & interesting) != interesting) { + // Not a LOAD segment, not executable code, and not a function + // descriptor. continue; } - if (num_executable_load_segments < obj->phdr.size()) { - memcpy(&obj->phdr[num_executable_load_segments++], &phdr, sizeof(phdr)); + if (num_interesting_load_segments < obj->phdr.size()) { + memcpy(&obj->phdr[num_interesting_load_segments++], &phdr, sizeof(phdr)); } else { ABSL_RAW_LOG( - WARNING, "%s: too many executable LOAD segments: %zu >= %zu", - obj->filename, num_executable_load_segments, obj->phdr.size()); + WARNING, "%s: too many interesting LOAD segments: %zu >= %zu", + obj->filename, num_interesting_load_segments, obj->phdr.size()); 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); + if (num_interesting_load_segments == 0) { + // This object has no interesting LOAD segments. That's unexpected. + ABSL_RAW_LOG(WARNING, "%s: no interesting LOAD segments", obj->filename); return false; } } @@ -1379,8 +1403,8 @@ const char *Symbolizer::GetUncachedSymbol(const void *pc) { // X in the file will have a start address of [true relocation]+X. relocation = static_cast<ptrdiff_t>(start_addr - obj->offset); - // Note: some binaries have multiple "rx" LOAD segments. We must - // find the right one. + // Note: some binaries have multiple LOAD segments that can contain + // function pointers. 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]; @@ -1390,7 +1414,7 @@ const char *Symbolizer::GetUncachedSymbol(const void *pc) { ABSL_RAW_CHECK(p.p_type == PT_NULL, "unexpected p_type"); break; } - if (pc < reinterpret_cast<void *>(start_addr + p.p_memsz)) { + if (pc < reinterpret_cast<void *>(start_addr + p.p_vaddr + p.p_memsz)) { phdr = &p; break; } diff --git a/absl/debugging/symbolize_emscripten.inc b/absl/debugging/symbolize_emscripten.inc index c226c456..a0f344dd 100644 --- a/absl/debugging/symbolize_emscripten.inc +++ b/absl/debugging/symbolize_emscripten.inc @@ -50,6 +50,9 @@ bool Symbolize(const void* pc, char* out, int out_size) { if (!HaveOffsetConverter()) { return false; } + if (pc == nullptr || out_size <= 0) { + return false; + } const char* func_name = emscripten_pc_get_function(pc); if (func_name == nullptr) { return false; diff --git a/absl/debugging/symbolize_test.cc b/absl/debugging/symbolize_test.cc index 3165c6ed..d0feab2f 100644 --- a/absl/debugging/symbolize_test.cc +++ b/absl/debugging/symbolize_test.cc @@ -14,6 +14,10 @@ #include "absl/debugging/symbolize.h" +#ifdef __EMSCRIPTEN__ +#include <emscripten.h> +#endif + #ifndef _WIN32 #include <fcntl.h> #include <sys/mman.h> @@ -29,12 +33,17 @@ #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" #include "absl/debugging/internal/stack_consumption.h" +#include "absl/log/check.h" +#include "absl/log/log.h" #include "absl/memory/memory.h" #include "absl/strings/string_view.h" +#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) +#define MAP_ANONYMOUS MAP_ANON +#endif + using testing::Contains; #ifdef _WIN32 @@ -81,21 +90,13 @@ int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.unlikely) unlikely_func() { return 0; } -int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.hot) hot_func() { - return 0; -} +int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.hot) hot_func() { return 0; } -int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.startup) startup_func() { - return 0; -} +int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.startup) startup_func() { return 0; } -int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.exit) exit_func() { - return 0; -} +int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.exit) exit_func() { return 0; } -int /*ABSL_ATTRIBUTE_SECTION_VARIABLE(.text)*/ regular_func() { - return 0; -} +int /*ABSL_ATTRIBUTE_SECTION_VARIABLE(.text)*/ regular_func() { return 0; } // Thread-local data may confuse the symbolizer, ensure that it does not. // Variable sizes and order are important. @@ -106,6 +107,8 @@ static ABSL_PER_THREAD_TLS_KEYWORD char #endif #if !defined(__EMSCRIPTEN__) +static void *GetPCFromFnPtr(void *ptr) { return ptr; } + // Used below to hopefully inhibit some compiler/linker optimizations // that may remove kHpageTextPadding, kPadding0, and kPadding1 from // the binary. @@ -114,7 +117,14 @@ static volatile bool volatile_bool = false; // Force the binary to be large enough that a THP .text remap will succeed. static constexpr size_t kHpageSize = 1 << 21; const char kHpageTextPadding[kHpageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE( - .text) = ""; + .text) = ""; + +#else +static void *GetPCFromFnPtr(void *ptr) { + return EM_ASM_PTR( + { return wasmOffsetConverter.convert(wasmTable.get($0).name, 0); }, ptr); +} + #endif // !defined(__EMSCRIPTEN__) static char try_symbolize_buffer[4096]; @@ -124,15 +134,17 @@ static char try_symbolize_buffer[4096]; // absl::Symbolize() returns false, otherwise returns try_symbolize_buffer with // the result of absl::Symbolize(). static const char *TrySymbolizeWithLimit(void *pc, int limit) { - ABSL_RAW_CHECK(limit <= sizeof(try_symbolize_buffer), - "try_symbolize_buffer is too small"); + CHECK_LE(limit, sizeof(try_symbolize_buffer)) + << "try_symbolize_buffer is too small"; // Use the heap to facilitate heap and buffer sanitizer tools. auto heap_buffer = absl::make_unique<char[]>(sizeof(try_symbolize_buffer)); bool found = absl::Symbolize(pc, heap_buffer.get(), limit); if (found) { - ABSL_RAW_CHECK(strnlen(heap_buffer.get(), limit) < limit, - "absl::Symbolize() did not properly terminate the string"); + CHECK_LT(static_cast<int>( + strnlen(heap_buffer.get(), static_cast<size_t>(limit))), + limit) + << "absl::Symbolize() did not properly terminate the string"; strncpy(try_symbolize_buffer, heap_buffer.get(), sizeof(try_symbolize_buffer) - 1); try_symbolize_buffer[sizeof(try_symbolize_buffer) - 1] = '\0'; @@ -155,21 +167,20 @@ void ABSL_ATTRIBUTE_NOINLINE TestWithReturnAddress() { #if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE) void *return_address = __builtin_return_address(0); const char *symbol = TrySymbolize(return_address); - ABSL_RAW_CHECK(symbol != nullptr, "TestWithReturnAddress failed"); - ABSL_RAW_CHECK(strcmp(symbol, "main") == 0, "TestWithReturnAddress failed"); + CHECK_NE(symbol, nullptr) << "TestWithReturnAddress failed"; + CHECK_STREQ(symbol, "main") << "TestWithReturnAddress failed"; std::cout << "TestWithReturnAddress passed" << std::endl; #endif } -#ifndef ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE - TEST(Symbolize, Cached) { // Compilers should give us pointers to them. - EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func))); - + EXPECT_STREQ("nonstatic_func", + TrySymbolize(GetPCFromFnPtr((void *)(&nonstatic_func)))); // The name of an internal linkage symbol is not specified; allow either a // mangled or an unmangled name here. - const char *static_func_symbol = TrySymbolize((void *)(&static_func)); + const char *static_func_symbol = + TrySymbolize(GetPCFromFnPtr((void *)(&static_func))); EXPECT_TRUE(strcmp("static_func", static_func_symbol) == 0 || strcmp("static_func()", static_func_symbol) == 0); @@ -179,33 +190,50 @@ TEST(Symbolize, Cached) { TEST(Symbolize, Truncation) { constexpr char kNonStaticFunc[] = "nonstatic_func"; EXPECT_STREQ("nonstatic_func", - TrySymbolizeWithLimit((void *)(&nonstatic_func), + TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)), strlen(kNonStaticFunc) + 1)); EXPECT_STREQ("nonstatic_...", - TrySymbolizeWithLimit((void *)(&nonstatic_func), + TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)), strlen(kNonStaticFunc) + 0)); EXPECT_STREQ("nonstatic...", - TrySymbolizeWithLimit((void *)(&nonstatic_func), + TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)), strlen(kNonStaticFunc) - 1)); - EXPECT_STREQ("n...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 5)); - EXPECT_STREQ("...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 4)); - EXPECT_STREQ("..", TrySymbolizeWithLimit((void *)(&nonstatic_func), 3)); - EXPECT_STREQ(".", TrySymbolizeWithLimit((void *)(&nonstatic_func), 2)); - EXPECT_STREQ("", TrySymbolizeWithLimit((void *)(&nonstatic_func), 1)); - EXPECT_EQ(nullptr, TrySymbolizeWithLimit((void *)(&nonstatic_func), 0)); + EXPECT_STREQ("n...", TrySymbolizeWithLimit( + GetPCFromFnPtr((void *)(&nonstatic_func)), 5)); + EXPECT_STREQ("...", TrySymbolizeWithLimit( + GetPCFromFnPtr((void *)(&nonstatic_func)), 4)); + EXPECT_STREQ("..", TrySymbolizeWithLimit( + GetPCFromFnPtr((void *)(&nonstatic_func)), 3)); + EXPECT_STREQ( + ".", TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)), 2)); + EXPECT_STREQ( + "", TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)), 1)); + EXPECT_EQ(nullptr, TrySymbolizeWithLimit( + GetPCFromFnPtr((void *)(&nonstatic_func)), 0)); } TEST(Symbolize, SymbolizeWithDemangling) { Foo::func(100); - EXPECT_STREQ("Foo::func()", TrySymbolize((void *)(&Foo::func))); +#ifdef __EMSCRIPTEN__ + // Emscripten's online symbolizer is more precise with arguments. + EXPECT_STREQ("Foo::func(int)", + TrySymbolize(GetPCFromFnPtr((void *)(&Foo::func)))); +#else + EXPECT_STREQ("Foo::func()", + TrySymbolize(GetPCFromFnPtr((void *)(&Foo::func)))); +#endif } TEST(Symbolize, SymbolizeSplitTextSections) { - EXPECT_STREQ("unlikely_func()", TrySymbolize((void *)(&unlikely_func))); - EXPECT_STREQ("hot_func()", TrySymbolize((void *)(&hot_func))); - EXPECT_STREQ("startup_func()", TrySymbolize((void *)(&startup_func))); - EXPECT_STREQ("exit_func()", TrySymbolize((void *)(&exit_func))); - EXPECT_STREQ("regular_func()", TrySymbolize((void *)(®ular_func))); + EXPECT_STREQ("unlikely_func()", + TrySymbolize(GetPCFromFnPtr((void *)(&unlikely_func)))); + EXPECT_STREQ("hot_func()", TrySymbolize(GetPCFromFnPtr((void *)(&hot_func)))); + EXPECT_STREQ("startup_func()", + TrySymbolize(GetPCFromFnPtr((void *)(&startup_func)))); + EXPECT_STREQ("exit_func()", + TrySymbolize(GetPCFromFnPtr((void *)(&exit_func)))); + EXPECT_STREQ("regular_func()", + TrySymbolize(GetPCFromFnPtr((void *)(®ular_func)))); } // Tests that verify that Symbolize stack footprint is within some limit. @@ -275,15 +303,14 @@ TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) { #endif // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION -#ifndef ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE +#if !defined(ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE) && \ + !defined(ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE) // Use a 64K page size for PPC. const size_t kPageSize = 64 << 10; // We place a read-only symbols into the .text section and verify that we can // symbolize them and other symbols after remapping them. -const char kPadding0[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) = - ""; -const char kPadding1[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) = - ""; +const char kPadding0[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) = ""; +const char kPadding1[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) = ""; static int FilterElfHeader(struct dl_phdr_info *info, size_t size, void *data) { for (int i = 0; i < info->dlpi_phnum; i++) { @@ -314,8 +341,8 @@ static int FilterElfHeader(struct dl_phdr_info *info, size_t size, void *data) { TEST(Symbolize, SymbolizeWithMultipleMaps) { // Force kPadding0 and kPadding1 to be linked in. if (volatile_bool) { - ABSL_RAW_LOG(INFO, "%s", kPadding0); - ABSL_RAW_LOG(INFO, "%s", kPadding1); + LOG(INFO) << kPadding0; + LOG(INFO) << kPadding1; } // Verify we can symbolize everything. @@ -433,17 +460,17 @@ TEST(Symbolize, ForEachSection) { close(fd); } -#endif // !ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE -#endif // !ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE +#endif // !ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE && + // !ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE // x86 specific tests. Uses some inline assembler. extern "C" { inline void *ABSL_ATTRIBUTE_ALWAYS_INLINE inline_func() { void *pc = nullptr; #if defined(__i386__) - __asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [ PC ] "=r"(pc)); + __asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [PC] "=r"(pc)); #elif defined(__x86_64__) - __asm__ __volatile__("leaq 0(%%rip),%[PC];\n" : [ PC ] "=r"(pc)); + __asm__ __volatile__("leaq 0(%%rip),%[PC];\n" : [PC] "=r"(pc)); #endif return pc; } @@ -451,9 +478,9 @@ inline void *ABSL_ATTRIBUTE_ALWAYS_INLINE inline_func() { void *ABSL_ATTRIBUTE_NOINLINE non_inline_func() { void *pc = nullptr; #if defined(__i386__) - __asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [ PC ] "=r"(pc)); + __asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [PC] "=r"(pc)); #elif defined(__x86_64__) - __asm__ __volatile__("leaq 0(%%rip),%[PC];\n" : [ PC ] "=r"(pc)); + __asm__ __volatile__("leaq 0(%%rip),%[PC];\n" : [PC] "=r"(pc)); #endif return pc; } @@ -463,9 +490,9 @@ void ABSL_ATTRIBUTE_NOINLINE TestWithPCInsideNonInlineFunction() { (defined(__i386__) || defined(__x86_64__)) void *pc = non_inline_func(); const char *symbol = TrySymbolize(pc); - ABSL_RAW_CHECK(symbol != nullptr, "TestWithPCInsideNonInlineFunction failed"); - ABSL_RAW_CHECK(strcmp(symbol, "non_inline_func") == 0, - "TestWithPCInsideNonInlineFunction failed"); + CHECK_NE(symbol, nullptr) << "TestWithPCInsideNonInlineFunction failed"; + CHECK_STREQ(symbol, "non_inline_func") + << "TestWithPCInsideNonInlineFunction failed"; std::cout << "TestWithPCInsideNonInlineFunction passed" << std::endl; #endif } @@ -475,9 +502,8 @@ void ABSL_ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() { (defined(__i386__) || defined(__x86_64__)) void *pc = inline_func(); // Must be inlined. const char *symbol = TrySymbolize(pc); - ABSL_RAW_CHECK(symbol != nullptr, "TestWithPCInsideInlineFunction failed"); - ABSL_RAW_CHECK(strcmp(symbol, __FUNCTION__) == 0, - "TestWithPCInsideInlineFunction failed"); + CHECK_NE(symbol, nullptr) << "TestWithPCInsideInlineFunction failed"; + CHECK_STREQ(symbol, __FUNCTION__) << "TestWithPCInsideInlineFunction failed"; std::cout << "TestWithPCInsideInlineFunction passed" << std::endl; #endif } @@ -519,9 +545,8 @@ __attribute__((target("arm"))) int ArmThumbOverlapArm(int x) { void ABSL_ATTRIBUTE_NOINLINE TestArmThumbOverlap() { #if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE) const char *symbol = TrySymbolize((void *)&ArmThumbOverlapArm); - ABSL_RAW_CHECK(symbol != nullptr, "TestArmThumbOverlap failed"); - ABSL_RAW_CHECK(strcmp("ArmThumbOverlapArm()", symbol) == 0, - "TestArmThumbOverlap failed"); + CHECK_NE(symbol, nullptr) << "TestArmThumbOverlap failed"; + CHECK_STREQ("ArmThumbOverlapArm()", symbol) << "TestArmThumbOverlap failed"; std::cout << "TestArmThumbOverlap passed" << std::endl; #endif } @@ -570,7 +595,7 @@ TEST(Symbolize, SymbolizeWithDemangling) { } #endif // !defined(ABSL_CONSUME_DLL) -#else // Symbolizer unimplemented +#else // Symbolizer unimplemented TEST(Symbolize, Unimplemented) { char buf[64]; EXPECT_FALSE(absl::Symbolize((void *)(&nonstatic_func), buf, sizeof(buf))); @@ -584,7 +609,7 @@ int main(int argc, char **argv) { #if !defined(__EMSCRIPTEN__) // Make sure kHpageTextPadding is linked into the binary. if (volatile_bool) { - ABSL_RAW_LOG(INFO, "%s", kHpageTextPadding); + LOG(INFO) << kHpageTextPadding; } #endif // !defined(__EMSCRIPTEN__) @@ -597,7 +622,8 @@ int main(int argc, char **argv) { absl::InitializeSymbolizer(argv[0]); testing::InitGoogleTest(&argc, argv); -#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) || \ +#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) || \ + defined(ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE) || \ defined(ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE) TestWithPCInsideInlineFunction(); TestWithPCInsideNonInlineFunction(); |