go icon indicating copy to clipboard operation
go copied to clipboard

cmd/link: DWARF5 implementation breaks debugedit

Open alexsaezm opened this issue 3 weeks ago • 7 comments

Go's DWARF5 line tables use DW_FORM_string for directory and file paths, which causes debugedit and other tools to fail.

It can be easily reproduced using debugedit, for example, in Delve:

$ gotip build -o dlv-upstream cmd/dlv/main.go
$ debugedit -b $(pwd) -d /usr/src/debug -i ./dlv-upstream 
[...]
debugedit: ./dlv-upstream: Unsupported .debug_line directory 0 path DW_FORM_0x8
debugedit: ./dlv-upstream: Unsupported .debug_line directory 0 path DW_FORM_0x8
debugedit: ./dlv-upstream: Unsupported .debug_line directory 0 path DW_FORM_0x8
debugedit: ./dlv-upstream: Unsupported .debug_line directory 0 path DW_FORM_0x8
debugedit: ./dlv-upstream: Unsupported .debug_line directory 0 path DW_FORM_0x8
debugedit: ./dlv-upstream: Unsupported .debug_line directory 0 path DW_FORM_0x8
debugedit: ./dlv-upstream: Unsupported .debug_line directory 0 path DW_FORM_0x8
5e781272b49e753bcddccf567b746e1edd677f9a

This behavior was detected during the previous Fedora mass rebuild when Go 1.25 made DWARF5 the default implementation. We currently have DWARF5 disabled in Fedora, CentOS Stream, and RHEL. Other distributions that use debugedit in their build pipelines might also be affected.

There is a tracking issue since the mass rebuild on the sourceware side: https://sourceware.org/bugzilla/show_bug.cgi?id=33204

These tools expect the .debug_line_str section instead.

I created a PR, but it's worth noting that this is not a bug per se, more like a misalignment of what is expected from each other's projects. My suggested change might not be useful if it is fixed in the tooling.

https://go-review.googlesource.com/c/go/+/725160

alexsaezm avatar Nov 29 '25 10:11 alexsaezm

Why can't we fix debugedit? It knows how to handle DW_FORM_string for DW_AT_comp_dir, it doesn't seem unreasonable that it should handle it for DW_LCNT_path.

ianlancetaylor avatar Nov 30 '25 04:11 ianlancetaylor

@alexsaezm Could we possibly contact and involve a debugedit owner/maintainer? (Are you that person?)

mknyszek avatar Dec 03 '25 21:12 mknyszek

@alexsaezm Could we possibly contact and involve a debugedit owner/maintainer? (Are you that person?)

I just emailed Mark Wielaard with this conversation. I am not sure if he has a GitHub account. Hope he can jump in.

alexsaezm avatar Dec 04 '25 10:12 alexsaezm

So Mark answered me back. He doesn't have a GitHub account, so I will try to answer everything here myself and bother him with the questions. :) Sorry in advance for destroying his takes.

Regarding this:

Why can't we fix debugedit? It knows how to handle DW_FORM_string for DW_AT_comp_dir, it doesn't seem unreasonable that it should handle it for DW_LCNT_path.

He said:

Yes, it is reasonable for debugedit to try to handle DW_FORM_string in DWARF5 .debug_line. But it is a bit of work because rewriting embedded strings causes the section to change size so all references from other sections like .debug_info need to be rewritten, so we need to do it in multiple passes. That is debugedit bug https://sourceware.org/bugzilla/show_bug.cgi?id=33204

But I believe this patch for the Go DWARF5 producer is useful on its own. No other DWARF5 producer uses embedded DW_FORM_strings in .debug_line. They all store the strings together in a mergable string pool. Using DW_FORM_line_strp here also prepares for storing other identical file/directory strings from other debug sections, like e.g. the compilation file name and DW_AT_comp_dir in the same pool.

P.S. That does mean the .debug_line_strp should be created with SHF_STRINGS + SHF_MERGE for the linker to do the string merging. It isn't immediately clear to me that is done by this patch with lineStrSym = mkSecSym(".debug_line_str")

alexsaezm avatar Dec 04 '25 13:12 alexsaezm

Just to note it, Arch Linux also has DWARF5 disabled for its Go distribution for the same reason: https://gitlab.archlinux.org/archlinux/packaging/packages/go/-/commit/a2a4a14d45c78ade2565be537d20cb3b2605fbc9

jakebailey avatar Dec 04 '25 17:12 jakebailey

@alexsaezm thanks for sending this tracking issue.

I mentioned this in the Gerrit CL comments but I want to echo here as well -- in addition to the debugedit errors, the original binutils issue also indicates that dwz (run alongside or in combination with debugedit) is issuing this error for Go binaries:

DWARF-compressing 1 files
dwz: ./usr/bin/docker-compose-1.0.5-3.fc43.x86_64.debug: Unknown debugging section .debug_addr

Looking at the source code for dwz, it appears to not recognize this DWARF-5 specific section. Browsing the git logs, the commit comment for 90a85c884556df07dd7b00c5f692bdb68bb3dc31 seem to imply that the authors expected .debug_addr to be used only by GCC with split-dwarf mode. While that is currently the case, other compilers (ex: clang) don't share that strategy, and do employ .debug_addr for regular non-split-DWARF builds. Example:

$ clang-16 -g himom.c && llvm-objdump-16 -x a.out | fgrep .debug
 28 .debug_info        00000172 0000000000000000 DEBUG
 29 .debug_abbrev      0000011a 0000000000000000 DEBUG
 30 .debug_line        00000164 0000000000000000 DEBUG
 31 .debug_str         00000087 0000000000000000 DEBUG
 32 .debug_addr        00000058 0000000000000000 DEBUG
 33 .debug_line_str    00000018 0000000000000000 DEBUG
 34 .debug_str_offsets 0000006c 0000000000000000 DEBUG
$

Hence even if we move ahead with this patch for .debug_line_str support, the dwz problem would still be there. Go's DWARF5 generation strategy relies heavily on .debug_addr, there isn't any easy way to work around that I would think.

Regarding the comment passed on from Mark Wielaard, e.g.

But I believe this patch for the Go DWARF5 producer is useful on its own. No
other DWARF5 producer uses embedded DW_FORM_strings in .debug_line. They all
store the strings together in a mergable string pool. Using DW_FORM_line_strp
here also prepares for storing other identical file/directory strings from
other debug sections, like e.g. the compilation file name and DW_AT_comp_dir
in the same pool.

I am leery of making changes to Go's DWARF generation that effectively nudge it in the direction of generating more "C-like" DWARF (or an even more restrictive "GCC-like DWARF") just because that makes it slightly simpler to write tools that read DWARF. Go should be free to use DWARF (including DWARF 5) in whatever ways it needs to produce the most compact and expressive info, as opposed to mimicing however C compilers do it. The reason that Go has fantastically speedy compile and build times is in a good part due to the willingness of Go's designers to do things differently from C compilers.

thanm avatar Dec 06 '25 23:12 thanm