Skip to content

Commit a24dcf8

Browse files
authored
Correct hashtable parsing (#67)
* Correct hashtable parsing After version 10 bitmap data was added into the hash table values, the length of this wasn't being parsed leading to values parsed missing 64 bits at the end. This PR aims to fix this * Changelog * Fmt * Add regression test
1 parent fd7f615 commit a24dcf8

6 files changed

Lines changed: 52 additions & 23 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [0.9.2]
8+
### Fixed
9+
- Parsing of hash tables with the bitmap data field
10+
711
## [0.9.1]
812
### Fixed
913
- Fix expression evaluation for split regions.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "llvm_profparser"
3-
version = "0.9.1"
3+
version = "0.9.2"
44
authors = ["xd009642 <danielmckenna93@gmail.com>"]
55
description = "Parsing and interpretation of llvm coverage profiles and generated data"
66
repository = "https://github.com/xd009642/llvm-profparser"

src/hash_table.rs

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -93,34 +93,45 @@ fn read_value(
9393
break;
9494
}
9595

96-
// If the version is > v2 then there can also be value profiling data so lets try and parse
97-
// that now
98-
let (bytes, total_size) = le_u32(input)?;
99-
if bytes.len() <= end_len {
100-
break;
101-
}
102-
let (bytes, num_value_kinds) = le_u32(bytes)?;
103-
// Here it's just less than because we don't need to read anything else so if it's equal to
104-
// we're good
105-
if bytes.len() < end_len {
106-
break;
96+
if version > 10 {
97+
let (bytes, bitmap_bytes) = le_u64(input)?;
98+
input = bytes;
99+
for _i in 0..bitmap_bytes {
100+
let (bytes, _) = le_u64(input)?;
101+
input = bytes;
102+
}
107103
}
108-
input = bytes;
109-
let value_prof_data = ValueProfData {
110-
total_size,
111-
num_value_kinds,
112-
};
113-
if value_prof_data.num_value_kinds > 0 && version > 2 {
114-
// If we actually want to change data in future get result.last_mut() and change it
115-
// there
116-
break;
104+
// This should always be true
105+
if version > 2 {
106+
// If the version is > v2 then there can also be value profiling data so lets try and parse
107+
// that now
108+
let (bytes, total_size) = le_u32(input)?;
109+
if bytes.len() <= end_len {
110+
break;
111+
}
112+
let (bytes, num_value_kinds) = le_u32(bytes)?;
113+
// Here it's just less than because we don't need to read anything else so if it's equal to
114+
// we're good
115+
if bytes.len() < end_len {
116+
break;
117+
}
118+
input = bytes;
119+
let value_prof_data = ValueProfData {
120+
total_size,
121+
num_value_kinds,
122+
};
123+
if value_prof_data.num_value_kinds > 0 && version > 2 {
124+
// If we actually want to change data in future get result.last_mut() and change it
125+
// there
126+
break;
127+
}
117128
}
118129
}
119130
if result.is_empty() {
120131
result.push((last_hash, InstrProfRecord::default()));
121132
}
122133
input = expected_end;
123-
assert_eq!(result.len(), 1);
134+
assert!(!result.is_empty());
124135
Ok((input, result.remove(0)))
125136
}
126137

@@ -142,6 +153,7 @@ impl HashTable {
142153
debug!("Number of hashtable buckets: {}", num_buckets);
143154
let (_bytes, mut num_entries) = le_u64(bytes)?;
144155
debug!("Number of entries: {}", num_entries);
156+
145157
let mut payload = input;
146158
let mut result = Self::new();
147159
//TODO is this change right?

src/instrumentation_profile/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ pub fn parse_bytes(data: &[u8]) -> io::Result<InstrumentationProfile> {
4444
));
4545
};
4646
nom_res.map(|(_bytes, res)| res).map_err(|e| {
47-
// trace!("{}", e);
47+
trace!("{}", e);
4848
let verbose_error_message = |err: VerboseError<&[u8]>| {
4949
err.errors
5050
.iter()
Binary file not shown.

tests/profdata.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,3 +491,16 @@ fn check_raw_data_consistency() {
491491
std::assert_eq!(data_record, raw_record);
492492
}
493493
}
494+
495+
// https://github.com/xd009642/llvm-profparser/issues/65 prevent regression on hash table parsing
496+
// changing
497+
#[test]
498+
fn hash_table_regression_check() {
499+
let ferrocene = data_root_dir()
500+
.join("misc")
501+
.join("ferrocene-library-aarch64-apple-darwin.profdata");
502+
503+
// We've not locked this to version, but it's enough to parse it and making sure it parses
504+
// correctly to prevent a regression.
505+
parse(&ferrocene).unwrap();
506+
}

0 commit comments

Comments
 (0)