#![doc(
html_logo_url = "https://raw.githubusercontent.com/Xevion/idakit/master/assets/idakit-logo.png",
html_favicon_url = "https://raw.githubusercontent.com/Xevion/idakit/master/assets/idakit-favicon.png"
)]
#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
use std::cell::Cell;
use std::marker::PhantomData;
pub use idakit_sys as sys;
#[macro_use]
mod macros;
pub mod decompiler;
pub mod error;
pub mod function;
pub mod instruction;
pub mod kernel;
pub mod netnode;
pub mod types;
#[doc(hidden)]
pub mod corpus;
#[doc(hidden)]
pub mod doctest;
mod address;
mod arena;
mod bitness;
mod bytes;
mod claim;
mod data;
mod export;
mod ffi;
mod flowchart;
mod import;
mod location;
mod meta;
mod name;
mod raw;
mod search;
mod segment;
mod stack;
mod strings;
mod xref;
#[doc(inline)]
pub use crate::decompiler::ctree::Ctree;
#[doc(inline)]
pub use crate::function::Function;
#[doc(inline)]
pub use crate::kernel::Ida;
#[doc(inline)]
pub use crate::types::Type;
pub use crate::address::Address;
pub use crate::arena::{Arena, Idx};
pub use crate::bitness::Bitness;
pub use crate::export::{Export, Exports};
pub use crate::flowchart::{BasicBlock, BasicBlockId, BasicBlockKind, ExternalExit, FlowChart};
pub use crate::import::{Import, Imports};
pub use crate::location::{Location, LocationMut};
pub use crate::meta::DatabaseInfo;
pub use crate::name::{Name, NameFlags, Names};
pub use crate::netnode::{
Altvals, HashEntries, Netnode, NetnodeBytes, NetnodeBytesError, NetnodeMut, Netnodes, NodeId,
Persist, Supvals, Tag, TaggedNetnode, TaggedNetnodeMut,
};
pub use crate::search::{Matches, Pattern};
pub use crate::segment::{
Segment, SegmentAlignment, SegmentClass, SegmentCombination, SegmentFlags, SegmentType,
Segments,
};
pub use crate::stack::{StackFrame, StackSlot, StackSlotKind};
pub use crate::strings::{StringLiteral, Strings};
pub use crate::xref::{CodeXref, DataXref, Xref, XrefKind, XrefOrigin, Xrefs};
pub mod prelude {
pub use crate::Database;
pub use crate::address::Address;
pub use crate::bitness::Bitness;
pub use crate::decompiler::ctree::{AssignmentOp, BinaryOp, Ctree, UnaryOp};
pub use crate::decompiler::{CtreeCounts, DecompiledFunction};
pub use crate::error::{CallError, Error, InitError, KernelErrno, PatternRejection, Result};
pub use crate::export::{Export, Exports};
pub use crate::flowchart::{BasicBlock, BasicBlockId, BasicBlockKind, ExternalExit, FlowChart};
pub use crate::function::{
CallingConvention, Function, FunctionChunk, FunctionChunks, FunctionEdit, FunctionName,
FunctionSnapshot, Functions,
};
pub use crate::import::{Import, Imports};
pub use crate::instruction::{
Access, DecodeError, Flow, FpControl, Instruction, Instructions, InstructionsIn, Isa,
Masking, Memory, Operand, OperandDataType, OperandKind, Register, RegisterClass, RoundMode,
};
pub use crate::kernel::{Ida, IdaConfig, IdaConfigBuilder};
pub use crate::location::{Location, LocationMut};
pub use crate::meta::DatabaseInfo;
pub use crate::name::{Name, NameFlags, Names};
pub use crate::netnode::{
Altvals, HashEntries, Netnode, NetnodeBytes, NetnodeBytesError, NetnodeMut, Netnodes,
NodeId, Persist, Supvals, Tag, TaggedNetnode, TaggedNetnodeMut,
};
pub use crate::search::{Matches, Pattern};
pub use crate::segment::{
Segment, SegmentAlignment, SegmentClass, SegmentCombination, SegmentFlags, SegmentType,
Segments,
};
pub use crate::stack::{StackFrame, StackSlot, StackSlotKind};
pub use crate::strings::{StringLiteral, Strings};
pub use crate::types::diff::{
AggregateKind, CanonicalMember, CanonicalOptions, CanonicalType, CatalogDiff, Change,
ChangeKind, RecordKind, TypeCatalog, TypeDiff, TypeIdentity, TypeKey, canonicalize,
};
pub use crate::types::expr;
pub use crate::types::{
ConstantEdit, EnumMember, MemberEdit, MemberRef, NamedType, NamedTypes, Type, TypeEdit,
TypeEditCode, TypeExpr, TypeId, TypeInfo, TypeMember, TypeShape, TypeTable, TypeValue,
TypeWriteError, TypesMut,
};
pub use crate::xref::{CodeXref, DataXref, Xref, XrefKind, XrefOrigin, Xrefs};
}
use crate::error::{Error, Result};
use crate::kernel::KernelClaim;
pub struct Database {
hexrays_ready: Cell<bool>,
_claim: Option<KernelClaim>,
_not_sync: PhantomData<*const ()>,
}
unsafe impl Send for Database {}
#[cfg(test)]
const _: () = {
const fn assert_send<T: Send>() {}
assert_send::<Database>();
};
impl std::fmt::Debug for Database {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Database").finish_non_exhaustive()
}
}
#[bon::bon]
impl Database {
#[builder(builder_type(doc {
/// Builder for [`Database::open`]. Set `run_auto`, then finish with `.call()`.
}))]
#[doc(alias("open_database"))]
pub fn open(
&mut self,
#[builder(start_fn)] path: impl AsRef<str>,
#[builder(default)] run_auto: bool,
) -> Result<()> {
let path = path.as_ref();
let rc = ffi::with_cstr(path, "path", |p| self.open_database(p, run_auto))?;
if rc == sys::EXIT_TRAPPED {
return Err(self.kernel_exit_error());
}
if rc != 0 {
let (errno, reason) = self.last_reason();
return Err(Error::Open {
path: path.to_owned(),
errno,
reason: reason.unwrap_or_else(|| format!("open failed (status {rc})")),
});
}
if run_auto && self.auto_wait() == sys::EXIT_TRAPPED {
return Err(self.kernel_exit_error());
}
Ok(())
}
}
impl Database {
pub(crate) fn new() -> Self {
Self {
hexrays_ready: Cell::new(false),
_claim: None,
_not_sync: PhantomData,
}
}
pub(crate) fn owned(claim: KernelClaim) -> Self {
Self {
hexrays_ready: Cell::new(false),
_claim: Some(claim),
_not_sync: PhantomData,
}
}
#[doc(alias("close_database"))]
pub fn close(&mut self, save: bool) {
self.close_database(save);
}
pub fn with_open<T>(
&mut self,
path: impl AsRef<str>,
f: impl FnOnce(&mut Self) -> Result<T>,
) -> Result<T> {
self.open(path).call()?;
let closer = CloseOnDrop { db: self };
f(&mut *closer.db)
}
pub fn accept_eula(&self) -> bool {
self.reg_accept_eula()
}
pub(crate) fn kernel_exit_error(&self) -> Error {
let captured = self.last_output();
let trimmed = captured.trim();
Error::KernelExit {
code: self.last_exit_code(),
diagnostic: (!trimmed.is_empty()).then(|| trimmed.to_owned()),
}
}
}
struct CloseOnDrop<'db> {
db: &'db mut Database,
}
impl Drop for CloseOnDrop<'_> {
fn drop(&mut self) {
self.db.close(false);
}
}