1#![allow(clippy::needless_lifetimes)]
76
77use std::marker::PhantomData;
78use std::sync::{Mutex, MutexGuard, OnceLock};
79
80pub mod bookmarks;
81pub mod decompiler;
82pub mod func;
83pub mod idb;
84pub mod insn;
85pub mod license;
86pub mod meta;
87pub mod name;
88pub mod plugin;
89pub mod processor;
90pub mod segment;
91pub mod strings;
92pub mod typeinf;
93pub mod xref;
94
95pub use idalib_sys as ffi;
96
97pub use ffi::IDAError;
98pub use idb::IDB;
99#[cfg(not(feature = "plugin"))]
100pub use idb::IDBOpenOptions;
101pub use license::{LicenseId, is_valid_license, license_id};
102#[cfg(feature = "plugin")]
103pub use plugin::{IDAPlugin, PluginFlags};
104
105#[cfg(feature = "plugin")]
106pub use idalib_macros::plugin;
107
108pub type Address = u64;
109pub struct AddressFlags<'a> {
110 flags: ffi::bytes::flags64_t,
111 _marker: PhantomData<&'a IDB>,
112}
113
114impl<'a> AddressFlags<'a> {
115 pub(crate) fn new(flags: ffi::bytes::flags64_t) -> Self {
116 Self {
117 flags,
118 _marker: PhantomData,
119 }
120 }
121
122 pub fn is_code(&self) -> bool {
123 unsafe { ffi::bytes::is_code(self.flags) }
124 }
125
126 pub fn is_data(&self) -> bool {
127 unsafe { ffi::bytes::is_data(self.flags) }
128 }
129
130 pub fn is_byte(&self) -> bool {
131 unsafe { ffi::bytes::is_byte(self.flags) }
132 }
133
134 pub fn is_word(&self) -> bool {
135 unsafe { ffi::bytes::is_word(self.flags) }
136 }
137
138 pub fn is_dword(&self) -> bool {
139 unsafe { ffi::bytes::is_dword(self.flags) }
140 }
141
142 pub fn is_qword(&self) -> bool {
143 unsafe { ffi::bytes::is_qword(self.flags) }
144 }
145
146 pub fn is_oword(&self) -> bool {
147 unsafe { ffi::bytes::is_oword(self.flags) }
148 }
149
150 pub fn is_float(&self) -> bool {
151 unsafe { ffi::bytes::is_float(self.flags) }
152 }
153
154 pub fn is_double(&self) -> bool {
155 unsafe { ffi::bytes::is_double(self.flags) }
156 }
157
158 pub fn is_strlit(&self) -> bool {
159 unsafe { ffi::bytes::is_strlit(self.flags) }
160 }
161
162 pub fn is_off(&self, n: usize) -> bool {
163 unsafe { ffi::bytes::is_off(self.flags, (n as i32).into()) }
164 }
165}
166
167pub struct IDA;
168
169impl IDA {
170 pub fn new(_: &IDB) -> Self {
171 Self
174 }
175
176 pub fn msg(&self, message: impl AsRef<str>) -> Result<(), IDAError> {
177 unsafe { ffi::ida::msg(message) }
178 }
179}
180
181#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
182pub struct IDAVersion {
183 major: i32,
184 minor: i32,
185 build: i32,
186}
187
188impl IDAVersion {
189 pub fn major(&self) -> i32 {
190 self.major
191 }
192
193 pub fn minor(&self) -> i32 {
194 self.minor
195 }
196
197 pub fn build(&self) -> i32 {
198 self.build
199 }
200}
201
202static INIT: OnceLock<Mutex<()>> = OnceLock::new();
203
204#[cfg(not(any(target_os = "windows", feature = "plugin")))]
205unsafe extern "C" {
206 static mut batch: std::ffi::c_char;
207}
208
209pub(crate) type IDARuntimeHandle = MutexGuard<'static, ()>;
210
211#[cfg(not(feature = "plugin"))]
212pub fn force_batch_mode() {
213 #[cfg(not(target_os = "windows"))]
214 unsafe {
215 batch = 1;
216 }
217}
218
219#[cfg(feature = "plugin")]
220pub fn init_library() -> &'static Mutex<()> {
221 INIT.get_or_init(|| Mutex::new(()))
222}
223
224#[cfg(not(feature = "plugin"))]
225pub fn init_library() -> &'static Mutex<()> {
226 INIT.get_or_init(|| {
227 force_batch_mode();
228 ffi::ida::init_library().expect("IDA initialised successfully");
229 Mutex::new(())
230 })
231}
232
233pub(crate) fn prepare_library() -> IDARuntimeHandle {
234 let mutex = init_library();
235 mutex.lock().unwrap()
236}
237
238#[cfg(not(feature = "plugin"))]
239pub fn enable_console_messages(enabled: bool) {
240 init_library();
241 ffi::ida::enable_console_messages(enabled);
242}
243
244pub fn version() -> Result<IDAVersion, IDAError> {
245 ffi::ida::library_version().map(|(major, minor, build)| IDAVersion {
246 major,
247 minor,
248 build,
249 })
250}