diff options
| -rw-r--r-- | src/tools/coverage-dump/src/covfun.rs | 11 | ||||
| -rw-r--r-- | src/tools/coverage-dump/src/covmap.rs | 75 | ||||
| -rw-r--r-- | src/tools/coverage-dump/src/main.rs | 4 |
3 files changed, 87 insertions, 3 deletions
diff --git a/src/tools/coverage-dump/src/covfun.rs b/src/tools/coverage-dump/src/covfun.rs index 4c0ce205822..d3744d3bf80 100644 --- a/src/tools/coverage-dump/src/covfun.rs +++ b/src/tools/coverage-dump/src/covfun.rs @@ -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}"); } diff --git a/src/tools/coverage-dump/src/covmap.rs b/src/tools/coverage-dump/src/covmap.rs new file mode 100644 index 00000000000..2246ca2d575 --- /dev/null +++ b/src/tools/coverage-dump/src/covmap.rs @@ -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 }) +} diff --git a/src/tools/coverage-dump/src/main.rs b/src/tools/coverage-dump/src/main.rs index 6408b97a06f..2c76d2f2460 100644 --- a/src/tools/coverage-dump/src/main.rs +++ b/src/tools/coverage-dump/src/main.rs @@ -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(()) } |
