Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/agent/coverage/src/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@
use std::collections::{BTreeMap, BTreeSet};

use anyhow::{bail, Result};
use debuggable_module::{block, path::FilePath, Module, Offset};
use debuggable_module::Module;
pub use debuggable_module::{block, path::FilePath, Offset};
use symbolic::debuginfo::Object;
use symbolic::symcache::{SymCache, SymCacheConverter};

use crate::allowlist::TargetAllowList;

#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct BinaryCoverage {
pub modules: BTreeMap<FilePath, ModuleBinaryCoverage>,
}

#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct ModuleBinaryCoverage {
pub offsets: BTreeMap<Offset, Count>,
}
Expand Down
25 changes: 16 additions & 9 deletions src/agent/onefuzz-file-format/src/coverage/binary/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,29 @@ use crate::hex::Hex;
#[derive(Deserialize, Serialize)]
pub struct BinaryCoverageJson {
#[serde(flatten)]
pub modules: BTreeMap<String, BTreeMap<Hex, u32>>,
pub modules: BTreeMap<String, ModuleCoverageJson>,
}

#[derive(Deserialize, Serialize)]
pub struct ModuleCoverageJson {
pub blocks: BTreeMap<Hex, u32>,
}

impl From<BinaryCoverage> for BinaryCoverageJson {
fn from(binary: BinaryCoverage) -> Self {
let mut modules = BTreeMap::new();

for (module, offsets) in &binary.modules {
let mut map: BTreeMap<Hex, u32> = BTreeMap::new();
for (path, offsets) in &binary.modules {
let mut blocks: BTreeMap<Hex, u32> = BTreeMap::new();

for (offset, count) in offsets.as_ref() {
map.insert(Hex(offset.0), count.0);
blocks.insert(Hex(offset.0), count.0);
}

let path = module.as_str().to_owned();
modules.insert(path, map);
let path = path.as_str().to_owned();
let module = ModuleCoverageJson { blocks };

modules.insert(path, module);
}

Self { modules }
Expand All @@ -41,15 +48,15 @@ impl TryFrom<BinaryCoverageJson> for BinaryCoverage {
fn try_from(json: BinaryCoverageJson) -> Result<Self> {
let mut process = BinaryCoverage::default();

for (module, offsets) in json.modules {
for (path, module) in json.modules {
let mut coverage = ModuleBinaryCoverage::default();

for (hex, count) in offsets {
for (hex, count) in module.blocks {
let offset = Offset(hex.0);
coverage.offsets.insert(offset, Count(count));
}

let path = FilePath::new(module)?;
let path = FilePath::new(path)?;
process.modules.insert(path, coverage);
}

Expand Down
32 changes: 32 additions & 0 deletions src/agent/onefuzz-file-format/tests/files/binary-coverage.v0.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[
{
"module": "/setup/main.exe",
"blocks": [
{
"offset": 1,
"count": 0
},
{
"offset": 300,
"count": 1
},
{
"offset": 5000,
"count": 0
}
]
},
{
"module": "/setup/lib/some.dll",
"blocks": [
{
"offset": 123,
"count": 0
},
{
"offset": 456,
"count": 10
}
]
}
]
15 changes: 15 additions & 0 deletions src/agent/onefuzz-file-format/tests/files/binary-coverage.v1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"/setup/main.exe": {
"blocks": {
"1": 0,
"12c": 1,
"1388": 0
}
},
"/setup/lib/some.dll": {
"blocks": {
"7b": 0,
"1c8": 10
}
}
}
45 changes: 45 additions & 0 deletions src/agent/onefuzz-file-format/tests/integration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use pretty_assertions::assert_eq;

use anyhow::Result;
use coverage::binary::{BinaryCoverage, Count, FilePath, ModuleBinaryCoverage, Offset};
use onefuzz_file_format::coverage::binary::{v0, v1};

fn expected_binary_coverage() -> Result<BinaryCoverage> {
let main_exe_path = FilePath::new("/setup/main.exe")?;
let some_dll_path = FilePath::new("/setup/lib/some.dll")?;

let mut main_exe = ModuleBinaryCoverage::default();
main_exe.offsets.insert(Offset(1), Count(0));
main_exe.offsets.insert(Offset(300), Count(1));
main_exe.offsets.insert(Offset(5000), Count(0));

let mut some_dll = ModuleBinaryCoverage::default();
some_dll.offsets.insert(Offset(123), Count(0));
some_dll.offsets.insert(Offset(456), Count(10));

let mut binary = BinaryCoverage::default();
binary.modules.insert(some_dll_path, some_dll);
binary.modules.insert(main_exe_path, main_exe);

Ok(binary)
}

#[test]
fn test_binary_coverage_formats() -> Result<()> {
let expected = expected_binary_coverage()?;

let v0_text = include_str!("files/binary-coverage.v0.json");
let v0_json: v0::BinaryCoverageJson = serde_json::from_str(v0_text)?;
let from_v0 = BinaryCoverage::try_from(v0_json)?;
assert_eq!(from_v0, expected);

let v1_text = include_str!("files/binary-coverage.v1.json");
let v1_json: v1::BinaryCoverageJson = serde_json::from_str(v1_text)?;
let from_v1 = BinaryCoverage::try_from(v1_json)?;
assert_eq!(from_v1, expected);

Ok(())
}