diff --git a/lib/runtime-core/src/backend.rs b/lib/runtime-core/src/backend.rs index 0a062ba5f..9491c2377 100644 --- a/lib/runtime-core/src/backend.rs +++ b/lib/runtime-core/src/backend.rs @@ -70,6 +70,78 @@ impl std::str::FromStr for Backend { } } +#[derive(Copy, Clone, Debug)] +pub enum Architecture { + X64, + Aarch64, +} + +#[repr(u8)] +#[derive(Copy, Clone, Debug)] +pub enum InlineBreakpointType { + Trace, + Middleware, + Unknown, +} + +#[derive(Clone, Debug)] +pub struct InlineBreakpoint { + pub size: usize, + pub ty: InlineBreakpointType, +} + +pub fn get_inline_breakpoint_size(arch: Architecture, backend: Backend) -> Option<usize> { + match (arch, backend) { + (Architecture::X64, Backend::Singlepass) => Some(7), + (Architecture::Aarch64, Backend::Singlepass) => Some(12), + _ => None + } +} + +pub fn read_inline_breakpoint(arch: Architecture, backend: Backend, code: &[u8]) -> Option<InlineBreakpoint> { + match arch { + Architecture::X64 => match backend { + Backend::Singlepass => { + if code.len() < 7 { + None + } else if &code[..6] == &[0x0f, 0x0b, 0x0f, 0xb9, 0xcd, 0xff] { + // ud2 ud (int 0xff) code + Some(InlineBreakpoint { + size: 7, + ty: match code[6] { + 0 => InlineBreakpointType::Trace, + 1 => InlineBreakpointType::Middleware, + _ => InlineBreakpointType::Unknown, + }, + }) + } else { + None + } + } + _ => None + }, + Architecture::Aarch64 => match backend { + Backend::Singlepass => { + if code.len() < 12 { + None + } else if &code[..8] == &[0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff] { + Some(InlineBreakpoint { + size: 12, + ty: match code[8] { + 0 => InlineBreakpointType::Trace, + 1 => InlineBreakpointType::Middleware, + _ => InlineBreakpointType::Unknown, + } + }) + } else { + None + } + }, + _ => None, + } + } +} + #[cfg(test)] mod backend_test { use super::*; diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index 68148bb1c..23d17de16 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -244,9 +244,59 @@ extern "C" fn signal_trap_handler( siginfo: *mut siginfo_t, ucontext: *mut c_void, ) { + use crate::backend::{Architecture, InlineBreakpointType, get_inline_breakpoint_size, read_inline_breakpoint}; + + #[cfg(target_arch = "x86_64")] + static ARCH: Architecture = Architecture::X64; + + #[cfg(target_arch = "aarch64")] + static ARCH: Architecture = Architecture::Aarch64; + unsafe { let fault = get_fault_info(siginfo as _, ucontext); - println!("Fault: {:?}", fault); + let early_return = CURRENT_CODE_VERSIONS.with(|versions| { + let versions = versions.borrow(); + for v in versions.iter() { + let magic_size = if let Some(x) = get_inline_breakpoint_size(ARCH, v.backend) { + x + } else { + continue + }; + let ip = fault.ip.get(); + let end = v.base + v.msm.total_size; + if ip >= v.base && ip < end && ip + magic_size <= end { + if let Some(ib) = read_inline_breakpoint(ARCH, v.backend, unsafe { + std::slice::from_raw_parts(ip as *const u8, magic_size) + }) { + fault.ip.set(ip + magic_size); + + match ib.ty { + InlineBreakpointType::Trace => {}, + InlineBreakpointType::Middleware => { + let out: Option<Result<(), Box<dyn Any>>> = with_breakpoint_map(|bkpt_map| { + bkpt_map.and_then(|x| x.get(&ip)).map(|x| { + x(BreakpointInfo { + fault: Some(&fault), + }) + }) + }); + if let Some(Ok(())) = out { + } else { + println!("Failed calling middleware: {:?}", out); + } + } + _ => println!("Unknown breakpoint type: {:?}", ib.ty) + } + return true; + } + break; + } + } + false + }); + if early_return { + return; + } let mut unwind_result: Box<dyn Any> = Box::new(()); @@ -259,7 +309,7 @@ extern "C" fn signal_trap_handler( Ok(SIGTRAP) => { // breakpoint let out: Option<Result<(), Box<dyn Any>>> = with_breakpoint_map(|bkpt_map| { - bkpt_map.and_then(|x| x.get(&(fault.ip as usize))).map(|x| { + bkpt_map.and_then(|x| x.get(&(fault.ip.get()))).map(|x| { x(BreakpointInfo { fault: Some(&fault), }) @@ -293,12 +343,11 @@ extern "C" fn signal_trap_handler( let es_image = CURRENT_CODE_VERSIONS.with(|versions| { let versions = versions.borrow(); - println!("V = {}", versions.len()); read_stack( || versions.iter(), rsp as usize as *const u64, fault.known_registers, - Some(fault.ip as usize as u64), + Some(fault.ip.get() as u64), ) }); @@ -307,7 +356,6 @@ extern "C" fn signal_trap_handler( unwind_result = Box::new(image); } else { use colored::*; - println!("F = {}", es_image.frames.len()); if es_image.frames.len() > 0 { eprintln!( "\n{}", @@ -374,12 +422,12 @@ unsafe fn install_sighandler() { #[derive(Debug, Clone)] pub struct FaultInfo { pub faulting_addr: *const c_void, - pub ip: *const c_void, + pub ip: &'static Cell<usize>, pub known_registers: [Option<u64>; 24], } #[cfg(all(target_os = "linux", target_arch = "aarch64"))] -pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> FaultInfo { +pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> FaultInfo { #[allow(dead_code)] #[repr(packed)] struct sigcontext { @@ -411,7 +459,7 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> let siginfo = siginfo as *const siginfo_t; let si_addr = (*siginfo).si_addr; - let ucontext = ucontext as *const ucontext; + let ucontext = ucontext as *mut ucontext; let gregs = &(*ucontext).uc_mcontext.regs; let mut known_registers: [Option<u64>; 24] = [None; 24]; @@ -436,13 +484,13 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> FaultInfo { faulting_addr: si_addr as usize as _, - ip: (*ucontext).uc_mcontext.pc as _, + ip: std::mem::transmute::<&mut u64, &'static Cell<usize>>(&mut (*ucontext).uc_mcontext.pc), known_registers, } } #[cfg(all(target_os = "linux", target_arch = "x86_64"))] -pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> FaultInfo { +pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> FaultInfo { use libc::{ _libc_xmmreg, ucontext_t, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_R15, REG_R8, REG_R9, REG_RAX, REG_RBP, REG_RBX, REG_RCX, REG_RDI, REG_RDX, REG_RIP, REG_RSI, REG_RSP, @@ -465,9 +513,8 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> let siginfo = siginfo as *const siginfo_t; let si_addr = (*siginfo).si_addr; - let ucontext = ucontext as *const ucontext_t; - let gregs = &(*ucontext).uc_mcontext.gregs; - let fpregs = &*(*ucontext).uc_mcontext.fpregs; + let ucontext = ucontext as *mut ucontext_t; + let gregs = &mut (*ucontext).uc_mcontext.gregs; let mut known_registers: [Option<u64>; 24] = [None; 24]; known_registers[X64Register::GPR(GPR::R15).to_index().0] = Some(gregs[REG_R15 as usize] as _); @@ -488,18 +535,23 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> known_registers[X64Register::GPR(GPR::RBP).to_index().0] = Some(gregs[REG_RBP as usize] as _); known_registers[X64Register::GPR(GPR::RSP).to_index().0] = Some(gregs[REG_RSP as usize] as _); - known_registers[X64Register::XMM(XMM::XMM0).to_index().0] = Some(read_xmm(&fpregs._xmm[0])); - known_registers[X64Register::XMM(XMM::XMM1).to_index().0] = Some(read_xmm(&fpregs._xmm[1])); - known_registers[X64Register::XMM(XMM::XMM2).to_index().0] = Some(read_xmm(&fpregs._xmm[2])); - known_registers[X64Register::XMM(XMM::XMM3).to_index().0] = Some(read_xmm(&fpregs._xmm[3])); - known_registers[X64Register::XMM(XMM::XMM4).to_index().0] = Some(read_xmm(&fpregs._xmm[4])); - known_registers[X64Register::XMM(XMM::XMM5).to_index().0] = Some(read_xmm(&fpregs._xmm[5])); - known_registers[X64Register::XMM(XMM::XMM6).to_index().0] = Some(read_xmm(&fpregs._xmm[6])); - known_registers[X64Register::XMM(XMM::XMM7).to_index().0] = Some(read_xmm(&fpregs._xmm[7])); + // WSL bug + if !(*ucontext).uc_mcontext.fpregs.is_null() { + let fpregs = &*(*ucontext).uc_mcontext.fpregs; + + known_registers[X64Register::XMM(XMM::XMM0).to_index().0] = Some(read_xmm(&fpregs._xmm[0])); + known_registers[X64Register::XMM(XMM::XMM1).to_index().0] = Some(read_xmm(&fpregs._xmm[1])); + known_registers[X64Register::XMM(XMM::XMM2).to_index().0] = Some(read_xmm(&fpregs._xmm[2])); + known_registers[X64Register::XMM(XMM::XMM3).to_index().0] = Some(read_xmm(&fpregs._xmm[3])); + known_registers[X64Register::XMM(XMM::XMM4).to_index().0] = Some(read_xmm(&fpregs._xmm[4])); + known_registers[X64Register::XMM(XMM::XMM5).to_index().0] = Some(read_xmm(&fpregs._xmm[5])); + known_registers[X64Register::XMM(XMM::XMM6).to_index().0] = Some(read_xmm(&fpregs._xmm[6])); + known_registers[X64Register::XMM(XMM::XMM7).to_index().0] = Some(read_xmm(&fpregs._xmm[7])); + } FaultInfo { faulting_addr: si_addr as usize as _, - ip: gregs[REG_RIP as usize] as _, + ip: std::mem::transmute::<&mut i64, &'static Cell<usize>>(&mut gregs[REG_RIP as usize]), known_registers, } } diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 1896c5c9e..82f34eaed 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -1,5 +1,6 @@ use std::collections::BTreeMap; use std::ops::Bound::{Included, Unbounded}; +use crate::backend::Backend; #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct RegisterIndex(pub usize); @@ -111,6 +112,7 @@ pub struct CodeVersion { pub baseline: bool, pub msm: ModuleStateMap, pub base: usize, + pub backend: Backend, } impl ModuleStateMap {