1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
use crate::cli::Args;
use crate::registers::RegistersData;
use nix::{
sys::{
ptrace,
signal::Signal,
wait::{waitpid, WaitStatus},
},
unistd::Pid,
};
use std::{
fs::File,
io::{self, Write},
os::unix::process::CommandExt,
process::{Command, Stdio},
str,
};
/// Exec the `command` value tracing it with `ptrace` lib
pub fn exec(command: &str) -> anyhow::Result<()> {
let params: Vec<&str> = command.split(' ').collect();
let mut command = Command::new(params[0]);
command.args(params[1..].iter());
command.stdout(Stdio::null());
unsafe {
command.pre_exec(|| ptrace::traceme().map_err(|e| e.into()));
}
command.exec();
Ok(())
}
/// Attach a ptrace status to a `pid`
pub fn attach(pid: Pid) -> anyhow::Result<()> {
ptrace::attach(pid)?;
Ok(())
}
/// Trace a process with `pid` ID and returns a list of `RegistersData`
pub fn trace(pid: Pid, args: &Args) -> anyhow::Result<Vec<RegistersData>> {
// First wait for the parent process
_ = waitpid(pid, None)?;
// FIXME: file writing on attachment
// If `file_to_print` is not None, create a new file with that value for redirecting all the
// output (also in stdout)
let mut f = None;
if let Some(filename) = &args.file_to_print {
f = Some(File::create(filename)?);
}
let mut lines: Vec<RegistersData> = Vec::new();
// Since you have to do 2 syscalls (start and end) you have to alternate the print value,
// because it could be equals except for the `rax` register.
let mut have_to_print = true;
let filters: Vec<&str> = match &args.filter {
Some(filter) => filter.split(",").collect::<Vec<&str>>(),
None => vec![],
};
while let Some(reg) = trace_next(pid)? {
have_to_print ^= true;
if have_to_print {
if !filters.is_empty() && !filters.contains(®.name()) {
continue;
}
if let Some(ref mut f) = f {
writeln!(f, "{}", reg.output())?;
}
if args.no_tui {
writeln!(io::stdout(), "{}", reg.output())?;
}
lines.push(reg);
}
}
Ok(lines)
}
/// Get the next step for a ptrace process
pub fn trace_next(pid: Pid) -> anyhow::Result<Option<RegistersData>> {
ptrace::syscall(pid, None)?;
let status = waitpid(pid, None).unwrap();
match status {
// Match the stopped value for a process
WaitStatus::Stopped(pid, signal) => {
match signal {
Signal::SIGTRAP => {
let reg = RegistersData::new(ptrace::getregs(pid)?);
return Ok(Some(reg));
}
_ => {}
};
}
_ => {}
};
Ok(None)
}
/// Kill a process traced by ptrace
pub fn trace_kill(pid: Pid) -> anyhow::Result<()> {
let _ = ptrace::kill(pid);
Ok(())
}
|