Skip to content
This repository has been archived by the owner on Nov 1, 2023. It is now read-only.

Commit

Permalink
embed coverage debugger scripts (#783)
Browse files Browse the repository at this point in the history
  • Loading branch information
bmc-msft authored Apr 9, 2021
1 parent a91b5aa commit ef8e200
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ impl CoverageProcessor {
pub async fn new(config: Arc<Config>) -> Result<Self> {
let heartbeat_client = config.common.init_heartbeat().await?;
let total = TotalCoverage::new(config.coverage.path.join(TOTAL_COVERAGE));
let recorder = CoverageRecorder::new(config.clone());
let recorder = CoverageRecorder::new(config.clone()).await?;
let module_totals = BTreeMap::default();

Ok(Self {
Expand Down
88 changes: 63 additions & 25 deletions src/agent/onefuzz-agent/src/tasks/coverage/recorder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@ use std::{
};

use anyhow::{Context, Result};
use onefuzz::{
fs::{has_files, OwnedDir},
sha256::digest_file,
};
use onefuzz::{fs::has_files, sha256::digest_file};
use tempfile::{tempdir, TempDir};
use tokio::{
fs,
process::{Child, Command},
Expand All @@ -22,17 +20,71 @@ use crate::tasks::coverage::libfuzzer_coverage::Config;

pub struct CoverageRecorder {
config: Arc<Config>,
script_dir: OwnedDir,
script_path: PathBuf,
// keep _temp_dir such that Drop cleans up temporary files
_temp_dir: Option<TempDir>,
}

const SYMBOL_EXTRACT_ERROR: &str = "Target appears to be missing sancov instrumentation. This error can also happen if symbols for the target are not available.";

impl CoverageRecorder {
pub fn new(config: Arc<Config>) -> Self {
let script_dir =
OwnedDir::new(env::var("ONEFUZZ_TOOLS").unwrap_or_else(|_| "script".to_string()));
pub async fn new(config: Arc<Config>) -> Result<Self> {
let (script_path, _temp_dir) = match env::var("ONEFUZZ_TOOLS") {
Ok(tools_dir) => {
let script_path = PathBuf::from(tools_dir);
if cfg!(target_os = "linux") {
(
script_path
.join("linux")
.join("libfuzzer-coverage")
.join("coverage_cmd.py"),
None,
)
} else if cfg!(target_os = "windows") {
(
script_path
.join("win64")
.join("libfuzzer-coverage")
.join("DumpCounters.js"),
None,
)
} else {
bail!("coverage recorder not implemented for target os");
}
}
Err(_) => {
let temp_dir = tempdir()?;
let script_path = if cfg!(target_os = "linux") {
let script_path = temp_dir.path().join("coverage_cmd.py");
let content = include_bytes!(
"../../../../script/linux/libfuzzer-coverage/coverage_cmd.py"
);
fs::write(&script_path, content).await.with_context(|| {
format!("unable to write file: {}", script_path.display())
})?;
script_path
} else if cfg!(target_os = "windows") {
let script_path = temp_dir.path().join("DumpCounters.js");
let content = include_bytes!(
"../../../../script/win64/libfuzzer-coverage/DumpCounters.js"
);
fs::write(&script_path, content).await.with_context(|| {
format!("unable to write file: {}", script_path.display())
})?;
script_path
} else {
bail!("coverage recorder not implemented for target os");
};

(script_path, Some(temp_dir))
}
};

Self { config, script_dir }
Ok(Self {
config,
script_path,
_temp_dir,
})
}

/// Invoke a script to write coverage to a file.
Expand Down Expand Up @@ -103,19 +155,12 @@ impl CoverageRecorder {

#[cfg(target_os = "linux")]
fn invoke_debugger_script(&self, test_input: &Path, output: &Path) -> Result<Child> {
let script_path = self
.script_dir
.path()
.join("linux")
.join("libfuzzer-coverage")
.join("coverage_cmd.py");

let mut cmd = Command::new("gdb");
cmd.arg(&self.config.target_exe)
.arg("-nh")
.arg("-batch")
.arg("-x")
.arg(script_path)
.arg(&self.script_path)
.arg("-ex")
.arg(format!(
"coverage {} {} {}",
Expand All @@ -139,18 +184,11 @@ impl CoverageRecorder {

#[cfg(target_os = "windows")]
fn invoke_debugger_script(&self, test_input: &Path, output: &Path) -> Result<Child> {
let script_path = self
.script_dir
.path()
.join("win64")
.join("libfuzzer-coverage")
.join("DumpCounters.js");

let should_disable_sympath = !self.config.target_env.contains_key("_NT_SYMBOL_PATH");

let cdb_cmd = format!(
".scriptload {}; !dumpcounters {:?}, {}; q",
script_path.to_string_lossy(),
self.script_path.to_string_lossy(),
output.to_string_lossy(),
should_disable_sympath,
);
Expand Down

0 comments on commit ef8e200

Please sign in to comment.