diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/SwiftTypeMetadataAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/SwiftTypeMetadataAnalyzer.java new file mode 100644 index 0000000000..73022a73e7 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/SwiftTypeMetadataAnalyzer.java @@ -0,0 +1,57 @@ +/* ### + * 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.plugin.core.analysis; + +import java.io.IOException; + +import ghidra.app.services.*; +import ghidra.app.util.bin.format.swift.SwiftTypeMetadata; +import ghidra.app.util.bin.format.swift.SwiftUtils; +import ghidra.app.util.importer.MessageLog; +import ghidra.program.model.address.AddressSetView; +import ghidra.program.model.listing.Program; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.TaskMonitor; + +public class SwiftTypeMetadataAnalyzer extends AbstractAnalyzer { + + private static final String NAME = "Swift Type Metadata Analyzer"; + private static final String DESCRIPTION = "Discovers Swift type metadata records."; + + public SwiftTypeMetadataAnalyzer() { + super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER); + setDefaultEnablement(true); + setPriority(AnalysisPriority.FORMAT_ANALYSIS); + } + + @Override + public boolean canAnalyze(Program program) { + return SwiftUtils.isSwift(program); + } + + @Override + public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) + throws CancelledException { + try { + SwiftTypeMetadata typeMetadata = new SwiftTypeMetadata(program, monitor, log); + typeMetadata.markup(); + } + catch (IOException e) { + return false; + } + return true; + } +} 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 new file mode 100644 index 0000000000..42fc4207dd --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/SwiftSection.java @@ -0,0 +1,60 @@ +/* ### + * 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; + +import java.util.List; + +/** + * Used to refer to a Swift section, which can have different names depending on the platform + * + * @see llvm/BinaryFormat/Swift.def + */ +public enum SwiftSection { + + + BLOCK_FIELDMD("__swift5_fieldmd", "swift5_fieldmd", ".sw5flmd"), + BLOCK_ASSOCTY("__swift5_assocty", "swift5_assocty", ".sw5asty"), + BLOCK_BUILTIN("__swift5_builtin", "swift5_builtin", ".sw5bltn"), + BLOCK_CAPTURE("__swift5_capture", "swift5_capture", ".sw5cptr"), + BLOCK_TYPEREF("__swift5_typeref", "swift5_typeref", ".sw5tyrf"), + BLOCK_REFLSTR("__swift5_reflstr", "swift5_reflstr", ".sw5rfst"), + BLOCK_CONFORM("__swift5_proto", "swift5_protocol_conformances", ".sw5prtc"), + BLOCK_PROTOCS("__swift5_protos", "swift5_protocols", ".sw5prt"), + BLOCK_ACFUNCS("__swift5_acfuncs", "swift5_accessible_functions", ".sw5acfn"), + BLOCK_MPENUM("__swift5_mpenum", "swift5_mpenum", ".sw5mpen"), + BLOCK_TYPES("__swift5_types", "swift5_types", ".sw5tymd"), + BLOCK_ENTRY("__swift5_entry", "swift5_entry", ".sw5entr"); + + private List sectionNames; + + /** + * Create a new {@link SwiftSection} + * + * @param names The names the section goes by + */ + private SwiftSection(String... names) { + sectionNames = List.of(names); + } + + /** + * Gets 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/SwiftStructure.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/SwiftStructure.java new file mode 100644 index 0000000000..169791c6d6 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/SwiftStructure.java @@ -0,0 +1,40 @@ +/* ### + * 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; + +import ghidra.app.util.bin.StructConverter; + +/** + * Implemented by all Swift structures + */ +public interface SwiftStructure extends StructConverter { + + public static final String DATA_TYPE_CATEGORY = "/Swift"; + + /** + * Gets the name of the {@link SwiftStructure} + * + * @return The name of the {@link SwiftStructure} + */ + public String getStructureName(); + + /** + * Gets a short description of the {@link SwiftStructure} + * + * @return A short description of the {@link SwiftStructure} + */ + public String getDescription(); +} 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 new file mode 100644 index 0000000000..fc453f36ae --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/SwiftTypeMetadata.java @@ -0,0 +1,506 @@ +/* ### + * 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; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import ghidra.app.util.bin.*; +import ghidra.app.util.bin.format.swift.types.*; +import ghidra.app.util.importer.MessageLog; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; +import ghidra.program.model.data.DataUtilities.ClearDataMode; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryBlock; +import ghidra.program.model.util.CodeUnitInsertionException; +import ghidra.util.exception.CancelledException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; + +/** + * Parses marks up, and provide access to Swift type metadata + */ +public class SwiftTypeMetadata { + + private Program program; + private TaskMonitor monitor; + private MessageLog log; + + private List entryPoints = new ArrayList<>(); + private List builtinTypeDescriptors = new ArrayList<>(); + private List fieldDescriptors = new ArrayList<>(); + private List associatedTypeDescriptors = new ArrayList<>(); + private List captureDescriptors = new ArrayList<>(); + private List mpEnumDescriptors = new ArrayList<>(); + private List typeDescriptors = new ArrayList<>(); + private List protocolDescriptors = new ArrayList<>(); + private List protocolConformanceDescriptors = + new ArrayList<>(); + + private List markupList = new ArrayList<>(); + + /** + * Creates a new {@link SwiftTypeMetadata} + * + * @param program The {@link Program} + * @param monitor A cancellable task monitor + * @param log The log + * @throws IOException if there was an IO-related error + * @throws CancelledException if the user cancelled the operation + */ + public SwiftTypeMetadata(Program program, TaskMonitor monitor, MessageLog log) + throws IOException, CancelledException { + this.program = program; + this.monitor = monitor; + this.log = log; + + parse(); + } + + /** + * Parses the {@link SwiftTypeMetadata} + * + * @throws IOException if there was an IO-related error + * @throws CancelledException if the user cancelled the operation + */ + private void parse() throws IOException, CancelledException { + try (ByteProvider provider = + MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false)) { + BinaryReader reader = new BinaryReader(provider, !program.getLanguage().isBigEndian()); + + parseEntryPoints(SwiftSection.BLOCK_ENTRY, reader); + parseBuiltinTypeDescriptors(SwiftSection.BLOCK_BUILTIN, reader); + parseFieldDescriptors(SwiftSection.BLOCK_FIELDMD, reader); + parseAssociatedTypeDescriptors(SwiftSection.BLOCK_ASSOCTY, reader); + parseCaptureTypeDescriptors(SwiftSection.BLOCK_CAPTURE, reader); + parseMultiPayloadEnumDescriptors(SwiftSection.BLOCK_MPENUM, reader); + parseProtocolDescriptors(SwiftSection.BLOCK_PROTOCS, reader); + parseProtocolConformanceDescriptors(SwiftSection.BLOCK_CONFORM, reader); + parseTypeDescriptors(SwiftSection.BLOCK_TYPES, reader); + } + } + + /** + * Parses the entry point(s) + * + * @param section The {@link SwiftSection} that contains the entry point(s) + * @param reader A {@link BinaryReader} + * @throws CancelledException if the user cancelled the operation + */ + private void parseEntryPoints(SwiftSection section, BinaryReader reader) + 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(); + 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 + "'"); + } + } + + /** + * Parses the {@link BuiltinTypeDescriptor}s + * + * @param section The {@link SwiftSection} that contains the descriptors + * @param reader A {@link BinaryReader} + * @throws CancelledException if the user cancelled the operation + */ + private void parseBuiltinTypeDescriptors(SwiftSection section, BinaryReader reader) + throws CancelledException { + monitor.setMessage("Parsing Swift builtin type descriptors..."); + monitor.setIndeterminate(true); + try { + for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) { + Address blockStart = block.getStart(); + reader.setPointerIndex(blockStart.getOffset()); + int i = 0; + while (i + BuiltinTypeDescriptor.SIZE <= block.getSize()) { + monitor.checkCancelled(); + BuiltinTypeDescriptor descriptor = new BuiltinTypeDescriptor(reader); + builtinTypeDescriptors.add(descriptor); + markupList.add(new SwiftStructureInfo(descriptor, + new SwiftStructureAddress(blockStart.add(i), null))); + i += BuiltinTypeDescriptor.SIZE; + } + } + } + catch (IOException e) { + log("Failed to parse builtin type descriptors from section '" + section + "'"); + } + } + + /** + * Parses the {@link FieldDescriptor}s + * + * @param section The {@link SwiftSection} that contains the descriptors + * @param reader A {@link BinaryReader} + * @throws CancelledException if the user cancelled the operation + */ + private void parseFieldDescriptors(SwiftSection section, BinaryReader reader) + throws CancelledException { + monitor.setMessage("Parsing Swift field descriptors..."); + monitor.setIndeterminate(true); + try { + for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) { + Address blockStart = block.getStart(); + reader.setPointerIndex(blockStart.getOffset()); + int i = 0; + while (i + FieldDescriptor.SIZE <= block.getSize()) { + monitor.checkCancelled(); + FieldDescriptor descriptor = new FieldDescriptor(reader); + fieldDescriptors.add(descriptor); + markupList.add(new SwiftStructureInfo(descriptor, + new SwiftStructureAddress(blockStart.add(i), null))); + List records = descriptor.getFieldRecords(); + i += FieldDescriptor.SIZE; + for (int j = 0; j < records.size(); j++) { + FieldRecord record = records.get(j); + markupList.add(new SwiftStructureInfo(record, + new SwiftStructureAddress(blockStart.add(i + j * FieldRecord.SIZE), + null))); + } + i += descriptor.getNumFields() * FieldRecord.SIZE; + } + } + } + catch (IOException e) { + log("Failed to parse field descriptors from section '" + section + "'"); + } + } + + /** + * Parses the {@link AssociatedTypeDescriptor}s + * + * @param section The {@link SwiftSection} that contains the descriptors + * @param reader A {@link BinaryReader} + * @throws CancelledException if the user cancelled the operation + */ + private void parseAssociatedTypeDescriptors(SwiftSection section, BinaryReader reader) + throws CancelledException { + monitor.setMessage("Parsing Swift associated type descriptors..."); + monitor.setIndeterminate(true); + try { + for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) { + Address blockStart = block.getStart(); + reader.setPointerIndex(blockStart.getOffset()); + int i = 0; + while (i + AssociatedTypeDescriptor.SIZE <= block.getSize()) { + monitor.checkCancelled(); + AssociatedTypeDescriptor descriptor = new AssociatedTypeDescriptor(reader); + associatedTypeDescriptors.add(descriptor); + markupList.add(new SwiftStructureInfo(descriptor, + new SwiftStructureAddress(blockStart.add(i), null))); + List records = descriptor.getAssociatedTypeRecords(); + i += AssociatedTypeDescriptor.SIZE; + for (int j = 0; j < records.size(); j++) { + AssociatedTypeRecord record = records.get(j); + markupList.add(new SwiftStructureInfo(record, + new SwiftStructureAddress( + blockStart.add(i + j * AssociatedTypeRecord.SIZE), null))); + } + i += descriptor.getNumAssociatedTypes() * AssociatedTypeRecord.SIZE; + } + } + } + catch (IOException e) { + log("Failed to parse associated type descriptors from section '" + section + "'"); + } + } + + /** + * Parses the {@link CaptureDescriptor}s + * + * @param section The {@link SwiftSection} that contains the descriptors + * @param reader A {@link BinaryReader} + * @throws CancelledException if the user cancelled the operation + */ + private void parseCaptureTypeDescriptors(SwiftSection section, BinaryReader reader) + throws CancelledException { + monitor.setMessage("Parsing Swift capture descriptors..."); + monitor.setIndeterminate(true); + try { + for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) { + Address blockStart = block.getStart(); + reader.setPointerIndex(blockStart.getOffset()); + int i = 0; + while (i + CaptureDescriptor.SIZE <= block.getSize()) { + monitor.checkCancelled(); + CaptureDescriptor descriptor = new CaptureDescriptor(reader); + captureDescriptors.add(descriptor); + markupList.add(new SwiftStructureInfo(descriptor, + new SwiftStructureAddress(blockStart.add(i), null))); + List records = descriptor.getCaptureTypeRecords(); + i += CaptureDescriptor.SIZE; + for (int j = 0; j < records.size(); j++) { + CaptureTypeRecord record = records.get(j); + markupList.add(new SwiftStructureInfo(record, + new SwiftStructureAddress( + blockStart.add(i + j * CaptureTypeRecord.SIZE), null))); + } + i += descriptor.getNumCaptureTypes() * CaptureTypeRecord.SIZE; + List sourceRecords = + descriptor.getMetadataSourceRecords(); + for (int j = 0; j < sourceRecords.size(); j++) { + MetadataSourceRecord record = sourceRecords.get(j); + markupList.add(new SwiftStructureInfo(record, + new SwiftStructureAddress( + blockStart.add(i + j * MetadataSourceRecord.SIZE), null))); + } + i += descriptor.getNumMetadataSources() * MetadataSourceRecord.SIZE; + } + } + } + catch (IOException e) { + log("Failed to parse capture descriptors from section '" + section + "'"); + } + } + + /** + * Parses the {@link MultiPayloadEnumDescriptor}s + * + * @param section The {@link SwiftSection} that contains the descriptors + * @param reader A {@link BinaryReader} + * @throws CancelledException if the user cancelled the operation + */ + private void parseMultiPayloadEnumDescriptors(SwiftSection section, BinaryReader reader) + throws CancelledException { + monitor.setMessage("Parsing Swift multipayload enum descriptors..."); + monitor.setIndeterminate(true); + try { + for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) { + Address blockStart = block.getStart(); + reader.setPointerIndex(blockStart.getOffset()); + int i = 0; + while (i < block.getSize()) { + monitor.checkCancelled(); + MultiPayloadEnumDescriptor descriptor = new MultiPayloadEnumDescriptor(reader); + mpEnumDescriptors.add(descriptor); + markupList.add(new SwiftStructureInfo(descriptor, + new SwiftStructureAddress(blockStart.add(i), null))); + i += MultiPayloadEnumDescriptor.SIZE + descriptor.getContentsSize(); + } + } + } + catch (IOException e) { + log("Failed to parse multipayload enum descriptors from section '" + section + "'"); + } + } + + /** + * Parses the {@link TargetProtocolDescriptor}s + * + * @param section The section name that contains the descriptors + * @param reader A {@link BinaryReader} + * @throws CancelledException if the user cancelled the operation + */ + 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()); + TargetProtocolDescriptor descriptor = new TargetProtocolDescriptor(reader); + protocolDescriptors.add(descriptor); + markupList.add(new SwiftStructureInfo(descriptor, + new SwiftStructureAddress(addrPair.structAddr(), addrPair.pointerAddr()))); + } + } + catch (IOException e) { + log("Failed to parse protocol descriptors from section '" + section + "'"); + } + } + + /** + * Parses the {@link TargetProtocolConformanceDescriptor}s + * + * @param section The {@link SwiftSection} that contains the descriptors + * @param reader A {@link BinaryReader} + * @throws CancelledException if the user cancelled the operation + */ + 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) { + reader.setPointerIndex(addrPair.structAddr().getOffset()); + TargetProtocolConformanceDescriptor descriptor = + new TargetProtocolConformanceDescriptor(reader); + protocolConformanceDescriptors.add(descriptor); + markupList.add(new SwiftStructureInfo(descriptor, + new SwiftStructureAddress(addrPair.structAddr(), + addrPair.pointerAddr()))); + } + } + catch (IOException e) { + log("Failed to parse protocol conformance descriptors from section '" + section + + "'"); + } + } + + /** + * Parses the {@link TargetTypeContextDescriptor}s + * + * @param section The {@link SwiftSection} that contains the descriptors + * @param reader A {@link BinaryReader} + * @throws CancelledException if the user cancelled the operation + */ + 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) { + 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: + yield new TargetClassDescriptor(reader); + case ContextDescriptorKind.STRUCT: + yield new TargetStructDescriptor(reader); + case ContextDescriptorKind.ENUM: + yield new TargetEnumDescriptor(reader); + default: + log("Unrecognized type descriptor %d at index: 0x%x" + .formatted(contextDescriptorKind, origIndex)); + yield null; + }; + if (descriptor != null) { + typeDescriptors.add(descriptor); + markupList.add(new SwiftStructureInfo(descriptor, + new SwiftStructureAddress(addrPair.structAddr(), addrPair.pointerAddr()))); + } + } + } + catch (IOException e) { + log("Failed to parse type descriptors from section '" + section + "'"); + } + } + + /** + * Parses a table of pointers to {@link SwiftStructure}s found in the given section + * + * @param section The {@link SwiftSection} that contains the pointer table + * @param reader A {@link BinaryReader} + * @return A {@link List} of {@link SwiftStructureAddress}s + * @throws CancelledException if the user cancelled the operation + */ + private List parsePointerTable(SwiftSection section, BinaryReader reader) + throws CancelledException { + final int POINTER_SIZE = 4; + List result = new ArrayList<>(); + try { + for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) { + Address blockAddr = block.getStart(); + for (int i = 0; i < block.getSize(); i += POINTER_SIZE) { + monitor.checkCancelled(); + reader.setPointerIndex(blockAddr.getOffset() + i); + Address pointerAddr = blockAddr.add(i); + int offset = reader.readInt(pointerAddr.getOffset()); + if (offset == 0) { + break; + } + Address structAddr = pointerAddr.add(offset); + result.add(new SwiftStructureAddress(structAddr, pointerAddr)); + } + } + } + catch (IOException e) { + log("Failed to parse Swift struction pointers from section '" + section + "'"); + } + return result; + } + + /** + * Marks up this {@link SwiftTypeMetadata} with data structures and comments + * + * @throws CancelledException if the user cancelled the operation + */ + public void markup() throws CancelledException { + monitor.setMessage("Marking up Swift structures..."); + monitor.initialize(markupList.size()); + for (SwiftStructureInfo structInfo : markupList) { + monitor.checkCancelled(); + monitor.incrementProgress(1); + try { + SwiftStructure struct = structInfo.struct(); + DataType dt = struct.toDataType(); + DataUtilities.createData(program, structInfo.addr().structAddr(), dt, -1, + ClearDataMode.CLEAR_ALL_DEFAULT_CONFLICT_DATA); + 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); + } + } + catch (CodeUnitInsertionException | DuplicateNameException | IOException e) { + log("Failed to markup: " + structInfo); + } + } + } + + /** + * Convenience method to perform logging + * + * @param message The message to log + */ + private void log(String message) { + log.appendMsg(SwiftTypeMetadata.class.getSimpleName(), message); + } + + /** + * The {@link Address} of a {@link SwiftStructure} and the optional {@link Address} of its + * pointer + * + * @param structAddr The {@link Address} of a {@link SwiftStructure} + * @param pointerAddr The {@link Address} of a pointer to a {@link SwiftStructure} (could be + * null if there is no associated pointer} + */ + private record SwiftStructureAddress(Address structAddr, Address pointerAddr) {} + + /** + * Information about a {@link SwiftStructure} + * + * @param struct The {@link SwiftStructure} + * @param addr The {@link SwiftStructureAddress address} of the {@link SwiftStructure} + */ + private record SwiftStructureInfo(SwiftStructure struct, SwiftStructureAddress addr) { + + @Override + public String toString() { + return "%s %s".formatted(struct.getDescription(), addr); + } + } +} 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 new file mode 100644 index 0000000000..2c3097c345 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/SwiftUtils.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; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryBlock; + +/** + * Swift-related utility methods + */ +public class SwiftUtils { + + /** + * A {@link PointerTypedef pointer} to a relative 4-byte offset + */ + public static final PointerTypedef PTR_RELATIVE = + new PointerTypedef(null, null, 4, null, PointerType.RELATIVE); + + /** + * A {@link PointerTypedef string pointer} to a 4-byte relative offset + */ + public static final PointerTypedef PTR_STRING = + new PointerTypedef(null, StringDataType.dataType, 4, null, PointerType.RELATIVE); + + /** + * Checks if the given {@link Program} is a Swift program + * + * @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"); + for (MemoryBlock block : program.getMemory().getBlocks()) { + if (prefixes.stream().anyMatch(prefix -> block.getName().startsWith(prefix))) { + return true; + } + } + return false; + } + + /** + * Gets 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<>(); + for (MemoryBlock block : program.getMemory().getBlocks()) { + for (String sectionName : section.getSwiftSectionNames()) { + if (block.getName().equals(sectionName)) { + result.add(block); + break; + } + } + } + return result; + } + + /** + * Reads the integer at the current index and uses it as a relative pointer to read and + * return a string at that location. When the read completes, the {@link BinaryReader} will + * be positioned directly after the initial relative pointer that was read. + * + * @param reader A {@link BinaryReader} positioned at the start of relative string pointer + * @return The read string + * @throws IOException if there was an IO-related problem during the reads + */ + public static String relativeString(BinaryReader reader) throws IOException { + long fieldIndex = reader.getPointerIndex(); + int offset = reader.readNextInt(); + return reader.readAsciiString(fieldIndex + offset); + } +} 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 new file mode 100644 index 0000000000..5b32c6e1b0 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/AssociatedTypeDescriptor.java @@ -0,0 +1,130 @@ +/* ### + * 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.SwiftStructure; +import ghidra.app.util.bin.format.swift.SwiftUtils; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift AssociatedTypeDescriptor structure + * + * @see swift/RemoteInspection/Records.h + */ +public final class AssociatedTypeDescriptor implements SwiftStructure { + + /** + * The size (in bytes) of an {@link AssociatedTypeDescriptor} structure + */ + public static final int SIZE = 16; + + private String conformingTypeName; + private String protocolTypeName; + private int numAssociatedTypes; + private int associatedTypeRecordSize; + + private List associatedTypeRecords = new ArrayList<>(); + + /** + * Creates a new {@link AssociatedTypeDescriptor} + * + * @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 AssociatedTypeDescriptor(BinaryReader reader) throws IOException { + conformingTypeName = reader.readNext(SwiftUtils::relativeString); + protocolTypeName = reader.readNext(SwiftUtils::relativeString); + numAssociatedTypes = reader.readNextInt(); + associatedTypeRecordSize = reader.readNextInt(); + + for (int i = 0; i < numAssociatedTypes; i++) { + associatedTypeRecords.add(new AssociatedTypeRecord(reader)); + } + } + + /** + * Gets the conforming type name + * + * @return The conforming type name + */ + public String getConformingTypeName() { + return conformingTypeName; + } + + /** + * Gets 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 + */ + public int getNumAssociatedTypes() { + return numAssociatedTypes; + } + + /** + * Gets 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 + */ + public List getAssociatedTypeRecords() { + return associatedTypeRecords; + } + + @Override + public String getStructureName() { + return AssociatedTypeDescriptor.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "associated type descriptor"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(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 new file mode 100644 index 0000000000..04b43d7999 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/AssociatedTypeRecord.java @@ -0,0 +1,89 @@ +/* ### + * 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.SwiftStructure; +import ghidra.app.util.bin.format.swift.SwiftUtils; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift AssociatedTypeRecord structure + * + * @see swift/RemoteInspection/Records.h + */ +public final class AssociatedTypeRecord implements SwiftStructure { + + /** + * The size (in bytes) of an {@link AssociatedTypeRecord} structure + */ + public static final int SIZE = 8; + + private String name; + private String substitutedTypeName; + + /** + * Creates a new {@link AssociatedTypeRecord} + * + * @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 AssociatedTypeRecord(BinaryReader reader) throws IOException { + name = reader.readNext(SwiftUtils::relativeString); + substitutedTypeName = reader.readNext(SwiftUtils::relativeString); + } + + /** + * Gets the name + * + * @return The name + */ + public String getName() { + return name; + } + + /** + * Gets the substituted type name + * + * @return The substituted type name + */ + public String getSubstitutedTypeName() { + return substitutedTypeName; + } + + @Override + public String getStructureName() { + return AssociatedTypeRecord.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "associated type record"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(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 new file mode 100644 index 0000000000..896608c967 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/BuiltinTypeDescriptor.java @@ -0,0 +1,124 @@ +/* ### + * 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.*; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift BuiltinTypeDescriptor structure + * + * @see swift/RemoteInspection/Records.h + */ +public final class BuiltinTypeDescriptor implements SwiftStructure { + + /** + * The size (in bytes) of a {@link BuiltinTypeDescriptor} structure + */ + public static final int SIZE = 20; + + private String typeName; + private int size; + private int alignmentAndFlags; + private int stride; + private int numExtraInhabitants; + + /** + * Creates a new {@link BuiltinTypeDescriptor} + * + * @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 BuiltinTypeDescriptor(BinaryReader reader) throws IOException { + typeName = reader.readNext(SwiftUtils::relativeString); + size = reader.readNextInt(); + alignmentAndFlags = reader.readNextInt(); + stride = reader.readNextInt(); + numExtraInhabitants = reader.readNextInt(); + } + + /** + * Gets the type name + * + * @return The type name + */ + public String getTypeName() { + return typeName; + } + + /** + * Gets the size + * + * @return The size + */ + public int getSize() { + return size; + } + + /** + * Gets the alignment and flags + * + * @return The alignment and flags + */ + public int getAlignmentAndFlags() { + return alignmentAndFlags; + } + + /** + * Gets the stride + * + * @return The stride + */ + public int getStride() { + return stride; + } + + /** + * Gets the number of extra inhabitants + * + * @return The number of extra inhabitants + */ + public int getNumExtraInhabitants() { + return numExtraInhabitants; + } + + @Override + public String getStructureName() { + return BuiltinTypeDescriptor.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "builtin type descriptor"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(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 new file mode 100644 index 0000000000..96b1bb78a2 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/CaptureDescriptor.java @@ -0,0 +1,133 @@ +/* ### + * 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.SwiftStructure; +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 CaptureDescriptor structure + * + * @see swift/RemoteInspection/Records.h + */ +public final class CaptureDescriptor implements SwiftStructure { + + /** + * The size (in bytes) of a {@link CaptureDescriptor} structure + */ + public static final int SIZE = 12; + + private int numCaptureTypes; + private int numMetadataSources; + private int numBindings; + + private List captureTypeRecords = new ArrayList<>(); + private List metadataSourceRecords = new ArrayList<>(); + + /** + * Creates a new {@link CaptureDescriptor} + * + * @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 CaptureDescriptor(BinaryReader reader) throws IOException { + numCaptureTypes = reader.readNextInt(); + numMetadataSources = reader.readNextInt(); + numBindings = reader.readNextInt(); + + for (int i = 0; i < numCaptureTypes; i++) { + captureTypeRecords.add(new CaptureTypeRecord(reader)); + } + + for (int i = 0; i < numMetadataSources; i++) { + metadataSourceRecords.add(new MetadataSourceRecord(reader)); + } + } + + /** + * Gets 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 + */ + public int getNumMetadataSources() { + return numMetadataSources; + } + + /** + * Gets 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 + */ + public List getCaptureTypeRecords() { + return captureTypeRecords; + } + + /** + * Gets the {@link List} of {@link MetadataSourceRecord}s + * + * @return The {@link List} of {@link MetadataSourceRecord}s + */ + public List getMetadataSourceRecords() { + return metadataSourceRecords; + } + + @Override + public String getStructureName() { + return CaptureDescriptor.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "capture descriptor"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(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 new file mode 100644 index 0000000000..8101cc3c55 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/CaptureTypeRecord.java @@ -0,0 +1,77 @@ +/* ### + * 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.*; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift CaptureTypeRecord structure + * + * @see swift/RemoteInspection/Records.h + */ +public final class CaptureTypeRecord implements SwiftStructure { + + /** + * The size (in bytes) of a {@link CaptureTypeRecord} structure + */ + public static final int SIZE = 4; + + private String mangledTypeName; + + /** + * Creates a new {@link CaptureTypeRecord} + * + * @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 CaptureTypeRecord(BinaryReader reader) throws IOException { + mangledTypeName = reader.readNext(SwiftUtils::relativeString); + + } + + /** + * Gets the mangled type name + * + * @return The mangled type name + */ + public String getMangledTypeName() { + return mangledTypeName; + } + + @Override + public String getStructureName() { + return CaptureTypeRecord.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "capture type record"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(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/ContextDescriptorKind.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ContextDescriptorKind.java new file mode 100644 index 0000000000..48faf502c2 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/ContextDescriptorKind.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; + +/** + * Swift 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; + } + + //--------------------------------------------------------------------------------------------- + + /** + * This context descriptor represents a module + */ + public static final int MODULE = 0; + + /** + * This context descriptor represents an extension + */ + public static final int EXTENSION = 1; + + /** + * This context descriptor represents an anonymous possibly-generic context such as a function + * body + */ + public static final int ANONYMOUS = 2; + + /** + * This context descriptor represents a protocol context + */ + public static final int 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; + + /** + * This context descriptor represents a class + */ + public static final int CLASS = TYPE_FIRST; + + /** + * This context descriptor represents a struct + */ + public static final int STRUCT = TYPE_FIRST + 1; + + /** + * This context descriptor represents an enum + */ + public static final int ENUM = TYPE_FIRST + 2; + + /** + * Last kind that represents a type of any sort + */ + public static final int TYPE_LAST = 31; +} 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 new file mode 100644 index 0000000000..31055a01f4 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/EntryPoint.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.SwiftStructure; +import ghidra.app.util.bin.format.swift.SwiftUtils; +import ghidra.program.model.data.DataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift entry point + */ +public final class EntryPoint implements SwiftStructure { + + /** + * The size (in bytes) of an {@link EntryPoint} structure + */ + public static final int SIZE = 4; + + private int entryPoint; + + /** + * Creates a new {@link EntryPoint} + * + * @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 EntryPoint(BinaryReader reader) throws IOException { + entryPoint = reader.readNextInt(); + } + + /** + * Gets the entry point + * + * @return The entry point + */ + public int getEntryPoint() { + return entryPoint; + } + + @Override + public String getStructureName() { + return EntryPoint.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "entry point"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + return SwiftUtils.PTR_RELATIVE; + } + +} 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 new file mode 100644 index 0000000000..5798be7c99 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/FieldDescriptor.java @@ -0,0 +1,141 @@ +/* ### + * 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.*; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift FieldDescriptor structure + * + * @see swift/RemoteInspection/Records.h + */ +public final class FieldDescriptor implements SwiftStructure { + + /** + * The size (in bytes) of a {@link FieldDescriptor} structure + */ + public static final int SIZE = 16; + + private String mangledTypeName; + private int superclass; + private int kind; + private int fieldRecordSize; + private int numFields; + + private List fieldRecords = new ArrayList<>(); + + /** + * Creates a new {@link FieldDescriptor} + * + * @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 FieldDescriptor(BinaryReader reader) throws IOException { + mangledTypeName = reader.readNext(SwiftUtils::relativeString); + superclass = reader.readNextInt(); + kind = reader.readNextUnsignedShort(); + fieldRecordSize = reader.readNextUnsignedShort(); + numFields = reader.readNextInt(); + + for (int i = 0; i < numFields; i++) { + fieldRecords.add(new FieldRecord(reader)); + } + } + + /** + * Gets the mangled type name + * + * @return The mangled type name + */ + public String getMangledTypeName() { + return mangledTypeName; + } + + /** + * Gets the superclass + * + * @return The superclass + */ + public int getSuperclass() { + return superclass; + } + + /** + * Gets the kind + * + * @return The kind + */ + public int getKind() { + return kind; + } + + /** + * Gets the field record size + * + * @return The field record size + */ + public int getFieldRecordSize() { + return fieldRecordSize; + } + + /** + * Gets 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 + */ + public List getFieldRecords() { + return fieldRecords; + } + + @Override + public String getStructureName() { + return FieldDescriptor.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "field descriptor"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(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 new file mode 100644 index 0000000000..b4a9a9a067 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/FieldRecord.java @@ -0,0 +1,100 @@ +/* ### + * 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.*; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift FieldRecord structure + * + * @see swift/RemoteInspection/Records.h + */ +public final class FieldRecord implements SwiftStructure { + + /** + * The size (in bytes) of a {@link FieldRecord} structure + */ + public static final int SIZE = 12; + + private int flags; + private String mangledTypeName; + private String fieldName; + + /** + * Creates a new {@link FieldRecord} + * + * @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 FieldRecord(BinaryReader reader) throws IOException { + flags = reader.readNextInt(); + mangledTypeName = reader.readNext(SwiftUtils::relativeString); + fieldName = reader.readNext(SwiftUtils::relativeString); + } + + /** + * Gets the flags + * + * @return The flags + */ + public int getFlags() { + return flags; + } + + /** + * Gets the mangled type name + * + * @return The mangled type name + */ + public String getMangledTypeName() { + return mangledTypeName; + } + + /** + * Gets the field name + * + * @return The field name + */ + public String getFieldName() { + return fieldName; + } + + @Override + public String getStructureName() { + return FieldRecord.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "field record"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(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/MetadataSourceRecord.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MetadataSourceRecord.java new file mode 100644 index 0000000000..2d3d89df38 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MetadataSourceRecord.java @@ -0,0 +1,88 @@ +/* ### + * 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.*; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift MetadataSourceRecord structure + * + * @see swift/RemoteInspection/Records.h + */ +public final class MetadataSourceRecord implements SwiftStructure { + + /** + * The size (in bytes) of a {@link MetadataSourceRecord} structure + */ + public static final int SIZE = 8; + + private String mangledTypeName; + private String mangledMetadataSource; + + /** + * Creates a new {@link MetadataSourceRecord} + * + * @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 MetadataSourceRecord(BinaryReader reader) throws IOException { + mangledTypeName = reader.readNext(SwiftUtils::relativeString); + mangledMetadataSource = reader.readNext(SwiftUtils::relativeString); + } + + /** + * Gets the mangled type name + * + * @return The mangled type name + */ + public String getMangledTypeName() { + return mangledTypeName; + } + + /** + * Gets the mangled metadata source + * + * @return The mangled metadata source + */ + public String getMangledMetadataSource() { + return mangledMetadataSource; + } + + @Override + public String getStructureName() { + return MetadataSourceRecord.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "metadata source record"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(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/MultiPayloadEnumDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MultiPayloadEnumDescriptor.java new file mode 100644 index 0000000000..f8aa845839 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MultiPayloadEnumDescriptor.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 ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.swift.SwiftStructure; +import ghidra.app.util.bin.format.swift.SwiftUtils; +import ghidra.program.model.data.DataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift MultiPayloadEnumDescriptor structure + * + * @see swift/RemoteInspection/Records.h + */ +public final class MultiPayloadEnumDescriptor implements SwiftStructure { + + /** + * The size (in bytes) of a {@link MultiPayloadEnumDescriptor} structure. This size does not + * take into account the size of the contents array. + * + * @see #getContentsSize() + */ + public static final int SIZE = 4; + + private String typeName; + private int[] contents; + + /** + * Creates a new {@link MultiPayloadEnumDescriptor} + * + * @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 MultiPayloadEnumDescriptor(BinaryReader reader) throws IOException { + typeName = reader.readNext(SwiftUtils::relativeString); + int size = (reader.readNextInt() >> 16) & 0xffff; + reader.setPointerIndex(reader.getPointerIndex() - 4); + contents = reader.readNextIntArray(size); + } + + /** + * Gets the type name + * + * @return The type name + */ + public String getTypeName() { + return typeName; + } + + /** + * Gets 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 + */ + public long getContentsSize() { + return contents.length * Integer.BYTES; + } + + @Override + public String getStructureName() { + return MultiPayloadEnumDescriptor.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "multipayload enum descriptor"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + return SwiftUtils.PTR_STRING; + } +} 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 new file mode 100644 index 0000000000..26073e7b25 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetClassDescriptor.java @@ -0,0 +1,138 @@ +/* ### + * 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.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 TargetClassDescriptor structure + * + * @see swift/ABI/Metadata.h + */ +public final class TargetClassDescriptor extends TargetTypeContextDescriptor { + + private int superclassType; + private int metadataNegativeSizeInWords; + private int metadataPositiveSizeInWords; + private int numImmediateMembers; + private int numFields; + + /** + * Creates a new {@link TargetClassDescriptor} + * + * @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 TargetClassDescriptor(BinaryReader reader) throws IOException { + super(reader); + superclassType = reader.readNextInt(); + metadataNegativeSizeInWords = reader.readNextInt(); + metadataPositiveSizeInWords = reader.readNextInt(); + numImmediateMembers = reader.readNextInt(); + numFields = reader.readNextInt(); + } + + /** + * 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 + */ + 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 + */ + public int getMetadataNegativeSizeInWords() { + return metadataNegativeSizeInWords; + } + + /** + * 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. + */ + public int getMetadataPositiveSizeInWords() { + return metadataPositiveSizeInWords; + } + + /** + * 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 + */ + 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. + */ + public int getNumFields() { + return numFields; + } + + @Override + public String getStructureName() { + return TargetClassDescriptor.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "class descriptor"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(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(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.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 new file mode 100644 index 0000000000..ec464f2a6e --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetContextDescriptor.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.*; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift TargetContextDescriptor structure + * + * @see swift/ABI/Metadata.h + */ +public class TargetContextDescriptor implements SwiftStructure { + + private int flags; + private int parent; + + /** + * Create a new {@link TargetContextDescriptor} + * + * @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 TargetContextDescriptor(BinaryReader reader) throws IOException { + flags = reader.readNextInt(); + parent = reader.readNextInt(); + } + + /** + * Gets the flags + * + * @return The flags + */ + public int getFlags() { + return flags; + } + + /** + * Gets the parent's relative offset + * + * @return The parent's relative offset + */ + public int getParent() { + return parent; + } + + @Override + public String getStructureName() { + return getMyStructureName(); + } + + @Override + public String getDescription() { + return "context descriptor"; + } + + /** + * Gets this class's structure name (will not be affected by subclass's name) + * + * @return This class's structure name + */ + private final String getMyStructureName() { + return TargetContextDescriptor.class.getSimpleName(); + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(getMyStructureName(), 0); + struct.add(DWORD, "Flags", + "Flags describing the context, including its kind and format version"); + struct.add(SwiftUtils.PTR_RELATIVE, "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 new file mode 100644 index 0000000000..3b3b3f71ec --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetEnumDescriptor.java @@ -0,0 +1,88 @@ +/* ### + * 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.program.model.data.CategoryPath; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift TargetEnumDescriptor structure + * + * @see swift/ABI/Metadata.h + */ +public final class TargetEnumDescriptor extends TargetTypeContextDescriptor { + + private int numPayloadCasesAndPayloadSizeOffset; + private int numEmptyCases; + + /** + * Creates a new {@link TargetEnumDescriptor} + * + * @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 TargetEnumDescriptor(BinaryReader reader) throws IOException { + super(reader); + numPayloadCasesAndPayloadSizeOffset = reader.readNextInt(); + numEmptyCases = reader.readNextInt(); + } + + /** + * Gets 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; + + * @return The number of non-empty cases in the enum and the offset of the payload size + */ + public int getNumPayloadCasesAndPayloadSizeOffset() { + return numPayloadCasesAndPayloadSizeOffset; + } + + /** + * Gets the number of empty cases in the enum + * + * @return The number of empty cases in the enum + */ + public int getNumEmptyCases() { + return numEmptyCases; + } + + @Override + public String getStructureName() { + return TargetEnumDescriptor.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "enum descriptor"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(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/TargetProtocolConformanceDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetProtocolConformanceDescriptor.java new file mode 100644 index 0000000000..74d81c3afc --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetProtocolConformanceDescriptor.java @@ -0,0 +1,109 @@ +/* ### + * 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.*; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift TargetProtocolConformanceDescriptor structure + * + * @see swift/ABI/Metadata.h + */ +public final class TargetProtocolConformanceDescriptor implements SwiftStructure { + + private int protocolDescriptor; + private int nominalTypeDescriptor; + private int protocolWitnessTable; + private int conformanceFlags; + + /** + * Creates a new {@link TargetProtocolConformanceDescriptor} + * + * @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 TargetProtocolConformanceDescriptor(BinaryReader reader) throws IOException { + protocolDescriptor = reader.readNextInt(); + nominalTypeDescriptor = reader.readNextInt(); + protocolWitnessTable = reader.readNextInt(); + conformanceFlags = reader.readNextInt(); + } + + /** + * Gets the protocol being conformed to + * + * @return The protocol being conformed to + */ + public int getProtocolDescriptor() { + return protocolDescriptor; + } + + /** + * Gets 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; + } + + /** + * 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 + */ + public int getProtocolWitnessTable() { + return protocolWitnessTable; + } + + /** + * Gets various flags, including the kind of conformance + * + * @return Various flags, including the kind of conformance + */ + public int getConformanceFlags() { + return conformanceFlags; + } + + @Override + public String getStructureName() { + return TargetProtocolConformanceDescriptor.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "protocol conformance descriptor"; + } + + @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", + "Some description of the type that conforms to the protocol"); + struct.add(DWORD, "ProtocolWitnessTable", + "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)); + 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 new file mode 100644 index 0000000000..3aa6ce1c07 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetProtocolDescriptor.java @@ -0,0 +1,118 @@ +/* ### + * 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.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 + * + * @see swift/ABI/Metadata.h + */ +public final class TargetProtocolDescriptor extends TargetContextDescriptor { + + private String name; + private int numRequirementsInSig; + private int numRequirements; + private int associatedTypeNames; + + /** + * Creates a new {@link TargetProtocolDescriptor} + * + * @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 TargetProtocolDescriptor(BinaryReader reader) throws IOException { + super(reader); + name = reader.readNext(SwiftUtils::relativeString); + numRequirementsInSig = reader.readNextInt(); + numRequirements = reader.readNextInt(); + associatedTypeNames = reader.readNextInt(); + } + + /** + * Gets 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 + */ + public int getNumRequirementsInSignature() { + return numRequirementsInSig; + } + + /** + * Gets 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 + */ + public int getAssociatedTypeNames() { + return associatedTypeNames; // TODO: it's a list...improve + } + + @Override + public String toString() { + return name; + } + + @Override + public String getStructureName() { + return TargetProtocolDescriptor.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "protocol descriptor"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(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", + "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/TargetStructDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetStructDescriptor.java new file mode 100644 index 0000000000..092bd49739 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetStructDescriptor.java @@ -0,0 +1,92 @@ +/* ### + * 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.program.model.data.CategoryPath; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.StructureDataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift TargetStructDescriptor structure + * + * @see swift/ABI/Metadata.h + */ +public final class TargetStructDescriptor extends TargetTypeContextDescriptor { + + private int numFields; + private int fieldOffsetVectorOffset; + + /** + * Creates a new {@link TargetStructDescriptor} + * + * @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 TargetStructDescriptor(BinaryReader reader) throws IOException { + super(reader); + numFields = reader.readNextInt(); + fieldOffsetVectorOffset = reader.readNextInt(); + } + + /** + * 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. + */ + 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. + */ + public int getFieldOffsetVectorOffset() { + return fieldOffsetVectorOffset; + } + + @Override + public String getStructureName() { + return TargetStructDescriptor.class.getSimpleName(); + } + + @Override + public String getDescription() { + return "struct descriptor"; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(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 new file mode 100644 index 0000000000..3b2f10ea9c --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetTypeContextDescriptor.java @@ -0,0 +1,112 @@ +/* ### + * 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.SwiftUtils; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a Swift TargetTypeContextDescriptor structure + * + * @see swift/ABI/Metadata.h + */ +public class TargetTypeContextDescriptor extends TargetContextDescriptor { + + private String name; + private int accessFunctionPtr; + private int fields; + + /** + * Creates a new {@link TargetTypeContextDescriptor} + * + * @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 TargetTypeContextDescriptor(BinaryReader reader) throws IOException { + super(reader); + name = reader.readNext(SwiftUtils::relativeString); + accessFunctionPtr = reader.readNextInt(); + fields = reader.readNextInt(); + } + + /** + * Gets 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 + */ + 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 + */ + public int getFields() { + return fields; + } + + @Override + public String getStructureName() { + return getMyStructureName(); + } + + @Override + public String getDescription() { + return "type context descriptor"; + } + + @Override + public String toString() { + return name; + } + + /** + * Gets this class's structure name (will not be affected by subclass's name) + * + * @return This class's structure name + */ + private final String getMyStructureName() { + return TargetTypeContextDescriptor.class.getSimpleName(); + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType(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; + } +}