Bug 22288 - eu-addr2line doesn't find a rust file:line
Summary: eu-addr2line doesn't find a rust file:line
Status: NEW
Alias: None
Product: elfutils
Classification: Unclassified
Component: tools (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-10-12 18:56 UTC by Josh Stone
Modified: 2017-10-12 22:42 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments
hello world binary (95.78 KB, application/x-sharedlib)
2017-10-12 18:56 UTC, Josh Stone
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Josh Stone 2017-10-12 18:56:43 UTC
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:

rust-1.20.0-2.fc26.x86_64
cargo-0.21.1-1.fc26.x86_64

$ 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
     Running `target/debug/hello`
Hello, world!

Let's try to locate hello::main...

$ nm target/debug/hello | grep main
                 U __libc_start_main@@GLIBC_2.2.5
0000000000003750 T main
0000000000227808 d _ZN5hello4main15__STATIC_FMTSTR17h02cd196921af1863E
0000000000003710 t _ZN5hello4main17ha1ca5e9e738df91eE
$ eu-addr2line -e target/debug/hello -f 3710
_ZN5hello4main17ha1ca5e9e738df91eE
??:0
$ addr2line -e target/debug/hello -f 3710
_ZN5hello4mainE
/tmp/hello/src/main.rs:1

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)
binutils-2.27-24.fc26.x86_64
Comment 1 Mark Wielaard 2017-10-12 20:36:40 UTC
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.
Comment 2 Josh Stone 2017-10-12 20:49:43 UTC
(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.
Comment 3 Josh Stone 2017-10-12 22:42:35 UTC
> I can talk to upstream about making that the default,

https://github.com/rust-lang/rust/issues/45246