From 48a360baa4570a31d760040118d005bb656c6389 Mon Sep 17 00:00:00 2001 From: Daniel Colson Date: Mon, 28 Apr 2025 12:54:25 -0400 Subject: [PATCH] Fix C level backtraces for USE_ELF After upgrading GitHub to Ruby 3.4 we noticed that we stopped getting useful C level backtrace information in our crash reports. We traced it back to https://github.com/github/ruby/commit/7dd2afbe3a14d021e5554288517709f5778c3d58. Passing 0 instead of -1 made sense for the Mach-O version of `fill_lines`, but there is a separate ELF version of `fill_lines` that still has special handling for -1: https://github.com/ruby/ruby/blob/58e3aa02240a9ec1b5fe6ce60d63828c2cf0c73a/addr2line.c#L2178-L2209 Without this special handling for the main executable, we don't have the right `base_addr` when reading debug info, and so we fail to populate the information for that line: https://github.com/ruby/ruby/blob/58e3aa02240a9ec1b5fe6ce60d63828c2cf0c73a/addr2line.c#L1948 Then we get to https://github.com/ruby/ruby/blob/58e3aa02240a9ec1b5fe6ce60d63828c2cf0c73a/addr2line.c#L2649, and potentially (depending on how things were run) get back `"ruby"` as `info.dli_fname` instead of the absolute path for the executable. We set that as the `binary_filename` and then try to open it inside the next call to `fill_lines`, but that fails (unless you happen to be in the directory where the ruby executable lives) and break out of filling lines entirely: https://github.com/ruby/ruby/blob/58e3aa02240a9ec1b5fe6ce60d63828c2cf0c73a/addr2line.c#L2673-L2674 This commit treats offset 0 as the main executable, rather than having a special meaning for -1 (which gets turned into 0 anyway). [Bug #21289] --- addr2line.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/addr2line.c b/addr2line.c index dc0892e308..745364cc0f 100644 --- a/addr2line.c +++ b/addr2line.c @@ -2175,9 +2175,8 @@ fill_lines(int num_traces, void **traces, int check_debuglink, } } - if (offset == -1) { + if (offset == 0) { /* main executable */ - offset = 0; if (dynsym_shdr && dynstr_shdr) { char *strtab = file + dynstr_shdr->sh_offset; ElfW(Sym) *symtab = (ElfW(Sym) *)(file + dynsym_shdr->sh_offset);