use crate::value::map_output;
use crate::value::Value;
use crate::Ident;
use crate::SyscallParameters;
use crate::{Definition, SyscallError};
use colored::Colorize;
use std::fmt;
pub struct TraceOutput {
pub pid: usize,
pub nr: usize,
pub ident: Ident,
pub variables: Vec<Value>,
pub out: Option<Result<Value, SyscallError>>,
}
impl TraceOutput {
pub(crate) fn new(ident: Ident, nr: usize, variables: Vec<Value>, pid: usize) -> Self {
TraceOutput {
ident,
nr,
variables,
out: None,
pid,
}
}
pub(crate) fn from_definition<T>(
ptrace: &mut T,
definition: &Definition,
info: &SyscallParameters,
) -> Self
where
T: crate::Tracer,
{
let mut variables: Vec<Value> = Vec::new();
for _ in 0..definition.var_types.len() {
variables.push(Value::None);
}
for (idx, var_type) in definition.var_types.iter().enumerate().rev() {
let mapped_val = info.transform_value(idx, ptrace, var_type, &variables);
variables[idx] = mapped_val;
}
TraceOutput::new(definition.ident, info.nr, variables, info.pid)
}
pub(crate) fn update_exit<T>(&mut self, ptrace: &mut T, info: &SyscallParameters)
where
T: crate::Tracer,
{
let definition = info.get_definition().unwrap();
self.out = Some(map_output(
&definition.out_value,
info.exit.is_error,
info.exit.rval,
));
let mut updated_variables: Vec<Option<Value>> = Vec::with_capacity(self.variables.len());
for idx in 0..self.variables.len() {
let val =
info.transform_value(idx, ptrace, &definition.var_types[idx], &self.variables);
if let Value::Skip = val {
updated_variables.push(None);
} else {
updated_variables.push(Some(val));
}
}
for (idx, transformed_input) in updated_variables.into_iter().enumerate() {
if let Some(input) = transformed_input {
self.variables[idx] = input;
}
}
}
}
impl fmt::Debug for TraceOutput {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let var_strs: Vec<String> = self
.variables
.iter()
.map(|a| format!("{}", format!("{:?}", a).cyan()))
.collect();
let ident_str = match &self.ident {
Ident::Unknown => format!("__unknown"),
_ => format!("{}", self.ident.to_string().to_lowercase()),
}
.yellow();
let out_var = match self.out.as_ref() {
Some(o) => match o {
Ok(o) => format!("{:?}", o).green(),
Err(e) => format!("-1 {:?} ({})", e, e.to_errno().desc()).magenta(),
},
None => format!("?").yellow(),
};
write!(
f,
"[{}] {}{}{}{} = {}", self.pid,
ident_str,
"(".purple(),
var_strs.join(", "),
")".purple(),
out_var,
)
}
}