1pub mod raw {
5 use std::ffi::c_void;
7
8 #[cfg(target_arch = "x86_64")]
9 extern "C" {
10 pub fn run_on_alternative_stack(stack_end: *mut u64, stack_begin: *mut u64) -> u64;
12 pub fn register_preservation_trampoline(); }
15
16 #[cfg(not(target_arch = "x86_64"))]
18 pub extern "C" fn register_preservation_trampoline() {
19 unimplemented!("register_preservation_trampoline");
20 }
21
22 extern "C" {
23 pub fn setjmp(env: *mut c_void) -> i32;
25 pub fn longjmp(env: *mut c_void, val: i32) -> !;
27 }
28}
29
30use crate::codegen::{BreakpointInfo, BreakpointMap};
31use crate::error::{InvokeError, RuntimeError};
32use crate::state::x64::{build_instance_image, read_stack, X64Register, GPR};
33use crate::state::{CodeVersion, ExecutionStateImage};
34use crate::vm;
35use libc::{mmap, mprotect, siginfo_t, MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE};
36use nix::sys::signal::{
37 sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal, SIGBUS, SIGFPE, SIGILL, SIGINT,
38 SIGSEGV, SIGTRAP,
39};
40use std::cell::{Cell, RefCell, UnsafeCell};
41use std::ffi::c_void;
42use std::process;
43use std::sync::atomic::{AtomicBool, Ordering};
44use std::sync::Once;
45
46#[cfg(target_arch = "x86_64")]
47pub(crate) unsafe fn run_on_alternative_stack(stack_end: *mut u64, stack_begin: *mut u64) -> u64 {
48 raw::run_on_alternative_stack(stack_end, stack_begin)
49}
50
51#[cfg(not(target_arch = "x86_64"))]
52pub(crate) unsafe fn run_on_alternative_stack(_stack_end: *mut u64, _stack_begin: *mut u64) -> u64 {
53 unimplemented!("run_on_alternative_stack");
54}
55
56const TRAP_STACK_SIZE: usize = 1048576; const SETJMP_BUFFER_LEN: usize = 128;
59type SetJmpBuffer = [i32; SETJMP_BUFFER_LEN];
60
61struct UnwindInfo {
62 jmpbuf: SetJmpBuffer, breakpoints: Option<BreakpointMap>,
64 payload: Option<Box<RuntimeError>>, }
66
67#[repr(packed)]
69#[derive(Default, Copy, Clone)]
70pub struct BoundaryRegisterPreservation {
71 pub r15: u64,
73 pub r14: u64,
75 pub r13: u64,
77 pub r12: u64,
79 pub rbx: u64,
81}
82
83thread_local! {
84 static UNWIND: UnsafeCell<Option<UnwindInfo>> = UnsafeCell::new(None);
85 static CURRENT_CTX: UnsafeCell<*mut vm::Ctx> = UnsafeCell::new(::std::ptr::null_mut());
86 static CURRENT_CODE_VERSIONS: RefCell<Vec<CodeVersion>> = RefCell::new(vec![]);
87 static WAS_SIGINT_TRIGGERED: Cell<bool> = Cell::new(false);
88 static BOUNDARY_REGISTER_PRESERVATION: UnsafeCell<BoundaryRegisterPreservation> = UnsafeCell::new(BoundaryRegisterPreservation::default());
89}
90
91#[no_mangle]
93pub unsafe extern "C" fn get_boundary_register_preservation() -> *mut BoundaryRegisterPreservation {
94 BOUNDARY_REGISTER_PRESERVATION.with(|x| x.get())
95}
96
97struct InterruptSignalMem(*mut u8);
98unsafe impl Send for InterruptSignalMem {}
99unsafe impl Sync for InterruptSignalMem {}
100
101const INTERRUPT_SIGNAL_MEM_SIZE: usize = 4096;
102
103lazy_static! {
104 static ref INTERRUPT_SIGNAL_MEM: InterruptSignalMem = {
105 let ptr = unsafe {
106 mmap(
107 ::std::ptr::null_mut(),
108 INTERRUPT_SIGNAL_MEM_SIZE,
109 PROT_READ | PROT_WRITE,
110 MAP_PRIVATE | MAP_ANON,
111 -1,
112 0,
113 )
114 };
115 if ptr as isize == -1 {
116 panic!("cannot allocate code memory");
117 }
118 InterruptSignalMem(ptr as _)
119 };
120}
121static INTERRUPT_SIGNAL_DELIVERED: AtomicBool = AtomicBool::new(false);
122
123pub fn was_sigint_triggered_fault() -> bool {
125 WAS_SIGINT_TRIGGERED.with(|x| x.get())
126}
127
128pub unsafe fn with_ctx<R, F: FnOnce() -> R>(ctx: *mut vm::Ctx, cb: F) -> R {
130 let addr = CURRENT_CTX.with(|x| x.get());
131 let old = *addr;
132 *addr = ctx;
133 let ret = cb();
134 *addr = old;
135 ret
136}
137
138pub fn push_code_version(version: CodeVersion) {
140 CURRENT_CODE_VERSIONS.with(|x| x.borrow_mut().push(version));
141}
142
143pub fn pop_code_version() -> Option<CodeVersion> {
145 CURRENT_CODE_VERSIONS.with(|x| x.borrow_mut().pop())
146}
147
148pub unsafe fn get_wasm_interrupt_signal_mem() -> *mut u8 {
150 INTERRUPT_SIGNAL_MEM.0
151}
152
153pub unsafe fn set_wasm_interrupt_on_ctx(ctx: *mut vm::Ctx) {
155 if mprotect(
156 (&*ctx).internal.interrupt_signal_mem as _,
157 INTERRUPT_SIGNAL_MEM_SIZE,
158 PROT_NONE,
159 ) < 0
160 {
161 panic!("cannot set PROT_NONE on signal mem");
162 }
163}
164
165pub unsafe fn set_wasm_interrupt() {
167 let mem: *mut u8 = INTERRUPT_SIGNAL_MEM.0;
168 if mprotect(mem as _, INTERRUPT_SIGNAL_MEM_SIZE, PROT_NONE) < 0 {
169 panic!("cannot set PROT_NONE on signal mem");
170 }
171}
172
173pub unsafe fn clear_wasm_interrupt() {
175 let mem: *mut u8 = INTERRUPT_SIGNAL_MEM.0;
176 if mprotect(mem as _, INTERRUPT_SIGNAL_MEM_SIZE, PROT_READ | PROT_WRITE) < 0 {
177 panic!("cannot set PROT_READ | PROT_WRITE on signal mem");
178 }
179}
180
181pub unsafe fn catch_unsafe_unwind<R, F: FnOnce() -> R>(
183 f: F,
184 breakpoints: Option<BreakpointMap>,
185) -> Result<R, RuntimeError> {
186 let unwind = UNWIND.with(|x| x.get());
187 let old = (*unwind).take();
188 *unwind = Some(UnwindInfo {
189 jmpbuf: [0; SETJMP_BUFFER_LEN],
190 breakpoints: breakpoints,
191 payload: None,
192 });
193
194 if raw::setjmp(&mut (*unwind).as_mut().unwrap().jmpbuf as *mut SetJmpBuffer as *mut _) != 0 {
195 let ret = (*unwind).as_mut().unwrap().payload.take().unwrap();
197 *unwind = old;
198 Err(*ret)
199 } else {
200 let ret = f();
201 *unwind = old;
203 Ok(ret)
204 }
205}
206
207pub unsafe fn begin_unsafe_unwind(e: Box<RuntimeError>) -> ! {
209 let unwind = UNWIND.with(|x| x.get());
210 let inner = (*unwind)
211 .as_mut()
212 .expect("not within a catch_unsafe_unwind scope");
213 inner.payload = Some(e);
214 raw::longjmp(&mut inner.jmpbuf as *mut SetJmpBuffer as *mut _, 0xffff);
215}
216
217unsafe fn with_breakpoint_map<R, F: FnOnce(Option<&BreakpointMap>) -> R>(f: F) -> R {
218 let unwind = UNWIND.with(|x| x.get());
219 let inner = (*unwind)
220 .as_mut()
221 .expect("not within a catch_unsafe_unwind scope");
222 f(inner.breakpoints.as_ref())
223}
224
225#[cfg(not(target_arch = "x86_64"))]
226pub fn allocate_and_run<R, F: FnOnce() -> R>(_size: usize, f: F) -> R {
228 f()
229}
230
231#[cfg(target_arch = "x86_64")]
232pub fn allocate_and_run<R, F: FnOnce() -> R>(size: usize, f: F) -> R {
234 struct Context<F: FnOnce() -> R, R> {
235 f: Option<F>,
236 ret: Option<R>,
237 }
238
239 extern "C" fn invoke<F: FnOnce() -> R, R>(ctx: &mut Context<F, R>) {
240 let f = ctx.f.take().unwrap();
241 ctx.ret = Some(f());
242 }
243
244 unsafe {
245 let mut ctx = Context {
246 f: Some(f),
247 ret: None,
248 };
249 assert!(size % 16 == 0);
250 assert!(size >= 4096);
251
252 let mut stack: Vec<u64> = vec![0; size / 8];
253 let end_offset = stack.len();
254
255 stack[end_offset - 4] = invoke::<F, R> as usize as u64;
256
257 stack[end_offset - 4 - 10] = &mut ctx as *mut Context<F, R> as usize as u64; const NUM_SAVED_REGISTERS: usize = 31;
260 let stack_begin = stack.as_mut_ptr().add(end_offset - 4 - NUM_SAVED_REGISTERS);
261 let stack_end = stack.as_mut_ptr().add(end_offset);
262
263 raw::run_on_alternative_stack(stack_end, stack_begin);
264 ctx.ret.take().unwrap()
265 }
266}
267
268extern "C" fn signal_trap_handler(
269 signum: ::nix::libc::c_int,
270 siginfo: *mut siginfo_t,
271 ucontext: *mut c_void,
272) {
273 use crate::backend::{Architecture, InlineBreakpointType};
274
275 #[cfg(target_arch = "x86_64")]
276 static ARCH: Architecture = Architecture::X64;
277
278 #[cfg(target_arch = "aarch64")]
279 static ARCH: Architecture = Architecture::Aarch64;
280
281 let mut should_unwind = false;
282 let mut unwind_result: Option<Box<RuntimeError>> = None;
283 let get_unwind_result = |uw_result: Option<Box<RuntimeError>>| -> Box<RuntimeError> {
284 uw_result
285 .unwrap_or_else(|| Box::new(RuntimeError::InvokeError(InvokeError::FailedWithNoError)))
286 };
287
288 unsafe {
289 let fault = get_fault_info(siginfo as _, ucontext);
290 let early_return = allocate_and_run(TRAP_STACK_SIZE, || {
291 CURRENT_CODE_VERSIONS.with(|versions| {
292 let versions = versions.borrow();
293 for v in versions.iter() {
294 let magic_size =
295 if let Some(x) = v.runnable_module.get_inline_breakpoint_size(ARCH) {
296 x
297 } else {
298 continue;
299 };
300 let ip = fault.ip.get();
301 let end = v.base + v.msm.total_size;
302 if ip >= v.base && ip < end && ip + magic_size <= end {
303 if let Some(ib) = v.runnable_module.read_inline_breakpoint(
304 ARCH,
305 std::slice::from_raw_parts(ip as *const u8, magic_size),
306 ) {
307 match ib.ty {
308 InlineBreakpointType::Middleware => {
309 let out: Option<Result<(), RuntimeError>> =
310 with_breakpoint_map(|bkpt_map| {
311 bkpt_map.and_then(|x| x.get(&ip)).map(|x| {
312 x(BreakpointInfo {
313 fault: Some(&fault),
314 })
315 })
316 });
317 if let Some(Ok(())) = out {
318 } else if let Some(Err(e)) = out {
319 should_unwind = true;
320 unwind_result = Some(Box::new(e));
321 }
322 }
323 }
324
325 fault.ip.set(ip + magic_size);
326 return true;
327 }
328 break;
329 }
330 }
331 false
332 })
333 });
334 if should_unwind {
335 begin_unsafe_unwind(get_unwind_result(unwind_result));
336 }
337 if early_return {
338 return;
339 }
340
341 should_unwind = allocate_and_run(TRAP_STACK_SIZE, || {
342 let mut is_suspend_signal = false;
343
344 WAS_SIGINT_TRIGGERED.with(|x| x.set(false));
345
346 match Signal::from_c_int(signum) {
347 Ok(SIGTRAP) => {
348 let out: Option<Result<(), RuntimeError>> =
350 with_breakpoint_map(|bkpt_map| -> Option<Result<(), RuntimeError>> {
351 bkpt_map.and_then(|x| x.get(&(fault.ip.get()))).map(
352 |x| -> Result<(), RuntimeError> {
353 x(BreakpointInfo {
354 fault: Some(&fault),
355 })
356 },
357 )
358 });
359 match out {
360 Some(Ok(())) => {
361 return false;
362 }
363 Some(Err(e)) => {
364 unwind_result = Some(Box::new(e));
365 return true;
366 }
367 None => {}
368 }
369 }
370 Ok(SIGSEGV) | Ok(SIGBUS) => {
371 if fault.faulting_addr as usize == get_wasm_interrupt_signal_mem() as usize {
372 is_suspend_signal = true;
373 clear_wasm_interrupt();
374 if INTERRUPT_SIGNAL_DELIVERED.swap(false, Ordering::SeqCst) {
375 WAS_SIGINT_TRIGGERED.with(|x| x.set(true));
376 }
377 }
378 }
379 _ => {}
380 }
381
382 let ctx: &mut vm::Ctx = &mut **CURRENT_CTX.with(|x| x.get());
389 let es_image = fault
390 .read_stack(None)
391 .expect("fault.read_stack() failed. Broken invariants?");
392
393 if is_suspend_signal {
394 let image = build_instance_image(ctx, es_image);
396 unwind_result = Some(Box::new(RuntimeError::InstanceImage(Box::new(image))));
397 } else {
398 if !es_image.frames.is_empty() {
400 eprintln!(
401 "\n{}",
402 "Wasmer encountered an error while running your WebAssembly program."
403 );
404 es_image.print_backtrace_if_needed();
405 }
406
407 let exc_code = CURRENT_CODE_VERSIONS.with(|versions| {
409 let versions = versions.borrow();
410 for v in versions.iter() {
411 if let Some(table) = v.runnable_module.get_exception_table() {
412 let ip = fault.ip.get();
413 let end = v.base + v.msm.total_size;
414 if ip >= v.base && ip < end {
415 if let Some(exc_code) = table.offset_to_code.get(&(ip - v.base)) {
416 return Some(*exc_code);
417 }
418 }
419 }
420 }
421 None
422 });
423 if let Some(code) = exc_code {
424 unwind_result =
425 Some(Box::new(RuntimeError::InvokeError(InvokeError::TrapCode {
426 code,
427 srcloc: 0,
429 })));
430 }
431 }
432
433 true
434 });
435
436 if should_unwind {
437 begin_unsafe_unwind(get_unwind_result(unwind_result));
438 }
439 }
440}
441
442extern "C" fn sigint_handler(
443 _signum: ::nix::libc::c_int,
444 _siginfo: *mut siginfo_t,
445 _ucontext: *mut c_void,
446) {
447 if INTERRUPT_SIGNAL_DELIVERED.swap(true, Ordering::SeqCst) {
448 eprintln!("Got another SIGINT before trap is triggered on WebAssembly side, aborting");
449 process::abort();
450 }
451 unsafe {
452 set_wasm_interrupt();
453 }
454}
455
456pub fn ensure_sighandler() {
458 INSTALL_SIGHANDLER.call_once(|| unsafe {
459 install_sighandler();
460 });
461}
462
463static INSTALL_SIGHANDLER: Once = Once::new();
464
465unsafe fn install_sighandler() {
466 let sa_trap = SigAction::new(
467 SigHandler::SigAction(signal_trap_handler),
468 SaFlags::SA_ONSTACK,
469 SigSet::empty(),
470 );
471 sigaction(SIGFPE, &sa_trap).unwrap();
472 sigaction(SIGILL, &sa_trap).unwrap();
473 sigaction(SIGSEGV, &sa_trap).unwrap();
474 sigaction(SIGBUS, &sa_trap).unwrap();
475 sigaction(SIGTRAP, &sa_trap).unwrap();
476
477 let sa_interrupt = SigAction::new(
478 SigHandler::SigAction(sigint_handler),
479 SaFlags::SA_ONSTACK,
480 SigSet::empty(),
481 );
482 sigaction(SIGINT, &sa_interrupt).unwrap();
483}
484
485#[derive(Debug, Clone)]
486pub struct FaultInfo {
488 pub faulting_addr: *const c_void,
490 pub ip: &'static Cell<usize>,
492 pub known_registers: [Option<u64>; 32],
494}
495
496impl FaultInfo {
497 pub unsafe fn read_stack(&self, max_depth: Option<usize>) -> Option<ExecutionStateImage> {
499 let rsp = self.known_registers[X64Register::GPR(GPR::RSP).to_index().0]?;
500
501 Some(CURRENT_CODE_VERSIONS.with(|versions| {
502 let versions = versions.borrow();
503 read_stack(
504 || versions.iter(),
505 rsp as usize as *const u64,
506 self.known_registers,
507 Some(self.ip.get() as u64),
508 max_depth,
509 )
510 }))
511 }
512}
513
514#[cfg(all(target_os = "freebsd", target_arch = "aarch64"))]
515pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> FaultInfo {
517 #[repr(C)]
518 pub struct ucontext_t {
519 uc_sigmask: libc::sigset_t,
520 uc_mcontext: mcontext_t,
521 uc_link: *mut ucontext_t,
522 uc_stack: libc::stack_t,
523 uc_flags: i32,
524 __spare__: [i32; 4],
525 }
526 #[repr(C)]
527 pub struct gpregs {
528 gp_x: [u64; 30],
529 gp_lr: u64,
530 gp_sp: u64,
531 gp_elr: u64,
532 gp_spsr: u64,
533 gp_pad: i32,
534 };
535 #[repr(C)]
536 pub struct fpregs {
537 fp_q: [u128; 32],
538 fp_sr: u32,
539 fp_cr: u32,
540 fp_flags: i32,
541 fp_pad: i32,
542 };
543 #[repr(C)]
544 pub struct mcontext_t {
545 mc_gpregs: gpregs,
546 mc_fpregs: fpregs,
547 mc_flags: i32,
548 mc_pad: i32,
549 mc_spare: [u64; 8],
550 }
551
552 let siginfo = siginfo as *const siginfo_t;
553 let si_addr = (*siginfo).si_addr;
554
555 let ucontext = ucontext as *mut ucontext_t;
556 let gregs = &(*ucontext).uc_mcontext.mc_gpregs;
557
558 let mut known_registers: [Option<u64>; 32] = [None; 32];
559
560 known_registers[X64Register::GPR(GPR::R15).to_index().0] = Some(gregs.gp_x[15] as _);
561 known_registers[X64Register::GPR(GPR::R14).to_index().0] = Some(gregs.gp_x[14] as _);
562 known_registers[X64Register::GPR(GPR::R13).to_index().0] = Some(gregs.gp_x[13] as _);
563 known_registers[X64Register::GPR(GPR::R12).to_index().0] = Some(gregs.gp_x[12] as _);
564 known_registers[X64Register::GPR(GPR::R11).to_index().0] = Some(gregs.gp_x[11] as _);
565 known_registers[X64Register::GPR(GPR::R10).to_index().0] = Some(gregs.gp_x[10] as _);
566 known_registers[X64Register::GPR(GPR::R9).to_index().0] = Some(gregs.gp_x[9] as _);
567 known_registers[X64Register::GPR(GPR::R8).to_index().0] = Some(gregs.gp_x[8] as _);
568 known_registers[X64Register::GPR(GPR::RSI).to_index().0] = Some(gregs.gp_x[6] as _);
569 known_registers[X64Register::GPR(GPR::RDI).to_index().0] = Some(gregs.gp_x[7] as _);
570 known_registers[X64Register::GPR(GPR::RDX).to_index().0] = Some(gregs.gp_x[2] as _);
571 known_registers[X64Register::GPR(GPR::RCX).to_index().0] = Some(gregs.gp_x[1] as _);
572 known_registers[X64Register::GPR(GPR::RBX).to_index().0] = Some(gregs.gp_x[3] as _);
573 known_registers[X64Register::GPR(GPR::RAX).to_index().0] = Some(gregs.gp_x[0] as _);
574
575 known_registers[X64Register::GPR(GPR::RBP).to_index().0] = Some(gregs.gp_x[5] as _);
576 known_registers[X64Register::GPR(GPR::RSP).to_index().0] = Some(gregs.gp_x[28] as _);
577
578 FaultInfo {
579 faulting_addr: si_addr as usize as _,
580 ip: std::mem::transmute::<&mut u64, &'static Cell<usize>>(
581 &mut (*ucontext).uc_mcontext.mc_gpregs.gp_elr,
582 ),
583 known_registers,
584 }
585}
586
587#[cfg(all(target_os = "freebsd", target_arch = "x86_64"))]
588pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> FaultInfo {
590 use crate::state::x64::XMM;
591 #[repr(C)]
592 pub struct ucontext_t {
593 uc_sigmask: libc::sigset_t,
594 uc_mcontext: mcontext_t,
595 uc_link: *mut ucontext_t,
596 uc_stack: libc::stack_t,
597 uc_flags: i32,
598 __spare__: [i32; 4],
599 }
600 #[repr(C)]
601 pub struct mcontext_t {
602 mc_onstack: u64,
603 mc_rdi: u64,
604 mc_rsi: u64,
605 mc_rdx: u64,
606 mc_rcx: u64,
607 mc_r8: u64,
608 mc_r9: u64,
609 mc_rax: u64,
610 mc_rbx: u64,
611 mc_rbp: u64,
612 mc_r10: u64,
613 mc_r11: u64,
614 mc_r12: u64,
615 mc_r13: u64,
616 mc_r14: u64,
617 mc_r15: u64,
618 mc_trapno: u32,
619 mc_fs: u16,
620 mc_gs: u16,
621 mc_addr: u64,
622 mc_flags: u32,
623 mc_es: u16,
624 mc_ds: u16,
625 mc_err: u64,
626 mc_rip: u64,
627 mc_cs: u64,
628 mc_rflags: u64,
629 mc_rsp: u64,
630 mc_ss: u64,
631 mc_len: i64,
632
633 mc_fpformat: i64,
634 mc_ownedfp: i64,
635 mc_savefpu: *const savefpu,
636 mc_fpstate: [i64; 63], mc_fsbase: u64,
639 mc_gsbase: u64,
640
641 mc_xfpustate: u64,
642 mc_xfpustate_len: u64,
643
644 mc_spare: [i64; 4],
645 }
646 #[repr(C)]
647 pub struct xmmacc {
648 element: [u32; 4],
649 }
650 #[repr(C)]
651 pub struct __envxmm64 {
652 en_cw: u16,
653 en_sw: u16,
654 en_tw: u8,
655 en_zero: u8,
656 en_opcode: u16,
657 en_rip: u64,
658 en_rdp: u64,
659 en_mxcsr: u32,
660 en_mxcsr_mask: u32,
661 }
662 #[repr(C)]
663 pub struct fpacc87 {
664 fp_bytes: [u8; 10],
665 }
666 #[repr(C)]
667 pub struct sv_fp {
668 fp_acc: fpacc87,
669 fp_pad: [u8; 6],
670 }
671 #[repr(C, align(16))]
672 pub struct savefpu {
673 sv_env: __envxmm64,
674 sv_fp_t: [sv_fp; 8],
675 sv_xmm: [xmmacc; 16],
676 sv_pad: [u8; 96],
677 }
678
679 let siginfo = siginfo as *const siginfo_t;
680 let si_addr = (*siginfo).si_addr;
681
682 let ucontext = ucontext as *mut ucontext_t;
683 let gregs = &mut (*ucontext).uc_mcontext;
684
685 fn read_xmm(reg: &xmmacc) -> u64 {
686 (reg.element[0] as u64) | ((reg.element[1] as u64) << 32)
687 }
688
689 let mut known_registers: [Option<u64>; 32] = [None; 32];
690 known_registers[X64Register::GPR(GPR::R15).to_index().0] = Some(gregs.mc_r15);
691 known_registers[X64Register::GPR(GPR::R14).to_index().0] = Some(gregs.mc_r14);
692 known_registers[X64Register::GPR(GPR::R13).to_index().0] = Some(gregs.mc_r13);
693 known_registers[X64Register::GPR(GPR::R12).to_index().0] = Some(gregs.mc_r12);
694 known_registers[X64Register::GPR(GPR::R11).to_index().0] = Some(gregs.mc_r11);
695 known_registers[X64Register::GPR(GPR::R10).to_index().0] = Some(gregs.mc_r10);
696 known_registers[X64Register::GPR(GPR::R9).to_index().0] = Some(gregs.mc_r9);
697 known_registers[X64Register::GPR(GPR::R8).to_index().0] = Some(gregs.mc_r8);
698 known_registers[X64Register::GPR(GPR::RSI).to_index().0] = Some(gregs.mc_rsi);
699 known_registers[X64Register::GPR(GPR::RDI).to_index().0] = Some(gregs.mc_rdi);
700 known_registers[X64Register::GPR(GPR::RDX).to_index().0] = Some(gregs.mc_rdx);
701 known_registers[X64Register::GPR(GPR::RCX).to_index().0] = Some(gregs.mc_rcx);
702 known_registers[X64Register::GPR(GPR::RBX).to_index().0] = Some(gregs.mc_rbx);
703 known_registers[X64Register::GPR(GPR::RAX).to_index().0] = Some(gregs.mc_rax);
704
705 known_registers[X64Register::GPR(GPR::RBP).to_index().0] = Some(gregs.mc_rbp);
706 known_registers[X64Register::GPR(GPR::RSP).to_index().0] = Some(gregs.mc_rsp);
707
708 const _MC_HASFPXSTATE: u32 = 0x4;
711 if (gregs.mc_flags & _MC_HASFPXSTATE) == 0 {
712 let fpregs = &*(*ucontext).uc_mcontext.mc_savefpu;
714 known_registers[X64Register::XMM(XMM::XMM0).to_index().0] =
715 Some(read_xmm(&fpregs.sv_xmm[0]));
716 known_registers[X64Register::XMM(XMM::XMM1).to_index().0] =
717 Some(read_xmm(&fpregs.sv_xmm[1]));
718 known_registers[X64Register::XMM(XMM::XMM2).to_index().0] =
719 Some(read_xmm(&fpregs.sv_xmm[2]));
720 known_registers[X64Register::XMM(XMM::XMM3).to_index().0] =
721 Some(read_xmm(&fpregs.sv_xmm[3]));
722 known_registers[X64Register::XMM(XMM::XMM4).to_index().0] =
723 Some(read_xmm(&fpregs.sv_xmm[4]));
724 known_registers[X64Register::XMM(XMM::XMM5).to_index().0] =
725 Some(read_xmm(&fpregs.sv_xmm[5]));
726 known_registers[X64Register::XMM(XMM::XMM6).to_index().0] =
727 Some(read_xmm(&fpregs.sv_xmm[6]));
728 known_registers[X64Register::XMM(XMM::XMM7).to_index().0] =
729 Some(read_xmm(&fpregs.sv_xmm[7]));
730 known_registers[X64Register::XMM(XMM::XMM8).to_index().0] =
731 Some(read_xmm(&fpregs.sv_xmm[8]));
732 known_registers[X64Register::XMM(XMM::XMM9).to_index().0] =
733 Some(read_xmm(&fpregs.sv_xmm[9]));
734 known_registers[X64Register::XMM(XMM::XMM10).to_index().0] =
735 Some(read_xmm(&fpregs.sv_xmm[10]));
736 known_registers[X64Register::XMM(XMM::XMM11).to_index().0] =
737 Some(read_xmm(&fpregs.sv_xmm[11]));
738 known_registers[X64Register::XMM(XMM::XMM12).to_index().0] =
739 Some(read_xmm(&fpregs.sv_xmm[12]));
740 known_registers[X64Register::XMM(XMM::XMM13).to_index().0] =
741 Some(read_xmm(&fpregs.sv_xmm[13]));
742 known_registers[X64Register::XMM(XMM::XMM14).to_index().0] =
743 Some(read_xmm(&fpregs.sv_xmm[14]));
744 known_registers[X64Register::XMM(XMM::XMM15).to_index().0] =
745 Some(read_xmm(&fpregs.sv_xmm[15]));
746 }
747
748 FaultInfo {
749 faulting_addr: si_addr,
750 ip: std::mem::transmute::<&mut u64, &'static Cell<usize>>(
751 &mut (*ucontext).uc_mcontext.mc_rip,
752 ),
753 known_registers,
754 }
755}
756
757#[cfg(all(
758 any(target_os = "linux", target_os = "android"),
759 target_arch = "aarch64"
760))]
761pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> FaultInfo {
763 #[allow(dead_code)]
764 #[allow(non_camel_case_types)]
765 #[repr(packed)]
766 struct sigcontext {
767 fault_address: u64,
768 regs: [u64; 31],
769 sp: u64,
770 pc: u64,
771 pstate: u64,
772 reserved: [u8; 4096],
773 }
774
775 #[allow(dead_code)]
776 #[allow(non_camel_case_types)]
777 #[repr(packed)]
778 struct ucontext {
779 unknown: [u8; 176],
780 uc_mcontext: sigcontext,
781 }
782
783 #[allow(dead_code)]
784 #[allow(non_camel_case_types)]
785 #[repr(C)]
786 struct siginfo_t {
787 si_signo: i32,
788 si_errno: i32,
789 si_code: i32,
790 si_addr: u64,
791 }
793
794 let siginfo = siginfo as *const siginfo_t;
795 let si_addr = (*siginfo).si_addr;
796
797 let ucontext = ucontext as *mut ucontext;
798 let gregs = &(*ucontext).uc_mcontext.regs;
799
800 let mut known_registers: [Option<u64>; 32] = [None; 32];
801
802 known_registers[X64Register::GPR(GPR::R15).to_index().0] = Some(gregs[15] as _);
803 known_registers[X64Register::GPR(GPR::R14).to_index().0] = Some(gregs[14] as _);
804 known_registers[X64Register::GPR(GPR::R13).to_index().0] = Some(gregs[13] as _);
805 known_registers[X64Register::GPR(GPR::R12).to_index().0] = Some(gregs[12] as _);
806 known_registers[X64Register::GPR(GPR::R11).to_index().0] = Some(gregs[11] as _);
807 known_registers[X64Register::GPR(GPR::R10).to_index().0] = Some(gregs[10] as _);
808 known_registers[X64Register::GPR(GPR::R9).to_index().0] = Some(gregs[9] as _);
809 known_registers[X64Register::GPR(GPR::R8).to_index().0] = Some(gregs[8] as _);
810 known_registers[X64Register::GPR(GPR::RSI).to_index().0] = Some(gregs[6] as _);
811 known_registers[X64Register::GPR(GPR::RDI).to_index().0] = Some(gregs[7] as _);
812 known_registers[X64Register::GPR(GPR::RDX).to_index().0] = Some(gregs[2] as _);
813 known_registers[X64Register::GPR(GPR::RCX).to_index().0] = Some(gregs[1] as _);
814 known_registers[X64Register::GPR(GPR::RBX).to_index().0] = Some(gregs[3] as _);
815 known_registers[X64Register::GPR(GPR::RAX).to_index().0] = Some(gregs[0] as _);
816
817 known_registers[X64Register::GPR(GPR::RBP).to_index().0] = Some(gregs[5] as _);
818 known_registers[X64Register::GPR(GPR::RSP).to_index().0] = Some(gregs[28] as _);
819
820 FaultInfo {
821 faulting_addr: si_addr as usize as _,
822 ip: std::mem::transmute::<&mut u64, &'static Cell<usize>>(&mut (*ucontext).uc_mcontext.pc),
823 known_registers,
824 }
825}
826
827#[cfg(all(
828 any(target_os = "linux", target_os = "android"),
829 target_arch = "x86_64"
830))]
831pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> FaultInfo {
833 use libc::{
834 ucontext_t, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_R15, REG_R8, REG_R9, REG_RAX,
835 REG_RBP, REG_RBX, REG_RCX, REG_RDI, REG_RDX, REG_RIP, REG_RSI, REG_RSP,
836 };
837
838 #[cfg(not(target_env = "musl"))]
839 fn read_xmm(reg: &libc::_libc_xmmreg) -> u64 {
840 (reg.element[0] as u64) | ((reg.element[1] as u64) << 32)
841 }
842
843 #[allow(dead_code)]
844 #[repr(C)]
845 struct siginfo_t {
846 si_signo: i32,
847 si_errno: i32,
848 si_code: i32,
849 si_addr: u64,
850 }
852
853 let siginfo = siginfo as *const siginfo_t;
854 let si_addr = (*siginfo).si_addr;
855
856 let ucontext = ucontext as *mut ucontext_t;
857 let gregs = &mut (*ucontext).uc_mcontext.gregs;
858
859 let mut known_registers: [Option<u64>; 32] = [None; 32];
860 known_registers[X64Register::GPR(GPR::R15).to_index().0] = Some(gregs[REG_R15 as usize] as _);
861 known_registers[X64Register::GPR(GPR::R14).to_index().0] = Some(gregs[REG_R14 as usize] as _);
862 known_registers[X64Register::GPR(GPR::R13).to_index().0] = Some(gregs[REG_R13 as usize] as _);
863 known_registers[X64Register::GPR(GPR::R12).to_index().0] = Some(gregs[REG_R12 as usize] as _);
864 known_registers[X64Register::GPR(GPR::R11).to_index().0] = Some(gregs[REG_R11 as usize] as _);
865 known_registers[X64Register::GPR(GPR::R10).to_index().0] = Some(gregs[REG_R10 as usize] as _);
866 known_registers[X64Register::GPR(GPR::R9).to_index().0] = Some(gregs[REG_R9 as usize] as _);
867 known_registers[X64Register::GPR(GPR::R8).to_index().0] = Some(gregs[REG_R8 as usize] as _);
868 known_registers[X64Register::GPR(GPR::RSI).to_index().0] = Some(gregs[REG_RSI as usize] as _);
869 known_registers[X64Register::GPR(GPR::RDI).to_index().0] = Some(gregs[REG_RDI as usize] as _);
870 known_registers[X64Register::GPR(GPR::RDX).to_index().0] = Some(gregs[REG_RDX as usize] as _);
871 known_registers[X64Register::GPR(GPR::RCX).to_index().0] = Some(gregs[REG_RCX as usize] as _);
872 known_registers[X64Register::GPR(GPR::RBX).to_index().0] = Some(gregs[REG_RBX as usize] as _);
873 known_registers[X64Register::GPR(GPR::RAX).to_index().0] = Some(gregs[REG_RAX as usize] as _);
874
875 known_registers[X64Register::GPR(GPR::RBP).to_index().0] = Some(gregs[REG_RBP as usize] as _);
876 known_registers[X64Register::GPR(GPR::RSP).to_index().0] = Some(gregs[REG_RSP as usize] as _);
877
878 #[cfg(not(target_env = "musl"))]
881 {
882 use crate::state::x64::XMM;
883 if !(*ucontext).uc_mcontext.fpregs.is_null() {
884 let fpregs = &*(*ucontext).uc_mcontext.fpregs;
885 known_registers[X64Register::XMM(XMM::XMM0).to_index().0] =
886 Some(read_xmm(&fpregs._xmm[0]));
887 known_registers[X64Register::XMM(XMM::XMM1).to_index().0] =
888 Some(read_xmm(&fpregs._xmm[1]));
889 known_registers[X64Register::XMM(XMM::XMM2).to_index().0] =
890 Some(read_xmm(&fpregs._xmm[2]));
891 known_registers[X64Register::XMM(XMM::XMM3).to_index().0] =
892 Some(read_xmm(&fpregs._xmm[3]));
893 known_registers[X64Register::XMM(XMM::XMM4).to_index().0] =
894 Some(read_xmm(&fpregs._xmm[4]));
895 known_registers[X64Register::XMM(XMM::XMM5).to_index().0] =
896 Some(read_xmm(&fpregs._xmm[5]));
897 known_registers[X64Register::XMM(XMM::XMM6).to_index().0] =
898 Some(read_xmm(&fpregs._xmm[6]));
899 known_registers[X64Register::XMM(XMM::XMM7).to_index().0] =
900 Some(read_xmm(&fpregs._xmm[7]));
901 known_registers[X64Register::XMM(XMM::XMM8).to_index().0] =
902 Some(read_xmm(&fpregs._xmm[8]));
903 known_registers[X64Register::XMM(XMM::XMM9).to_index().0] =
904 Some(read_xmm(&fpregs._xmm[9]));
905 known_registers[X64Register::XMM(XMM::XMM10).to_index().0] =
906 Some(read_xmm(&fpregs._xmm[10]));
907 known_registers[X64Register::XMM(XMM::XMM11).to_index().0] =
908 Some(read_xmm(&fpregs._xmm[11]));
909 known_registers[X64Register::XMM(XMM::XMM12).to_index().0] =
910 Some(read_xmm(&fpregs._xmm[12]));
911 known_registers[X64Register::XMM(XMM::XMM13).to_index().0] =
912 Some(read_xmm(&fpregs._xmm[13]));
913 known_registers[X64Register::XMM(XMM::XMM14).to_index().0] =
914 Some(read_xmm(&fpregs._xmm[14]));
915 known_registers[X64Register::XMM(XMM::XMM15).to_index().0] =
916 Some(read_xmm(&fpregs._xmm[15]));
917 }
918 }
919
920 FaultInfo {
921 faulting_addr: si_addr as usize as _,
922 ip: std::mem::transmute::<&mut i64, &'static Cell<usize>>(&mut gregs[REG_RIP as usize]),
923 known_registers,
924 }
925}
926
927#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
929pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> FaultInfo {
930 use crate::state::x64::XMM;
931 #[allow(dead_code)]
932 #[repr(C)]
933 struct ucontext_t {
934 uc_onstack: u32,
935 uc_sigmask: u32,
936 uc_stack: libc::stack_t,
937 uc_link: *const ucontext_t,
938 uc_mcsize: u64,
939 uc_mcontext: *mut mcontext_t,
940 }
941 #[repr(C)]
942 struct exception_state {
943 trapno: u16,
944 cpu: u16,
945 err: u32,
946 faultvaddr: u64,
947 }
948 #[repr(C)]
949 struct regs {
950 rax: u64,
951 rbx: u64,
952 rcx: u64,
953 rdx: u64,
954 rdi: u64,
955 rsi: u64,
956 rbp: u64,
957 rsp: u64,
958 r8: u64,
959 r9: u64,
960 r10: u64,
961 r11: u64,
962 r12: u64,
963 r13: u64,
964 r14: u64,
965 r15: u64,
966 rip: u64,
967 rflags: u64,
968 cs: u64,
969 fs: u64,
970 gs: u64,
971 }
972 #[repr(C)]
973 struct fpstate {
974 _cwd: u16,
975 _swd: u16,
976 _ftw: u16,
977 _fop: u16,
978 _rip: u64,
979 _rdp: u64,
980 _mxcsr: u32,
981 _mxcr_mask: u32,
982 _st: [[u16; 8]; 8],
983 xmm: [[u64; 2]; 16],
984 _padding: [u32; 24],
985 }
986 #[allow(dead_code)]
987 #[repr(C)]
988 struct mcontext_t {
989 es: exception_state,
990 ss: regs,
991 fs: fpstate,
992 }
993
994 let siginfo = siginfo as *const siginfo_t;
995 let si_addr = (*siginfo).si_addr;
996
997 let ucontext = ucontext as *mut ucontext_t;
998 let ss = &mut (*(*ucontext).uc_mcontext).ss;
999 let fs = &(*(*ucontext).uc_mcontext).fs;
1000
1001 let mut known_registers: [Option<u64>; 32] = [None; 32];
1002
1003 known_registers[X64Register::GPR(GPR::R15).to_index().0] = Some(ss.r15);
1004 known_registers[X64Register::GPR(GPR::R14).to_index().0] = Some(ss.r14);
1005 known_registers[X64Register::GPR(GPR::R13).to_index().0] = Some(ss.r13);
1006 known_registers[X64Register::GPR(GPR::R12).to_index().0] = Some(ss.r12);
1007 known_registers[X64Register::GPR(GPR::R11).to_index().0] = Some(ss.r11);
1008 known_registers[X64Register::GPR(GPR::R10).to_index().0] = Some(ss.r10);
1009 known_registers[X64Register::GPR(GPR::R9).to_index().0] = Some(ss.r9);
1010 known_registers[X64Register::GPR(GPR::R8).to_index().0] = Some(ss.r8);
1011 known_registers[X64Register::GPR(GPR::RSI).to_index().0] = Some(ss.rsi);
1012 known_registers[X64Register::GPR(GPR::RDI).to_index().0] = Some(ss.rdi);
1013 known_registers[X64Register::GPR(GPR::RDX).to_index().0] = Some(ss.rdx);
1014 known_registers[X64Register::GPR(GPR::RCX).to_index().0] = Some(ss.rcx);
1015 known_registers[X64Register::GPR(GPR::RBX).to_index().0] = Some(ss.rbx);
1016 known_registers[X64Register::GPR(GPR::RAX).to_index().0] = Some(ss.rax);
1017
1018 known_registers[X64Register::GPR(GPR::RBP).to_index().0] = Some(ss.rbp);
1019 known_registers[X64Register::GPR(GPR::RSP).to_index().0] = Some(ss.rsp);
1020
1021 known_registers[X64Register::XMM(XMM::XMM0).to_index().0] = Some(fs.xmm[0][0]);
1022 known_registers[X64Register::XMM(XMM::XMM1).to_index().0] = Some(fs.xmm[1][0]);
1023 known_registers[X64Register::XMM(XMM::XMM2).to_index().0] = Some(fs.xmm[2][0]);
1024 known_registers[X64Register::XMM(XMM::XMM3).to_index().0] = Some(fs.xmm[3][0]);
1025 known_registers[X64Register::XMM(XMM::XMM4).to_index().0] = Some(fs.xmm[4][0]);
1026 known_registers[X64Register::XMM(XMM::XMM5).to_index().0] = Some(fs.xmm[5][0]);
1027 known_registers[X64Register::XMM(XMM::XMM6).to_index().0] = Some(fs.xmm[6][0]);
1028 known_registers[X64Register::XMM(XMM::XMM7).to_index().0] = Some(fs.xmm[7][0]);
1029 known_registers[X64Register::XMM(XMM::XMM8).to_index().0] = Some(fs.xmm[8][0]);
1030 known_registers[X64Register::XMM(XMM::XMM9).to_index().0] = Some(fs.xmm[9][0]);
1031 known_registers[X64Register::XMM(XMM::XMM10).to_index().0] = Some(fs.xmm[10][0]);
1032 known_registers[X64Register::XMM(XMM::XMM11).to_index().0] = Some(fs.xmm[11][0]);
1033 known_registers[X64Register::XMM(XMM::XMM12).to_index().0] = Some(fs.xmm[12][0]);
1034 known_registers[X64Register::XMM(XMM::XMM13).to_index().0] = Some(fs.xmm[13][0]);
1035 known_registers[X64Register::XMM(XMM::XMM14).to_index().0] = Some(fs.xmm[14][0]);
1036 known_registers[X64Register::XMM(XMM::XMM15).to_index().0] = Some(fs.xmm[15][0]);
1037
1038 FaultInfo {
1039 faulting_addr: si_addr,
1040 ip: std::mem::transmute::<&mut u64, &'static Cell<usize>>(&mut ss.rip),
1041 known_registers,
1042 }
1043}