Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Windows VMI Options #98

Merged
merged 14 commits into from
Sep 15, 2024
Merged
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Enable turning on symbolic cov separately from execution trace capture
novafacing committed Sep 13, 2024
commit 2f300d286d3d894b7a6a696e7f396379311d68b0
12 changes: 12 additions & 0 deletions src/haps/mod.rs
Original file line number Diff line number Diff line change
@@ -173,6 +173,10 @@ impl Tsffs {
self.save_execution_trace()?;
}

if self.symbolic_coverage {
self.save_symbolic_coverage()?;
}

debug!(self.as_conf_object(), "Resuming simulation");

run_alone(|| {
@@ -380,6 +384,10 @@ impl Tsffs {
self.save_execution_trace()?;
}

if self.symbolic_coverage {
self.save_symbolic_coverage()?;
}

debug!(self.as_conf_object(), "Resuming simulation");

run_alone(|| {
@@ -481,6 +489,10 @@ impl Tsffs {
self.save_execution_trace()?;
}

if self.symbolic_coverage {
self.save_symbolic_coverage()?;
}

debug!(self.as_conf_object(), "Resuming simulation");

run_alone(|| {
63 changes: 34 additions & 29 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -935,41 +935,46 @@ impl Tsffs {
Ok(())
}

/// Save the current execution trace to a file
pub fn save_execution_trace(&mut self) -> Result<()> {
let execution_trace = self.execution_trace.clone();
let execution_trace_dir = self.execution_trace_directory.clone();
let coverage = self.coverage.clone();
let symbolic_coverage_directory = self.symbolic_coverage_directory.clone();
// We just fire and forget this thread -- we won't know if it fails but it's basically
// guaranteed not to. This stops us from having to wait every exec to write a huge file.
spawn(move || {
let mut hasher = DefaultHasher::new();
execution_trace.hash(&mut hasher);
let hash = hasher.finish();

if !execution_trace_dir.is_dir() {
create_dir_all(&execution_trace_dir)?;
}
pub fn save_symbolic_coverage(&mut self) -> Result<()> {
if self.symbolic_coverage_directory.is_dir() {
create_dir_all(&self.symbolic_coverage_directory)?;
}

let trace_path = execution_trace_dir.join(format!("{:x}.json", hash));
debug!(
self.as_conf_object(),
"Saving symbolic coverage to {}",
self.symbolic_coverage_directory.display()
);

if !trace_path.exists() {
let trace_file = File::create(&trace_path)?;
println!("Saving execution trace to {}", trace_path.display());
to_writer(trace_file, &execution_trace)?;
}
self.coverage.to_html(&self.symbolic_coverage_directory)?;

if !symbolic_coverage_directory.is_dir() {
create_dir_all(&symbolic_coverage_directory)?;
}
debug!(
self.as_conf_object(),
"Symbolic coverage saved to {}",
self.symbolic_coverage_directory.display()
);

Ok(())
}

println!("Saving coverage information to symbolic coverage directory {symbolic_coverage_directory:?}");
coverage.to_html(&symbolic_coverage_directory)?;
/// Save the current execution trace to a file
pub fn save_execution_trace(&mut self) -> Result<()> {
let mut hasher = DefaultHasher::new();
self.execution_trace.hash(&mut hasher);
let hash = hasher.finish();

Ok::<(), anyhow::Error>(())
});
if !self.execution_trace_directory.is_dir() {
create_dir_all(&self.execution_trace_directory)?;
}

let trace_path = self
.execution_trace_directory
.join(format!("{:x}.json", hash));

if !trace_path.exists() {
let trace_file = File::create(&trace_path)?;
to_writer(trace_file, &self.execution_trace)?;
}
Ok(())
}
}
12 changes: 12 additions & 0 deletions src/log/mod.rs
Original file line number Diff line number Diff line change
@@ -152,6 +152,10 @@ impl Tsffs {
if self.save_interesting_execution_traces {
self.save_execution_trace()?;
}

if self.symbolic_coverage {
self.save_symbolic_coverage()?;
}
}
FuzzerMessage::Crash { indices, input } => {
info!(
@@ -184,6 +188,10 @@ impl Tsffs {
if self.save_solution_execution_traces {
self.save_execution_trace()?;
}

if self.symbolic_coverage {
self.save_symbolic_coverage()?;
}
}
FuzzerMessage::Timeout { indices, input } => {
info!(
@@ -216,6 +224,10 @@ impl Tsffs {
if self.save_timeout_execution_traces {
self.save_execution_trace()?;
}

if self.symbolic_coverage {
self.save_symbolic_coverage()?;
}
}
}

100 changes: 61 additions & 39 deletions src/os/windows/debug_info.rs
Original file line number Diff line number Diff line change
@@ -11,13 +11,13 @@ use std::{
};

use lending_iterator::{windows_mut, LendingIterator};
use simics::{debug, get_object, info, ConfObject};
use simics::{debug, get_object, info, warn, ConfObject};
use windows::Win32::System::{
Diagnostics::Debug::{
IMAGE_DEBUG_DIRECTORY, IMAGE_DEBUG_TYPE_CODEVIEW, IMAGE_DIRECTORY_ENTRY_DEBUG,
IMAGE_NT_HEADERS64,
},
SystemServices::IMAGE_DOS_HEADER,
SystemServices::{FILE_NOTIFY_FULL_INFORMATION, IMAGE_DOS_HEADER},
};

use crate::{os::DebugInfoConfig, source_cov::SourceCache};
@@ -448,14 +448,18 @@ impl ProcessModule {
)
})
.collect::<Vec<_>>();
Some(SymbolInfo::new(
let info = SymbolInfo::new(
procedure_rva.0 as u64,
self.base,
procedure_symbol.len as u64,
symbol_name.to_string().to_string(),
self.full_name.clone(),
lines,
))
);
if let Ok(o) = get_object("tsffs") {
debug!(o, "Got symbol: {:?}", info);
}
Some(info)
})
.collect::<Vec<_>>()
})
@@ -604,49 +608,67 @@ impl Module {
.iterator()
.filter_map(|line| line.ok())
.filter_map(|line_info| {
line_program
.get_file_info(line_info.file_index)
.ok()
.and_then(|line_file_info| {
string_table
.get(line_file_info.name)
.map(|line_file_name| (line_file_info, line_file_name))
.ok()
})
.and_then(|(line_file_info, line_file_name)| {
line_info.offset.to_rva(&address_map).map(|line_rva| {
(line_file_info, line_file_name, line_rva, line_info)
})
})
.and_then(
|(line_file_info, line_file_name, line_rva, line_info)| {
source_cache
.lookup_pdb(
&line_file_info,
&line_file_name.to_string(),
)
.ok()
.flatten()
.map(|p| p.to_path_buf())
.map(|file_path| LineInfo {
rva: line_rva.0 as u64,
size: line_info.length.unwrap_or(1),
file_path,
start_line: line_info.line_start,
end_line: line_info.line_end,
})
},
)
let Ok(line_file_info) =
line_program.get_file_info(line_info.file_index)
else {
if let Ok(o) = get_object("tsffs") {
debug!(o, "No file info for line {:?}", line_info);
}
return None;
};

let Ok(line_file_name) = string_table.get(line_file_info.name)
else {
if let Ok(o) = get_object("tsffs") {
debug!(o, "No file name for line {:?}", line_file_info);
}
return None;
};

let Some(line_rva) = line_info.offset.to_rva(&address_map) else {
if let Ok(o) = get_object("tsffs") {
debug!(o, "No RVA for line {:?}", line_info);
}
return None;
};

let Ok(Some(source_file)) = source_cache
.lookup_pdb(&line_file_info, &line_file_name.to_string())
else {
if let Ok(o) = get_object("tsffs") {
debug!(o, "No source file path for line {:?}", line_info);
}
return None;
};

let info = LineInfo {
rva: line_rva.0 as u64,
size: line_info.length.unwrap_or(1),
file_path: source_file.to_path_buf(),
start_line: line_info.line_start,
end_line: line_info.line_end,
};
if let Ok(o) = get_object("tsffs") {
debug!(o, "Got line info {:?}", line_info);
}

Some(info)
})
.collect::<Vec<_>>();
Some(SymbolInfo::new(

let info = SymbolInfo::new(
procedure_rva.0 as u64,
self.base,
procedure_symbol.len as u64,
symbol_name.to_string().to_string(),
self.full_name.clone(),
lines,
))
);

if let Ok(o) = get_object("tsffs") {
debug!(o, "Got symbol: {:?}", info);
}
Some(info)
})
.collect::<Vec<_>>()
})
15 changes: 10 additions & 5 deletions src/os/windows/mod.rs
Original file line number Diff line number Diff line change
@@ -5,8 +5,9 @@ use intervaltree::IntervalTree;
use kernel::{find_kernel_with_idt, KernelInfo};
use raw_cstr::AsRawCstr;
use simics::{
get_interface, get_object, get_processor_number, info, sys::cpu_cb_handle_t, warn, ConfObject,
CpuInstrumentationSubscribeInterface, IntRegisterInterface, ProcessorInfoV2Interface,
debug, get_interface, get_object, get_processor_number, info, sys::cpu_cb_handle_t, warn,
ConfObject, CpuInstrumentationSubscribeInterface, IntRegisterInterface,
ProcessorInfoV2Interface,
};
use std::{
collections::{hash_map::Entry, HashMap, HashSet},
@@ -158,7 +159,10 @@ impl WindowsOsInfo {
m.intervals(source_cache).ok().or_else(|| {
get_object("tsffs")
.and_then(|obj| {
warn!(obj, "Failed to get intervals for module {}", &m.full_name);
debug!(
obj,
"Failed (or skipped) getting intervals for module {}", &m.full_name
);
Err(
anyhow!("Failed to get intervals for module {}", &m.full_name)
.into(),
@@ -185,9 +189,10 @@ impl WindowsOsInfo {
m.intervals(source_cache).ok().or_else(|| {
get_object("tsffs")
.and_then(|obj| {
warn!(
debug!(
obj,
"Failed to get intervals for module {}", &m.full_name
"Failed (or skipped) getting intervals for module {}",
&m.full_name
);
Err(anyhow!(
"Failed to get intervals for module {}",
10 changes: 10 additions & 0 deletions src/source_cov/html.rs
Original file line number Diff line number Diff line change
@@ -30,6 +30,16 @@ pub(crate) struct HtmlSummaryInfo {
pub(crate) hit_functions: usize,
}

impl std::fmt::Display for HtmlSummaryInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"HtmlSummaryInfo {{ is_dir: {}, top_level: {:?}, parent: {:?}, filename: {:?}, total_lines: {}, hit_lines: {}, total_functions: {}, hit_functions: {} }}",
self.is_dir, self.top_level, self.parent, self.filename, self.total_lines, self.hit_lines, self.total_functions, self.hit_functions
)
}
}

define! {
Head {
}
Loading