mirror of
https://github.com/fluencelabs/wasmer
synced 2025-03-30 22:41:03 +00:00
Inline breakpoint support in core.
This commit is contained in:
parent
2e1fb7abca
commit
db59127f71
@ -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)]
|
#[cfg(test)]
|
||||||
mod backend_test {
|
mod backend_test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -244,9 +244,59 @@ extern "C" fn signal_trap_handler(
|
|||||||
siginfo: *mut siginfo_t,
|
siginfo: *mut siginfo_t,
|
||||||
ucontext: *mut c_void,
|
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 {
|
unsafe {
|
||||||
let fault = get_fault_info(siginfo as _, ucontext);
|
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(());
|
let mut unwind_result: Box<dyn Any> = Box::new(());
|
||||||
|
|
||||||
@ -259,7 +309,7 @@ extern "C" fn signal_trap_handler(
|
|||||||
Ok(SIGTRAP) => {
|
Ok(SIGTRAP) => {
|
||||||
// breakpoint
|
// breakpoint
|
||||||
let out: Option<Result<(), Box<dyn Any>>> = with_breakpoint_map(|bkpt_map| {
|
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 {
|
x(BreakpointInfo {
|
||||||
fault: Some(&fault),
|
fault: Some(&fault),
|
||||||
})
|
})
|
||||||
@ -293,12 +343,11 @@ extern "C" fn signal_trap_handler(
|
|||||||
|
|
||||||
let es_image = CURRENT_CODE_VERSIONS.with(|versions| {
|
let es_image = CURRENT_CODE_VERSIONS.with(|versions| {
|
||||||
let versions = versions.borrow();
|
let versions = versions.borrow();
|
||||||
println!("V = {}", versions.len());
|
|
||||||
read_stack(
|
read_stack(
|
||||||
|| versions.iter(),
|
|| versions.iter(),
|
||||||
rsp as usize as *const u64,
|
rsp as usize as *const u64,
|
||||||
fault.known_registers,
|
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);
|
unwind_result = Box::new(image);
|
||||||
} else {
|
} else {
|
||||||
use colored::*;
|
use colored::*;
|
||||||
println!("F = {}", es_image.frames.len());
|
|
||||||
if es_image.frames.len() > 0 {
|
if es_image.frames.len() > 0 {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"\n{}",
|
"\n{}",
|
||||||
@ -374,12 +422,12 @@ unsafe fn install_sighandler() {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FaultInfo {
|
pub struct FaultInfo {
|
||||||
pub faulting_addr: *const c_void,
|
pub faulting_addr: *const c_void,
|
||||||
pub ip: *const c_void,
|
pub ip: &'static Cell<usize>,
|
||||||
pub known_registers: [Option<u64>; 24],
|
pub known_registers: [Option<u64>; 24],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(target_os = "linux", target_arch = "aarch64"))]
|
#[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)]
|
#[allow(dead_code)]
|
||||||
#[repr(packed)]
|
#[repr(packed)]
|
||||||
struct sigcontext {
|
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 siginfo = siginfo as *const siginfo_t;
|
||||||
let si_addr = (*siginfo).si_addr;
|
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 gregs = &(*ucontext).uc_mcontext.regs;
|
||||||
|
|
||||||
let mut known_registers: [Option<u64>; 24] = [None; 24];
|
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 {
|
FaultInfo {
|
||||||
faulting_addr: si_addr as usize as _,
|
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,
|
known_registers,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
|
#[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::{
|
use libc::{
|
||||||
_libc_xmmreg, ucontext_t, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_R15, REG_R8,
|
_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,
|
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 siginfo = siginfo as *const siginfo_t;
|
||||||
let si_addr = (*siginfo).si_addr;
|
let si_addr = (*siginfo).si_addr;
|
||||||
|
|
||||||
let ucontext = ucontext as *const ucontext_t;
|
let ucontext = ucontext as *mut ucontext_t;
|
||||||
let gregs = &(*ucontext).uc_mcontext.gregs;
|
let gregs = &mut (*ucontext).uc_mcontext.gregs;
|
||||||
let fpregs = &*(*ucontext).uc_mcontext.fpregs;
|
|
||||||
|
|
||||||
let mut known_registers: [Option<u64>; 24] = [None; 24];
|
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 _);
|
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::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::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]));
|
// WSL bug
|
||||||
known_registers[X64Register::XMM(XMM::XMM1).to_index().0] = Some(read_xmm(&fpregs._xmm[1]));
|
if !(*ucontext).uc_mcontext.fpregs.is_null() {
|
||||||
known_registers[X64Register::XMM(XMM::XMM2).to_index().0] = Some(read_xmm(&fpregs._xmm[2]));
|
let fpregs = &*(*ucontext).uc_mcontext.fpregs;
|
||||||
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::XMM0).to_index().0] = Some(read_xmm(&fpregs._xmm[0]));
|
||||||
known_registers[X64Register::XMM(XMM::XMM5).to_index().0] = Some(read_xmm(&fpregs._xmm[5]));
|
known_registers[X64Register::XMM(XMM::XMM1).to_index().0] = Some(read_xmm(&fpregs._xmm[1]));
|
||||||
known_registers[X64Register::XMM(XMM::XMM6).to_index().0] = Some(read_xmm(&fpregs._xmm[6]));
|
known_registers[X64Register::XMM(XMM::XMM2).to_index().0] = Some(read_xmm(&fpregs._xmm[2]));
|
||||||
known_registers[X64Register::XMM(XMM::XMM7).to_index().0] = Some(read_xmm(&fpregs._xmm[7]));
|
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 {
|
FaultInfo {
|
||||||
faulting_addr: si_addr as usize as _,
|
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,
|
known_registers,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::ops::Bound::{Included, Unbounded};
|
use std::ops::Bound::{Included, Unbounded};
|
||||||
|
use crate::backend::Backend;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
pub struct RegisterIndex(pub usize);
|
pub struct RegisterIndex(pub usize);
|
||||||
@ -111,6 +112,7 @@ pub struct CodeVersion {
|
|||||||
pub baseline: bool,
|
pub baseline: bool,
|
||||||
pub msm: ModuleStateMap,
|
pub msm: ModuleStateMap,
|
||||||
pub base: usize,
|
pub base: usize,
|
||||||
|
pub backend: Backend,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleStateMap {
|
impl ModuleStateMap {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user