Remove usage of the WasmOffsetConverter for Wasm / Emscripten stack-traces.

It was removed in a recent version of [Emscripten](https://github.com/emscripten-core/emscripten/blob/main/ChangeLog.md#4014---090225).

This is unfortunate as there is no longer a way to map from function pointer
(index) back to file offset for PC get function name, however the only such uses I could find were the test itself.

Stack trace symbolization should still work.

PiperOrigin-RevId: 819879868
Change-Id: I5b41d5ebfe5e9f476972e44127bbeaaf2f864281
This commit is contained in:
Tom Rybka
2025-10-15 13:02:22 -07:00
committed by Copybara-Service
parent b6f7ac3fe5
commit 067246f7ba
4 changed files with 32 additions and 64 deletions

View File

@@ -52,13 +52,6 @@ static std::atomic<bool> disable_stacktraces(true); // Disabled until healthy.
// Waiting until static initializers run seems to be late enough.
// This file is included into stacktrace.cc so this will only run once.
ABSL_ATTRIBUTE_UNUSED static int stacktraces_enabler = []() {
// Check if we can even create stacktraces. If not, bail early and leave
// disable_stacktraces set as-is.
// clang-format off
if (!EM_ASM_INT({ return (typeof wasmOffsetConverter !== 'undefined'); })) {
return 0;
}
// clang-format on
disable_stacktraces.store(false, std::memory_order_relaxed);
return 0;
}();

View File

@@ -26,33 +26,20 @@
extern "C" {
const char* emscripten_pc_get_function(const void* pc);
void* emscripten_stack_snapshot();
}
// clang-format off
EM_JS(bool, HaveOffsetConverter, (),
{ return typeof wasmOffsetConverter !== 'undefined'; });
// clang-format on
namespace absl {
ABSL_NAMESPACE_BEGIN
void InitializeSymbolizer(const char*) {
if (!HaveOffsetConverter()) {
ABSL_RAW_LOG(INFO,
"Symbolization unavailable. Rebuild with -sWASM=1 "
"and -sUSE_OFFSET_CONVERTER=1.");
}
}
void InitializeSymbolizer(const char*) {}
bool Symbolize(const void* pc, char* out, int out_size) {
// Check if we have the offset converter necessary for pc_get_function.
// Without it, the program will abort().
if (!HaveOffsetConverter()) {
return false;
}
if (pc == nullptr || out_size <= 0) {
return false;
}
// Need to capture a snapshot first.
emscripten_stack_snapshot();
const char* func_name = emscripten_pc_get_function(pc);
if (func_name == nullptr) {
return false;

View File

@@ -107,8 +107,6 @@ 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.
@@ -119,12 +117,6 @@ 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];
@@ -174,12 +166,10 @@ void ABSL_ATTRIBUTE_NOINLINE TestWithReturnAddress() {
TEST(Symbolize, Cached) {
// Compilers should give us pointers to them.
EXPECT_STREQ("nonstatic_func",
TrySymbolize(GetPCFromFnPtr((void *)(&nonstatic_func))));
EXPECT_STREQ("nonstatic_func", TrySymbolize((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(GetPCFromFnPtr((void *)(&static_func)));
const char* static_func_symbol = TrySymbolize((void*)(&static_func));
EXPECT_TRUE(strcmp("static_func", static_func_symbol) == 0 ||
strcmp("static_func()", static_func_symbol) == 0);
@@ -189,50 +179,38 @@ TEST(Symbolize, Cached) {
TEST(Symbolize, Truncation) {
constexpr char kNonStaticFunc[] = "nonstatic_func";
EXPECT_STREQ("nonstatic_func",
TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)),
TrySymbolizeWithLimit((void*)(&nonstatic_func),
strlen(kNonStaticFunc) + 1));
EXPECT_STREQ("nonstatic_...",
TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)),
TrySymbolizeWithLimit((void*)(&nonstatic_func),
strlen(kNonStaticFunc) + 0));
EXPECT_STREQ("nonstatic...",
TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)),
TrySymbolizeWithLimit((void*)(&nonstatic_func),
strlen(kNonStaticFunc) - 1));
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));
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));
}
TEST(Symbolize, SymbolizeWithDemangling) {
Foo::func(100);
#ifdef __EMSCRIPTEN__
// Emscripten's online symbolizer is more precise with arguments.
EXPECT_STREQ("Foo::func(int)",
TrySymbolize(GetPCFromFnPtr((void *)(&Foo::func))));
EXPECT_STREQ("Foo::func(int)", TrySymbolize((void*)(&Foo::func)));
#else
EXPECT_STREQ("Foo::func()",
TrySymbolize(GetPCFromFnPtr((void *)(&Foo::func))));
EXPECT_STREQ("Foo::func()", TrySymbolize((void*)(&Foo::func)));
#endif
}
TEST(Symbolize, SymbolizeSplitTextSections) {
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))));
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)));
}
// Tests that verify that Symbolize stack footprint is within some limit.
@@ -630,5 +608,12 @@ int main(int argc, char **argv) {
#endif
#endif
#if !defined(__EMSCRIPTEN__)
// All of these test cases rely on symbolizing function pointers.
// On most platforms, function pointers directly map to PC.
// In WebAssembly, function pointers are indices into the function table
// and there is no longer a mapping from function index back into the
// file offset for symbolization.
return RUN_ALL_TESTS();
#endif // !defined(__EMSCRIPTEN__)
}

View File

@@ -86,6 +86,9 @@ cc_test(
],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
tags = [
"no_test_wasm", # b/452379654
],
deps = [
":hash",
":hash_testing",