D.gnu - Reducing debug info for stack traces, while preserving for gdb
- Witold Baryluk (51/51) Dec 14 2022 Hi,
- Witold Baryluk (153/153) Dec 14 2022 For example to give you some context.
- Iain Buclaw (18/31) Dec 24 2022 Hi,
Hi, I am trying to split debug symbols out of final binary, to reduce its size. But I would like to preserve at least line numbers in the stacktraces from `Exception`s. Linux, amd64. gdc 12.2.0 on Debian testing. Binary is compiled using `-O3 -g -g3` (and possibly -gz). I then use `objcopy` to split debug info from final ELF binary file into .exe and .debug files. I use `objcopy --only-keep-debug --compress-debug-sections=zlib binary binary.debug` to produce .debug file. Then I use normally `objcopy --strip-debug binary binary.exe` (possibly with --compress-debug-sections=zlib) to produce binary. This makes it possibly to use in gdb without issues (using `gdb -s binary.debug -e binary` for example, or by utilizing `--add-gnu-debuglink=` option in `objcopy`). But this causes stacktraces to miss line numbers (and columns). (function names are still there, as these are derived from symbol tables instead). I tried selectively removing DWARF debug sections, but it looks that at least these are required: `.debug_info` `.debug_aranges` `.debug_abbrev` `.debug_line` `.debug_str` `.debug_line_str` `.debug_rnglists` So, I can only remove these: `objcopy -R .debug_loc -R .debug_macro -R .debug_ranges -R .debug_loclists` (`.debug_loc` and `.debug_ranges` are not even generated by gcc, so it does not matter probably). The issue is, this saves me very little space. `.debug_macro` and `.debug_loclists` are rather small. The bulk of information is in `.debug_info`. But I believe it contains way more information than is really needed to just produce line numbers. I did inspect final binaries , and it is using DWARF version 5. I also tried `-gas-loc-support` , but no change. Using `-g1` makes stack traces work nicely, by making `.debug_info` smaller, but then debugging in `gdb` is very limited. One option would be to compile application twice, once with `-g1` and once with `-g3`. But I really do not think this is supported, or reliable, even if I enable deterministic builds. In one article ( https://support.backtrace.io/hc/en-us/articles/360040105792-DWARF#Remo ingDebugInformation ) I read that for C/C++ in GCC, it is enough to preserve only `.debug_frame` and `.debug_line` to get function, source filenames and line numbers. But that is not true for gdc and its stacktrace handler. I did read about this gdb extension, which is interesting, https://sourceware.org/gdb/onlinedocs/gdb/MiniDebugInfo.html , but I did not try, and it is probably only supported in gdb (i.e. addr2libe, Phobos, libunwind do not support it). Any ideas?
Dec 14 2022
For example to give you some context. This is an example small app, the actual app is significantly larger (binary with debug symbols is about 20MB, without debug symbols only 2-3MB). ``` FILE SIZE VM SIZE -------------- -------------- 19.8% 107Ki 39.3% 107Ki .text 17.0% 93.0Ki 0.0% 0 .strtab 72kB 12.0% 65.3Ki 23.8% 65.3Ki .dynstr 5.2% 28.5Ki 10.4% 28.5Ki .rodata 5.1% 27.9Ki 10.2% 27.9Ki .eh_frame 27kB 4.5% 24.8Ki 0.0% 0 .symtab 20kB 18.5kB 3.2% 17.6Ki 6.4% 17.6Ki .dynsym 1.3% 7.25Ki 0.0% 0 [Unmapped] 1.2% 6.61Ki 2.1% 5.64Ki [27 Others] 1.1% 6.18Ki 2.3% 6.18Ki .eh_frame_hdr 0.9% 5.08Ki 1.9% 5.08Ki .gnu.hash 0.8% 4.31Ki 1.6% 4.31Ki .data.rel.ro 0.8% 4.12Ki 1.5% 4.12Ki .rela.dyn 0.5% 2.69Ki 0.0% 0 [ELF Section Headers] small small 0.3% 1.52Ki 0.6% 1.52Ki .rela.plt 100.0% 545Ki 100.0% 273Ki TOTAL ``` ``` compressed debug sections FILE SIZE VM SIZE -------------- -------------- 24.4% 107Ki 39.3% 107Ki .text 21.1% 93.0Ki 0.0% 0 .strtab 14.8% 65.3Ki 23.8% 65.3Ki .dynstr 6.5% 28.5Ki 10.4% 28.5Ki .rodata 6.3% 27.9Ki 10.2% 27.9Ki .eh_frame 5.6% 24.8Ki 0.0% 0 .symtab 4.0% 17.6Ki 6.4% 17.6Ki .dynsym smaller smaller smaller 1.6% 7.25Ki 0.0% 0 [Unmapped] 1.4% 6.18Ki 2.3% 6.18Ki .eh_frame_hdr 1.2% 5.08Ki 1.9% 5.08Ki .gnu.hash 1.0% 4.31Ki 1.6% 4.31Ki .data.rel.ro 1.0% 4.20Ki 0.9% 2.43Ki [25 Others] 0.9% 4.12Ki 1.5% 4.12Ki .rela.dyn 0.6% 2.56Ki 0.0% 0 [ELF Section Headers] 0.3% 1.52Ki 0.6% 1.52Ki .rela.plt 0.3% 1.47Ki 0.5% 1.47Ki .gnu.version 0.2% 1.03Ki 0.4% 1.03Ki .plt 0.2% 728 0.3% 728 [ELF Program Headers] 100.0% 441Ki 100.0% 273Ki TOTAL ``` (`.debug_rnglists` and `.debug_abbrev` do not even register). ``` sections (broken lines in stack trace) FILE SIZE VM SIZE -------------- -------------- 26.9% 107Ki 39.3% 107Ki .text 23.2% 92.9Ki 0.0% 0 .strtab 16.3% 65.3Ki 23.8% 65.3Ki .dynstr 7.1% 28.5Ki 10.4% 28.5Ki .rodata 6.9% 27.9Ki 10.2% 27.9Ki .eh_frame 6.2% 24.7Ki 0.0% 0 .symtab 4.4% 17.6Ki 6.4% 17.6Ki .dynsym 1.8% 7.25Ki 0.0% 0 [Unmapped] 1.5% 6.18Ki 2.3% 6.18Ki .eh_frame_hdr 1.3% 5.08Ki 1.9% 5.08Ki .gnu.hash 1.1% 4.31Ki 1.6% 4.31Ki .data.rel.ro 1.0% 4.12Ki 1.5% 4.12Ki .rela.dyn 0.5% 2.12Ki 0.0% 0 [ELF Section Headers] 0.4% 1.52Ki 0.6% 1.52Ki .rela.plt 0.4% 1.47Ki 0.5% 1.47Ki .gnu.version 0.3% 1.18Ki 0.3% 881 [18 Others] 0.3% 1.03Ki 0.4% 1.03Ki .plt 0.2% 728 0.3% 728 [ELF Program Headers] 0.1% 552 0.2% 552 .data 0.1% 544 0.2% 544 .got.plt 0.1% 512 0.2% 512 .dynamic 100.0% 401Ki 100.0% 273Ki TOTAL ``` ``` sections FILE SIZE VM SIZE -------------- -------------- 31.0% 178Ki 0.0% 0 .debug_info 0.0% 0 39.3% 107Ki .text 18.5% 106Ki 0.0% 0 .debug_loclists 16.8% 96.9Ki 0.0% 0 .debug_str 16.1% 93.0Ki 0.0% 0 .strtab 0.0% 0 23.8% 65.3Ki .dynstr 10.5% 60.7Ki 0.0% 0 .debug_line 0.0% 0 10.4% 28.5Ki .rodata 0.0% 0 10.2% 27.9Ki .eh_frame 4.3% 24.8Ki 0.0% 0 .symtab 0.0% 0 6.4% 17.6Ki .dynsym 0.0% 0 2.3% 6.18Ki .eh_frame_hdr 1.0% 5.86Ki 0.0% 0 .debug_rnglists 0.0% 0 1.9% 5.08Ki .gnu.hash 0.8% 4.54Ki 0.0% 0 .debug_abbrev 0.0% 0 1.6% 4.31Ki .data.rel.ro 0.5% 2.79Ki 1.5% 4.17Ki [27 Others] 0.0% 0 1.5% 4.12Ki .rela.dyn 0.5% 2.69Ki 0.0% 0 [ELF Section Headers] 0.0% 0 0.6% 1.52Ki .rela.plt 0.0% 0 0.5% 1.47Ki .gnu.version 100.0% 576Ki 100.0% 273Ki TOTAL ``` ``` debug sections FILE SIZE VM SIZE -------------- -------------- 0.0% 0 39.3% 107Ki .text 35.0% 93.0Ki 0.0% 0 .strtab 27.3% 72.4Ki 0.0% 0 .debug_info 0.0% 0 23.8% 65.3Ki .dynstr 0.0% 0 10.4% 28.5Ki .rodata 0.0% 0 10.2% 27.9Ki .eh_frame 10.4% 27.5Ki 0.0% 0 .debug_loclists 9.4% 24.8Ki 0.0% 0 .symtab 7.7% 20.4Ki 0.0% 0 .debug_str 7.0% 18.5Ki 0.0% 0 .debug_line 0.0% 0 6.4% 17.6Ki .dynsym 0.0% 0 2.3% 6.18Ki .eh_frame_hdr 0.0% 0 1.9% 5.08Ki .gnu.hash 0.0% 0 1.6% 4.31Ki .data.rel.ro 0.7% 1.89Ki 1.5% 4.17Ki [27 Others] 0.0% 0 1.5% 4.12Ki .rela.dyn 1.0% 2.69Ki 0.0% 0 [ELF Section Headers] 0.9% 2.38Ki 0.0% 0 .debug_rnglists 0.7% 1.74Ki 0.0% 0 .debug_abbrev 0.0% 0 0.6% 1.52Ki .rela.plt 0.0% 0 0.5% 1.47Ki .gnu.version 100.0% 265Ki 100.0% 273Ki TOTAL ```
Dec 14 2022
Hi, On Wednesday, 14 December 2022 at 22:23:49 UTC, Witold Baryluk wrote:>The bulk of information is in `.debug_info`. But I believe it contains way more information than is really needed to just produce line numbers.You're observation is correct. GDC uses libbacktrace to produce stack traces, and this indeed does traverse the `.debug_info` section in order to achieve its job. https://github.com/gcc-mirror/gcc/blob/8ec139af5ea9657c7517c1483c7a577815bea48e/libbacktrace/dwarf.c#L2116-L2120I did inspect final binaries , and it is using DWARF version 5. I also tried `-gas-loc-support` , but no change. Using `-g1` makes stack traces work nicely, by making `.debug_info` smaller, but then debugging in `gdb` is very limited. One option would be to compile application twice, once with `-g1` and once with `-g3`. But I really do not think this is supported, or reliable, even if I enable deterministic builds.I'm not sure on this, I'd have to give it some thought.In one article ( https://support.backtrace.io/hc/en-us/articles/360040105792-DWARF#Remo ingDebugInformation ) I read that for C/C++ in GCC, it is enough to preserve only `.debug_frame` and `.debug_line` to get function, source filenames and line numbers. But that is not true for gdc and its stacktrace handler.C++ stdlib doesn't give stack traces AFAIU, and if it does, it would be using libbacktrace too. I guess then the article must be referring to the implementation of `execinfo.h` and/or `dladdr`. Perhaps a run-time fallback could be added to gdc's stack trace support to use the `execinfo.h` backtrace functions if the `.debug_info` (or whatever platform equivalent) section does not exist. From what I recall, execinfo is not quite as accurate as libbacktrace though. Iain.
Dec 24 2022