gnzlbg / cargo-asm

cargo subcommand showing the assembly or llvm-ir generated for Rust code
https://github.com/gnzlbg/cargo-asm
Other
1.17k stars 36 forks source link

Returning an integer literal missing from the Rust output (debug build) #129

Closed jstasiak closed 5 years ago

jstasiak commented 5 years ago

Hi, first of all – thank you for a great project, it's been a great help when learning Rust. Not sure in what program or library the issue lies, so cargo-asm is my first stop. I'm using Rust 1.35.0 (3c235d560 2019-05-20) with the latest cargo-asm. With a piece of code like this:

pub fn fun1() -> i32 {
    1
}

pub fn fun2() -> i32 {
    1 + 1
}

I get the following output:

% cargo asm --rust what::fun1 --build-type debug
 pub fn fun1() -> i32 {
 push    rbp
 mov     rbp, rsp
 }
 mov     eax, 1
 pop     rbp
 ret

% cargo asm --rust what::fun2 --build-type debug
 pub fn fun2() -> i32 {
 push    rbp
 mov     rbp, rsp
 sub     rsp, 16
 1 + 1
 mov     eax, 1
 inc     eax
 seto    cl
 test    cl, 1
 mov     dword, ptr, [rbp, -, 4], eax
 jne     LBB1_2
 mov     eax, dword, ptr, [rbp, -, 4]
 }
 add     rsp, 16
 pop     rbp
 ret
LBB1_2:
 1 + 1
 lea     rdi, [rip, +, l_anon.392417d54f1427779e64f41b8b78d144.0]
 call    core::panicking::panic

fun2 looks ok, but for fun1 I'd expect something like:

% cargo asm --rust what::fun1 --build-type debug
 pub fn fun1() -> i32 {
 push    rbp
 mov     rbp, rsp
 1
 mov     eax, 1
 }
 pop     rbp
 ret

An explanation why I'm even looking at the assembly output of those two functions: there's a discussion of some coverage issues over in the cargo-tarpaulin repository and I've discovered the coverage of the two functions above isn't perfect either. It's been suggested some inlining is going on so I went ahead and looked at the assembly.

gnzlbg commented 5 years ago

The annotated rust code is best-effort based on the debug information emitted by rustc. If rustc doesn't emit debug information for a line, then the assembly doesn't contain it, and cargo-asm cannot display it. For just reading the inline assembly, this isn't critical, since one is interested in the assembly itself, and that is completely included. The rust source code at best help you skim through it quicker.

I believe tarpaulin also uses debug information to track coverage. That's a bad idea. There you are interested in the coverage of Rust code, and because debug information is unreliable, the coverage is unrelaible. That is, tarpaulin is broken by design.

The only reliable way to do code coverage is to use compiler instrumentation. Rust already supports building instrumented binaries, e.g., for PGO. The output of that could be read to compute code coverage, and should be quiet reliable.

gnzlbg commented 5 years ago

So i'm closing this as "working as intended". If you were to use a more recent rust version, you might get better debug information, but debug information from Rust, and LLVM in general, isn't great, so don't trust it.

jstasiak commented 5 years ago

That's fair, thank you for the explanation.