#![allow(clippy::module_name_repetitions)]
pub mod registry;
pub use registry::{for_arch, register, CodecFactory};
#[derive(Debug, thiserror::Error)]
pub enum ArchError {
#[error("arch {arch} does not support {operation}")]
Unsupported {
arch: &'static str,
operation: &'static str,
},
#[error("assembly failed: {0}")]
Assemble(String),
#[error("operand out of range: {0}")]
OutOfRange(String),
#[error(
"no codec registered for arch = {arch:?}, e_machine = {e_machine:?}; \
did you call <arch_crate>::register() at startup?"
)]
UnknownArch {
arch: Option<String>,
e_machine: Option<u64>,
},
#[error("{0}")]
Other(String),
}
#[derive(Debug, Clone, Copy, Default)]
pub struct EncodeHints {
pub wide: Option<bool>,
pub bpf_call_local: Option<bool>,
}
impl EncodeHints {
#[must_use]
pub const fn wide(wide: bool) -> Self {
Self {
wide: Some(wide),
bpf_call_local: None,
}
}
#[must_use]
pub fn wide_or(self, default: bool) -> bool {
self.wide.unwrap_or(default)
}
}
#[derive(Debug, Clone, Copy)]
pub struct SwitchSpec<'a> {
pub selector: &'a str,
pub cases: &'a [u64],
pub default_addr: u64,
pub dispatch: &'a str,
pub table_va: u64,
pub cmp_ip: u64,
}
pub trait ArchCodec: Sync + Send + std::fmt::Debug {
fn name(&self) -> &'static str;
fn assemble_one(&self, text: &str, addr: u64) -> Result<Vec<u8>, ArchError>;
fn desymbolize(&self, text: &str, _addr: u64) -> String {
text.to_string()
}
fn encode_jump(
&self,
source_ip: u64,
target: u64,
hints: EncodeHints,
) -> Result<Vec<u8>, ArchError>;
fn encode_call(
&self,
source_ip: u64,
target: u64,
hints: EncodeHints,
) -> Result<Vec<u8>, ArchError>;
fn encode_cond_jump(
&self,
cond_text: &str,
source_ip: u64,
target: u64,
hints: EncodeHints,
) -> Result<Vec<u8>, ArchError>;
fn encode_cond_jump_with_code(
&self,
_cond_code: u8,
_source_ip: u64,
_target: u64,
_hints: EncodeHints,
) -> Result<Vec<u8>, ArchError> {
Err(ArchError::Unsupported {
arch: self.name(),
operation: "cond_jump_with_code",
})
}
fn encode_switch_dispatch(&self, _spec: &SwitchSpec) -> Result<Vec<u8>, ArchError> {
Err(ArchError::Unsupported {
arch: self.name(),
operation: "switch_dispatch",
})
}
fn encoded_jump_size(&self, source_ip: u64, target: u64, hints: EncodeHints) -> usize;
fn encoded_cond_jump_size(&self, source_ip: u64, target: u64, hints: EncodeHints) -> usize;
fn encoded_call_size(&self, source_ip: u64, target: u64, hints: EncodeHints) -> usize;
fn direct_call_bytes_contain_call(&self) -> bool {
false
}
fn encode_move(&self, _dst: &str, _src: &str) -> Result<Vec<u8>, ArchError> {
Err(ArchError::Unsupported {
arch: self.name(),
operation: "move",
})
}
fn encode_arith(&self, _dst: &str, _op: &str, _src: &str) -> Result<Vec<u8>, ArchError> {
Err(ArchError::Unsupported {
arch: self.name(),
operation: "arith",
})
}
fn encode_return(&self, _value: Option<u64>) -> Result<Vec<u8>, ArchError> {
Err(ArchError::Unsupported {
arch: self.name(),
operation: "return",
})
}
}