1use crate::arch::parse_args;
2use crate::style::StyleConfig;
3use libc::{c_ulonglong, user_regs_struct};
4use nix::unistd::Pid;
5use serde::ser::{SerializeMap, SerializeSeq};
6use serde::Serialize;
7use serde_json::Value;
8use std::borrow::Cow::{self, Borrowed, Owned};
9use std::fmt::{Debug, Display};
10use std::io;
11use std::io::Write;
12use std::time::Duration;
13use syscalls::Sysno;
14
15#[derive(Debug)]
16pub struct SyscallInfo {
17 pub typ: &'static str,
18 pub pid: Pid,
19 pub syscall: Sysno,
20 pub args: SyscallArgs,
21 pub result: RetCode,
22 pub duration: Duration,
23}
24
25impl SyscallInfo {
26 pub fn new(
27 pid: Pid,
28 syscall: Sysno,
29 ret_code: RetCode,
30 registers: user_regs_struct,
31 duration: Duration,
32 ) -> Self {
33 Self {
34 typ: "SYSCALL",
35 pid,
36 syscall,
37 args: parse_args(pid, syscall, registers),
38 result: ret_code,
39 duration,
40 }
41 }
42
43 pub fn write_syscall(
44 &self,
45 style: StyleConfig,
46 string_limit: Option<usize>,
47 show_syscall_num: bool,
48 show_duration: bool,
49 output: &mut dyn Write,
50 ) -> anyhow::Result<()> {
51 if style.use_colors {
52 write!(output, "[{}] ", style.pid.apply_to(&self.pid.to_string()))?;
53 } else {
54 write!(output, "[{}] ", &self.pid)?;
55 }
56 if show_syscall_num {
57 write!(output, "{:>3} ", self.syscall.id())?;
58 }
59 if style.use_colors {
60 let styled = style.syscall.apply_to(self.syscall.to_string());
61 write!(output, "{styled}(")
62 } else {
63 write!(output, "{}(", &self.syscall)
64 }?;
65 for (idx, arg) in self.args.0.iter().enumerate() {
66 if idx > 0 {
67 write!(output, ", ")?;
68 }
69 arg.write(output, string_limit)?;
70 }
71 write!(output, ") = ")?;
72 if self.syscall == Sysno::exit || self.syscall == Sysno::exit_group {
73 write!(output, "?")?;
74 } else {
75 if style.use_colors {
76 let style = style.from_ret_code(self.result);
77 write!(output, "{}", style.apply_to(self.result.to_string()))
82 } else {
83 write!(output, "{}", self.result)
84 }?;
85 if show_duration {
86 write!(output, " <{:.6}ns>", self.duration.as_nanos())?;
88 }
89 }
90 Ok(writeln!(output)?)
91 }
92}
93
94impl Serialize for SyscallInfo {
95 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
96 let mut map = serializer.serialize_map(Some(7))?;
97 map.serialize_entry("type", &self.typ)?;
98 map.serialize_entry("pid", &self.pid.as_raw())?;
99 map.serialize_entry("num", &self.syscall)?;
100 map.serialize_entry("syscall", &self.syscall.to_string())?;
101 map.serialize_entry("args", &self.args)?;
102 match self.result {
103 RetCode::Ok(value) => map.serialize_entry("success", &value)?,
104 RetCode::Err(value) => map.serialize_entry("error", &value)?,
105 RetCode::Address(value) => map.serialize_entry("result", &value)?,
106 }
107 map.serialize_entry("duration", &self.duration.as_secs_f64())?;
108 map.end()
109 }
110}
111
112#[derive(Debug)]
113pub struct SyscallArgs(pub Vec<SyscallArg>);
114
115impl Serialize for SyscallArgs {
116 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
117 let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
118 for arg in &self.0 {
119 let value = match arg {
120 SyscallArg::Int(v) => serde_json::to_value(v).unwrap(),
121 SyscallArg::Str(v) => serde_json::to_value(v).unwrap(),
122 SyscallArg::Addr(v) => Value::String(format!("{v:#x}")),
123 };
124 seq.serialize_element(&value)?;
125 }
126 seq.end()
127 }
128}
129
130#[derive(Debug, Copy, Clone)]
131pub enum RetCode {
132 Ok(i32),
133 Err(i32),
134 Address(usize),
135}
136
137impl RetCode {
138 pub fn from_raw(ret_code: c_ulonglong) -> Self {
139 let ret_i32 = ret_code as isize;
140 if ret_i32.abs() > 0x8000 {
142 Self::Address(ret_code as usize)
143 } else if ret_i32 < 0 {
144 Self::Err(ret_i32 as i32)
145 } else {
146 Self::Ok(ret_i32 as i32)
147 }
148 }
149}
150
151impl Display for RetCode {
152 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153 match self {
154 Self::Ok(v) | Self::Err(v) => Display::fmt(v, f),
155 Self::Address(v) => write!(f, "{v:#X}"),
156 }
157 }
158}
159
160#[derive(Debug, Serialize)]
161pub enum SyscallArg {
162 Int(i64),
163 Str(String),
164 Addr(usize),
165}
166
167impl SyscallArg {
168 pub fn write(&self, f: &mut dyn Write, string_limit: Option<usize>) -> io::Result<()> {
169 match self {
170 Self::Int(v) => write!(f, "{v}"),
171 Self::Str(v) => {
172 let value: Value = match string_limit {
173 Some(width) => trim_str(v, width),
174 None => Borrowed(v.as_ref()),
175 }
176 .into();
177 write!(f, "{value}")
178 }
179 Self::Addr(v) => write!(f, "{v:#X}"),
180 }
181 }
182}
183
184fn trim_str(string: &str, limit: usize) -> Cow<'_, str> {
185 match string.chars().as_str().get(..limit) {
186 None => Borrowed(string),
187 Some(s) => Owned(format!("{s}...")),
188 }
189}