embed coverage debugger scripts (#783)

This commit is contained in:
bmc-msft
2021-04-09 19:16:41 -04:00
committed by GitHub
parent a91b5aae89
commit ef8e200438
2 changed files with 64 additions and 26 deletions

View File

@ -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 {

View File

@ -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},
@ -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");
};
Self { config, script_dir }
(script_path, Some(temp_dir))
}
};
Ok(Self {
config,
script_path,
_temp_dir,
})
}
/// Invoke a script to write coverage to a file.
@ -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 {} {} {}",
@ -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,
);