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 { code_regions, expansion_regions, branch_regions } = regions;
67
68    // SAFETY:
69    // - All types are FFI-compatible and have matching representations in Rust/C++.
70    // - For pointer/length pairs, the pointer and length come from the same vector or slice.
71    // - C++ code does not retain any pointers after the call returns.
72    llvm::build_byte_buffer(|buffer| unsafe {
73        llvm::LLVMRustCoverageWriteFunctionMappingsToBuffer(
74            virtual_file_mapping.as_ptr(),
75            virtual_file_mapping.len(),
76            expressions.as_ptr(),
77            expressions.len(),
78            code_regions.as_ptr(),
79            code_regions.len(),
80            expansion_regions.as_ptr(),
81            expansion_regions.len(),
82            branch_regions.as_ptr(),
83            branch_regions.len(),
84            buffer,
85        )
86    })
87}
88
89/// Hashes some bytes into a 64-bit hash, via LLVM's `IndexedInstrProf::ComputeHash`,
90/// as required for parts of the LLVM coverage mapping format.
91pub(crate) fn hash_bytes(bytes: &[u8]) -> u64 {
92    unsafe { llvm::LLVMRustCoverageHashBytes(bytes.as_c_char_ptr(), bytes.len()) }
93}
94
95/// Returns LLVM's `coverage::CovMapVersion::CurrentVersion` (CoverageMapping.h)
96/// as a raw numeric value. For historical reasons, the numeric value is 1 less
97/// than the number in the version's name, so `Version7` is actually `6u32`.
98pub(crate) fn mapping_version() -> u32 {
99    unsafe { llvm::LLVMRustCoverageMappingVersion() }
100}