summaryrefslogtreecommitdiff
path: root/rust/src/types.rs
diff options
context:
space:
mode:
authorMason Reed <mason@vector35.com>2024-12-22 01:21:02 -0500
committerMason Reed <mason@vector35.com>2025-01-25 00:52:29 -0500
commit6a63c17853009ce7a0071458e39c140a09440230 (patch)
treead59ab3b356b0a2c60423e55f62c996891788788 /rust/src/types.rs
parentbfa1d409b2d5e734804a5fdb4c68c90a93712f1f (diff)
Rust refactor
Moves a bunch of stuff out of src/types.rs that did not belong: - Confidence - Variable - Function specific stuff - Refactored InstructionInfo, see the msp430 and riscv examples. - Renamed Function::from_raw to Function::ref_from_raw and fixed places where the ref was incremented twice - Fixed FunctionRecognizer leaking functions (see above) - Fixed some apis incorrectly returning Result where Option is clearer - Started to move destructured types to the From trait for converting to an from ffi types, see Location for an example - Started to remove bad module level imports (importing std modules like mem all over the place) - Moved some wrapper handle types to named handle field (this improves readability), see CoreArchitecture for an example - Removed some unintuitive getters, this is bad practice for Rust code, just access the field directly, see DataVariable for an example - General code cleanup, purposely did not run rustfmt, that will be a single seperate commit More rust cleanup - Fixed invalid views being able to invoke UB when dealing with databases - Cleaned up some helper code in dwarf_import - Fixed inverted is_null checks causing crashes! Oops! More rust cleanup Still a WIP, I think branch info is still invalid, need to figure out the issue there. - Fixed some invalid Ref lifetimes when constructing indirectly, see Array<DataVariable> for example - Added some more comments - Removed some "magic" functions like MLIL Function::ssa_variables There are still a bunch of invalid lifetimes that aren't crashing us due to the usage of those API's not living long enough. But they ARE an issue. More rust cleanup Trying to comment more TODO's as I go along. - Renamed llil::Function to llil::LowLevelILFunction for clarity and consistency - Take base structures by ref in StructureBuilder::set_base_structures to prevent premature drops - Added more raw to wrapper conversions - Removed UB prone apis - Getting rid of more core module references, use std! - Removed improper Guard usage in array impls for wrapper types with no context - Untangling the UB of the Label api, still only half done :/ More rust cleanup - Misc formatting - Made Logger ref counted - Fixed leaking name of logger every time something was logged - Fixed the last (hopefully) of the unresolved labels - Simplified some code Fix leak in DebugInfo::AddType componentArray was never freed Add more HLIL related functions to rust More rust cleanup improve the CustomBinaryView init process Canonicalize path in `create_delete_empty` test Link core in rust When linking you must depend on the -sys crate. This is because linker arguments (what says where to find binaryninjacore) are NOT transitive. The top level application crate MUST provide it. For more information see: - https://github.com/rust-lang/cargo/issues/9554#issuecomment-857882964 - https://github.com/oxidecomputer/omicron/pull/225 Remove vendored pdb crate Use cargo to manage the git repo ref instead Fix misc rustdoc warnings Move actual plugins out of `rust/examples` and into `plugins` This is where all shipped public plugins that are not arch/view/platform/lang will be at from now on Originally they were in the rust workspace, meaning they all shared a Cargo.lock which is ill-advised. More rust cleanup - More clarification on plugin/executable requirements - Made examples actually rust examples - Add Display impl for InstructionTextToken - Renamed feature "noexports" to "no_exports" Move under_construction.png to assets directory This really did bother me Remove unneeded `extern crate bindgen` Replace nop'd log::info with println We don't register a compatible log sink so they will just get sent into the void Move inline tests into tests directory This is being done in the hopes of curbing the multi-thousand line files that will occur once we flesh out the tests Format rust code Update rust ci Still need to add support for running tests in ci More rust cleanup - Architecture id's are now typed accordingly - Fix some clippy lints - Make instruction index public in LLIL - Removed useless helper functions - LLIL expressions and instruction indexes are now typed accordingly Generate binaryninjacore-sys documentation This should show binaryninjacore-sys alongside binaryninja crate More rust cleanup - Remove lazy_static dependency - Remove hacky impl Debug for Type and just use the display impl - Add more debug impls - Reorder some top level namespace items - Add first type test Remove unneeded script helper in rust api More rust cleanup - Added main thread handler api - Register a headless main thread handler by default in initialization - Refactor QualifiedName to be properly owned - Loosened some type constraints on some apis involving QualifiedName - Fixed some apis that were crashing due to incorrect param types - Removed extern crate cruft for log crate - Simplified headless initialization using more wrapper apis - Fixed segments leaking because of no ref wrapper, see BinaryViewExt::segment_at - Added rstest to manage headless init in unit tests - Added some more unit tests - Refactored demangler api to be more ergonomic - Fixed minidump plugin not building More rust cleanup - Fixup usage of QualifiedName in plugins - Make QualifiedName more usable Implement rust TypeParser fix Platform TypeParser related functions separate User and System implementations of TypeParserResult Implement rust TypeContainer More rust cleanup - Hopefully fixed the rust.yml CI - Added TypePrinter API (this is still WIP and will crash) - Added TypeParser API - Added TypeContainer API - More work around QualifiedName apis Oh your suppose to do this Add workflow_dispatch trigger to rust.yml More rust fixes - Swapped some usage of raw 255 to MAX_CONFIDENCE, no one likes magic numbers - New InstructionTextToken API, complete with owned data, this still needs a lot of testing. - InstructionTextTokenKind describes a destructured InstructionTextToken, this should make token usage much clearer, some docs pending - Added some misc Default and Debug impls - Updated TypePrinter and architectures to use new InstructionTextToken API Misc formatting changes More rust cleanup - Fixed MANY memory leaks (most due to QualifiedName) - Made StructureBuilder more builder and less structure - Fixed CMakeLists.txt that were globbing entire api, resulting in 100 second slowdown on cmake generation - Added more Debug impl's - Added some more tests - Fixed TypeParserResult UB - Moved the From impls to blank impl for clarity, we have multiple different variants of core to rust for some structures, it should be explicit which one you are choosing. - PossibleValueSet should now be able to allocate so we can go from rust to core with those variants that require allocation - Misc doc code formatting Misc clippy lints and clippy CI Co-authored-by: Michael Krasnitski <michael.krasnitski@gmail.com> Fix typo in rust CI Misc rust formatting Fix misc typos and add typos to rust CI Add cargo workspace This will help tooling and external contributors get a map of the rust crates within binaryninja-api More rust cleanup - Format all rust plugins - Fix some tests that were out of date - Simplify WARP tests to only binaries, building object files from source is a pain - Link to core in all rust plugins - Fix some memory leaks - Update warp insta snapshots - Fix some misc clippy lints Run rust tests in CI This commit also coincides with the creation of the "testing" environment which exposes a BN_SERIAL secret for pulling a headless Binary Ninja Install missing wayland dependency in github CI Apparently its needed for linux file picker for the WARP integration Set the BINARYNINJADIR so rust can find binaryninjacore in CI The chances of this working are low Misc remove unused dependency Rust misc formatting fixes Improve initialization in rust headless scripts Provide sensible errors and validation to rust headless scripts, solves https://github.com/Vector35/binaryninja-api/issues/5796 Add BN_LICENSE environment variable to rust CI We pass the serial to download binary ninja, but we never provided the license for core initialization Fix typo More rust cleanup - Improved binary view initialization (see init_with_opts) - Allow floating license to free itself before initialization - Add initialization unit test - Add better Debug impls for some common types - Use Path api for opening binary views, this is not breaking as it uses the AsRef impl - Bump rayon dependency and constrain dependencies to x.x Update readme and include that directly in the rustdocs More rust documentation changes Add format comment to InitializationOptions::with_license Misc formatting and clippy lint allow More rust cleanup - Remove under_construction.png from the build.rs it has been removed - Use InstructionIndex in more places - Add missing PartialOrd and Ord impls for id types More rust cleanup - Make workflow cloning explicit - Add workflow tests - Add missing property string list getting for settings - Remove IntoActivityName (see https://github.com/Vector35/binaryninja-api/pull/6257) More rust cleanup This commit is half done Misc rust formatting More rust cleanup - Renamed common name conflictions (I will put my justification in the PR) - Fixed invalid instruction retrieval for LLIL - Added common aliases for llil function, instruction and expression types (see my comment in the PR) - Refactored the instruction retrieval for LLIL, MLIL and HLIL - Added instruction index types to MLIL and HLIL - Moved llil module to lowlevelil module (mlil and hlil will be moved as well) - Added preliminary LLIL unit testing Fix typos Misc clippy fixes More rust cleanup - Normalized modules - Split some code out into own files - Fixed some UB in type archive and projects - Improved API around type archives and projects substantially - Added ProgressExecutor abstraction for functions which have a progress callback - Improved background task documentation and added unit tests - Added worker thread api and unit tests - Moved some owned types to ref types, this is still not complete, but this is the path forward. - Add external location/library accessors to the binary view - Added some misc documentation - Replaced mod.rs with the module name source file Still need to normalize some paths and also update some documentation surrounding that change. Update some tests and examples Fix background task tests colliding We were creating multiple background tasks with the same progress text on multiple threads More rust cleanup - Fixed progress executor freeing itself after one iteration - Updated the last of the doc imports - Moved mainthread to main_thread - Made project creation and opening failable We could probably AsRef<ProgressExecutor> to get around the allocation and free inside the function bodies, not high priority as those functions are long running anyways. Move binary view initialization into function body for LLIL test Normalize test file names More rust cleanup - Updated README to clarify offline documentation - Refactored settings api - Added settings example to show dumping settings value and specific properties - Use the workspace to depend on binaryninja and binaryninjacore-sys - Remove binaryninjacore-sys as a workspace member (its not really required) Update workflow test to new settings api More rust cleanup - Rename Label to LowLevelILLabel - Update the functions label map automatically This fixed a major api blunder where the label map is returned as a reference and originally resulted in UB prone lifetime semantics. It was temporarily "fixed" with explicit label updates in the architecture implementation code. But that was less than ideal and was easy to mess up. Now the label map will be updated automatically as the location of labels is now tracked. Misc clippy lints More rust cleanup - Get rid of RawFunctionViewType - Add better Debug impl for Function More rust cleanup - Fixed the documentation icon using local files (thank you @mkrasnitski) - Fixed labels being updated and overwriting the label location used to update the label map More rust cleanup - Added unit tests for MLIL and HLIL - "Fixed" MLIL, LLIL, and HLIL having issues regarding Instruction vs Expression indexes - Renamed CallingConvention to CoreCallingConvention and removed architecture generic - Renamed CallingConventionBase to CallingConvention - Simplified calling convention code and fixed some bugs with implicit registers - Added impl Debug to MLIL and HLIL instructions Still need to at some point add an Expression to MLIL and HLIL. We also might want to look into having the Instruction kind just return the expression kind. Misc clippy lint More rust cleanup - Allow calling conventions to be registered for multiple architectures - Swapped a unreachable statement to an unimplemented statement More rust cleanup - Fixed the issue with PDB types, this has caused me an insane amount of grief - Fixed LLIL visit_tree missing LLIL_LOAD expressions - Added LLIL visitor test - Made all WARP file pickers use the rfd crate Use the dev branch of Binary Ninja in rust CI Misc rust fmt More rust cleanup - Refactored BinaryReader and BinaryWriter - Added some warnings to high_level_il and medium_level_il modules that they are unstable - Add BinaryReader and BinaryWriter tests - Changed BinaryView len to return u64 (that is what the core returns) - Misc formatting changes - Remove extern uses in lib.rs Add impl Debug for BinaryReader and BinaryWriter Turn off broken tests Add more info to the rust README.md More rust cleanup - Make EdgeStyle type not wrap raw - Regression tests for WARP will run on all bins in the out dir now impl rust Collaboration and Remote API Fix typo Update collaboration API Makes collaboration more in line with the refactor. Still a lot of work to do. Namely still need: - Proper errors - _with_opts functions - More ergonomic api - Better connection procedure - Updated documentation - A LOT of unit tests - An example - Typed id's for everything (i dont want BnString as the id!!!) - NEED to refactor the progress callbacks into the new progress api, but we should pull in some of the stuff the collab progress has - Elimination of apis that are dumb helpers Separate out the rust testing and use pull_request_target pull_request_target allows PR's to access the headless license, for this to be safe we need to prevent people from running the job. To prevent the job from being ran we add an environment requirement on testing that a reviewer must review the code and then manually approve it to run. More rust cleanup - Use GroupId instead of u64 - Use ProgressCallback in place of ProgressExecutor - Misc cleanup of FileMetadata - Add `save_to_path` and `save_to_accessor` to save modified binaries - Added binary_view unit tests - Added collaboration unit tests - Fixed a few issues with the collaboration apis - Renamed Command registration functions so that there is no import ambiguity - Split out RemoteUndoEntry - Collaboration apis now have a explicit `_with_progress` set of apis - Misc clippy lint fixes Fix some typos More rust cleanup - Add extra info to README.md - Refactor components api - Add components unit test Add testing and documentation to contributing section in README.md Fix misc doc comments
Diffstat (limited to 'rust/src/types.rs')
-rw-r--r--rust/src/types.rs3300
1 files changed, 938 insertions, 2362 deletions
diff --git a/rust/src/types.rs b/rust/src/types.rs
index c0156454..bd184b18 100644
--- a/rust/src/types.rs
+++ b/rust/src/types.rs
@@ -11,6 +11,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(unused)]
// TODO : More widely enforce the use of ref_from_raw vs just from_raw to simplify internal binding usage? Perhaps remove from_raw functions?
// TODO : Add documentation and fix examples
@@ -20,305 +21,33 @@ use binaryninjacore_sys::*;
use crate::{
architecture::{Architecture, CoreArchitecture},
- binaryview::{BinaryView, BinaryViewExt},
- callingconvention::CallingConvention,
- filemetadata::FileMetadata,
- function::Function,
- mlil::MediumLevelILFunction,
+ binary_view::{BinaryView, BinaryViewExt},
+ calling_convention::CoreCallingConvention,
rc::*,
- string::{raw_to_string, BnStrCompatible, BnString},
- symbol::Symbol,
+ string::{BnStrCompatible, BnString},
};
-use lazy_static::lazy_static;
-use std::ptr::null_mut;
+use crate::confidence::{Conf, MAX_CONFIDENCE, MIN_CONFIDENCE};
+use crate::string::{raw_to_string, strings_to_string_list};
+use crate::variable::{Variable, VariableSourceType};
+use std::borrow::Cow;
+use std::num::NonZeroUsize;
+use std::ops::{Index, IndexMut};
use std::{
- borrow::{Borrow, Cow},
- collections::{HashMap, HashSet},
+ collections::HashSet,
ffi::CStr,
- fmt::{self, Debug, Display, Formatter},
+ fmt::{Debug, Display, Formatter},
hash::{Hash, Hasher},
- iter::{zip, IntoIterator},
- mem::{self, ManuallyDrop},
- ops::Range,
- os::raw::c_char,
- ptr, result, slice,
- sync::Mutex,
+ iter::IntoIterator,
};
-pub type Result<R> = result::Result<R, ()>;
-
+pub type StructureType = BNStructureVariant;
pub type ReferenceType = BNReferenceType;
pub type TypeClass = BNTypeClass;
pub type NamedTypeReferenceClass = BNNamedTypeReferenceClass;
pub type MemberAccess = BNMemberAccess;
pub type MemberScope = BNMemberScope;
-pub type ILBranchDependence = BNILBranchDependence;
-pub type DataFlowQueryOption = BNDataFlowQueryOption;
-pub type VariableSourceType = BNVariableSourceType;
-
-////////////////
-// Confidence
-
-/// Compatible with the `BNType*WithConfidence` types
-pub struct Conf<T> {
- pub contents: T,
- pub confidence: u8,
-}
-
-pub trait ConfMergable<T, O> {
- type Result;
- /// Merge two confidence types' values depending on whichever has higher confidence
- /// In the event of a tie, the LHS (caller's) value is used.
- fn merge(self, other: O) -> Self::Result;
-}
-
-impl<T> Conf<T> {
- pub fn new(contents: T, confidence: u8) -> Self {
- Self {
- contents,
- confidence,
- }
- }
-
- pub fn map<U, F>(self, f: F) -> Conf<U>
- where
- F: FnOnce(T) -> U,
- {
- Conf::new(f(self.contents), self.confidence)
- }
-
- pub fn as_ref<U>(&self) -> Conf<&U>
- where
- T: AsRef<U>,
- {
- Conf::new(self.contents.as_ref(), self.confidence)
- }
-}
-
-/// Returns best value or LHS on tie
-///
-/// `Conf<T>` + `Conf<T>` → `Conf<T>`
-impl<T> ConfMergable<T, Conf<T>> for Conf<T> {
- type Result = Conf<T>;
- fn merge(self, other: Conf<T>) -> Conf<T> {
- if other.confidence > self.confidence {
- other
- } else {
- self
- }
- }
-}
-
-/// Returns LHS if RHS is None
-///
-/// `Conf<T>` + `Option<Conf<T>>` → `Conf<T>`
-impl<T> ConfMergable<T, Option<Conf<T>>> for Conf<T> {
- type Result = Conf<T>;
- fn merge(self, other: Option<Conf<T>>) -> Conf<T> {
- match other {
- Some(c @ Conf { confidence, .. }) if confidence > self.confidence => c,
- _ => self,
- }
- }
-}
-
-/// Returns RHS if LHS is None
-///
-/// `Option<Conf<T>>` + `Conf<T>` → `Conf<T>`
-impl<T> ConfMergable<T, Conf<T>> for Option<Conf<T>> {
- type Result = Conf<T>;
- fn merge(self, other: Conf<T>) -> Conf<T> {
- match self {
- Some(c @ Conf { confidence, .. }) if confidence >= other.confidence => c,
- _ => other,
- }
- }
-}
-
-/// Returns best non-None value or None
-///
-/// `Option<Conf<T>>` + `Option<Conf<T>>` → `Option<Conf<T>>`
-impl<T> ConfMergable<T, Option<Conf<T>>> for Option<Conf<T>> {
- type Result = Option<Conf<T>>;
- fn merge(self, other: Option<Conf<T>>) -> Option<Conf<T>> {
- match (self, other) {
- (
- Some(
- this @ Conf {
- confidence: this_confidence,
- ..
- },
- ),
- Some(
- other @ Conf {
- confidence: other_confidence,
- ..
- },
- ),
- ) => {
- if this_confidence >= other_confidence {
- Some(this)
- } else {
- Some(other)
- }
- }
- (None, Some(c)) => Some(c),
- (Some(c), None) => Some(c),
- (None, None) => None,
- }
- }
-}
-
-impl<T: Debug> Debug for Conf<T> {
- fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
- write!(f, "{:?} ({} confidence)", self.contents, self.confidence)
- }
-}
-
-impl<T: Display> Display for Conf<T> {
- fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
- write!(f, "{} ({} confidence)", self.contents, self.confidence)
- }
-}
-
-impl<T: PartialEq> PartialEq for Conf<T> {
- fn eq(&self, other: &Self) -> bool {
- self.contents.eq(&other.contents)
- }
-}
-
-impl<T: Eq> Eq for Conf<T> {}
-
-impl<T: Hash> Hash for Conf<T> {
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.contents.hash(state);
- }
-}
-
-impl<'a, T> From<&'a Conf<T>> for Conf<&'a T> {
- fn from(c: &'a Conf<T>) -> Self {
- Conf::new(&c.contents, c.confidence)
- }
-}
-
-impl<'a, T: RefCountable> From<&'a Conf<Ref<T>>> for Conf<&'a T> {
- fn from(c: &'a Conf<Ref<T>>) -> Self {
- Conf::new(c.contents.as_ref(), c.confidence)
- }
-}
-
-impl<'a, T: RefCountable> From<&'a Ref<T>> for Conf<&'a T> {
- fn from(r: &'a Ref<T>) -> Self {
- r.as_ref().into()
- }
-}
-
-#[inline]
-pub fn min_confidence() -> u8 {
- u8::MIN
-}
-
-#[inline]
-pub fn max_confidence() -> u8 {
- u8::MAX
-}
-
-impl<T: Clone> Clone for Conf<T> {
- fn clone(&self) -> Self {
- Self {
- contents: self.contents.clone(),
- confidence: self.confidence,
- }
- }
-}
-
-impl<T: Copy> Copy for Conf<T> {}
-
-impl<T> From<T> for Conf<T> {
- fn from(contents: T) -> Self {
- Self::new(contents, max_confidence())
- }
-}
-
-impl From<BNTypeWithConfidence> for Conf<Ref<Type>> {
- fn from(type_with_confidence: BNTypeWithConfidence) -> Self {
- Self::new(
- unsafe { Type::ref_from_raw(type_with_confidence.type_) },
- type_with_confidence.confidence,
- )
- }
-}
-
-impl From<BNBoolWithConfidence> for Conf<bool> {
- fn from(bool_with_confidence: BNBoolWithConfidence) -> Self {
- Self::new(bool_with_confidence.value, bool_with_confidence.confidence)
- }
-}
-
-impl From<BNCallingConventionWithConfidence> for Conf<Ref<CallingConvention<CoreArchitecture>>> {
- fn from(cc_with_confidence: BNCallingConventionWithConfidence) -> Self {
- Self::new(
- unsafe {
- CallingConvention::ref_from_raw(
- cc_with_confidence.convention,
- CoreArchitecture::from_raw(BNGetCallingConventionArchitecture(
- cc_with_confidence.convention,
- )),
- )
- },
- cc_with_confidence.confidence,
- )
- }
-}
-
-impl From<BNOffsetWithConfidence> for Conf<i64> {
- fn from(offset_with_confidence: BNOffsetWithConfidence) -> Self {
- Self::new(
- offset_with_confidence.value,
- offset_with_confidence.confidence,
- )
- }
-}
-
-impl From<Conf<&Type>> for BNTypeWithConfidence {
- fn from(conf: Conf<&Type>) -> Self {
- Self {
- type_: conf.contents.handle,
- confidence: conf.confidence,
- }
- }
-}
-
-impl From<Conf<bool>> for BNBoolWithConfidence {
- fn from(conf: Conf<bool>) -> Self {
- Self {
- value: conf.contents,
- confidence: conf.confidence,
- }
- }
-}
-
-impl<A: Architecture> From<Conf<&CallingConvention<A>>> for BNCallingConventionWithConfidence {
- fn from(conf: Conf<&CallingConvention<A>>) -> Self {
- Self {
- convention: conf.contents.handle,
- confidence: conf.confidence,
- }
- }
-}
-
-impl From<Conf<i64>> for BNOffsetWithConfidence {
- fn from(conf: Conf<i64>) -> Self {
- Self {
- value: conf.contents,
- confidence: conf.confidence,
- }
- }
-}
-
-//////////////////
-// Type Builder
+pub type IntegerDisplayType = BNIntegerDisplayType;
#[derive(PartialEq, Eq, Hash)]
pub struct TypeBuilder {
@@ -396,59 +125,54 @@ impl TypeBuilder {
unsafe { BNIsTypeBuilderFloatingPoint(self.handle) }
}
- pub fn target(&self) -> Result<Conf<Ref<Type>>> {
+ pub fn child_type(&self) -> Option<Conf<Ref<Type>>> {
let raw_target = unsafe { BNGetTypeBuilderChildType(self.handle) };
- if raw_target.type_.is_null() {
- Err(())
- } else {
- Ok(raw_target.into())
+ match raw_target.type_.is_null() {
+ false => Some(Conf::<Ref<Type>>::from_owned_raw(raw_target)),
+ true => None,
}
}
- pub fn element_type(&self) -> Result<Conf<Ref<Type>>> {
- let raw_target = unsafe { BNGetTypeBuilderChildType(self.handle) };
- if raw_target.type_.is_null() {
- Err(())
- } else {
- Ok(raw_target.into())
- }
+ /// This is an alias for [`Self::child_type`].
+ pub fn target(&self) -> Option<Conf<Ref<Type>>> {
+ self.child_type()
}
- pub fn return_value(&self) -> Result<Conf<Ref<Type>>> {
- let raw_target = unsafe { BNGetTypeBuilderChildType(self.handle) };
- if raw_target.type_.is_null() {
- Err(())
- } else {
- Ok(raw_target.into())
- }
+ /// This is an alias for [`Self::child_type`].
+ pub fn element_type(&self) -> Option<Conf<Ref<Type>>> {
+ self.child_type()
}
- pub fn calling_convention(&self) -> Result<Conf<Ref<CallingConvention<CoreArchitecture>>>> {
- let convention_confidence = unsafe { BNGetTypeBuilderCallingConvention(self.handle) };
- if convention_confidence.convention.is_null() {
- Err(())
- } else {
- Ok(convention_confidence.into())
+ /// This is an alias for [`Self::child_type`].
+ pub fn return_value(&self) -> Option<Conf<Ref<Type>>> {
+ self.child_type()
+ }
+
+ pub fn calling_convention(&self) -> Option<Conf<Ref<CoreCallingConvention>>> {
+ let raw_convention_confidence = unsafe { BNGetTypeBuilderCallingConvention(self.handle) };
+ match raw_convention_confidence.convention.is_null() {
+ false => Some(Conf::<Ref<CoreCallingConvention>>::from_owned_raw(
+ raw_convention_confidence,
+ )),
+ true => None,
}
}
- pub fn parameters(&self) -> Result<Vec<FunctionParameter>> {
+ pub fn parameters(&self) -> Option<Vec<FunctionParameter>> {
unsafe {
let mut count = 0;
- let parameters_raw = BNGetTypeBuilderParameters(self.handle, &mut count);
- if parameters_raw.is_null() {
- Err(())
- } else {
- let parameters: &[BNFunctionParameter] =
- slice::from_raw_parts(parameters_raw, count);
-
- let result = (0..count)
- .map(|i| FunctionParameter::from_raw(parameters[i]))
- .collect();
-
- BNFreeTypeParameterList(parameters_raw, count);
-
- Ok(result)
+ let raw_parameters_ptr = BNGetTypeBuilderParameters(self.handle, &mut count);
+ match raw_parameters_ptr.is_null() {
+ false => {
+ let raw_parameters = std::slice::from_raw_parts(raw_parameters_ptr, count);
+ let parameters = raw_parameters
+ .iter()
+ .map(FunctionParameter::from_raw)
+ .collect();
+ BNFreeTypeParameterList(raw_parameters_ptr, count);
+ Some(parameters)
+ }
+ true => None,
}
}
}
@@ -465,30 +189,33 @@ impl TypeBuilder {
unsafe { BNIsTypeBuilderPure(self.handle).into() }
}
- pub fn get_structure(&self) -> Result<Ref<Structure>> {
- let result = unsafe { BNGetTypeBuilderStructure(self.handle) };
- if result.is_null() {
- Err(())
- } else {
- Ok(unsafe { Structure::ref_from_raw(result) })
+ // TODO: This naming is problematic... rename to `as_structure`?
+ // TODO: We wouldn't need these sort of functions if we destructured `Type`...
+ pub fn get_structure(&self) -> Option<Ref<Structure>> {
+ let raw_struct_ptr = unsafe { BNGetTypeBuilderStructure(self.handle) };
+ match raw_struct_ptr.is_null() {
+ false => Some(unsafe { Structure::ref_from_raw(raw_struct_ptr) }),
+ true => None,
}
}
- pub fn get_enumeration(&self) -> Result<Ref<Enumeration>> {
- let result = unsafe { BNGetTypeBuilderEnumeration(self.handle) };
- if result.is_null() {
- Err(())
- } else {
- Ok(unsafe { Enumeration::ref_from_raw(result) })
+ // TODO: This naming is problematic... rename to `as_enumeration`?
+ // TODO: We wouldn't need these sort of functions if we destructured `Type`...
+ pub fn get_enumeration(&self) -> Option<Ref<Enumeration>> {
+ let raw_enum_ptr = unsafe { BNGetTypeBuilderEnumeration(self.handle) };
+ match raw_enum_ptr.is_null() {
+ false => Some(unsafe { Enumeration::ref_from_raw(raw_enum_ptr) }),
+ true => None,
}
}
- pub fn get_named_type_reference(&self) -> Result<Ref<NamedTypeReference>> {
- let result = unsafe { BNGetTypeBuilderNamedTypeReference(self.handle) };
- if result.is_null() {
- Err(())
- } else {
- Ok(unsafe { NamedTypeReference::ref_from_raw(result) })
+ // TODO: This naming is problematic... rename to `as_named_type_reference`?
+ // TODO: We wouldn't need these sort of functions if we destructured `Type`...
+ pub fn get_named_type_reference(&self) -> Option<Ref<NamedTypeReference>> {
+ let raw_type_ref_ptr = unsafe { BNGetTypeBuilderNamedTypeReference(self.handle) };
+ match raw_type_ref_ptr.is_null() {
+ false => Some(unsafe { NamedTypeReference::ref_from_raw(raw_type_ref_ptr) }),
+ true => None,
}
}
@@ -520,7 +247,7 @@ impl TypeBuilder {
}
pub fn int(width: usize, is_signed: bool) -> Self {
- let mut is_signed = Conf::new(is_signed, max_confidence()).into();
+ let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into();
unsafe {
Self::from_raw(BNCreateIntegerTypeBuilder(
@@ -532,7 +259,7 @@ impl TypeBuilder {
}
pub fn named_int<S: BnStrCompatible>(width: usize, is_signed: bool, alt_name: S) -> Self {
- let mut is_signed = Conf::new(is_signed, max_confidence()).into();
+ let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into();
// let alt_name = BnString::new(alt_name);
let alt_name = alt_name.into_bytes_with_nul(); // This segfaulted once, so the above version is there if we need to change to it, but in theory this is copied into a `const string&` on the C++ side; I'm just not 100% confident that a constant reference copies data
@@ -566,24 +293,27 @@ impl TypeBuilder {
}
}
- pub fn array<'a, T: Into<Conf<&'a Type>>>(t: T, count: u64) -> Self {
- unsafe { Self::from_raw(BNCreateArrayTypeBuilder(&t.into().into(), count)) }
+ pub fn array<'a, T: Into<Conf<&'a Type>>>(ty: T, count: u64) -> Self {
+ let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
+ unsafe { Self::from_raw(BNCreateArrayTypeBuilder(&owned_raw_ty, count)) }
}
- /// The C/C++ APIs require an associated architecture, but in the core we only query the default_int_size if the given width is 0
- /// For simplicity's sake, that convention isn't followed and you can query the default_int_size from an arch, if you have it, if you need to
+ /// ## NOTE
+ ///
+ /// The C/C++ APIs require an associated architecture, but in the core we only query the default_int_size if the given width is 0.
+ ///
+ /// For simplicity's sake, that convention isn't followed, and you can query [`Architecture::default_integer_size`] if you need to.
pub fn enumeration<T: Into<Conf<bool>>>(
enumeration: &Enumeration,
- width: usize,
+ width: NonZeroUsize,
is_signed: T,
) -> Self {
unsafe {
- // TODO : This is _extremely fragile_, we should change the internals of BNCreateEnumerationTypeBuilder instead of doing this
- let mut fake_arch: BNArchitecture = mem::zeroed();
Self::from_raw(BNCreateEnumerationTypeBuilder(
- &mut fake_arch,
+ // TODO: We pass nullptr arch, really we should not even be passing arch.
+ std::ptr::null_mut(),
enumeration.handle,
- width,
+ width.get(),
&mut is_signed.into().into(),
))
}
@@ -594,8 +324,8 @@ impl TypeBuilder {
}
pub fn named_type(type_reference: NamedTypeReference) -> Self {
- let mut is_const = Conf::new(false, min_confidence()).into();
- let mut is_volatile = Conf::new(false, min_confidence()).into();
+ let mut is_const = Conf::new(false, MIN_CONFIDENCE).into();
+ let mut is_volatile = Conf::new(false, MIN_CONFIDENCE).into();
unsafe {
Self::from_raw(BNCreateNamedTypeReferenceBuilder(
type_reference.handle,
@@ -607,28 +337,31 @@ impl TypeBuilder {
}
}
- pub fn named_type_from_type<S: BnStrCompatible>(name: S, t: &Type) -> Self {
- let mut name = QualifiedName::from(name);
+ pub fn named_type_from_type<T: Into<QualifiedName>>(name: T, t: &Type) -> Self {
+ let mut raw_name = QualifiedName::into_raw(name.into());
+ let id = c"";
- unsafe {
+ let result = unsafe {
Self::from_raw(BNCreateNamedTypeReferenceBuilderFromTypeAndId(
- BnString::new("").as_ptr() as *mut _,
- &mut name.0,
+ id.as_ptr() as *mut _,
+ &mut raw_name,
t.handle,
))
- }
+ };
+ QualifiedName::free_raw(raw_name);
+ result
}
// TODO : BNCreateFunctionTypeBuilder
- pub fn pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(arch: &A, t: T) -> Self {
- let mut is_const = Conf::new(false, min_confidence()).into();
- let mut is_volatile = Conf::new(false, min_confidence()).into();
-
+ pub fn pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(arch: &A, ty: T) -> Self {
+ let mut is_const = Conf::new(false, MIN_CONFIDENCE).into();
+ let mut is_volatile = Conf::new(false, MIN_CONFIDENCE).into();
+ let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe {
Self::from_raw(BNCreatePointerTypeBuilder(
- arch.as_ref().0,
- &t.into().into(),
+ arch.as_ref().handle,
+ &owned_raw_ty,
&mut is_const,
&mut is_volatile,
ReferenceType::PointerReferenceType,
@@ -636,14 +369,14 @@ impl TypeBuilder {
}
}
- pub fn const_pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(arch: &A, t: T) -> Self {
- let mut is_const = Conf::new(true, max_confidence()).into();
- let mut is_volatile = Conf::new(false, min_confidence()).into();
-
+ pub fn const_pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(arch: &A, ty: T) -> Self {
+ let mut is_const = Conf::new(true, MAX_CONFIDENCE).into();
+ let mut is_volatile = Conf::new(false, MIN_CONFIDENCE).into();
+ let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe {
Self::from_raw(BNCreatePointerTypeBuilder(
- arch.as_ref().0,
- &t.into().into(),
+ arch.as_ref().handle,
+ &owned_raw_ty,
&mut is_const,
&mut is_volatile,
ReferenceType::PointerReferenceType,
@@ -652,19 +385,19 @@ impl TypeBuilder {
}
pub fn pointer_of_width<'a, T: Into<Conf<&'a Type>>>(
- t: T,
+ ty: T,
size: usize,
is_const: bool,
is_volatile: bool,
ref_type: Option<ReferenceType>,
) -> Self {
- let mut is_const = Conf::new(is_const, max_confidence()).into();
- let mut is_volatile = Conf::new(is_volatile, max_confidence()).into();
-
+ let mut is_const = Conf::new(is_const, MAX_CONFIDENCE).into();
+ let mut is_volatile = Conf::new(is_volatile, MAX_CONFIDENCE).into();
+ let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe {
Self::from_raw(BNCreatePointerTypeBuilderOfWidth(
size,
- &t.into().into(),
+ &owned_raw_ty,
&mut is_const,
&mut is_volatile,
ref_type.unwrap_or(ReferenceType::PointerReferenceType),
@@ -674,17 +407,18 @@ impl TypeBuilder {
pub fn pointer_with_options<'a, A: Architecture, T: Into<Conf<&'a Type>>>(
arch: &A,
- t: T,
+ ty: T,
is_const: bool,
is_volatile: bool,
ref_type: Option<ReferenceType>,
) -> Self {
- let mut is_const = Conf::new(is_const, max_confidence()).into();
- let mut is_volatile = Conf::new(is_volatile, max_confidence()).into();
+ let mut is_const = Conf::new(is_const, MAX_CONFIDENCE).into();
+ let mut is_volatile = Conf::new(is_volatile, MAX_CONFIDENCE).into();
+ let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe {
Self::from_raw(BNCreatePointerTypeBuilder(
- arch.as_ref().0,
- &t.into().into(),
+ arch.as_ref().handle,
+ &owned_raw_ty,
&mut is_const,
&mut is_volatile,
ref_type.unwrap_or(ReferenceType::PointerReferenceType),
@@ -693,10 +427,10 @@ impl TypeBuilder {
}
}
-impl fmt::Display for TypeBuilder {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+impl Display for TypeBuilder {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", unsafe {
- BnString::from_raw(BNGetTypeBuilderString(self.handle, ptr::null_mut()))
+ BnString::from_raw(BNGetTypeBuilderString(self.handle, std::ptr::null_mut()))
})
}
}
@@ -707,16 +441,13 @@ impl Drop for TypeBuilder {
}
}
-//////////
-// Type
-
#[repr(transparent)]
pub struct Type {
pub(crate) handle: *mut BNType,
}
/// ```no_run
-/// # use crate::binaryninja::binaryview::BinaryViewExt;
+/// # use crate::binaryninja::binary_view::BinaryViewExt;
/// # use binaryninja::types::Type;
/// let bv = binaryninja::load("example.bin").unwrap();
/// let my_custom_type_1 = Type::named_int(5, false, "my_w");
@@ -725,7 +456,7 @@ pub struct Type {
/// bv.define_user_type("int_2", &my_custom_type_2);
/// ```
impl Type {
- unsafe fn from_raw(handle: *mut BNType) -> Self {
+ pub(crate) unsafe fn from_raw(handle: *mut BNType) -> Self {
debug_assert!(!handle.is_null());
Self { handle }
}
@@ -739,12 +470,12 @@ impl Type {
TypeBuilder::new(self)
}
- // Readable properties
-
pub fn type_class(&self) -> TypeClass {
unsafe { BNGetTypeClass(self.handle) }
}
+ // TODO: We need to decide on a public type to represent type width.
+ // TODO: The api uses both `u64` and `usize`, pick one or a new type!
pub fn width(&self) -> u64 {
unsafe { BNGetTypeWidth(self.handle) }
}
@@ -769,60 +500,54 @@ impl Type {
unsafe { BNIsTypeFloatingPoint(self.handle) }
}
- pub fn target(&self) -> Result<Conf<Ref<Type>>> {
+ pub fn child_type(&self) -> Option<Conf<Ref<Type>>> {
let raw_target = unsafe { BNGetChildType(self.handle) };
- if raw_target.type_.is_null() {
- Err(())
- } else {
- Ok(raw_target.into())
+ match raw_target.type_.is_null() {
+ false => Some(Conf::<Ref<Type>>::from_owned_raw(raw_target)),
+ true => None,
}
}
- pub fn element_type(&self) -> Result<Conf<Ref<Type>>> {
- let raw_target = unsafe { BNGetChildType(self.handle) };
- if raw_target.type_.is_null() {
- Err(())
- } else {
- Ok(raw_target.into())
- }
+ /// This is an alias for [`Self::child_type`].
+ pub fn target(&self) -> Option<Conf<Ref<Type>>> {
+ self.child_type()
}
- pub fn return_value(&self) -> Result<Conf<Ref<Type>>> {
- let raw_target = unsafe { BNGetChildType(self.handle) };
- if raw_target.type_.is_null() {
- Err(())
- } else {
- Ok(raw_target.into())
- }
+ /// This is an alias for [`Self::child_type`].
+ pub fn element_type(&self) -> Option<Conf<Ref<Type>>> {
+ self.child_type()
+ }
+
+ /// This is an alias for [`Self::child_type`].
+ pub fn return_value(&self) -> Option<Conf<Ref<Type>>> {
+ self.child_type()
}
- pub fn calling_convention(&self) -> Result<Conf<Ref<CallingConvention<CoreArchitecture>>>> {
+ pub fn calling_convention(&self) -> Option<Conf<Ref<CoreCallingConvention>>> {
let convention_confidence = unsafe { BNGetTypeCallingConvention(self.handle) };
- if convention_confidence.convention.is_null() {
- Err(())
- } else {
- Ok(convention_confidence.into())
+ match convention_confidence.convention.is_null() {
+ false => Some(Conf::<Ref<CoreCallingConvention>>::from_owned_raw(
+ convention_confidence,
+ )),
+ true => None,
}
}
- pub fn parameters(&self) -> Result<Vec<FunctionParameter>> {
+ pub fn parameters(&self) -> Option<Vec<FunctionParameter>> {
unsafe {
let mut count = 0;
- let parameters_raw: *mut BNFunctionParameter =
- BNGetTypeParameters(self.handle, &mut count);
- if parameters_raw.is_null() {
- Err(())
- } else {
- let parameters: &[BNFunctionParameter] =
- slice::from_raw_parts(parameters_raw, count);
-
- let result = (0..count)
- .map(|i| FunctionParameter::from_raw(parameters[i]))
- .collect();
-
- BNFreeTypeParameterList(parameters_raw, count);
-
- Ok(result)
+ let raw_parameters_ptr = BNGetTypeParameters(self.handle, &mut count);
+ match raw_parameters_ptr.is_null() {
+ false => {
+ let raw_parameters = std::slice::from_raw_parts(raw_parameters_ptr, count);
+ let parameters = raw_parameters
+ .iter()
+ .map(FunctionParameter::from_raw)
+ .collect();
+ BNFreeTypeParameterList(raw_parameters_ptr, count);
+ Some(parameters)
+ }
+ true => None,
}
}
}
@@ -839,30 +564,33 @@ impl Type {
unsafe { BNIsTypePure(self.handle).into() }
}
- pub fn get_structure(&self) -> Result<Ref<Structure>> {
- let result = unsafe { BNGetTypeStructure(self.handle) };
- if result.is_null() {
- Err(())
- } else {
- Ok(unsafe { Structure::ref_from_raw(result) })
+ // TODO: This naming is problematic... rename to `as_structure`?
+ // TODO: We wouldn't need these sort of functions if we destructured `Type`...
+ pub fn get_structure(&self) -> Option<Ref<Structure>> {
+ let raw_struct_ptr = unsafe { BNGetTypeStructure(self.handle) };
+ match raw_struct_ptr.is_null() {
+ false => Some(unsafe { Structure::ref_from_raw(raw_struct_ptr) }),
+ true => None,
}
}
- pub fn get_enumeration(&self) -> Result<Ref<Enumeration>> {
- let result = unsafe { BNGetTypeEnumeration(self.handle) };
- if result.is_null() {
- Err(())
- } else {
- Ok(unsafe { Enumeration::ref_from_raw(result) })
+ // TODO: This naming is problematic... rename to `as_enumeration`?
+ // TODO: We wouldn't need these sort of functions if we destructured `Type`...
+ pub fn get_enumeration(&self) -> Option<Ref<Enumeration>> {
+ let raw_enum_ptr = unsafe { BNGetTypeEnumeration(self.handle) };
+ match raw_enum_ptr.is_null() {
+ false => Some(unsafe { Enumeration::ref_from_raw(raw_enum_ptr) }),
+ true => None,
}
}
- pub fn get_named_type_reference(&self) -> Result<Ref<NamedTypeReference>> {
- let result = unsafe { BNGetTypeNamedTypeReference(self.handle) };
- if result.is_null() {
- Err(())
- } else {
- Ok(unsafe { NamedTypeReference::ref_from_raw(result) })
+ // TODO: This naming is problematic... rename to `as_named_type_reference`?
+ // TODO: We wouldn't need these sort of functions if we destructured `Type`...
+ pub fn get_named_type_reference(&self) -> Option<Ref<NamedTypeReference>> {
+ let raw_type_ref_ptr = unsafe { BNGetTypeNamedTypeReference(self.handle) };
+ match raw_type_ref_ptr.is_null() {
+ false => Some(unsafe { NamedTypeReference::ref_from_raw(raw_type_ref_ptr) }),
+ true => None,
}
}
@@ -878,12 +606,11 @@ impl Type {
unsafe { BNGetTypeStackAdjustment(self.handle).into() }
}
- pub fn registered_name(&self) -> Result<Ref<NamedTypeReference>> {
- let result = unsafe { BNGetRegisteredTypeName(self.handle) };
- if result.is_null() {
- Err(())
- } else {
- Ok(unsafe { NamedTypeReference::ref_from_raw(result) })
+ pub fn registered_name(&self) -> Option<Ref<NamedTypeReference>> {
+ let raw_type_ref_ptr = unsafe { BNGetRegisteredTypeName(self.handle) };
+ match raw_type_ref_ptr.is_null() {
+ false => Some(unsafe { NamedTypeReference::ref_from_raw(raw_type_ref_ptr) }),
+ true => None,
}
}
@@ -912,7 +639,7 @@ impl Type {
}
pub fn int(width: usize, is_signed: bool) -> Ref<Self> {
- let mut is_signed = Conf::new(is_signed, max_confidence()).into();
+ let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into();
unsafe {
Self::ref_from_raw(BNCreateIntegerType(
width,
@@ -923,7 +650,7 @@ impl Type {
}
pub fn named_int<S: BnStrCompatible>(width: usize, is_signed: bool, alt_name: S) -> Ref<Self> {
- let mut is_signed = Conf::new(is_signed, max_confidence()).into();
+ let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into();
// let alt_name = BnString::new(alt_name);
let alt_name = alt_name.into_bytes_with_nul(); // This segfaulted once, so the above version is there if we need to change to it, but in theory this is copied into a `const string&` on the C++ side; I'm just not 100% confident that a constant reference copies data
@@ -952,25 +679,27 @@ impl Type {
unsafe { Self::ref_from_raw(BNCreateFloatType(width, alt_name.as_ref().as_ptr() as _)) }
}
- pub fn array<'a, T: Into<Conf<&'a Type>>>(t: T, count: u64) -> Ref<Self> {
- unsafe { Self::ref_from_raw(BNCreateArrayType(&t.into().into(), count)) }
+ pub fn array<'a, T: Into<Conf<&'a Type>>>(ty: T, count: u64) -> Ref<Self> {
+ let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
+ unsafe { Self::ref_from_raw(BNCreateArrayType(&owned_raw_ty, count)) }
}
- /// The C/C++ APIs require an associated architecture, but in the core we only query the default_int_size if the given width is 0
+ /// ## NOTE
///
- /// For simplicity's sake, that convention isn't followed and you can query the default_int_size from an arch, if you have it, if you need to
+ /// The C/C++ APIs require an associated architecture, but in the core we only query the default_int_size if the given width is 0.
+ ///
+ /// For simplicity's sake, that convention isn't followed, and you can query [`Architecture::default_integer_size`] if you need to.
pub fn enumeration<T: Into<Conf<bool>>>(
enumeration: &Enumeration,
- width: usize,
+ width: NonZeroUsize,
is_signed: T,
) -> Ref<Self> {
unsafe {
- // TODO : This is _extremely fragile_, we should change the internals of BNCreateEnumerationType instead of doing this
- let mut fake_arch: BNArchitecture = mem::zeroed();
Self::ref_from_raw(BNCreateEnumerationType(
- &mut fake_arch,
+ // TODO: We pass nullptr arch, really we should not even be passing arch.
+ std::ptr::null_mut(),
enumeration.handle,
- width,
+ width.get(),
&mut is_signed.into().into(),
))
}
@@ -981,8 +710,8 @@ impl Type {
}
pub fn named_type(type_reference: &NamedTypeReference) -> Ref<Self> {
- let mut is_const = Conf::new(false, min_confidence()).into();
- let mut is_volatile = Conf::new(false, min_confidence()).into();
+ let mut is_const = Conf::new(false, MIN_CONFIDENCE).into();
+ let mut is_volatile = Conf::new(false, MIN_CONFIDENCE).into();
unsafe {
Self::ref_from_raw(BNCreateNamedTypeReference(
type_reference.handle,
@@ -994,65 +723,56 @@ impl Type {
}
}
- pub fn named_type_from_type<S: BnStrCompatible>(name: S, t: &Type) -> Ref<Self> {
- let mut name = QualifiedName::from(name);
+ pub fn named_type_from_type<T: Into<QualifiedName>>(name: T, t: &Type) -> Ref<Self> {
+ let mut raw_name = QualifiedName::into_raw(name.into());
+ // TODO: No id is present for this call?
+ let id = c"";
- unsafe {
+ let result = unsafe {
Self::ref_from_raw(BNCreateNamedTypeReferenceFromTypeAndId(
- BnString::new("").as_ptr() as *mut _,
- &mut name.0,
+ id.as_ptr(),
+ &mut raw_name,
t.handle,
))
- }
+ };
+ QualifiedName::free_raw(raw_name);
+ result
}
+ // TODO: FunctionBuilder
pub fn function<'a, T: Into<Conf<&'a Type>>>(
return_type: T,
- parameters: &[FunctionParameter],
+ parameters: Vec<FunctionParameter>,
variable_arguments: bool,
) -> Ref<Self> {
- let mut return_type = return_type.into().into();
- let mut variable_arguments = Conf::new(variable_arguments, max_confidence()).into();
- let mut can_return = Conf::new(true, min_confidence()).into();
- let mut pure = Conf::new(false, min_confidence()).into();
+ let mut owned_raw_return_type = Conf::<&Type>::into_raw(return_type.into());
+ let mut variable_arguments = Conf::new(variable_arguments, MAX_CONFIDENCE).into();
+ let mut can_return = Conf::new(true, MIN_CONFIDENCE).into();
+ let mut pure = Conf::new(false, MIN_CONFIDENCE).into();
let mut raw_calling_convention: BNCallingConventionWithConfidence =
BNCallingConventionWithConfidence {
- convention: ptr::null_mut(),
- confidence: min_confidence(),
- };
-
- let mut stack_adjust = Conf::<i64>::new(0, min_confidence()).into();
- let mut raw_parameters = Vec::<BNFunctionParameter>::with_capacity(parameters.len());
- let mut parameter_name_references = Vec::with_capacity(parameters.len());
- for parameter in parameters {
- let raw_name = parameter.name.as_str().into_bytes_with_nul();
- let location = match &parameter.location {
- Some(location) => location.raw(),
- None => unsafe { mem::zeroed() },
+ convention: std::ptr::null_mut(),
+ confidence: MIN_CONFIDENCE,
};
- raw_parameters.push(BNFunctionParameter {
- name: raw_name.as_slice().as_ptr() as *mut _,
- type_: parameter.t.contents.handle,
- typeConfidence: parameter.t.confidence,
- defaultLocation: parameter.location.is_none(),
- location,
- });
- parameter_name_references.push(raw_name);
- }
- let reg_stack_adjust_regs = ptr::null_mut();
- let reg_stack_adjust_values = ptr::null_mut();
+ let mut stack_adjust = Conf::new(0, MIN_CONFIDENCE).into();
+ let mut raw_parameters = parameters
+ .into_iter()
+ .map(FunctionParameter::into_raw)
+ .collect::<Vec<_>>();
+ let reg_stack_adjust_regs = std::ptr::null_mut();
+ let reg_stack_adjust_values = std::ptr::null_mut();
let mut return_regs: BNRegisterSetWithConfidence = BNRegisterSetWithConfidence {
- regs: ptr::null_mut(),
+ regs: std::ptr::null_mut(),
count: 0,
confidence: 0,
};
- unsafe {
+ let result = unsafe {
Self::ref_from_raw(BNNewTypeReference(BNCreateFunctionType(
- &mut return_type,
+ &mut owned_raw_return_type,
&mut raw_calling_convention,
raw_parameters.as_mut_ptr(),
raw_parameters.len(),
@@ -1066,14 +786,20 @@ impl Type {
BNNameType::NoNameType,
&mut pure,
)))
+ };
+
+ for raw_param in raw_parameters {
+ FunctionParameter::free_raw(raw_param);
}
+
+ result
}
- pub fn function_with_options<
+ // TODO: FunctionBuilder
+ pub fn function_with_opts<
'a,
- A: Architecture,
T: Into<Conf<&'a Type>>,
- C: Into<Conf<&'a CallingConvention<A>>>,
+ C: Into<Conf<Ref<CoreCallingConvention>>>,
>(
return_type: T,
parameters: &[FunctionParameter],
@@ -1081,52 +807,35 @@ impl Type {
calling_convention: C,
stack_adjust: Conf<i64>,
) -> Ref<Self> {
- let mut return_type = return_type.into().into();
- let mut variable_arguments = Conf::new(variable_arguments, max_confidence()).into();
- let mut can_return = Conf::new(true, min_confidence()).into();
- let mut pure = Conf::new(false, min_confidence()).into();
- let mut raw_calling_convention: BNCallingConventionWithConfidence =
- calling_convention.into().into();
- let mut stack_adjust = stack_adjust.into();
-
- let mut raw_parameters = Vec::<BNFunctionParameter>::with_capacity(parameters.len());
- let mut parameter_name_references = Vec::with_capacity(parameters.len());
- let mut name_ptrs = vec![];
- for parameter in parameters {
- name_ptrs.push(parameter.name.clone());
- }
+ let mut owned_raw_return_type = Conf::<&Type>::into_raw(return_type.into());
+ let mut variable_arguments = Conf::new(variable_arguments, MAX_CONFIDENCE).into();
+ let mut can_return = Conf::new(true, MIN_CONFIDENCE).into();
+ let mut pure = Conf::new(false, MIN_CONFIDENCE).into();
- for (name, parameter) in zip(name_ptrs, parameters) {
- let raw_name = name.as_str().into_bytes_with_nul();
- let location = match &parameter.location {
- Some(location) => location.raw(),
- None => unsafe { mem::zeroed() },
- };
+ let mut owned_raw_calling_convention =
+ Conf::<Ref<CoreCallingConvention>>::into_owned_raw(&calling_convention.into());
- raw_parameters.push(BNFunctionParameter {
- name: raw_name.as_slice().as_ptr() as *mut _,
- type_: parameter.t.contents.handle,
- typeConfidence: parameter.t.confidence,
- defaultLocation: parameter.location.is_none(),
- location,
- });
- parameter_name_references.push(raw_name);
- }
+ let mut stack_adjust = stack_adjust.into();
+ let mut raw_parameters = parameters
+ .iter()
+ .cloned()
+ .map(FunctionParameter::into_raw)
+ .collect::<Vec<_>>();
// TODO: Update type signature and include these (will be a breaking change)
- let reg_stack_adjust_regs = ptr::null_mut();
- let reg_stack_adjust_values = ptr::null_mut();
+ let reg_stack_adjust_regs = std::ptr::null_mut();
+ let reg_stack_adjust_values = std::ptr::null_mut();
let mut return_regs: BNRegisterSetWithConfidence = BNRegisterSetWithConfidence {
- regs: ptr::null_mut(),
+ regs: std::ptr::null_mut(),
count: 0,
confidence: 0,
};
- unsafe {
+ let result = unsafe {
Self::ref_from_raw(BNCreateFunctionType(
- &mut return_type,
- &mut raw_calling_convention,
+ &mut owned_raw_return_type,
+ &mut owned_raw_calling_convention,
raw_parameters.as_mut_ptr(),
raw_parameters.len(),
&mut variable_arguments,
@@ -1139,16 +848,23 @@ impl Type {
BNNameType::NoNameType,
&mut pure,
))
+ };
+
+ for raw_param in raw_parameters {
+ FunctionParameter::free_raw(raw_param);
}
+
+ result
}
- pub fn pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(arch: &A, t: T) -> Ref<Self> {
- let mut is_const = Conf::new(false, min_confidence()).into();
- let mut is_volatile = Conf::new(false, min_confidence()).into();
+ pub fn pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(arch: &A, ty: T) -> Ref<Self> {
+ let mut is_const = Conf::new(false, MIN_CONFIDENCE).into();
+ let mut is_volatile = Conf::new(false, MIN_CONFIDENCE).into();
+ let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe {
Self::ref_from_raw(BNCreatePointerType(
- arch.as_ref().0,
- &t.into().into(),
+ arch.as_ref().handle,
+ &owned_raw_ty,
&mut is_const,
&mut is_volatile,
ReferenceType::PointerReferenceType,
@@ -1158,14 +874,15 @@ impl Type {
pub fn const_pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(
arch: &A,
- t: T,
+ ty: T,
) -> Ref<Self> {
- let mut is_const = Conf::new(true, max_confidence()).into();
- let mut is_volatile = Conf::new(false, min_confidence()).into();
+ let mut is_const = Conf::new(true, MAX_CONFIDENCE).into();
+ let mut is_volatile = Conf::new(false, MIN_CONFIDENCE).into();
+ let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe {
Self::ref_from_raw(BNCreatePointerType(
- arch.as_ref().0,
- &t.into().into(),
+ arch.as_ref().handle,
+ &owned_raw_ty,
&mut is_const,
&mut is_volatile,
ReferenceType::PointerReferenceType,
@@ -1174,18 +891,19 @@ impl Type {
}
pub fn pointer_of_width<'a, T: Into<Conf<&'a Type>>>(
- t: T,
+ ty: T,
size: usize,
is_const: bool,
is_volatile: bool,
ref_type: Option<ReferenceType>,
) -> Ref<Self> {
- let mut is_const = Conf::new(is_const, max_confidence()).into();
- let mut is_volatile = Conf::new(is_volatile, max_confidence()).into();
+ let mut is_const = Conf::new(is_const, MAX_CONFIDENCE).into();
+ let mut is_volatile = Conf::new(is_volatile, MAX_CONFIDENCE).into();
+ let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe {
Self::ref_from_raw(BNCreatePointerTypeOfWidth(
size,
- &t.into().into(),
+ &owned_raw_ty,
&mut is_const,
&mut is_volatile,
ref_type.unwrap_or(ReferenceType::PointerReferenceType),
@@ -1195,17 +913,18 @@ impl Type {
pub fn pointer_with_options<'a, A: Architecture, T: Into<Conf<&'a Type>>>(
arch: &A,
- t: T,
+ ty: T,
is_const: bool,
is_volatile: bool,
ref_type: Option<ReferenceType>,
) -> Ref<Self> {
- let mut is_const = Conf::new(is_const, max_confidence()).into();
- let mut is_volatile = Conf::new(is_volatile, max_confidence()).into();
+ let mut is_const = Conf::new(is_const, MAX_CONFIDENCE).into();
+ let mut is_volatile = Conf::new(is_volatile, MAX_CONFIDENCE).into();
+ let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe {
Self::ref_from_raw(BNCreatePointerType(
- arch.as_ref().0,
- &t.into().into(),
+ arch.as_ref().handle,
+ &owned_raw_ty,
&mut is_const,
&mut is_volatile,
ref_type.unwrap_or(ReferenceType::PointerReferenceType),
@@ -1213,95 +932,54 @@ impl Type {
}
}
- pub fn generate_auto_demangled_type_id<S: BnStrCompatible>(name: S) -> BnString {
- let mut name = QualifiedName::from(name);
- unsafe { BnString::from_raw(BNGenerateAutoDemangledTypeId(&mut name.0)) }
+ pub fn generate_auto_demangled_type_id<T: Into<QualifiedName>>(name: T) -> BnString {
+ let mut raw_name = QualifiedName::into_raw(name.into());
+ let type_id = unsafe { BnString::from_raw(BNGenerateAutoDemangledTypeId(&mut raw_name)) };
+ QualifiedName::free_raw(raw_name);
+ type_id
}
}
-impl fmt::Display for Type {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+impl Display for Type {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", unsafe {
BnString::from_raw(BNGetTypeString(
self.handle,
- ptr::null_mut(),
+ std::ptr::null_mut(),
BNTokenEscapingType::NoTokenEscapingType,
))
})
}
}
-lazy_static! {
- static ref TYPE_DEBUG_BV: Mutex<Option<Ref<BinaryView>>> =
- Mutex::new(BinaryView::from_data(&FileMetadata::new(), &[]).ok());
-}
-
-impl fmt::Debug for Type {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- if let Ok(lock) = TYPE_DEBUG_BV.lock() {
- if let Some(bv) = &*lock {
- let container = unsafe { BNGetAnalysisTypeContainer(bv.handle) };
-
- let printer = if f.alternate() {
- unsafe { BNGetTypePrinterByName(c"_DebugTypePrinter".as_ptr()) }
- } else {
- unsafe { BNGetTypePrinterByName(c"CoreTypePrinter".as_ptr()) }
- };
- if printer.is_null() {
- return Err(fmt::Error);
- }
-
- let mut name = QualifiedName::from("");
-
- let mut lines: *mut BNTypeDefinitionLine = null_mut();
- let mut count: usize = 0;
-
- unsafe {
- BNGetTypePrinterTypeLines(
- printer,
- self.handle,
- container,
- &mut name.0,
- 64,
- false,
- BNTokenEscapingType::NoTokenEscapingType,
- &mut lines,
- &mut count,
- )
- };
- unsafe {
- BNFreeTypeContainer(container);
- }
-
- if lines.is_null() {
- return Err(fmt::Error);
- }
-
- let line_slice: &[BNTypeDefinitionLine] =
- unsafe { slice::from_raw_parts(lines, count) };
-
- for (i, line) in line_slice.iter().enumerate() {
- if i > 0 {
- writeln!(f)?;
- }
-
- let tokens: &[BNInstructionTextToken] =
- unsafe { slice::from_raw_parts(line.tokens, line.count) };
-
- for token in tokens {
- let text: *const c_char = token.text;
- let str = unsafe { CStr::from_ptr(text) };
- write!(f, "{}", str.to_string_lossy())?;
- }
- }
-
- unsafe {
- BNFreeTypeDefinitionLineList(lines, count);
- }
- return Ok(());
- }
- }
- Err(fmt::Error)
+impl Debug for Type {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ // You might be tempted to rip this atrocity out and make this more "sensible". READ BELOW!
+ // Type is a one-size fits all structure, these are actually its fields! If we wanted to
+ // omit some fields for different type classes what you really want to do is implement your
+ // own formatter. This is supposed to represent the structure entirely, it's not supposed to be pretty!
+ f.debug_struct("Type")
+ .field("type_class", &self.type_class())
+ .field("width", &self.width())
+ .field("alignment", &self.alignment())
+ .field("is_signed", &self.is_signed())
+ .field("is_const", &self.is_const())
+ .field("is_volatile", &self.is_volatile())
+ .field("is_floating_point", &self.is_floating_point())
+ .field("child_type", &self.child_type())
+ .field("calling_convention", &self.calling_convention())
+ .field("parameters", &self.parameters())
+ .field("has_variable_arguments", &self.has_variable_arguments())
+ .field("can_return", &self.can_return())
+ .field("pure", &self.pure())
+ .field("get_structure", &self.get_structure())
+ .field("get_enumeration", &self.get_enumeration())
+ .field("get_named_type_reference", &self.get_named_type_reference())
+ .field("count", &self.count())
+ .field("offset", &self.offset())
+ .field("stack_adjustment", &self.stack_adjustment())
+ .field("registered_name", &self.registered_name())
+ .finish()
}
}
@@ -1340,286 +1018,181 @@ impl ToOwned for Type {
}
}
-pub struct ComponentReferencedTypes;
-impl CoreArrayProvider for ComponentReferencedTypes {
+impl CoreArrayProvider for Type {
+ type Raw = *mut BNType;
+ type Context = ();
+ type Wrapped<'a> = &'a Self;
+}
+
+unsafe impl CoreArrayProviderInner for Type {
+ unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
+ BNFreeTypeList(raw, count)
+ }
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
+ // TODO: This is assuming &'a Type is &*mut BNType
+ std::mem::transmute(raw)
+ }
+}
+
+// TODO: Remove this struct, or make it not a ZST with a terrible array provider.
+/// ZST used only for `Array<ComponentReferencedType>`.
+pub struct ComponentReferencedType;
+
+impl CoreArrayProvider for ComponentReferencedType {
type Raw = *mut BNType;
type Context = ();
type Wrapped<'a> = &'a Type;
}
-unsafe impl CoreArrayProviderInner for ComponentReferencedTypes {
+unsafe impl CoreArrayProviderInner for ComponentReferencedType {
unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
BNComponentFreeReferencedTypes(raw, count)
}
unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
- // SAFETY: BNType and Type are trasparent
- core::mem::transmute(raw)
+ // SAFETY: &*mut BNType == &Type (*mut BNType == Type)
+ std::mem::transmute(raw)
}
}
-///////////////////////
-// FunctionParameter
-
-#[derive(Clone, Debug)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct FunctionParameter {
- pub t: Conf<Ref<Type>>,
+ pub ty: Conf<Ref<Type>>,
pub name: String,
pub location: Option<Variable>,
}
impl FunctionParameter {
- pub fn new<T: Into<Conf<Ref<Type>>>>(t: T, name: String, location: Option<Variable>) -> Self {
- Self {
- t: t.into(),
- name,
- location,
- }
- }
-
- pub(crate) fn from_raw(member: BNFunctionParameter) -> Self {
- let name = if member.name.is_null() {
- if member.location.type_ == VariableSourceType::RegisterVariableSourceType {
- format!("reg_{}", member.location.storage)
- } else if member.location.type_ == VariableSourceType::StackVariableSourceType {
- format!("arg_{}", member.location.storage)
+ pub(crate) fn from_raw(value: &BNFunctionParameter) -> Self {
+ // TODO: I copied this from the original `from_raw` function.
+ // TODO: So this actually needs to be audited later.
+ let name = if value.name.is_null() {
+ if value.location.type_ == VariableSourceType::RegisterVariableSourceType {
+ format!("reg_{}", value.location.storage)
+ } else if value.location.type_ == VariableSourceType::StackVariableSourceType {
+ format!("arg_{}", value.location.storage)
} else {
String::new()
}
} else {
- unsafe { CStr::from_ptr(member.name) }
- .to_str()
- .unwrap()
- .to_owned()
+ raw_to_string(value.name as *const _).unwrap()
};
Self {
- t: Conf::new(
- unsafe { Type::ref_from_raw(BNNewTypeReference(member.type_)) },
- member.typeConfidence,
+ ty: Conf::new(
+ unsafe { Type::from_raw(value.type_).to_owned() },
+ value.typeConfidence,
),
name,
- location: if member.defaultLocation {
- None
- } else {
- Some(unsafe { Variable::from_raw(member.location) })
+ location: match value.defaultLocation {
+ false => Some(Variable::from(value.location)),
+ true => None,
},
}
}
-}
-
-//////////////
-// Variable
-#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
-pub struct Variable {
- pub t: VariableSourceType,
- pub index: u32,
- pub storage: i64,
-}
-
-impl Variable {
- pub fn new(t: VariableSourceType, index: u32, storage: i64) -> Self {
- Self { t, index, storage }
+ pub(crate) fn from_owned_raw(value: BNFunctionParameter) -> Self {
+ let owned = Self::from_raw(&value);
+ Self::free_raw(value);
+ owned
}
- pub(crate) unsafe fn from_raw(var: BNVariable) -> Self {
- Self {
- t: var.type_,
- index: var.index,
- storage: var.storage,
+ pub(crate) fn into_raw(value: Self) -> BNFunctionParameter {
+ let bn_name = BnString::new(value.name);
+ BNFunctionParameter {
+ name: BnString::into_raw(bn_name),
+ type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
+ typeConfidence: value.ty.confidence,
+ defaultLocation: value.location.is_none(),
+ location: value.location.map(Into::into).unwrap_or_default(),
}
}
- pub(crate) unsafe fn from_identifier(var: u64) -> Self {
- Self::from_raw(unsafe { BNFromVariableIdentifier(var) })
- }
- pub(crate) fn raw(&self) -> BNVariable {
- BNVariable {
- type_: self.t,
- index: self.index,
- storage: self.storage,
- }
+ pub(crate) fn free_raw(value: BNFunctionParameter) {
+ let _ = unsafe { BnString::from_raw(value.name) };
+ let _ = unsafe { Type::ref_from_raw(value.type_) };
}
-}
-
-impl CoreArrayProvider for Variable {
- type Raw = BNVariable;
- type Context = ();
- type Wrapped<'a> = Self;
-}
-unsafe impl CoreArrayProviderInner for Variable {
- unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
- BNFreeVariableList(raw)
- }
- unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
- Variable::from_raw(*raw)
+ pub fn new<T: Into<Conf<Ref<Type>>>>(ty: T, name: String, location: Option<Variable>) -> Self {
+ Self {
+ ty: ty.into(),
+ name,
+ location,
+ }
}
}
+// TODO: We need to delete this...
// Name, Variable and Type
impl CoreArrayProvider for (&str, Variable, &Type) {
type Raw = BNVariableNameAndType;
type Context = ();
- type Wrapped<'a> = (&'a str, Variable, &'a Type) where Self: 'a;
+ type Wrapped<'a>
+ = (&'a str, Variable, &'a Type)
+ where
+ Self: 'a;
}
+// TODO: This needs to go!
unsafe impl CoreArrayProviderInner for (&str, Variable, &Type) {
unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
BNFreeVariableNameAndTypeList(raw, count)
}
+
unsafe fn wrap_raw<'a>(
raw: &'a Self::Raw,
_context: &'a Self::Context,
) -> (&'a str, Variable, &'a Type) {
let name = CStr::from_ptr(raw.name).to_str().unwrap();
- let var = Variable::from_raw(raw.var);
- let var_type = core::mem::transmute(&raw.type_);
+ let var = Variable::from(raw.var);
+ let var_type = &*(raw.type_ as *mut Type);
(name, var, var_type)
}
}
-//////////////
-// SSAVariable
-
-#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
-pub struct SSAVariable {
- pub variable: Variable,
- pub version: usize,
-}
-
-impl SSAVariable {
- pub fn new(variable: Variable, version: usize) -> Self {
- Self { variable, version }
- }
-}
-
-impl CoreArrayProvider for SSAVariable {
- type Raw = usize;
- type Context = Variable;
- type Wrapped<'a> = Self;
-}
-
-unsafe impl CoreArrayProviderInner for SSAVariable {
- unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
- BNFreeILInstructionList(raw)
- }
-
- unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
- SSAVariable::new(*context, *raw)
- }
-}
-
-impl CoreArrayProvider for Array<SSAVariable> {
- type Raw = BNVariable;
- type Context = Ref<MediumLevelILFunction>;
- type Wrapped<'a> = Self;
-}
-
-unsafe impl CoreArrayProviderInner for Array<SSAVariable> {
- unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
- BNFreeVariableList(raw)
- }
-
- unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
- let mut count = 0;
- let versions =
- unsafe { BNGetMediumLevelILVariableSSAVersions(context.handle, raw, &mut count) };
- Array::new(versions, count, Variable::from_raw(*raw))
- }
-}
-
-///////////////
-// NamedVariable
-
-#[derive(Clone, Debug, Hash, Eq, PartialEq)]
-pub struct NamedTypedVariable {
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub struct EnumerationMember {
pub name: String,
- pub ty: Conf<Ref<Type>>,
- pub var: Variable,
- pub auto_defined: bool,
+ /// The associated constant value for the member.
+ pub value: u64,
+ /// Whether this is the default member for the associated [`Enumeration`].
+ pub default: bool,
}
-impl NamedTypedVariable {
- pub fn new(var: Variable, name: String, ty: Conf<Ref<Type>>, auto_defined: bool) -> Self {
- Self {
- name,
- ty,
- var,
- auto_defined,
- }
- }
-
- pub(crate) unsafe fn from_raw(var: &BNVariableNameAndType) -> Self {
+impl EnumerationMember {
+ pub(crate) fn from_raw(value: &BNEnumerationMember) -> Self {
Self {
- var: Variable::from_raw(var.var),
- auto_defined: var.autoDefined,
- name: CStr::from_ptr(var.name).to_str().unwrap().to_string(),
- ty: Conf::new(Type::ref_from_raw(var.type_), var.typeConfidence),
+ name: raw_to_string(value.name).unwrap(),
+ value: value.value,
+ default: value.isDefault,
}
}
- pub fn name(&self) -> &str {
- &self.name
- }
-
- pub fn var(&self) -> Variable {
- self.var
- }
-
- pub fn auto_defined(&self) -> bool {
- self.auto_defined
+ pub(crate) fn from_owned_raw(value: BNEnumerationMember) -> Self {
+ let owned = Self::from_raw(&value);
+ Self::free_raw(value);
+ owned
}
- pub fn type_confidence(&self) -> u8 {
- self.ty.confidence
- }
-
- pub fn var_type(&self) -> Ref<Type> {
- self.ty.contents.clone()
+ pub(crate) fn into_raw(value: Self) -> BNEnumerationMember {
+ let bn_name = BnString::new(value.name);
+ BNEnumerationMember {
+ name: BnString::into_raw(bn_name),
+ value: value.value,
+ isDefault: value.default,
+ }
}
-}
-
-impl CoreArrayProvider for NamedTypedVariable {
- type Raw = BNVariableNameAndType;
- type Context = ();
- type Wrapped<'a> = Guard<'a, NamedTypedVariable>;
-}
-unsafe impl CoreArrayProviderInner for NamedTypedVariable {
- unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
- BNFreeVariableNameAndTypeList(raw, count)
+ pub(crate) fn free_raw(value: BNEnumerationMember) {
+ let _ = unsafe { BnString::from_raw(value.name) };
}
- unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
- unsafe { Guard::new(NamedTypedVariable::from_raw(raw), raw) }
- }
-}
-////////////////////////
-// EnumerationBuilder
-
-#[derive(Debug, Clone)]
-pub struct EnumerationMember {
- pub name: String,
- pub value: u64,
- pub is_default: bool,
-}
-
-impl EnumerationMember {
- pub fn new(name: String, value: u64, is_default: bool) -> Self {
+ pub fn new(name: String, value: u64, default: bool) -> Self {
Self {
name,
value,
- is_default,
- }
- }
-
- pub(crate) unsafe fn from_raw(member: BNEnumerationMember) -> Self {
- Self {
- name: raw_to_string(member.name).unwrap(),
- value: member.value,
- is_default: member.isDefault,
+ default,
}
}
}
@@ -1679,16 +1252,15 @@ impl EnumerationBuilder {
pub fn members(&self) -> Vec<EnumerationMember> {
unsafe {
let mut count = 0;
- let members_raw = BNGetEnumerationBuilderMembers(self.handle, &mut count);
- let members: &[BNEnumerationMember] = slice::from_raw_parts(members_raw, count);
-
- let result = (0..count)
- .map(|i| EnumerationMember::from_raw(members[i]))
+ let members_raw_ptr = BNGetEnumerationBuilderMembers(self.handle, &mut count);
+ let members_raw: &[BNEnumerationMember] =
+ std::slice::from_raw_parts(members_raw_ptr, count);
+ let members = members_raw
+ .iter()
+ .map(EnumerationMember::from_raw)
.collect();
-
- BNFreeEnumerationMemberList(members_raw, count);
-
- result
+ BNFreeEnumerationMemberList(members_raw_ptr, count);
+ members
}
}
}
@@ -1715,9 +1287,6 @@ impl Drop for EnumerationBuilder {
}
}
-/////////////////
-// Enumeration
-
#[derive(PartialEq, Eq, Hash)]
pub struct Enumeration {
pub(crate) handle: *mut BNEnumeration,
@@ -1736,20 +1305,28 @@ impl Enumeration {
pub fn members(&self) -> Vec<EnumerationMember> {
unsafe {
let mut count = 0;
- let members_raw = BNGetEnumerationMembers(self.handle, &mut count);
- let members: &[BNEnumerationMember] = slice::from_raw_parts(members_raw, count);
-
- let result = (0..count)
- .map(|i| EnumerationMember::from_raw(members[i]))
+ let members_raw_ptr = BNGetEnumerationMembers(self.handle, &mut count);
+ debug_assert!(!members_raw_ptr.is_null());
+ let members_raw: &[BNEnumerationMember] =
+ std::slice::from_raw_parts(members_raw_ptr, count);
+ let members = members_raw
+ .iter()
+ .map(EnumerationMember::from_raw)
.collect();
-
- BNFreeEnumerationMemberList(members_raw, count);
-
- result
+ BNFreeEnumerationMemberList(members_raw_ptr, count);
+ members
}
}
}
+impl Debug for Enumeration {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("Enumeration")
+ .field("members", &self.members())
+ .finish()
+ }
+}
+
unsafe impl RefCountable for Enumeration {
unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
Self::ref_from_raw(BNNewEnumerationReference(handle.handle))
@@ -1768,11 +1345,6 @@ impl ToOwned for Enumeration {
}
}
-//////////////////////
-// StructureBuilder
-
-pub type StructureType = BNStructureVariant;
-
#[derive(PartialEq, Eq, Hash)]
pub struct StructureBuilder {
pub(crate) handle: *mut BNStructureBuilder,
@@ -1780,20 +1352,47 @@ pub struct StructureBuilder {
/// ```no_run
/// // Includes
-/// # use binaryninja::binaryview::BinaryViewExt;
-/// use binaryninja::types::{Structure, StructureBuilder, Type, MemberAccess, MemberScope};
+/// # use binaryninja::binary_view::BinaryViewExt;
+/// use binaryninja::types::{MemberAccess, MemberScope, Structure, StructureBuilder, Type};
///
-/// // Define struct, set size (in bytes)
-/// let mut my_custom_struct = StructureBuilder::new();
-/// let field_1 = Type::named_int(5, false, "my_weird_int_type");
-/// let field_2 = Type::int(4, false);
-/// let field_3 = Type::int(8, false);
+/// // Types to use in the members
+/// let field_1_ty = Type::named_int(5, false, "my_weird_int_type");
+/// let field_2_ty = Type::int(4, false);
+/// let field_3_ty = Type::int(8, false);
///
/// // Assign those fields
-/// my_custom_struct.insert(&field_1, "field_1", 0, false, MemberAccess::PublicAccess, MemberScope::NoScope);
-/// my_custom_struct.insert(&field_2, "field_2", 5, false, MemberAccess::PublicAccess, MemberScope::NoScope);
-/// my_custom_struct.insert(&field_3, "field_3", 9, false, MemberAccess::PublicAccess, MemberScope::NoScope);
-/// my_custom_struct.append(&field_1, "field_4", MemberAccess::PublicAccess, MemberScope::NoScope);
+/// let mut my_custom_struct = StructureBuilder::new();
+/// my_custom_struct
+/// .insert(
+/// &field_1_ty,
+/// "field_1",
+/// 0,
+/// false,
+/// MemberAccess::PublicAccess,
+/// MemberScope::NoScope,
+/// )
+/// .insert(
+/// &field_2_ty,
+/// "field_2",
+/// 5,
+/// false,
+/// MemberAccess::PublicAccess,
+/// MemberScope::NoScope,
+/// )
+/// .insert(
+/// &field_3_ty,
+/// "field_3",
+/// 9,
+/// false,
+/// MemberAccess::PublicAccess,
+/// MemberScope::NoScope,
+/// )
+/// .append(
+/// &field_1_ty,
+/// "field_4",
+/// MemberAccess::PublicAccess,
+/// MemberScope::NoScope,
+/// );
///
/// // Convert structure to type
/// let my_custom_structure_type = Type::structure(&my_custom_struct.finalize());
@@ -1814,99 +1413,98 @@ impl StructureBuilder {
Self { handle }
}
- // Chainable terminal
- pub fn finalize(&self) -> Ref<Structure> {
- unsafe { Structure::ref_from_raw(BNFinalizeStructureBuilder(self.handle)) }
+ // TODO: Document the width adjustment with alignment.
+ pub fn finalize(&mut self) -> Ref<Structure> {
+ let raw_struct_ptr = unsafe { BNFinalizeStructureBuilder(self.handle) };
+ unsafe { Structure::ref_from_raw(raw_struct_ptr) }
}
- // Chainable builders/setters
-
- pub fn set_width(&self, width: u64) -> &Self {
+ /// Sets the width of the [`StructureBuilder`] to the new width.
+ ///
+ /// This will remove all previously inserted members outside the new width. This is done by computing
+ /// the member access range (member offset + member width) and if it is larger than the new width
+ /// it will be removed.
+ pub fn width(&mut self, width: u64) -> &mut Self {
unsafe {
BNSetStructureBuilderWidth(self.handle, width);
}
-
self
}
- pub fn set_alignment(&self, alignment: usize) -> &Self {
+ pub fn alignment(&mut self, alignment: usize) -> &mut Self {
unsafe {
BNSetStructureBuilderAlignment(self.handle, alignment);
}
-
self
}
- pub fn set_packed(&self, packed: bool) -> &Self {
+ /// Sets whether the [`StructureBuilder`] is packed.
+ ///
+ /// If set the alignment of the structure will be `1`. You do not need to set the alignment to `1`.
+ pub fn packed(&mut self, packed: bool) -> &mut Self {
unsafe {
BNSetStructureBuilderPacked(self.handle, packed);
}
-
self
}
- pub fn set_structure_type(&self, t: StructureType) -> &Self {
+ pub fn structure_type(&mut self, t: StructureType) -> &mut Self {
unsafe { BNSetStructureBuilderType(self.handle, t) };
self
}
- pub fn set_pointer_offset(&self, offset: i64) -> &Self {
+ pub fn pointer_offset(&mut self, offset: i64) -> &mut Self {
unsafe { BNSetStructureBuilderPointerOffset(self.handle, offset) };
self
}
- pub fn set_propagates_data_var_refs(&self, does: bool) -> &Self {
- unsafe { BNSetStructureBuilderPropagatesDataVariableReferences(self.handle, does) };
+ pub fn propagates_data_var_refs(&mut self, propagates: bool) -> &mut Self {
+ unsafe { BNSetStructureBuilderPropagatesDataVariableReferences(self.handle, propagates) };
self
}
- pub fn set_base_structures(&self, bases: Vec<BaseStructure>) -> &Self {
- let mut bases_api = vec![];
- for base in &bases {
- bases_api.push(BNBaseStructure {
- type_: base.ty.handle,
- offset: base.offset,
- width: base.width,
- });
- }
-
+ pub fn base_structures(&mut self, bases: &[BaseStructure]) -> &mut Self {
+ let raw_base_structs: Vec<BNBaseStructure> =
+ bases.iter().map(BaseStructure::into_owned_raw).collect();
unsafe {
BNSetBaseStructuresForStructureBuilder(
self.handle,
- bases_api.as_mut_ptr(),
- bases_api.len(),
+ raw_base_structs.as_ptr() as *mut _,
+ raw_base_structs.len(),
)
};
-
self
}
pub fn append<'a, S: BnStrCompatible, T: Into<Conf<&'a Type>>>(
- &self,
- t: T,
+ &mut self,
+ ty: T,
name: S,
access: MemberAccess,
scope: MemberScope,
- ) -> &Self {
+ ) -> &mut Self {
let name = name.into_bytes_with_nul();
+ let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe {
BNAddStructureBuilderMember(
self.handle,
- &t.into().into(),
+ &owned_raw_ty,
name.as_ref().as_ptr() as _,
access,
scope,
);
}
-
self
}
- pub fn insert_member(&self, member: &StructureMember, overwrite_existing: bool) -> &Self {
- let ty = member.ty.clone();
+ pub fn insert_member(
+ &mut self,
+ member: StructureMember,
+ overwrite_existing: bool,
+ ) -> &mut Self {
self.insert(
- ty.as_ref(),
- member.name.clone(),
+ &member.ty,
+ member.name,
member.offset,
overwrite_existing,
member.access,
@@ -1916,19 +1514,20 @@ impl StructureBuilder {
}
pub fn insert<'a, S: BnStrCompatible, T: Into<Conf<&'a Type>>>(
- &self,
- t: T,
+ &mut self,
+ ty: T,
name: S,
offset: u64,
overwrite_existing: bool,
access: MemberAccess,
scope: MemberScope,
- ) -> &Self {
+ ) -> &mut Self {
let name = name.into_bytes_with_nul();
+ let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe {
BNAddStructureBuilderMemberAtOffset(
self.handle,
- &t.into().into(),
+ &owned_raw_ty,
name.as_ref().as_ptr() as _,
offset,
overwrite_existing,
@@ -1936,118 +1535,33 @@ impl StructureBuilder {
scope,
);
}
-
self
}
- pub fn with_members<'a, S: BnStrCompatible, T: Into<Conf<&'a Type>>>(
- &self,
- members: impl IntoIterator<Item = (T, S)>,
- ) -> &Self {
- for (t, name) in members {
- self.append(t, name, MemberAccess::NoAccess, MemberScope::NoScope);
+ pub fn replace<'a, S: BnStrCompatible, T: Into<Conf<&'a Type>>>(
+ &mut self,
+ index: usize,
+ ty: T,
+ name: S,
+ overwrite_existing: bool,
+ ) -> &mut Self {
+ let name = name.into_bytes_with_nul();
+ let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
+ unsafe {
+ BNReplaceStructureBuilderMember(
+ self.handle,
+ index,
+ &owned_raw_ty,
+ name.as_ref().as_ptr() as _,
+ overwrite_existing,
+ )
}
self
}
- // Getters
-
- pub fn width(&self) -> u64 {
- unsafe { BNGetStructureBuilderWidth(self.handle) }
- }
-
- pub fn alignment(&self) -> usize {
- unsafe { BNGetStructureBuilderAlignment(self.handle) }
- }
-
- pub fn packed(&self) -> bool {
- unsafe { BNIsStructureBuilderPacked(self.handle) }
- }
-
- pub fn structure_type(&self) -> StructureType {
- unsafe { BNGetStructureBuilderType(self.handle) }
- }
-
- pub fn pointer_offset(&self) -> i64 {
- unsafe { BNGetStructureBuilderPointerOffset(self.handle) }
- }
-
- pub fn propagates_data_var_refs(&self) -> bool {
- unsafe { BNStructureBuilderPropagatesDataVariableReferences(self.handle) }
- }
-
- pub fn base_structures(&self) -> Result<Vec<BaseStructure>> {
- let mut count = 0usize;
- let bases = unsafe { BNGetBaseStructuresForStructureBuilder(self.handle, &mut count) };
- if bases.is_null() {
- Err(())
- } else {
- let bases_slice = unsafe { slice::from_raw_parts_mut(bases, count) };
-
- let result = bases_slice
- .iter()
- .map(|base| unsafe { BaseStructure::from_raw(*base) })
- .collect::<Vec<_>>();
-
- unsafe {
- BNFreeBaseStructureList(bases, count);
- }
-
- Ok(result)
- }
- }
-
- pub fn members(&self) -> Array<StructureMember> {
- let mut count = 0;
- let members_raw = unsafe { BNGetStructureBuilderMembers(self.handle, &mut count) };
- unsafe { Array::new(members_raw, count, ()) }
- }
-
- pub fn index_by_name(&self, name: &str) -> Option<usize> {
- self.members().iter().position(|member| member.name == name)
- }
-
- pub fn index_by_offset(&self, offset: u64) -> Option<usize> {
- self.members()
- .iter()
- .position(|member| member.offset == offset)
- }
-
- // Setters
-
- pub fn clear_members(&self) {
- let len = self.members().len();
- for idx in (0..len).rev() {
- self.remove(idx)
- }
- }
-
- pub fn add_members<'a>(&self, members: impl IntoIterator<Item = &'a StructureMember>) {
- for member in members {
- self.append(&member.ty, &member.name, member.access, member.scope);
- }
- }
-
- pub fn set_members<'a>(&self, members: impl IntoIterator<Item = &'a StructureMember>) {
- self.clear_members();
- self.add_members(members);
- }
-
- pub fn remove(&self, index: usize) {
- unsafe { BNRemoveStructureBuilderMember(self.handle, index) }
- }
-
- pub fn replace(&self, index: usize, type_: Conf<&Type>, name: &str, overwrite: bool) {
- let name = name.into_bytes_with_nul();
- let name_ptr = name.as_ptr() as *const _;
-
- let raw_type_ = BNTypeWithConfidence {
- type_: type_.contents as *const Type as *mut _,
- confidence: type_.confidence,
- };
- unsafe {
- BNReplaceStructureBuilderMember(self.handle, index, &raw_type_, name_ptr, overwrite)
- }
+ pub fn remove(&mut self, index: usize) -> &mut Self {
+ unsafe { BNRemoveStructureBuilderMember(self.handle, index) };
+ self
}
}
@@ -2059,20 +1573,14 @@ impl From<&Structure> for StructureBuilder {
impl From<Vec<StructureMember>> for StructureBuilder {
fn from(members: Vec<StructureMember>) -> StructureBuilder {
- let builder = StructureBuilder::new();
- for m in members {
- builder.insert_member(&m, false);
+ let mut builder = StructureBuilder::new();
+ for member in members {
+ builder.insert_member(member, false);
}
builder
}
}
-impl Debug for StructureBuilder {
- fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
- write!(f, "StructureBuilder {{ ... }}")
- }
-}
-
impl Drop for StructureBuilder {
fn drop(&mut self) {
unsafe { BNFreeStructureBuilder(self.handle) };
@@ -2085,20 +1593,12 @@ impl Default for StructureBuilder {
}
}
-///////////////
-// Structure
-
#[derive(PartialEq, Eq, Hash)]
pub struct Structure {
pub(crate) handle: *mut BNStructure,
}
impl Structure {
- unsafe fn from_raw(handle: *mut BNStructure) -> Self {
- debug_assert!(!handle.is_null());
- Self { handle }
- }
-
pub(crate) unsafe fn ref_from_raw(handle: *mut BNStructure) -> Ref<Self> {
debug_assert!(!handle.is_null());
Ref::new(Self { handle })
@@ -2116,65 +1616,46 @@ impl Structure {
unsafe { BNGetStructureType(self.handle) }
}
- pub fn members(&self) -> Result<Vec<StructureMember>> {
+ pub fn members(&self) -> Vec<StructureMember> {
unsafe {
let mut count = 0;
- let members_raw: *mut BNStructureMember =
+ let members_raw_ptr: *mut BNStructureMember =
BNGetStructureMembers(self.handle, &mut count);
- if members_raw.is_null() {
- return Err(());
- }
- let members = slice::from_raw_parts(members_raw, count);
-
- let result = (0..count)
- .map(|i| StructureMember::from_raw(members[i]))
- .collect();
-
- BNFreeStructureMemberList(members_raw, count);
-
- Ok(result)
+ debug_assert!(!members_raw_ptr.is_null());
+ let members_raw = std::slice::from_raw_parts(members_raw_ptr, count);
+ let members = members_raw.iter().map(StructureMember::from_raw).collect();
+ BNFreeStructureMemberList(members_raw_ptr, count);
+ members
}
}
- pub fn base_structures(&self) -> Result<Vec<BaseStructure>> {
- let mut count = 0usize;
- let bases = unsafe { BNGetBaseStructuresForStructure(self.handle, &mut count) };
- if bases.is_null() {
- Err(())
- } else {
- let bases_slice = unsafe { slice::from_raw_parts_mut(bases, count) };
-
- let result = bases_slice
- .iter()
- .map(|base| unsafe { BaseStructure::from_raw(*base) })
- .collect::<Vec<_>>();
-
- unsafe {
- BNFreeBaseStructureList(bases, count);
- }
-
- Ok(result)
- }
+ pub fn base_structures(&self) -> Vec<BaseStructure> {
+ let mut count = 0;
+ let bases_raw_ptr = unsafe { BNGetBaseStructuresForStructure(self.handle, &mut count) };
+ debug_assert!(!bases_raw_ptr.is_null());
+ let bases_raw = unsafe { std::slice::from_raw_parts(bases_raw_ptr, count) };
+ let bases = bases_raw.iter().map(BaseStructure::from_raw).collect();
+ unsafe { BNFreeBaseStructureList(bases_raw_ptr, count) };
+ bases
}
// TODO : The other methods in the python version (alignment, packed, type, members, remove, replace, etc)
}
impl Debug for Structure {
- fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
- write!(f, "Structure {{")?;
- if let Ok(members) = self.members() {
- for member in members {
- write!(f, " {:?}", member)?;
- }
- }
- write!(f, "}}")
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("Structure")
+ .field("width", &self.width())
+ .field("structure_type", &self.structure_type())
+ .field("base_structures", &self.base_structures())
+ .field("members", &self.members())
+ .finish()
}
}
unsafe impl RefCountable for Structure {
unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
- Ref::new(Self::from_raw(BNNewStructureReference(handle.handle)))
+ Self::ref_from_raw(BNNewStructureReference(handle.handle))
}
unsafe fn dec_ref(handle: &Self) {
@@ -2190,9 +1671,10 @@ impl ToOwned for Structure {
}
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct StructureMember {
pub ty: Conf<Ref<Type>>,
+ // TODO: Shouldnt this be a QualifiedName? The ffi says no...
pub name: String,
pub offset: u64,
pub access: MemberAccess,
@@ -2200,6 +1682,43 @@ pub struct StructureMember {
}
impl StructureMember {
+ pub(crate) fn from_raw(value: &BNStructureMember) -> Self {
+ Self {
+ ty: Conf::new(
+ unsafe { Type::from_raw(value.type_) }.to_owned(),
+ value.typeConfidence,
+ ),
+ // TODO: I dislike using this function here.
+ name: raw_to_string(value.name as *mut _).unwrap(),
+ offset: value.offset,
+ access: value.access,
+ scope: value.scope,
+ }
+ }
+
+ pub(crate) fn from_owned_raw(value: BNStructureMember) -> Self {
+ let owned = Self::from_raw(&value);
+ Self::free_raw(value);
+ owned
+ }
+
+ pub(crate) fn into_raw(value: Self) -> BNStructureMember {
+ let bn_name = BnString::new(value.name);
+ BNStructureMember {
+ type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
+ name: BnString::into_raw(bn_name),
+ offset: value.offset,
+ typeConfidence: value.ty.confidence,
+ access: value.access,
+ scope: value.scope,
+ }
+ }
+
+ pub(crate) fn free_raw(value: BNStructureMember) {
+ let _ = unsafe { Type::ref_from_raw(value.type_) };
+ let _ = unsafe { BnString::from_raw(value.name) };
+ }
+
pub fn new(
ty: Conf<Ref<Type>>,
name: String,
@@ -2215,37 +1734,25 @@ impl StructureMember {
scope,
}
}
-
- pub(crate) unsafe fn from_raw(handle: BNStructureMember) -> Self {
- Self {
- ty: Conf::new(
- RefCountable::inc_ref(&Type::from_raw(handle.type_)),
- handle.typeConfidence,
- ),
- name: CStr::from_ptr(handle.name).to_string_lossy().to_string(),
- offset: handle.offset,
- access: handle.access,
- scope: handle.scope,
- }
- }
}
impl CoreArrayProvider for StructureMember {
type Raw = BNStructureMember;
type Context = ();
- type Wrapped<'a> = Guard<'a, StructureMember>;
+ type Wrapped<'a> = Self;
}
unsafe impl CoreArrayProviderInner for StructureMember {
unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
BNFreeStructureMemberList(raw, count)
}
+
unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
- Guard::new(StructureMember::from_raw(*raw), &())
+ Self::from_raw(raw)
}
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct InheritedStructureMember {
pub base: Ref<NamedTypeReference>,
pub base_offset: u64,
@@ -2267,18 +1774,9 @@ impl InheritedStructureMember {
member_index,
}
}
-
- // pub(crate) unsafe fn from_raw(handle: BNInheritedStructureMember) -> Self {
- // Self {
- // base: RefCountable::inc_ref(&NamedTypeReference::from_raw(handle.base)),
- // base_offset: handle.baseOffset,
- // member: StructureMember::from_raw(handle.member),
- // member_index: handle.memberIndex,
- // }
- // }
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct BaseStructure {
pub ty: Ref<NamedTypeReference>,
pub offset: u64,
@@ -2286,21 +1784,44 @@ pub struct BaseStructure {
}
impl BaseStructure {
- pub fn new(ty: Ref<NamedTypeReference>, offset: u64, width: u64) -> Self {
- Self { ty, offset, width }
+ pub(crate) fn from_raw(value: &BNBaseStructure) -> Self {
+ Self {
+ ty: unsafe { NamedTypeReference::from_raw(value.type_) }.to_owned(),
+ offset: value.offset,
+ width: value.width,
+ }
}
- pub(crate) unsafe fn from_raw(handle: BNBaseStructure) -> Self {
- Self {
- ty: RefCountable::inc_ref(&NamedTypeReference::from_raw(handle.type_)),
- offset: handle.offset,
- width: handle.width,
+ pub(crate) fn from_owned_raw(value: BNBaseStructure) -> Self {
+ let owned = Self::from_raw(&value);
+ Self::free_raw(value);
+ owned
+ }
+
+ pub(crate) fn into_raw(value: Self) -> BNBaseStructure {
+ BNBaseStructure {
+ type_: unsafe { Ref::into_raw(value.ty) }.handle,
+ offset: value.offset,
+ width: value.width,
+ }
+ }
+
+ pub(crate) fn into_owned_raw(value: &Self) -> BNBaseStructure {
+ BNBaseStructure {
+ type_: value.ty.handle,
+ offset: value.offset,
+ width: value.width,
}
}
-}
-////////////////////////
-// NamedTypeReference
+ pub(crate) fn free_raw(value: BNBaseStructure) {
+ let _ = unsafe { NamedTypeReference::ref_from_raw(value.type_) };
+ }
+
+ pub fn new(ty: Ref<NamedTypeReference>, offset: u64, width: u64) -> Self {
+ Self { ty, offset, width }
+ }
+}
#[derive(PartialEq, Eq, Hash)]
pub struct NamedTypeReference {
@@ -2310,7 +1831,6 @@ pub struct NamedTypeReference {
impl NamedTypeReference {
pub(crate) unsafe fn from_raw(handle: *mut BNNamedTypeReference) -> Self {
debug_assert!(!handle.is_null());
-
Self { handle }
}
@@ -2324,10 +1844,17 @@ impl NamedTypeReference {
/// You should not assign type ids yourself, that is the responsibility of the BinaryView
/// implementation after your types have been added. Just make sure the names match up and
/// the core will do the id stuff for you.
- pub fn new(type_class: NamedTypeReferenceClass, mut name: QualifiedName) -> Ref<Self> {
- unsafe {
- Self::ref_from_raw(BNCreateNamedType(type_class, ptr::null() as *const _, &mut name.0))
- }
+ pub fn new<T: Into<QualifiedName>>(type_class: NamedTypeReferenceClass, name: T) -> Ref<Self> {
+ let mut raw_name = QualifiedName::into_raw(name.into());
+ let result = unsafe {
+ Self::ref_from_raw(BNCreateNamedType(
+ type_class,
+ std::ptr::null(),
+ &mut raw_name,
+ ))
+ };
+ QualifiedName::free_raw(raw_name);
+ result
}
/// Create an NTR to a type with an existing type id, which generally means it came directly
@@ -2335,21 +1862,27 @@ impl NamedTypeReference {
/// You should not assign type ids yourself: if you use this to reference a type you are going
/// to create but have not yet created, you may run into problems when giving your types to
/// a BinaryView.
- pub fn new_with_id<S: BnStrCompatible>(
+ pub fn new_with_id<T: Into<QualifiedName>, S: BnStrCompatible>(
type_class: NamedTypeReferenceClass,
type_id: S,
- mut name: QualifiedName,
+ name: T,
) -> Ref<Self> {
let type_id = type_id.into_bytes_with_nul();
-
- unsafe {
- Self::ref_from_raw(BNCreateNamedType(type_class, type_id.as_ref().as_ptr() as _, &mut name.0))
- }
+ let mut raw_name = QualifiedName::into_raw(name.into());
+ let result = unsafe {
+ Self::ref_from_raw(BNCreateNamedType(
+ type_class,
+ type_id.as_ref().as_ptr() as _,
+ &mut raw_name,
+ ))
+ };
+ QualifiedName::free_raw(raw_name);
+ result
}
pub fn name(&self) -> QualifiedName {
- let named_ref: BNQualifiedName = unsafe { BNGetTypeReferenceName(self.handle) };
- QualifiedName(named_ref)
+ let raw_name = unsafe { BNGetTypeReferenceName(self.handle) };
+ QualifiedName::from_owned_raw(raw_name)
}
pub fn id(&self) -> BnString {
@@ -2361,28 +1894,26 @@ impl NamedTypeReference {
}
fn target_helper(&self, bv: &BinaryView, visited: &mut HashSet<BnString>) -> Option<Ref<Type>> {
- // TODO : This is a clippy bug (#10088, I think); remove after we upgrade past 2022-12-12
- #[allow(clippy::manual_filter)]
- if let Some(t) = bv.get_type_by_id(self.id()) {
- if t.type_class() != TypeClass::NamedTypeReferenceClass {
- Some(t)
- } else {
- let t = t.get_named_type_reference().unwrap();
- if visited.contains(&t.id()) {
- error!("Can't get target for recursively defined type!");
- None
- } else {
- visited.insert(t.id());
- t.target_helper(bv, visited)
+ let ty = bv.type_by_id(self.id())?;
+ match ty.type_class() {
+ TypeClass::NamedTypeReferenceClass => {
+ // Recurse into the NTR type until we get the target type.
+ let ntr = ty.get_named_type_reference().unwrap();
+ match visited.insert(ntr.id()) {
+ true => ntr.target_helper(bv, visited),
+ false => {
+ log::error!("Can't get target for recursively defined type!");
+ None
+ }
}
}
- } else {
- None
+ // Found target type
+ _ => Some(ty),
}
}
+ /// Type referenced by this [`NamedTypeReference`].
pub fn target(&self, bv: &BinaryView) -> Option<Ref<Type>> {
- //! Returns the type referenced by this named type reference
self.target_helper(bv, &mut HashSet::new())
}
}
@@ -2406,1375 +1937,420 @@ unsafe impl RefCountable for NamedTypeReference {
}
impl Debug for NamedTypeReference {
- fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{} (id: {})", self.name(), self.id())
}
}
-///////////////////
-// QualifiedName
-
-#[repr(transparent)]
-pub struct QualifiedName(pub(crate) BNQualifiedName);
+// TODO: Document usage, specifically how to make a qualified name and why it exists.
+#[derive(Default, Debug, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
+pub struct QualifiedName {
+ // TODO: Make this Option<String> where default is "::".
+ pub separator: String,
+ pub items: Vec<String>,
+}
impl QualifiedName {
- // TODO : I think this is bad
- pub fn string(&self) -> String {
- unsafe {
- slice::from_raw_parts(self.0.name, self.0.nameCount)
- .iter()
- .map(|c| CStr::from_ptr(*c).to_string_lossy())
- .collect::<Vec<_>>()
- .join("::")
- }
+ pub(crate) fn from_raw(value: &BNQualifiedName) -> Self {
+ // TODO: This could be improved...
+ let raw_names = unsafe { std::slice::from_raw_parts(value.name, value.nameCount) };
+ let items = raw_names
+ .iter()
+ .filter_map(|&raw_name| raw_to_string(raw_name as *const _))
+ .collect();
+ let separator = raw_to_string(value.join).unwrap();
+ Self { items, separator }
}
- pub fn join(&self) -> Cow<str> {
- let join: *mut c_char = self.0.join;
- unsafe { CStr::from_ptr(join) }.to_string_lossy()
+ pub(crate) fn from_owned_raw(value: BNQualifiedName) -> Self {
+ let result = Self::from_raw(&value);
+ Self::free_raw(value);
+ result
}
- pub fn strings(&self) -> Vec<Cow<str>> {
- let names: *mut *mut c_char = self.0.name;
- unsafe {
- slice::from_raw_parts(names, self.0.nameCount)
- .iter()
- .map(|name| CStr::from_ptr(*name).to_string_lossy())
- .collect::<Vec<_>>()
+ pub fn into_raw(value: Self) -> BNQualifiedName {
+ let bn_join = BnString::new(&value.separator);
+ BNQualifiedName {
+ // NOTE: Leaking string list must be freed by core or us!
+ name: strings_to_string_list(&value.items),
+ // NOTE: Leaking string must be freed by core or us!
+ join: BnString::into_raw(bn_join),
+ nameCount: value.items.len(),
}
}
- pub fn len(&self) -> usize {
- self.0.nameCount
- }
-
- pub fn is_empty(&self) -> bool {
- self.0.nameCount == 0
- }
-}
-
-impl<S: BnStrCompatible> From<S> for QualifiedName {
- fn from(name: S) -> Self {
- let join = BnString::new("::");
- let name = name.into_bytes_with_nul();
- let mut list = vec![name.as_ref().as_ptr() as *const _];
-
- QualifiedName(BNQualifiedName {
- name: unsafe { BNAllocStringList(list.as_mut_ptr(), 1) },
- join: join.into_raw(),
- nameCount: 1,
- })
+ pub(crate) fn free_raw(value: BNQualifiedName) {
+ unsafe { BNFreeString(value.join) };
+ unsafe { BNFreeStringList(value.name, value.nameCount) };
}
-}
-impl<S: BnStrCompatible> From<Vec<S>> for QualifiedName {
- fn from(names: Vec<S>) -> Self {
- let join = BnString::new("::");
- let names = names
- .into_iter()
- .map(|n| n.into_bytes_with_nul())
- .collect::<Vec<_>>();
- let mut list = names
- .iter()
- .map(|n| n.as_ref().as_ptr() as *const _)
- .collect::<Vec<_>>();
-
- QualifiedName(BNQualifiedName {
- name: unsafe { BNAllocStringList(list.as_mut_ptr(), list.len()) },
- join: join.into_raw(),
- nameCount: list.len(),
- })
+ pub fn new(items: Vec<String>) -> Self {
+ Self::new_with_separator(items, "::".to_string())
}
-}
-impl Clone for QualifiedName {
- fn clone(&self) -> Self {
- let strings = self.strings();
- let name = Self::from(strings.iter().collect::<Vec<&Cow<str>>>());
- name
+ pub fn new_with_separator(items: Vec<String>, separator: String) -> Self {
+ Self { items, separator }
}
-}
-impl Hash for QualifiedName {
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.join().hash(state);
- self.strings().hash(state);
+ pub fn with_item(&self, item: impl Into<String>) -> Self {
+ let mut items = self.items.clone();
+ items.push(item.into());
+ Self::new_with_separator(items, self.separator.clone())
}
-}
-impl Debug for QualifiedName {
- fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
- write!(f, "{}", self.string())
+ pub fn push(&mut self, item: String) {
+ self.items.push(item);
}
-}
-
-impl Display for QualifiedName {
- fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
- write!(f, "{}", self.string())
- }
-}
-impl PartialEq for QualifiedName {
- fn eq(&self, other: &Self) -> bool {
- self.strings() == other.strings()
+ pub fn pop(&mut self) -> Option<String> {
+ self.items.pop()
}
-}
-impl Eq for QualifiedName {}
-
-impl Drop for QualifiedName {
- fn drop(&mut self) {
- unsafe {
- BNFreeQualifiedName(&mut self.0);
+ pub fn insert(&mut self, index: usize, item: String) {
+ if index <= self.items.len() {
+ self.items.insert(index, item);
}
}
-}
-impl CoreArrayProvider for QualifiedName {
- type Raw = BNQualifiedName;
- type Context = ();
- type Wrapped<'a> = &'a QualifiedName;
-}
-unsafe impl CoreArrayProviderInner for QualifiedName {
- unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
- BNFreeTypeNameList(raw, count);
- }
- unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
- mem::transmute(raw)
- }
-}
-
-//////////////////////////
-// QualifiedNameAndType
-
-#[repr(transparent)]
-pub struct QualifiedNameAndType(pub(crate) BNQualifiedNameAndType);
-
-impl QualifiedNameAndType {
- pub fn name(&self) -> &QualifiedName {
- unsafe { mem::transmute(&self.0.name) }
- }
-
- pub fn type_object(&self) -> Guard<Type> {
- unsafe { Guard::new(Type::from_raw(self.0.type_), self) }
+ pub fn split_last(&self) -> Option<(String, QualifiedName)> {
+ self.items.split_last().map(|(a, b)| {
+ (
+ a.to_owned(),
+ QualifiedName::new_with_separator(b.to_vec(), self.separator.clone()),
+ )
+ })
}
-}
-impl Drop for QualifiedNameAndType {
- fn drop(&mut self) {
- unsafe {
- BNFreeQualifiedNameAndType(&mut self.0);
+ /// Replaces all occurrences of a substring with another string in all items of the `QualifiedName`
+ /// and returns an owned version of the modified `QualifiedName`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use binaryninja::types::QualifiedName;
+ ///
+ /// let qualified_name =
+ /// QualifiedName::new(vec!["my::namespace".to_string(), "mytype".to_string()]);
+ /// let replaced = qualified_name.replace("my", "your");
+ /// assert_eq!(
+ /// replaced.items,
+ /// vec!["your::namespace".to_string(), "yourtype".to_string()]
+ /// );
+ /// ```
+ pub fn replace(&self, from: &str, to: &str) -> Self {
+ Self {
+ items: self
+ .items
+ .iter()
+ .map(|item| item.replace(from, to))
+ .collect(),
+ separator: self.separator.clone(),
}
}
-}
-impl CoreArrayProvider for QualifiedNameAndType {
- type Raw = BNQualifiedNameAndType;
- type Context = ();
- type Wrapped<'a> = &'a QualifiedNameAndType;
-}
-unsafe impl CoreArrayProviderInner for QualifiedNameAndType {
- unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
- BNFreeTypeAndNameList(raw, count);
+ /// Returns the last item, or `None` if it is empty.
+ pub fn last(&self) -> Option<&String> {
+ self.items.last()
}
- unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
- mem::transmute(raw)
- }
-}
-
-//////////////////////////
-// QualifiedNameTypeAndId
-#[repr(transparent)]
-pub struct QualifiedNameTypeAndId(pub(crate) BNQualifiedNameTypeAndId);
-
-impl QualifiedNameTypeAndId {
- pub fn name(&self) -> &QualifiedName {
- unsafe { mem::transmute(&self.0.name) }
+ /// Returns a mutable reference to the last item, or `None` if it is empty.
+ pub fn last_mut(&mut self) -> Option<&mut String> {
+ self.items.last_mut()
}
- pub fn id(&self) -> &str {
- unsafe { CStr::from_ptr(self.0.id).to_str().unwrap() }
+ pub fn len(&self) -> usize {
+ self.items.len()
}
- pub fn type_object(&self) -> Guard<Type> {
- unsafe { Guard::new(Type::from_raw(self.0.type_), self) }
+ /// A [`QualifiedName`] is empty if it has no items.
+ ///
+ /// If you want to know if the unqualified name is empty (i.e. no characters)
+ /// you must first convert the qualified name to unqualified via the `to_string` method.
+ pub fn is_empty(&self) -> bool {
+ self.items.is_empty()
}
}
-impl Drop for QualifiedNameTypeAndId {
- fn drop(&mut self) {
- unsafe {
- BNFreeQualifiedNameTypeAndId(&mut self.0);
+impl From<String> for QualifiedName {
+ fn from(value: String) -> Self {
+ Self {
+ items: vec![value],
+ // TODO: See comment in struct def.
+ separator: String::from("::"),
}
}
}
-impl CoreArrayProvider for QualifiedNameTypeAndId {
- type Raw = BNQualifiedNameTypeAndId;
- type Context = ();
- type Wrapped<'a> = &'a QualifiedNameTypeAndId;
-}
-unsafe impl CoreArrayProviderInner for QualifiedNameTypeAndId {
- unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
- BNFreeTypeIdList(raw, count);
- }
- unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
- mem::transmute(raw)
+impl From<&str> for QualifiedName {
+ fn from(value: &str) -> Self {
+ Self::from(value.to_string())
}
}
-//////////////////////////
-// NameAndType
-
-pub struct NameAndType(pub(crate) BNNameAndType);
-
-impl NameAndType {
- pub(crate) unsafe fn from_raw(raw: &BNNameAndType) -> Self {
- Self(*raw)
+impl From<&String> for QualifiedName {
+ fn from(value: &String) -> Self {
+ Self::from(value.to_owned())
}
}
-impl NameAndType {
- pub fn new<S: BnStrCompatible>(name: S, t: &Type, confidence: u8) -> Ref<Self> {
- unsafe {
- Ref::new(Self(BNNameAndType {
- name: BNAllocString(name.into_bytes_with_nul().as_ref().as_ptr() as *mut _),
- type_: Ref::into_raw(t.to_owned()).handle,
- typeConfidence: confidence,
- }))
- }
- }
-
- pub fn name(&self) -> &str {
- let c_str = unsafe { CStr::from_ptr(self.0.name) };
- c_str.to_str().unwrap()
- }
-
- pub fn t(&self) -> &Type {
- unsafe { mem::transmute::<_, &Type>(&self.0.type_) }
- }
-
- pub fn type_with_confidence(&self) -> Conf<&Type> {
- Conf::new(self.t(), self.0.typeConfidence)
+impl From<Cow<'_, str>> for QualifiedName {
+ fn from(value: Cow<'_, str>) -> Self {
+ Self::from(value.to_string())
}
}
-impl ToOwned for NameAndType {
- type Owned = Ref<Self>;
-
- fn to_owned(&self) -> Self::Owned {
- unsafe { RefCountable::inc_ref(self) }
+impl From<Vec<String>> for QualifiedName {
+ fn from(value: Vec<String>) -> Self {
+ Self::new(value)
}
}
-unsafe impl RefCountable for NameAndType {
- unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
- Self::new(
- CStr::from_ptr(handle.0.name),
- handle.t(),
- handle.0.typeConfidence,
- )
- }
-
- unsafe fn dec_ref(handle: &Self) {
- unsafe {
- BNFreeString(handle.0.name);
- RefCountable::dec_ref(handle.t());
- }
+impl From<Vec<&str>> for QualifiedName {
+ fn from(value: Vec<&str>) -> Self {
+ value
+ .iter()
+ .map(ToString::to_string)
+ .collect::<Vec<_>>()
+ .into()
}
}
-impl CoreArrayProvider for NameAndType {
- type Raw = BNNameAndType;
- type Context = ();
- type Wrapped<'a> = Guard<'a, NameAndType>;
-}
-
-unsafe impl CoreArrayProviderInner for NameAndType {
- unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
- BNFreeNameAndTypeList(raw, count);
- }
- unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
- unsafe { Guard::new(NameAndType::from_raw(raw), raw) }
+impl From<QualifiedName> for String {
+ fn from(value: QualifiedName) -> Self {
+ value.to_string()
}
}
-//////////////////
-// DataVariable
-
-#[repr(transparent)]
-pub struct DataVariable(pub(crate) BNDataVariable);
-
-// impl DataVariable {
-// pub(crate) fn from_raw(var: &BNDataVariable) -> Self {
-// let var = DataVariable(*var);
-// Self(BNDataVariable {
-// type_: unsafe { Ref::into_raw(var.t().to_owned()).handle },
-// ..var.0
-// })
-// }
-// }
-
-impl DataVariable {
- pub fn address(&self) -> u64 {
- self.0.address
- }
-
- pub fn auto_discovered(&self) -> bool {
- self.0.autoDiscovered
- }
-
- pub fn t(&self) -> &Type {
- unsafe { mem::transmute(&self.0.type_) }
- }
-
- pub fn type_with_confidence(&self) -> Conf<&Type> {
- Conf::new(self.t(), self.0.typeConfidence)
- }
+impl Index<usize> for QualifiedName {
+ type Output = String;
- pub fn symbol(&self, bv: &BinaryView) -> Option<Ref<Symbol>> {
- bv.symbol_by_address(self.0.address).ok()
+ fn index(&self, index: usize) -> &Self::Output {
+ &self.items[index]
}
}
-impl ToOwned for DataVariable {
- type Owned = Ref<Self>;
-
- fn to_owned(&self) -> Self::Owned {
- unsafe { RefCountable::inc_ref(self) }
+impl IndexMut<usize> for QualifiedName {
+ fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+ &mut self.items[index]
}
}
-unsafe impl RefCountable for DataVariable {
- unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
- unsafe {
- Ref::new(Self(BNDataVariable {
- type_: Ref::into_raw(handle.t().to_owned()).handle,
- ..handle.0
- }))
- }
- }
-
- unsafe fn dec_ref(handle: &Self) {
- unsafe { BNFreeType(handle.0.type_) }
+impl Display for QualifiedName {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", self.items.join(&self.separator))
}
}
-impl CoreArrayProvider for DataVariable {
- type Raw = BNDataVariable;
+impl CoreArrayProvider for QualifiedName {
+ type Raw = BNQualifiedName;
type Context = ();
- type Wrapped<'a> = &'a DataVariable;
+ type Wrapped<'a> = Self;
}
-unsafe impl CoreArrayProviderInner for DataVariable {
+
+unsafe impl CoreArrayProviderInner for QualifiedName {
unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
- BNFreeDataVariables(raw, count);
+ BNFreeTypeNameList(raw, count);
}
+
unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
- mem::transmute(raw)
+ QualifiedName::from_raw(raw)
}
}
-/////////////////////////
-// DataVariableAndName
-
-pub struct DataVariableAndName<S: BnStrCompatible> {
- pub address: u64,
- pub t: Conf<Ref<Type>>,
- pub auto_discovered: bool,
- pub name: S,
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub struct QualifiedNameAndType {
+ pub name: QualifiedName,
+ pub ty: Ref<Type>,
}
-impl DataVariableAndName<String> {
- pub(crate) fn from_raw(var: &BNDataVariableAndName) -> Self {
- Self {
- address: var.address,
- t: Conf::new(unsafe { Type::ref_from_raw(var.type_) }, var.typeConfidence),
- auto_discovered: var.autoDiscovered,
- name: raw_to_string(var.name).unwrap(),
- }
- }
-}
-
-impl<S: BnStrCompatible> DataVariableAndName<S> {
- pub fn new(address: u64, t: Conf<Ref<Type>>, auto_discovered: bool, name: S) -> Self {
+impl QualifiedNameAndType {
+ pub(crate) fn from_raw(value: &BNQualifiedNameAndType) -> Self {
Self {
- address,
- t,
- auto_discovered,
- name,
+ name: QualifiedName::from_raw(&value.name),
+ ty: unsafe { Type::from_raw(value.type_).to_owned() },
}
}
- pub fn type_with_confidence(&self) -> Conf<Ref<Type>> {
- Conf::new(self.t.contents.clone(), self.t.confidence)
- }
-}
-
-/////////////////////////
-// RegisterValueType
-
-#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
-pub enum RegisterValueType {
- UndeterminedValue,
- EntryValue,
- ConstantValue,
- ConstantPointerValue,
- ExternalPointerValue,
- StackFrameOffset,
- ReturnAddressValue,
- ImportedAddressValue,
- SignedRangeValue,
- UnsignedRangeValue,
- LookupTableValue,
- InSetOfValues,
- NotInSetOfValues,
- ConstantDataValue,
- ConstantDataZeroExtendValue,
- ConstantDataSignExtendValue,
- ConstantDataAggregateValue,
-}
-
-impl RegisterValueType {
- pub(crate) fn from_raw_value(value: u32) -> Option<Self> {
- use BNRegisterValueType::*;
- Some(match value {
- x if x == UndeterminedValue as u32 => Self::UndeterminedValue,
- x if x == EntryValue as u32 => Self::EntryValue,
- x if x == ConstantValue as u32 => Self::ConstantValue,
- x if x == ConstantPointerValue as u32 => Self::ConstantPointerValue,
- x if x == ExternalPointerValue as u32 => Self::ExternalPointerValue,
- x if x == StackFrameOffset as u32 => Self::StackFrameOffset,
- x if x == ReturnAddressValue as u32 => Self::ReturnAddressValue,
- x if x == ImportedAddressValue as u32 => Self::ImportedAddressValue,
- x if x == SignedRangeValue as u32 => Self::SignedRangeValue,
- x if x == UnsignedRangeValue as u32 => Self::UnsignedRangeValue,
- x if x == LookupTableValue as u32 => Self::LookupTableValue,
- x if x == InSetOfValues as u32 => Self::InSetOfValues,
- x if x == NotInSetOfValues as u32 => Self::NotInSetOfValues,
- x if x == ConstantDataValue as u32 => Self::ConstantDataValue,
- x if x == ConstantDataZeroExtendValue as u32 => Self::ConstantDataZeroExtendValue,
- x if x == ConstantDataSignExtendValue as u32 => Self::ConstantDataSignExtendValue,
- x if x == ConstantDataAggregateValue as u32 => Self::ConstantDataAggregateValue,
- _ => return None,
- })
+ pub(crate) fn from_owned_raw(value: BNQualifiedNameAndType) -> Self {
+ let owned = Self::from_raw(&value);
+ Self::free_raw(value);
+ owned
}
- pub(crate) fn into_raw_value(self) -> BNRegisterValueType {
- use BNRegisterValueType::*;
- match self {
- Self::UndeterminedValue => UndeterminedValue,
- Self::EntryValue => EntryValue,
- Self::ConstantValue => ConstantValue,
- Self::ConstantPointerValue => ConstantPointerValue,
- Self::ExternalPointerValue => ExternalPointerValue,
- Self::StackFrameOffset => StackFrameOffset,
- Self::ReturnAddressValue => ReturnAddressValue,
- Self::ImportedAddressValue => ImportedAddressValue,
- Self::SignedRangeValue => SignedRangeValue,
- Self::UnsignedRangeValue => UnsignedRangeValue,
- Self::LookupTableValue => LookupTableValue,
- Self::InSetOfValues => InSetOfValues,
- Self::NotInSetOfValues => NotInSetOfValues,
- Self::ConstantDataValue => ConstantDataValue,
- Self::ConstantDataZeroExtendValue => ConstantDataZeroExtendValue,
- Self::ConstantDataSignExtendValue => ConstantDataSignExtendValue,
- Self::ConstantDataAggregateValue => ConstantDataAggregateValue,
+ pub(crate) fn into_raw(value: Self) -> BNQualifiedNameAndType {
+ BNQualifiedNameAndType {
+ name: QualifiedName::into_raw(value.name),
+ type_: unsafe { Ref::into_raw(value.ty).handle },
}
}
-}
-/////////////////////////
-// RegisterValue
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct RegisterValue {
- pub(crate) state: RegisterValueType,
- pub(crate) value: i64,
- pub(crate) offset: i64,
- pub(crate) size: usize,
-}
-
-impl RegisterValue {
- pub fn new(state: RegisterValueType, value: i64, offset: i64, size: usize) -> Self {
- Self {
- state,
- value,
- offset,
- size,
- }
+ pub(crate) fn free_raw(value: BNQualifiedNameAndType) {
+ QualifiedName::free_raw(value.name);
+ let _ = unsafe { Type::ref_from_raw(value.type_) };
}
-}
-impl From<BNRegisterValue> for RegisterValue {
- fn from(value: BNRegisterValue) -> Self {
- Self {
- state: RegisterValueType::from_raw_value(value.state as u32).unwrap(),
- value: value.value,
- offset: value.offset,
- size: value.size,
- }
+ pub fn new(name: QualifiedName, ty: Ref<Type>) -> Self {
+ Self { name, ty }
}
}
-impl From<RegisterValue> for BNRegisterValue {
- fn from(value: RegisterValue) -> Self {
+impl<T> From<(T, Ref<Type>)> for QualifiedNameAndType
+where
+ T: Into<QualifiedName>,
+{
+ fn from(value: (T, Ref<Type>)) -> Self {
Self {
- state: value.state.into_raw_value(),
- value: value.value,
- offset: value.offset,
- size: value.size,
+ name: value.0.into(),
+ ty: value.1,
}
}
}
-/////////////////////////
-// ConstantData
-
-#[derive(Clone, Debug, PartialEq, Hash)]
-pub struct ConstantData {
- function: Ref<Function>,
- value: RegisterValue,
-}
-
-impl ConstantData {
- pub(crate) fn new(function: Ref<Function>, value: RegisterValue) -> Self {
- Self { function, value }
- }
-}
-
-// unsafe impl<S: BnStrCompatible> CoreArrayProvider for DataVariableAndName<S> {
-// type Raw = BNDataVariableAndName;
-// type Context = ();
-// }
-
-// unsafe impl<S: BnStrCompatible> CoreOwnedArrayProvider for DataVariableAndName<S> {
-// unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
-// BNFreeDataVariablesAndName(raw, count);
-// }
-// }
-
-// unsafe impl<'a, S: 'a + BnStrCompatible> CoreArrayWrapper<'a> for DataVariableAndName<S> {
-// type Wrapped = &'a DataVariableAndName<S>;
-// }
-
-// unsafe impl<'a, S: 'a + BnStrCompatible> CoreArrayWrapper<'a> for DataVariableAndName<S> {
-// unsafe fn wrap_raw(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped {
-// mem::transmute(raw)
-// }
-// }
-
-/////////////////////////
-// ValueRange
-
-#[repr(transparent)]
-#[derive(Copy, Clone, Debug)]
-pub struct ValueRange<T> {
- raw: BNValueRange,
- _t: core::marker::PhantomData<T>,
-}
-
-impl<T> ValueRange<T> {
- fn from_raw(value: BNValueRange) -> Self {
+impl<T> From<(T, &Type)> for QualifiedNameAndType
+where
+ T: Into<QualifiedName>,
+{
+ fn from(value: (T, &Type)) -> Self {
+ let ty = value.1.to_owned();
Self {
- raw: value,
- _t: core::marker::PhantomData,
+ name: value.0.into(),
+ ty,
}
}
- fn into_raw(self) -> BNValueRange {
- self.raw
- }
-}
-
-impl IntoIterator for ValueRange<u64> {
- type Item = u64;
- type IntoIter = core::iter::StepBy<Range<u64>>;
-
- fn into_iter(self) -> Self::IntoIter {
- (self.raw.start..self.raw.end).step_by(self.raw.step.try_into().unwrap())
- }
}
-impl IntoIterator for ValueRange<i64> {
- type Item = i64;
- type IntoIter = core::iter::StepBy<Range<i64>>;
- fn into_iter(self) -> Self::IntoIter {
- (self.raw.start as i64..self.raw.end as i64).step_by(self.raw.step.try_into().unwrap())
- }
-}
-
-/////////////////////////
-// PossibleValueSet
-
-#[derive(Clone, Debug)]
-pub enum PossibleValueSet {
- UndeterminedValue,
- EntryValue {
- reg: i64,
- },
- ConstantValue {
- value: i64,
- },
- ConstantPointerValue {
- value: i64,
- },
- ExternalPointerValue,
- StackFrameOffset {
- offset: i64,
- },
- ReturnAddressValue,
- ImportedAddressValue,
- SignedRangeValue {
- offset: i64,
- ranges: Vec<ValueRange<i64>>,
- },
- UnsignedRangeValue {
- offset: i64,
- ranges: Vec<ValueRange<u64>>,
- },
- LookupTableValue {
- tables: Vec<LookupTableEntry>,
- },
- InSetOfValues {
- values: HashSet<i64>,
- },
- NotInSetOfValues {
- values: HashSet<i64>,
- },
- ConstantDataValue {
- value_type: ConstantDataType,
- value: i64,
- },
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum ConstantDataType {
- Value,
- ZeroExtend,
- SignExtend,
- Aggregate,
+impl CoreArrayProvider for QualifiedNameAndType {
+ type Raw = BNQualifiedNameAndType;
+ type Context = ();
+ type Wrapped<'a> = Self;
}
-impl PossibleValueSet {
- pub(crate) unsafe fn from_raw(value: BNPossibleValueSet) -> Self {
- unsafe fn from_range<T>(value: BNPossibleValueSet) -> Vec<ValueRange<T>> {
- core::slice::from_raw_parts(value.ranges, value.count)
- .iter()
- .copied()
- .map(|range| ValueRange::from_raw(range))
- .collect()
- }
- let from_sets = |value: BNPossibleValueSet| {
- unsafe { core::slice::from_raw_parts(value.valueSet, value.count) }
- .iter()
- .copied()
- .collect()
- };
- use BNRegisterValueType::*;
- match value.state {
- UndeterminedValue => Self::UndeterminedValue,
- EntryValue => Self::EntryValue { reg: value.value },
- ConstantValue => Self::ConstantValue { value: value.value },
- ConstantPointerValue => Self::ConstantPointerValue { value: value.value },
- StackFrameOffset => Self::StackFrameOffset {
- offset: value.value,
- },
- ConstantDataValue => Self::ConstantDataValue {
- value_type: ConstantDataType::Value,
- value: value.value,
- },
- ConstantDataZeroExtendValue => Self::ConstantDataValue {
- value_type: ConstantDataType::ZeroExtend,
- value: value.value,
- },
- ConstantDataSignExtendValue => Self::ConstantDataValue {
- value_type: ConstantDataType::SignExtend,
- value: value.value,
- },
- ConstantDataAggregateValue => Self::ConstantDataValue {
- value_type: ConstantDataType::Aggregate,
- value: value.value,
- },
- SignedRangeValue => Self::SignedRangeValue {
- offset: value.value,
- ranges: from_range(value),
- },
- UnsignedRangeValue => Self::UnsignedRangeValue {
- offset: value.value,
- ranges: from_range(value),
- },
- LookupTableValue => {
- let raw_tables = unsafe { core::slice::from_raw_parts(value.table, value.count) };
- let raw_from_tables = |i: &BNLookupTableEntry| unsafe {
- core::slice::from_raw_parts(i.fromValues, i.fromCount)
- };
- let tables = raw_tables
- .iter()
- .map(|table| LookupTableEntry {
- from_values: raw_from_tables(table).to_vec(),
- to_value: table.toValue,
- })
- .collect();
- Self::LookupTableValue { tables }
- }
- NotInSetOfValues => Self::NotInSetOfValues {
- values: from_sets(value),
- },
- InSetOfValues => Self::InSetOfValues {
- values: from_sets(value),
- },
- ImportedAddressValue => Self::ImportedAddressValue,
- ReturnAddressValue => Self::ReturnAddressValue,
- ExternalPointerValue => Self::ExternalPointerValue,
- }
- }
- pub(crate) fn into_raw(self) -> PossibleValueSetRaw {
- let mut raw: BNPossibleValueSet = unsafe { core::mem::zeroed() };
- // set the state field
- raw.state = self.value_type().into_raw_value();
- // set all other fields
- match self {
- PossibleValueSet::UndeterminedValue
- | PossibleValueSet::ExternalPointerValue
- | PossibleValueSet::ReturnAddressValue
- | PossibleValueSet::ImportedAddressValue => {}
- PossibleValueSet::EntryValue { reg: value }
- | PossibleValueSet::ConstantValue { value }
- | PossibleValueSet::ConstantPointerValue { value }
- | PossibleValueSet::ConstantDataValue { value, .. }
- | PossibleValueSet::StackFrameOffset { offset: value } => raw.value = value,
- PossibleValueSet::NotInSetOfValues { values }
- | PossibleValueSet::InSetOfValues { values } => {
- let values = Box::leak(values.into_iter().collect());
- raw.valueSet = values.as_mut_ptr();
- raw.count = values.len();
- }
- PossibleValueSet::SignedRangeValue { offset, ranges } => {
- let ranges = Box::leak(ranges.into_iter().map(|x| x.into_raw()).collect());
- raw.value = offset;
- raw.ranges = ranges.as_mut_ptr();
- raw.count = ranges.len();
- }
- PossibleValueSet::UnsignedRangeValue { offset, ranges } => {
- let ranges = Box::leak(ranges.into_iter().map(|x| x.into_raw()).collect());
- raw.value = offset;
- raw.ranges = ranges.as_mut_ptr();
- raw.count = ranges.len();
- }
- PossibleValueSet::LookupTableValue { tables } => {
- let tables = Box::leak(tables.into_iter().map(|table| table.into_raw()).collect());
- // SAFETY: BNLookupTableEntry and LookupTableEntryRaw are transparent
- raw.table = tables.as_mut_ptr() as *mut BNLookupTableEntry;
- raw.count = tables.len();
- }
- }
- PossibleValueSetRaw(raw)
+unsafe impl CoreArrayProviderInner for QualifiedNameAndType {
+ unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
+ BNFreeTypeAndNameList(raw, count);
}
- pub fn value_type(&self) -> RegisterValueType {
- use RegisterValueType::*;
- match self {
- PossibleValueSet::UndeterminedValue => UndeterminedValue,
- PossibleValueSet::EntryValue { .. } => EntryValue,
- PossibleValueSet::ConstantValue { .. } => ConstantValue,
- PossibleValueSet::ConstantPointerValue { .. } => ConstantPointerValue,
- PossibleValueSet::ExternalPointerValue => ExternalPointerValue,
- PossibleValueSet::StackFrameOffset { .. } => StackFrameOffset,
- PossibleValueSet::ReturnAddressValue => ReturnAddressValue,
- PossibleValueSet::ImportedAddressValue => ImportedAddressValue,
- PossibleValueSet::SignedRangeValue { .. } => SignedRangeValue,
- PossibleValueSet::UnsignedRangeValue { .. } => UnsignedRangeValue,
- PossibleValueSet::LookupTableValue { .. } => LookupTableValue,
- PossibleValueSet::InSetOfValues { .. } => InSetOfValues,
- PossibleValueSet::NotInSetOfValues { .. } => NotInSetOfValues,
- PossibleValueSet::ConstantDataValue {
- value_type: ConstantDataType::Value,
- ..
- } => ConstantDataValue,
- PossibleValueSet::ConstantDataValue {
- value_type: ConstantDataType::ZeroExtend,
- ..
- } => ConstantDataZeroExtendValue,
- PossibleValueSet::ConstantDataValue {
- value_type: ConstantDataType::SignExtend,
- ..
- } => ConstantDataSignExtendValue,
- PossibleValueSet::ConstantDataValue {
- value_type: ConstantDataType::Aggregate,
- ..
- } => ConstantDataAggregateValue,
- }
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
+ QualifiedNameAndType::from_raw(raw)
}
}
-/// The owned version of the BNPossibleValueSet
-#[repr(transparent)]
-pub(crate) struct PossibleValueSetRaw(BNPossibleValueSet);
-
-impl PossibleValueSetRaw {
- pub fn as_ffi(&self) -> &BNPossibleValueSet {
- &self.0
- }
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub struct QualifiedNameTypeAndId {
+ pub name: QualifiedName,
+ pub ty: Ref<Type>,
+ pub id: String,
}
-impl Drop for PossibleValueSetRaw {
- fn drop(&mut self) {
- use BNRegisterValueType::*;
- match self.0.state {
- UndeterminedValue
- | ExternalPointerValue
- | ReturnAddressValue
- | ImportedAddressValue
- | EntryValue
- | ConstantValue
- | ConstantPointerValue
- | StackFrameOffset
- | ConstantDataValue
- | ConstantDataZeroExtendValue
- | ConstantDataSignExtendValue
- | ConstantDataAggregateValue => {}
- InSetOfValues | NotInSetOfValues => {
- let _values: Box<[i64]> = unsafe {
- Box::from_raw(ptr::slice_from_raw_parts_mut(self.0.valueSet, self.0.count))
- };
- }
- SignedRangeValue | UnsignedRangeValue => {
- let _ranges: Box<[BNValueRange]> = unsafe {
- Box::from_raw(ptr::slice_from_raw_parts_mut(self.0.ranges, self.0.count))
- };
- }
- LookupTableValue => {
- // SAFETY: LookupTableEntryRaw and BNLookupTableEntry can be safely transmuted
- let table_ptr = self.0.table as *mut LookupTableEntryRaw;
- let _table: Box<[LookupTableEntryRaw]> = unsafe {
- Box::from_raw(ptr::slice_from_raw_parts_mut(table_ptr, self.0.count))
- };
- }
+impl QualifiedNameTypeAndId {
+ pub(crate) fn from_raw(value: &BNQualifiedNameTypeAndId) -> Self {
+ Self {
+ name: QualifiedName::from_raw(&value.name),
+ ty: unsafe { Type::from_raw(value.type_) }.to_owned(),
+ id: raw_to_string(value.id).unwrap(),
}
}
-}
-
-/////////////////////////
-// LookupTableEntry
-#[derive(Clone, Debug)]
-pub struct LookupTableEntry {
- pub from_values: Vec<i64>,
- pub to_value: i64,
-}
-
-impl LookupTableEntry {
- fn into_raw(self) -> LookupTableEntryRaw {
- let from_value = Box::leak(self.from_values.into_boxed_slice());
- LookupTableEntryRaw(BNLookupTableEntry {
- toValue: self.to_value,
- fromValues: from_value.as_mut_ptr(),
- fromCount: from_value.len(),
- })
+ pub(crate) fn from_owned_raw(value: BNQualifiedNameTypeAndId) -> Self {
+ let owned = Self::from_raw(&value);
+ Self::free_raw(value);
+ owned
}
-}
-/// The owned version of the BNLookupTableEntry
-#[repr(transparent)]
-struct LookupTableEntryRaw(BNLookupTableEntry);
-impl Drop for LookupTableEntryRaw {
- fn drop(&mut self) {
- let _from_value: Box<[i64]> = unsafe {
- Box::from_raw(ptr::slice_from_raw_parts_mut(
- self.0.fromValues,
- self.0.fromCount,
- ))
- };
- }
-}
-
-/////////////////////////
-// ArchAndAddr
-
-#[derive(Copy, Clone, Eq, Hash, PartialEq)]
-pub struct ArchAndAddr {
- pub arch: CoreArchitecture,
- pub address: u64,
-}
-
-/////////////////////////
-// UserVariableValues
-
-pub struct UserVariableValues {
- pub(crate) vars: *const [BNUserVariableValue],
-}
-
-impl UserVariableValues {
- pub fn into_hashmap(self) -> HashMap<Variable, HashMap<ArchAndAddr, PossibleValueSet>> {
- let mut result: HashMap<Variable, HashMap<ArchAndAddr, PossibleValueSet>> = HashMap::new();
- for (var, def_site, possible_val) in self.all() {
- result
- .entry(var)
- .or_default()
- .entry(def_site)
- .or_insert(possible_val);
+ pub(crate) fn into_raw(value: Self) -> BNQualifiedNameTypeAndId {
+ let bn_id = BnString::new(value.id);
+ BNQualifiedNameTypeAndId {
+ name: QualifiedName::into_raw(value.name),
+ id: BnString::into_raw(bn_id),
+ type_: unsafe { Ref::into_raw(value.ty) }.handle,
}
- result
- }
- pub fn all(&self) -> impl Iterator<Item = (Variable, ArchAndAddr, PossibleValueSet)> {
- unsafe { &*self.vars }.iter().map(|var_val| {
- let var = unsafe { Variable::from_raw(var_val.var) };
- let def_site = ArchAndAddr {
- arch: unsafe { CoreArchitecture::from_raw(var_val.defSite.arch) },
- address: var_val.defSite.address,
- };
- let possible_val = unsafe { PossibleValueSet::from_raw(var_val.value) };
- (var, def_site, possible_val)
- })
- }
- pub fn values_from_variable(
- &self,
- var: Variable,
- ) -> impl Iterator<Item = (ArchAndAddr, PossibleValueSet)> {
- self.all()
- .filter(move |(t_var, _, _)| t_var == &var)
- .map(|(_var, def_site, possible_val)| (def_site, possible_val))
- }
-}
-
-impl Drop for UserVariableValues {
- fn drop(&mut self) {
- unsafe { BNFreeUserVariableValues(self.vars as *mut BNUserVariableValue) };
}
-}
-
-/////////////////////////
-// ConstantReference
-#[derive(Copy, Clone, Eq, Hash, PartialEq)]
-pub struct ConstantReference {
- pub value: i64,
- pub size: usize,
- pub pointer: bool,
- pub intermediate: bool,
-}
-
-impl ConstantReference {
- pub fn from_raw(value: BNConstantReference) -> Self {
- Self {
- value: value.value,
- size: value.size,
- pointer: value.pointer,
- intermediate: value.intermediate,
- }
- }
- pub fn into_raw(self) -> BNConstantReference {
- BNConstantReference {
- value: self.value,
- size: self.size,
- pointer: self.pointer,
- intermediate: self.intermediate,
- }
+ pub(crate) fn free_raw(value: BNQualifiedNameTypeAndId) {
+ QualifiedName::free_raw(value.name);
+ let _ = unsafe { Type::ref_from_raw(value.type_) };
+ let _ = unsafe { BnString::from_raw(value.id) };
}
}
-impl CoreArrayProvider for ConstantReference {
- type Raw = BNConstantReference;
+impl CoreArrayProvider for QualifiedNameTypeAndId {
+ type Raw = BNQualifiedNameTypeAndId;
type Context = ();
- type Wrapped<'a> = Self;
+ type Wrapped<'a> = QualifiedNameTypeAndId;
}
-unsafe impl CoreArrayProviderInner for ConstantReference {
- unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
- BNFreeConstantReferenceList(raw)
+unsafe impl CoreArrayProviderInner for QualifiedNameTypeAndId {
+ unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
+ BNFreeTypeIdList(raw, count);
}
+
unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
- Self::from_raw(*raw)
+ QualifiedNameTypeAndId::from_raw(raw)
}
}
-/////////////////////////
-// IndirectBranchInfo
-
-pub struct IndirectBranchInfo {
- pub source_arch: CoreArchitecture,
- pub source_addr: u64,
- pub dest_arch: CoreArchitecture,
- pub dest_addr: u64,
- pub auto_defined: bool,
+// TODO: Document how this type is used for many different purposes. (this is literally (string, type))
+// TODO: Ex. the name might be the parser it came from
+// TODO: Ex. the name might be the param name for an intrinsic input
+// TODO: Should we make new types for each varying use case?
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+pub struct NameAndType {
+ pub name: String,
+ pub ty: Conf<Ref<Type>>,
}
-impl IndirectBranchInfo {
- pub fn from_raw(value: BNIndirectBranchInfo) -> Self {
+impl NameAndType {
+ pub(crate) fn from_raw(value: &BNNameAndType) -> Self {
Self {
- source_arch: unsafe { CoreArchitecture::from_raw(value.sourceArch) },
- source_addr: value.sourceAddr,
- dest_arch: unsafe { CoreArchitecture::from_raw(value.destArch) },
- dest_addr: value.destAddr,
- auto_defined: value.autoDefined,
- }
- }
- pub fn into_raw(self) -> BNIndirectBranchInfo {
- BNIndirectBranchInfo {
- sourceArch: self.source_arch.0,
- sourceAddr: self.source_addr,
- destArch: self.dest_arch.0,
- destAddr: self.dest_addr,
- autoDefined: self.auto_defined,
+ // TODO: I dislike using this function here.
+ name: raw_to_string(value.name as *mut _).unwrap(),
+ ty: Conf::new(
+ unsafe { Type::from_raw(value.type_).to_owned() },
+ value.typeConfidence,
+ ),
}
}
-}
-impl CoreArrayProvider for IndirectBranchInfo {
- type Raw = BNIndirectBranchInfo;
- type Context = ();
- type Wrapped<'a> = Self;
-}
-
-unsafe impl CoreArrayProviderInner for IndirectBranchInfo {
- unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
- BNFreeIndirectBranchList(raw)
- }
- unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
- Self::from_raw(*raw)
+ pub(crate) fn from_owned_raw(value: BNNameAndType) -> Self {
+ let owned = Self::from_raw(&value);
+ Self::free_raw(value);
+ owned
}
-}
-
-/////////////////////////
-// HighlightStandardColor
-
-#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
-pub enum HighlightStandardColor {
- //NoHighlightColor,
- BlueHighlightColor,
- GreenHighlightColor,
- CyanHighlightColor,
- RedHighlightColor,
- MagentaHighlightColor,
- YellowHighlightColor,
- OrangeHighlightColor,
- WhiteHighlightColor,
- BlackHighlightColor,
-}
-impl HighlightStandardColor {
- pub fn from_raw(value: BNHighlightStandardColor) -> Option<Self> {
- Some(match value {
- BNHighlightStandardColor::NoHighlightColor => return None,
- BNHighlightStandardColor::BlueHighlightColor => Self::BlueHighlightColor,
- BNHighlightStandardColor::GreenHighlightColor => Self::GreenHighlightColor,
- BNHighlightStandardColor::CyanHighlightColor => Self::CyanHighlightColor,
- BNHighlightStandardColor::RedHighlightColor => Self::RedHighlightColor,
- BNHighlightStandardColor::MagentaHighlightColor => Self::MagentaHighlightColor,
- BNHighlightStandardColor::YellowHighlightColor => Self::YellowHighlightColor,
- BNHighlightStandardColor::OrangeHighlightColor => Self::OrangeHighlightColor,
- BNHighlightStandardColor::WhiteHighlightColor => Self::WhiteHighlightColor,
- BNHighlightStandardColor::BlackHighlightColor => Self::BlackHighlightColor,
- })
- }
- pub fn into_raw(self) -> BNHighlightStandardColor {
- match self {
- //Self::NoHighlightColor => BNHighlightStandardColor::NoHighlightColor,
- Self::BlueHighlightColor => BNHighlightStandardColor::BlueHighlightColor,
- Self::GreenHighlightColor => BNHighlightStandardColor::GreenHighlightColor,
- Self::CyanHighlightColor => BNHighlightStandardColor::CyanHighlightColor,
- Self::RedHighlightColor => BNHighlightStandardColor::RedHighlightColor,
- Self::MagentaHighlightColor => BNHighlightStandardColor::MagentaHighlightColor,
- Self::YellowHighlightColor => BNHighlightStandardColor::YellowHighlightColor,
- Self::OrangeHighlightColor => BNHighlightStandardColor::OrangeHighlightColor,
- Self::WhiteHighlightColor => BNHighlightStandardColor::WhiteHighlightColor,
- Self::BlackHighlightColor => BNHighlightStandardColor::BlackHighlightColor,
+ pub(crate) fn into_raw(value: Self) -> BNNameAndType {
+ let bn_name = BnString::new(value.name);
+ BNNameAndType {
+ name: BnString::into_raw(bn_name),
+ type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
+ typeConfidence: value.ty.confidence,
}
}
-}
-
-/////////////////////////
-// HighlightColor
-
-#[derive(Debug, Copy, Clone)]
-pub enum HighlightColor {
- NoHighlightColor {
- alpha: u8,
- },
- StandardHighlightColor {
- color: HighlightStandardColor,
- alpha: u8,
- },
- MixedHighlightColor {
- color: HighlightStandardColor,
- mix_color: HighlightStandardColor,
- mix: u8,
- alpha: u8,
- },
- CustomHighlightColor {
- r: u8,
- g: u8,
- b: u8,
- alpha: u8,
- },
-}
-impl HighlightColor {
- pub fn from_raw(raw: BNHighlightColor) -> Self {
- const HIGHLIGHT_COLOR: u32 = BNHighlightColorStyle::StandardHighlightColor as u32;
- const MIXED_HIGHLIGHT_COLOR: u32 = BNHighlightColorStyle::MixedHighlightColor as u32;
- const CUSTOM_HIGHLIHGT_COLOR: u32 = BNHighlightColorStyle::CustomHighlightColor as u32;
- match raw.style as u32 {
- HIGHLIGHT_COLOR => {
- let Some(color) = HighlightStandardColor::from_raw(raw.color) else {
- // StandardHighlightColor with NoHighlightColor, is no color
- return Self::NoHighlightColor { alpha: raw.alpha };
- };
- Self::StandardHighlightColor {
- color,
- alpha: raw.alpha,
- }
- }
- MIXED_HIGHLIGHT_COLOR => {
- let Some(color) = HighlightStandardColor::from_raw(raw.color) else {
- panic!("Highlight mixed color with no color");
- };
- let Some(mix_color) = HighlightStandardColor::from_raw(raw.mixColor) else {
- panic!("Highlight mixed color with no mix_color");
- };
- Self::MixedHighlightColor {
- color,
- mix_color,
- mix: raw.mix,
- alpha: raw.alpha,
- }
- }
- CUSTOM_HIGHLIHGT_COLOR => Self::CustomHighlightColor {
- r: raw.r,
- g: raw.g,
- b: raw.b,
- alpha: raw.alpha,
- },
- // other color style is just no color
- _ => Self::NoHighlightColor { alpha: u8::MAX },
- }
- }
-
- pub fn into_raw(self) -> BNHighlightColor {
- let zeroed: BNHighlightColor = unsafe { core::mem::zeroed() };
- match self {
- Self::NoHighlightColor { alpha } => BNHighlightColor {
- style: BNHighlightColorStyle::StandardHighlightColor,
- color: BNHighlightStandardColor::NoHighlightColor,
- alpha,
- ..zeroed
- },
- Self::StandardHighlightColor { color, alpha } => BNHighlightColor {
- style: BNHighlightColorStyle::StandardHighlightColor,
- color: color.into_raw(),
- alpha,
- ..zeroed
- },
- Self::MixedHighlightColor {
- color,
- mix_color,
- mix,
- alpha,
- } => BNHighlightColor {
- color: color.into_raw(),
- mixColor: mix_color.into_raw(),
- mix,
- alpha,
- ..zeroed
- },
- Self::CustomHighlightColor { r, g, b, alpha } => BNHighlightColor {
- r,
- g,
- b,
- alpha,
- ..zeroed
- },
- }
+ pub(crate) fn free_raw(value: BNNameAndType) {
+ let _ = unsafe { BnString::from_raw(value.name) };
+ let _ = unsafe { Type::ref_from_raw(value.type_) };
}
-}
-/////////////////////////
-// IntegerDisplayType
-
-pub type IntegerDisplayType = binaryninjacore_sys::BNIntegerDisplayType;
-
-/////////////////////////
-// StackVariableReference
-
-#[derive(Debug, Clone)]
-pub struct StackVariableReference {
- _source_operand: u32,
- var_type: Conf<Ref<Type>>,
- name: BnString,
- var: Variable,
- offset: i64,
- size: usize,
-}
-
-impl StackVariableReference {
- pub fn from_raw(value: BNStackVariableReference) -> Self {
- let var_type = Conf::new(
- unsafe { Type::ref_from_raw(value.type_) },
- value.typeConfidence,
- );
- let name = unsafe { BnString::from_raw(value.name) };
- let var = unsafe { Variable::from_identifier(value.varIdentifier) };
- let offset = value.referencedOffset;
- let size = value.size;
+ pub fn new(name: impl Into<String>, ty: Conf<Ref<Type>>) -> Self {
Self {
- _source_operand: value.sourceOperand,
- var_type,
- name,
- var,
- offset,
- size,
- }
- }
- pub fn variable(&self) -> &Variable {
- &self.var
- }
- pub fn variable_type(&self) -> Conf<&Type> {
- self.var_type.as_ref()
- }
- pub fn name(&self) -> &str {
- self.name.as_str()
- }
- pub fn offset(&self) -> i64 {
- self.offset
- }
- pub fn size(&self) -> usize {
- self.size
- }
-}
-
-impl CoreArrayProvider for StackVariableReference {
- type Raw = BNStackVariableReference;
- type Context = ();
- type Wrapped<'a> = Guard<'a, Self>;
-}
-
-unsafe impl CoreArrayProviderInner for StackVariableReference {
- unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
- BNFreeStackVariableReferenceList(raw, count)
- }
- unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
- Guard::new(Self::from_raw(*raw), context)
- }
-}
-
-/////////////////////////
-// RegisterStackAdjustment
-
-#[derive(Debug, Copy, Clone)]
-pub struct RegisterStackAdjustment<A: Architecture> {
- reg_id: u32,
- adjustment: Conf<i32>,
- arch: A::Handle,
-}
-
-impl<A: Architecture> RegisterStackAdjustment<A> {
- pub(crate) unsafe fn from_raw(value: BNRegisterStackAdjustment, arch: A::Handle) -> Self {
- RegisterStackAdjustment {
- reg_id: value.regStack,
- adjustment: Conf::new(value.adjustment, value.confidence),
- arch,
- }
- }
- pub(crate) fn into_raw(self) -> BNRegisterStackAdjustment {
- BNRegisterStackAdjustment {
- regStack: self.reg_id,
- adjustment: self.adjustment.contents,
- confidence: self.adjustment.confidence,
- }
- }
- pub fn new<I>(reg_id: u32, adjustment: I, arch_handle: A::Handle) -> Self
- where
- I: Into<Conf<i32>>,
- {
- Self {
- reg_id,
- adjustment: adjustment.into(),
- arch: arch_handle,
+ name: name.into(),
+ ty,
}
}
- pub const fn register_id(&self) -> u32 {
- self.reg_id
- }
- pub fn register(&self) -> A::Register {
- self.arch.borrow().register_from_id(self.reg_id).unwrap()
- }
-}
-
-impl<A: Architecture> CoreArrayProvider for RegisterStackAdjustment<A> {
- type Raw = BNRegisterStackAdjustment;
- type Context = A::Handle;
- type Wrapped<'a> = Self;
-}
-
-unsafe impl<A: Architecture> CoreArrayProviderInner for RegisterStackAdjustment<A> {
- unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
- BNFreeRegisterStackAdjustments(raw)
- }
- unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
- Self::from_raw(*raw, context.clone())
- }
-}
-
-/////////////////////////
-// RegisterStackAdjustment
-
-// NOTE only exists as part of an Array, never owned
-pub struct MergedVariable {
- target: Variable,
- // droped by the CoreArrayProviderInner::free
- sources: ManuallyDrop<Array<Variable>>,
-}
-
-impl MergedVariable {
- pub fn target(&self) -> Variable {
- self.target
- }
- pub fn sources(&self) -> &Array<Variable> {
- &self.sources
- }
}
-impl CoreArrayProvider for MergedVariable {
- type Raw = BNMergedVariable;
+impl CoreArrayProvider for NameAndType {
+ type Raw = BNNameAndType;
type Context = ();
type Wrapped<'a> = Self;
}
-unsafe impl CoreArrayProviderInner for MergedVariable {
+unsafe impl CoreArrayProviderInner for NameAndType {
unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
- BNFreeMergedVariableList(raw, count)
- }
- unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
- Self {
- target: Variable::from_raw(raw.target),
- sources: ManuallyDrop::new(Array::new(raw.sources, raw.sourceCount, ())),
- }
- }
-}
-
-/////////////////////////
-// UnresolvedIndirectBranches
-
-// NOTE only exists as part of an Array, never owned
-pub struct UnresolvedIndirectBranches(u64);
-
-impl UnresolvedIndirectBranches {
- pub fn address(&self) -> u64 {
- self.0
+ BNFreeNameAndTypeList(raw, count);
}
-}
-impl CoreArrayProvider for UnresolvedIndirectBranches {
- type Raw = u64;
- type Context = ();
- type Wrapped<'a> = Self;
-}
-
-unsafe impl CoreArrayProviderInner for UnresolvedIndirectBranches {
- unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
- BNFreeAddressList(raw)
- }
unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
- Self(*raw)
+ NameAndType::from_raw(raw)
}
}