use crate::error::{self, Result};
pub type Address = u64;
pub type AddressDelta = i64;
pub type AddressSize = u64;
pub const BAD_ADDRESS: Address = !0u64;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Range {
pub start: Address,
pub end: Address,
}
impl Range {
pub fn new(start: Address, end: Address) -> Self {
Self { start, end }
}
pub fn size(&self) -> AddressSize {
if self.end > self.start {
self.end - self.start
} else {
0
}
}
pub fn contains(&self, ea: Address) -> bool {
ea >= self.start && ea < self.end
}
pub fn is_empty(&self) -> bool {
self.start >= self.end
}
}
impl Default for Range {
fn default() -> Self {
Self {
start: BAD_ADDRESS,
end: BAD_ADDRESS,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(i32)]
pub enum Predicate {
Mapped = 0,
Loaded = 1,
Code = 2,
Data = 3,
Unknown = 4,
Head = 5,
Tail = 6,
}
pub fn item_start(ea: Address) -> Result<Address> {
let mut out: Address = BAD_ADDRESS;
let ret = unsafe { idax_sys::idax_address_item_start(ea, &mut out) };
if ret != 0 {
Err(error::consume_last_error("item_start failed"))
} else {
Ok(out)
}
}
pub fn item_end(ea: Address) -> Result<Address> {
let mut out: Address = BAD_ADDRESS;
let ret = unsafe { idax_sys::idax_address_item_end(ea, &mut out) };
if ret != 0 {
Err(error::consume_last_error("item_end failed"))
} else {
Ok(out)
}
}
pub fn item_size(ea: Address) -> Result<AddressSize> {
let mut out: AddressSize = 0;
let ret = unsafe { idax_sys::idax_address_item_size(ea, &mut out) };
if ret != 0 {
Err(error::consume_last_error("item_size failed"))
} else {
Ok(out)
}
}
pub fn next_head(ea: Address, limit: Address) -> Result<Address> {
let mut out: Address = BAD_ADDRESS;
let ret = unsafe { idax_sys::idax_address_next_head(ea, limit, &mut out) };
if ret != 0 {
Err(error::consume_last_error("next_head failed"))
} else {
Ok(out)
}
}
pub fn prev_head(ea: Address, limit: Address) -> Result<Address> {
let mut out: Address = BAD_ADDRESS;
let ret = unsafe { idax_sys::idax_address_prev_head(ea, limit, &mut out) };
if ret != 0 {
Err(error::consume_last_error("prev_head failed"))
} else {
Ok(out)
}
}
pub fn next_defined(ea: Address, limit: Address) -> Result<Address> {
next_head(ea, limit)
}
pub fn prev_defined(ea: Address, limit: Address) -> Result<Address> {
prev_head(ea, limit)
}
pub fn next_not_tail(ea: Address) -> Result<Address> {
let mut out: Address = BAD_ADDRESS;
let ret = unsafe { idax_sys::idax_address_next_not_tail(ea, &mut out) };
if ret != 0 {
Err(error::consume_last_error("next_not_tail failed"))
} else {
Ok(out)
}
}
pub fn prev_not_tail(ea: Address) -> Result<Address> {
let mut out: Address = BAD_ADDRESS;
let ret = unsafe { idax_sys::idax_address_prev_not_tail(ea, &mut out) };
if ret != 0 {
Err(error::consume_last_error("prev_not_tail failed"))
} else {
Ok(out)
}
}
pub fn next_mapped(ea: Address) -> Result<Address> {
let mut out: Address = BAD_ADDRESS;
let ret = unsafe { idax_sys::idax_address_next_mapped(ea, &mut out) };
if ret != 0 {
Err(error::consume_last_error("next_mapped failed"))
} else {
Ok(out)
}
}
pub fn prev_mapped(ea: Address) -> Result<Address> {
let mut out: Address = BAD_ADDRESS;
let ret = unsafe { idax_sys::idax_address_prev_mapped(ea, &mut out) };
if ret != 0 {
Err(error::consume_last_error("prev_mapped failed"))
} else {
Ok(out)
}
}
pub fn find_first(start: Address, end: Address, predicate: Predicate) -> Result<Address> {
let mut out: Address = BAD_ADDRESS;
let ret = unsafe { idax_sys::idax_address_find_first(start, end, predicate as i32, &mut out) };
if ret != 0 {
Err(error::consume_last_error("find_first failed"))
} else {
Ok(out)
}
}
pub fn find_next(ea: Address, predicate: Predicate, end: Address) -> Result<Address> {
let mut out: Address = BAD_ADDRESS;
let ret = unsafe { idax_sys::idax_address_find_next(ea, predicate as i32, end, &mut out) };
if ret != 0 {
Err(error::consume_last_error("find_next failed"))
} else {
Ok(out)
}
}
pub fn is_mapped(ea: Address) -> bool {
unsafe { idax_sys::idax_address_is_mapped(ea) != 0 }
}
pub fn is_loaded(ea: Address) -> bool {
unsafe { idax_sys::idax_address_is_loaded(ea) != 0 }
}
pub fn is_code(ea: Address) -> bool {
unsafe { idax_sys::idax_address_is_code(ea) != 0 }
}
pub fn is_data(ea: Address) -> bool {
unsafe { idax_sys::idax_address_is_data(ea) != 0 }
}
pub fn is_unknown(ea: Address) -> bool {
unsafe { idax_sys::idax_address_is_unknown(ea) != 0 }
}
pub fn is_head(ea: Address) -> bool {
unsafe { idax_sys::idax_address_is_head(ea) != 0 }
}
pub fn is_tail(ea: Address) -> bool {
unsafe { idax_sys::idax_address_is_tail(ea) != 0 }
}
pub struct ItemIter {
current: Address,
end: Address,
}
impl Iterator for ItemIter {
type Item = Address;
fn next(&mut self) -> Option<Self::Item> {
if self.current >= self.end || self.current == BAD_ADDRESS {
return None;
}
let addr = self.current;
match next_head(self.current, self.end) {
Ok(next) => self.current = next,
Err(_) => self.current = BAD_ADDRESS,
}
Some(addr)
}
}
pub fn items(start: Address, end: Address) -> ItemIter {
let first = if is_head(start) {
start
} else {
next_head(start, end).unwrap_or(BAD_ADDRESS)
};
ItemIter {
current: if first < end { first } else { BAD_ADDRESS },
end,
}
}
pub struct PredicateIter {
current: Address,
end: Address,
predicate: Predicate,
}
impl PredicateIter {
fn test(&self, ea: Address) -> bool {
match self.predicate {
Predicate::Mapped => is_mapped(ea),
Predicate::Loaded => is_loaded(ea),
Predicate::Code => is_code(ea),
Predicate::Data => is_data(ea),
Predicate::Unknown => is_unknown(ea),
Predicate::Head => is_head(ea),
Predicate::Tail => is_tail(ea),
}
}
}
impl Iterator for PredicateIter {
type Item = Address;
fn next(&mut self) -> Option<Self::Item> {
if self.current >= self.end || self.current == BAD_ADDRESS {
return None;
}
let addr = self.current;
match next_head(self.current, self.end) {
Ok(next) => {
let mut candidate = next;
while candidate < self.end && candidate != BAD_ADDRESS {
if self.test(candidate) {
break;
}
candidate = next_head(candidate, self.end).unwrap_or(BAD_ADDRESS);
}
self.current = if candidate < self.end {
candidate
} else {
BAD_ADDRESS
};
}
Err(_) => self.current = BAD_ADDRESS,
}
Some(addr)
}
}
fn find_first_predicate(start: Address, end: Address, predicate: Predicate) -> Address {
let test = |ea: Address| -> bool {
match predicate {
Predicate::Mapped => is_mapped(ea),
Predicate::Loaded => is_loaded(ea),
Predicate::Code => is_code(ea),
Predicate::Data => is_data(ea),
Predicate::Unknown => is_unknown(ea),
Predicate::Head => is_head(ea),
Predicate::Tail => is_tail(ea),
}
};
if start < end && test(start) {
return start;
}
let mut candidate = next_head(start, end).unwrap_or(BAD_ADDRESS);
while candidate < end && candidate != BAD_ADDRESS {
if test(candidate) {
return candidate;
}
candidate = next_head(candidate, end).unwrap_or(BAD_ADDRESS);
}
BAD_ADDRESS
}
pub fn code_items(start: Address, end: Address) -> PredicateIter {
let first = find_first_predicate(start, end, Predicate::Code);
PredicateIter {
current: first,
end,
predicate: Predicate::Code,
}
}
pub fn data_items(start: Address, end: Address) -> PredicateIter {
let first = find_first_predicate(start, end, Predicate::Data);
PredicateIter {
current: first,
end,
predicate: Predicate::Data,
}
}
pub fn unknown_bytes(start: Address, end: Address) -> PredicateIter {
let first = find_first_predicate(start, end, Predicate::Unknown);
PredicateIter {
current: first,
end,
predicate: Predicate::Unknown,
}
}