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::__private::ser::FlatMapSerializer;
8use serde_json::Value;
9use std::borrow::Cow::{self, Borrowed, Owned};
10use std::fmt::{Debug, Display};
11use std::io;
12use std::io::Write;
13use std::time::Duration;
14use syscalls::Sysno;
15
16#[derive(Debug)]
17pub struct SyscallInfo {
18 pub typ: &'static str,
19 pub pid: Pid,
20 pub syscall: Sysno,
21 pub args: SyscallArgs,
22 pub result: RetCode,
23 pub duration: Duration,
24}
25
26impl SyscallInfo {
27 pub fn new(
28 pid: Pid,
29 syscall: Sysno,
30 ret_code: RetCode,
31 registers: user_regs_struct,
32 duration: Duration,
33 ) -> Self {
34 Self {
35 typ: "SYSCALL",
36 pid,
37 syscall,
38 args: parse_args(pid, syscall, registers),
39 result: ret_code,
40 duration,
41 }
42 }
43
44 pub fn write_syscall(
45 &self,
46 style: StyleConfig,
47 string_limit: Option<usize>,
48 show_syscall_num: bool,
49 show_duration: bool,
50 output: &mut dyn Write,
51 ) -> anyhow::Result<()> {
52 if style.use_colors {
53 write!(output, "[{}] ", style.pid.apply_to(&self.pid.to_string()))?;
54 } else {
55 write!(output, "[{}] ", &self.pid)?;
56 }
57 if show_syscall_num {
58 write!(output, "{:>3} ", self.syscall.id())?;
59 }
60 if style.use_colors {
61 let styled = style.syscall.apply_to(self.syscall.to_string());
62 write!(output, "{styled}(")
63 } else {
64 write!(output, "{}(", &self.syscall)
65 }?;
66 for (idx, arg) in self.args.0.iter().enumerate() {
67 if idx > 0 {
68 write!(output, ", ")?;
69 }
70 arg.write(output, string_limit)?;
71 }
72 write!(output, ") = ")?;
73 if self.syscall == Sysno::exit || self.syscall == Sysno::exit_group {
74 write!(output, "?")?;
75 } else {
76 if style.use_colors {
77 let style = style.from_ret_code(self.result);
78 write!(output, "{}", style.apply_to(self.result.to_string()))
83 } else {
84 write!(output, "{}", self.result)
85 }?;
86 if show_duration {
87 write!(output, " <{:.6}ns>", self.duration.as_nanos())?;
89 }
90 }
91 Ok(writeln!(output)?)
92 }
93}
94
95impl Serialize for SyscallInfo {
96 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
97 let mut map = serializer.serialize_map(Some(7))?;
98 map.serialize_entry("type", &self.typ)?;
99 map.serialize_entry("pid", &self.pid.as_raw())?;
100 map.serialize_entry("num", &self.syscall)?;
101 map.serialize_entry("syscall", &self.syscall.to_string())?;
102 map.serialize_entry("args", &self.args)?;
103 Serialize::serialize(&self.result, FlatMapSerializer(&mut map))?;
104 map.serialize_entry("duration", &self.duration.as_secs_f64())?;
105 map.end()
106 }
107}
108
109#[derive(Debug)]
110pub struct SyscallArgs(pub Vec<SyscallArg>);
111
112impl Serialize for SyscallArgs {
113 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
114 let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
115 for arg in &self.0 {
116 let value = match arg {
117 SyscallArg::Int(v) => serde_json::to_value(v).unwrap(),
118 SyscallArg::Str(v) => serde_json::to_value(v).unwrap(),
119 SyscallArg::Addr(v) => Value::String(format!("{v:#x}")),
120 };
121 seq.serialize_element(&value)?;
122 }
123 seq.end()
124 }
125}
126
127#[derive(Debug, Copy, Clone, Serialize)]
128pub enum RetCode {
129 #[serde(rename = "success")]
130 Ok(i32),
131 #[serde(rename = "error")]
132 Err(i32),
133 #[serde(rename = "result")]
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}