Created attachment 10524 [details]
hello world binary
With a simple hello world program in Rust, eu-addr2line can't locate the file:line of the main subprogram.
The binary is attached, generated using:
$ cargo new --bin hello
Created binary (application) `hello` project
$ cd hello/
$ cargo run
Compiling hello v0.1.0 (file:///tmp/hello)
Finished dev [unoptimized + debuginfo] target(s) in 0.13 secs
Let's try to locate hello::main...
$ nm target/debug/hello | grep main
0000000000003750 T main
0000000000227808 d _ZN5hello4main15__STATIC_FMTSTR17h02cd196921af1863E
0000000000003710 t _ZN5hello4main17ha1ca5e9e738df91eE
$ eu-addr2line -e target/debug/hello -f 3710
$ addr2line -e target/debug/hello -f 3710
So elfutils finds the raw symbol name, but not the file:line, whereas binutils finds the DIE's DW_AT_linkage_name and the correct file:line.
(I don't know why the linkage name doesn't have the hashed part, but that's indeed what the DWARF says.)
elfutils-0.169-1.fc26.x86_64 (and also master, commit 734118467b1a)
The problem is that there are no .debug_aranges. eu-addr2line uses that to know which CU it needs to inspect to find the subprogram in.
Without .debug_aranges we would have to scan all CUs to create our own aranges table by inspecting the DW_AT_low_pc/DW_AT_high_pc or DW_AT_ranges attributes.
In theory we could do that, but it is not immediately obvious when we should.
If there is no .debug_aranges at all then it might be sensible to assume this does not mean there are really no CUs that cover program scope addresses. But if there are .debug_aranges then it seems bad to assume they are wrong or incomplete.
Best would be to fix rustc to generate .debug_aranges.
Second best would be to have a mechanism to for scanning all CUs and (re)create the same cache that dwarf_getaranges() would create from the .debug_aranges section for the CU. One question is if this isn't the default how it interacts with other users of the aranges cache like dwarf_addrdie, dwfl_module_addrdie and dwfl_module_getsrc. The last one is what eu-addr2line (and eu-stack) use.
(In reply to Mark Wielaard from comment #1)
> But if there are .debug_aranges then it seems bad to assume they
> are wrong or incomplete.
I think it's safe to trust that given aranges are valid, but not that they're complete. The binary may be composed of objects from multiple compilers, with different policies toward aranges, and the final user linking it all may not be able to control this.
> Best would be to fix rustc to generate .debug_aranges.
I found that Clang also doesn't emit .debug_aranges by default, but it has -gdwarf-aranges for that. This passes to LLVM -generate-arange-section, and in fact "rustc -Cllvm-args=-generate-arange-section" does work!
I can talk to upstream about making that the default, but they may well take a similar stance as Clang, that it's redundant with other pc/range info.
> Second best would be to have a mechanism to for scanning all CUs and
> (re)create the same cache that dwarf_getaranges() would create from the
> .debug_aranges section for the CU. One question is if this isn't the default
> how it interacts with other users of the aranges cache like dwarf_addrdie,
> dwfl_module_addrdie and dwfl_module_getsrc. The last one is what
> eu-addr2line (and eu-stack) use.
I think this mechanism is desirable even if rustc changes its default. Start with the aranges, and lazily augment it with a CU scan if that misses. But I don't doubt there are tricky corners to this.
> I can talk to upstream about making that the default,
Here's my rustc PR to enable aranges by default:
Just a quick +1 to Comment #2 - consumers shouldn't rely on the presence of .debug_aranges, or them being complete (DWARF doesn't require/guarantee this - and Clang doesn't emit aranges by default, for instance). Each contribution to .debug_aranges says which CU it covers and any CUs not covered should be parsed/assumed to contain things covering other addresses.
Ideally parsing CUs lightly (just enough to get their CU ranges) should be fairly cheap - cheap enough to be worth doing so to avoid/save producers having to emit all the extra/duplicate data into .debug_aranges that's already covered by CU ranges.
It'd be nice if Rust could revert/avoid emitting these aranges, like Clang does.