File scoping and reporting works
This commit is contained in:
parent
6926711e83
commit
62f7e40c64
|
@ -6,7 +6,7 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nix = { version = "0.28.0", features = ["ptrace", "process"] }
|
||||
nix = { version = "0.28.0", features = ["ptrace", "process", "fs"] }
|
||||
linux-personality = "1.0.0"
|
||||
anyhow = { version = "1", features = ["backtrace"] }
|
||||
log = "0.4"
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::{
|
|||
path::PathBuf, borrow::Cow,
|
||||
};
|
||||
|
||||
use gimli::{constants, AttributeValue, DW_TAG_compile_unit};
|
||||
use gimli::{constants, DW_TAG_compile_unit};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{digest::generic_array::{GenericArray, typenum::U32}, Digest, Sha256};
|
||||
use object::{Object, ReadCache, ObjectSection};
|
||||
|
@ -110,7 +110,7 @@ impl FileStore {
|
|||
self.files
|
||||
.get_mut(*e.get())
|
||||
.unwrap()
|
||||
.output_names
|
||||
.input_names
|
||||
.insert(filename.clone());
|
||||
*e.get()
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ impl FileStore {
|
|||
}
|
||||
|
||||
let fp = fs::File::open(&filename)?;
|
||||
self.ingest_output(filename, fp);
|
||||
self.ingest_output(filename, fp)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
48
src/main.rs
48
src/main.rs
|
@ -1,5 +1,6 @@
|
|||
mod tracer;
|
||||
mod filestore;
|
||||
mod reports;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
@ -13,18 +14,30 @@ struct Cli {
|
|||
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
enum Subcommands {
|
||||
/// Run a command and record its execution
|
||||
Run {
|
||||
/// Any number of filepaths to treat as inputs. They will be hashed and accesses to
|
||||
/// equivalent files will be treated specially.
|
||||
#[arg(short, long)]
|
||||
input: Vec<PathBuf>,
|
||||
file_scope: Vec<PathBuf>,
|
||||
|
||||
/// The filepath to dump the json report to. will dump to stdout if unspecified.
|
||||
#[arg(short, long)]
|
||||
output: Option<PathBuf>,
|
||||
|
||||
#[arg(short, long)]
|
||||
mute: bool,
|
||||
|
||||
/// The command to run. Have fun!
|
||||
cmd: Vec<String>,
|
||||
},
|
||||
/// Query from the report how in-scope items were used
|
||||
QueryParameters {
|
||||
/// The filepath of the report ot open. will read from stdin if unspecified.
|
||||
input: Option<PathBuf>,
|
||||
|
||||
/// The filepath to dump the json report to. will dump to stdout if unspecified.
|
||||
output: Option<PathBuf>,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,20 +45,41 @@ fn main() {
|
|||
env_logger::init();
|
||||
let cli = Cli::parse();
|
||||
match cli.cmd {
|
||||
Subcommands::Run { input, output, cmd } => {
|
||||
Subcommands::Run { file_scope, output, cmd, mute } => {
|
||||
let fp: Box<dyn std::io::Write> = if let Some(output) = &output {
|
||||
Box::new(std::fs::File::options().write(true).create(true).open(output).unwrap())
|
||||
} else {
|
||||
Box::new(std::io::stdout())
|
||||
};
|
||||
let mut t = tracer::Tracer::new(input).unwrap();
|
||||
t.start_root_process(cmd).unwrap();
|
||||
let mut t = tracer::Tracer::new(file_scope).unwrap();
|
||||
t.start_root_process(cmd, mute).unwrap();
|
||||
|
||||
if output.is_none() {
|
||||
serde_json::to_writer_pretty(fp, &t.report).unwrap();
|
||||
serde_json::to_writer_pretty(fp, &t.report)
|
||||
} else {
|
||||
serde_json::to_writer(fp, &t.report).unwrap();
|
||||
}
|
||||
serde_json::to_writer(fp, &t.report)
|
||||
}.expect("Could not serialize json trace report");
|
||||
}
|
||||
Subcommands::QueryParameters { input, output } => {
|
||||
let fp: Box<dyn std::io::Write> = if let Some(output) = &output {
|
||||
Box::new(std::fs::File::options().write(true).create(true).open(output).unwrap())
|
||||
} else {
|
||||
Box::new(std::io::stdout())
|
||||
};
|
||||
|
||||
let in_report: tracer::TracerReport = if let Some(input) = &input {
|
||||
serde_json::from_reader(std::fs::File::open(input).unwrap())
|
||||
} else {
|
||||
serde_json::from_reader(std::io::stdin())
|
||||
}.expect("Could not deserialize json trace report");
|
||||
|
||||
let out_report = reports::parameters::run(&in_report).unwrap();
|
||||
|
||||
if output.is_none() {
|
||||
serde_json::to_writer_pretty(fp, &out_report)
|
||||
} else {
|
||||
serde_json::to_writer(fp, &out_report)
|
||||
}.expect("Could not serialize json parameter report");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::{
|
|||
collections::HashMap,
|
||||
ffi::CString,
|
||||
ffi::OsString,
|
||||
os::unix::prelude::OsStringExt,
|
||||
os::{fd::{AsRawFd}, unix::prelude::OsStringExt},
|
||||
path::PathBuf,
|
||||
process::exit,
|
||||
time::{Duration, Instant},
|
||||
|
@ -465,7 +465,7 @@ impl Tracer {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn start_root_process(&mut self, args: Vec<String>) -> anyhow::Result<()> {
|
||||
pub fn start_root_process(&mut self, args: Vec<String>, mute: bool) -> anyhow::Result<()> {
|
||||
log::trace!("start_root_process: {:?}", args);
|
||||
|
||||
if let ForkResult::Parent { child: root_child } = unsafe { nix::unistd::fork()? } {
|
||||
|
@ -633,6 +633,13 @@ impl Tracer {
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
if mute {
|
||||
let null = std::fs::File::options().read(true).write(true).open("/dev/null").expect("Could not open /dev/null");
|
||||
nix::unistd::dup2(null.as_raw_fd(), 0).expect("Could not dup /dev/null to /dev/stdin");
|
||||
nix::unistd::dup2(null.as_raw_fd(), 1).expect("Could not dup /dev/null to /dev/stdout");
|
||||
nix::unistd::dup2(null.as_raw_fd(), 2).expect("Could not dup /dev/null to /dev/stderr");
|
||||
}
|
||||
|
||||
let args = args
|
||||
.into_iter()
|
||||
.map(CString::new)
|
||||
|
|
Loading…
Reference in New Issue