Skip to content

Commit cfdf96b

Browse files
committed
coverage-dump: Make filenames available to covfun record dumping
Actually printing the filenames is deferred to a subsequent commit that will simultaneously bless all affected tests.
1 parent f0af83c commit cfdf96b

File tree

3 files changed

+87
-3
lines changed

3 files changed

+87
-3
lines changed

src/tools/coverage-dump/src/covfun.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ use std::collections::HashMap;
22
use std::fmt::{self, Debug, Write as _};
33
use std::sync::LazyLock;
44

5-
use anyhow::{Context, anyhow, ensure};
5+
use anyhow::{Context, anyhow, bail, ensure};
66
use itertools::Itertools;
77
use regex::Regex;
88

9+
use crate::covmap::FilenameTables;
910
use crate::llvm_junk::unescape_llvm_string_contents;
1011
use crate::parser::Parser;
1112

@@ -14,6 +15,7 @@ mod tests;
1415

1516
pub(crate) fn dump_covfun_mappings(
1617
llvm_ir: &str,
18+
filename_tables: &FilenameTables,
1719
function_names: &HashMap<u64, String>,
1820
) -> anyhow::Result<()> {
1921
// Extract function coverage entries from the LLVM IR assembly, and associate
@@ -49,7 +51,12 @@ pub(crate) fn dump_covfun_mappings(
4951
println!("Number of files: {num_files}");
5052

5153
for i in 0..num_files {
52-
let global_file_id = parser.read_uleb128_u32()?;
54+
let global_file_id = parser.read_uleb128_usize()?;
55+
let &CovfunLineData { filenames_hash, .. } = line_data;
56+
#[expect(unused)] // Removed later in this PR.
57+
let Some(filename) = filename_tables.lookup(filenames_hash, global_file_id) else {
58+
bail!("couldn't resolve global file: {filenames_hash}, {global_file_id}");
59+
};
5360
println!("- file {i} => global file {global_file_id}");
5461
}
5562

src/tools/coverage-dump/src/covmap.rs

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use std::collections::HashMap;
2+
use std::sync::LazyLock;
3+
4+
use anyhow::{Context, ensure};
5+
use regex::Regex;
6+
7+
use crate::llvm_junk::{truncated_md5, unescape_llvm_string_contents};
8+
use crate::parser::Parser;
9+
10+
#[derive(Debug, Default)]
11+
pub(crate) struct FilenameTables {
12+
map: HashMap<u64, Vec<String>>,
13+
}
14+
15+
impl FilenameTables {
16+
pub(crate) fn lookup(&self, filenames_hash: u64, global_file_id: usize) -> Option<&str> {
17+
let table = self.map.get(&filenames_hash)?;
18+
let filename = table.get(global_file_id)?;
19+
Some(filename)
20+
}
21+
}
22+
23+
struct CovmapLineData {
24+
payload: Vec<u8>,
25+
}
26+
27+
pub(crate) fn make_filename_tables(llvm_ir: &str) -> anyhow::Result<FilenameTables> {
28+
let mut map = HashMap::default();
29+
30+
for line in llvm_ir.lines().filter(|line| is_covmap_line(line)) {
31+
let CovmapLineData { payload } = parse_covmap_line(line)?;
32+
33+
let mut parser = Parser::new(&payload);
34+
let n_filenames = parser.read_uleb128_usize()?;
35+
let uncompressed_bytes = parser.read_chunk_to_uncompressed_bytes()?;
36+
parser.ensure_empty()?;
37+
38+
let mut filenames_table = vec![];
39+
40+
let mut parser = Parser::new(&uncompressed_bytes);
41+
for _ in 0..n_filenames {
42+
let len = parser.read_uleb128_usize()?;
43+
let bytes = parser.read_n_bytes(len)?;
44+
let filename = str::from_utf8(bytes)?;
45+
filenames_table.push(filename.to_owned());
46+
}
47+
48+
let filenames_hash = truncated_md5(&payload);
49+
map.insert(filenames_hash, filenames_table);
50+
}
51+
52+
Ok(FilenameTables { map })
53+
}
54+
55+
fn is_covmap_line(line: &str) -> bool {
56+
line.starts_with("@__llvm_coverage_mapping ")
57+
}
58+
59+
fn parse_covmap_line(line: &str) -> anyhow::Result<CovmapLineData> {
60+
ensure!(is_covmap_line(line));
61+
62+
const RE_STRING: &str = r#"(?x)^
63+
@__llvm_coverage_mapping \ =
64+
.*
65+
\[ [0-9]+ \ x \ i8 \] \ c"(?<payload>[^"]*)"
66+
.*$
67+
"#;
68+
static RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(RE_STRING).unwrap());
69+
70+
let captures =
71+
RE.captures(line).with_context(|| format!("couldn't parse covmap line: {line:?}"))?;
72+
let payload = unescape_llvm_string_contents(&captures["payload"]);
73+
74+
Ok(CovmapLineData { payload })
75+
}

src/tools/coverage-dump/src/main.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod covfun;
2+
mod covmap;
23
mod llvm_junk;
34
mod parser;
45
mod prf_names;
@@ -18,8 +19,9 @@ fn main() -> anyhow::Result<()> {
1819
let llvm_ir_path = args.get(1).context("LLVM IR file not specified")?;
1920
let llvm_ir = std::fs::read_to_string(llvm_ir_path).context("couldn't read LLVM IR file")?;
2021

22+
let filename_tables = covmap::make_filename_tables(&llvm_ir)?;
2123
let function_names = crate::prf_names::make_function_names_table(&llvm_ir)?;
22-
crate::covfun::dump_covfun_mappings(&llvm_ir, &function_names)?;
24+
crate::covfun::dump_covfun_mappings(&llvm_ir, &filename_tables, &function_names)?;
2325

2426
Ok(())
2527
}

0 commit comments

Comments
 (0)