panda-re 0.49.0

The official library for interfacing with PANDA (Platform for Architecture-Neutral Dynamic Analysis)
Documentation
use super::{GuestAlign, GuestPtr, GuestReadFail, GuestWriteFail};
use crate::prelude::*;
use crate::{enums::Endian, mem::*, GuestType, ARCH_ENDIAN};

use std::alloc::Layout;

macro_rules! impl_for_num {
    ($($ty:ty),*) => {
        $(
            impl GuestType for $ty {
                fn guest_layout() -> Option<Layout> {
                    Layout::from_size_align(
                        core::mem::size_of::<$ty>(),
                        <$ty as GuestAlign>::ALIGN
                    ).ok()
                }

                fn read_from_guest(cpu: &mut CPUState, ptr: target_ptr_t) -> Result<Self, GuestReadFail> {
                    let mut bytes = [0u8; core::mem::size_of::<$ty>()];
                    virtual_memory_read_into(cpu, ptr, &mut bytes).or(Err(GuestReadFail))?;

                    Ok(match ARCH_ENDIAN {
                        Endian::Big => <$ty>::from_be_bytes(bytes),
                        Endian::Little => <$ty>::from_le_bytes(bytes),
                    })
                }

                fn read_from_guest_phys(ptr: target_ptr_t) -> Result<Self, GuestReadFail> {
                    let mut bytes = [0u8; core::mem::size_of::<$ty>()];
                    physical_memory_read_into(ptr, &mut bytes).or(Err(GuestReadFail))?;

                    Ok(match ARCH_ENDIAN {
                        Endian::Big => <$ty>::from_be_bytes(bytes),
                        Endian::Little => <$ty>::from_le_bytes(bytes),
                    })
                }

                fn write_to_guest(&self, cpu: &mut CPUState, ptr: target_ptr_t) -> Result<(), GuestWriteFail> {
                    let bytes = match ARCH_ENDIAN {
                        Endian::Big => <$ty>::to_be_bytes(*self),
                        Endian::Little => <$ty>::to_le_bytes(*self),
                    };

                    virtual_memory_write(cpu, ptr, &bytes);

                    Ok(())
                }

                fn write_to_guest_phys(&self, ptr: target_ptr_t) -> Result<(), GuestWriteFail> {
                    let bytes = match ARCH_ENDIAN {
                        Endian::Big => <$ty>::to_be_bytes(*self),
                        Endian::Little => <$ty>::to_le_bytes(*self),
                    };

                    physical_memory_write(ptr, &bytes);

                    Ok(())
                }
            }
        )*
    };
}

impl_for_num!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64);

impl<T: GuestType> GuestType for GuestPtr<T> {
    fn guest_layout() -> Option<Layout> {
        target_ptr_t::guest_layout()
    }

    fn read_from_guest(cpu: &mut CPUState, ptr: target_ptr_t) -> Result<Self, GuestReadFail> {
        target_ptr_t::read_from_guest(cpu, ptr).map(Self::from)
    }

    fn write_to_guest(&self, cpu: &mut CPUState, ptr: target_ptr_t) -> Result<(), GuestWriteFail> {
        self.pointer.write_to_guest(cpu, ptr)
    }

    fn read_from_guest_phys(ptr: target_ptr_t) -> Result<Self, GuestReadFail> {
        target_ptr_t::read_from_guest_phys(ptr).map(Self::from)
    }

    fn write_to_guest_phys(&self, ptr: target_ptr_t) -> Result<(), GuestWriteFail> {
        self.pointer.write_to_guest_phys(ptr)
    }
}

fn padding_needed_for(layout: &Layout, align: usize) -> usize {
    let len = layout.size();

    let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
    len_rounded_up.wrapping_sub(len)
}

fn padded_size(layout: &Layout) -> usize {
    layout.size() + padding_needed_for(&layout, layout.align())
}

fn repeat(layout: &Layout, n: usize) -> Layout {
    let alloc_size = padded_size(layout)
        .checked_mul(n)
        .expect("Layout of guest array overflow");

    Layout::from_size_align(alloc_size, layout.align()).expect("Layout of guest array invalid")
}

impl<T: GuestType, const N: usize> GuestType for [T; N] {
    fn guest_layout() -> Option<Layout> {
        T::guest_layout().map(|layout| repeat(&layout, N))
    }

    fn read_from_guest(cpu: &mut CPUState, ptr: target_ptr_t) -> Result<Self, GuestReadFail> {
        let padded_size = padded_size(
            &T::guest_layout().expect("Cannot read array of unsized types from guest."),
        );

        array_init::from_iter(
            (ptr..)
                .step_by(padded_size)
                .take(N)
                .filter_map(|ptr| T::read_from_guest(cpu, ptr).ok()),
        )
        .ok_or(GuestReadFail)
    }

    fn write_to_guest(&self, cpu: &mut CPUState, ptr: target_ptr_t) -> Result<(), GuestWriteFail> {
        let padded_size = padded_size(
            &T::guest_layout().expect("Cannot write array of unsized types to the guest."),
        );

        for (ptr, item) in (ptr..).step_by(padded_size).zip(self.iter()) {
            item.write_to_guest(cpu, ptr)?;
        }

        Ok(())
    }

    fn read_from_guest_phys(ptr: target_ptr_t) -> Result<Self, GuestReadFail> {
        let padded_size = padded_size(
            &T::guest_layout().expect("Cannot read array of unsized types from guest."),
        );

        array_init::from_iter(
            (ptr..)
                .step_by(padded_size)
                .take(N)
                .filter_map(|ptr| T::read_from_guest_phys(ptr).ok()),
        )
        .ok_or(GuestReadFail)
    }

    fn write_to_guest_phys(&self, ptr: target_ptr_t) -> Result<(), GuestWriteFail> {
        let padded_size = padded_size(
            &T::guest_layout().expect("Cannot write array of unsized types to the guest."),
        );

        for (ptr, item) in (ptr..).step_by(padded_size).zip(self.iter()) {
            item.write_to_guest_phys(ptr)?;
        }

        Ok(())
    }
}