rustc_codegen_llvm/coverageinfo/
llvm_cov.rs

1//! Safe wrappers for coverage-specific FFI functions.
2
3use std::ffi::CString;
4
5use crate::common::AsCCharPtr;
6use crate::coverageinfo::ffi;
7use crate::llvm;
8
9pub(crate) fn covmap_var_name() -> CString {
10    CString::new(llvm::build_byte_buffer(|s| unsafe {
11        llvm::LLVMRustCoverageWriteCovmapVarNameToString(s);
12    }))
13    .expect("covmap variable name should not contain NUL")
14}
15
16pub(crate) fn covmap_section_name(llmod: &llvm::Module) -> CString {
17    CString::new(llvm::build_byte_buffer(|s| unsafe {
18        llvm::LLVMRustCoverageWriteCovmapSectionNameToString(llmod, s);
19    }))
20    .expect("covmap section name should not contain NUL")
21}
22
23pub(crate) fn covfun_section_name(llmod: &llvm::Module) -> CString {
24    CString::new(llvm::build_byte_buffer(|s| unsafe {
25        llvm::LLVMRustCoverageWriteCovfunSectionNameToString(llmod, s);
26    }))
27    .expect("covfun section name should not contain NUL")
28}
29
30pub(crate) fn create_pgo_func_name_var<'ll>(
31    llfn: &'ll llvm::Value,
32    mangled_fn_name: &str,
33) -> &'ll llvm::Value {
34    unsafe {
35        llvm::LLVMRustCoverageCreatePGOFuncNameVar(
36            llfn,
37            mangled_fn_name.as_c_char_ptr(),
38            mangled_fn_name.len(),
39        )
40    }
41}
42
43pub(crate) fn write_filenames_to_buffer(filenames: &[impl AsRef<str>]) -> Vec<u8> {
44    let (pointers, lengths) = filenames
45        .into_iter()
46        .map(AsRef::as_ref)
47        .map(|s: &str| (s.as_c_char_ptr(), s.len()))
48        .unzip::<_, _, Vec<_>, Vec<_>>();
49
50    llvm::build_byte_buffer(|buffer| unsafe {
51        llvm::LLVMRustCoverageWriteFilenamesToBuffer(
52            pointers.as_ptr(),
53            pointers.len(),
54            lengths.as_ptr(),
55            lengths.len(),
56            buffer,
57        );
58    })
59}
60
61pub(crate) fn write_function_mappings_to_buffer(
62    virtual_file_mapping: &[u32],
63    expressions: &[ffi::CounterExpression],
64    regions: &ffi::Regions,
65) -> Vec<u8> {
66    let ffi::Regions {
67        code_regions,
68        expansion_regions,
69        branch_regions,
70        mcdc_branch_regions,
71        mcdc_decision_regions,
72    } = regions;
73
74    // SAFETY:
75    // - All types are FFI-compatible and have matching representations in Rust/C++.
76    // - For pointer/length pairs, the pointer and length come from the same vector or slice.
77    // - C++ code does not retain any pointers after the call returns.
78    llvm::build_byte_buffer(|buffer| unsafe {
79        llvm::LLVMRustCoverageWriteFunctionMappingsToBuffer(
80            virtual_file_mapping.as_ptr(),
81            virtual_file_mapping.len(),
82            expressions.as_ptr(),
83            expressions.len(),
84            code_regions.as_ptr(),
85            code_regions.len(),
86            expansion_regions.as_ptr(),
87            expansion_regions.len(),
88            branch_regions.as_ptr(),
89            branch_regions.len(),
90            mcdc_branch_regions.as_ptr(),
91            mcdc_branch_regions.len(),
92            mcdc_decision_regions.as_ptr(),
93            mcdc_decision_regions.len(),
94            buffer,
95        )
96    })
97}
98
99/// Hashes some bytes into a 64-bit hash, via LLVM's `IndexedInstrProf::ComputeHash`,
100/// as required for parts of the LLVM coverage mapping format.
101pub(crate) fn hash_bytes(bytes: &[u8]) -> u64 {
102    unsafe { llvm::LLVMRustCoverageHashBytes(bytes.as_c_char_ptr(), bytes.len()) }
103}
104
105/// Returns LLVM's `coverage::CovMapVersion::CurrentVersion` (CoverageMapping.h)
106/// as a raw numeric value. For historical reasons, the numeric value is 1 less
107/// than the number in the version's name, so `Version7` is actually `6u32`.
108pub(crate) fn mapping_version() -> u32 {
109    unsafe { llvm::LLVMRustCoverageMappingVersion() }
110}