From bbd2285583ef3bacc9f75294749267873ab22cb5 Mon Sep 17 00:00:00 2001 From: Ryan Kurtz Date: Mon, 24 Nov 2025 05:54:54 -0500 Subject: [PATCH] GP-6281: More Swift type metadata markup (mostly TrailingObjects) --- .../ghidra/app/util/bin/StructConverter.java | 4 + .../util/bin/format/swift/SwiftSection.java | 8 +- .../bin/format/swift/SwiftTypeMetadata.java | 140 ++++++---- .../swift/SwiftTypeMetadataStructure.java | 35 ++- .../app/util/bin/format/swift/SwiftUtils.java | 28 +- .../swift/types/AssociatedTypeDescriptor.java | 28 +- .../swift/types/AssociatedTypeRecord.java | 16 +- .../swift/types/BuiltinTypeDescriptor.java | 28 +- .../format/swift/types/CaptureDescriptor.java | 28 +- .../format/swift/types/CaptureTypeRecord.java | 12 +- .../format/swift/types/ConformanceFlags.java | 153 ++++++++++ .../swift/types/ContextDescriptorFlags.java | 231 +++++++++++++++ .../swift/types/ContextDescriptorKind.java | 92 +++--- .../bin/format/swift/types/EntryPoint.java | 8 +- .../types/ExtraClassDescriptorFlags.java | 90 ++++++ .../format/swift/types/FieldDescriptor.java | 32 +-- .../bin/format/swift/types/FieldRecord.java | 20 +- .../types/GenericContextDescriptorFlags.java | 110 ++++++++ .../swift/types/GenericParamDescriptor.java | 94 +++++++ .../format/swift/types/GenericParamKind.java | 75 +++++ .../swift/types/GenericRequirementFlags.java | 115 ++++++++ .../swift/types/GenericRequirementKind.java | 79 ++++++ .../types/GenericRequirementLayoutKind.java | 73 +++++ .../types/MetadataInitializationKind.java | 75 +++++ .../swift/types/MetadataSourceRecord.java | 16 +- .../swift/types/MethodDescriptorFlags.java | 119 ++++++++ .../swift/types/MethodDescriptorKind.java | 78 ++++++ .../types/MultiPayloadEnumDescriptor.java | 16 +- .../swift/types/ProtocolRequirementFlags.java | 111 ++++++++ .../swift/types/ProtocolRequirementKind.java | 81 ++++++ .../swift/types/TargetClassDescriptor.java | 262 +++++++++++++++--- .../swift/types/TargetContextDescriptor.java | 30 +- .../swift/types/TargetEnumDescriptor.java | 87 +++++- .../TargetForeignMetadataInitialization.java | 71 +++++ .../TargetGenericContextDescriptorHeader.java | 144 ++++++++++ .../TargetGenericRequirementsDescriptor.java | 132 +++++++++ .../types/TargetGenericWitnessTable.java | 104 +++++++ .../swift/types/TargetMethodDescriptor.java | 85 ++++++ .../types/TargetMethodOverrideDescriptor.java | 96 +++++++ .../TargetObjCResilientClassStubInfo.java | 79 ++++++ .../types/TargetOverrideTableHeader.java | 71 +++++ .../TargetProtocolConformanceDescriptor.java | 132 ++++++--- .../swift/types/TargetProtocolDescriptor.java | 59 ++-- .../types/TargetProtocolRequirement.java | 79 ++++++ .../types/TargetRelativeContextPointer.java | 67 +++++ ...getRelativeProtocolRequirementPointer.java | 72 +++++ .../types/TargetResilientSuperclass.java | 78 ++++++ .../swift/types/TargetResilientWitness.java | 79 ++++++ .../types/TargetResilientWitnessHeader.java | 69 +++++ ...TargetSingletonMetadataInitialization.java | 114 ++++++++ .../swift/types/TargetStructDescriptor.java | 97 ++++++- .../types/TargetTypeContextDescriptor.java | 29 +- ...getTypeGenericContextDescriptorHeader.java | 98 +++++++ .../types/TargetVTableDescriptorHeader.java | 80 ++++++ .../format/swift/types/TypeReferenceKind.java | 76 +++++ .../swift/SwiftDemangledNodeKind.java | 1 + .../util/demangler/swift/nodes/SwiftNode.java | 1 + 57 files changed, 3874 insertions(+), 413 deletions(-) create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ConformanceFlags.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ContextDescriptorFlags.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ExtraClassDescriptorFlags.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericContextDescriptorFlags.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericParamDescriptor.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericParamKind.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericRequirementFlags.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericRequirementKind.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericRequirementLayoutKind.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MetadataInitializationKind.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MethodDescriptorFlags.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MethodDescriptorKind.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ProtocolRequirementFlags.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ProtocolRequirementKind.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetForeignMetadataInitialization.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetGenericContextDescriptorHeader.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetGenericRequirementsDescriptor.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetGenericWitnessTable.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetMethodDescriptor.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetMethodOverrideDescriptor.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetObjCResilientClassStubInfo.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetOverrideTableHeader.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetProtocolRequirement.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetRelativeContextPointer.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetRelativeProtocolRequirementPointer.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetResilientSuperclass.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetResilientWitness.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetResilientWitnessHeader.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetSingletonMetadataInitialization.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetTypeGenericContextDescriptorHeader.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetVTableDescriptorHeader.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TypeReferenceKind.java diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/StructConverter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/StructConverter.java index 050e14cb59..12aa41cd13 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/StructConverter.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/StructConverter.java @@ -77,6 +77,10 @@ public interface StructConverter { * Reusable 64-bit image base offset datatype. */ public final static DataType IBO64 = IBO64DataType.dataType; + /** + * Reusable boolean data type. + */ + public final static DataType BOOL = BooleanDataType.dataType; /** * Reusable Unsigned LEB128 dynamic length data type diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/SwiftSection.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/SwiftSection.java index 4fbfab217e..a8b3d6c7a7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/SwiftSection.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/SwiftSection.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -51,9 +51,7 @@ public enum SwiftSection { } /** - * Gets a {@link List} of the {@link SwiftSection}'s names - * - * @return A {@link List} of the {@link SwiftSection}'s names + * {@return a {@link List} of the {@link SwiftSection}'s names} */ public List getSwiftSectionNames() { return sectionNames; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/SwiftTypeMetadata.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/SwiftTypeMetadata.java index a6c638302e..5a91358d1b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/SwiftTypeMetadata.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/SwiftTypeMetadata.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -168,19 +168,19 @@ public class SwiftTypeMetadata { throws CancelledException { monitor.setMessage("Parsing Swift entry point(s)..."); monitor.setIndeterminate(true); - try { - for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) { - monitor.checkCancelled(); - Address blockStart = block.getStart(); + for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) { + monitor.checkCancelled(); + Address blockStart = block.getStart(); + try { reader.setPointerIndex(blockStart.getOffset()); EntryPoint entryPoint = new EntryPoint(reader); entryPoints.add(entryPoint); markupList.add(new SwiftStructureInfo(entryPoint, new SwiftStructureAddress(blockStart, null))); } - } - catch (IOException e) { - log("Failed to parse entry point(s) from section '" + section + "'"); + catch (IOException e) { + log("Failed to parse entry point at %s: %s".formatted(blockStart, e.getMessage())); + } } } @@ -386,20 +386,20 @@ public class SwiftTypeMetadata { */ private void parseProtocolDescriptors(SwiftSection section, BinaryReader reader) throws CancelledException { - monitor.setMessage("Parsing Swift protocol descriptors..."); - monitor.setIndeterminate(true); - try { - List addrPairs = parsePointerTable(section, reader); - for (SwiftStructureAddress addrPair : addrPairs) { - reader.setPointerIndex(addrPair.structAddr().getOffset()); + List addrPairs = parsePointerTable(section, reader); + monitor.initialize(addrPairs.size(), "Parsing Swift protocol descriptors..."); + for (SwiftStructureAddress addrPair : addrPairs) { + monitor.increment(); + reader.setPointerIndex(addrPair.structAddr().getOffset()); + try { TargetProtocolDescriptor descriptor = new TargetProtocolDescriptor(reader); protocolDescriptors.add(descriptor); - markupList.add(new SwiftStructureInfo(descriptor, - new SwiftStructureAddress(addrPair.structAddr(), addrPair.pointerAddr()))); + markupList.add(new SwiftStructureInfo(descriptor, addrPair)); + } + catch (IOException e) { + log("Failed to parse protocol descriptors at %s: %s" + .formatted(addrPair.structAddr(), e.getMessage())); } - } - catch (IOException e) { - log("Failed to parse protocol descriptors from section '" + section + "'"); } } @@ -412,23 +412,21 @@ public class SwiftTypeMetadata { */ private void parseProtocolConformanceDescriptors(SwiftSection section, BinaryReader reader) throws CancelledException { - monitor.setMessage("Parsing Swift protocol conformance descriptors..."); - monitor.setIndeterminate(true); - try { - List addrPairs = parsePointerTable(section, reader); - for (SwiftStructureAddress addrPair : addrPairs) { + List addrPairs = parsePointerTable(section, reader); + monitor.initialize(addrPairs.size(), "Parsing Swift protocol conformance descriptors..."); + for (SwiftStructureAddress addrPair : addrPairs) { + monitor.increment(); + try { reader.setPointerIndex(addrPair.structAddr().getOffset()); TargetProtocolConformanceDescriptor descriptor = new TargetProtocolConformanceDescriptor(reader); protocolConformanceDescriptors.add(descriptor); - markupList.add(new SwiftStructureInfo(descriptor, - new SwiftStructureAddress(addrPair.structAddr(), - addrPair.pointerAddr()))); + markupList.add(new SwiftStructureInfo(descriptor, addrPair)); + } + catch (IOException e) { + log("Failed to parse protocol conformance descriptor at %s: %s" + .formatted(addrPair.structAddr(), e.getMessage())); } - } - catch (IOException e) { - log("Failed to parse protocol conformance descriptors from section '" + section + - "'"); } } @@ -441,37 +439,37 @@ public class SwiftTypeMetadata { */ private void parseTypeDescriptors(SwiftSection section, BinaryReader reader) throws CancelledException { - monitor.setMessage("Parsing Swift type descriptors..."); - monitor.setIndeterminate(true); - try { - List addrPairs = parsePointerTable(section, reader); - for (SwiftStructureAddress addrPair : addrPairs) { + List addrPairs = parsePointerTable(section, reader); + monitor.initialize(addrPairs.size(), "Parsing Swift type descriptors..."); + for (SwiftStructureAddress addrPair : addrPairs) { + monitor.increment(); + try { reader.setPointerIndex(addrPair.structAddr().getOffset()); long origIndex = reader.getPointerIndex(); TargetTypeContextDescriptor descriptor = new TargetTypeContextDescriptor(reader); reader.setPointerIndex(origIndex); - int contextDescriptorKind = ContextDescriptorKind.getKind(descriptor.getFlags()); - descriptor = switch (contextDescriptorKind) { - case ContextDescriptorKind.CLASS: + ContextDescriptorKind kind = descriptor.getFlags().getKind(); + descriptor = switch (kind) { + case Class: yield new TargetClassDescriptor(reader); - case ContextDescriptorKind.STRUCT: + case Struct: yield new TargetStructDescriptor(reader); - case ContextDescriptorKind.ENUM: + case Enum: yield new TargetEnumDescriptor(reader); default: log("Unrecognized type descriptor %d at index: 0x%x" - .formatted(contextDescriptorKind, origIndex)); + .formatted(kind.getValue(), origIndex)); yield null; }; if (descriptor != null) { typeDescriptors.put(descriptor.getName(), descriptor); - markupList.add(new SwiftStructureInfo(descriptor, - new SwiftStructureAddress(addrPair.structAddr(), addrPair.pointerAddr()))); + markupList.add(new SwiftStructureInfo(descriptor, addrPair)); } } - } - catch (IOException e) { - log("Failed to parse type descriptors from section '" + section + "'"); + catch (IOException e) { + log("Failed to parse type descriptor at %s: %s".formatted(addrPair, + e.getMessage())); + } } } @@ -487,6 +485,8 @@ public class SwiftTypeMetadata { throws CancelledException { final int POINTER_SIZE = 4; List result = new ArrayList<>(); + monitor.setMessage("Parsing Swift protocol conformance descriptors..."); + monitor.setIndeterminate(true); try { for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) { Address blockAddr = block.getStart(); @@ -503,7 +503,7 @@ public class SwiftTypeMetadata { } } catch (IOException e) { - log("Failed to parse Swift struction pointers from section '" + section + "'"); + log("Failed to parse Swift structure pointers from section '" + section + "'"); } return result; } @@ -514,27 +514,45 @@ public class SwiftTypeMetadata { * @throws CancelledException if the user cancelled the operation */ public void markup() throws CancelledException { - monitor.setMessage("Marking up Swift structures..."); - monitor.initialize(markupList.size()); + monitor.initialize(markupList.size(), "Marking up Swift structures..."); for (SwiftStructureInfo structInfo : markupList) { - monitor.checkCancelled(); - monitor.incrementProgress(1); + monitor.increment(); try { SwiftTypeMetadataStructure struct = structInfo.struct(); DataType dt = struct.toDataType(); - DataUtilities.createData(program, structInfo.addr().structAddr(), dt, -1, - ClearDataMode.CLEAR_ALL_DEFAULT_CONFLICT_DATA); + try { + DataUtilities.createData(program, structInfo.addr().structAddr(), dt, -1, + ClearDataMode.CLEAR_ALL_DEFAULT_CONFLICT_DATA); + } + catch (CodeUnitInsertionException e) { + // Probably multiple pointers to same structure + } + for (SwiftTypeMetadataStructure trailingStruct : struct.getTrailingObjects()) { + Address trailingAddr = structInfo.addr() + .structAddr() + .add(trailingStruct.getBase() - struct.getBase()); + DataType trailingDt = trailingStruct.toDataType(); + try { + DataUtilities.createData(program, trailingAddr, trailingDt, -1, + ClearDataMode.CLEAR_ALL_DEFAULT_CONFLICT_DATA); + } + catch (CodeUnitInsertionException e) { + // Probably multiple pointers to same structure + } + } if (structInfo.addr().pointerAddr() != null) { PointerTypedef relativePtrDataType = new PointerTypedef(null, dt, 4, null, PointerType.RELATIVE); - DataUtilities.createData(program, structInfo.addr().pointerAddr(), - relativePtrDataType, -1, ClearDataMode.CLEAR_ALL_DEFAULT_CONFLICT_DATA); + try { + DataUtilities.createData(program, structInfo.addr().pointerAddr(), + relativePtrDataType, -1, ClearDataMode.CLEAR_ALL_DEFAULT_CONFLICT_DATA); + } + catch (CodeUnitInsertionException e) { + // Unexpected, but safe to ignore + } } } - catch (CodeUnitInsertionException e) { - // Probably just called more than once - } - catch (DuplicateNameException | IOException e) { + catch (IllegalArgumentException | DuplicateNameException | IOException e) { log("Failed to markup: " + structInfo); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/SwiftTypeMetadataStructure.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/SwiftTypeMetadataStructure.java index 2714e2c4b2..c242d505f4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/SwiftTypeMetadataStructure.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/SwiftTypeMetadataStructure.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,41 +15,52 @@ */ package ghidra.app.util.bin.format.swift; +import java.util.List; + import ghidra.app.util.bin.StructConverter; +import ghidra.program.model.data.CategoryPath; /** * Implemented by all Swift type metadata structures */ public abstract class SwiftTypeMetadataStructure implements StructConverter { - public static final String DATA_TYPE_CATEGORY = "/SwiftTypeMetadata"; + public static final String CATEGORY = "/SwiftTypeMetadata"; + public static final CategoryPath CATEGORY_PATH = new CategoryPath(CATEGORY); private long base; + /** + * Creates a new {@link SwiftTypeMetadataStructure} + * + * @param base The base "address" of this {@link SwiftTypeMetadataStructure} + */ public SwiftTypeMetadataStructure(long base) { this.base = base; } /** - * Gets the base "address" of this {@link SwiftTypeMetadataStructure} - * - * @return The base "address" of this {@link SwiftTypeMetadataStructure} + * {@return the base "address" of this {@link SwiftTypeMetadataStructure}} */ public long getBase() { return base; } /** - * Gets the name of the {@link SwiftTypeMetadataStructure} - * - * @return The name of the {@link SwiftTypeMetadataStructure} + * {@return a {@link List} of {@link SwiftTypeMetadataStructure structures} that trail this + * {@link SwiftTypeMetadataStructure structure}} + */ + public List getTrailingObjects() { + return List.of(); + } + + /** + * {@return the name of the {@link SwiftTypeMetadataStructure}} */ public abstract String getStructureName(); /** - * Gets a short description of the {@link SwiftTypeMetadataStructure} - * - * @return A short description of the {@link SwiftTypeMetadataStructure} + * {@return a short description of the {@link SwiftTypeMetadataStructure}} */ public abstract String getDescription(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/SwiftUtils.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/SwiftUtils.java index 6bb4ad673d..dc43e0ae4e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/SwiftUtils.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/SwiftUtils.java @@ -32,10 +32,21 @@ public class SwiftUtils { public static final String SWIFT_COMPILER = "swift"; /** - * A {@link PointerTypedef pointer} to a relative 4-byte offset + * A {@link TypeDef pointer} to a relative 4-byte offset */ - public static final PointerTypedef PTR_RELATIVE = - new PointerTypedef(null, null, 4, null, PointerType.RELATIVE); + public static final TypeDef PTR_RELATIVE = + new PointerTypedefBuilder(Pointer32DataType.dataType, null) + .type(PointerType.RELATIVE) + .build(); + + /** + * A {@link TypeDef pointer} to a relative 4-byte offset (low bit masked off) + */ + public static final TypeDef PTR_RELATIVE_MASKED = + new PointerTypedefBuilder(Pointer32DataType.dataType, null) + .type(PointerType.RELATIVE) + .bitMask(~1) + .build(); /** * A {@link PointerTypedef string pointer} to a 4-byte relative offset @@ -44,10 +55,9 @@ public class SwiftUtils { new PointerTypedef(null, StringDataType.dataType, 4, null, PointerType.RELATIVE); /** - * Checks if the given {@link Program} is a Swift program + * {@return true if the given {@link Program} is a Swift program; otherwise, false} * * @param program The {@link Program} to check - * @return True if the given {@link Program} is a Swift program; otherwise, false */ public static boolean isSwift(Program program) { List prefixes = List.of("__swift", "swift", ".sw5"); @@ -60,11 +70,10 @@ public class SwiftUtils { } /** - * Checks if the given {@link List} of section names contains a Swift section name + * {@return true if the given {@link List} of section names contains a Swift section name; + * otherwise, false} * * @param sectionNames The {@link List} of section names to check - * @return True if the given {@link List} of section names contains a Swift section name; otherwise, - * false */ public static boolean isSwift(List sectionNames) { List prefixes = List.of("__swift", "swift", ".sw5"); @@ -77,11 +86,10 @@ public class SwiftUtils { } /** - * Gets a {@link List} of {@link MemoryBlock}s that match the given {@link SwiftSection} + * {@return a {@link List} of {@link MemoryBlock}s that match the given {@link SwiftSection}} * * @param section The {@link SwiftSection} * @param program The {@link Program} - * @return A {@link List} of {@link MemoryBlock}s that match the given {@link SwiftSection} */ public static List getSwiftBlocks(SwiftSection section, Program program) { List result = new ArrayList<>(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/AssociatedTypeDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/AssociatedTypeDescriptor.java index d427895608..96e9c58575 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/AssociatedTypeDescriptor.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/AssociatedTypeDescriptor.java @@ -22,11 +22,12 @@ import java.util.List; import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; import ghidra.app.util.bin.format.swift.SwiftUtils; -import ghidra.program.model.data.*; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; import ghidra.util.exception.DuplicateNameException; /** - * Represents a Swift AssociatedTypeDescriptor structure + * Represents a Swift {@code AssociatedTypeDescriptor} structure * * @see swift/RemoteInspection/Records.h */ @@ -63,45 +64,35 @@ public final class AssociatedTypeDescriptor extends SwiftTypeMetadataStructure { } /** - * Gets the conforming type name - * - * @return The conforming type name + * {@return the conforming type name} */ public String getConformingTypeName() { return conformingTypeName; } /** - * Gets the protocol type name - * - * @return The protocol type name + * {@return the protocol type name} */ public String getProtocolTypeName() { return protocolTypeName; } /** - * Gets the number of associated types - * - * @return The number of associated types + * {@return the number of associated types} */ public int getNumAssociatedTypes() { return numAssociatedTypes; } /** - * Gets the associated type record size - * - * @return The associated type record size + * {@return the associated type record size} */ public int getAssociatedTypeRecordSize() { return associatedTypeRecordSize; } /** - * Gets the {@link List} of {@link AssociatedTypeRecord}s - * - * @return The {@link List} of {@link AssociatedTypeRecord}s + * {@return The {@link List} of {@link AssociatedTypeRecord}s} */ public List getAssociatedTypeRecords() { return associatedTypeRecords; @@ -119,12 +110,11 @@ public final class AssociatedTypeDescriptor extends SwiftTypeMetadataStructure { @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType struct = new StructureDataType(getStructureName(), 0); + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); struct.add(SwiftUtils.PTR_STRING, "ConformingTypeName", ""); struct.add(SwiftUtils.PTR_STRING, "ProtocolTypeName", ""); struct.add(DWORD, "NumAssociatedTypes", ""); struct.add(DWORD, "AssociatedTypeRecordSize", ""); - struct.setCategoryPath(new CategoryPath(DATA_TYPE_CATEGORY)); return struct; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/AssociatedTypeRecord.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/AssociatedTypeRecord.java index 6caf9dcd45..130d9e4992 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/AssociatedTypeRecord.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/AssociatedTypeRecord.java @@ -20,11 +20,12 @@ import java.io.IOException; import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; import ghidra.app.util.bin.format.swift.SwiftUtils; -import ghidra.program.model.data.*; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; import ghidra.util.exception.DuplicateNameException; /** - * Represents a Swift AssociatedTypeRecord structure + * Represents a Swift {@code AssociatedTypeRecord} structure * * @see swift/RemoteInspection/Records.h */ @@ -51,18 +52,14 @@ public final class AssociatedTypeRecord extends SwiftTypeMetadataStructure { } /** - * Gets the name - * - * @return The name + * {@return the name} */ public String getName() { return name; } /** - * Gets the substituted type name - * - * @return The substituted type name + * {@return the substituted type name} */ public String getSubstitutedTypeName() { return substitutedTypeName; @@ -80,10 +77,9 @@ public final class AssociatedTypeRecord extends SwiftTypeMetadataStructure { @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType struct = new StructureDataType(getStructureName(), 0); + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); struct.add(SwiftUtils.PTR_STRING, "Name", ""); struct.add(SwiftUtils.PTR_STRING, "SubstitutedTypeName", ""); - struct.setCategoryPath(new CategoryPath(DATA_TYPE_CATEGORY)); return struct; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/BuiltinTypeDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/BuiltinTypeDescriptor.java index 22be07c157..a52c2f2650 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/BuiltinTypeDescriptor.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/BuiltinTypeDescriptor.java @@ -20,11 +20,12 @@ import java.io.IOException; import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; import ghidra.app.util.bin.format.swift.SwiftUtils; -import ghidra.program.model.data.*; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; import ghidra.util.exception.DuplicateNameException; /** - * Represents a Swift BuiltinTypeDescriptor structure + * Represents a Swift {@code BuiltinTypeDescriptor} structure * * @see swift/RemoteInspection/Records.h */ @@ -57,45 +58,35 @@ public final class BuiltinTypeDescriptor extends SwiftTypeMetadataStructure { } /** - * Gets the type name - * - * @return The type name + * {@return the type name} */ public String getTypeName() { return typeName; } /** - * Gets the size - * - * @return The size + * {@return the size} */ public int getSize() { return size; } /** - * Gets the alignment and flags - * - * @return The alignment and flags + * {@return the alignment and flags} */ public int getAlignmentAndFlags() { return alignmentAndFlags; } /** - * Gets the stride - * - * @return The stride + * {@return the stride} */ public int getStride() { return stride; } /** - * Gets the number of extra inhabitants - * - * @return The number of extra inhabitants + * {@return the number of extra inhabitants} */ public int getNumExtraInhabitants() { return numExtraInhabitants; @@ -113,13 +104,12 @@ public final class BuiltinTypeDescriptor extends SwiftTypeMetadataStructure { @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType struct = new StructureDataType(getStructureName(), 0); + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); struct.add(SwiftUtils.PTR_STRING, "TypeName", ""); struct.add(DWORD, "Size", ""); struct.add(DWORD, "AlignmentAndFlags", ""); struct.add(DWORD, "Stride", ""); struct.add(DWORD, "NumExtraInhabitants", ""); - struct.setCategoryPath(new CategoryPath(DATA_TYPE_CATEGORY)); return struct; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/CaptureDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/CaptureDescriptor.java index 94f26ed6a5..9c57979448 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/CaptureDescriptor.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/CaptureDescriptor.java @@ -21,11 +21,12 @@ import java.util.List; import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; -import ghidra.program.model.data.*; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; import ghidra.util.exception.DuplicateNameException; /** - * Represents a Swift CaptureDescriptor structure + * Represents a Swift {@code CaptureDescriptor} structure * * @see swift/RemoteInspection/Records.h */ @@ -65,45 +66,35 @@ public final class CaptureDescriptor extends SwiftTypeMetadataStructure { } /** - * Gets the number of capture types - * - * @return The number of capture types + * {@return the number of capture types} */ public int getNumCaptureTypes() { return numCaptureTypes; } /** - * Gets the number of metadata sources - * - * @return The number of metadata sources + * {@return the number of metadata sources} */ public int getNumMetadataSources() { return numMetadataSources; } /** - * Gets the number of bindings - * - * @return The number of bindings + * {@return the number of bindings} */ public int getNumBindings() { return numBindings; } /** - * Gets the {@link List} of {@link CaptureTypeRecord}s - * - * @return The {@link List} of {@link CaptureTypeRecord}s + * {@return the {@link List} of {@link CaptureTypeRecord}s} */ public List getCaptureTypeRecords() { return captureTypeRecords; } /** - * Gets the {@link List} of {@link MetadataSourceRecord}s - * - * @return The {@link List} of {@link MetadataSourceRecord}s + * {@return the {@link List} of {@link MetadataSourceRecord}s} */ public List getMetadataSourceRecords() { return metadataSourceRecords; @@ -121,11 +112,10 @@ public final class CaptureDescriptor extends SwiftTypeMetadataStructure { @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType struct = new StructureDataType(getStructureName(), 0); + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); struct.add(DWORD, "NumCaptureTypes", ""); struct.add(DWORD, "NumMetadataSources", ""); struct.add(DWORD, "NumBindings", ""); - struct.setCategoryPath(new CategoryPath(DATA_TYPE_CATEGORY)); return struct; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/CaptureTypeRecord.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/CaptureTypeRecord.java index 691c6087d3..8a2659929e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/CaptureTypeRecord.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/CaptureTypeRecord.java @@ -20,11 +20,12 @@ import java.io.IOException; import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; import ghidra.app.util.bin.format.swift.SwiftUtils; -import ghidra.program.model.data.*; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; import ghidra.util.exception.DuplicateNameException; /** - * Represents a Swift CaptureTypeRecord structure + * Represents a Swift {@code CaptureTypeRecord} structure * * @see swift/RemoteInspection/Records.h */ @@ -50,9 +51,7 @@ public final class CaptureTypeRecord extends SwiftTypeMetadataStructure { } /** - * Gets the mangled type name - * - * @return The mangled type name + * {@return the mangled type name} */ public String getMangledTypeName() { return mangledTypeName; @@ -70,9 +69,8 @@ public final class CaptureTypeRecord extends SwiftTypeMetadataStructure { @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType struct = new StructureDataType(getStructureName(), 0); + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); struct.add(SwiftUtils.PTR_STRING, "MangledTypeName", ""); - struct.setCategoryPath(new CategoryPath(DATA_TYPE_CATEGORY)); return struct; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ConformanceFlags.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ConformanceFlags.java new file mode 100644 index 0000000000..9fe598b5db --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ConformanceFlags.java @@ -0,0 +1,153 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift {@code ConformanceFlags} structure + * + * @see swift/ABI/MetadataValues.h + */ +public class ConformanceFlags extends SwiftTypeMetadataStructure { + + /** + * The size (in bytes) of a {@link ConformanceFlags} structure + */ + public static final int SIZE = 4; + + private int flags; + + /** + * Create a new {@link ConformanceFlags} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public ConformanceFlags(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + flags = reader.readNextInt(); + } + + /** + * {@return the flags} + */ + public int getFlags() { + return flags; + } + + /** + * {@return the {@link TypeReferenceKind}} + */ + public TypeReferenceKind getKind() { + return TypeReferenceKind.valueOf((flags >> 3) & 0x3); + } + + /** + * {@return whether or not it is retroactive} + */ + public boolean isRetroactive() { + return ((flags >> 6) & 0x1) != 0; + } + + /** + * {@return whether or not it is synthesized non-unique} + */ + public boolean isSynthesizedNonUnique() { + return ((flags >> 7) & 0x1) != 0; + } + + /** + * {@return the number of conditional requirements} + */ + public int getNumConditionalRequirements() { + return (flags >> 8) & 0x8; + } + + /** + * {@return whether or not it has resilient witnesses} + */ + public boolean hasResilientWitnesses() { + return ((flags >> 16) & 0x1) != 0; + } + + /** + * {@return whether or not it a generic witness table} + */ + public boolean hasGenericWitnessTable() { + return ((flags >> 17) & 0x1) != 0; + } + + /** + * {@return whether or not it is conformance of protocol} + */ + public boolean isConformanceOfProtocol() { + return ((flags >> 18) & 0x1) != 0; + } + + /** + * {@return whether or not it has global actor isolation} + */ + public boolean hasGlobalActorIsolation() { + return ((flags >> 19) & 0x1) != 0; + } + + /** + * {@return the number of conditional pack descriptors} + */ + public int getNumConditionalPackDescriptor() { + return (flags >> 24) & 0x8; + } + + @Override + public String getStructureName() { + return ConformanceFlags.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "conformance flags"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), SIZE); + struct.setPackingEnabled(true); + try { + struct.addBitField(DWORD, 3, "UnusedLowBits", "historical conformance kind"); + struct.addBitField(getKind().toDataType(), 3, "TypeMetadataKind", + "8 type reference kinds"); + struct.addBitField(BOOL, 1, "IsRetroactive", null); + struct.addBitField(BOOL, 1, "IsSynthesizedNonUnique", null); + struct.addBitField(DWORD, 8, "NumConditionalRequirements", null); + struct.addBitField(BOOL, 1, "HasResilientWitnesses", null); + struct.addBitField(BOOL, 1, "HasGenericWitnessTable", null); + struct.addBitField(BOOL, 1, "IsConformanceOfProtocol", null); + struct.addBitField(BOOL, 1, "HasGlobalActorIsolation", null); + struct.addBitField(DWORD, 4, "reserved", null); + struct.addBitField(DWORD, 8, "NumConditionalPackDescriptor", null); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ContextDescriptorFlags.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ContextDescriptorFlags.java new file mode 100644 index 0000000000..3edbab7bff --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ContextDescriptorFlags.java @@ -0,0 +1,231 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift {@code ContextDescriptorFlags} structure + * + * @see swift/ABI/MetadataValues.h + */ +public class ContextDescriptorFlags extends SwiftTypeMetadataStructure { + + /** + * The size (in bytes) of a {@link ContextDescriptorFlags} structure + */ + public static final int SIZE = 4; + + private int flags; + + /** + * Create a new {@link ContextDescriptorFlags} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public ContextDescriptorFlags(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + flags = reader.readNextInt(); + } + + /** + * {@return the flags} + */ + public int getFlags() { + return flags; + } + + /** + * {@return the {@link ContextDescriptorKind}} + */ + public ContextDescriptorKind getKind() { + return ContextDescriptorKind.valueOf(flags & 0x1f); + } + + /** + * {@return whether or not the context has information about invertable protocols, which will + * show up as a trailing field in the context descriptor} + */ + public boolean hasInvertableProtocols() { + return (flags & 0x20) != 0; + } + + /** + * {@return whether this is a unique record describing the referenced context} + */ + public boolean isUnique() { + return (flags & 0x40) != 0; + } + + /** + * {@return whether the context being described is generic} + */ + public boolean isGeneric() { + return (flags & 0x80) != 0; + } + + /** + * {@return whether there's something unusual about how the metadata is initialized} + */ + public MetadataInitializationKind getMetadataInitialization() { + return MetadataInitializationKind.valueOf((flags >> 16) & 0x3); + } + + /** + * {@return whether or not the type has extended import information} + */ + public boolean hasImportInfo() { + return ((flags >> 18) & 0x1) != 0; + } + + /** + * {@return whether or not the generic type descriptor has a pointer to a list of canonical + * prespecializations, or the non-generic type descriptor has a pointer to its singleton + * metadata} + */ + public boolean hasCanonicalMetadataPrespecializationsOrSingletonMetadataPonter() { + return ((flags >> 19) & 0x1) != 0; + } + + /** + * {@return whether or not the metadata contains a pointer to a layout string} + */ + public boolean hasLayoutString() { + return ((flags >> 20) & 0x1) != 0; + } + + /** + * {@return whether or not the class has a default override table} + */ + public boolean hasClassDefaultOverrideTable() { + return ((flags >> 22) & 0x1) != 0; + } + + /** + * {@return whether or not the class is an actor} + */ + public boolean isClassActor() { + return ((flags >> 23) & 0x1) != 0; + } + + /** + * {@return whether or not the class is a default actor} + */ + public boolean isClassDefaultActor() { + return ((flags >> 24) & 0x1) != 0; + } + + /** + * {@return the kind of reference that this class makes to its resilient superclass descriptor. + * A TypeReferenceKind.} + */ + public int getClassResilientSuperclassReferenceKind() { + return (flags >> 25) & 0x7; + } + + /** + * {@return whether the immediate class members in this metadata are allocated at negative + * offsets} + */ + public boolean areClassImmediateMembersNegative() { + return ((flags >> 28) & 0x1) != 0; + } + + /** + * {@return Whether or not the context descriptor is for a class with resilient ancestry} + */ + public boolean hasClassResilientSuperclass() { + return ((flags >> 29) & 0x1) != 0; + } + + /** + * {@return whether or not the context descriptor includes metadata for dynamically installing + * method overrides at metadata instantiation time} + */ + public boolean hasClassOverrideTable() { + return ((flags >> 30) & 0x1) != 0; + } + + /** + * {@return whether or not the context descriptor includes metadata for dynamically constructing + * a class's vtables at metadata instantiation time} + */ + public boolean hasClassVTable() { + return ((flags >> 31) & 0x1) != 0; + } + + @Override + public String getStructureName() { + return ContextDescriptorFlags.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "context descriptor flags"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), SIZE); + struct.setPackingEnabled(true); + try { + struct.addBitField(ContextDescriptorKind.values()[0].toDataType(), 5, "kind", + "Kind of context descriptor"); + struct.addBitField(BOOL, 1, "hasInvertableProtocols", + "Whether or not the context has information about invertable protocols, which will show up as a trailing field in the context descriptor."); + struct.addBitField(BOOL, 1, "isUnique", + "Whether this is a unique record describing the referenced context."); + struct.addBitField(BOOL, 1, "isGeneric", + "Whether the context being described is generic."); + struct.addBitField(DWORD, 8, "reserved", null); + struct.addBitField(MetadataInitializationKind.values()[0].toDataType(), 2, + "MetadataInitialization", + "Whether there's something unusual about how the metadata is initialized."); + struct.addBitField(BOOL, 1, "HasImportInfo", + "Set if the type has extended import information."); + struct.addBitField(BOOL, 1, + "HasCanonicalMetadataPrespecializationsOrSingletonMetadataPonter", + "Set if the generic type descriptor has a pointer to a list of canonical prespecializations, or the non-generic type descriptor has a pointer to its singleton metadata."); + struct.addBitField(BOOL, 1, "HasLayoutString", + "Set if the metadata contains a pointer to a layout string."); + struct.addBitField(DWORD, 1, "reserved", null); + struct.addBitField(BOOL, 1, "Class_HasDefaultOverrideTable", null); + struct.addBitField(BOOL, 1, "Class_IsActor", "Set if the class is an actor."); + struct.addBitField(BOOL, 1, "Class_IsDefaultActor", + "Set if the class is a default actor class."); + struct.addBitField(DWORD, 3, "Class_ResilientSuperclassReferenceKind", + "The kind of reference that this class makes to its resilient superclass descriptor. A TypeReferenceKind."); + struct.addBitField(BOOL, 1, "Class_AreImmediateMembersNegative", + "Whether the immediate class members in this metadata are allocated at negative offsets."); + struct.addBitField(BOOL, 1, "Class_HasResilientSuperclass", + "Set if the context descriptor is for a class with resilient ancestry."); + struct.addBitField(BOOL, 1, "Class_HasOverrideTable", + "Set if the context descriptor includes metadata for dynamically installing method overrides at metadata instantiation time."); + struct.addBitField(BOOL, 1, "Class_HasVTable", + "Set if the context descriptor includes metadata for dynamically constructing a class's vtables at metadata instantiation time."); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ContextDescriptorKind.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ContextDescriptorKind.java index fb1d6a6f1c..e85ee61e36 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ContextDescriptorKind.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ContextDescriptorKind.java @@ -15,80 +15,98 @@ */ package ghidra.app.util.bin.format.swift.types; +import java.io.IOException; +import java.util.Arrays; + +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.EnumDataType; +import ghidra.util.exception.DuplicateNameException; + /** - * Swift ContextDescriptorKind values + * Swift {@code ContextDescriptorKind} values * * @see swift/ABI/MetadataValues.h */ -public class ContextDescriptorKind { - - /** - * The mask to apply to the {@link TargetContextDescriptor#getFlags() flags} to get the - * {@link ContextDescriptorKind} value - */ - private static int KIND_MASK = 0x1f; - - /** - * Gets the {@link ContextDescriptorKind} value from the - * {@link TargetContextDescriptor#getFlags() flags} - * - * @param flags The {@link TargetContextDescriptor#getFlags() flags} that contain the kind - * @return The {@link ContextDescriptorKind} value - */ - public static int getKind(int flags) { - return flags & KIND_MASK; - } - - //--------------------------------------------------------------------------------------------- - +public enum ContextDescriptorKind implements StructConverter { + /** * This context descriptor represents a module */ - public static final int MODULE = 0; + Module(0), /** * This context descriptor represents an extension */ - public static final int EXTENSION = 1; + Extension(1), /** * This context descriptor represents an anonymous possibly-generic context such as a function * body */ - public static final int ANONYMOUS = 2; + Anonymous(2), /** * This context descriptor represents a protocol context */ - public static final int PROTOCOL = 3; + Protocol(3), /** * This context descriptor represents an opaque type alias */ - public static final int OPAQUE_TYPE = 4; - - /** - * First kind that represents a type of any sort - */ - public static final int TYPE_FIRST = 16; + OpaqueType(4), /** * This context descriptor represents a class */ - public static final int CLASS = TYPE_FIRST; + Class(16), /** * This context descriptor represents a struct */ - public static final int STRUCT = TYPE_FIRST + 1; + Struct(17), /** * This context descriptor represents an enum */ - public static final int ENUM = TYPE_FIRST + 2; + Enum(18); + + private int value; /** - * Last kind that represents a type of any sort + * Creates a new {@link ContextDescriptorKind} + * + * @param value The kind value */ - public static final int TYPE_LAST = 31; + private ContextDescriptorKind(int value) { + this.value = value; + } + + /** + * {@return the kind value} + */ + public int getValue() { + return value; + } + + /** + * {@return the {@link ContextDescriptorKind} with the given kind value, or {@code null} if it + * does not exist} + * + * @param value The kind value to get the value of + */ + public static ContextDescriptorKind valueOf(int value) { + return Arrays.stream(values()).filter(e -> e.getValue() == value).findFirst().orElse(null); + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + EnumDataType dt = new EnumDataType(SwiftTypeMetadataStructure.CATEGORY_PATH, + ContextDescriptorKind.class.getSimpleName(), 1); + for (ContextDescriptorKind kind : values()) { + dt.add(kind.name(), kind.getValue()); + } + return dt; + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/EntryPoint.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/EntryPoint.java index 6829e62cf9..78d41cd13e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/EntryPoint.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/EntryPoint.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -47,9 +47,7 @@ public final class EntryPoint extends SwiftTypeMetadataStructure { } /** - * Gets the entry point - * - * @return The entry point + * {@return the entry point} */ public int getEntryPoint() { return entryPoint; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ExtraClassDescriptorFlags.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ExtraClassDescriptorFlags.java new file mode 100644 index 0000000000..77ae9b960a --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ExtraClassDescriptorFlags.java @@ -0,0 +1,90 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift {@code ExtraClassDescriptorFlags} enum + * + * @see swift/ABI/MetadataValues.h + */ +public class ExtraClassDescriptorFlags extends SwiftTypeMetadataStructure { + + /** + * The size (in bytes) of a {@link ExtraClassDescriptorFlags} structure + */ + public static final int SIZE = 4; + + private int flags; + + /** + * Creates a new {@link ExtraClassDescriptorFlags} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public ExtraClassDescriptorFlags(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + flags = reader.readNextInt(); + } + + /** + * {@return the flags} + */ + public int getFlags() { + return flags; + } + + /** + * {@return whether or not the context descriptor includes a pointer to an Objective-C resilient class stub structure} + *

+ * Only meaningful for class descriptors when Objective-C interop is enabled. + */ + public boolean hasObjcResilientClassStub() { + return (flags & 0x1) != 0; + } + + @Override + public String getStructureName() { + return ExtraClassDescriptorFlags.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "extra class descriptor flags"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), SIZE); + struct.setPackingEnabled(true); + try { + struct.addBitField(BOOL, 1, "HasObjCResilientClassStub", + "Set if the context descriptor includes a pointer to an Objective-C resilient class stub structure. Only meaningful for class descriptors when Objective-C interop is enabled."); + struct.addBitField(DWORD, 31, "reserved", null); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/FieldDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/FieldDescriptor.java index 4bcc322a4f..f05afab422 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/FieldDescriptor.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/FieldDescriptor.java @@ -22,11 +22,12 @@ import java.util.List; import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; import ghidra.app.util.bin.format.swift.SwiftUtils; -import ghidra.program.model.data.*; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; import ghidra.util.exception.DuplicateNameException; /** - * Represents a Swift FieldDescriptor structure + * Represents a Swift {@code FieldDescriptor} structure * * @see swift/RemoteInspection/Records.h */ @@ -65,54 +66,42 @@ public final class FieldDescriptor extends SwiftTypeMetadataStructure { } /** - * Gets the mangled type name - * - * @return The mangled type name + * {@return the mangled type name} */ public String getMangledTypeName() { return mangledTypeName; } /** - * Gets the superclass - * - * @return The superclass + * {@return the superclass} */ public int getSuperclass() { return superclass; } /** - * Gets the kind - * - * @return The kind + * {@return the kind} */ public int getKind() { return kind; } /** - * Gets the field record size - * - * @return The field record size + * {@return the field record size} */ public int getFieldRecordSize() { return fieldRecordSize; } /** - * Gets the number of fields - * - * @return The number of fields + * {@return the number of fields} */ public int getNumFields() { return numFields; } /** - * Gets the {@link List} of {@link FieldRecord}s - * - * @return The {@link List} of {@link FieldRecord}s + * {@return the {@link List} of {@link FieldRecord}s} */ public List getFieldRecords() { return fieldRecords; @@ -130,13 +119,12 @@ public final class FieldDescriptor extends SwiftTypeMetadataStructure { @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType struct = new StructureDataType(getStructureName(), 0); + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); struct.add(SwiftUtils.PTR_STRING, "MangledTypeName", ""); struct.add(SwiftUtils.PTR_RELATIVE, "Superclass", ""); struct.add(WORD, "Kind", ""); struct.add(WORD, "FieldRecordSize", ""); struct.add(DWORD, "NumFields", ""); - struct.setCategoryPath(new CategoryPath(DATA_TYPE_CATEGORY)); return struct; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/FieldRecord.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/FieldRecord.java index 1ede69ed6d..e4c6511bda 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/FieldRecord.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/FieldRecord.java @@ -20,11 +20,12 @@ import java.io.IOException; import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; import ghidra.app.util.bin.format.swift.SwiftUtils; -import ghidra.program.model.data.*; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; import ghidra.util.exception.DuplicateNameException; /** - * Represents a Swift FieldRecord structure + * Represents a Swift {@code FieldRecord} structure * * @see swift/RemoteInspection/Records.h */ @@ -53,27 +54,21 @@ public final class FieldRecord extends SwiftTypeMetadataStructure { } /** - * Gets the flags - * - * @return The flags + * {@return the flags} */ public int getFlags() { return flags; } /** - * Gets the mangled type name - * - * @return The mangled type name + * {@return the mangled type name} */ public String getMangledTypeName() { return mangledTypeName; } /** - * Gets the field name - * - * @return The field name + * {@return the field name} */ public String getFieldName() { return fieldName; @@ -91,11 +86,10 @@ public final class FieldRecord extends SwiftTypeMetadataStructure { @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType struct = new StructureDataType(getStructureName(), 0); + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); struct.add(DWORD, "Flags", ""); struct.add(SwiftUtils.PTR_STRING, "MangledTypeName", ""); struct.add(SwiftUtils.PTR_STRING, "FieldName", ""); - struct.setCategoryPath(new CategoryPath(DATA_TYPE_CATEGORY)); return struct; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericContextDescriptorFlags.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericContextDescriptorFlags.java new file mode 100644 index 0000000000..00e8ba5e1f --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericContextDescriptorFlags.java @@ -0,0 +1,110 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift {@code GenericRequirementFlags} structure + * + * @see swift/ABI/MetadataValues.h + */ +public class GenericContextDescriptorFlags extends SwiftTypeMetadataStructure { + + /** + * The size (in bytes) of a {@link GenericContextDescriptorFlags} structure + */ + public static final int SIZE = 2; + + private short flags; + + /** + * Create a new {@link GenericContextDescriptorFlags} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public GenericContextDescriptorFlags(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + flags = reader.readNextShort(); + } + + /** + * {@return the flags} + */ + public short getFlags() { + return flags; + } + + /** + * {@return whether or not the generic context has at least one type parameter pack, in which + * case the generic context will have a trailing GenericPackShapeHeader} + */ + public boolean hasTypePacks() { + return (flags & 0x1) != 0; + } + + /** + * {@return whether or not the generic context has any conditional conformances to inverted + * protocols, in which case the generic context will have a trailing InvertibleProtocolSet and + * conditional requirements} + */ + public boolean hasConditionalInvertedProtocols() { + return (flags & 0x2) != 0; + } + + /** + * {@return whether or not the generic context has at least one value parameter, in which case + * the generic context will have a trailing GenericValueHeader} + */ + public boolean hasValues() { + return (flags & 0x4) != 0; + } + + @Override + public String getStructureName() { + return GenericContextDescriptorFlags.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "generic context descriptor flags"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), SIZE); + struct.setPackingEnabled(true); + try { + struct.addBitField(BOOL, 1, "TypePacks", + "Has at least one type parameter pack and a trailing GenericPackShapeHeader."); + struct.addBitField(BOOL, 1, "ConditionalInvertedProtocols", + "Has any conditional conformances to inverted protocols and a trailing InvertibleProtocolSet and conditional requirements."); + struct.addBitField(BOOL, 1, "Values", + "Has at least one value parameter, and a trailing GenericValueHeader."); + struct.addBitField(WORD, 13, "reserved", null); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericParamDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericParamDescriptor.java new file mode 100644 index 0000000000..52e2273527 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericParamDescriptor.java @@ -0,0 +1,94 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift {@code GenericParamDescriptor} structure + * + * @see swift/ABI/MetadataValues.h + */ +public class GenericParamDescriptor extends SwiftTypeMetadataStructure { + + /** + * The size (in bytes) of a {@link GenericParamDescriptor} structure + */ + public static final int SIZE = 1; + + private int value; + + /** + * Create a new {@link GenericParamDescriptor} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public GenericParamDescriptor(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + value = reader.readNextUnsignedByte(); + } + + /** + * {@return the value} + */ + public int getValue() { + return value; + } + + /** + * {@return the {@link GenericParamKind}} + */ + public GenericParamKind getKind() { + return GenericParamKind.valueOf(value & 0x3f); + } + + /** + * {@return whether or not the subject type of the requirement has a key argument} + */ + public boolean hasKeyArgument() { + return (value & 0x80) != 0; + } + + @Override + public String getStructureName() { + return GenericParamDescriptor.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "generic param descriptor"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), SIZE); + struct.setPackingEnabled(true); + try { + struct.addBitField(GenericParamKind.values()[0].toDataType(), 7, "kind", null); + struct.addBitField(BOOL, 1, "HasKeyArgument", null); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericParamKind.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericParamKind.java new file mode 100644 index 0000000000..ff8371449e --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericParamKind.java @@ -0,0 +1,75 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; +import java.util.Arrays; + +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.EnumDataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Swift {@code GenericParamKind} values + * + * @see swift/ABI/MetadataValues.h + */ +public enum GenericParamKind implements StructConverter { + + Type(0), + TypePack(1), + Value(2); + + private int value; + + /** + * Creates a new {@link GenericRequirementKind} + * + * @param value The kind value + */ + private GenericParamKind(int value) { + this.value = value; + } + + /** + * {@return the kind value} + */ + public int getValue() { + return value; + } + + /** + * {@return the {@link GenericParamKind} with the given kind value, or {@code null} if it + * does not exist} + * + * @param value The kind value to get the value of + */ + public static GenericParamKind valueOf(int value) { + return Arrays.stream(values()).filter(e -> e.getValue() == value).findFirst().orElse(null); + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + EnumDataType dt = new EnumDataType(SwiftTypeMetadataStructure.CATEGORY_PATH, + GenericParamKind.class.getSimpleName(), 1); + for (GenericParamKind kind : values()) { + dt.add(kind.name(), kind.getValue()); + } + return dt; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericRequirementFlags.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericRequirementFlags.java new file mode 100644 index 0000000000..5c94f464f7 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericRequirementFlags.java @@ -0,0 +1,115 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift {@code GenericRequirementFlags} structure + * + * @see swift/ABI/MetadataValues.h + */ +public class GenericRequirementFlags extends SwiftTypeMetadataStructure { + + /** + * The size (in bytes) of a {@link GenericRequirementFlags} structure + */ + public static final int SIZE = 4; + + private int flags; + + /** + * Create a new {@link GenericRequirementFlags} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public GenericRequirementFlags(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + flags = reader.readNextInt(); + } + + /** + * {@return the flags} + */ + public int getFlags() { + return flags; + } + + /** + * {@return the {@link GenericRequirementKind}} + */ + public GenericRequirementKind getKind() { + return GenericRequirementKind.valueOf(flags & 0x1f); + } + + /** + * {@return whether or not the subject type of the requirement is a pack} + */ + public boolean isPackRequirement() { + return (flags & 0x20) != 0; + } + + /** + * {@return whether or not the subject type of the requirement has a key argument} + */ + public boolean hasKeyArgument() { + return (flags & 0x80) != 0; + } + + /** + * {@return whether or not the subject type of the requirement is a value} + */ + public boolean isValueRequirement() { + return (flags & 0x100) != 0; + } + + @Override + public String getStructureName() { + return GenericRequirementFlags.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "generic requirement flags"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), SIZE); + struct.setPackingEnabled(true); + try { + struct.addBitField(GenericRequirementKind.values()[0].toDataType(), 5, "kind", null); + struct.addBitField(BOOL, 1, "isPackRequirement", + "If true, the subject type of the requirement is a pack."); + struct.addBitField(BOOL, 1, "legacy", + "Don't set 0x40 for compatibility with pre-Swift 5.8 runtimes"); + struct.addBitField(BOOL, 1, "hasKeyArgument", null); + struct.addBitField(BOOL, 1, "isValueRequirement", + "If true, the subject type of the requirement is a value."); + struct.addBitField(DWORD, 23, "reserved", null); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericRequirementKind.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericRequirementKind.java new file mode 100644 index 0000000000..433facca5a --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericRequirementKind.java @@ -0,0 +1,79 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; +import java.util.Arrays; + +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.EnumDataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Swift {@code GenericRequirementKind} values + * + * @see swift/ABI/MetadataValues.h + */ +public enum GenericRequirementKind implements StructConverter { + + Protocol(0), + SameType(1), + BaseClass(2), + SameConformance(3), + SameShape(4), + IntertedProtocol(5), + Layout(0x1f); + + private int value; + + /** + * Creates a new {@link GenericRequirementKind} + * + * @param value The kind value + */ + private GenericRequirementKind(int value) { + this.value = value; + } + + /** + * {@return the kind value} + */ + public int getValue() { + return value; + } + + /** + * {@return the {@link GenericRequirementKind} with the given kind value, or {@code null} if it + * does not exist} + * + * @param value The kind value to get the value of + */ + public static GenericRequirementKind valueOf(int value) { + return Arrays.stream(values()).filter(e -> e.getValue() == value).findFirst().orElse(null); + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + EnumDataType dt = new EnumDataType(SwiftTypeMetadataStructure.CATEGORY_PATH, + GenericRequirementKind.class.getSimpleName(), 1); + for (GenericRequirementKind kind : values()) { + dt.add(kind.name(), kind.getValue()); + } + return dt; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericRequirementLayoutKind.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericRequirementLayoutKind.java new file mode 100644 index 0000000000..d9b82f0b9d --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/GenericRequirementLayoutKind.java @@ -0,0 +1,73 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; +import java.util.Arrays; + +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.EnumDataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Swift {@code GenericRequirementLayoutKind} values + * + * @see swift/ABI/MetadataValues.h + */ +public enum GenericRequirementLayoutKind implements StructConverter { + + Class(0); + + private int value; + + /** + * Creates a new {@link GenericRequirementLayoutKind} + * + * @param value The kind value + */ + private GenericRequirementLayoutKind(int value) { + this.value = value; + } + + /** + * {@return the kind value} + */ + public int getValue() { + return value; + } + + /** + * {@return the {@link GenericRequirementLayoutKind} with the given kind value, or {@code null} + * if it does not exist} + * + * @param value The kind value to get the value of + */ + public static GenericRequirementLayoutKind valueOf(int value) { + return Arrays.stream(values()).filter(e -> e.getValue() == value).findFirst().orElse(null); + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + EnumDataType dt = new EnumDataType(SwiftTypeMetadataStructure.CATEGORY_PATH, + GenericRequirementLayoutKind.class.getSimpleName(), 1); + for (GenericRequirementLayoutKind kind : values()) { + dt.add(kind.name(), kind.getValue()); + } + return dt; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MetadataInitializationKind.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MetadataInitializationKind.java new file mode 100644 index 0000000000..8a66e3aca4 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MetadataInitializationKind.java @@ -0,0 +1,75 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; +import java.util.Arrays; + +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.EnumDataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Swift {@code MetadataInitializationKind} values + * + * @see swift/ABI/MetadataValues.h + */ +public enum MetadataInitializationKind implements StructConverter { + + NoMetadataInitialization(0), + SingletonMetadataInitialization(1), + ForeignMetadataInitialization(2); + + private int value; + + /** + * Creates a new {@link MetadataInitializationKind} + * + * @param value The kind value + */ + private MetadataInitializationKind(int value) { + this.value = value; + } + + /** + * {@return the kind value} + */ + public int getValue() { + return value; + } + + /** + * {@return the {@link MetadataInitializationKind} with the given kind value, or {@code null} if it + * does not exist} + * + * @param value The kind value to get the value of + */ + public static MetadataInitializationKind valueOf(int value) { + return Arrays.stream(values()).filter(e -> e.getValue() == value).findFirst().orElse(null); + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + EnumDataType dt = new EnumDataType(SwiftTypeMetadataStructure.CATEGORY_PATH, + MetadataInitializationKind.class.getSimpleName(), 1); + for (MetadataInitializationKind kind : values()) { + dt.add(kind.name(), kind.getValue()); + } + return dt; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MetadataSourceRecord.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MetadataSourceRecord.java index ca9e40840d..7e42a69ebc 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MetadataSourceRecord.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MetadataSourceRecord.java @@ -20,11 +20,12 @@ import java.io.IOException; import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; import ghidra.app.util.bin.format.swift.SwiftUtils; -import ghidra.program.model.data.*; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; import ghidra.util.exception.DuplicateNameException; /** - * Represents a Swift MetadataSourceRecord structure + * Represents a Swift {@code MetadataSourceRecord} structure * * @see swift/RemoteInspection/Records.h */ @@ -51,18 +52,14 @@ public final class MetadataSourceRecord extends SwiftTypeMetadataStructure { } /** - * Gets the mangled type name - * - * @return The mangled type name + * {@return the mangled type name} */ public String getMangledTypeName() { return mangledTypeName; } /** - * Gets the mangled metadata source - * - * @return The mangled metadata source + * {@return the mangled metadata source} */ public String getMangledMetadataSource() { return mangledMetadataSource; @@ -80,10 +77,9 @@ public final class MetadataSourceRecord extends SwiftTypeMetadataStructure { @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType struct = new StructureDataType(getStructureName(), 0); + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); struct.add(SwiftUtils.PTR_STRING, "MangledTypeName", ""); struct.add(SwiftUtils.PTR_STRING, "MangledMetadataSource", ""); - struct.setCategoryPath(new CategoryPath(DATA_TYPE_CATEGORY)); return struct; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MethodDescriptorFlags.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MethodDescriptorFlags.java new file mode 100644 index 0000000000..be241dfabd --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MethodDescriptorFlags.java @@ -0,0 +1,119 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift {@code MethodDescriptorFlags} structure + * + * @see swift/ABI/MetadataValues.h + */ +public class MethodDescriptorFlags extends SwiftTypeMetadataStructure { + + /** + * The size (in bytes) of a {@link MethodDescriptorFlags} structure + */ + public static final int SIZE = 4; + + private int flags; + + /** + * Create a new {@link MethodDescriptorFlags} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public MethodDescriptorFlags(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + flags = reader.readNextInt(); + } + + /** + * {@return the flags} + */ + public int getFlags() { + return flags; + } + + /** + * {@return the {@link MethodDescriptorKind}} + */ + public MethodDescriptorKind getKind() { + return MethodDescriptorKind.valueOf(flags & 0x0f); + } + + /** + * {@return whether or not the method is an instance method} + */ + public boolean isInstance() { + return (flags & 0x10) != 0; + } + + /** + * {@return whether or not the method is dynamic} + */ + public boolean isDynamic() { + return (flags & 0x20) != 0; + } + + /** + * {@return whether or not the method is async} + */ + public boolean isAnsyc() { + return (flags & 0x40) != 0; + } + + /** + * {@return the extra descriminator} + */ + public int getExtraDescriminator() { + return (flags >> 16) & 0xffff; + } + + @Override + public String getStructureName() { + return MethodDescriptorFlags.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "method descriptor flags"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), SIZE); + struct.setPackingEnabled(true); + try { + struct.addBitField(MethodDescriptorKind.values()[0].toDataType(), 4, "kind", null); + struct.addBitField(BOOL, 1, "IsInstance", null); + struct.addBitField(BOOL, 1, "IsDynamic", null); + struct.addBitField(BOOL, 1, "IsAsync", null); + struct.addBitField(DWORD, 9, "reserved", null); + struct.addBitField(DWORD, 16, "ExtraDescriminator", null); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MethodDescriptorKind.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MethodDescriptorKind.java new file mode 100644 index 0000000000..c5d418f364 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MethodDescriptorKind.java @@ -0,0 +1,78 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; +import java.util.Arrays; + +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.EnumDataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Swift {@code MethodDescriptorFlags.Kind} values + * + * @see swift/ABI/MetadataValues.h + */ +public enum MethodDescriptorKind implements StructConverter { + + Method(0), + Init(1), + Getter(2), + Setter(3), + ModifyCoroutine(4), + ReadCoroutine(5); + + private int value; + + /** + * Creates a new {@link MethodDescriptorKind} + * + * @param value The kind value + */ + private MethodDescriptorKind(int value) { + this.value = value; + } + + /** + * {@return the kind value} + */ + public int getValue() { + return value; + } + + /** + * {@return the {@link MethodDescriptorKind} with the given kind value, or {@code null} if it + * does not exist} + * + * @param value The kind value to get the value of + */ + public static MethodDescriptorKind valueOf(int value) { + return Arrays.stream(values()).filter(e -> e.getValue() == value).findFirst().orElse(null); + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + EnumDataType dt = new EnumDataType(SwiftTypeMetadataStructure.CATEGORY_PATH, + MethodDescriptorKind.class.getSimpleName(), 1); + for (MethodDescriptorKind kind : values()) { + dt.add(kind.name(), kind.getValue()); + } + return dt; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MultiPayloadEnumDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MultiPayloadEnumDescriptor.java index b2ce21a104..af967f4277 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MultiPayloadEnumDescriptor.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MultiPayloadEnumDescriptor.java @@ -24,7 +24,7 @@ import ghidra.program.model.data.DataType; import ghidra.util.exception.DuplicateNameException; /** - * Represents a Swift MultiPayloadEnumDescriptor structure + * Represents a Swift {@code MultiPayloadEnumDescriptor} structure * * @see swift/RemoteInspection/Records.h */ @@ -32,7 +32,7 @@ public final class MultiPayloadEnumDescriptor extends SwiftTypeMetadataStructure /** * The size (in bytes) of a {@link MultiPayloadEnumDescriptor} structure. This size does not - * take into account the size of the contents array. + * take into account the size of the {@code contents} array. * * @see #getContentsSize() */ @@ -56,27 +56,21 @@ public final class MultiPayloadEnumDescriptor extends SwiftTypeMetadataStructure } /** - * Gets the type name - * - * @return The type name + * {@return the type name} */ public String getTypeName() { return typeName; } /** - * Gets the contents - * - * @return The contents + * {@return the contents} */ public int[] getContents() { return contents; } /** - * Gets the size of the contents in bytes - * - * @return The size of the contents in bytes + * {@return The size of the contents in bytes} */ public long getContentsSize() { return contents.length * Integer.BYTES; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ProtocolRequirementFlags.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ProtocolRequirementFlags.java new file mode 100644 index 0000000000..16852b43b8 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ProtocolRequirementFlags.java @@ -0,0 +1,111 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift {@code ProtocolRequirementFlags} structure + * + * @see swift/ABI/MetadataValues.h + */ +public class ProtocolRequirementFlags extends SwiftTypeMetadataStructure { + + /** + * The size (in bytes) of a {@link ProtocolRequirementFlags} structure + */ + public static final int SIZE = 4; + + private int flags; + + /** + * Create a new {@link ProtocolRequirementFlags} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public ProtocolRequirementFlags(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + flags = reader.readNextInt(); + } + + /** + * {@return the flags} + */ + public int getFlags() { + return flags; + } + + /** + * {@return the {@link ProtocolRequirementKind}} + */ + public ProtocolRequirementKind getKind() { + return ProtocolRequirementKind.valueOf(flags & 0x0f); + } + + /** + * {@return whether or not the protocol requirement is instance} + */ + public boolean isInstance() { + return (flags & 0x10) != 0; + } + + /** + * {@return whether or not the protocol requirement is async} + */ + public boolean isAnsyc() { + return (flags & 0x20) != 0; + } + + /** + * {@return the extra descriminator} + */ + public int getExtraDescriminator() { + return (flags >> 16) & 0xffff; + } + + @Override + public String getStructureName() { + return ProtocolRequirementFlags.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "protocol requirements flags"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), SIZE); + struct.setPackingEnabled(true); + try { + struct.addBitField(getKind().toDataType(), 4, "kind", null); + struct.addBitField(BOOL, 1, "IsInstance", null); + struct.addBitField(BOOL, 1, "IsAsync", null); + struct.addBitField(DWORD, 10, "reserved", null); + struct.addBitField(DWORD, 16, "ExtraDescriminator", null); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ProtocolRequirementKind.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ProtocolRequirementKind.java new file mode 100644 index 0000000000..7635030695 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ProtocolRequirementKind.java @@ -0,0 +1,81 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; +import java.util.Arrays; + +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.EnumDataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Swift {@code ProtocolRequirementFlags.Kind} values + * + * @see swift/ABI/MetadataValues.h + */ +public enum ProtocolRequirementKind implements StructConverter { + + BaseProtocol(0), + Method(1), + Init(2), + Getter(3), + Setter(4), + ReadCoroutine(5), + ModifyCoroutine(6), + AssociatedTypeAccessFunction(7), + AssociatedConformanceAccessFunction(8); + + private int value; + + /** + * Creates a new {@link ProtocolRequirementKind} + * + * @param value The kind value + */ + private ProtocolRequirementKind(int value) { + this.value = value; + } + + /** + * {@return the kind value} + */ + public int getValue() { + return value; + } + + /** + * {@return the {@link ProtocolRequirementKind} with the given kind value, or {@code null} if it + * does not exist} + * + * @param value The kind value to get the value of + */ + public static ProtocolRequirementKind valueOf(int value) { + return Arrays.stream(values()).filter(e -> e.getValue() == value).findFirst().orElse(null); + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + EnumDataType dt = new EnumDataType(SwiftTypeMetadataStructure.CATEGORY_PATH, + ProtocolRequirementKind.class.getSimpleName(), 1); + for (ProtocolRequirementKind kind : values()) { + dt.add(kind.name(), kind.getValue()); + } + return dt; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetClassDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetClassDescriptor.java index 62ca353b71..736f705ee5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetClassDescriptor.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetClassDescriptor.java @@ -16,14 +16,17 @@ package ghidra.app.util.bin.format.swift.types; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; import ghidra.app.util.bin.format.swift.SwiftUtils; import ghidra.program.model.data.*; import ghidra.util.exception.DuplicateNameException; /** - * Represents a Swift TargetClassDescriptor structure + * Represents a Swift {@code TargetClassDescriptor} structure * * @see swift/ABI/Metadata.h */ @@ -31,11 +34,24 @@ public final class TargetClassDescriptor extends TargetTypeContextDescriptor { private int superclassType; private int metadataNegativeSizeInWords; + private int resilientMetadataBounds; private int metadataPositiveSizeInWords; + private ExtraClassDescriptorFlags extraClassFlags; private int numImmediateMembers; private int numFields; private int fieldOffsetVectorOffset; + // Trailing Objects + private TargetTypeGenericContextDescriptorHeader genericHeader; + private TargetResilientSuperclass resilientSuperclass; + private TargetSingletonMetadataInitialization singleton; + private TargetForeignMetadataInitialization foreign; + private TargetVTableDescriptorHeader vtableHeader; + private List methodDescriptors = new ArrayList<>(); + private TargetOverrideTableHeader overrideHeader; + private List methodOverrideDescriptors = new ArrayList<>(); + private TargetObjCResilientClassStubInfo objcResilientClassStub; + /** * Creates a new {@link TargetClassDescriptor} * @@ -45,79 +61,231 @@ public final class TargetClassDescriptor extends TargetTypeContextDescriptor { public TargetClassDescriptor(BinaryReader reader) throws IOException { super(reader); superclassType = reader.readNextInt(); - metadataNegativeSizeInWords = reader.readNextInt(); - metadataPositiveSizeInWords = reader.readNextInt(); + resilientMetadataBounds = reader.readNextInt(); + metadataNegativeSizeInWords = resilientMetadataBounds; // union + extraClassFlags = new ExtraClassDescriptorFlags(reader); + metadataPositiveSizeInWords = extraClassFlags.getFlags(); // union numImmediateMembers = reader.readNextInt(); numFields = reader.readNextInt(); fieldOffsetVectorOffset = reader.readNextInt(); + + if (flags.isGeneric()) { + genericHeader = new TargetTypeGenericContextDescriptorHeader(reader); + } + + if (flags.hasClassResilientSuperclass()) { + resilientSuperclass = new TargetResilientSuperclass(reader); + } + + switch (flags.getMetadataInitialization()) { + case NoMetadataInitialization: + break; + case SingletonMetadataInitialization: + singleton = new TargetSingletonMetadataInitialization(reader, flags); + break; + case ForeignMetadataInitialization: + foreign = new TargetForeignMetadataInitialization(reader); + break; + } + + if (flags.hasClassVTable()) { + vtableHeader = new TargetVTableDescriptorHeader(reader); + for (int i = 0; i < vtableHeader.getVTableSize(); i++) { + methodDescriptors.add(new TargetMethodDescriptor(reader)); + } + } + + if (flags.hasClassOverrideTable()) { + overrideHeader = new TargetOverrideTableHeader(reader); + for (int i = 0; i < overrideHeader.getNumEntries(); i++) { + methodOverrideDescriptors.add(new TargetMethodOverrideDescriptor(reader)); + } + } + + if (flags.hasClassResilientSuperclass() && + extraClassFlags.hasObjcResilientClassStub()) { + objcResilientClassStub = new TargetObjCResilientClassStubInfo(reader); + } + + if (flags.isGeneric() && + flags.hasCanonicalMetadataPrespecializationsOrSingletonMetadataPonter()) { + throw new IOException("Unimplemented TargetCanonicalSpecializedMetadatas detected."); + } + + if (flags.hasInvertableProtocols()) { + throw new IOException("Unimplemented InvertibleProtocolSet detected."); + } + + if (!flags.isGeneric() && + flags.hasCanonicalMetadataPrespecializationsOrSingletonMetadataPonter()) { + throw new IOException("Unimplemented TargetSingletonMetadataPointer detected."); + } + + if (flags.hasClassDefaultOverrideTable()) { + throw new IOException("Unimplemented TargetMethodDefaultOverride detected."); + } } /** - * Gets the type of the superclass, expressed as a mangled type name that can refer to the - * generic arguments of the subclass type - * - * @return The type of the superclass, expressed as a mangled type name that can refer to the - * generic arguments of the subclass type + * {@return the type of the superclass, expressed as a mangled type name that can refer to the + * generic arguments of the subclass type} */ public int getSuperclassType() { return superclassType; } /** - * If this descriptor does not have a resilient superclass, this is the negative size of - * metadata objects of this class (in words). If this descriptor has a resilient superclass, - * this is a reference to a cache holding the metadata's extents. - * - * @return The negative size of metadata objects of this class (in words) or a reference to a - * cache holding the metadata's extents + * {@return a reference to a cache holding the metadata's extents if this descriptor has a + * resilient superclass; otherwise, 0} + */ + public int getResilientMetadataBounds() { + return flags.hasClassResilientSuperclass() ? resilientMetadataBounds : 0; + } + + /** + * {@return the negative size of metadata objects of this class (in words) if this descriptor + * does not have a resilient superclass} */ public int getMetadataNegativeSizeInWords() { - return metadataNegativeSizeInWords; + return !flags.hasClassResilientSuperclass() ? metadataNegativeSizeInWords : 0; } /** - * If this descriptor does not have a resilient superclass, this is the positive size of - * metadata objects of this class (in words). Otherwise, these flags are used to do things like - * indicate the presence of an Objective-C resilient class stub. - * - * @return The positive size of metadata objects of this class (in words) or flags used to do - * things like indicate the presence of an Objective-C resilient class stub. + * {@return flags used to do things like indicate the presence of an Objective-C resilient class + * stub if this descriptor has a resilient superclass; otherwise, {@code null}} + */ + public ExtraClassDescriptorFlags getExtraClassDescriptorFlags() { + return flags.hasClassResilientSuperclass() ? extraClassFlags : null; + } + + /** + * {@return the positive size of metadata objects of this class (in words) if this descriptor + * does not have a resilient superclass} */ public int getMetadataPositiveSizeInWords() { - return metadataPositiveSizeInWords; + return !flags.hasClassResilientSuperclass() ? metadataPositiveSizeInWords : 0; } /** - * Gets the number of additional members added by this class to the class metadata - * - * @return The number of additional members added by this class to the class metadata + * {@return the number of additional members added by this class to the class metadata} */ public int getNumImmediateMembers() { return numImmediateMembers; } /** - * Gets the number of stored properties in the class, not including its superclasses. If there - * is a field offset vector, this is its length. - * - * @return The number of stored properties in the class, not including its superclasses. - * If there is a field offset vector, this is its length. + * {@return the number of stored properties in the class, not including its superclasses} + *

+ * If there is a field offset vector, this is its length. */ public int getNumFields() { return numFields; } /** - * Gets the offset of the field offset vector for this class's stored properties in its - * metadata, in words. 0 means there is no field offset vector. - * - * @return THe offset of the field offset vector for this class's stored properties in its - * metadata, in words. 0 means there is no field offset vector. + * {@return the offset of the field offset vector for this class's stored properties in its + * metadata, in words (0 means there is no field offset vector)} */ public int getFieldOffsetVectorOffset() { return fieldOffsetVectorOffset; } + /** + * {@return the {@link TargetTypeGenericContextDescriptorHeader}, or {@code null} if it doesn't + * exist} + */ + public TargetTypeGenericContextDescriptorHeader getGenericHeader() { + return genericHeader; + } + + /** + * {@return the {@link TargetResilientSuperclass}, or {@code null} if it doesn't exist} + */ + public TargetResilientSuperclass getResilientSuperclass() { + return resilientSuperclass; + } + + /** + * {@return the {@link TargetSingletonMetadataInitialization}, or {@code null} if it doesn't + * exist} + */ + public TargetSingletonMetadataInitialization getTargetSingletonMetadataInitialization() { + return singleton; + } + + /** + * {@return the {@link TargetForeignMetadataInitialization}, or {@code null} if it doesn't + * exist} + */ + public TargetForeignMetadataInitialization getTargetForeignMetadataInitialization() { + return foreign; + } + + /** + * {@return the {@link TargetVTableDescriptorHeader}, or {@code null} if it doesn't exist} + */ + public TargetVTableDescriptorHeader getVTableDescriptorHeader() { + return vtableHeader; + } + + /** + * {@return the {@link List} of method descriptors} + */ + public List getMethodDescriptors() { + return methodDescriptors; + } + + /** + * {@return the {@link TargetOverrideTableHeader}, or {@code null} if it doesn't exist} + */ + public TargetOverrideTableHeader getTargetOverrideTableHeader() { + return overrideHeader; + } + + /** + * {@return the {@link List} of method override descriptors} + */ + public List getMethodOverrideDescriptors() { + return methodOverrideDescriptors; + } + + /** + * {@return the {@link TargetObjCResilientClassStubInfo}, or {@code null} if it doesn't exist} + */ + public TargetObjCResilientClassStubInfo getObjcResilientClassStub() { + return objcResilientClassStub; + } + + @Override + public List getTrailingObjects() { + List ret = new ArrayList<>(); + if (genericHeader != null) { + ret.add(genericHeader); + ret.addAll(genericHeader.getTrailingObjects()); + } + if (resilientSuperclass != null) { + ret.add(resilientSuperclass); + } + if (singleton != null) { + ret.add(singleton); + } + if (foreign != null) { + ret.add(foreign); + } + if (vtableHeader != null) { + ret.add(vtableHeader); + ret.addAll(methodDescriptors); + } + if (overrideHeader != null) { + ret.add(overrideHeader); + ret.addAll(methodOverrideDescriptors); + } + if (objcResilientClassStub != null) { + ret.add(objcResilientClassStub); + } + return ret; + } + @Override public String getStructureName() { return TargetClassDescriptor.class.getSimpleName(); @@ -130,22 +298,32 @@ public final class TargetClassDescriptor extends TargetTypeContextDescriptor { @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType struct = new StructureDataType(getStructureName(), 0); + UnionDataType union1 = new UnionDataType(CATEGORY_PATH, + "Union_MetadataNegativeSizeInWords_ResilientMetadataBounds"); + union1.add(DWORD, "MetadataNegativeSizeInWords", + "If this descriptor does not have a resilient superclass, this is the negative size of metadata objects of this class (in words)"); + union1.add(SwiftUtils.PTR_RELATIVE, "ResilientMetadataBounds", + "If this descriptor has a resilient superclass, this is a reference to a cache holding the metadata's extends."); + + UnionDataType union2 = + new UnionDataType(CATEGORY_PATH, "Union_MetadataPositiveSizeInWords/ExtraClassFlags"); + union2.add(DWORD, "MetadataPositiveSizeInWords", + "If this descriptor does not have a resilient superclass, this is the positive size of metadata objects of this class (in words)"); + union2.add(extraClassFlags.toDataType(), "ExtraClassFlags", + "Otherwise, these flags are used to do things like indicating the presence of an Objective-C resilient class stub."); + + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); struct.add(super.toDataType(), super.getStructureName(), ""); struct.add(SwiftUtils.PTR_STRING, "SuperclassType", "The type of the superclass, expressed as a mangled type name that can refer to the generic arguments of the subclass type"); - struct.add(DWORD, "MetadataNegativeSizeInWords", - "If this descriptor does not have a resilient superclass, this is the negative size of metadata objects of this class (in words)"); - struct.add(DWORD, "MetadataPositiveSizeInWords", - "If this descriptor does not have a resilient superclass, this is the positive size of metadata objects of this class (in words)"); + struct.add(union1, "MetadataNegativeSizeInWords/ResilientMetadataBounds", null); + struct.add(union2, "MetadataPositiveSizeInWords/ExtraClassFlags", null); struct.add(DWORD, "NumImmediateMembers", "The number of additional members added by this class to the class metadata"); struct.add(DWORD, "NumFields", "The number of stored properties in the class, not including its superclasses. If there is a field offset vector, this is its length."); struct.add(DWORD, "FieldOffsetVectorOffset", "The offset of the field offset vector for this class's stored properties in its metadata, in words. 0 means there is no field offset vector."); - struct.setCategoryPath(new CategoryPath(DATA_TYPE_CATEGORY)); return struct; } - } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetContextDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetContextDescriptor.java index 8379642bc6..7d3a107376 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetContextDescriptor.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetContextDescriptor.java @@ -20,11 +20,12 @@ import java.io.IOException; import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; import ghidra.app.util.bin.format.swift.SwiftUtils; -import ghidra.program.model.data.*; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; import ghidra.util.exception.DuplicateNameException; /** - * Represents a Swift TargetContextDescriptor structure + * Represents a Swift {@code TargetContextDescriptor} structure * * @see swift/ABI/Metadata.h */ @@ -35,7 +36,7 @@ public class TargetContextDescriptor extends SwiftTypeMetadataStructure { */ public static final int SIZE = 8; - private int flags; + protected ContextDescriptorFlags flags; private int parent; /** @@ -46,23 +47,19 @@ public class TargetContextDescriptor extends SwiftTypeMetadataStructure { */ public TargetContextDescriptor(BinaryReader reader) throws IOException { super(reader.getPointerIndex()); - flags = reader.readNextInt(); + flags = new ContextDescriptorFlags(reader); parent = reader.readNextInt(); } /** - * Gets the flags - * - * @return The flags + * {@return the flags} */ - public int getFlags() { + public ContextDescriptorFlags getFlags() { return flags; } /** - * Gets the parent's relative offset - * - * @return The parent's relative offset + * {@return the parent's relative offset} */ public int getParent() { return parent; @@ -79,9 +76,7 @@ public class TargetContextDescriptor extends SwiftTypeMetadataStructure { } /** - * Gets this class's structure name (will not be affected by subclass's name) - * - * @return This class's structure name + * {@return this class's structure name (will not be affected by subclass's name)} */ private final String getMyStructureName() { return TargetContextDescriptor.class.getSimpleName(); @@ -89,12 +84,11 @@ public class TargetContextDescriptor extends SwiftTypeMetadataStructure { @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType struct = new StructureDataType(getMyStructureName(), 0); - struct.add(DWORD, "Flags", + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getMyStructureName(), 0); + struct.add(flags.toDataType(), "Flags", "Flags describing the context, including its kind and format version"); - struct.add(SwiftUtils.PTR_RELATIVE, "Parent", + struct.add(SwiftUtils.PTR_RELATIVE_MASKED, "Parent", "The parent context, or null if this is a top-level context"); - struct.setCategoryPath(new CategoryPath(DATA_TYPE_CATEGORY)); return struct; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetEnumDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetEnumDescriptor.java index 4301205ab6..c1101bfd47 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetEnumDescriptor.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetEnumDescriptor.java @@ -16,15 +16,17 @@ package ghidra.app.util.bin.format.swift.types; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import ghidra.app.util.bin.BinaryReader; -import ghidra.program.model.data.CategoryPath; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; import ghidra.program.model.data.DataType; import ghidra.program.model.data.StructureDataType; import ghidra.util.exception.DuplicateNameException; /** - * Represents a Swift TargetEnumDescriptor structure + * Represents a Swift {@code TargetEnumDescriptor} structure * * @see swift/ABI/Metadata.h */ @@ -33,6 +35,11 @@ public final class TargetEnumDescriptor extends TargetTypeContextDescriptor { private int numPayloadCasesAndPayloadSizeOffset; private int numEmptyCases; + // Trailing objects + private TargetTypeGenericContextDescriptorHeader genericHeader; + private TargetSingletonMetadataInitialization singleton; + private TargetForeignMetadataInitialization foreign; + /** * Creates a new {@link TargetEnumDescriptor} * @@ -43,6 +50,35 @@ public final class TargetEnumDescriptor extends TargetTypeContextDescriptor { super(reader); numPayloadCasesAndPayloadSizeOffset = reader.readNextInt(); numEmptyCases = reader.readNextInt(); + + if (flags.isGeneric()) { + genericHeader = new TargetTypeGenericContextDescriptorHeader(reader); + } + + switch (flags.getMetadataInitialization()) { + case NoMetadataInitialization: + break; + case SingletonMetadataInitialization: + singleton = new TargetSingletonMetadataInitialization(reader, flags); + break; + case ForeignMetadataInitialization: + foreign = new TargetForeignMetadataInitialization(reader); + break; + } + + if (flags.isGeneric() && + flags.hasCanonicalMetadataPrespecializationsOrSingletonMetadataPonter()) { + throw new IOException("Unimplemented TargetCanonicalSpecializedMetadatas detected."); + } + + if (flags.hasInvertableProtocols()) { + throw new IOException("Unimplemented InvertibleProtocolSet detected."); + } + + if (!flags.isGeneric() && + flags.hasCanonicalMetadataPrespecializationsOrSingletonMetadataPonter()) { + throw new IOException("Unimplemented TargetSingletonMetadataPointer detected."); + } } /** @@ -56,14 +92,52 @@ public final class TargetEnumDescriptor extends TargetTypeContextDescriptor { } /** - * Gets the number of empty cases in the enum - * - * @return The number of empty cases in the enum + * {@return the number of empty cases in the enum} */ public int getNumEmptyCases() { return numEmptyCases; } + /** + * {@return the {@link TargetTypeGenericContextDescriptorHeader}, or {@code null} if it doesn't + * exist} + */ + public TargetTypeGenericContextDescriptorHeader getGenericHeader() { + return genericHeader; + } + + /** + * {@return the {@link TargetSingletonMetadataInitialization}, or {@code null} if it doesn't + * exist} + */ + public TargetSingletonMetadataInitialization getTargetSingletonMetadataInitialization() { + return singleton; + } + + /** + * {@return the {@link TargetForeignMetadataInitialization}, or {@code null} if it doesn't + * exist} + */ + public TargetForeignMetadataInitialization getTargetForeignMetadataInitialization() { + return foreign; + } + + @Override + public List getTrailingObjects() { + List ret = new ArrayList<>(); + if (genericHeader != null) { + ret.add(genericHeader); + ret.addAll(genericHeader.getTrailingObjects()); + } + if (singleton != null) { + ret.add(singleton); + } + if (foreign != null) { + ret.add(foreign); + } + return ret; + } + @Override public String getStructureName() { return TargetEnumDescriptor.class.getSimpleName(); @@ -76,12 +150,11 @@ public final class TargetEnumDescriptor extends TargetTypeContextDescriptor { @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType struct = new StructureDataType(getStructureName(), 0); + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); struct.add(super.toDataType(), super.getStructureName(), ""); struct.add(DWORD, "NumPayloadCasesAndPayloadSizeOffset", "The number of non-empty cases in the enum are in the low 24 bits; the offset of the payload size in the metadata record in words, if any, is stored in the high 8 bits."); struct.add(DWORD, "NumEmptyCases", "The number of empty cases in the enum"); - struct.setCategoryPath(new CategoryPath(DATA_TYPE_CATEGORY)); return struct; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetForeignMetadataInitialization.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetForeignMetadataInitialization.java new file mode 100644 index 0000000000..729984a67c --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetForeignMetadataInitialization.java @@ -0,0 +1,71 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.app.util.bin.format.swift.SwiftUtils; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift {@code TargetForeignMetadataInitialization} structure + * + * @see swift/ABI/Metadata.h + */ +public class TargetForeignMetadataInitialization extends SwiftTypeMetadataStructure { + + private int completionFunction; + + /** + * Creates a new {@link TargetForeignMetadataInitialization} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public TargetForeignMetadataInitialization(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + completionFunction = reader.readNextInt(); + } + + /** + * {@return the completion function (the pattern will always be null)} + */ + public int getCompletionFunction() { + return completionFunction; + } + + @Override + public String getStructureName() { + return TargetForeignMetadataInitialization.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "foreign metadata initialization"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); + struct.add(SwiftUtils.PTR_RELATIVE, "CompletionFunction", + "The completion function. The pattern will always be null."); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetGenericContextDescriptorHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetGenericContextDescriptorHeader.java new file mode 100644 index 0000000000..25437d896e --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetGenericContextDescriptorHeader.java @@ -0,0 +1,144 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift {@code TargetGenericContextDescriptorHeader} structure + * + * @see swift/ABI/GenericContext.h + */ +public class TargetGenericContextDescriptorHeader extends SwiftTypeMetadataStructure { + + private int numParams; + private int numRequirements; + private int numKeyArguments; + private GenericContextDescriptorFlags flags; + + private List params = new ArrayList<>(); + private List requirements = new ArrayList<>(); + + /** + * Creates a new {@link TargetGenericContextDescriptorHeader} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public TargetGenericContextDescriptorHeader(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + numParams = reader.readNextUnsignedShort(); + numRequirements = reader.readNextUnsignedShort(); + numKeyArguments = reader.readNextUnsignedShort(); + flags = new GenericContextDescriptorFlags(reader); + + for (int i = 0; i < numParams; i++) { + params.add(new GenericParamDescriptor(reader)); + } + + // It seems we have to round to the next 4 byte boundary after reading the params??? + reader.setPointerIndex((reader.getPointerIndex() + 3) & (~3)); + + for (int i = 0; i < numRequirements; i++) { + requirements.add(new TargetGenericRequirementsDescriptor(reader)); + } + } + + /** + * {@return the number of (source-written) generic parameters, and thus the number of + * GenericParamDescriptors associated with this context} + */ + public int getNumParams() { + return numParams; + } + + /** + * {@return the number of GenericRequirementDescriptors in this generic signature} + */ + public int getNumRequirements() { + return numRequirements; + } + + /** + * {@return the size of the "key" area of the argument layout, in words} + *

+ * Key arguments include shape classes, generic parameters, and conformance requirements which + * are part of the identity of the context. + */ + public int getNumKeyArguments() { + return numKeyArguments; + } + + /** + * {@return the flags} + */ + public GenericContextDescriptorFlags getFlags() { + return flags; + } + + /** + * {@return the {@link List} of generic parameter descriptors} + */ + public List getParams() { + return params; + } + + /** + * {@return the {@link List} of generic requirements descriptors} + */ + public List getRequirements() { + return requirements; + } + + @Override + public List getTrailingObjects() { + List ret = new ArrayList<>(); + ret.addAll(params); + ret.addAll(requirements); + return ret; + } + + @Override + public String getStructureName() { + return TargetGenericContextDescriptorHeader.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "generic context descriptor header"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); + struct.add(WORD, "NumParams", + "The number of (source-written) generic parameters, and thus the number of GenericParamDescriptors associated with this context."); + struct.add(WORD, "NumRequirements", + "The number of GenericRequirementDescriptors in this generic signature."); + struct.add(WORD, "NumKeyArguments", + "The size of the key area of the argument layout, in words."); + struct.add(flags.toDataType(), "Flags", ""); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetGenericRequirementsDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetGenericRequirementsDescriptor.java new file mode 100644 index 0000000000..a202e645ed --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetGenericRequirementsDescriptor.java @@ -0,0 +1,132 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.app.util.bin.format.swift.SwiftUtils; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +public class TargetGenericRequirementsDescriptor extends SwiftTypeMetadataStructure { + + private GenericRequirementFlags flags; + private int param; + private int thing; + private GenericRequirementLayoutKind layout; + private int genericParamIndex; + private int protocols; // TODO: Make this a real InvertibleProtocolSet + + /** + * Creates a new {@link TargetGenericRequirementsDescriptor} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public TargetGenericRequirementsDescriptor(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + flags = new GenericRequirementFlags(reader); + param = reader.readNextInt(); + thing = reader.readNextInt(); + layout = GenericRequirementLayoutKind.valueOf(thing); // union + genericParamIndex = thing & 0xffff; // union + protocols = (thing) & 0xffff; // union + } + + /** + * {@return the flags} + */ + public GenericRequirementFlags getFlags() { + return flags; + } + + /** + * {@return the type that's constrained, described as a mangled name} + */ + public int getParam() { + return param; + } + + /** + * {@return the thing (same-type, class, protocol, conformance) the param is constrained to} + */ + public int getThing() { + return thing; + } + + /** + * {@return the layout if the requirement has Layout kind; otherwise, {@code null}} + */ + public GenericRequirementLayoutKind getLayout() { + return layout; + } + + /** + * {@return the index of the generic parameter whose set of invertible protocols has disabled + * checks} + *

+ * Only valid if the requirement has {@link GenericRequirementKind#IntertedProtocol} kind + */ + public int getGenericParamIndex() { + return genericParamIndex; + } + + /** + * {@return the set of invertible protocols whose check is disabled} + *

+ * Only valid if the requirement has {@link GenericRequirementKind#IntertedProtocol} kind + */ + public int getProtocols() { + return protocols; + } + + @Override + public String getStructureName() { + return TargetGenericRequirementsDescriptor.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "generic requirements descriptor"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType invertedProtocolsStruct = new StructureDataType(CATEGORY_PATH, "InvertedProtocols", 0); + invertedProtocolsStruct.add(WORD, "GenericParamIndex", + "The index of the generic parameter to which this applies."); + invertedProtocolsStruct.add(WORD, "Protocols", + "The set of invertiable protocols whose check is disabled."); + + UnionDataType union = + new UnionDataType(CATEGORY_PATH, "Union_TargetGenericRequirementsDescriptor"); + union.add(SwiftUtils.PTR_RELATIVE, "Type", "A mangled representation of the same-type or base class the param is constrained to."); + union.add(SwiftUtils.PTR_RELATIVE, "Protocol", "The protocol the param is constrained to."); + union.add(SwiftUtils.PTR_RELATIVE, "Conformance", "The conformance the param is constrained to use."); + union.add(GenericRequirementLayoutKind.values()[0].toDataType(), "Layout", + "The kind of layout constraint."); + union.add(invertedProtocolsStruct, invertedProtocolsStruct.getName(), null); + + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); + struct.add(flags.toDataType(), "Flags", null); + struct.add(SwiftUtils.PTR_RELATIVE, "Param", + "The type that's constrained, described as a mangled name."); + struct.add(union, union.getName(), null); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetGenericWitnessTable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetGenericWitnessTable.java new file mode 100644 index 0000000000..ae41b7efae --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetGenericWitnessTable.java @@ -0,0 +1,104 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.app.util.bin.format.swift.SwiftUtils; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; +import ghidra.util.exception.DuplicateNameException; + +public class TargetGenericWitnessTable extends SwiftTypeMetadataStructure { + + private int witnessTableSizeInWords; + private int witnessTablePrivateSizeInWordsAndRequiresInstantiation; + private int instantiator; + private int privateData; + + /** + * Creates a new {@link TargetGenericWitnessTable} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public TargetGenericWitnessTable(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + witnessTableSizeInWords = reader.readNextUnsignedShort(); + witnessTablePrivateSizeInWordsAndRequiresInstantiation = reader.readNextUnsignedShort(); + instantiator = reader.readNextInt(); + privateData = reader.readNextInt(); + } + + /** + * {@return the size of the witness table in words} + *

+ * The amount is copied from the witness table template into the instantiated witness table. + */ + public int getWitnessTableSizeInWords() { + return witnessTableSizeInWords; + } + + /** + * {@return the amount of private storage to allocate before the address point, in words} + *

+ * This memory is zeroed out in the instantiated witness table template. The low bit is used to + * indicate whether this witness table is known to require instantiation. + */ + public int getWitnessTablePrivateSizeInWordsAndRequiresInstantiation() { + return witnessTablePrivateSizeInWordsAndRequiresInstantiation; + } + + /** + * {@return the instantiation function, which is called after the template is copied} + */ + public int getInstantiator() { + return instantiator; + } + + /** + * {@return the private data for the instantiator} + *

+ * Might be null with building with {@code -disable-preallocated-instantiation-caches}. + */ + public int getPrivateData() { + return privateData; + } + + @Override + public String getStructureName() { + return TargetGenericWitnessTable.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "generic witness table"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); + struct.add(WORD, "WitnessTableSizeInWords", "The size of the witness table in words."); + struct.add(WORD, "WitnessTablePrivateSizeInWordsAndRequiresInstantiation", + "The amount of private storage to allocate before the address point, in words."); + struct.add(SwiftUtils.PTR_RELATIVE, "Instantiator", + "The instantiation function, which is called after the template is copied."); + struct.add(SwiftUtils.PTR_RELATIVE, "PrivateData", "Private data for the instantiator."); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetMethodDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetMethodDescriptor.java new file mode 100644 index 0000000000..e0160a6b2b --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetMethodDescriptor.java @@ -0,0 +1,85 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.app.util.bin.format.swift.SwiftUtils; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift {@code TargetMethodDescriptor} structure + * + * @see swift/ABI/Metadata.h + */ +public class TargetMethodDescriptor extends SwiftTypeMetadataStructure { + + /** + * The size (in bytes) of a {@link TargetMethodDescriptor} structure + */ + public static final int SIZE = 8; + + private MethodDescriptorFlags flags; + private int impl; + + /** + * Creates a new {@link TargetMethodDescriptor} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public TargetMethodDescriptor(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + flags = new MethodDescriptorFlags(reader); + impl = reader.readNextInt(); + } + + /** + * {@return the flags} + */ + public MethodDescriptorFlags getFlags() { + return flags; + } + + /** + * {@return the method implementation's relative offset} + */ + public int getImpl() { + return impl; + } + + @Override + public String getStructureName() { + return TargetMethodDescriptor.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "method descriptor"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); + struct.add(flags.toDataType(), "Flags", "Flags describing the method"); + struct.add(SwiftUtils.PTR_RELATIVE, "Impl", "The method implementation"); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetMethodOverrideDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetMethodOverrideDescriptor.java new file mode 100644 index 0000000000..aedab51ed0 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetMethodOverrideDescriptor.java @@ -0,0 +1,96 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.app.util.bin.format.swift.SwiftUtils; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift {@code TargetMethodOverrideDescriptor} structure + * + * @see swift/ABI/Metadata.h + */ +public class TargetMethodOverrideDescriptor extends SwiftTypeMetadataStructure { + + /** + * The size (in bytes) of a {@link TargetMethodOverrideDescriptor} structure + */ + public static final int SIZE = 8; + + private int classPtr; + private int methodPtr; + private int impl; + + /** + * Creates a new {@link TargetMethodOverrideDescriptor} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public TargetMethodOverrideDescriptor(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + classPtr = reader.readNextInt(); + methodPtr = reader.readNextInt(); + impl = reader.readNextInt(); + } + + /** + * {@return the class containing the base method} + */ + public int getClassPtr() { + return classPtr; + } + + /** + * {@return the base method} + */ + public int getMethodPtr() { + return methodPtr; + } + + /** + * {@return the implementation of the override} + */ + public int getImpl() { + return impl; + } + + @Override + public String getStructureName() { + return TargetMethodOverrideDescriptor.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "method override descriptor"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); + struct.add(SwiftUtils.PTR_RELATIVE_MASKED, "Class", + "The class containing the base method."); + struct.add(SwiftUtils.PTR_RELATIVE_MASKED, "Method", "The base method."); + struct.add(SwiftUtils.PTR_RELATIVE, "Impl", "The implementation of the override"); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetObjCResilientClassStubInfo.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetObjCResilientClassStubInfo.java new file mode 100644 index 0000000000..322d22b7ab --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetObjCResilientClassStubInfo.java @@ -0,0 +1,79 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.app.util.bin.format.swift.SwiftUtils; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift {@code TargetObjCResilientClassStubInfo} structure + * + * @see swift/ABI/Metadata.h + */ +public class TargetObjCResilientClassStubInfo extends SwiftTypeMetadataStructure { + + private int stub; + + /** + * Create a new {@link TargetObjCResilientClassStubInfo} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public TargetObjCResilientClassStubInfo(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + stub = reader.readNextInt(); + } + + /** + * {@return a relative pointer to an Objective-C resilient class stub} + */ + public int getStub() { + return stub; + } + + @Override + public String getStructureName() { + return getMyStructureName(); + } + + @Override + public String getDescription() { + return "objc resilient class stub"; + } + + /** + * {@return this class's structure name (will not be affected by subclass's name)} + */ + private final String getMyStructureName() { + return TargetObjCResilientClassStubInfo.class.getSimpleName(); + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getMyStructureName(), 0); + struct.add(SwiftUtils.PTR_RELATIVE, "Stub", + "A relative pointer to an Objective-C resilient class stub."); + return struct; + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetOverrideTableHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetOverrideTableHeader.java new file mode 100644 index 0000000000..dab0de9dab --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetOverrideTableHeader.java @@ -0,0 +1,71 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift {@code TargetOverrideTableHeader} structure + * + * @see swift/ABI/Metadata.h + */ +public class TargetOverrideTableHeader extends SwiftTypeMetadataStructure { + + private long numEntries; + + /** + * Creates a new {@link TargetOverrideTableHeader} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public TargetOverrideTableHeader(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + numEntries = reader.readNextUnsignedInt(); + } + + /** + * {@return the number of MethodOverrideDescriptor records following the vtable override header + * in the class's nominal type descriptor} + */ + public long getNumEntries() { + return numEntries; + } + + @Override + public String getStructureName() { + return TargetOverrideTableHeader.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "override table header"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); + struct.add(DWORD, "NumEntries", + "The number of MethodOverrideDescriptor records following the vtable override header in the class's nominal type descriptor."); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetProtocolConformanceDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetProtocolConformanceDescriptor.java index 95edd606f9..05c6b50330 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetProtocolConformanceDescriptor.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetProtocolConformanceDescriptor.java @@ -16,24 +16,33 @@ package ghidra.app.util.bin.format.swift.types; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; import ghidra.app.util.bin.format.swift.SwiftUtils; -import ghidra.program.model.data.*; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; import ghidra.util.exception.DuplicateNameException; /** - * Represents a Swift TargetProtocolConformanceDescriptor structure + * Represents a Swift {@code TargetProtocolConformanceDescriptor} structure * * @see swift/ABI/Metadata.h */ public final class TargetProtocolConformanceDescriptor extends SwiftTypeMetadataStructure { - private int protocolDescriptor; - private int nominalTypeDescriptor; - private int protocolWitnessTable; - private int conformanceFlags; + private int protocol; + private int typeRef; + private int witnessTablePattern; + private ConformanceFlags flags; + + // Trailing objects + private TargetRelativeContextPointer retroactiveContext; + private TargetResilientWitnessHeader resilientWitnessHeader; + private List resilientWitnesses = new ArrayList<>(); + private TargetGenericWitnessTable genericWitnessTable; /** * Creates a new {@link TargetProtocolConformanceDescriptor} @@ -43,46 +52,98 @@ public final class TargetProtocolConformanceDescriptor extends SwiftTypeMetadata */ public TargetProtocolConformanceDescriptor(BinaryReader reader) throws IOException { super(reader.getPointerIndex()); - protocolDescriptor = reader.readNextInt(); - nominalTypeDescriptor = reader.readNextInt(); - protocolWitnessTable = reader.readNextInt(); - conformanceFlags = reader.readNextInt(); + protocol = reader.readNextInt(); + typeRef = reader.readNextInt(); + witnessTablePattern = reader.readNextInt(); + flags = new ConformanceFlags(reader); + + if (flags.isRetroactive()) { + retroactiveContext = new TargetRelativeContextPointer(reader); + } + + if (flags.hasResilientWitnesses()) { + resilientWitnessHeader = new TargetResilientWitnessHeader(reader); + for (int i = 0; i < resilientWitnessHeader.getNumWitnesses(); i++) { + resilientWitnesses.add(new TargetResilientWitness(reader)); + } + } + + if (flags.hasGenericWitnessTable()) { + genericWitnessTable = new TargetGenericWitnessTable(reader); + } } /** - * Gets the protocol being conformed to - * - * @return The protocol being conformed to + * {@return the protocol being conformed to} */ - public int getProtocolDescriptor() { - return protocolDescriptor; + public int getProtocol() { + return protocol; } /** - * Gets some description of the type that conforms to the protocol - * - * @return Some description of the type that conforms to the protocol + * {@return some description of the type that conforms to the protocol} */ - public int getNominalTypeDescriptor() { - return nominalTypeDescriptor; + public int getTypeRef() { + return typeRef; } /** - * Gets the witness table pattern, which may also serve as the witness table - * - * @return The witness table pattern, which may also serve as the witness table + * {@return the witness table pattern, which may also serve as the witness table} */ - public int getProtocolWitnessTable() { - return protocolWitnessTable; + public int getWitnessTablePattern() { + return witnessTablePattern; } /** - * Gets various flags, including the kind of conformance - * - * @return Various flags, including the kind of conformance + * {@return various flags, including the kind of conformance} */ - public int getConformanceFlags() { - return conformanceFlags; + public ConformanceFlags getConformanceFlags() { + return flags; + } + + /** + * {@return the {@link TargetRelativeContextPointer retroactive context}, or {@code null} if it + * doesn't exist} + */ + public TargetRelativeContextPointer getRetroactiveContext() { + return retroactiveContext; + } + + /** + * {@return the {@link TargetResilientWitnessHeader}, or {@code null} if it doesn't exist} + */ + public TargetResilientWitnessHeader getResilientWitnessHeader() { + return resilientWitnessHeader; + } + + /** + * {@return the {@link List} of resilient witnesses} + */ + public List getResilientWitnesses() { + return resilientWitnesses; + } + + /** + * {@return the {@link TargetGenericWitnessTable}, or {@code null} if it doesn't exist} + */ + public TargetGenericWitnessTable getGenericWitnessTable() { + return genericWitnessTable; + } + + @Override + public List getTrailingObjects() { + List ret = new ArrayList<>(); + if (retroactiveContext != null) { + ret.add(retroactiveContext); + } + if (resilientWitnessHeader != null) { + ret.add(resilientWitnessHeader); + ret.addAll(resilientWitnesses); + } + if (genericWitnessTable != null) { + ret.add(genericWitnessTable); + } + return ret; } @Override @@ -97,14 +158,13 @@ public final class TargetProtocolConformanceDescriptor extends SwiftTypeMetadata @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType struct = new StructureDataType(getStructureName(), 0); - struct.add(DWORD, "ProtocolDescriptor", "The protocol being conformed to"); - struct.add(SwiftUtils.PTR_RELATIVE, "NominalTypeDescriptor", + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); + struct.add(SwiftUtils.PTR_RELATIVE_MASKED, "Protocol", "The protocol being conformed to"); + struct.add(SwiftUtils.PTR_RELATIVE, "TypeRef", "Some description of the type that conforms to the protocol"); - struct.add(DWORD, "ProtocolWitnessTable", + struct.add(DWORD, "WitnessTablePattern", "The witness table pattern, which may also serve as the witness table"); - struct.add(DWORD, "ConformanceFlags", "Various flags, including the kind of conformance"); - struct.setCategoryPath(new CategoryPath(DATA_TYPE_CATEGORY)); + struct.add(flags.toDataType(), "Flags", "Various flags, including the kind of conformance"); return struct; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetProtocolDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetProtocolDescriptor.java index eac949ff82..e969e082ed 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetProtocolDescriptor.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetProtocolDescriptor.java @@ -16,16 +16,18 @@ package ghidra.app.util.bin.format.swift.types; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; import ghidra.app.util.bin.format.swift.SwiftUtils; -import ghidra.program.model.data.CategoryPath; import ghidra.program.model.data.DataType; import ghidra.program.model.data.StructureDataType; import ghidra.util.exception.DuplicateNameException; /** - * Represents a Swift TargetProtocolDescriptor structure + * Represents a Swift {@code TargetProtocolDescriptor} structure * * @see swift/ABI/Metadata.h */ @@ -36,6 +38,9 @@ public final class TargetProtocolDescriptor extends TargetContextDescriptor { private int numRequirements; private int associatedTypeNames; + private List requirementsInSig = new ArrayList<>(); + private List requirements = new ArrayList<>(); + /** * Creates a new {@link TargetProtocolDescriptor} * @@ -48,49 +53,70 @@ public final class TargetProtocolDescriptor extends TargetContextDescriptor { numRequirementsInSig = reader.readNextInt(); numRequirements = reader.readNextInt(); associatedTypeNames = reader.readNextInt(); + + for (int i = 0; i < numRequirementsInSig; i++) { + requirementsInSig.add(new TargetGenericRequirementsDescriptor(reader)); + } + for (int i = 0; i < numRequirements; i++) { + requirements.add(new TargetProtocolRequirement(reader)); + } } /** - * Gets the name of the protocol - * - * @return The name of the protocol + * {@return the name of the protocol} */ public String getName() { return name; } /** - * Gets the number of generic requirements in the requirement signature of the protocol - * - * @return The number of generic requirements in the requirement signature of the protocol + * {@return the number of generic requirements in the requirement signature of the protocol} */ public int getNumRequirementsInSignature() { return numRequirementsInSig; } /** - * Gets the number of requirements in the protocol - * - * @return The number of requirements in the protocol + * {@return the number of requirements in the protocol} */ public int getNumRequirements() { return numRequirements; } /** - * Gets the associated type names - * - * @return The associated type names + * @return the associated type names} */ public int getAssociatedTypeNames() { return associatedTypeNames; // TODO: it's a list...improve } + /** + * {@return a {@link List} of generic requirements in the requirement signature of the protocol} + */ + public List getRequirementsInSignature() { + return requirementsInSig; + } + + /** + * {@return a {@link List} of requirements in the protocol} + */ + public List getRequirements() { + return requirements; + } + @Override public String toString() { return name; } + @Override + public List getTrailingObjects() { + List ret = new ArrayList<>(); + ret.addAll(requirementsInSig); + ret.addAll(requirements); + return ret; + } + @Override public String getStructureName() { return TargetProtocolDescriptor.class.getSimpleName(); @@ -103,15 +129,14 @@ public final class TargetProtocolDescriptor extends TargetContextDescriptor { @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType struct = new StructureDataType(getStructureName(), 0); + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); struct.add(super.toDataType(), super.getStructureName(), ""); struct.add(SwiftUtils.PTR_STRING, "Name", "The name of the protocol"); struct.add(DWORD, "NumRequirementsInSignature", "The number of generic requirements in the requirement signature of the protocol"); struct.add(DWORD, "NumRequirements", "The number of requirements in the protocol"); - struct.add(DWORD, "AssociatedTypeNames", + struct.add(SwiftUtils.PTR_RELATIVE, "AssociatedTypeNames", "Associated type names, as a space-separated list in the same order as the requirements"); - struct.setCategoryPath(new CategoryPath(DATA_TYPE_CATEGORY)); return struct; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetProtocolRequirement.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetProtocolRequirement.java new file mode 100644 index 0000000000..007152df17 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetProtocolRequirement.java @@ -0,0 +1,79 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.app.util.bin.format.swift.SwiftUtils; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +public class TargetProtocolRequirement extends SwiftTypeMetadataStructure { + + private ProtocolRequirementFlags flags; + private int impl; + + /** + * Creates a new {@link TargetProtocolRequirement} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public TargetProtocolRequirement(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + flags = new ProtocolRequirementFlags(reader); + impl = reader.readNextInt(); + } + + /** + * {@return the flags} + */ + public ProtocolRequirementFlags getFlags() { + return flags; + } + + /** + * {@return the optional default implementation of the protocol} + */ + public int getImpl() { + return impl; + } + + @Override + public String getStructureName() { + return TargetProtocolRequirement.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "protocol requirement"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + UnionDataType union = new UnionDataType(CATEGORY_PATH, + "Union_DefaultFuncImplementation_DefaultImplementation"); + union.add(SwiftUtils.PTR_RELATIVE, "DefaultFuncImplementation", null); + union.add(SwiftUtils.PTR_RELATIVE, "DefaultImplementation", null); + + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); + struct.add(flags.toDataType(), "Flags", null); + struct.add(union, "Implementation", "The optional default implementation."); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetRelativeContextPointer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetRelativeContextPointer.java new file mode 100644 index 0000000000..fb467bcf12 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetRelativeContextPointer.java @@ -0,0 +1,67 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.app.util.bin.format.swift.SwiftUtils; +import ghidra.program.model.data.DataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift {@code TargetRelativeContextPointer} structure + * + * @see swift/ABI/MetadataRef.h + */ +public class TargetRelativeContextPointer extends SwiftTypeMetadataStructure { + + private int value; + + /** + * Creates a new {@link TargetRelativeContextPointer} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public TargetRelativeContextPointer(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + value = reader.readNextInt(); + } + + /** + * {@return the pointer value} + */ + public long getValue() { + return value; + } + + @Override + public String getStructureName() { + return TargetRelativeContextPointer.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "relative context pointer"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + return SwiftUtils.PTR_RELATIVE_MASKED; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetRelativeProtocolRequirementPointer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetRelativeProtocolRequirementPointer.java new file mode 100644 index 0000000000..3c16dd0ce7 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetRelativeProtocolRequirementPointer.java @@ -0,0 +1,72 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift {@code TargetRelativeContextPointer} structure + * + * @see swift/ABI/Metadata.h + */ +public class TargetRelativeProtocolRequirementPointer extends SwiftTypeMetadataStructure { + + public static final TypeDef dataType = + new PointerTypedefBuilder(Pointer32DataType.dataType, null) + .type(PointerType.RELATIVE) + .bitMask(~1) + .build(); + + private int value; + + /** + * Creates a new {@link TargetRelativeProtocolRequirementPointer} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public TargetRelativeProtocolRequirementPointer(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + value = reader.readNextInt(); + } + + /** + * {@return the pointer value} + */ + public long getValue() { + return value; + } + + @Override + public String getStructureName() { + return TargetRelativeProtocolRequirementPointer.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "relative protocol requirement pointer"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + return dataType; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetResilientSuperclass.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetResilientSuperclass.java new file mode 100644 index 0000000000..9a6bbfcae6 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetResilientSuperclass.java @@ -0,0 +1,78 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.app.util.bin.format.swift.SwiftUtils; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift {@code TargetResilientSuperclass} structure + * + * @see swift/ABI/Metadata.h + */ +public class TargetResilientSuperclass extends SwiftTypeMetadataStructure { + + private int superclass; + + /** + * Create a new {@link TargetResilientSuperclass} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public TargetResilientSuperclass(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + superclass = reader.readNextInt(); + } + + /** + * {@return the superclass of this class, or 0 if there isn't one} + */ + public int getSuperclass() { + return superclass; + } + + @Override + public String getStructureName() { + return getMyStructureName(); + } + + @Override + public String getDescription() { + return "resilient superclass"; + } + + /** + * {@return this class's structure name (will not be affected by subclass's name)} + */ + private final String getMyStructureName() { + return TargetResilientSuperclass.class.getSimpleName(); + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getMyStructureName(), 0); + struct.add(SwiftUtils.PTR_RELATIVE, "Superclass", "The superclass of this class."); + return struct; + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetResilientWitness.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetResilientWitness.java new file mode 100644 index 0000000000..03e4544305 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetResilientWitness.java @@ -0,0 +1,79 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.app.util.bin.format.swift.SwiftUtils; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +public class TargetResilientWitness extends SwiftTypeMetadataStructure { + + private TargetRelativeProtocolRequirementPointer requirement; + private int impl; + + /** + * Creates a new {@link TargetResilientWitness} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public TargetResilientWitness(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + requirement = new TargetRelativeProtocolRequirementPointer(reader); + impl = reader.readNextInt(); + } + + /** + * {@return the requirement} + */ + public TargetRelativeProtocolRequirementPointer getRequirement() { + return requirement; + } + + /** + * {@return the implementation} + */ + public int getImpl() { + return impl; + } + + @Override + public String getStructureName() { + return TargetResilientWitness.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "resilient witness"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + UnionDataType union = new UnionDataType(CATEGORY_PATH, + "Union_Impl_FuncImpl"); + union.add(SwiftUtils.PTR_RELATIVE, "Impl", null); + union.add(SwiftUtils.PTR_RELATIVE, "FuncImpl", null); + + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); + struct.add(TargetRelativeProtocolRequirementPointer.dataType, "Requirement", null); + struct.add(union, "Implementation", null); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetResilientWitnessHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetResilientWitnessHeader.java new file mode 100644 index 0000000000..554b4b3d1a --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetResilientWitnessHeader.java @@ -0,0 +1,69 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift {@code TargetResilientWitnessHeader} structure + * + * @see swift/ABI/Metadata.h + */ +public class TargetResilientWitnessHeader extends SwiftTypeMetadataStructure { + + private long numWitnesses; + + /** + * Creates a new {@link TargetResilientWitnessHeader} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public TargetResilientWitnessHeader(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + numWitnesses = reader.readNextUnsignedInt(); + } + + /** + * {@return the number of witnesses} + */ + public long getNumWitnesses() { + return numWitnesses; + } + + @Override + public String getStructureName() { + return TargetResilientWitnessHeader.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "resilient witness header"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); + struct.add(DWORD, "NumWitnesses", null); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetSingletonMetadataInitialization.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetSingletonMetadataInitialization.java new file mode 100644 index 0000000000..f670a09e29 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetSingletonMetadataInitialization.java @@ -0,0 +1,114 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.app.util.bin.format.swift.SwiftUtils; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift {@code TargetSingletonMetadataInitialization} structure + * + * @see swift/ABI/Metadata.h + */ +public class TargetSingletonMetadataInitialization extends SwiftTypeMetadataStructure { + + private ContextDescriptorFlags flags; + + private int initializationCache; + private int incompleteMetadata; + private int resilientPattern; + private int completionFunction; + + /** + * Creates a new {@link TargetSingletonMetadataInitialization} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @param flags The {@link ContextDescriptorFlags} + * @throws IOException if there was an IO-related problem creating the structure + */ + public TargetSingletonMetadataInitialization(BinaryReader reader, ContextDescriptorFlags flags) + throws IOException { + super(reader.getPointerIndex()); + this.flags = flags; + initializationCache = reader.readNextInt(); + incompleteMetadata = reader.readNextInt(); + resilientPattern = incompleteMetadata; + completionFunction = reader.readNextInt(); + } + + /** + * {@return the initialization cache} + */ + public int getInitializationCache() { + return initializationCache; + } + + /** + * {@return the incomplete metadata for structs, enums, and classes if there is no resilient + * ancestry; otherwise, 0} + */ + public int getIncompleteMetadata() { + return !flags.hasClassResilientSuperclass() ? incompleteMetadata : 0; + } + + /** + * {@return a pattern used to allocation and initialize metadata for this class if there is a + * resilient superclass; otherwise, 0} + */ + public int getResilientPattern() { + return flags.hasClassResilientSuperclass() ? resilientPattern : 0; + } + + /** + * {@return the completion function (the pattern will always be null, even for a resilient + * class)} + */ + public int getCompletionFunction() { + return completionFunction; + } + + @Override + public String getStructureName() { + return TargetSingletonMetadataInitialization.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "singleton metadata initialization"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + UnionDataType union = + new UnionDataType(CATEGORY_PATH, "Union_IncompleteMetadata_ResilientPattern"); + union.add(SwiftUtils.PTR_RELATIVE, "IncompleteMetadata", + "The incomplete metadata, for structs, enums and classes without resilient ancestry."); + union.add(SwiftUtils.PTR_RELATIVE, "ResilientPattern", + "If the classes descriptor has a resilient superclass, this points at a pattern used to allcoate and initialize metadata for this class, since its size and contents is not known at compile time."); + + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); + struct.add(SwiftUtils.PTR_RELATIVE, "InitializationCache", "The initialization cache."); + struct.add(union, union.getName(), null); + struct.add(SwiftUtils.PTR_RELATIVE, "CompletionFunction", + "The completion function. The pattern will always be null, even for a resilient class."); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetStructDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetStructDescriptor.java index 80ed197d5a..0983358c87 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetStructDescriptor.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetStructDescriptor.java @@ -16,15 +16,17 @@ package ghidra.app.util.bin.format.swift.types; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import ghidra.app.util.bin.BinaryReader; -import ghidra.program.model.data.CategoryPath; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; import ghidra.program.model.data.DataType; import ghidra.program.model.data.StructureDataType; import ghidra.util.exception.DuplicateNameException; /** - * Represents a Swift TargetStructDescriptor structure + * Represents a Swift {@code TargetStructDescriptor} structure * * @see swift/ABI/Metadata.h */ @@ -33,6 +35,11 @@ public final class TargetStructDescriptor extends TargetTypeContextDescriptor { private int numFields; private int fieldOffsetVectorOffset; + // Trailing objects + private TargetTypeGenericContextDescriptorHeader genericHeader; + private TargetSingletonMetadataInitialization singleton; + private TargetForeignMetadataInitialization foreign; + /** * Creates a new {@link TargetStructDescriptor} * @@ -43,30 +50,93 @@ public final class TargetStructDescriptor extends TargetTypeContextDescriptor { super(reader); numFields = reader.readNextInt(); fieldOffsetVectorOffset = reader.readNextInt(); + + if (flags.isGeneric()) { + genericHeader = new TargetTypeGenericContextDescriptorHeader(reader); + } + + switch (flags.getMetadataInitialization()) { + case NoMetadataInitialization: + break; + case SingletonMetadataInitialization: + singleton = new TargetSingletonMetadataInitialization(reader, flags); + break; + case ForeignMetadataInitialization: + foreign = new TargetForeignMetadataInitialization(reader); + break; + } + + if (flags.isGeneric() && + flags.hasCanonicalMetadataPrespecializationsOrSingletonMetadataPonter()) { + throw new IOException("Unimplemented TargetCanonicalSpecializedMetadatas detected."); + } + + if (flags.hasInvertableProtocols()) { + throw new IOException("Unimplemented InvertibleProtocolSet detected."); + } + + if (!flags.isGeneric() && + flags.hasCanonicalMetadataPrespecializationsOrSingletonMetadataPonter()) { + throw new IOException("Unimplemented TargetSingletonMetadataPointer detected."); + } } /** - * Gets the number of stored properties in the struct. If there is a field offset vector, - * this is its length. - - * @return The number of stored properties in the struct. If there is a field offset vector, - * this is its length. + * {@return the number of stored properties in the struct (if there is a field offset vector, + * this is its length} */ public int getNumFields() { return numFields; } /** - * Gets the offset of the field offset vector for this struct's stored properties in its - * metadata, if any. 0 means there is no field offset vector. - * - * @return The offset of the field offset vector for this struct's stored properties in its - * metadata, if any. 0 means there is no field offset vector. + * {@return the offset of the field offset vector for this struct's stored properties in its + * metadata, if any. 0 means there is no field offset vector} */ public int getFieldOffsetVectorOffset() { return fieldOffsetVectorOffset; } + /** + * {@return the {@link TargetTypeGenericContextDescriptorHeader}, or {@code null} if it doesn't + * exist} + */ + public TargetTypeGenericContextDescriptorHeader getGenericHeader() { + return genericHeader; + } + + /** + * {@return the {@link TargetSingletonMetadataInitialization}, or {@code null} if it doesn't + * exist} + */ + public TargetSingletonMetadataInitialization getTargetSingletonMetadataInitialization() { + return singleton; + } + + /** + * {@return the {@link TargetForeignMetadataInitialization}, or {@code null} if it doesn't + * exist} + */ + public TargetForeignMetadataInitialization getTargetForeignMetadataInitialization() { + return foreign; + } + + @Override + public List getTrailingObjects() { + List ret = new ArrayList<>(); + if (genericHeader != null) { + ret.add(genericHeader); + ret.addAll(genericHeader.getTrailingObjects()); + } + if (singleton != null) { + ret.add(singleton); + } + if (foreign != null) { + ret.add(foreign); + } + return ret; + } + @Override public String getStructureName() { return TargetStructDescriptor.class.getSimpleName(); @@ -79,13 +149,12 @@ public final class TargetStructDescriptor extends TargetTypeContextDescriptor { @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType struct = new StructureDataType(getStructureName(), 0); + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); struct.add(super.toDataType(), super.getStructureName(), ""); struct.add(DWORD, "NumFields", "The number of stored properties in the struct. If there is a field offset vector, this is its length."); struct.add(DWORD, "FieldOffsetVectorOffset", "The offset of the field offset vector for this struct's stored properties in its metadata, if any. 0 means there is no field offset vector."); - struct.setCategoryPath(new CategoryPath(DATA_TYPE_CATEGORY)); return struct; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetTypeContextDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetTypeContextDescriptor.java index bfd551c5be..67ad43d0f3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetTypeContextDescriptor.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetTypeContextDescriptor.java @@ -20,11 +20,12 @@ import java.util.Map; import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.format.swift.SwiftUtils; -import ghidra.program.model.data.*; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; import ghidra.util.exception.DuplicateNameException; /** - * Represents a Swift TargetTypeContextDescriptor structure + * Represents a Swift {@code TargetTypeContextDescriptor} structure * * @see swift/ABI/Metadata.h */ @@ -48,39 +49,32 @@ public class TargetTypeContextDescriptor extends TargetContextDescriptor { } /** - * Gets the name of the type - * - * @return The name of the type + * {@return the name of the type} */ public String getName() { return name; } /** - * Gets the pointer to the metadata access function for this type - * - * @return The pointer to the metadata access function for this type + * {@return the pointer to the metadata access function for this type} */ public int getAccessFunctionPtr() { return accessFunctionPtr; } /** - * Gets the pointer to the field descriptor for the type, if any - * - * @return The pointer to the field descriptor for the type, if any + * {@return the pointer to the field descriptor for the type, if any} */ public int getFields() { return fields; } /** - * Gets this {@link TargetTypeContextDescriptor}'s {@link FieldDescriptor} + * {@return this {@link TargetTypeContextDescriptor}'s {@link FieldDescriptor}, or {@code null} + * if it doesn't have one} * * @param fieldDescriptors A {@link Map} of {@link FieldDescriptor}'s keyed by their base * addresses - * @return This {@link TargetTypeContextDescriptor}'s {@link FieldDescriptor}, or null if it - * doesn't have one */ public FieldDescriptor getFieldDescriptor(Map fieldDescriptors) { FieldDescriptor fieldDescriptor = @@ -104,9 +98,7 @@ public class TargetTypeContextDescriptor extends TargetContextDescriptor { } /** - * Gets this class's structure name (will not be affected by subclass's name) - * - * @return This class's structure name + * {@return this class's structure name (will not be affected by subclass's name)} */ private final String getMyStructureName() { return TargetTypeContextDescriptor.class.getSimpleName(); @@ -114,14 +106,13 @@ public class TargetTypeContextDescriptor extends TargetContextDescriptor { @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType struct = new StructureDataType(getMyStructureName(), 0); + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getMyStructureName(), 0); struct.add(super.toDataType(), super.getStructureName(), ""); struct.add(SwiftUtils.PTR_STRING, "Name", "The name of the type"); struct.add(SwiftUtils.PTR_RELATIVE, "AccessFunctionPtr", "A pointer to the metadata access function for this type"); struct.add(SwiftUtils.PTR_RELATIVE, "Fields", "A pointer to the field descriptor for the type, if any"); - struct.setCategoryPath(new CategoryPath(DATA_TYPE_CATEGORY)); return struct; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetTypeGenericContextDescriptorHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetTypeGenericContextDescriptorHeader.java new file mode 100644 index 0000000000..17f1907739 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetTypeGenericContextDescriptorHeader.java @@ -0,0 +1,98 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; +import java.util.List; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.app.util.bin.format.swift.SwiftUtils; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift {@code TargetTypeGenericContextDescriptorHeader} structure + * + * @see swift/ABI/Metadata.h + */ +public class TargetTypeGenericContextDescriptorHeader extends SwiftTypeMetadataStructure { + + private int instantiationCache; + private int defaultInstallationPattern; + private TargetGenericContextDescriptorHeader base; + + /** + * Creates a new {@link TargetTypeGenericContextDescriptorHeader} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public TargetTypeGenericContextDescriptorHeader(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + instantiationCache = reader.readNextInt(); + defaultInstallationPattern = reader.readNextInt(); + base = new TargetGenericContextDescriptorHeader(reader); + } + + /** + * {@return the metadata instantiation cache} + */ + public int getInstantiationCache() { + return instantiationCache; + } + + /** + * {@return the default instantiation pattern} + */ + public int getDefaultInstallationPattern() { + return defaultInstallationPattern; + } + + /** + * {@return the base header} + */ + public TargetGenericContextDescriptorHeader getBaseHeader() { + return base; + } + + @Override + public List getTrailingObjects() { + return base.getTrailingObjects(); + } + + @Override + public String getStructureName() { + return TargetTypeGenericContextDescriptorHeader.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "type generic context descriptor header"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); + struct.add(SwiftUtils.PTR_RELATIVE, "InstantiationCache", + "The metadata instantiation cache."); + struct.add(SwiftUtils.PTR_RELATIVE, "DefaultInstantiationPattern", + "The default instantiation pattern."); + struct.add(base.toDataType(), "Base", "The base header."); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetVTableDescriptorHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetVTableDescriptorHeader.java new file mode 100644 index 0000000000..c4a5240065 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetVTableDescriptorHeader.java @@ -0,0 +1,80 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift {@code TargetVTableDescriptorHeader} structure + * + * @see swift/ABI/Metadata.h + */ +public class TargetVTableDescriptorHeader extends SwiftTypeMetadataStructure { + + private long vtableOffset; + private long vtableSize; + + /** + * Creates a new {@link TargetVTableDescriptorHeader} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public TargetVTableDescriptorHeader(BinaryReader reader) throws IOException { + super(reader.getPointerIndex()); + vtableOffset = reader.readNextUnsignedInt(); + vtableSize = reader.readNextUnsignedInt(); + } + + /** + * {@return the offset of the vtable for this class in its metadata, if any, in words} + */ + public long getVTableOffset() { + return vtableOffset; + } + + /** + * {@return the number of vtable entries} + */ + public long getVTableSize() { + return vtableSize; + } + + @Override + public String getStructureName() { + return TargetVTableDescriptorHeader.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "vtable descriptor header"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0); + struct.add(DWORD, "VTableOffset", + "The offset of the vtable for this class in its metadata, if any, in words."); + struct.add(DWORD, "VTableSize", "The number of vtable entries."); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TypeReferenceKind.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TypeReferenceKind.java new file mode 100644 index 0000000000..7d0ec538e6 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TypeReferenceKind.java @@ -0,0 +1,76 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ +package ghidra.app.util.bin.format.swift.types; + +import java.io.IOException; +import java.util.Arrays; + +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.EnumDataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Swift {@code TypeReferenceKind} values + * + * @see swift/ABI/MetadataValues.h + */ +public enum TypeReferenceKind implements StructConverter { + + DirectTypeDescriptor(0), + IndirectTypeDescriptor(1), + DirectObjCClassName(2), + IndirectObjCClass(3); + + private int value; + + /** + * Creates a new {@link TypeReferenceKind} + * + * @param value The kind value + */ + private TypeReferenceKind(int value) { + this.value = value; + } + + /** + * {@return the kind value} + */ + public int getValue() { + return value; + } + + /** + * {@return the {@link TypeReferenceKind} with the given kind value, or {@code null} if it + * does not exist} + * + * @param value The kind value to get the value of + */ + public static TypeReferenceKind valueOf(int value) { + return Arrays.stream(values()).filter(e -> e.getValue() == value).findFirst().orElse(null); + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + EnumDataType dt = new EnumDataType(SwiftTypeMetadataStructure.CATEGORY_PATH, + TypeReferenceKind.class.getSimpleName(), 1); + for (TypeReferenceKind kind : values()) { + dt.add(kind.name(), kind.getValue()); + } + return dt; + } +} diff --git a/Ghidra/Features/SwiftDemangler/src/main/java/ghidra/app/util/demangler/swift/SwiftDemangledNodeKind.java b/Ghidra/Features/SwiftDemangler/src/main/java/ghidra/app/util/demangler/swift/SwiftDemangledNodeKind.java index 6fd3caf1d2..181a63e393 100644 --- a/Ghidra/Features/SwiftDemangler/src/main/java/ghidra/app/util/demangler/swift/SwiftDemangledNodeKind.java +++ b/Ghidra/Features/SwiftDemangler/src/main/java/ghidra/app/util/demangler/swift/SwiftDemangledNodeKind.java @@ -56,6 +56,7 @@ public enum SwiftDemangledNodeKind { LazyProtocolWitnessTableAccessor, LocalDeclName, MergedFunction, + MethodDescriptor, ModifyAccessor, Module, ModuleDescriptor, diff --git a/Ghidra/Features/SwiftDemangler/src/main/java/ghidra/app/util/demangler/swift/nodes/SwiftNode.java b/Ghidra/Features/SwiftDemangler/src/main/java/ghidra/app/util/demangler/swift/nodes/SwiftNode.java index 1d263b4d56..42825b5693 100644 --- a/Ghidra/Features/SwiftDemangler/src/main/java/ghidra/app/util/demangler/swift/nodes/SwiftNode.java +++ b/Ghidra/Features/SwiftDemangler/src/main/java/ghidra/app/util/demangler/swift/nodes/SwiftNode.java @@ -87,6 +87,7 @@ public abstract class SwiftNode { case LazyProtocolWitnessTableAccessor -> new SwiftLazyProtocolWitnessTableAccessorNode(); case LocalDeclName -> new SwiftLocalDeclNameNode(); case MergedFunction -> new SwiftGenericPassthroughNode(); + case MethodDescriptor -> new SwiftGenericDescriptorNode(); case ModifyAccessor -> new SwiftModifyAccessorNode(); case Module -> new SwiftGenericTextNode(); case ModuleDescriptor -> new SwiftGenericDescriptorNode();