Skip to content

Commit

Permalink
refactor/tracer: use OutputMsg for filename and cwd
Browse files Browse the repository at this point in the history
  • Loading branch information
kxxt committed Sep 2, 2024
1 parent 406bc6f commit bdd1ba0
Show file tree
Hide file tree
Showing 11 changed files with 130 additions and 148 deletions.
2 changes: 1 addition & 1 deletion src/bpf/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub struct Path {
segments: Vec<OutputMsg>,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(u8)]
pub enum BpfError {
Dropped,
Expand Down
5 changes: 5 additions & 0 deletions src/cli/theme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ pub struct Theme {
pub added_env_var: Style,
pub modified_env_key: Style,
pub modified_env_val: Style,
// Info
pub filename: Style,
pub cwd: Style,
}

impl Default for Theme {
Expand All @@ -21,6 +24,8 @@ impl Default for Theme {
added_env_var: Style::new().green(),
modified_env_key: Style::new().yellow(),
modified_env_val: Style::new().bright_blue(),
filename: Style::new(),
cwd: Style::new().bright_cyan(),
}
}
}
Expand Down
45 changes: 22 additions & 23 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ use crate::{
#[cfg(feature = "ebpf")]
use crate::bpf::BpfError;

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u64)]
pub enum FriendlyError {
InspectError(Errno),
Expand Down Expand Up @@ -147,6 +147,20 @@ impl From<ArcStr> for OutputMsg {
}

impl OutputMsg {
pub fn is_ok_and(&self, predicate: impl FnOnce(&str) -> bool) -> bool {
match self {
OutputMsg::Ok(s) => predicate(&s),
OutputMsg::Err(_) => false,
}
}

pub fn is_err_or(&self, predicate: impl FnOnce(&str) -> bool) -> bool {
match self {
OutputMsg::Ok(s) => predicate(&s),
OutputMsg::Err(_) => true,
}
}

/// Escape the content for bash shell if it is not error
pub fn tui_bash_escaped_with_style(&self, style: Style) -> Span<'static> {
match self {
Expand Down Expand Up @@ -307,9 +321,9 @@ pub struct TracerEventMessage {
#[derive(Debug, Clone, PartialEq)]
pub struct ExecEvent {
pub pid: Pid,
pub cwd: PathBuf,
pub cwd: OutputMsg,
pub comm: ArcStr,
pub filename: Result<PathBuf, InspectError>,
pub filename: OutputMsg,
pub argv: Arc<Result<Vec<OutputMsg>, InspectError>>,
pub envp: Arc<Result<BTreeMap<OutputMsg, OutputMsg>, InspectError>>,
pub interpreter: Option<Vec<Interpreter>>,
Expand Down Expand Up @@ -454,9 +468,7 @@ impl TracerEventDetails {
// Handle argv[0]
let _ = argv.as_deref().inspect(|v| {
v.first().inspect(|&arg0| {
if filename.is_ok()
&& filename.as_ref().unwrap().as_os_str() != OsStr::new(arg0.as_ref())
{
if filename != arg0 {
spans.push(space.clone());
spans.push("-a ".set_style(THEME.arg0));
spans.push(arg0.tui_bash_escaped_with_style(THEME.arg0));
Expand All @@ -467,7 +479,8 @@ impl TracerEventDetails {
if cwd != &baseline.cwd && rt_modifier_effective.show_cwd {
cwd_range = Some(spans.len()..(spans.len() + 2));
spans.push(space.clone());
spans.push(format!("-C {}", escape_str_for_bash!(cwd)).set_style(THEME.cwd));
spans.push("-C ".set_style(THEME.cwd));
spans.push(cwd.tui_bash_escaped_with_style(THEME.cwd));
}
if rt_modifier_effective.show_env {
env_range = Some((spans.len(), 0));
Expand Down Expand Up @@ -499,14 +512,7 @@ impl TracerEventDetails {
}
spans.push(space.clone());
// Filename
match filename {
Ok(filename) => {
spans.push(escape_str_for_bash!(filename).set_style(THEME.filename));
}
Err(_) => {
spans.push("[failed to read filename]".set_style(THEME.inline_tracer_error));
}
}
spans.push(filename.tui_bash_escaped_with_style(THEME.filename));
// Argv[1..]
match argv.as_ref() {
Ok(argv) => {
Expand Down Expand Up @@ -725,19 +731,12 @@ impl TracerEventDetails {
result.into()
}
CopyTarget::Argv => Self::argv_to_string(&event.argv).into(),
CopyTarget::Filename => Self::filename_to_cow(&event.filename),
CopyTarget::Filename => Cow::Borrowed(event.filename.as_ref()),
CopyTarget::SyscallResult => event.result.to_string().into(),
CopyTarget::Line => unreachable!(),
}
}

pub fn filename_to_cow(filename: &Result<PathBuf, InspectError>) -> Cow<str> {
match filename {
Ok(filename) => filename.to_string_lossy(),
Err(_) => "[failed to read filename]".into(),
}
}

pub fn argv_to_string(argv: &Result<Vec<OutputMsg>, InspectError>) -> String {
let Ok(argv) = argv else {
return "[failed to read argv]".into();
Expand Down
6 changes: 3 additions & 3 deletions src/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ impl<T: Serialize + Clone> JsonResult<T> {
pub struct JsonExecEvent {
pub id: u64,
pub pid: pid_t,
pub cwd: PathBuf,
pub cwd: OutputMsg,
pub comm_before_exec: ArcStr,
pub result: i64,
pub filename: JsonResult<PathBuf>,
pub filename: OutputMsg,
pub argv: JsonResult<Vec<OutputMsg>>,
pub env: JsonResult<EnvDiff>,
pub fdinfo: FileDescriptorInfoCollection,
Expand All @@ -53,7 +53,7 @@ impl JsonExecEvent {
cwd: event.cwd,
comm_before_exec: event.comm,
result: event.result,
filename: JsonResult::from_result(event.filename),
filename: event.filename,
argv: JsonResult::from_result(Arc::unwrap_or_clone(event.argv)),
env: JsonResult::from_result(event.env_diff),
fdinfo: Arc::unwrap_or_clone(event.fdinfo),
Expand Down
87 changes: 33 additions & 54 deletions src/printer.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use std::{
cell::RefCell,
collections::BTreeMap,
ffi::OsStr,
fmt::{Debug, Display},
io::{self, Write},
path::Path,
sync::Arc,
};

Expand All @@ -13,12 +11,9 @@ use crate::{
args::{LogModeArgs, ModifierArgs},
theme::THEME,
},
event::{OutputMsg, TracerEventDetails},
event::{FriendlyError, OutputMsg},
proc::{diff_env, BaselineInfo, FileDescriptorInfoCollection, Interpreter},
tracer::{
state::{ExecData, ProcessState},
InspectError,
},
tracer::state::{ExecData, ProcessState},
};

use arcstr::ArcStr;
Expand Down Expand Up @@ -134,9 +129,9 @@ pub type PrinterOut = dyn Write + Send + Sync + 'static;

enum DeferredWarningKind {
NoArgv0,
FailedReadingArgv(InspectError),
FailedReadingFilename(InspectError),
FailedReadingEnvp(InspectError),
FailedReadingArgv(FriendlyError),
FailedReadingFilename(FriendlyError),
FailedReadingEnvp(FriendlyError),
}

struct DeferredWarnings {
Expand Down Expand Up @@ -409,7 +404,7 @@ impl Printer {
result: i64,
exec_data: &ExecData,
env: &BTreeMap<OutputMsg, OutputMsg>,
cwd: &Path,
cwd: &OutputMsg,
) -> color_eyre::Result<()> {
// Preconditions:
// 1. execve syscall exit, which leads to 2
Expand All @@ -435,32 +430,24 @@ impl Printer {
}
write!(out, ":")?;

match exec_data.filename.as_ref() {
Ok(filename) => {
if self.args.trace_filename {
write!(out, " {:?}", filename)?;
}
}
Err(e) => {
write!(
out,
" {}",
format!("[Failed to read filename: {e}]")
.bright_red()
.blink()
.bold()
)?;
_deferred_warnings.push(DeferredWarnings {
warning: DeferredWarningKind::FailedReadingFilename(*e),
pid,
});
}
if self.args.trace_filename {
write!(
out,
" {}",
exec_data.filename.cli_escaped_styled(THEME.filename)
)?;
}
if let OutputMsg::Err(e) = exec_data.filename {
_deferred_warnings.push(DeferredWarnings {
warning: DeferredWarningKind::FailedReadingFilename(e),
pid,
});
}

match exec_data.argv.as_ref() {
Err(e) => {
_deferred_warnings.push(DeferredWarnings {
warning: DeferredWarningKind::FailedReadingArgv(*e),
warning: DeferredWarningKind::FailedReadingArgv(FriendlyError::InspectError(*e)),
pid,
});
}
Expand Down Expand Up @@ -598,7 +585,7 @@ impl Printer {
EnvPrintFormat::None => {}
}
_deferred_warnings.push(DeferredWarnings {
warning: DeferredWarningKind::FailedReadingEnvp(*e),
warning: DeferredWarningKind::FailedReadingEnvp(FriendlyError::InspectError(*e)),
pid,
});
}
Expand Down Expand Up @@ -695,31 +682,29 @@ impl Printer {
Ok(argv) => {
if let Some(arg0) = argv.first() {
// filename warning is already handled
if let Ok(filename) = exec_data.filename.as_ref() {
if filename.as_os_str() != OsStr::new(arg0.as_ref()) {
write!(
out,
" {} {}",
"-a".bright_white().italic(),
escape_str_for_bash!(arg0.as_ref()).bright_white().italic()
)?;
}
if &exec_data.filename != arg0 {
write!(
out,
" {} {}",
"-a".bright_white().italic(),
escape_str_for_bash!(arg0.as_ref()).bright_white().italic()
)?;
}
} else {
_deferred_warnings.push(DeferredWarnings {
warning: DeferredWarningKind::NoArgv0,
pid,
});
}
if cwd != exec_data.cwd {
if cwd != &exec_data.cwd {
if self.args.color >= ColorLevel::Normal {
write!(
out,
" -C {}",
escape_str_for_bash!(&exec_data.cwd).bright_cyan()
&exec_data.cwd.cli_bash_escaped_with_style(THEME.cwd)
)?;
} else {
write!(out, " -C {}", escape_str_for_bash!(&exec_data.cwd))?;
write!(out, " -C {}", exec_data.cwd.bash_escaped())?;
}
}
// envp warning is already handled
Expand Down Expand Up @@ -763,21 +748,15 @@ impl Printer {
}
}
}
write!(
out,
" {}",
escape_str_for_bash!(
TracerEventDetails::filename_to_cow(&exec_data.filename).as_ref()
)
)?;
write!(out, " {}", exec_data.filename.bash_escaped())?;
for arg in argv.iter().skip(1) {
// TODO: don't escape err msg
write!(out, " {}", escape_str_for_bash!(arg.as_ref()))?;
write!(out, " {}", arg.bash_escaped())?;
}
}
Err(e) => {
_deferred_warnings.push(DeferredWarnings {
warning: DeferredWarningKind::FailedReadingArgv(*e),
warning: DeferredWarningKind::FailedReadingArgv(FriendlyError::InspectError(*e)),
pid,
});
}
Expand Down
21 changes: 10 additions & 11 deletions src/proc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,16 @@ pub fn read_comm(pid: Pid) -> color_eyre::Result<ArcStr> {
Ok(cache.get_or_insert(&utf8))
}

pub fn read_cwd(pid: Pid) -> std::io::Result<PathBuf> {
pub fn read_cwd(pid: Pid) -> std::io::Result<ArcStr> {
let filename = format!("/proc/{pid}/cwd");
let buf = std::fs::read_link(filename)?;
Ok(buf)
Ok(cached_str(&buf.to_string_lossy()))
}

pub fn read_exe(pid: Pid) -> std::io::Result<PathBuf> {
pub fn read_exe(pid: Pid) -> std::io::Result<ArcStr> {
let filename = format!("/proc/{pid}/exe");
let buf = std::fs::read_link(filename)?;
Ok(buf)
Ok(cached_str(&buf.to_string_lossy()))
}

#[derive(Debug, Clone, Default, PartialEq, Serialize)]
Expand Down Expand Up @@ -148,12 +148,12 @@ impl Default for FileDescriptorInfo {
}
}

pub fn read_fd(pid: Pid, fd: i32) -> std::io::Result<PathBuf> {
pub fn read_fd(pid: Pid, fd: i32) -> std::io::Result<ArcStr> {
if fd == AT_FDCWD {
return read_cwd(pid);
}
let filename = format!("/proc/{pid}/fd/{fd}");
std::fs::read_link(filename)
Ok(cached_str(&std::fs::read_link(filename)?.to_string_lossy()))
}

/// Read /proc/{pid}/fdinfo/{fd} to get more information about the file descriptor.
Expand All @@ -180,8 +180,7 @@ pub fn read_fdinfo(pid: Pid, fd: i32) -> color_eyre::Result<FileDescriptorInfo>
}
}
info.mnt = get_mountinfo_by_mnt_id(pid, info.mnt_id)?;
let mut cache = CACHE.write().unwrap();
info.path = cache.get_or_insert(&read_fd(pid, fd)?.to_string_lossy());
info.path = read_fd(pid, fd)?;
Ok(info)
}

Expand Down Expand Up @@ -400,14 +399,14 @@ pub fn diff_env(

#[derive(Debug, Clone, Serialize)]
pub struct BaselineInfo {
pub cwd: PathBuf,
pub cwd: OutputMsg,
pub env: BTreeMap<OutputMsg, OutputMsg>,
pub fdinfo: FileDescriptorInfoCollection,
}

impl BaselineInfo {
pub fn new() -> color_eyre::Result<Self> {
let cwd = std::env::current_dir()?;
let cwd = cached_str(&std::env::current_dir()?.to_string_lossy()).into();
let env = std::env::vars()
.map(|(k, v)| {
let mut cache = CACHE.write().unwrap();
Expand All @@ -422,7 +421,7 @@ impl BaselineInfo {
}

pub fn with_pts(pts: &UnixSlavePty) -> color_eyre::Result<Self> {
let cwd = std::env::current_dir()?;
let cwd = cached_str(&std::env::current_dir()?.to_string_lossy()).into();
let env = std::env::vars()
.map(|(k, v)| {
let mut cache = CACHE.write().unwrap();
Expand Down
Loading

0 comments on commit bdd1ba0

Please sign in to comment.