use lief_ffi as ffi;
use std::marker::PhantomData;
use super::ExceptionInfo;
use crate::common::FromFFI;
use crate::{declare_iterator, to_slice};
#[derive(Debug)]
pub enum RuntimeFunction<'a> {
Packed(Packed<'a>),
Unpacked(Unpacked<'a>),
}
impl<'a> FromFFI<ffi::PE_RuntimeFunctionAArch64> for RuntimeFunction<'a> {
fn from_ffi(ffi_entry: cxx::UniquePtr<ffi::PE_RuntimeFunctionAArch64>) -> Self {
unsafe {
let obj_ref = ffi_entry.as_ref().unwrap();
if ffi::PE_unwind_aarch64_UnpackedFunction::classof(obj_ref) {
let raw = {
type From = cxx::UniquePtr<ffi::PE_RuntimeFunctionAArch64>;
type To = cxx::UniquePtr<ffi::PE_unwind_aarch64_UnpackedFunction>;
std::mem::transmute::<From, To>(ffi_entry)
};
RuntimeFunction::Unpacked(Unpacked::from_ffi(raw))
} else if ffi::PE_unwind_aarch64_PackedFunction::classof(obj_ref) {
let raw = {
type From = cxx::UniquePtr<ffi::PE_RuntimeFunctionAArch64>;
type To = cxx::UniquePtr<ffi::PE_unwind_aarch64_PackedFunction>;
std::mem::transmute::<From, To>(ffi_entry)
};
RuntimeFunction::Packed(Packed::from_ffi(raw))
} else {
panic!("unsupported format: {}", obj_ref.as_ref().to_string());
}
}
}
}
impl ExceptionInfo for RuntimeFunction<'_> {
fn as_generic(&self) -> &ffi::PE_ExceptionInfo {
match &self {
RuntimeFunction::Packed(f) => f.as_generic(),
RuntimeFunction::Unpacked(f) => f.as_generic(),
}
}
}
pub struct Packed<'a> {
ptr: cxx::UniquePtr<ffi::PE_unwind_aarch64_PackedFunction>,
_owner: PhantomData<&'a ffi::PE_Binary>,
}
impl<'a> FromFFI<ffi::PE_unwind_aarch64_PackedFunction> for Packed<'a> {
fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_unwind_aarch64_PackedFunction>) -> Self {
Self {
ptr,
_owner: PhantomData,
}
}
}
impl Packed<'_> {
pub fn frame_size(&self) -> u8 {
self.ptr.frame_size()
}
#[allow(non_snake_case)]
pub fn reg_I(&self) -> u8 {
self.ptr.reg_I()
}
#[allow(non_snake_case)]
pub fn reg_F(&self) -> u8 {
self.ptr.reg_F()
}
#[allow(non_snake_case)]
pub fn H(&self) -> u8 {
self.ptr.H()
}
#[allow(non_snake_case)]
pub fn CR(&self) -> u8 {
self.ptr.CR()
}
}
impl ExceptionInfo for Packed<'_> {
fn as_generic(&self) -> &ffi::PE_ExceptionInfo {
self.ptr.as_ref().unwrap().as_ref().as_ref()
}
}
impl std::fmt::Debug for Packed<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Packed")
.field("frame_size", &self.frame_size())
.field("RI", &self.reg_I())
.field("RF", &self.reg_F())
.field("H", &self.H())
.field("CR", &self.CR())
.finish()
}
}
pub struct Unpacked<'a> {
ptr: cxx::UniquePtr<ffi::PE_unwind_aarch64_UnpackedFunction>,
_owner: PhantomData<&'a ffi::PE_Binary>,
}
impl<'a> FromFFI<ffi::PE_unwind_aarch64_UnpackedFunction> for Unpacked<'a> {
fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_unwind_aarch64_UnpackedFunction>) -> Self {
Self {
ptr,
_owner: PhantomData,
}
}
}
impl Unpacked<'_> {
pub fn xdata_rva(&self) -> u32 {
self.ptr.xdata_rva()
}
pub fn version(&self) -> u32 {
self.ptr.version()
}
#[allow(non_snake_case)]
pub fn X(&self) -> u8 {
self.ptr.X()
}
#[allow(non_snake_case)]
pub fn E(&self) -> u8 {
self.ptr.E()
}
pub fn epilog_count(&self) -> u16 {
self.ptr.epilog_count()
}
pub fn epilog_offset(&self) -> u16 {
self.ptr.epilog_offset()
}
pub fn code_words(&self) -> u32 {
self.ptr.code_words()
}
pub fn exception_handler(&self) -> u32 {
self.ptr.exception_handler()
}
pub fn unwind_code(&self) -> &[u8] {
to_slice!(self.ptr.unwind_code());
}
pub fn epilog_scopes(&self) -> EpilogScopes<'_> {
EpilogScopes::new(self.ptr.epilog_scopes())
}
}
impl ExceptionInfo for Unpacked<'_> {
fn as_generic(&self) -> &ffi::PE_ExceptionInfo {
self.ptr.as_ref().unwrap().as_ref().as_ref()
}
}
impl std::fmt::Debug for Unpacked<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Unpacked")
.field("xdata_rva", &self.xdata_rva())
.field("version", &self.version())
.field("X", &self.X())
.field("E", &self.E())
.field("epilog_count", &self.epilog_count())
.field("epilog_offset", &self.epilog_offset())
.field("code_words", &self.code_words())
.field("exception_handler", &self.exception_handler())
.finish()
}
}
pub struct EpilogScope<'a> {
ptr: cxx::UniquePtr<ffi::PE_unwind_aarch64_UnpackedFunction_epilog_scope_t>,
_owner: PhantomData<&'a ffi::PE_unwind_aarch64_UnpackedFunction>,
}
impl<'a> FromFFI<ffi::PE_unwind_aarch64_UnpackedFunction_epilog_scope_t> for EpilogScope<'a> {
fn from_ffi(
ptr: cxx::UniquePtr<ffi::PE_unwind_aarch64_UnpackedFunction_epilog_scope_t>,
) -> Self {
Self {
ptr,
_owner: PhantomData,
}
}
}
impl EpilogScope<'_> {
pub fn start_offset(&self) -> u32 {
self.ptr.start_offset()
}
pub fn start_index(&self) -> u16 {
self.ptr.start_index()
}
pub fn reserved(&self) -> u8 {
self.ptr.reserved()
}
}
impl std::fmt::Debug for EpilogScope<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("EpilogScope")
.field("start_offset", &self.start_offset())
.field("start_index", &self.start_index())
.field("reserved", &self.reserved())
.finish()
}
}
declare_iterator!(
EpilogScopes,
EpilogScope<'a>,
ffi::PE_unwind_aarch64_UnpackedFunction_epilog_scope_t,
ffi::PE_unwind_aarch64_UnpackedFunction,
ffi::PE_unwind_aarch64_UnpackedFunction_it_const_epilog_scopes
);