summaryrefslogtreecommitdiff
path: root/plugins/workflow_swift
diff options
context:
space:
mode:
authorMark Rowe <mark@vector35.com>2026-02-18 22:03:29 -0800
committerMark Rowe <mark@vector35.com>2026-03-23 16:08:45 -0700
commit1fb9828d1e12f242fa6a53aa43603ae5e556b69d (patch)
tree40fd4fa7ca487ca8cce5a8eca8e18d5e4a15da83 /plugins/workflow_swift
parent7aa5bd46fc2343458dff6a24ec2c67169fcac34c (diff)
[Swift] Add support for applying parameter and return types during demangling
This is disabled by default due to a current limitation where core is not able to represent parameters that are small structs being passed across multiple registers. `analysis.swift.extractTypesFromMangledNames` can be enabled to test this.
Diffstat (limited to 'plugins/workflow_swift')
-rw-r--r--plugins/workflow_swift/src/demangler/function_type.rs271
-rw-r--r--plugins/workflow_swift/src/demangler/mod.rs36
-rw-r--r--plugins/workflow_swift/src/demangler/name.rs84
-rw-r--r--plugins/workflow_swift/src/demangler/type_reconstruction.rs204
-rw-r--r--plugins/workflow_swift/src/lib.rs14
5 files changed, 602 insertions, 7 deletions
diff --git a/plugins/workflow_swift/src/demangler/function_type.rs b/plugins/workflow_swift/src/demangler/function_type.rs
new file mode 100644
index 00000000..3313143e
--- /dev/null
+++ b/plugins/workflow_swift/src/demangler/function_type.rs
@@ -0,0 +1,271 @@
+use binaryninja::architecture::{ArchitectureExt, CoreArchitecture, Register};
+use binaryninja::confidence::Conf;
+use binaryninja::rc::Ref;
+use binaryninja::types::{FunctionParameter, Type};
+use binaryninja::variable::{Variable, VariableSourceType};
+use swift_demangler::{
+ Accessor, AccessorKind, ConstructorKind, HasFunctionSignature, HasModule, Metadata,
+ MetadataKind, Symbol,
+};
+
+use super::type_reconstruction::{make_named_type_ref, TypeRefExt};
+
+/// Swift calling convention builder.
+///
+/// Tracks which implicit parameters (self, error, async context) are present,
+/// constructs the corresponding `FunctionParameter`s, and resolves the correct
+/// architecture-specific calling convention when building the final function type.
+struct CallingConvention {
+ arch: CoreArchitecture,
+ flags: u8,
+ leading_params: Vec<FunctionParameter>,
+ trailing_params: Vec<FunctionParameter>,
+}
+
+impl CallingConvention {
+ const SELF: u8 = 1;
+ const THROWS: u8 = 2;
+ const ASYNC: u8 = 4;
+
+ fn for_arch(arch: &CoreArchitecture) -> Self {
+ Self {
+ arch: *arch,
+ flags: 0,
+ leading_params: Vec::new(),
+ trailing_params: Vec::new(),
+ }
+ }
+
+ /// Mark this as a concrete instance method with self in x20.
+ fn set_self(&mut self, module: Option<&str>, containing_type: &str) {
+ self.flags |= Self::SELF;
+ let named_ty = make_named_type_ref(module, containing_type);
+ let self_ty = Type::pointer(&self.arch, &named_ty);
+ self.leading_params.push(FunctionParameter {
+ ty: self_ty.into(),
+ name: "self".to_string(),
+ location: None,
+ });
+ }
+
+ /// Optionally mark as a concrete instance method if `containing_type` is `Some`.
+ fn set_self_if(&mut self, module: Option<&str>, containing_type: Option<&str>) {
+ if let Some(ct) = containing_type {
+ self.set_self(module, ct);
+ }
+ }
+
+ /// Mark this as a protocol witness method. Self is in x20 (swift-self)
+ /// like concrete methods. The self type metadata and witness table are
+ /// appended as trailing arguments after the explicit params.
+ fn set_protocol_self(&mut self, module: Option<&str>, containing_type: &str) {
+ self.set_self(module, containing_type);
+ let void_ptr = Type::pointer(&self.arch, &Type::void());
+ self.trailing_params.push(FunctionParameter {
+ ty: void_ptr.clone().into(),
+ name: "selfMetadata".to_string(),
+ location: None,
+ });
+ self.trailing_params.push(FunctionParameter {
+ ty: void_ptr.into(),
+ name: "selfWitnessTable".to_string(),
+ location: None,
+ });
+ }
+
+ fn set_protocol_self_if(&mut self, module: Option<&str>, containing_type: Option<&str>) {
+ if let Some(ct) = containing_type {
+ self.set_protocol_self(module, ct);
+ }
+ }
+
+ /// Mark this as a throwing function.
+ fn set_throws(&mut self) {
+ self.flags |= Self::THROWS;
+ }
+
+ /// Mark this as an async function.
+ fn set_async(&mut self) {
+ self.flags |= Self::ASYNC;
+ }
+
+ /// Build the final function type.
+ ///
+ /// Prepends `self` before `params` and appends error/async context after,
+ /// then looks up the appropriate calling convention by name on the architecture.
+ fn build_type(self, ret_type: &Type, params: Vec<FunctionParameter>) -> Ref<Type> {
+ let mut all_params = self.leading_params;
+ all_params.extend(params);
+ all_params.extend(self.trailing_params);
+
+ if self.flags & Self::THROWS != 0 {
+ let error_ty = Type::pointer(&self.arch, &make_named_type_ref(Some("Swift"), "Error"));
+ all_params.push(FunctionParameter {
+ ty: error_ty.into(),
+ name: "error".to_string(),
+ location: None,
+ });
+ }
+
+ if self.flags & Self::ASYNC != 0 {
+ let ptr_ty = Type::pointer(&self.arch, &Type::void());
+ all_params.push(FunctionParameter {
+ ty: ptr_ty.into(),
+ name: "asyncContext".to_string(),
+ location: None,
+ });
+ }
+
+ Type::function(ret_type, all_params, false)
+ }
+}
+
+/// Build a Binary Ninja function type from a parsed Swift symbol.
+///
+/// Returns `None` if the symbol does not have a function signature (e.g. metadata, variables).
+/// Thunks are intentionally excluded for now.
+pub fn build_function_type(symbol: &Symbol, arch: &CoreArchitecture) -> Option<Ref<Type>> {
+ match symbol {
+ Symbol::Accessor(a) => return build_accessor_type(a, arch),
+ Symbol::Metadata(m) => return build_metadata_function_type(m, arch),
+ Symbol::Attributed(a) => return build_function_type(&a.inner, arch),
+ Symbol::Specialization(s) => return build_function_type(&s.inner, arch),
+ Symbol::Suffixed(s) => return build_function_type(&s.inner, arch),
+ _ => {}
+ }
+
+ let mut cc = CallingConvention::for_arch(arch);
+
+ // Determine implicit `self` parameter for instance methods/constructors.
+ match symbol {
+ Symbol::Function(f) if f.is_method() && !f.is_static() => {
+ if f.containing_type_is_protocol() {
+ cc.set_protocol_self_if(f.module(), f.containing_type());
+ } else {
+ cc.set_self_if(f.module(), f.containing_type());
+ }
+ }
+ Symbol::Constructor(c) if c.kind() != ConstructorKind::Allocating => {
+ cc.set_self_if(c.module(), c.containing_type());
+ }
+ Symbol::Destructor(d) => {
+ cc.set_self_if(d.module(), d.containing_type());
+ return Some(cc.build_type(&Type::void(), vec![]));
+ }
+ _ => {}
+ };
+
+ let (sig, labels) = match symbol {
+ Symbol::Function(f) => (f.signature(), f.labels()),
+ Symbol::Constructor(c) => (c.signature(), c.labels()),
+ Symbol::Closure(c) => (c.signature(), vec![]),
+ _ => (None, vec![]),
+ };
+ let sig = sig?;
+
+ if sig.is_throwing() {
+ cc.set_throws();
+ }
+ if sig.is_async() {
+ cc.set_async();
+ }
+
+ let params: Vec<FunctionParameter> = sig
+ .parameters()
+ .iter()
+ .enumerate()
+ .filter_map(|(i, p)| {
+ let ty = p.type_ref.to_bn_type(arch)?;
+ let name = labels
+ .get(i)
+ .copied()
+ .flatten()
+ .or(p.label)
+ .unwrap_or("")
+ .to_string();
+ Some(FunctionParameter {
+ ty: ty.into(),
+ name,
+ location: None,
+ })
+ })
+ .collect();
+
+ let ret_type = sig
+ .return_type()
+ .and_then(|rt| rt.to_bn_type(arch))
+ .unwrap_or_else(Type::void);
+
+ Some(cc.build_type(&ret_type, params))
+}
+
+/// Build a function type for a property accessor from its property type.
+fn build_accessor_type(accessor: &Accessor, arch: &CoreArchitecture) -> Option<Ref<Type>> {
+ let prop_ty = accessor
+ .property_type()
+ .and_then(|pt| pt.to_bn_type(arch))?;
+
+ let mut cc = CallingConvention::for_arch(arch);
+
+ // Non-static instance accessors take `self` as a parameter.
+ if !accessor.is_static() {
+ if let Some(ct) = accessor.containing_type() {
+ cc.set_self(accessor.module(), &ct);
+ }
+ }
+
+ match accessor.kind() {
+ // Getter-like: (self) -> PropertyType
+ AccessorKind::Getter | AccessorKind::GlobalGetter | AccessorKind::Read => {
+ Some(cc.build_type(&prop_ty, vec![]))
+ }
+
+ // Setter-like: (self, newValue: PropertyType) -> Void
+ AccessorKind::Setter
+ | AccessorKind::WillSet
+ | AccessorKind::DidSet
+ | AccessorKind::Modify
+ | AccessorKind::Init => {
+ let params = vec![FunctionParameter {
+ ty: prop_ty.into(),
+ name: "newValue".to_string(),
+ location: None,
+ }];
+ Some(cc.build_type(&Type::void(), params))
+ }
+
+ _ => None,
+ }
+}
+
+/// Build a function type for Swift runtime metadata functions.
+fn build_metadata_function_type(metadata: &Metadata, arch: &CoreArchitecture) -> Option<Ref<Type>> {
+ let void_ptr = Type::pointer(arch, &Type::void());
+
+ match metadata.kind() {
+ // Type metadata accessor: void* fn()
+ // Returns a pointer to the type metadata singleton.
+ MetadataKind::AccessFunction | MetadataKind::CanonicalSpecializedGenericAccessFunction => {
+ Some(Type::function(&void_ptr, vec![], false))
+ }
+
+ // Method lookup function: void* fn(void* metadata, void* method)
+ MetadataKind::MethodLookupFunction => {
+ let params = vec![
+ FunctionParameter {
+ ty: void_ptr.clone().into(),
+ name: "metadata".to_string(),
+ location: None,
+ },
+ FunctionParameter {
+ ty: void_ptr.clone().into(),
+ name: "method".to_string(),
+ location: None,
+ },
+ ];
+ Some(Type::function(&void_ptr, params, false))
+ }
+
+ _ => None,
+ }
+}
diff --git a/plugins/workflow_swift/src/demangler/mod.rs b/plugins/workflow_swift/src/demangler/mod.rs
index e1f22893..657c62c3 100644
--- a/plugins/workflow_swift/src/demangler/mod.rs
+++ b/plugins/workflow_swift/src/demangler/mod.rs
@@ -1,9 +1,22 @@
+mod function_type;
+mod name;
+mod type_reconstruction;
+
use binaryninja::architecture::CoreArchitecture;
use binaryninja::binary_view::BinaryView;
use binaryninja::demangle::CustomDemangler;
use binaryninja::rc::Ref;
+use binaryninja::settings::{QueryOptions, Settings};
use binaryninja::types::{QualifiedName, Type};
+fn should_extract_types(view: Option<&BinaryView>) -> bool {
+ let mut opts = match view {
+ Some(v) => QueryOptions::new_with_view(v),
+ None => QueryOptions::new(),
+ };
+ Settings::new().get_bool_with_opts(crate::SETTING_EXTRACT_TYPES, &mut opts)
+}
+
pub struct SwiftDemangler;
impl CustomDemangler for SwiftDemangler {
@@ -19,16 +32,25 @@ impl CustomDemangler for SwiftDemangler {
fn demangle(
&self,
- _arch: &CoreArchitecture,
+ arch: &CoreArchitecture,
name: &str,
- _view: Option<Ref<BinaryView>>,
+ view: Option<Ref<BinaryView>>,
) -> Option<(QualifiedName, Option<Ref<Type>>)> {
let ctx = swift_demangler::Context::new();
let symbol = swift_demangler::Symbol::parse(&ctx, name)?;
- // Use the canonical demangled form from the parsed node tree.
- // This matches what `xcrun swift-demangle` produces.
- // TODO: Use the structured Symbol API to also reconstruct BN Types.
- let demangled = symbol.display();
- Some((QualifiedName::from(demangled), None))
+
+ if should_extract_types(view.as_deref()) {
+ let ty = function_type::build_function_type(&symbol, arch);
+ let qname = if ty.is_some() {
+ name::build_short_name(&symbol)
+ } else {
+ None
+ }
+ .unwrap_or_else(|| QualifiedName::from(symbol.display()));
+ Some((qname, ty))
+ } else {
+ let qname = QualifiedName::from(symbol.display());
+ Some((qname, None))
+ }
}
}
diff --git a/plugins/workflow_swift/src/demangler/name.rs b/plugins/workflow_swift/src/demangler/name.rs
new file mode 100644
index 00000000..fd39d8b7
--- /dev/null
+++ b/plugins/workflow_swift/src/demangler/name.rs
@@ -0,0 +1,84 @@
+use binaryninja::types::QualifiedName;
+use swift_demangler::{ConstructorKind, DestructorKind, HasModule, Symbol};
+
+/// Push a module name into the name parts, skipping `__C` (Swift's internal
+/// module for C/Objective-C imports).
+fn push_module(parts: &mut Vec<String>, module: Option<&str>) {
+ if let Some(m) = module {
+ if m != "__C" {
+ parts.push(m.to_string());
+ }
+ }
+}
+
+/// Build a qualified name from a symbol's components, omitting parameter types
+/// and return type since those are represented directly in the function's type
+///
+/// Returns `None` for symbol kinds that don't benefit from shortening (e.g.
+/// variables, thunks), in which case the caller should fall back to `symbol.display()`.
+pub fn build_short_name(symbol: &swift_demangler::Symbol) -> Option<QualifiedName> {
+ let mut parts: Vec<String> = Vec::new();
+
+ match symbol {
+ Symbol::Function(f) => {
+ push_module(&mut parts, f.module());
+ if let Some(ct) = f.containing_type() {
+ parts.push(ct.to_string());
+ }
+ parts.push(f.full_name());
+ }
+ Symbol::Constructor(c) => {
+ push_module(&mut parts, c.module());
+ if let Some(ct) = c.containing_type() {
+ parts.push(ct.to_string());
+ }
+ let init_name = match c.kind() {
+ ConstructorKind::Allocating => "__allocating_init",
+ ConstructorKind::Regular => "init",
+ };
+ let labels: Vec<String> = c
+ .labels()
+ .iter()
+ .map(|l| {
+ l.map(|s| format!("{s}:"))
+ .unwrap_or_else(|| "_:".to_string())
+ })
+ .collect();
+ parts.push(format!("{init_name}({})", labels.join("")));
+ }
+ Symbol::Destructor(d) => {
+ push_module(&mut parts, d.module());
+ if let Some(ct) = d.containing_type() {
+ parts.push(ct.to_string());
+ }
+ let deinit_name = match d.kind() {
+ DestructorKind::Deallocating => "__deallocating_deinit",
+ DestructorKind::IsolatedDeallocating => "__isolated_deallocating_deinit",
+ DestructorKind::Regular => "deinit",
+ };
+ parts.push(deinit_name.to_string());
+ }
+ // Wrappers: combine the wrapper's display with the inner function's short name.
+ Symbol::Attributed(_) | Symbol::Specialization(_) => {
+ let inner = match symbol {
+ Symbol::Attributed(a) => &*a.inner,
+ Symbol::Specialization(s) => &*s.inner,
+ _ => unreachable!(),
+ };
+ return build_short_name(inner).map(|inner_name| {
+ QualifiedName::from(format!("{}{}", symbol.display(), inner_name))
+ });
+ }
+ Symbol::Suffixed(s) => {
+ return build_short_name(&s.inner)
+ .map(|inner_name| QualifiedName::from(format!("{} {}", inner_name, s.suffix)));
+ }
+ _ => return None,
+ }
+
+ if parts.is_empty() {
+ return None;
+ }
+
+ Some(QualifiedName::from(parts.join(".")))
+}
diff --git a/plugins/workflow_swift/src/demangler/type_reconstruction.rs b/plugins/workflow_swift/src/demangler/type_reconstruction.rs
new file mode 100644
index 00000000..3a3ba3e7
--- /dev/null
+++ b/plugins/workflow_swift/src/demangler/type_reconstruction.rs
@@ -0,0 +1,204 @@
+use binaryninja::architecture::{Architecture, CoreArchitecture};
+use binaryninja::rc::Ref;
+use binaryninja::types::{NamedTypeReference, NamedTypeReferenceClass, QualifiedName, Type};
+use swift_demangler::{TypeKind, TypeRef};
+
+pub(crate) trait TypeRefExt {
+ fn to_bn_type(&self, arch: &CoreArchitecture) -> Option<Ref<Type>>;
+}
+
+impl TypeRefExt for TypeRef<'_> {
+ fn to_bn_type(&self, arch: &CoreArchitecture) -> Option<Ref<Type>> {
+ match self.kind() {
+ TypeKind::Named(named) => {
+ let name = named.name()?;
+ let module = named.module();
+
+ // __C is Swift's internal module for C/Objective-C imports; drop it.
+ let module = match module {
+ Some("__C") => None,
+ other => other,
+ };
+
+ // Map Swift standard library primitive types to BN primitives.
+ // Bound generic types (e.g., Optional<T>) are never primitives.
+ if module == Some("Swift") && !named.is_generic() {
+ if let Some(ty) = swift_primitive(name, arch) {
+ return Some(ty);
+ }
+ }
+
+ let ntr = if named.is_generic() {
+ // Include generic arguments in the type name.
+ let args: Vec<String> =
+ named.generic_args().iter().map(|a| a.display()).collect();
+ let full_name = format!("{}<{}>", name, args.join(", "));
+ make_named_type_ref(module, &full_name)
+ } else {
+ make_named_type_ref(module, name)
+ };
+
+ // Class types (including ObjC classes) are reference types —
+ // always a pointer at the ABI level.
+ if named.is_class() {
+ Some(Type::pointer(arch, &ntr))
+ } else {
+ Some(ntr)
+ }
+ }
+
+ TypeKind::Function(func_type) => {
+ let params: Vec<_> = func_type
+ .parameters()
+ .iter()
+ .filter_map(|p| {
+ let ty = p.type_ref.to_bn_type(arch)?;
+ let name = p.label.unwrap_or("").to_string();
+ Some(binaryninja::types::FunctionParameter {
+ ty: ty.into(),
+ name,
+ location: None,
+ })
+ })
+ .collect();
+
+ let ret_type = func_type
+ .return_type()
+ .and_then(|rt| rt.to_bn_type(arch))
+ .unwrap_or_else(Type::void);
+
+ Some(Type::function(&ret_type, params, false))
+ }
+
+ TypeKind::Tuple(elements) => {
+ if elements.is_empty() {
+ // () is Swift.Void
+ Some(Type::void())
+ } else {
+ let display = self.display();
+ Some(make_named_type_ref(Some("Swift"), &display))
+ }
+ }
+
+ TypeKind::Optional(inner) => {
+ let display = inner.display();
+ Some(make_named_type_ref(Some("Swift"), &display))
+ }
+
+ TypeKind::Array(inner) => {
+ let display = inner.display();
+ let label = format!("[{display}]");
+ Some(make_named_type_ref(Some("Swift"), &label))
+ }
+
+ TypeKind::Dictionary { key, value } => {
+ let key_display = key.display();
+ let value_display = value.display();
+ let label = format!("[{key_display} : {value_display}]");
+ Some(make_named_type_ref(Some("Swift"), &label))
+ }
+
+ TypeKind::InOut(inner) => {
+ let inner_ty = inner.to_bn_type(arch)?;
+ Some(Type::pointer(arch, &inner_ty))
+ }
+
+ TypeKind::Metatype(_) => {
+ // Metatype is an opaque pointer-sized value at runtime.
+ Some(Type::pointer_of_width(
+ &Type::void(),
+ arch.address_size(),
+ false,
+ false,
+ None,
+ ))
+ }
+
+ TypeKind::GenericParam { .. } => {
+ // Generic parameters are opaque pointer-sized values at runtime.
+ Some(Type::pointer_of_width(
+ &Type::int(1, false),
+ arch.address_size(),
+ false,
+ false,
+ None,
+ ))
+ }
+
+ // Ownership wrappers: unwrap and recurse.
+ TypeKind::Shared(inner)
+ | TypeKind::Owned(inner)
+ | TypeKind::Sending(inner)
+ | TypeKind::Isolated(inner)
+ | TypeKind::NoDerivative(inner) => inner.to_bn_type(arch),
+
+ TypeKind::Weak(inner) | TypeKind::Unowned(inner) => inner.to_bn_type(arch),
+
+ TypeKind::DynamicSelf(inner) => inner.to_bn_type(arch),
+
+ TypeKind::ConstrainedExistential(inner) => inner.to_bn_type(arch),
+
+ TypeKind::Any => {
+ // Swift.Any is an existential container (pointer-sized at the ABI level).
+ Some(make_named_type_ref(Some("Swift"), "Any"))
+ }
+
+ TypeKind::Existential(protocols) => {
+ if protocols.len() == 1 {
+ protocols[0].to_bn_type(arch)
+ } else {
+ None
+ }
+ }
+
+ TypeKind::Generic { inner, .. } => inner.to_bn_type(arch),
+
+ // Types we can't meaningfully represent.
+ TypeKind::Error
+ | TypeKind::Builtin(_)
+ | TypeKind::BuiltinFixedArray { .. }
+ | TypeKind::ImplFunction(_)
+ | TypeKind::Pack(_)
+ | TypeKind::ValueGeneric(_)
+ | TypeKind::CompileTimeLiteral(_)
+ | TypeKind::AssociatedType { .. }
+ | TypeKind::Opaque { .. }
+ | TypeKind::SILBox { .. }
+ | TypeKind::Other(_) => None,
+ }
+ }
+}
+
+/// Map a Swift standard library type name to a primitive type.
+fn swift_primitive(name: &str, arch: &CoreArchitecture) -> Option<Ref<Type>> {
+ match name {
+ "Int" => Some(Type::int(arch.address_size(), true)),
+ "UInt" => Some(Type::int(arch.address_size(), false)),
+ "Int8" => Some(Type::int(1, true)),
+ "Int16" => Some(Type::int(2, true)),
+ "Int32" => Some(Type::int(4, true)),
+ "Int64" => Some(Type::int(8, true)),
+ "UInt8" => Some(Type::int(1, false)),
+ "UInt16" => Some(Type::int(2, false)),
+ "UInt32" => Some(Type::int(4, false)),
+ "UInt64" => Some(Type::int(8, false)),
+ "Float" => Some(Type::float(4)),
+ "Double" => Some(Type::float(8)),
+ "Float80" => Some(Type::float(10)),
+ "Bool" => Some(Type::bool()),
+ _ => None,
+ }
+}
+
+/// Create a named type reference from an optional module and a type name.
+///
+/// `__C` (Swift's internal module for C/Objective-C imports) is dropped since
+/// it is not meaningful to users.
+pub(crate) fn make_named_type_ref(module: Option<&str>, name: &str) -> Ref<Type> {
+ let qname = match module {
+ Some("__C") | None => QualifiedName::from(name),
+ Some(module) => QualifiedName::from(format!("{module}.{name}")),
+ };
+ let ntr = NamedTypeReference::new(NamedTypeReferenceClass::UnknownNamedTypeClass, qname);
+ Type::named_type(&ntr)
+}
diff --git a/plugins/workflow_swift/src/lib.rs b/plugins/workflow_swift/src/lib.rs
index 2e97a43b..a04f3659 100644
--- a/plugins/workflow_swift/src/lib.rs
+++ b/plugins/workflow_swift/src/lib.rs
@@ -2,8 +2,11 @@ mod demangler;
use binaryninja::add_optional_plugin_dependency;
use binaryninja::demangle::Demangler;
+use binaryninja::settings::Settings;
use demangler::SwiftDemangler;
+pub const SETTING_EXTRACT_TYPES: &str = "analysis.swift.extractTypesFromMangledNames";
+
#[no_mangle]
#[allow(non_snake_case)]
pub extern "C" fn CorePluginDependencies() {
@@ -16,6 +19,17 @@ pub extern "C" fn CorePluginDependencies() {
pub extern "C" fn CorePluginInit() -> bool {
binaryninja::tracing_init!("Plugin.Swift");
+ let settings = Settings::new();
+ settings.register_setting_json(
+ SETTING_EXTRACT_TYPES,
+ r#"{
+ "title" : "Extract Types from Mangled Names",
+ "type" : "boolean",
+ "default" : true,
+ "description" : "Extract parameter and return type information from Swift mangled names and apply them to function signatures. When disabled, only the demangled name is applied."
+ }"#,
+ );
+
Demangler::register("Swift", SwiftDemangler);
true