--- a/internal/compilers.h +++ b/internal/compilers.h @@ -101,4 +101,23 @@ # define BITFIELD(type, name, size) unsigned int name : size #endif +/* + * RUBY_DEBUG_EXPORT(name, target) gives `target`, a function or variable + * defined in the same file, the additional exported name `name`, so that + * tools outside the process, such as profilers, can still find it after + * libruby is stripped. Ruby itself keeps using `target`, so its generated + * code does not change. These names are best-effort debugging aids, not an + * API, and may change or disappear at any time. + */ +#if defined(__linux__) && defined(HAVE_ATTRIBUTE_FUNCTION_ALIAS) +# define RUBY_DEBUG_EXPORT_DECL(decl, target) \ + extern decl __attribute__((__alias__(STRINGIZE(target)), __visibility__("protected"))); +#else +# define RUBY_DEBUG_EXPORT_DECL(decl, target) /* not supported */ +#endif +#define RUBY_DEBUG_EXPORT(name, target) \ + RUBY_DEBUG_EXPORT_DECL(__typeof__(target) name, target) +#define RUBY_DEBUG_EXPORT_TLS(name, target) \ + RUBY_DEBUG_EXPORT_DECL(RB_THREAD_LOCAL_SPECIFIER __typeof__(target) name, target) + #endif /* INTERNAL_COMPILERS_H */ --- a/symbol.c +++ b/symbol.c @@ -91,6 +91,7 @@ rb_symbols_t ruby_global_symbols = { .next_id = tNEXT_ID, }; +RUBY_DEBUG_EXPORT(ruby_debug_global_symbols, ruby_global_symbols) struct sym_set_static_sym_entry { VALUE sym; --- a/vm.c +++ b/vm.c @@ -727,6 +727,7 @@ #ifdef RB_THREAD_LOCAL_SPECIFIER RB_THREAD_LOCAL_SPECIFIER rb_execution_context_t *ruby_current_ec; +RUBY_DEBUG_EXPORT_TLS(ruby_debug_current_ec, ruby_current_ec) #ifdef RUBY_NT_SERIAL RB_THREAD_LOCAL_SPECIFIER rb_atomic_t ruby_nt_serial; @@ -2937,6 +2938,7 @@ EC_POP_TAG(); return result; } +RUBY_DEBUG_EXPORT(ruby_debug_vm_exec, vm_exec) static inline VALUE vm_exec_loop(rb_execution_context_t *ec, enum ruby_tag_type state,