summaryrefslogtreecommitdiff
path: root/absl/debugging
diff options
context:
space:
mode:
Diffstat (limited to 'absl/debugging')
-rw-r--r--absl/debugging/BUILD.bazel17
-rw-r--r--absl/debugging/CMakeLists.txt14
-rw-r--r--absl/debugging/failure_signal_handler.cc48
-rw-r--r--absl/debugging/failure_signal_handler.h2
-rw-r--r--absl/debugging/failure_signal_handler_test.cc5
-rw-r--r--absl/debugging/internal/demangle_test.cc6
-rw-r--r--absl/debugging/internal/elf_mem_image.h3
-rw-r--r--absl/debugging/internal/examine_stack.cc3
-rw-r--r--absl/debugging/internal/stack_consumption.cc9
-rw-r--r--absl/debugging/internal/stack_consumption_test.cc4
-rw-r--r--absl/debugging/internal/stacktrace_aarch64-inl.inc82
-rw-r--r--absl/debugging/internal/stacktrace_powerpc-inl.inc2
-rw-r--r--absl/debugging/internal/stacktrace_x86-inl.inc2
-rw-r--r--absl/debugging/internal/symbolize.h2
-rw-r--r--absl/debugging/leak_check.cc4
-rw-r--r--absl/debugging/leak_check_fail_test.cc8
-rw-r--r--absl/debugging/leak_check_test.cc6
-rw-r--r--absl/debugging/stacktrace_test.cc4
-rw-r--r--absl/debugging/symbolize_elf.inc62
-rw-r--r--absl/debugging/symbolize_emscripten.inc3
-rw-r--r--absl/debugging/symbolize_test.cc156
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 *)(&regular_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 *)(&regular_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();