Bug 25173

Summary: dwarf_getsrc_die fails for rust code
Product: elfutils Reporter: Milian Wolff <mail>
Component: libdwAssignee: Not yet assigned to anyone <unassigned>
Status: UNCONFIRMED ---    
Severity: normal CC: elfutils-devel, jistone, mark
Priority: P2    
Version: unspecified   
Target Milestone: ---   
Host: Target:
Build: Last reconfirmed:
Attachments: binary for reproduction

Description Milian Wolff 2019-11-07 19:24:28 UTC
In hotspot/perfparser I notice that we fail to find srcfile information via `dwarf_getsrc_die` for a given address. To reproduce, eu-addr2line can be compared to addr2line from binutils:

```
$ cat main.rs 
fn main() {
    println!("Hello, world!");
}

$ rustc main.rs
$ objdump -S ./main
...
00000000000227f0 <_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..UpperHex$u20$for$u20$i32$GT$3fmt17hd6956218784a7031E>:
   227f0:       48 81 ec 88 00 00 00    sub    $0x88,%rsp
   227f7:       48 89 f0                mov    %rsi,%rax
   227fa:       8b 0f                   mov    (%rdi),%ecx
   227fc:       4c 8d 84 24 88 00 00    lea    0x88(%rsp),%r8
   22803:       00 
   22804:       45 31 c9                xor    %r9d,%r9d
   22807:       66 0f 1f 84 00 00 00    nopw   0x0(%rax,%rax,1)
...
$ addr2line -e ./main -a 227f0
0x00000000000227f0
/rustc/9fda7c2237db910e41d6a712e9a2139b352e558b//src/libcore/fmt/num.rs:142
$ eu-addr2line -e ./main -a 227f0
0x00000000000227f0
??:0
```

I have zero experience with rust and too little understanding of DWARF still to know what the exact reason here is. It would be great if elfutils could support rust here too like binutils does.
Comment 1 Mark Wielaard 2019-11-15 20:25:34 UTC
It might help if you could attach the binary. Locally (Fedora 31, rustc 1.38.0) I cannot replicate. Neither binutils addr2line, not elfutils eu-addr2line seem able to resolve addresses to source lines.
Comment 2 Milian Wolff 2019-11-16 20:08:57 UTC
Created attachment 12080 [details]
binary for reproduction

here's the compressed binary as compiled with rustc 1.39.0 (4560ea788 2019-11-04)

note that this one is compiled today, so the output is a bit different:

```
$ addr2line -f -i -C -e ./main -a 227f0
0x00000000000227f0
core::fmt::Arguments::new_v1
/rustc/4560ea788cb760f0a34127156c78e2552949f734//src/libcore/fmt/mod.rs:316
core::str::slice_error_fail
/rustc/4560ea788cb760f0a34127156c78e2552949f734//src/libcore/str/mod.rs:2068
```
Comment 3 Josh Stone 2019-11-18 17:59:10 UTC
(In reply to Mark Wielaard from comment #1)
> It might help if you could attach the binary. Locally (Fedora 31, rustc
> 1.38.0) I cannot replicate. Neither binutils addr2line, not elfutils
> eu-addr2line seem able to resolve addresses to source lines.

Note that rpmbuild strips Rust's rlibs (static archives), so you won't have any debuginfo for pre-compiled code from the standard library. You should still be able to resolve the user's own code though, as well as generic std code that gets monomorphized in the user's compilation.

$ bat main.rs
───────┬──────────────────────────────────
       │ File: main.rs
───────┼──────────────────────────────────
   1   │ fn main() {
   2   │     println!("Hello, world!");
   3   │ }
───────┴──────────────────────────────────
$ rustc -g main.rs
$ nm main | grep main
                 U __libc_start_main@@GLIBC_2.2.5
00000000000053d0 T main
0000000000005390 t _ZN4main4main17h6b07ac6c6f06cdd6E
$ addr2line -e main 5390
/tmp/hello/src/main.rs:1
$ eu-addr2line -e main 5390
??:0
Comment 4 Josh Stone 2019-11-18 18:11:47 UTC
I can also reproduce this with Clang (clang-9.0.0-1.fc31.x86_64), so it seems to be a more general problem with LLVM as the producer.

$ bat main.c                              
───────┬──────────────────────────────────
       │ File: main.c                     
───────┼──────────────────────────────────
   1   │ #include <stdio.h>               
   2   │ int main() {                     
   3   │     printf("Hello, world!\n");   
   4   │     return 0;                    
   5   │ }                                
───────┴──────────────────────────────────
$ clang -g main.c -o main
$ nm main | grep main
                 U __libc_start_main@@GLIBC_2.2.5
0000000000401130 T main
$ addr2line -e main 401130
/tmp/hello/src/main.c:2
$ eu-addr2line -e main 401130
??:0

When compiled with GCC, eu-addr2line resolves it fine.
Comment 5 Mark Wielaard 2019-11-18 18:39:50 UTC
I suspect this is the same as https://sourceware.org/bugzilla/show_bug.cgi?id=22288

If so then rustc -Cllvm-args=-generate-arange-section should resolve it.
Comment 6 Josh Stone 2019-11-18 18:47:12 UTC
Aha, I thought this was familiar. I guess I should try to implement that aranges change in rustc after all. However, I think elfutils should probably still try to deal without aranges, on par with binutils.
Comment 7 Milian Wolff 2019-11-20 13:12:26 UTC
hmm but in perfparser we have a workaround for missing aranges... I'll have to dig into this to see why it doesn't work here.
Comment 8 Mark Wielaard 2019-11-20 13:18:48 UTC
(In reply to Milian Wolff from comment #7)
> hmm but in perfparser we have a workaround for missing aranges... I'll have
> to dig into this to see why it doesn't work here.

You also mention it is an issue with dwarf_getsrc_die in the subject. Which would indicate that it is some other issue, because when you call dwarf_getsrc_die you already would have found the DIE (by address). So maybe it is something else in your case?

BTW. I do agree it would be nice if libdw handled missing debug_aranges. The problem is simply that you cannot know the difference between missing and not covered. Which means that for any address lookup that doesn't match an arange you would have to do some fallback lookup, which could be expensive. So still pondering how to handle this without penalizing debug files that do have correct and complete aranges (maybe we could just handle the case where there are just no  .debug_aranges at all, and only then make some fallback code kick in?)