Skip to main content

macho_demangle/swift_evidence/
model.rs

1use sha2::{Digest, Sha256};
2
3/// SHA-256 digest of exact mangling evidence.
4#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
5pub struct SwiftEvidenceDigest([u8; 32]);
6
7impl SwiftEvidenceDigest {
8    /// Hash exact evidence bytes.
9    #[must_use]
10    pub fn of(bytes: impl AsRef<[u8]>) -> Self {
11        Self(Sha256::digest(bytes.as_ref()).into())
12    }
13
14    /// Return the digest bytes.
15    #[must_use]
16    pub const fn into_bytes(self) -> [u8; 32] {
17        self.0
18    }
19}
20
21/// Bounded resources for one Swift mangling decode.
22#[derive(Clone, Copy, Debug, Eq, PartialEq)]
23pub struct SwiftCallableEvidenceLimits {
24    /// Maximum bytes in the authored mangling.
25    pub max_mangling_bytes: u64,
26    /// Maximum parser nodes.
27    pub max_mangling_nodes: u64,
28    /// Maximum bytes in one identifier.
29    pub max_identifier_bytes: u64,
30    /// Maximum declaration-context depth.
31    pub max_context_depth: u64,
32    /// Maximum converted type-AST depth.
33    pub max_type_ast_depth: u64,
34    /// Maximum converted type-AST nodes.
35    pub max_type_ast_nodes: u64,
36}
37
38impl SwiftCallableEvidenceLimits {
39    pub(super) fn validate(self) -> Result<(), String> {
40        if self.max_mangling_bytes == 0
41            || self.max_mangling_nodes == 0
42            || self.max_identifier_bytes == 0
43            || self.max_context_depth == 0
44            || self.max_type_ast_depth == 0
45            || self.max_type_ast_nodes == 0
46        {
47            return Err("Swift callable evidence limits must all be nonzero".into());
48        }
49        Ok(())
50    }
51}
52
53/// Swift mangling family.
54#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
55pub enum SwiftManglingScheme {
56    /// Stable `$s`/`$S` mangling.
57    StableSwift,
58    /// Embedded Swift `$e` mangling.
59    EmbeddedSwift,
60    /// Legacy `_T` mangling.
61    LegacySwift,
62}
63
64/// Stable reason that a mangling cannot enter the supported evidence arm.
65#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
66pub enum SwiftManglingGap {
67    /// The mangling prefix is outside the admitted families.
68    UnsupportedScheme,
69    /// The parser produced an unsupported node.
70    UnsupportedNode,
71    /// The ABI representation is outside the admitted subset.
72    UnsupportedRepresentation,
73    /// A generic requirement is outside the admitted subset.
74    UnsupportedRequirement,
75    /// A builtin type is outside the admitted profile.
76    UnsupportedBuiltin,
77    /// The selected ABI profile does not admit the evidence.
78    ProfileMismatch,
79    /// Type evidence exceeds the selected depth.
80    TypeAstDepthExceeded,
81    /// Type or parser evidence exceeds the selected node count.
82    TypeAstNodesExceeded,
83}
84
85/// Swift declaration kind carried by mangling evidence.
86#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
87pub enum SwiftTypeDeclarationKind {
88    /// Class.
89    Class,
90    /// Structure.
91    Struct,
92    /// Enumeration.
93    Enum,
94    /// Protocol.
95    Protocol,
96    /// Type alias.
97    TypeAlias,
98    /// Opaque declaration.
99    Opaque,
100    /// Objective-C class.
101    ObjcClass,
102}
103
104/// One declaration-context component.
105#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
106pub enum SwiftDeclarationPathComponent {
107    /// Named context.
108    Identifier {
109        /// Identifier spelling.
110        value: String,
111    },
112    /// Private discriminator.
113    PrivateContext {
114        /// Digest of the private discriminator.
115        discriminator_sha256: SwiftEvidenceDigest,
116    },
117    /// Local discriminator.
118    LocalContext {
119        /// Digest of the local discriminator.
120        discriminator_sha256: SwiftEvidenceDigest,
121    },
122    /// Extension context.
123    ExtensionContext {
124        /// Module that defines the extension.
125        defining_module: String,
126        /// Digest of the extended declaration.
127        extended_declaration_sha256: SwiftEvidenceDigest,
128    },
129}
130
131/// Exact nominal declaration identity carried by the mangling.
132#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
133pub struct SwiftTypeDeclaration {
134    /// Declaring module.
135    pub module: String,
136    /// Nested declaration path.
137    pub declaration_path: Vec<SwiftDeclarationPathComponent>,
138    /// Nominal kind.
139    pub kind: SwiftTypeDeclarationKind,
140}
141
142/// Callable kind carried by the mangling.
143#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
144pub enum SwiftCallableKind {
145    /// Free function.
146    Function,
147    /// Instance method.
148    InstanceMethod,
149    /// Static method.
150    StaticMethod,
151    /// Class method.
152    ClassMethod,
153    /// Initializer.
154    Initializer,
155    /// Allocator.
156    Allocator,
157    /// Deinitializer.
158    Deinitializer,
159    /// Subscript getter.
160    SubscriptGet,
161    /// Subscript setter.
162    SubscriptSet,
163    /// Property getter.
164    PropertyGet,
165    /// Property setter.
166    PropertySet,
167    /// Property read coroutine.
168    PropertyRead,
169    /// Property modify coroutine.
170    PropertyModify,
171    /// Closure.
172    Closure,
173}
174
175/// Physical callable role carried by the mangling.
176#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
177pub enum SwiftCallableVariantRole {
178    /// Direct entry.
179    DirectEntry,
180    /// Class-vtable entry.
181    ClassVtableEntry,
182    /// Protocol-witness entry.
183    ProtocolWitnessEntry,
184    /// Dispatch thunk.
185    DispatchThunk,
186    /// Reabstraction thunk.
187    ReabstractionThunk,
188    /// Specialization.
189    Specialization,
190    /// Prespecialization.
191    Prespecialization,
192    /// Async entry.
193    AsyncEntry,
194    /// Async resume.
195    AsyncResume,
196    /// Coroutine entry.
197    CoroutineEntry,
198    /// Coroutine resume.
199    CoroutineResume,
200    /// Destroying deallocator.
201    DestroyingDeallocator,
202    /// Deallocating deallocator.
203    DeallocatingDeallocator,
204    /// Dynamic replacement.
205    DynamicReplacement,
206    /// Metadata accessor.
207    MetadataAccessor,
208    /// Witness accessor.
209    WitnessAccessor,
210}
211
212/// Swift function representation.
213#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
214pub enum SwiftFunctionRepresentation {
215    /// Thin.
216    Thin,
217    /// Thick Swift function.
218    Thick,
219    /// Method.
220    Method,
221    /// Witness method.
222    WitnessMethod,
223    /// C function.
224    CFunction,
225    /// Objective-C block.
226    Block,
227}
228
229/// Swift metatype representation.
230#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
231pub enum SwiftMetatypeRepresentation {
232    /// Thick.
233    Thick,
234    /// Thin.
235    Thin,
236    /// Objective-C.
237    Objc,
238}
239
240/// One tuple element.
241#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
242pub struct SwiftTupleElement {
243    /// Optional label.
244    pub label: Option<String>,
245    /// Element type.
246    pub r#type: SwiftTypeEvidence,
247}
248
249/// One formal parameter.
250#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
251pub struct SwiftFormalParameter {
252    /// Optional label.
253    pub label: Option<String>,
254    /// Parameter type.
255    pub r#type: SwiftTypeEvidence,
256    /// Whether the parameter is variadic.
257    pub variadic: bool,
258}
259
260/// Closed Swift type evidence.
261#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
262pub enum SwiftTypeEvidence {
263    /// Nominal type.
264    Nominal {
265        /// Nominal declaration.
266        declaration: SwiftTypeDeclaration,
267        /// Bound generic arguments.
268        arguments: Vec<Self>,
269    },
270    /// Generic parameter.
271    GenericParameter {
272        /// Generic depth.
273        depth: u64,
274        /// Generic index.
275        index: u64,
276    },
277    /// Dependent member.
278    DependentMember {
279        /// Base dependent type.
280        base: Box<Self>,
281        /// Member name.
282        member: String,
283        /// Optional protocol qualification.
284        protocol: Option<SwiftTypeDeclaration>,
285    },
286    /// Tuple.
287    Tuple {
288        /// Tuple elements.
289        elements: Vec<SwiftTupleElement>,
290    },
291    /// Function type.
292    Function {
293        /// Calling representation.
294        representation: SwiftFunctionRepresentation,
295        /// Formal parameters.
296        parameters: Vec<SwiftFormalParameter>,
297        /// Formal result.
298        result: Box<Self>,
299        /// Async marker.
300        r#async: bool,
301        /// Throwing marker.
302        throwing: bool,
303    },
304    /// Metatype.
305    Metatype {
306        /// Metatype representation.
307        representation: SwiftMetatypeRepresentation,
308        /// Instance type.
309        instance: Box<Self>,
310    },
311    /// Existential.
312    Existential {
313        /// Required protocols.
314        protocols: Vec<SwiftTypeDeclaration>,
315        /// Optional superclass constraint.
316        superclass: Option<Box<Self>>,
317        /// Class-only constraint.
318        class_constraint: bool,
319    },
320    /// Inout value.
321    Inout {
322        /// Wrapped value.
323        value: Box<Self>,
324    },
325    /// Owned value.
326    Owned {
327        /// Wrapped value.
328        value: Box<Self>,
329    },
330    /// Shared value.
331    Shared {
332        /// Wrapped value.
333        value: Box<Self>,
334    },
335    /// Type pack.
336    Pack {
337        /// Pack elements.
338        elements: Vec<Self>,
339    },
340    /// Pack expansion.
341    PackExpansion {
342        /// Expansion pattern.
343        pattern: Box<Self>,
344    },
345    /// Profile-defined builtin.
346    Builtin {
347        /// Profile-defined atom.
348        profile_atom: String,
349    },
350}
351
352/// Formal callable type evidence.
353#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
354pub struct SwiftFormalTypeEvidence {
355    /// Calling representation.
356    pub representation: SwiftFunctionRepresentation,
357    /// Formal parameters.
358    pub parameters: Vec<SwiftFormalParameter>,
359    /// Formal result.
360    pub result: SwiftTypeEvidence,
361    /// Async marker.
362    pub r#async: bool,
363    /// Throwing marker.
364    pub throwing: bool,
365}
366
367/// Generic requirement evidence.
368#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
369pub enum SwiftGenericRequirementEvidence {
370    /// Protocol conformance.
371    Conformance {
372        /// Subject type.
373        subject: SwiftTypeEvidence,
374        /// Required protocol.
375        protocol: SwiftTypeDeclaration,
376    },
377    /// Same-type relation.
378    SameType {
379        /// Left type.
380        left: SwiftTypeEvidence,
381        /// Right type.
382        right: SwiftTypeEvidence,
383    },
384    /// Superclass relation.
385    Superclass {
386        /// Subject type.
387        subject: SwiftTypeEvidence,
388        /// Required superclass.
389        superclass: SwiftTypeEvidence,
390    },
391    /// Same-shape relation.
392    SameShape {
393        /// Left type.
394        left: SwiftTypeEvidence,
395        /// Right type.
396        right: SwiftTypeEvidence,
397    },
398}
399
400/// Generic specialization evidence before product-specific canonicalization.
401#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
402pub struct SwiftSpecializationEvidence {
403    /// Converted substitution types.
404    pub substitutions: Vec<SwiftTypeEvidence>,
405    /// Optional compiler pass identifier.
406    pub pass_id: Option<String>,
407}
408
409/// Owned typed entity recovered from one Swift mangling.
410#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
411pub struct SwiftMangledEntityEvidence {
412    /// Declaring module.
413    pub module: String,
414    /// Declaration path.
415    pub declaration_path: Vec<SwiftDeclarationPathComponent>,
416    /// Optional nominal owner.
417    pub declaration: Option<SwiftTypeDeclaration>,
418    /// Optional callable kind.
419    pub callable_kind: Option<SwiftCallableKind>,
420    /// Optional base name.
421    pub base_name: Option<String>,
422    /// Optional formal type.
423    pub formal_type: Option<SwiftFormalTypeEvidence>,
424    /// Generic requirements.
425    pub generic_requirements: Vec<SwiftGenericRequirementEvidence>,
426    /// Optional physical role.
427    pub variant_role: Option<SwiftCallableVariantRole>,
428    /// Optional specialization evidence.
429    pub specialization: Option<SwiftSpecializationEvidence>,
430}
431
432/// Result of parsing one Swift-looking symbol.
433#[derive(Clone, Debug, Eq, PartialEq)]
434pub enum SwiftManglingEvidence {
435    /// Fully supported owned evidence.
436    Supported {
437        /// Exact linkage bytes.
438        raw: Vec<u8>,
439        /// Mangling family.
440        scheme: SwiftManglingScheme,
441        /// Typed entity evidence.
442        entity: Box<SwiftMangledEntityEvidence>,
443        /// Process-free display spelling.
444        display: String,
445    },
446    /// Well-formed but outside the admitted evidence subset.
447    Unsupported {
448        /// Exact linkage bytes.
449        raw: Vec<u8>,
450        /// Stable reason.
451        reason: SwiftManglingGap,
452        /// Bounded safe detail.
453        safe_detail: String,
454    },
455    /// Parser rejection.
456    Malformed {
457        /// Exact linkage bytes.
458        raw: Vec<u8>,
459        /// Bounded diagnostic.
460        diagnostic: String,
461    },
462}
463
464pub(super) fn validate_entity(
465    entity: &SwiftMangledEntityEvidence,
466    limits: &SwiftCallableEvidenceLimits,
467) -> Result<(), String> {
468    limits.validate()?;
469    if entity.module.is_empty() || entity.module.len() as u64 > limits.max_identifier_bytes {
470        return Err("Swift mangling module is empty or oversized".into());
471    }
472    if entity.declaration_path.len() as u64 > limits.max_context_depth {
473        return Err("Swift mangling context depth exceeds the selected limit".into());
474    }
475    let mut nodes = 0_u64;
476    if let Some(formal) = &entity.formal_type {
477        for parameter in &formal.parameters {
478            validate_type(&parameter.r#type, 1, limits, &mut nodes)?;
479        }
480        validate_type(&formal.result, 1, limits, &mut nodes)?;
481    }
482    Ok(())
483}
484
485fn validate_type(
486    value: &SwiftTypeEvidence,
487    depth: u64,
488    limits: &SwiftCallableEvidenceLimits,
489    nodes: &mut u64,
490) -> Result<(), String> {
491    *nodes = nodes
492        .checked_add(1)
493        .ok_or_else(|| "Swift type AST node count overflowed".to_string())?;
494    if depth > limits.max_type_ast_depth || *nodes > limits.max_type_ast_nodes {
495        return Err("Swift type AST structural limit exceeded".into());
496    }
497    match value {
498        SwiftTypeEvidence::Nominal { arguments, .. }
499        | SwiftTypeEvidence::Pack {
500            elements: arguments,
501        } => {
502            for child in arguments {
503                validate_type(child, depth + 1, limits, nodes)?;
504            }
505        }
506        SwiftTypeEvidence::DependentMember { base, .. }
507        | SwiftTypeEvidence::Metatype { instance: base, .. }
508        | SwiftTypeEvidence::Inout { value: base }
509        | SwiftTypeEvidence::Owned { value: base }
510        | SwiftTypeEvidence::Shared { value: base }
511        | SwiftTypeEvidence::PackExpansion { pattern: base } => {
512            validate_type(base, depth + 1, limits, nodes)?;
513        }
514        SwiftTypeEvidence::Tuple { elements } => {
515            for element in elements {
516                validate_type(&element.r#type, depth + 1, limits, nodes)?;
517            }
518        }
519        SwiftTypeEvidence::Function {
520            parameters, result, ..
521        } => {
522            for parameter in parameters {
523                validate_type(&parameter.r#type, depth + 1, limits, nodes)?;
524            }
525            validate_type(result, depth + 1, limits, nodes)?;
526        }
527        SwiftTypeEvidence::Existential { superclass, .. } => {
528            if let Some(superclass) = superclass {
529                validate_type(superclass, depth + 1, limits, nodes)?;
530            }
531        }
532        SwiftTypeEvidence::GenericParameter { .. } | SwiftTypeEvidence::Builtin { .. } => {}
533    }
534    Ok(())
535}
536
537/// Classify a Swift-looking linkage name and return the parser spelling.
538#[must_use]
539pub fn swift_mangling_scheme(raw: &str) -> Option<(SwiftManglingScheme, &str)> {
540    let value = raw.strip_prefix('_').unwrap_or(raw);
541    if value.starts_with("$s") || value.starts_with("$S") {
542        Some((SwiftManglingScheme::StableSwift, value))
543    } else if value.starts_with("$e") {
544        Some((SwiftManglingScheme::EmbeddedSwift, value))
545    } else if value.starts_with("_T") {
546        Some((SwiftManglingScheme::LegacySwift, value))
547    } else {
548        None
549    }
550}