pub mod ctree;
use std::ffi::c_void;
use std::marker::PhantomData;
use idakit_sys as sys;
use crate::Database;
use crate::address::Address;
use crate::decompiler::ctree::{Ctree, ExtractError, walk};
use crate::error::{Error, Result};
impl Database {
pub fn ctree(&self, address: Address) -> Result<Ctree> {
self.function(address).ctree()
}
#[doc(alias("decompile_func"))]
pub fn decompile(&self, address: Address) -> Result<DecompiledFunction<'_>> {
if !self.hexrays_ready.get() {
let rc = self.hexrays_init();
if rc != 1 {
return Err(Error::HexRaysInit { code: rc });
}
self.hexrays_ready.set(true);
}
match sys::decompile(address.get()) {
Ok(handle) => Ok(DecompiledFunction::from_handle(handle, self)),
Err(e) => {
if self.was_trapped() {
return Err(self.kernel_exit_error());
}
Err(Error::Decompile {
address: address.get(),
reason: e.what().to_owned(),
})
}
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[doc(alias("ctree_visitor_t"))]
pub struct CtreeCounts {
pub insns: i32,
pub expressions: i32,
pub calls: i32,
}
#[doc(alias("cfuncptr_t", "cfunc_t"))]
pub struct DecompiledFunction<'db> {
handle: cxx::UniquePtr<sys::CFunc>,
_db: PhantomData<&'db Database>,
_not_send: PhantomData<*const ()>,
}
impl<'db> DecompiledFunction<'db> {
#[inline]
pub(crate) fn from_handle(handle: cxx::UniquePtr<sys::CFunc>, _db: &'db Database) -> Self {
debug_assert!(!handle.is_null());
Self {
handle,
_db: PhantomData,
_not_send: PhantomData,
}
}
#[inline]
fn cfunc(&self) -> &sys::CFunc {
self.handle.as_ref().expect("live handle")
}
#[must_use]
#[doc(alias("get_pseudocode"))]
pub fn pseudocode(&self) -> Option<String> {
sys::cfunc_pseudocode(self.cfunc()).ok()
}
#[must_use]
pub fn counts(&self) -> CtreeCounts {
let c = sys::cfunc_counts(self.cfunc());
CtreeCounts {
insns: c.insns,
expressions: c.expressions,
calls: c.calls,
}
}
#[must_use]
pub fn expr_extraction_expectation(&self) -> (i32, i32) {
let g = sys::cfunc_expr_gap(self.cfunc());
(g.visitor_total, g.expected)
}
pub fn ctree(&self) -> Result<Ctree, ExtractError> {
let cfunc = self.cfunc() as *const sys::CFunc as *mut c_void;
walk(cfunc)
}
}
impl std::fmt::Debug for DecompiledFunction<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DecompiledFunction")
.field("counts", &self.counts())
.finish()
}
}