From c26cd952ae342ac519fd9f98b67e6152f135c6ce Mon Sep 17 00:00:00 2001 From: Tom Rybka Date: Thu, 6 Jul 2023 09:11:49 -0700 Subject: symbolize_test: Add an indirection for getting the PC from function ptr. Don't assume that function ptr == PC. Adds a redirection mechanism, GetPCFromFnPtr, and enables more test cases for Emscripten/Wasm. On many (most?) platforms, the address of a function ptr is the same as its Program Counter (PC) for the purpose of most things, including symbolization. In Emscripten WebAssembly, the function ptr is just an index into a table of functions. However, the name section maps function names to their literal offsets into a Wasm binary. The WasmOffsetConverter is actually capable of both indirections, so we can effectively go from function ptr to offset into the binary (which is typically the "PC" for other Stack dumping things in Wasm, including `emscripten_pc_get_function`). More info: https://www.w3.org/TR/wasm-js-api-2/#exported-function-exotic-objects Also fix Emscripten symbolize handling for `nullptr` now that we have tests for that. PiperOrigin-RevId: 546006678 Change-Id: I0d4015ca9035b004158451b36c933cad009184ba --- absl/debugging/symbolize_emscripten.inc | 3 ++ absl/debugging/symbolize_test.cc | 79 +++++++++++++++++++++++---------- 2 files changed, 58 insertions(+), 24 deletions(-) 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 1d1199ff..922fe36f 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 +#endif + #ifndef _WIN32 #include #include @@ -107,6 +111,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. @@ -116,6 +122,13 @@ static volatile bool volatile_bool = false; static constexpr size_t kHpageSize = 1 << 21; const char kHpageTextPadding[kHpageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE( .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]; @@ -164,15 +177,14 @@ void ABSL_ATTRIBUTE_NOINLINE TestWithReturnAddress() { #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); @@ -182,33 +194,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. @@ -278,7 +307,8 @@ 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 @@ -436,8 +466,8 @@ 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" { @@ -598,7 +628,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(); -- cgit v1.2.3