Skip to content

Commit 7a18bda

Browse files
committed
Add some debug logging and fixes
1 parent 925dea0 commit 7a18bda

File tree

15 files changed

+278
-79
lines changed

15 files changed

+278
-79
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ version = "0.2.2"
2121

2222
[package.metadata.simics]
2323
package-number = 31337
24-
version = "6.1.5"
24+
version = "6.1.6"
2525

2626
[lib]
2727
crate-type = ["cdylib", "rlib"]
@@ -104,6 +104,7 @@ sha2 = "0.10.8"
104104
typed-path = "0.9.0"
105105
markup = "0.15.0"
106106
petgraph = "0.6.5"
107+
thiserror = "1.0.63"
107108

108109
[dev-dependencies]
109110
simics-test = "0.1.0"

src/haps/mod.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,10 @@ impl Tsffs {
6262
self.windows_os_info.collect(
6363
start_processor_raw,
6464
&self.debuginfo_download_directory,
65-
DebugInfoConfig {
65+
&mut DebugInfoConfig {
6666
system: self.symbolic_coverage_system,
6767
user_debug_info: &self.debug_info,
68+
coverage: &mut self.coverage,
6869
},
6970
&self.source_file_cache,
7071
)?;
@@ -225,9 +226,10 @@ impl Tsffs {
225226
self.windows_os_info.collect(
226227
processor,
227228
&self.debuginfo_download_directory,
228-
DebugInfoConfig {
229+
&mut DebugInfoConfig {
229230
system: self.symbolic_coverage_system,
230231
user_debug_info: &self.debug_info,
232+
coverage: &mut self.coverage,
231233
},
232234
&self.source_file_cache,
233235
)?;
@@ -271,9 +273,10 @@ impl Tsffs {
271273
self.windows_os_info.collect(
272274
processor,
273275
&self.debuginfo_download_directory,
274-
DebugInfoConfig {
276+
&mut DebugInfoConfig {
275277
system: self.symbolic_coverage_system,
276278
user_debug_info: &self.debug_info,
279+
coverage: &mut self.coverage,
277280
},
278281
&self.source_file_cache,
279282
)?;

src/lib.rs

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ use simics::{
6363
// which is necessary because this module is compatible with base versions which cross the
6464
// deprecation boundary
6565
use simics::{restore_snapshot, save_snapshot};
66-
use source_cov::{Coverage, SourceCache};
66+
use source_cov::{lcov::Records, SourceCache};
6767
use state::StopReason;
6868
use std::{
6969
alloc::{alloc_zeroed, Layout},
@@ -75,7 +75,7 @@ use std::{
7575
ptr::null_mut,
7676
str::FromStr,
7777
sync::mpsc::{Receiver, Sender},
78-
thread::JoinHandle,
78+
thread::{spawn, JoinHandle},
7979
time::SystemTime,
8080
};
8181
use tracer::{
@@ -422,6 +422,10 @@ pub(crate) struct Tsffs {
422422
/// Whether symbolic coverage should be collected for system components by downloading
423423
/// executable and debug info files where possible.
424424
pub symbolic_coverage_system: bool,
425+
#[class(attribute(optional, default = lookup_file("%simics%")?.join("symbolic-coverage")))]
426+
/// Directory in which source files are located. Source files do not need to be arranged in
427+
/// the same directory structure as the compiled source, and are looked up by hash.
428+
pub symbolic_coverage_directory: PathBuf,
425429

426430
/// Handle for the core simulation stopped hap
427431
stop_hap_handle: HapHandle,
@@ -478,7 +482,7 @@ pub(crate) struct Tsffs {
478482
execution_trace: ExecutionTrace,
479483
/// The current line coverage state comprising the total execution. This is not
480484
/// cleared and is persistent across the full campaign until the fuzzer stops.
481-
coverage: Coverage,
485+
coverage: Records,
482486

483487
/// The name of the fuzz snapshot, if saved
484488
snapshot_name: OnceCell<String>,
@@ -724,6 +728,10 @@ impl Tsffs {
724728
warn!(self.as_conf_object(), "Failed to disable VMP: {}", e);
725729
}
726730

731+
// Initialize the source cache for source/line lookups
732+
info!(self.as_conf_object(), "Initializing source cache");
733+
self.source_file_cache = SourceCache::new(&self.debuginfo_source_directory)?;
734+
727735
self.log(LogMessage::startup())?;
728736

729737
#[cfg(simics_version_7)]
@@ -929,23 +937,38 @@ impl Tsffs {
929937

930938
/// Save the current execution trace to a file
931939
pub fn save_execution_trace(&mut self) -> Result<()> {
932-
let mut hasher = DefaultHasher::new();
933-
self.execution_trace.hash(&mut hasher);
934-
let hash = hasher.finish();
940+
let execution_trace = self.execution_trace.clone();
941+
let execution_trace_dir = self.execution_trace_directory.clone();
942+
let coverage = self.coverage.clone();
943+
let symbolic_coverage_directory = self.symbolic_coverage_directory.clone();
944+
// We just fire and forget this thread -- we won't know if it fails but it's basically
945+
// guaranteed not to. This stops us from having to wait every exec to write a huge file.
946+
spawn(move || {
947+
let mut hasher = DefaultHasher::new();
948+
execution_trace.hash(&mut hasher);
949+
let hash = hasher.finish();
950+
951+
if !execution_trace_dir.is_dir() {
952+
create_dir_all(&execution_trace_dir)?;
953+
}
935954

936-
if !self.execution_trace_directory.is_dir() {
937-
create_dir_all(&self.execution_trace_directory)?;
938-
}
955+
let trace_path = execution_trace_dir.join(format!("{:x}.json", hash));
939956

940-
let trace_path = self
941-
.execution_trace_directory
942-
.join(format!("{:x}.json", hash));
957+
if !trace_path.exists() {
958+
let trace_file = File::create(&trace_path)?;
959+
println!("Saving execution trace to {}", trace_path.display());
960+
to_writer(trace_file, &execution_trace)?;
961+
}
962+
963+
if !symbolic_coverage_directory.is_dir() {
964+
create_dir_all(&symbolic_coverage_directory)?;
965+
}
943966

944-
if !trace_path.exists() {
945-
let trace_file = File::create(trace_path)?;
967+
println!("Saving coverage information to symbolic coverage directory {symbolic_coverage_directory:?}");
968+
coverage.to_html(&symbolic_coverage_directory)?;
946969

947-
to_writer(trace_file, &self.execution_trace)?;
948-
}
970+
Ok::<(), anyhow::Error>(())
971+
});
949972

950973
Ok(())
951974
}

src/os/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22

33
use std::{collections::HashMap, path::PathBuf};
44

5+
use crate::source_cov::lcov::Records;
6+
57
pub mod windows;
68

7-
#[derive(Debug, Clone)]
9+
#[derive(Debug)]
810
pub struct DebugInfoConfig<'a> {
911
pub system: bool,
1012
pub user_debug_info: &'a HashMap<String, Vec<PathBuf>>,
13+
pub coverage: &'a mut Records,
1114
}

src/os/windows/debug_info.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,27 @@ use super::{
2828
};
2929

3030
#[derive(Debug)]
31+
/// Debug info for an executable (which may be a .exe, .sys, etc)
3132
pub struct DebugInfo<'a> {
33+
/// The path to the executable file on the local system
3234
pub exe_path: PathBuf,
35+
/// The path to the PDB file corresponding to the executable on the local system
3336
pub pdb_path: PathBuf,
37+
/// The contents of the executable file
3438
pub exe_file_contents: Vec<u8>,
39+
/// The loaded PDB info
3540
pub pdb: PDB<'a, File>,
3641
}
3742

3843
impl<'a> DebugInfo<'a> {
44+
/// Instantiate a new debug info for an object
3945
pub fn new<P>(
4046
processor: *mut ConfObject,
4147
name: &str,
4248
base: u64,
4349
download_directory: P,
4450
not_found_full_name_cache: &mut HashSet<String>,
45-
user_debug_info: DebugInfoConfig,
51+
user_debug_info: &DebugInfoConfig,
4652
) -> Result<Option<Self>>
4753
where
4854
P: AsRef<Path>,
@@ -175,6 +181,7 @@ impl<'a> DebugInfo<'a> {
175181
}
176182
}
177183

184+
/// Instantiate a new debug info for an object with a specific directory table base
178185
pub fn new_dtb<P>(
179186
processor: *mut ConfObject,
180187
name: &str,
@@ -325,26 +332,36 @@ impl<'a> DebugInfo<'a> {
325332
}
326333
}
327334

335+
/// Return the parsed PE file
328336
pub fn exe(&self) -> Result<PE<'_>> {
329337
PE::parse(&self.exe_file_contents)
330338
.map_err(move |e| anyhow!("Failed to parse PE file: {}", e))
331339
}
332340

341+
/// Get a list of exports from the PE file
333342
pub fn exports(&self) -> Result<Vec<Export>> {
334343
Ok(self.exe()?.exports.iter().map(Export::from).collect())
335344
}
336345
}
337346

338347
#[derive(Debug)]
348+
/// A module (or object) loaded in a specific process
339349
pub struct ProcessModule {
350+
/// The base of the object
340351
pub base: u64,
352+
/// The size of the object
341353
pub size: u64,
354+
/// The full name (typically a path) of the object on disk
342355
pub full_name: String,
356+
/// The base name of the object
343357
pub base_name: String,
358+
/// Loaded debug info for the object
344359
pub debug_info: Option<DebugInfo<'static>>,
345360
}
346361

347362
impl ProcessModule {
363+
/// Return lookup intervals for symbols in the process module which can be used to build
364+
/// an interval tree
348365
pub fn intervals(
349366
&mut self,
350367
source_cache: &SourceCache,
@@ -452,14 +469,20 @@ impl ProcessModule {
452469
}
453470

454471
#[derive(Debug)]
472+
/// A process
455473
pub struct Process {
474+
/// The unique PID of the process
456475
pub pid: u64,
476+
/// The file name of the process's main object
457477
pub file_name: String,
478+
/// The base address of the process's main object
458479
pub base_address: u64,
480+
/// The list of modules/objects loaded into the process's address space
459481
pub modules: Vec<ProcessModule>,
460482
}
461483

462484
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
485+
/// Information about a line in a source file from a PDB
463486
pub struct LineInfo {
464487
/// The relative virtual address in the executable image
465488
pub rva: u64,
@@ -475,12 +498,19 @@ pub struct LineInfo {
475498
}
476499

477500
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
501+
/// Information about a symbol in a PDB, including the member lines of the symbol, if any.
478502
pub struct SymbolInfo {
503+
/// The relative virtual address in the executable image
479504
pub rva: u64,
505+
/// The base address of the executable image
480506
pub base: u64,
507+
/// The size of the symbol (e.g. function size)
481508
pub size: u64,
509+
/// The (possibly mangled) name of the symbol
482510
pub name: String,
511+
/// The name of the module the symbol is in
483512
pub module: String,
513+
/// The source lines of code for the symbol
484514
pub lines: Vec<LineInfo>,
485515
}
486516

@@ -505,16 +535,24 @@ impl SymbolInfo {
505535
}
506536

507537
#[derive(Debug)]
538+
/// A kernel module/driver
508539
pub struct Module {
540+
/// The base address of the module
509541
pub base: u64,
542+
/// The entrypoint of the module
510543
pub entry: u64,
544+
/// The size of the module
511545
pub size: u64,
546+
/// The full name of the module
512547
pub full_name: String,
548+
/// The base name of the module
513549
pub base_name: String,
550+
/// The loaded debug info for the module
514551
pub debug_info: Option<DebugInfo<'static>>,
515552
}
516553

517554
impl Module {
555+
/// Return lookup intervals for symbols in the module which can be used to build an interval tree
518556
pub fn intervals(
519557
&mut self,
520558
source_cache: &SourceCache,

src/os/windows/idt.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#[repr(C)] // NOTE: Without repr(C) alignment causes corruption
22
#[derive(Debug, Clone)]
3-
// NOTE: The vergilius generated struct is incorrectly sized
3+
// NOTE: The vergilius generated struct is incorrectly sized so we use this one
44
pub struct IdtEntry64 {
55
offset_low: u16,
66
selector: u16,

0 commit comments

Comments
 (0)