idakit 0.2.0

Idiomatic Rust bindings for IDA Pro's idalib kernel
Documentation
//! Typed reads of the data at an address: fixed-width integers, pointers, and strings.
//!
//! These interpret the analyzed image (the raw [`bytes`](Database::bytes)) as values, in the
//! database's byte order. Each read is `None` when the covered bytes are not fully mapped, so a
//! read off the end of a segment fails rather than quietly returning zero. They pair with the
//! data [`xrefs_to`](Database::xrefs_to): follow a data xref to an address, then read what
//! lives there.

use crate::Database;
use crate::address::Address;
use crate::bitness::Bitness;

impl Database {
    /// Read the unsigned byte at `address`, or `None` if it is not mapped.
    #[must_use]
    #[doc(alias("get_byte"))]
    pub fn read_u8(&self, address: Address) -> Option<u8> {
        self.get_u8(address)
    }

    /// Read a 16-bit unsigned value at `address` (database byte order), or `None` if the two
    /// covered bytes are not fully mapped.
    #[must_use]
    #[doc(alias("get_word"))]
    pub fn read_u16(&self, address: Address) -> Option<u16> {
        self.get_u16(address)
    }

    /// Read a 32-bit unsigned value at `address` (database byte order), or `None` if the four
    /// covered bytes are not fully mapped.
    #[must_use]
    #[doc(alias("get_dword"))]
    pub fn read_u32(&self, address: Address) -> Option<u32> {
        self.get_u32(address)
    }

    /// Read a 64-bit unsigned value at `address` (database byte order), or `None` if the eight
    /// covered bytes are not fully mapped.
    #[must_use]
    #[doc(alias("get_qword"))]
    pub fn read_u64(&self, address: Address) -> Option<u64> {
        self.get_u64(address)
    }

    /// Read a pointer at `address` as an [`Address`].
    ///
    /// The pointer is the width of the database's address size (4 bytes for a 32-bit image, 8
    /// for 64-bit). `None` if the database reports no recognized [`Bitness`], the bytes are
    /// unmapped, or the stored value is the `BADADDR` sentinel.
    #[must_use]
    pub fn read_pointer(&self, address: Address) -> Option<Address> {
        let raw = match self.bitness()? {
            Bitness::Bits64 => self.read_u64(address)?,
            Bitness::Bits32 => u64::from(self.read_u32(address)?),
            Bitness::Bits16 => u64::from(self.read_u16(address)?),
        };
        Address::try_new(raw)
    }

    /// Read the C string (1-byte units, NUL-terminated) at `address`, decoded as UTF-8, or
    /// `None` if `address` holds no string.
    ///
    /// The length is auto-detected up to the terminator, and undecodable bytes become the
    /// Unicode replacement character (U+FFFD). For wide strings and a whole-database sweep, use
    /// [`strings`](Database::strings) instead.
    #[must_use]
    #[doc(alias("get_strlit_contents"))]
    pub fn read_string(&self, address: Address) -> Option<String> {
        self.get_strlit(address, 0)
    }
}