use std::ptr::NonNull;
pub trait TypeWalkSink {
fn scalar(&mut self, kind: u32, bytes: u32, signed: u32, size: u64, has_size: u32) -> u32;
fn ptr(&mut self, target: u32, size: u64, has_size: u32) -> u32;
fn array(&mut self, elem: u32, nelems: u64, size: u64, has_size: u32) -> u32;
fn func(&mut self, ret: u32, params: &[u32], vararg: u32) -> u32;
fn opaque(&mut self, name: &str) -> u32;
fn named_ref(&mut self, name: &str) -> u32;
fn anon(&mut self) -> u32;
fn fill_struct(
&mut self,
id: u32,
is_union: bool,
members: &[ffi::MemberInfo],
size: u64,
has_size: u32,
);
fn fill_enum(
&mut self,
id: u32,
underlying: u32,
consts: &[ffi::EnumConstInfo],
size: u64,
has_size: u32,
);
fn fill_typedef(&mut self, id: u32, underlying: u32);
}
pub struct TypeWalkVisitor {
sink: NonNull<dyn TypeWalkSink>,
}
impl TypeWalkVisitor {
fn new(sink: &mut dyn TypeWalkSink) -> Self {
let sink: NonNull<dyn TypeWalkSink> = unsafe { std::mem::transmute(NonNull::from(sink)) };
Self { sink }
}
fn sink(&mut self) -> &mut dyn TypeWalkSink {
unsafe { self.sink.as_mut() }
}
fn scalar(&mut self, kind: u32, bytes: u32, is_signed: u32, size: u64, has_size: u32) -> u32 {
self.sink().scalar(kind, bytes, is_signed, size, has_size)
}
fn ptr(&mut self, target: u32, size: u64, has_size: u32) -> u32 {
self.sink().ptr(target, size, has_size)
}
fn array(&mut self, elem: u32, nelems: u64, size: u64, has_size: u32) -> u32 {
self.sink().array(elem, nelems, size, has_size)
}
fn func(&mut self, ret: u32, params: &[u32], vararg: u32) -> u32 {
self.sink().func(ret, params, vararg)
}
fn opaque(&mut self, name: &str) -> u32 {
self.sink().opaque(name)
}
fn named_ref(&mut self, name: &str) -> u32 {
self.sink().named_ref(name)
}
fn anon(&mut self) -> u32 {
self.sink().anon()
}
fn fill_struct(
&mut self,
id: u32,
is_union: bool,
members: &[ffi::MemberInfo],
size: u64,
has_size: u32,
) {
self.sink()
.fill_struct(id, is_union, members, size, has_size);
}
fn fill_enum(
&mut self,
id: u32,
underlying: u32,
consts: &[ffi::EnumConstInfo],
size: u64,
has_size: u32,
) {
self.sink()
.fill_enum(id, underlying, consts, size, has_size);
}
fn fill_typedef(&mut self, id: u32, underlying: u32) {
self.sink().fill_typedef(id, underlying);
}
}
#[cxx::bridge(namespace = "idakit_cxx")]
mod ffi {
struct MemberInfo<'a> {
name: &'a str,
bit_offset: u64,
ty: u32,
bitfield_width: u32,
}
struct EnumConstInfo<'a> {
name: &'a str,
value: u64,
}
struct FrameVar {
name: String,
offset: i64,
size: u64,
flags: u32,
ty: u32,
}
struct FrameWalk {
size: u64,
vars: Vec<FrameVar>,
}
extern "Rust" {
type TypeWalkVisitor;
fn scalar(
self: &mut TypeWalkVisitor,
kind: u32,
bytes: u32,
is_signed: u32,
size: u64,
has_size: u32,
) -> u32;
fn ptr(self: &mut TypeWalkVisitor, target: u32, size: u64, has_size: u32) -> u32;
fn array(
self: &mut TypeWalkVisitor,
elem: u32,
nelems: u64,
size: u64,
has_size: u32,
) -> u32;
fn func(self: &mut TypeWalkVisitor, ret: u32, params: &[u32], vararg: u32) -> u32;
fn opaque(self: &mut TypeWalkVisitor, name: &str) -> u32;
fn named_ref(self: &mut TypeWalkVisitor, name: &str) -> u32;
fn anon(self: &mut TypeWalkVisitor) -> u32;
fn fill_struct(
self: &mut TypeWalkVisitor,
id: u32,
is_union: bool,
members: &[MemberInfo],
size: u64,
has_size: u32,
);
fn fill_enum(
self: &mut TypeWalkVisitor,
id: u32,
underlying: u32,
consts: &[EnumConstInfo],
size: u64,
has_size: u32,
);
fn fill_typedef(self: &mut TypeWalkVisitor, id: u32, underlying: u32);
}
unsafe extern "C++" {
include!("typewalk_cxx.h");
fn type_walk_visit_named(name: &str, visitor: &mut TypeWalkVisitor) -> Result<u32>;
fn type_walk_visit_ordinal(ordinal: u32, visitor: &mut TypeWalkVisitor) -> Result<u32>;
fn func_type_walk_visit(ea: u64, visitor: &mut TypeWalkVisitor) -> Result<u32>;
fn frame_type_walk_visit(ea: u64, visitor: &mut TypeWalkVisitor) -> Result<FrameWalk>;
}
}
pub use ffi::{EnumConstInfo, FrameVar, FrameWalk, MemberInfo};
pub fn walk_type_named(name: &str, sink: &mut dyn TypeWalkSink) -> Option<u32> {
ffi::type_walk_visit_named(name, &mut TypeWalkVisitor::new(sink)).ok()
}
pub fn walk_type_ordinal(ordinal: u32, sink: &mut dyn TypeWalkSink) -> Option<u32> {
ffi::type_walk_visit_ordinal(ordinal, &mut TypeWalkVisitor::new(sink)).ok()
}
pub fn walk_func_type(ea: u64, sink: &mut dyn TypeWalkSink) -> Option<u32> {
ffi::func_type_walk_visit(ea, &mut TypeWalkVisitor::new(sink)).ok()
}
pub fn walk_frame_type(ea: u64, sink: &mut dyn TypeWalkSink) -> Option<FrameWalk> {
ffi::frame_type_walk_visit(ea, &mut TypeWalkVisitor::new(sink)).ok()
}
#[must_use]
pub unsafe fn type_walk_visitor(sink: *mut dyn TypeWalkSink) -> TypeWalkVisitor {
TypeWalkVisitor {
sink: NonNull::new(sink).expect("sink pointer must be non-null"),
}
}