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(msg:"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(msg:"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(msg:"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 F:llfn,
37 FuncName:mangled_fn_name.as_c_char_ptr(),
38 FuncNameLen:mangled_fn_name.len(),
39 )
40 }
41}
42
43pub(crate) fn write_filenames_to_buffer(filenames: &[impl AsRef<str>]) -> Vec<u8> {
44 let (pointers: Vec<*const i8>, lengths: Vec) = filenamesimpl Iterator
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: &RustString| unsafe {
51 llvm::LLVMRustCoverageWriteFilenamesToBuffer(
52 Filenames:pointers.as_ptr(),
53 FilenamesLen:pointers.len(),
54 lengths.as_ptr(),
55 LengthsLen:lengths.len(),
56 BufferOut: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(), NumBytes: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}
111