binaryninja/
type_library.rs

1use binaryninjacore_sys::*;
2use std::fmt::{Debug, Formatter};
3
4use crate::rc::{Guard, RefCountable};
5use crate::{
6    architecture::CoreArchitecture,
7    metadata::Metadata,
8    platform::Platform,
9    rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref},
10    string::{BnString, IntoCStr},
11    types::{QualifiedName, QualifiedNameAndType, Type},
12};
13use std::path::Path;
14use std::ptr::NonNull;
15
16#[repr(transparent)]
17pub struct TypeLibrary {
18    handle: NonNull<BNTypeLibrary>,
19}
20
21impl TypeLibrary {
22    pub(crate) unsafe fn from_raw(handle: NonNull<BNTypeLibrary>) -> Self {
23        Self { handle }
24    }
25
26    pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNTypeLibrary>) -> Ref<Self> {
27        Ref::new(Self { handle })
28    }
29
30    #[allow(clippy::mut_from_ref)]
31    pub(crate) unsafe fn as_raw(&self) -> &mut BNTypeLibrary {
32        &mut *self.handle.as_ptr()
33    }
34
35    pub fn new_duplicated(&self) -> Ref<Self> {
36        unsafe { Self::ref_from_raw(NonNull::new(BNDuplicateTypeLibrary(self.as_raw())).unwrap()) }
37    }
38
39    /// Creates an empty type library object with a random GUID and the provided name.
40    pub fn new(arch: CoreArchitecture, name: &str) -> Ref<TypeLibrary> {
41        let name = name.to_cstr();
42        let new_lib = unsafe { BNNewTypeLibrary(arch.handle, name.as_ptr()) };
43        unsafe { TypeLibrary::ref_from_raw(NonNull::new(new_lib).unwrap()) }
44    }
45
46    pub fn all(arch: CoreArchitecture) -> Array<TypeLibrary> {
47        let mut count = 0;
48        let result = unsafe { BNGetArchitectureTypeLibraries(arch.handle, &mut count) };
49        assert!(!result.is_null());
50        unsafe { Array::new(result, count, ()) }
51    }
52
53    /// Decompresses a type library file to a file on disk.
54    pub fn decompress_to_file(path: &Path, output_path: &Path) -> bool {
55        let path = path.to_cstr();
56        let output = output_path.to_cstr();
57        unsafe { BNTypeLibraryDecompressToFile(path.as_ptr(), output.as_ptr()) }
58    }
59
60    /// Loads a finalized type library instance from file
61    pub fn load_from_file(path: &Path) -> Option<Ref<TypeLibrary>> {
62        let path = path.to_cstr();
63        let handle = unsafe { BNLoadTypeLibraryFromFile(path.as_ptr()) };
64        NonNull::new(handle).map(|h| unsafe { TypeLibrary::ref_from_raw(h) })
65    }
66
67    /// Saves a finalized type library instance to file
68    pub fn write_to_file(&self, path: &Path) -> bool {
69        let path = path.to_cstr();
70        unsafe { BNWriteTypeLibraryToFile(self.as_raw(), path.as_ptr()) }
71    }
72
73    /// Looks up the first type library found with a matching name. Keep in mind that names are not
74    /// necessarily unique.
75    ///
76    /// NOTE: If the type library architecture's associated platform has not been initialized, this will
77    /// return `None`. To make sure that the platform has been initialized, one should instead get the type
78    /// libraries through [`Platform::get_type_libraries_by_name`].
79    pub fn from_name(arch: CoreArchitecture, name: &str) -> Option<Ref<TypeLibrary>> {
80        let name = name.to_cstr();
81        let handle = unsafe { BNLookupTypeLibraryByName(arch.handle, name.as_ptr()) };
82        NonNull::new(handle).map(|h| unsafe { TypeLibrary::ref_from_raw(h) })
83    }
84
85    /// Attempts to grab a type library associated with the provided Architecture and GUID pair.
86    ///
87    /// NOTE: If the associated platform for the architecture has not been initialized,  
88    /// this will return `None`. Avoid calling this outside of a view context.
89    pub fn from_guid(arch: CoreArchitecture, guid: &str) -> Option<Ref<TypeLibrary>> {
90        let guid = guid.to_cstr();
91        let handle = unsafe { BNLookupTypeLibraryByGuid(arch.handle, guid.as_ptr()) };
92        NonNull::new(handle).map(|h| unsafe { TypeLibrary::ref_from_raw(h) })
93    }
94
95    /// The Architecture this type library is associated with
96    pub fn arch(&self) -> CoreArchitecture {
97        let arch = unsafe { BNGetTypeLibraryArchitecture(self.as_raw()) };
98        assert!(!arch.is_null());
99        unsafe { CoreArchitecture::from_raw(arch) }
100    }
101
102    /// The primary name associated with this type library
103    pub fn name(&self) -> String {
104        let result = unsafe { BNGetTypeLibraryName(self.as_raw()) };
105        assert!(!result.is_null());
106        unsafe { BnString::into_string(result) }
107    }
108
109    /// Sets the name of a type library instance that has not been finalized
110    pub fn set_name(&self, value: &str) {
111        let value = value.to_cstr();
112        unsafe { BNSetTypeLibraryName(self.as_raw(), value.as_ptr()) }
113    }
114
115    /// The `dependency_name` of a library is the name used to record dependencies across
116    /// type libraries. This allows, for example, a library with the name "musl_libc" to have
117    /// dependencies on it recorded as "libc_generic", allowing a type library to be used across
118    /// multiple platforms where each has a specific libc that also provides the name "libc_generic"
119    /// as an `alternate_name`.
120    pub fn dependency_name(&self) -> String {
121        let result = unsafe { BNGetTypeLibraryDependencyName(self.as_raw()) };
122        assert!(!result.is_null());
123        unsafe { BnString::into_string(result) }
124    }
125
126    /// Sets the dependency name of a type library instance that has not been finalized
127    pub fn set_dependency_name(&self, value: &str) {
128        let value = value.to_cstr();
129        unsafe { BNSetTypeLibraryDependencyName(self.as_raw(), value.as_ptr()) }
130    }
131
132    /// Returns the GUID associated with the type library
133    pub fn guid(&self) -> String {
134        let result = unsafe { BNGetTypeLibraryGuid(self.as_raw()) };
135        assert!(!result.is_null());
136        unsafe { BnString::into_string(result) }
137    }
138
139    /// Sets the GUID of a type library instance that has not been finalized
140    pub fn set_guid(&self, value: &str) {
141        let value = value.to_cstr();
142        unsafe { BNSetTypeLibraryGuid(self.as_raw(), value.as_ptr()) }
143    }
144
145    /// A list of extra names that will be considered a match by [Platform::get_type_libraries_by_name]
146    pub fn alternate_names(&self) -> Array<BnString> {
147        let mut count = 0;
148        let result = unsafe { BNGetTypeLibraryAlternateNames(self.as_raw(), &mut count) };
149        assert!(!result.is_null());
150        unsafe { Array::new(result, count, ()) }
151    }
152
153    /// Adds an extra name to this type library used during library lookups and dependency resolution
154    pub fn add_alternate_name(&self, value: &str) {
155        let value = value.to_cstr();
156        unsafe { BNAddTypeLibraryAlternateName(self.as_raw(), value.as_ptr()) }
157    }
158
159    /// Returns a list of all platform names that this type library will register with during platform
160    /// type registration.
161    ///
162    /// This returns strings, not Platform objects, as type libraries can be distributed with support for
163    /// Platforms that may not be present.
164    pub fn platform_names(&self) -> Array<BnString> {
165        let mut count = 0;
166        let result = unsafe { BNGetTypeLibraryPlatforms(self.as_raw(), &mut count) };
167        assert!(!result.is_null());
168        unsafe { Array::new(result, count, ()) }
169    }
170
171    /// Associate a platform with a type library instance that has not been finalized.
172    ///
173    /// This will cause the library to be searchable by [Platform::get_type_libraries_by_name]
174    /// when loaded.
175    ///
176    /// This does not have side affects until finalization of the type library.
177    pub fn add_platform(&self, plat: &Platform) {
178        unsafe { BNAddTypeLibraryPlatform(self.as_raw(), plat.handle) }
179    }
180
181    /// Clears the list of platforms associated with a type library instance that has not been finalized
182    pub fn clear_platforms(&self) {
183        unsafe { BNClearTypeLibraryPlatforms(self.as_raw()) }
184    }
185
186    /// Flags a newly created type library instance as finalized and makes it available for Platform and Architecture
187    /// type library searches
188    pub fn finalize(&self) -> bool {
189        unsafe { BNFinalizeTypeLibrary(self.as_raw()) }
190    }
191
192    /// Retrieves a metadata associated with the given key stored in the type library
193    pub fn query_metadata(&self, key: &str) -> Option<Ref<Metadata>> {
194        let key = key.to_cstr();
195        let result = unsafe { BNTypeLibraryQueryMetadata(self.as_raw(), key.as_ptr()) };
196        (!result.is_null()).then(|| unsafe { Metadata::ref_from_raw(result) })
197    }
198
199    /// Stores an object for the given key in the current type library. Objects stored using
200    /// `store_metadata` can be retrieved from any reference to the library. Objects stored are not arbitrary python
201    /// objects! The values stored must be able to be held in a Metadata object. See [Metadata]
202    /// for more information. Python objects could obviously be serialized using pickle but this intentionally
203    /// a task left to the user since there is the potential security issues.
204    ///
205    /// This is primarily intended as a way to store Platform specific information relevant to BinaryView implementations;
206    /// for example the PE BinaryViewType uses type library metadata to retrieve ordinal information, when available.
207    ///
208    /// * `key` - key value to associate the Metadata object with
209    /// * `md` - object to store.
210    pub fn store_metadata(&self, key: &str, md: &Metadata) {
211        let key = key.to_cstr();
212        unsafe { BNTypeLibraryStoreMetadata(self.as_raw(), key.as_ptr(), md.handle) }
213    }
214
215    /// Removes the metadata associated with key from the current type library.
216    pub fn remove_metadata(&self, key: &str) {
217        let key = key.to_cstr();
218        unsafe { BNTypeLibraryRemoveMetadata(self.as_raw(), key.as_ptr()) }
219    }
220
221    /// Retrieves the metadata associated with the current type library.
222    pub fn metadata(&self) -> Ref<Metadata> {
223        let md_handle = unsafe { BNTypeLibraryGetMetadata(self.as_raw()) };
224        assert!(!md_handle.is_null());
225        unsafe { Metadata::ref_from_raw(md_handle) }
226    }
227
228    // TODO: implement TypeContainer
229    // /// Type Container for all TYPES within the Type Library. Objects are not included.
230    // /// The Type Container's Platform will be the first platform associated with the Type Library.
231    // pub fn type_container(&self) -> TypeContainer {
232    //     let result = unsafe{ BNGetTypeLibraryTypeContainer(self.as_raw())};
233    //     unsafe{TypeContainer::from_raw(NonNull::new(result).unwrap())}
234    // }
235
236    /// Directly inserts a named object into the type library's object store.
237    /// This is not done recursively, so care should be taken that types referring to other types
238    /// through NamedTypeReferences are already appropriately prepared.
239    ///
240    /// To add types and objects from an existing BinaryView, it is recommended to use
241    /// `export_object_to_library <binaryview.BinaryView.export_object_to_library>`, which will automatically pull in
242    /// all referenced types and record additional dependencies as needed.
243    pub fn add_named_object(&self, name: QualifiedName, type_: &Type) {
244        let mut raw_name = QualifiedName::into_raw(name);
245        unsafe { BNAddTypeLibraryNamedObject(self.as_raw(), &mut raw_name, type_.handle) }
246        QualifiedName::free_raw(raw_name);
247    }
248
249    /// Directly inserts a named object into the type library's object store.
250    /// This is not done recursively, so care should be taken that types referring to other types
251    /// through NamedTypeReferences are already appropriately prepared.
252    ///
253    /// To add types and objects from an existing BinaryView, it is recommended to use
254    /// `export_type_to_library <binaryview.BinaryView.export_type_to_library>`, which will automatically pull in
255    /// all referenced types and record additional dependencies as needed.
256    pub fn add_named_type(&self, name: QualifiedName, type_: &Type) {
257        let mut raw_name = QualifiedName::into_raw(name);
258        unsafe { BNAddTypeLibraryNamedType(self.as_raw(), &mut raw_name, type_.handle) }
259        QualifiedName::free_raw(raw_name);
260    }
261
262    /// Manually flag NamedTypeReferences to the given QualifiedName as originating from another source
263    /// TypeLibrary with the given dependency name.
264    ///
265    /// <div class="warning">
266    ///
267    /// Use this api with extreme caution.
268    ///
269    /// </div>
270    pub fn add_type_source(&self, name: QualifiedName, source: &str) {
271        let source = source.to_cstr();
272        let mut raw_name = QualifiedName::into_raw(name);
273        unsafe { BNAddTypeLibraryNamedTypeSource(self.as_raw(), &mut raw_name, source.as_ptr()) }
274        QualifiedName::free_raw(raw_name);
275    }
276
277    /// Direct extracts a reference to a contained object -- when
278    /// attempting to extract types from a library into a BinaryView, consider using
279    /// `import_library_object <binaryview.BinaryView.import_library_object>` instead.
280    pub fn get_named_object(&self, name: QualifiedName) -> Option<Ref<Type>> {
281        let mut raw_name = QualifiedName::into_raw(name);
282        let t = unsafe { BNGetTypeLibraryNamedObject(self.as_raw(), &mut raw_name) };
283        QualifiedName::free_raw(raw_name);
284        (!t.is_null()).then(|| unsafe { Type::ref_from_raw(t) })
285    }
286
287    /// Direct extracts a reference to a contained type -- when
288    /// attempting to extract types from a library into a BinaryView, consider using
289    /// `import_library_type <binaryview.BinaryView.import_library_type>` instead.
290    pub fn get_named_type(&self, name: QualifiedName) -> Option<Ref<Type>> {
291        let mut raw_name = QualifiedName::into_raw(name);
292        let t = unsafe { BNGetTypeLibraryNamedType(self.as_raw(), &mut raw_name) };
293        QualifiedName::free_raw(raw_name);
294        (!t.is_null()).then(|| unsafe { Type::ref_from_raw(t) })
295    }
296
297    /// A dict containing all named objects (functions, exported variables) provided by a type library
298    pub fn named_objects(&self) -> Array<QualifiedNameAndType> {
299        let mut count = 0;
300        let result = unsafe { BNGetTypeLibraryNamedObjects(self.as_raw(), &mut count) };
301        assert!(!result.is_null());
302        unsafe { Array::new(result, count, ()) }
303    }
304
305    /// A dict containing all named types provided by a type library
306    pub fn named_types(&self) -> Array<QualifiedNameAndType> {
307        let mut count = 0;
308        let result = unsafe { BNGetTypeLibraryNamedTypes(self.as_raw(), &mut count) };
309        assert!(!result.is_null());
310        unsafe { Array::new(result, count, ()) }
311    }
312}
313
314impl Debug for TypeLibrary {
315    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
316        f.debug_struct("TypeLibrary")
317            .field("name", &self.name())
318            .field("dependency_name", &self.dependency_name())
319            .field("arch", &self.arch())
320            .field("guid", &self.guid())
321            .field("alternate_names", &self.alternate_names().to_vec())
322            .field("platform_names", &self.platform_names().to_vec())
323            .field("metadata", &self.metadata())
324            // These two are too verbose.
325            // .field("named_objects", &self.named_objects().to_vec())
326            // .field("named_types", &self.named_types().to_vec())
327            .finish()
328    }
329}
330
331unsafe impl RefCountable for TypeLibrary {
332    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
333        Ref::new(Self {
334            handle: NonNull::new(BNNewTypeLibraryReference(handle.handle.as_ptr())).unwrap(),
335        })
336    }
337
338    unsafe fn dec_ref(handle: &Self) {
339        BNFreeTypeLibrary(handle.handle.as_ptr());
340    }
341}
342
343impl ToOwned for TypeLibrary {
344    type Owned = Ref<Self>;
345
346    fn to_owned(&self) -> Self::Owned {
347        unsafe { RefCountable::inc_ref(self) }
348    }
349}
350
351impl CoreArrayProvider for TypeLibrary {
352    type Raw = *mut BNTypeLibrary;
353    type Context = ();
354    type Wrapped<'a> = Guard<'a, Self>;
355}
356
357unsafe impl CoreArrayProviderInner for TypeLibrary {
358    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
359        BNFreeTypeLibraryList(raw, count)
360    }
361
362    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
363        Guard::new(Self::from_raw(NonNull::new(*raw).unwrap()), context)
364    }
365}