diff --git a/lib/runtime-core/src/backend.rs b/lib/runtime-core/src/backend.rs index a16478176..22fec7fef 100644 --- a/lib/runtime-core/src/backend.rs +++ b/lib/runtime-core/src/backend.rs @@ -76,34 +76,53 @@ impl std::str::FromStr for Backend { } } +/// The target architecture for code generation. #[derive(Copy, Clone, Debug)] pub enum Architecture { + /// x86-64. X64, + + /// Aarch64 (ARM64). Aarch64, } +/// The type of an inline breakpoint. #[repr(u8)] #[derive(Copy, Clone, Debug)] pub enum InlineBreakpointType { - Trace, + /// A middleware invocation breakpoint. Middleware, - Unknown, } +/// Information of an inline breakpoint. #[derive(Clone, Debug)] pub struct InlineBreakpoint { + /// Size in bytes taken by this breakpoint's instruction sequence. pub size: usize, + + /// Type of the inline breakpoint. pub ty: InlineBreakpointType, } +/// Inline breakpoint size for (x86-64, singlepass). +pub const INLINE_BREAKPOINT_SIZE_X86_SINGLEPASS: usize = 7; + +/// Inline breakpoint size for (aarch64, singlepass). +pub const INLINE_BREAKPOINT_SIZE_AARCH64_SINGLEPASS: usize = 12; + +/// Returns the inline breakpoint size corresponding to an (Architecture, Backend) pair. pub fn get_inline_breakpoint_size(arch: Architecture, backend: Backend) -> Option { match (arch, backend) { - (Architecture::X64, Backend::Singlepass) => Some(7), - (Architecture::Aarch64, Backend::Singlepass) => Some(12), + (Architecture::X64, Backend::Singlepass) => Some(INLINE_BREAKPOINT_SIZE_X86_SINGLEPASS), + (Architecture::Aarch64, Backend::Singlepass) => Some(INLINE_BREAKPOINT_SIZE_AARCH64_SINGLEPASS), _ => None, } } +/// Attempts to read an inline breakpoint from the code. +/// +/// Inline breakpoints are detected by special instruction sequences that never +/// appear in valid code. pub fn read_inline_breakpoint( arch: Architecture, backend: Backend, @@ -112,16 +131,18 @@ pub fn read_inline_breakpoint( match arch { Architecture::X64 => match backend { Backend::Singlepass => { - if code.len() < 7 { + if code.len() < INLINE_BREAKPOINT_SIZE_X86_SINGLEPASS { None - } else if &code[..6] == &[0x0f, 0x0b, 0x0f, 0xb9, 0xcd, 0xff] { - // ud2 ud (int 0xff) code + } else if &code[..INLINE_BREAKPOINT_SIZE_X86_SINGLEPASS - 1] == &[ + 0x0f, 0x0b, // ud2 + 0x0f, 0xb9, // ud + 0xcd, 0xff, // int 0xff + ] { Some(InlineBreakpoint { - size: 7, - ty: match code[6] { - 0 => InlineBreakpointType::Trace, - 1 => InlineBreakpointType::Middleware, - _ => InlineBreakpointType::Unknown, + size: INLINE_BREAKPOINT_SIZE_X86_SINGLEPASS, + ty: match code[INLINE_BREAKPOINT_SIZE_X86_SINGLEPASS - 1] { + 0 => InlineBreakpointType::Middleware, + _ => return None, }, }) } else { @@ -132,15 +153,17 @@ pub fn read_inline_breakpoint( }, Architecture::Aarch64 => match backend { Backend::Singlepass => { - if code.len() < 12 { + if code.len() < INLINE_BREAKPOINT_SIZE_AARCH64_SINGLEPASS { None - } else if &code[..8] == &[0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff] { + } else if &code[..INLINE_BREAKPOINT_SIZE_AARCH64_SINGLEPASS - 4] == &[ + 0, 0, 0, 0, // udf #0 + 0xff, 0xff, 0x00, 0x00, // udf #65535 + ] { Some(InlineBreakpoint { - size: 12, - ty: match code[8] { - 0 => InlineBreakpointType::Trace, - 1 => InlineBreakpointType::Middleware, - _ => InlineBreakpointType::Unknown, + size: INLINE_BREAKPOINT_SIZE_AARCH64_SINGLEPASS, + ty: match code[INLINE_BREAKPOINT_SIZE_AARCH64_SINGLEPASS - 4] { + 0 => InlineBreakpointType::Middleware, + _ => return None, }, }) } else {