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:
parent
f1b8cd433f
commit
041b2b2c98
3 changed files with 87 additions and 3 deletions
|
|
@ -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}");
|
||||
}
|
||||
|
||||
|
|
|
|||
75
src/tools/coverage-dump/src/covmap.rs
Normal file
75
src/tools/coverage-dump/src/covmap.rs
Normal 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 })
|
||||
}
|
||||
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue