From: "nayefg (Nayef Ghattas) via ruby-core" Date: 2026-10-21T16:16:11+00:00 Subject: [ruby-core:127193] [Ruby Feature#21539] Export symbols for external profiling of stripped shared Ruby builds Issue #21539 has been updated by nayefg (Nayef Ghattas). File debug-aliases.patch added Following up on [protected.patch](https://bugs.ruby-lang.org/attachments/download/10350/protected.patch): in our tests, exporting the original symbols had two effects, even with protected visibility. - With GCC, exporting `ruby_global_symbols` changes how `rb_id2str` addresses the table. On x86-64 the linker relaxes the GOT load into an extra LEA; on arm64 the GOT load remains. Against a build exporting only `ruby_current_ec`, a loop calling `rb_id2name` was about 2% slower on a Xeon and 6% slower by median on a Neoverse N1. - The longer code also moved other functions on x86-64. `rb_backref_get` moved by 80 bytes without changing its instructions, and a loop calling it was about 4% slower on the Xeon against the same reference build. Changing its alignment shifted timings by 3���5%, showing that code placement matters too. I'd suggest a small variation: leave the originals unchanged and add a protected alias next to each definition. These aliases would be best-effort debugging symbols, without a stable-layout guarantee. Ruby's own code keeps using the originals, with their existing declarations and visibility. ```c extern __typeof__(ruby_global_symbols) ruby_debug_global_symbols __attribute__((alias("ruby_global_symbols"), visibility("protected"))); ``` Proposed names, open to discussion: - `ruby_debug_current_ec`: the same TLS slot as `ruby_current_ec`; - `ruby_debug_vm_exec`: the actual `rb_vm_exec` function, including its full symbol size; - `ruby_debug_global_symbols`: the original symbol table. We tested the alias approach on Ruby `b709bdb3` with GCC 13.3.0 and Clang 14.0.6 on x86-64 and arm64 Linux. The aliases survived `strip --strip-all` and were still found by the OpenTelemetry profiler's ELF/TLS lookup code. Internal access sequences were unchanged, and the x86-64 builds also avoided the code displacement seen with direct exports. The benchmarks showed no consistent slowdown. The full patch is attached; the [investigation repository](https://github.com/Gandem/ruby-symbol-discovery) has the assembly and benchmark details. ---------------------------------------- Feature #21539: Export symbols for external profiling of stripped shared Ruby builds https://bugs.ruby-lang.org/issues/21539#change-119609 * Author: dalehamel (Dale Hamel) * Status: Open ---------------------------------------- ## Motivation External profilers such as [OpenTelemetry's eBPF profiler](https://github.com/open-telemetry/opentelemetry-ebpf-profiler) collect Ruby stacks from outside the Ruby process. Distribution packages commonly ship shared libruby but strip the full symbol table (`.symtab`) and debug information. Some of the symbols needed to discover Ruby's execution state are currently local symbols, so they disappear when stripped. Public dynamic symbols in `.dynsym` survive normal stripping. I'd like to narrow this proposal to making the necessary discovery symbols available in these stripped shared builds. ## Proposed exports Please export these three existing symbols from shared libruby: | Symbol | Purpose | | --- | --- | | `ruby_current_ec` | Locate the sampled native thread's execution context through TLS, providing access to its Ruby stack. | | `rb_vm_exec` | Identify the function's address range, where native stack unwinding should hand off to Ruby stack unwinding. The profiler does not call this function. | | `ruby_global_symbols` | Resolve Ruby method IDs to names for methods implemented in C. Stack walking can work without this, but those method names become ``. | The profiler also needs `ruby_version`, which is already exported and requires no change. The requested outcome is that these symbols are available through `.dynsym` in installed shared builds, without requiring distributions to retain the full symbol table or users to install debug information just to locate them. ## Scope This is a symbol-visibility request, not a request for a general out-of-process profiling API: - No requirement to stabilize internal struct layouts or make these internals a supported C-extension API. - No additional profiling stack, per-frame bookkeeping, or in-process profiling machinery. - The profiler remains responsible for supporting version-specific layouts and interpreter/JIT behavior. This would address the symbol-discovery obstacle for stripped distribution builds without taking on the broader API design discussed in #19119. Related profiler discussion: https://github.com/open-telemetry/opentelemetry-ebpf-profiler/issues/202 ---Files-------------------------------- protected.patch (1.55 KB) exported.patch (1.21 KB) debug-aliases.patch (1.88 KB) -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/