Merge remote-tracking branch 'origin/GP-2085_ryanmkurtz_Swift-Metadata--SQUASHED'

This commit is contained in:
Ryan Kurtz 2023-06-12 13:07:03 -04:00
commit 176bdea28a
23 changed files with 2654 additions and 0 deletions

View File

@ -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;
}
}

View File

@ -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 <a href="https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/BinaryFormat/Swift.def">llvm/BinaryFormat/Swift.def</a>
*/
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<String> 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<String> getSwiftSectionNames() {
return sectionNames;
}
}

View File

@ -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();
}

View File

@ -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<EntryPoint> entryPoints = new ArrayList<>();
private List<BuiltinTypeDescriptor> builtinTypeDescriptors = new ArrayList<>();
private List<FieldDescriptor> fieldDescriptors = new ArrayList<>();
private List<AssociatedTypeDescriptor> associatedTypeDescriptors = new ArrayList<>();
private List<CaptureDescriptor> captureDescriptors = new ArrayList<>();
private List<MultiPayloadEnumDescriptor> mpEnumDescriptors = new ArrayList<>();
private List<TargetTypeContextDescriptor> typeDescriptors = new ArrayList<>();
private List<TargetProtocolDescriptor> protocolDescriptors = new ArrayList<>();
private List<TargetProtocolConformanceDescriptor> protocolConformanceDescriptors =
new ArrayList<>();
private List<SwiftStructureInfo> 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<FieldRecord> 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<AssociatedTypeRecord> 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<CaptureTypeRecord> 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<MetadataSourceRecord> 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<SwiftStructureAddress> 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<SwiftStructureAddress> 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<SwiftStructureAddress> 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<SwiftStructureAddress> parsePointerTable(SwiftSection section, BinaryReader reader)
throws CancelledException {
final int POINTER_SIZE = 4;
List<SwiftStructureAddress> 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);
}
}
}

View File

@ -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<String> 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<MemoryBlock> getSwiftBlocks(SwiftSection section, Program program) {
List<MemoryBlock> 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);
}
}

View File

@ -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 <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
*/
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<AssociatedTypeRecord> 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<AssociatedTypeRecord> 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;
}
}

View File

@ -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 <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
*/
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;
}
}

View File

@ -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 <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
*/
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;
}
}

View File

@ -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 <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
*/
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<CaptureTypeRecord> captureTypeRecords = new ArrayList<>();
private List<MetadataSourceRecord> 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<CaptureTypeRecord> getCaptureTypeRecords() {
return captureTypeRecords;
}
/**
* Gets the {@link List} of {@link MetadataSourceRecord}s
*
* @return The {@link List} of {@link MetadataSourceRecord}s
*/
public List<MetadataSourceRecord> 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;
}
}

View File

@ -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 <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
*/
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;
}
}

View File

@ -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 <a href="https://github.com/apple/swift/blob/main/include/swift/ABI/MetadataValues.h">swift/ABI/MetadataValues.h</a>
*/
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;
}

View File

@ -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;
}
}

View File

@ -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 <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
*/
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<FieldRecord> 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<FieldRecord> 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;
}
}

View File

@ -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 <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
*/
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;
}
}

View File

@ -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 <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
*/
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;
}
}

View File

@ -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 <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
*/
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 <code>contents</code> 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;
}
}

View File

@ -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 <a href="https://github.com/apple/swift/blob/main/include/swift/ABI/Metadata.h">swift/ABI/Metadata.h</a>
*/
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;
}
}

View File

@ -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 <a href="https://github.com/apple/swift/blob/main/include/swift/ABI/Metadata.h">swift/ABI/Metadata.h</a>
*/
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;
}
}

View File

@ -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 <a href="https://github.com/apple/swift/blob/main/include/swift/ABI/Metadata.h">swift/ABI/Metadata.h</a>
*/
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;
}
}

View File

@ -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 <a href="https://github.com/apple/swift/blob/main/include/swift/ABI/Metadata.h">swift/ABI/Metadata.h</a>
*/
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;
}
}

View File

@ -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 <a href="https://github.com/apple/swift/blob/main/include/swift/ABI/Metadata.h">swift/ABI/Metadata.h</a>
*/
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;
}
}

View File

@ -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 <a href="https://github.com/apple/swift/blob/main/include/swift/ABI/Metadata.h">swift/ABI/Metadata.h</a>
*/
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;
}
}

View File

@ -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 <a href="https://github.com/apple/swift/blob/main/include/swift/ABI/Metadata.h">swift/ABI/Metadata.h</a>
*/
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;
}
}