Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No coverage data on x86_64-unknown-none target #29

Open
YanWQ-monad opened this issue Dec 26, 2024 · 2 comments
Open

No coverage data on x86_64-unknown-none target #29

YanWQ-monad opened this issue Dec 26, 2024 · 2 comments

Comments

@YanWQ-monad
Copy link

YanWQ-monad commented Dec 26, 2024

Reproduce

src/main.rs:

#![no_std]
#![cfg_attr(not(test), no_main)]

use core::fmt::Write;

struct Writer;

impl Write for Writer {
    fn write_str(&mut self, s: &str) -> core::fmt::Result {
        let s = s.as_bytes();
        unsafe {
            core::arch::asm!(
                "syscall",
                in("rax") 1,
                in("rdi") 2,
                in("rsi") s.as_ptr(),
                in("rdx") s.len(),
            )
        }
        Ok(())
    }
}

#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
    loop {}
}

struct SizeCounter(usize);

impl minicov::CoverageWriter for SizeCounter {
    fn write(&mut self, data: &[u8]) -> Result<(), minicov::CoverageWriteError> {
        self.0 += data.len();
        Ok(())
    }
}

#[no_mangle]
pub fn _start(_: *const u8) {
    let mut buffer = SizeCounter(0);
    unsafe { minicov::capture_coverage(&mut buffer).unwrap() };
    writeln!(Writer, "Coverage data size: {:#x}", buffer.0).unwrap();

    loop {}
}

Cargo.toml:

[package]
name = "minicov-test"
edition = "2021"

[dependencies]
minicov = { version = "0.3", default-features = false }

Run:

$ RUSTFLAGS="-Cinstrument-coverage -Zno-profiler-runtime -Crelocation-model=static" cargo run --target x86_64-unknown-none --release
   Compiling minicov-test v0.0.0 (/minicov-test)
    Finished `release` profile [optimized] target(s) in 0.14s
     Running `target/x86_64-unknown-none/release/minicov-test`
Coverage data size: 0x80

And 0x80 is (seemingly) barely the size of the .profraw header, and does not contain any coverage data.

Possible Cause

On x86_64-unknown-none target, minicov is compiled with InstrProfilingPlatformOther.c because none of these is hit:

#if defined(__linux__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
(defined(__sun__) && defined(__svr4__)) || defined(__NetBSD__) || \
defined(_AIX)

Then, when capture_coverage gets the address of the counters, it gets NULL because CountersFirst is NULL, so it cannot collect the coverage counters.

In fact, the expected platform should be InstrProfilingPlatformLinux.c. I tried to remove the #if in InstrProfilingPlatformLinux.c (make it use Linux platform instead of Other), then minicov could collect the counters and dump the correct coverage data.

@Amanieu
Copy link
Owner

Amanieu commented Dec 27, 2024

You need to execute static initializers to register counters at startup. This is normally done by libc but on -none targets you need to do this manually yourself.

@YanWQ-monad
Copy link
Author

Thanks for your reply. May I ask what's the proper way to call the "static initializers"?

AFAIK, LLVM does not emit the runtime registration code, because the target is an ELF file:
https://github.com/llvm/llvm-project/blob/8caeb2e0c2fb8a5f1689c11775b81ceee76de958/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp#L1423

And I also look into what InstrProfilingLoweringPass does in my example: https://www.diffchecker.com/07GpyZjq/ . It seems that no initializers are generated in this pass?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants