1use crate::cdecls::*;
5
6use std::any::Any;
7use std::ffi::{c_int, c_short, c_void};
8use std::marker::PhantomData;
9use std::mem::MaybeUninit;
10
11#[derive(Debug, Copy, Clone)]
17pub enum UnsupportedSignalError {
18 UnsupportedSigno {
20 signo: c_int,
22 },
23 UnsupportedCode {
25 signo: c_int,
27 code: c_int,
29 },
30}
31
32impl std::fmt::Display for UnsupportedSignalError {
33 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34 match self {
35 UnsupportedSignalError::UnsupportedSigno { signo } => {
36 write!(f, "Unsupported signal number: signo={}", signo)
37 }
38 UnsupportedSignalError::UnsupportedCode { signo, code } => {
39 write!(f, "Unsupported signal code: signo={}, code={}", signo, code)
40 }
41 }
42 }
43}
44
45impl std::error::Error for UnsupportedSignalError {}
46
47#[non_exhaustive]
48#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
49pub enum Signo {
51 SIGILL,
57 SIGFPE,
59 SIGSEGV,
61 SIGBUS,
63 SIGTRAP,
65}
66
67impl Signo {
68 pub const fn all() -> &'static [Signo] {
70 use Signo::*;
71 &[SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP]
72 }
73
74 pub fn from_raw(raw: c_int) -> Result<Signo, UnsupportedSignalError> {
76 match raw {
77 libc::SIGILL => Ok(Signo::SIGILL),
78 libc::SIGFPE => Ok(Signo::SIGFPE),
79 libc::SIGSEGV => Ok(Signo::SIGSEGV),
80 libc::SIGBUS => Ok(Signo::SIGBUS),
81 libc::SIGTRAP => Ok(Signo::SIGTRAP),
82 _ => Err(UnsupportedSignalError::UnsupportedSigno { signo: raw }),
83 }
84 }
85}
86
87impl From<Signo> for c_int {
88 fn from(value: Signo) -> Self {
89 match value {
90 Signo::SIGILL => libc::SIGILL,
91 Signo::SIGFPE => libc::SIGFPE,
92 Signo::SIGSEGV => libc::SIGSEGV,
93 Signo::SIGBUS => libc::SIGBUS,
94 Signo::SIGTRAP => libc::SIGTRAP,
95 }
96 }
97}
98
99#[non_exhaustive]
100#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
101pub enum Signal {
103 Ill(SigillCode),
105 Fpe(SigfpeCode),
107 Segv(SigsegvCode),
109 Bus(SigbusCode),
111 Trap(SigtrapCode),
113}
114
115impl Signal {
116 pub fn from_raw(signo: c_int, code: c_int) -> Result<Signal, UnsupportedSignalError> {
118 let cooked_signo = Signo::from_raw(signo)?;
119 let err = UnsupportedSignalError::UnsupportedCode { signo, code };
120
121 match cooked_signo {
122 Signo::SIGILL => unsafe {
123 let mut cooked_code: MaybeUninit<SigillCode> = MaybeUninit::uninit();
124 let ret = hwexception_translate_sigill_code(cooked_code.as_mut_ptr(), code);
125 if ret == 1 {
126 Ok(Signal::Ill(cooked_code.assume_init()))
127 } else {
128 Err(err)
129 }
130 },
131 Signo::SIGFPE => unsafe {
132 let mut cooked_code: MaybeUninit<SigfpeCode> = MaybeUninit::uninit();
133 let ret = hwexception_translate_sigfpe_code(cooked_code.as_mut_ptr(), code);
134 if ret == 1 {
135 Ok(Signal::Fpe(cooked_code.assume_init()))
136 } else {
137 Err(err)
138 }
139 },
140 Signo::SIGSEGV => unsafe {
141 let mut cooked_code: MaybeUninit<SigsegvCode> = MaybeUninit::uninit();
142 let ret = hwexception_translate_sigsegv_code(cooked_code.as_mut_ptr(), code);
143 if ret == 1 {
144 Ok(Signal::Segv(cooked_code.assume_init()))
145 } else {
146 Err(err)
147 }
148 },
149 Signo::SIGBUS => unsafe {
150 let mut cooked_code: MaybeUninit<SigbusCode> = MaybeUninit::uninit();
151 let ret = hwexception_translate_sigbus_code(cooked_code.as_mut_ptr(), code);
152 if ret == 1 {
153 Ok(Signal::Bus(cooked_code.assume_init()))
154 } else {
155 Err(err)
156 }
157 },
158 Signo::SIGTRAP => unsafe {
159 let mut cooked_code: MaybeUninit<SigtrapCode> = MaybeUninit::uninit();
160 let ret = hwexception_translate_sigtrap_code(cooked_code.as_mut_ptr(), code);
161 if ret == 1 {
162 Ok(Signal::Trap(cooked_code.assume_init()))
163 } else {
164 Err(err)
165 }
166 },
167 }
168 }
169
170 pub fn signo(self) -> Signo {
172 use Signal::*;
173 match self {
174 Ill(_) => Signo::SIGILL,
175 Fpe(_) => Signo::SIGFPE,
176 Segv(_) => Signo::SIGSEGV,
177 Bus(_) => Signo::SIGBUS,
178 Trap(_) => Signo::SIGTRAP,
179 }
180 }
181}
182
183#[derive(Debug,Clone)]
184enum ExceptionInfoImpl<'a> {
185 Borrowed {
186 signo: c_int,
187 siginfo: *mut libc::siginfo_t,
188 context: *mut c_void,
189 _phantom: PhantomData<&'a ()>,
190 },
191 Owned {
192 signo: c_int,
193 siginfo: libc::siginfo_t,
194 context: *mut c_void,
195 sp: *mut c_void,
196 ip: *mut c_void,
197 symbol_address: *mut c_void,
198 },
199}
200
201#[derive(Debug,Clone)]
202pub struct ExceptionInfo<'a>(ExceptionInfoImpl<'a>);
204
205impl ExceptionInfo<'_> {
206 pub unsafe fn new<'a>(
214 signo: c_int,
215 siginfo: *mut libc::siginfo_t,
216 context: *mut c_void,
217 ) -> ExceptionInfo<'a> {
218 ExceptionInfo(ExceptionInfoImpl::Borrowed {
219 signo,
220 siginfo,
221 context,
222 _phantom: PhantomData,
223 })
224 }
225
226 pub fn into_owned(self) -> ExceptionInfo<'static> {
228 ExceptionInfo(match self.0 {
229 ExceptionInfoImpl::Borrowed {
230 signo,
231 siginfo,
232 context,
233 ..
234 } => unsafe {
235 ExceptionInfoImpl::Owned {
236 signo,
237 siginfo: *siginfo,
238 context,
239 sp: hwexception_get_sp(context),
240 ip: hwexception_get_ip(context),
241 symbol_address: hwexception_get_symbol_address(context),
242 }
243 },
244 ExceptionInfoImpl::Owned {
245 signo,
246 siginfo,
247 context,
248 sp,
249 ip,
250 symbol_address,
251 } => ExceptionInfoImpl::Owned {
252 signo,
253 siginfo,
254 context,
255 sp,
256 ip,
257 symbol_address
258 },
259 })
260 }
261
262 pub fn signo_raw(&self) -> c_int {
264 match &self.0 {
265 ExceptionInfoImpl::Borrowed { signo, .. } => *signo,
266 ExceptionInfoImpl::Owned { signo, .. } => *signo,
267 }
268 }
269
270 pub fn signinfo_raw(&self) -> &libc::siginfo_t {
273 match &self.0 {
274 ExceptionInfoImpl::Borrowed { siginfo, .. } => unsafe { &**siginfo },
275 ExceptionInfoImpl::Owned { siginfo, .. } => siginfo,
276 }
277 }
278
279 pub fn context(&self) -> *mut c_void {
281 match &self.0 {
282 ExceptionInfoImpl::Borrowed { context, .. } => *context,
283 ExceptionInfoImpl::Owned { context, .. } => *context,
284 }
285 }
286
287 pub fn signo(&self) -> Signo {
289 Signo::from_raw(self.signo_raw()).unwrap()
290 }
291
292 pub fn addr(&self) -> *mut c_void {
294 unsafe { self.signinfo_raw().si_addr() }
295 }
296
297 pub fn signal(&self) -> Result<Signal, UnsupportedSignalError> {
304 Signal::from_raw(self.signo_raw(), self.signinfo_raw().si_code)
305 }
306
307 pub fn addr_lsb(&self) -> Option<c_short> {
314 match self.signal().ok()? {
315 Signal::Bus(SigbusCode::MCEERR_AO | SigbusCode::MCEERR_AR) => unsafe {
316 Some(hwexception_get_addr_lsb(self.signinfo_raw()))
317 },
318 _ => None,
319 }
320 }
321
322 pub fn lower(&self) -> Option<*mut c_void> {
325 match self.signal().ok()? {
326 Signal::Segv(SigsegvCode::BNDERR) => unsafe {
327 Some(hwexception_get_lower(self.signinfo_raw()))
328 },
329 _ => None,
330 }
331 }
332
333 pub fn upper(&self) -> Option<*mut c_void> {
336 match self.signal().ok()? {
337 Signal::Segv(SigsegvCode::BNDERR) => unsafe {
338 Some(hwexception_get_upper(self.signinfo_raw()))
339 },
340 _ => None,
341 }
342 }
343
344 pub fn pkey(&self) -> Option<c_int> {
347 match self.signal().ok()? {
348 Signal::Segv(SigsegvCode::PKUERR) => unsafe {
349 Some(hwexception_get_pkey(self.signinfo_raw()))
350 },
351 _ => None,
352 }
353 }
354
355 pub fn sp(&self) -> *mut c_void {
362 match &self.0 {
363 ExceptionInfoImpl::Borrowed { context, .. } => unsafe {
364 hwexception_get_sp(*context)
365 }
366 ExceptionInfoImpl::Owned { sp, .. } => *sp,
367 }
368 }
369
370 pub fn ip(&self) -> *mut c_void {
376 match &self.0 {
377 ExceptionInfoImpl::Borrowed { context, .. } => unsafe {
378 hwexception_get_ip(*context)
379 }
380 ExceptionInfoImpl::Owned { ip, .. } => *ip,
381 }
382 }
383
384 pub fn symbol_address(&self) -> *mut c_void {
391 match &self.0 {
392 ExceptionInfoImpl::Borrowed { context, .. } => unsafe {
393 hwexception_get_symbol_address(*context)
394 }
395 ExceptionInfoImpl::Owned { symbol_address, .. } => *symbol_address,
396 }
397 }
398}
399
400#[derive(Debug)]
401pub struct ExtExceptionInfo {
403 info: Box<ExceptionInfo<'static>>,
404 additional: Option<Box<dyn Any + 'static>>,
405}
406
407impl ExtExceptionInfo {
408 pub fn info(&self) -> &ExceptionInfo<'static> {
410 self.info.as_ref()
411 }
412 pub fn additional(&self) -> Option<&(dyn Any + 'static)> {
414 self.additional.as_ref().map(|b| b.as_ref())
415 }
416}
417
418impl From<ExceptionInfo<'_>> for ExtExceptionInfo {
419 fn from(info: ExceptionInfo<'_>) -> Self {
420 ExtExceptionInfo {
421 info: Box::new(info.into_owned()),
422 additional: None,
423 }
424 }
425}
426
427impl<A> From<(ExceptionInfo<'_>, A)> for ExtExceptionInfo
428where
429 A: 'static,
430{
431 fn from(val: (ExceptionInfo<'_>, A)) -> Self {
432 ExtExceptionInfo {
433 info: Box::new(val.0.into_owned()),
434 additional: Some(Box::new(val.1)),
435 }
436 }
437}