1use num_derive::{FromPrimitive, ToPrimitive};
4use schemars::JsonSchema;
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
8pub struct SigInfo {
9 #[serde(default, skip_serializing_if = "Option::is_none")]
10 pub si_addr: Option<String>,
11 pub si_code: libc::c_int,
12 pub si_code_human_readable: SiCodes,
13 pub si_signo: libc::c_int,
14 pub si_signo_human_readable: SignalNames,
15}
16
17#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
18#[allow(clippy::upper_case_acronyms, non_camel_case_types)]
19#[repr(C)]
20pub enum SignalNames {
22 SIGHUP,
23 SIGINT,
24 SIGQUIT,
25 SIGILL,
26 SIGTRAP,
27 SIGABRT,
28 SIGBUS,
29 SIGFPE,
30 SIGKILL,
31 SIGUSR1,
32 SIGSEGV,
33 SIGUSR2,
34 SIGPIPE,
35 SIGALRM,
36 SIGTERM,
37 SIGCHLD,
38 SIGCONT,
39 SIGSTOP,
40 SIGTSTP,
41 SIGTTIN,
42 SIGTTOU,
43 SIGURG,
44 SIGXCPU,
45 SIGXFSZ,
46 SIGVTALRM,
47 SIGPROF,
48 SIGWINCH,
49 SIGIO,
50 SIGSYS,
51 SIGEMT,
52 SIGINFO,
53 UNKNOWN,
54}
55
56#[cfg(unix)]
57pub use unix::*;
58
59#[cfg(unix)]
60mod unix {
61 use super::*;
62
63 impl From<libc::c_int> for SignalNames {
64 fn from(value: libc::c_int) -> Self {
65 match value {
66 libc::SIGHUP => SignalNames::SIGHUP,
67 libc::SIGINT => SignalNames::SIGINT,
68 libc::SIGQUIT => SignalNames::SIGQUIT,
69 libc::SIGILL => SignalNames::SIGILL,
70 libc::SIGTRAP => SignalNames::SIGTRAP,
71 libc::SIGABRT => SignalNames::SIGABRT,
72 libc::SIGBUS => SignalNames::SIGBUS,
73 libc::SIGFPE => SignalNames::SIGFPE,
74 libc::SIGKILL => SignalNames::SIGKILL,
75 libc::SIGUSR1 => SignalNames::SIGUSR1,
76 libc::SIGSEGV => SignalNames::SIGSEGV,
77 libc::SIGUSR2 => SignalNames::SIGUSR2,
78 libc::SIGPIPE => SignalNames::SIGPIPE,
79 libc::SIGALRM => SignalNames::SIGALRM,
80 libc::SIGTERM => SignalNames::SIGTERM,
81 libc::SIGCHLD => SignalNames::SIGCHLD,
82 libc::SIGCONT => SignalNames::SIGCONT,
83 libc::SIGSTOP => SignalNames::SIGSTOP,
84 libc::SIGTSTP => SignalNames::SIGTSTP,
85 libc::SIGTTIN => SignalNames::SIGTTIN,
86 libc::SIGTTOU => SignalNames::SIGTTOU,
87 libc::SIGURG => SignalNames::SIGURG,
88 libc::SIGXCPU => SignalNames::SIGXCPU,
89 libc::SIGXFSZ => SignalNames::SIGXFSZ,
90 libc::SIGVTALRM => SignalNames::SIGVTALRM,
91 libc::SIGPROF => SignalNames::SIGPROF,
92 libc::SIGWINCH => SignalNames::SIGWINCH,
93 libc::SIGIO => SignalNames::SIGIO,
94 libc::SIGSYS => SignalNames::SIGSYS,
95 #[cfg(not(any(
96 target_os = "android",
97 target_os = "emscripten",
98 target_os = "fuchsia",
99 target_os = "linux",
100 target_os = "redox",
101 target_os = "haiku"
102 )))]
103 libc::SIGEMT => SignalNames::SIGEMT,
104 #[cfg(not(any(
105 target_os = "android",
106 target_os = "emscripten",
107 target_os = "fuchsia",
108 target_os = "linux",
109 target_os = "redox",
110 target_os = "haiku",
111 target_os = "aix"
112 )))]
113 libc::SIGINFO => SignalNames::SIGINFO,
114 _ => SignalNames::UNKNOWN,
115 }
116 }
117 }
118
119 extern "C" {
120 fn translate_si_code_impl(signum: libc::c_int, si_code: libc::c_int) -> libc::c_int;
123 }
124
125 pub fn translate_si_code(signum: libc::c_int, si_code: libc::c_int) -> SiCodes {
126 use num_traits::FromPrimitive;
127 let translated = unsafe { translate_si_code_impl(signum, si_code) };
129 SiCodes::from_i32(translated).unwrap_or(SiCodes::UNKNOWN)
130 }
131
132 #[cfg(test)]
133 #[cfg_attr(miri, ignore)]
134 #[test]
135 fn test_si_code() {
136 assert_eq!(translate_si_code(libc::SIGSEGV, 2), SiCodes::SEGV_ACCERR);
140
141 assert_eq!(translate_si_code(libc::SIGSEGV, 42), SiCodes::UNKNOWN);
143 }
144
145 impl From<nix::sys::signal::Signal> for SignalNames {
146 fn from(value: nix::sys::signal::Signal) -> Self {
147 match value {
148 nix::sys::signal::Signal::SIGHUP => SignalNames::SIGHUP,
149 nix::sys::signal::Signal::SIGINT => SignalNames::SIGINT,
150 nix::sys::signal::Signal::SIGQUIT => SignalNames::SIGQUIT,
151 nix::sys::signal::Signal::SIGILL => SignalNames::SIGILL,
152 nix::sys::signal::Signal::SIGTRAP => SignalNames::SIGTRAP,
153 nix::sys::signal::Signal::SIGABRT => SignalNames::SIGABRT,
154 nix::sys::signal::Signal::SIGBUS => SignalNames::SIGBUS,
155 nix::sys::signal::Signal::SIGFPE => SignalNames::SIGFPE,
156 nix::sys::signal::Signal::SIGKILL => SignalNames::SIGKILL,
157 nix::sys::signal::Signal::SIGUSR1 => SignalNames::SIGUSR1,
158 nix::sys::signal::Signal::SIGSEGV => SignalNames::SIGSEGV,
159 nix::sys::signal::Signal::SIGUSR2 => SignalNames::SIGUSR2,
160 nix::sys::signal::Signal::SIGPIPE => SignalNames::SIGPIPE,
161 nix::sys::signal::Signal::SIGALRM => SignalNames::SIGALRM,
162 nix::sys::signal::Signal::SIGTERM => SignalNames::SIGTERM,
163 nix::sys::signal::Signal::SIGCHLD => SignalNames::SIGCHLD,
164 nix::sys::signal::Signal::SIGCONT => SignalNames::SIGCONT,
165 nix::sys::signal::Signal::SIGSTOP => SignalNames::SIGSTOP,
166 nix::sys::signal::Signal::SIGTSTP => SignalNames::SIGTSTP,
167 nix::sys::signal::Signal::SIGTTIN => SignalNames::SIGTTIN,
168 nix::sys::signal::Signal::SIGTTOU => SignalNames::SIGTTOU,
169 nix::sys::signal::Signal::SIGURG => SignalNames::SIGURG,
170 nix::sys::signal::Signal::SIGXCPU => SignalNames::SIGXCPU,
171 nix::sys::signal::Signal::SIGXFSZ => SignalNames::SIGXFSZ,
172 nix::sys::signal::Signal::SIGVTALRM => SignalNames::SIGVTALRM,
173 nix::sys::signal::Signal::SIGPROF => SignalNames::SIGPROF,
174 nix::sys::signal::Signal::SIGWINCH => SignalNames::SIGWINCH,
175 nix::sys::signal::Signal::SIGIO => SignalNames::SIGIO,
176 nix::sys::signal::Signal::SIGSYS => SignalNames::SIGSYS,
177 #[cfg(not(any(
178 target_os = "android",
179 target_os = "emscripten",
180 target_os = "fuchsia",
181 target_os = "linux",
182 target_os = "redox",
183 target_os = "haiku"
184 )))]
185 nix::sys::signal::Signal::SIGEMT => SignalNames::SIGEMT,
186 #[cfg(not(any(
187 target_os = "android",
188 target_os = "emscripten",
189 target_os = "fuchsia",
190 target_os = "linux",
191 target_os = "redox",
192 target_os = "haiku",
193 target_os = "aix"
194 )))]
195 nix::sys::signal::Signal::SIGINFO => SignalNames::SIGINFO,
196 _ => SignalNames::UNKNOWN,
197 }
198 }
199 }
200
201 pub fn signal_from_signum(value: libc::c_int) -> anyhow::Result<nix::sys::signal::Signal> {
203 let rval = match value {
204 libc::SIGHUP => nix::sys::signal::Signal::SIGHUP,
205 libc::SIGINT => nix::sys::signal::Signal::SIGINT,
206 libc::SIGQUIT => nix::sys::signal::Signal::SIGQUIT,
207 libc::SIGILL => nix::sys::signal::Signal::SIGILL,
208 libc::SIGTRAP => nix::sys::signal::Signal::SIGTRAP,
209 libc::SIGABRT => nix::sys::signal::Signal::SIGABRT,
210 libc::SIGBUS => nix::sys::signal::Signal::SIGBUS,
211 libc::SIGFPE => nix::sys::signal::Signal::SIGFPE,
212 libc::SIGKILL => nix::sys::signal::Signal::SIGKILL,
213 libc::SIGUSR1 => nix::sys::signal::Signal::SIGUSR1,
214 libc::SIGSEGV => nix::sys::signal::Signal::SIGSEGV,
215 libc::SIGUSR2 => nix::sys::signal::Signal::SIGUSR2,
216 libc::SIGPIPE => nix::sys::signal::Signal::SIGPIPE,
217 libc::SIGALRM => nix::sys::signal::Signal::SIGALRM,
218 libc::SIGTERM => nix::sys::signal::Signal::SIGTERM,
219 libc::SIGCHLD => nix::sys::signal::Signal::SIGCHLD,
220 libc::SIGCONT => nix::sys::signal::Signal::SIGCONT,
221 libc::SIGSTOP => nix::sys::signal::Signal::SIGSTOP,
222 libc::SIGTSTP => nix::sys::signal::Signal::SIGTSTP,
223 libc::SIGTTIN => nix::sys::signal::Signal::SIGTTIN,
224 libc::SIGTTOU => nix::sys::signal::Signal::SIGTTOU,
225 libc::SIGURG => nix::sys::signal::Signal::SIGURG,
226 libc::SIGXCPU => nix::sys::signal::Signal::SIGXCPU,
227 libc::SIGXFSZ => nix::sys::signal::Signal::SIGXFSZ,
228 libc::SIGVTALRM => nix::sys::signal::Signal::SIGVTALRM,
229 libc::SIGPROF => nix::sys::signal::Signal::SIGPROF,
230 libc::SIGWINCH => nix::sys::signal::Signal::SIGWINCH,
231 libc::SIGIO => nix::sys::signal::Signal::SIGIO,
232 libc::SIGSYS => nix::sys::signal::Signal::SIGSYS,
233 #[cfg(not(any(
234 target_os = "android",
235 target_os = "emscripten",
236 target_os = "fuchsia",
237 target_os = "linux",
238 target_os = "redox",
239 target_os = "haiku"
240 )))]
241 libc::SIGEMT => nix::sys::signal::Signal::SIGEMT,
242 #[cfg(not(any(
243 target_os = "android",
244 target_os = "emscripten",
245 target_os = "fuchsia",
246 target_os = "linux",
247 target_os = "redox",
248 target_os = "haiku",
249 target_os = "aix"
250 )))]
251 libc::SIGINFO => nix::sys::signal::Signal::SIGINFO,
252 _ => anyhow::bail!("Unexpected signal number {value}"),
253 };
254 Ok(rval)
255 }
256}
257
258#[derive(
259 Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, FromPrimitive, ToPrimitive,
260)]
261#[allow(clippy::upper_case_acronyms, non_camel_case_types)]
262#[repr(C)]
263pub enum SiCodes {
266 BUS_ADRALN,
267 BUS_ADRERR,
268 BUS_MCEERR_AO,
269 BUS_MCEERR_AR,
270 BUS_OBJERR,
271 ILL_BADSTK,
272 ILL_COPROC,
273 ILL_ILLADR,
274 ILL_ILLOPC,
275 ILL_ILLOPN,
276 ILL_ILLTRP,
277 ILL_PRVOPC,
278 ILL_PRVREG,
279 SEGV_ACCERR,
280 SEGV_BNDERR,
281 SEGV_MAPERR,
282 SEGV_PKUERR,
283 SI_ASYNCIO,
284 SI_KERNEL,
285 SI_MESGQ,
286 SI_QUEUE,
287 SI_SIGIO,
288 SI_TIMER,
289 SI_TKILL,
290 SI_USER,
291 SYS_SECCOMP,
292 UNKNOWN,
293}
294
295#[cfg(test)]
296impl SigInfo {
297 pub fn test_instance(_seed: u64) -> Self {
298 Self {
299 si_addr: Some("0x0000000000001234".to_string()),
300 si_code: 1,
301 si_code_human_readable: SiCodes::SEGV_BNDERR,
302 si_signo: 11,
303 si_signo_human_readable: SignalNames::SIGSEGV,
304 }
305 }
306}