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.
This commit is contained in:
Zalathar 2025-04-24 13:47:13 +10:00
parent f1b8cd433f
commit 041b2b2c98
3 changed files with 87 additions and 3 deletions

View file

@ -2,10 +2,11 @@ use std::collections::HashMap;
use std::fmt::{self, Debug, Write as _};
use std::sync::LazyLock;
use anyhow::{Context, anyhow, ensure};
use anyhow::{Context, anyhow, bail, ensure};
use itertools::Itertools;
use regex::Regex;
use crate::covmap::FilenameTables;
use crate::llvm_utils::unescape_llvm_string_contents;
use crate::parser::Parser;
@ -14,6 +15,7 @@ mod tests;
pub(crate) fn dump_covfun_mappings(
llvm_ir: &str,
filename_tables: &FilenameTables,
function_names: &HashMap<u64, String>,
) -> anyhow::Result<()> {
// Extract function coverage entries from the LLVM IR assembly, and associate
@ -49,7 +51,12 @@ pub(crate) fn dump_covfun_mappings(
println!("Number of files: {num_files}");
for i in 0..num_files {
let global_file_id = parser.read_uleb128_u32()?;
let global_file_id = parser.read_uleb128_usize()?;
let &CovfunLineData { filenames_hash, .. } = line_data;
#[expect(unused)] // Removed later in this PR.
let Some(filename) = filename_tables.lookup(filenames_hash, global_file_id) else {
bail!("couldn't resolve global file: {filenames_hash}, {global_file_id}");
};
println!("- file {i} => global file {global_file_id}");
}

View file

@ -0,0 +1,75 @@
use std::collections::HashMap;
use std::sync::LazyLock;
use anyhow::{Context, ensure};
use regex::Regex;
use crate::llvm_utils::{truncated_md5, unescape_llvm_string_contents};
use crate::parser::Parser;
#[derive(Debug, Default)]
pub(crate) struct FilenameTables {
map: HashMap<u64, Vec<String>>,
}
impl FilenameTables {
pub(crate) fn lookup(&self, filenames_hash: u64, global_file_id: usize) -> Option<&str> {
let table = self.map.get(&filenames_hash)?;
let filename = table.get(global_file_id)?;
Some(filename)
}
}
struct CovmapLineData {
payload: Vec<u8>,
}
pub(crate) fn make_filename_tables(llvm_ir: &str) -> anyhow::Result<FilenameTables> {
let mut map = HashMap::default();
for line in llvm_ir.lines().filter(|line| is_covmap_line(line)) {
let CovmapLineData { payload } = parse_covmap_line(line)?;
let mut parser = Parser::new(&payload);
let n_filenames = parser.read_uleb128_usize()?;
let uncompressed_bytes = parser.read_chunk_to_uncompressed_bytes()?;
parser.ensure_empty()?;
let mut filenames_table = vec![];
let mut parser = Parser::new(&uncompressed_bytes);
for _ in 0..n_filenames {
let len = parser.read_uleb128_usize()?;
let bytes = parser.read_n_bytes(len)?;
let filename = str::from_utf8(bytes)?;
filenames_table.push(filename.to_owned());
}
let filenames_hash = truncated_md5(&payload);
map.insert(filenames_hash, filenames_table);
}
Ok(FilenameTables { map })
}
fn is_covmap_line(line: &str) -> bool {
line.starts_with("@__llvm_coverage_mapping ")
}
fn parse_covmap_line(line: &str) -> anyhow::Result<CovmapLineData> {
ensure!(is_covmap_line(line));
const RE_STRING: &str = r#"(?x)^
@__llvm_coverage_mapping \ =
.*
\[ [0-9]+ \ x \ i8 \] \ c"(?<payload>[^"]*)"
.*$
"#;
static RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(RE_STRING).unwrap());
let captures =
RE.captures(line).with_context(|| format!("couldn't parse covmap line: {line:?}"))?;
let payload = unescape_llvm_string_contents(&captures["payload"]);
Ok(CovmapLineData { payload })
}

View file

@ -1,4 +1,5 @@
mod covfun;
mod covmap;
mod llvm_utils;
mod parser;
mod prf_names;
@ -18,8 +19,9 @@ fn main() -> anyhow::Result<()> {
let llvm_ir_path = args.get(1).context("LLVM IR file not specified")?;
let llvm_ir = std::fs::read_to_string(llvm_ir_path).context("couldn't read LLVM IR file")?;
let filename_tables = covmap::make_filename_tables(&llvm_ir)?;
let function_names = crate::prf_names::make_function_names_table(&llvm_ir)?;
crate::covfun::dump_covfun_mappings(&llvm_ir, &function_names)?;
crate::covfun::dump_covfun_mappings(&llvm_ir, &filename_tables, &function_names)?;
Ok(())
}