use crate::Error;
use serde::{Deserialize, Serialize};
use std::{
cmp::Ordering,
convert::Infallible,
fmt::{Display, Formatter},
};
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub enum RegisterDataType {
UnsignedInteger(usize),
FloatingPoint(usize),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub enum RegisterRole {
Core(&'static str),
Argument(&'static str),
Return(&'static str),
ProgramCounter,
FramePointer,
StackPointer,
MainStackPointer,
ProcessStackPointer,
ProcessorStatus,
ReturnAddress,
FloatingPoint,
FloatingPointStatus,
Other(&'static str),
}
impl Display for RegisterRole {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
RegisterRole::Core(name) => write!(f, "{name}"),
RegisterRole::Argument(name) => write!(f, "{name}"),
RegisterRole::Return(name) => write!(f, "{name}"),
RegisterRole::ProgramCounter => write!(f, "PC"),
RegisterRole::FramePointer => write!(f, "FP"),
RegisterRole::StackPointer => write!(f, "SP"),
RegisterRole::MainStackPointer => write!(f, "MSP"),
RegisterRole::ProcessStackPointer => write!(f, "PSP"),
RegisterRole::ProcessorStatus => write!(f, "PSR"),
RegisterRole::ReturnAddress => write!(f, "LR"),
RegisterRole::FloatingPoint => write!(f, "FPU"),
RegisterRole::FloatingPointStatus => write!(f, "FPSR"),
RegisterRole::Other(name) => write!(f, "{name}"),
}
}
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnwindRule {
Preserve,
#[default]
Clear,
SpecialRule,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct CoreRegister {
pub id: RegisterId,
pub roles: &'static [RegisterRole],
pub data_type: RegisterDataType,
#[serde(skip_serializing)]
pub unwind_rule: UnwindRule,
}
impl PartialOrd for CoreRegister {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for CoreRegister {
fn cmp(&self, other: &Self) -> Ordering {
self.id.cmp(&other.id)
}
}
impl Display for CoreRegister {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let primary_name = self.name();
write!(f, "{primary_name}")?;
if !self.roles.is_empty() {
for role in self.roles {
if primary_name != role.to_string() {
write!(f, "/{role}")?;
}
}
}
Ok(())
}
}
impl CoreRegister {
pub fn name(&self) -> &'static str {
self.roles
.iter()
.find_map(|role| match role {
RegisterRole::Core(name) => Some(*name),
_ => None,
})
.unwrap_or("Unknown")
}
pub fn id(&self) -> RegisterId {
self.id
}
pub fn data_type(&self) -> RegisterDataType {
self.data_type.clone()
}
pub fn size_in_bits(&self) -> usize {
match self.data_type() {
RegisterDataType::UnsignedInteger(size_in_bits) => size_in_bits,
RegisterDataType::FloatingPoint(size_in_bits) => size_in_bits,
}
}
pub fn size_in_bytes(&self) -> usize {
self.size_in_bits().div_ceil(8)
}
pub fn format_hex_width(&self) -> usize {
(self.size_in_bytes() * 2) + 2
}
pub fn register_has_role(&self, role: RegisterRole) -> bool {
for r in self.roles {
if r == &role {
return true;
}
}
false
}
}
impl From<CoreRegister> for RegisterId {
fn from(description: CoreRegister) -> RegisterId {
description.id
}
}
impl From<&CoreRegister> for RegisterId {
fn from(description: &CoreRegister) -> RegisterId {
description.id
}
}
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct RegisterId(pub u16);
impl From<RegisterId> for u32 {
fn from(value: RegisterId) -> Self {
u32::from(value.0)
}
}
impl From<u16> for RegisterId {
fn from(value: u16) -> Self {
RegisterId(value)
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum RegisterValue {
U32(u32),
U64(u64),
U128(u128),
}
impl RegisterValue {
pub fn increment_address(&mut self, bytes: usize) -> Result<(), Error> {
match self {
RegisterValue::U32(value) => {
if let Some(reg_val) = value.checked_add(bytes as u32) {
*value = reg_val;
Ok(())
} else {
Err(Error::Other(format!(
"Overflow error: Attempting to add {bytes} bytes to Register value {self}"
)))
}
}
RegisterValue::U64(value) => {
if let Some(reg_val) = value.checked_add(bytes as u64) {
*value = reg_val;
Ok(())
} else {
Err(Error::Other(format!(
"Overflow error: Attempting to add {bytes} bytes to Register value {self}"
)))
}
}
RegisterValue::U128(value) => {
if let Some(reg_val) = value.checked_add(bytes as u128) {
*value = reg_val;
Ok(())
} else {
Err(Error::Other(format!(
"Overflow error: Attempting to add {bytes} bytes to Register value {self}"
)))
}
}
}
}
pub fn decrement_address(&mut self, bytes: usize) -> Result<(), Error> {
match self {
RegisterValue::U32(value) => {
if let Some(reg_val) = value.checked_sub(bytes as u32) {
*value = reg_val;
Ok(())
} else {
Err(Error::Other(format!(
"Overflow error: Attempting to subtract {bytes} bytes to Register value {self}"
)))
}
}
RegisterValue::U64(value) => {
if let Some(reg_val) = value.checked_sub(bytes as u64) {
*value = reg_val;
Ok(())
} else {
Err(Error::Other(format!(
"Overflow error: Attempting to subtract {bytes} bytes to Register value {self}"
)))
}
}
RegisterValue::U128(value) => {
if let Some(reg_val) = value.checked_sub(bytes as u128) {
*value = reg_val;
Ok(())
} else {
Err(Error::Other(format!(
"Overflow error: Attempting to subtract {bytes} bytes to Register value {self}"
)))
}
}
}
}
pub fn is_max_value(&self) -> bool {
match self {
RegisterValue::U32(register_value) => *register_value == u32::MAX,
RegisterValue::U64(register_value) => *register_value == u64::MAX,
RegisterValue::U128(register_value) => *register_value == u128::MAX,
}
}
pub fn is_zero(&self) -> bool {
matches!(
self,
RegisterValue::U32(0) | RegisterValue::U64(0) | RegisterValue::U128(0)
)
}
}
impl Default for RegisterValue {
fn default() -> Self {
RegisterValue::U32(0_u32)
}
}
impl PartialOrd for RegisterValue {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
let self_value = match self {
RegisterValue::U32(self_value) => *self_value as u128,
RegisterValue::U64(self_value) => *self_value as u128,
RegisterValue::U128(self_value) => *self_value,
};
let other_value = match other {
RegisterValue::U32(other_value) => *other_value as u128,
RegisterValue::U64(other_value) => *other_value as u128,
RegisterValue::U128(other_value) => *other_value,
};
self_value.partial_cmp(&other_value)
}
}
impl PartialEq for RegisterValue {
fn eq(&self, other: &Self) -> bool {
let self_value = match self {
RegisterValue::U32(self_value) => *self_value as u128,
RegisterValue::U64(self_value) => *self_value as u128,
RegisterValue::U128(self_value) => *self_value,
};
let other_value = match other {
RegisterValue::U32(other_value) => *other_value as u128,
RegisterValue::U64(other_value) => *other_value as u128,
RegisterValue::U128(other_value) => *other_value,
};
self_value == other_value
}
}
impl core::fmt::Display for RegisterValue {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
RegisterValue::U32(register_value) => write!(f, "{register_value:#010x}"),
RegisterValue::U64(register_value) => write!(f, "{register_value:#018x}"),
RegisterValue::U128(register_value) => write!(f, "{register_value:#034x}"),
}
}
}
impl From<u32> for RegisterValue {
fn from(val: u32) -> Self {
Self::U32(val)
}
}
impl From<u64> for RegisterValue {
fn from(val: u64) -> Self {
Self::U64(val)
}
}
impl From<u128> for RegisterValue {
fn from(val: u128) -> Self {
Self::U128(val)
}
}
impl TryInto<u32> for RegisterValue {
type Error = crate::Error;
fn try_into(self) -> Result<u32, Self::Error> {
match self {
Self::U32(v) => Ok(v),
Self::U64(v) => v
.try_into()
.map_err(|_| crate::Error::Other(format!("Value '{v}' too large for u32"))),
Self::U128(v) => v
.try_into()
.map_err(|_| crate::Error::Other(format!("Value '{v}' too large for u32"))),
}
}
}
impl TryInto<u64> for RegisterValue {
type Error = crate::Error;
fn try_into(self) -> Result<u64, Self::Error> {
match self {
Self::U32(v) => Ok(v.into()),
Self::U64(v) => Ok(v),
Self::U128(v) => v
.try_into()
.map_err(|_| crate::Error::Other(format!("Value '{v}' too large for u64"))),
}
}
}
impl TryInto<u128> for RegisterValue {
type Error = crate::Error;
fn try_into(self) -> Result<u128, Self::Error> {
match self {
Self::U32(v) => Ok(v.into()),
Self::U64(v) => Ok(v.into()),
Self::U128(v) => Ok(v),
}
}
}
pub trait RegisterValueResultExt<T> {
fn into_crate_error(self) -> Result<T, Error>;
}
impl<T> RegisterValueResultExt<T> for Result<T, Error> {
fn into_crate_error(self) -> Result<T, Error> {
self
}
}
impl<T> RegisterValueResultExt<T> for Result<T, Infallible> {
fn into_crate_error(self) -> Result<T, Error> {
Ok(self.unwrap())
}
}
#[derive(Debug, PartialEq)]
pub struct CoreRegisters(Vec<&'static CoreRegister>);
impl CoreRegisters {
pub fn new(core_registers: Vec<&'static CoreRegister>) -> CoreRegisters {
CoreRegisters(core_registers)
}
pub fn core_registers(&self) -> impl Iterator<Item = &CoreRegister> {
self.0
.iter()
.filter(|r| {
!r.roles.iter().any(|role| {
matches!(
role,
RegisterRole::FloatingPoint | RegisterRole::FloatingPointStatus
)
})
})
.cloned()
}
pub fn all_registers(&self) -> impl Iterator<Item = &CoreRegister> {
self.0.iter().cloned()
}
pub fn core_register(&self, index: usize) -> &CoreRegister {
self.core_registers().nth(index).unwrap()
}
pub fn get_core_register(&self, index: usize) -> Option<&CoreRegister> {
self.core_registers().nth(index)
}
pub fn argument_register(&self, index: usize) -> &CoreRegister {
self.get_argument_register(index).unwrap()
}
pub fn get_argument_register(&self, index: usize) -> Option<&CoreRegister> {
self.0
.iter()
.filter(|r| {
r.roles
.iter()
.any(|role| matches!(role, RegisterRole::Argument(_)))
})
.cloned()
.nth(index)
}
pub fn result_register(&self, index: usize) -> &CoreRegister {
self.get_result_register(index).unwrap()
}
pub fn get_result_register(&self, index: usize) -> Option<&CoreRegister> {
self.0
.iter()
.filter(|r| {
r.roles
.iter()
.any(|role| matches!(role, RegisterRole::Return(_)))
})
.cloned()
.nth(index)
}
pub fn pc(&self) -> Option<&CoreRegister> {
self.0
.iter()
.find(|r| r.register_has_role(RegisterRole::ProgramCounter))
.cloned()
}
pub fn msp(&self) -> Option<&CoreRegister> {
self.0
.iter()
.find(|r| r.register_has_role(RegisterRole::MainStackPointer))
.cloned()
}
pub fn psp(&self) -> Option<&CoreRegister> {
self.0
.iter()
.find(|r| r.register_has_role(RegisterRole::ProcessStackPointer))
.cloned()
}
pub fn psr(&self) -> Option<&CoreRegister> {
self.0
.iter()
.find(|r| r.register_has_role(RegisterRole::ProcessorStatus))
.cloned()
}
pub fn other_by_name(&self, name: &str) -> Option<&CoreRegister> {
self.0
.iter()
.find(|r| {
r.roles
.iter()
.any(|role| matches!(role, RegisterRole::Other(n) if *n == name))
})
.cloned()
}
pub fn fpsr(&self) -> Option<&CoreRegister> {
self.0
.iter()
.find(|r| r.register_has_role(RegisterRole::FloatingPointStatus))
.cloned()
}
pub fn fpu_status_registers(&self) -> Option<impl Iterator<Item = &CoreRegister>> {
let mut fpu_registers = self
.0
.iter()
.filter(|r| r.register_has_role(RegisterRole::FloatingPointStatus))
.peekable();
if fpu_registers.peek().is_some() {
Some(fpu_registers.cloned())
} else {
None
}
}
pub fn fpu_registers(&self) -> Option<impl Iterator<Item = &CoreRegister>> {
let mut fpu_registers = self
.0
.iter()
.filter(|r| r.register_has_role(RegisterRole::FloatingPoint))
.peekable();
if fpu_registers.peek().is_some() {
Some(fpu_registers.cloned())
} else {
None
}
}
pub fn fpu_register(&self, index: usize) -> &CoreRegister {
self.get_fpu_register(index).unwrap()
}
pub fn get_fpu_register(&self, index: usize) -> Option<&CoreRegister> {
self.0
.iter()
.filter(|r| r.register_has_role(RegisterRole::FloatingPoint))
.cloned()
.nth(index)
}
}