GP-3535: Improved Swift support

This commit is contained in:
Ryan Kurtz
2024-02-26 11:31:24 -05:00
parent 74d52deabf
commit 32a0cf750b
104 changed files with 6438 additions and 161 deletions
@@ -31,6 +31,8 @@ public class SwiftTypeMetadataAnalyzer extends AbstractAnalyzer {
private static final String NAME = "Swift Type Metadata Analyzer"; private static final String NAME = "Swift Type Metadata Analyzer";
private static final String DESCRIPTION = "Discovers Swift type metadata records."; private static final String DESCRIPTION = "Discovers Swift type metadata records.";
private SwiftTypeMetadata typeMetadata;
public SwiftTypeMetadataAnalyzer() { public SwiftTypeMetadataAnalyzer() {
super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER); super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER);
setDefaultEnablement(true); setDefaultEnablement(true);
@@ -45,8 +47,11 @@ public class SwiftTypeMetadataAnalyzer extends AbstractAnalyzer {
@Override @Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException { throws CancelledException {
if (typeMetadata != null) {
return true;
}
try { try {
SwiftTypeMetadata typeMetadata = new SwiftTypeMetadata(program, monitor, log); typeMetadata = new SwiftTypeMetadata(program, monitor, log);
typeMetadata.markup(); typeMetadata.markup();
} }
catch (IOException e) { catch (IOException e) {
@@ -54,4 +59,9 @@ public class SwiftTypeMetadataAnalyzer extends AbstractAnalyzer {
} }
return true; return true;
} }
@Override
public void analysisEnded(Program program) {
typeMetadata = null;
}
} }
@@ -35,8 +35,9 @@ public enum SwiftSection {
BLOCK_PROTOCS("__swift5_protos", "swift5_protocols", ".sw5prt"), BLOCK_PROTOCS("__swift5_protos", "swift5_protocols", ".sw5prt"),
BLOCK_ACFUNCS("__swift5_acfuncs", "swift5_accessible_functions", ".sw5acfn"), BLOCK_ACFUNCS("__swift5_acfuncs", "swift5_accessible_functions", ".sw5acfn"),
BLOCK_MPENUM("__swift5_mpenum", "swift5_mpenum", ".sw5mpen"), BLOCK_MPENUM("__swift5_mpenum", "swift5_mpenum", ".sw5mpen"),
BLOCK_TYPES("__swift5_types", "swift5_types", ".sw5tymd"), BLOCK_TYPES("__swift5_types", "swift5_type_metadata", ".sw5tymd"),
BLOCK_ENTRY("__swift5_entry", "swift5_entry", ".sw5entr"); BLOCK_ENTRY("__swift5_entry", "swift5_entry", ".sw5entr"),
BLOCK_SWIFTAST("__swift_ast", ".swift_ast", "swiftast");
private List<String> sectionNames; private List<String> sectionNames;
@@ -16,8 +16,7 @@
package ghidra.app.util.bin.format.swift; package ghidra.app.util.bin.format.swift;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import ghidra.app.util.bin.*; import ghidra.app.util.bin.*;
import ghidra.app.util.bin.format.swift.types.*; import ghidra.app.util.bin.format.swift.types.*;
@@ -43,11 +42,11 @@ public class SwiftTypeMetadata {
private List<EntryPoint> entryPoints = new ArrayList<>(); private List<EntryPoint> entryPoints = new ArrayList<>();
private List<BuiltinTypeDescriptor> builtinTypeDescriptors = new ArrayList<>(); private List<BuiltinTypeDescriptor> builtinTypeDescriptors = new ArrayList<>();
private List<FieldDescriptor> fieldDescriptors = new ArrayList<>(); private Map<Long, FieldDescriptor> fieldDescriptors = new HashMap<>();
private List<AssociatedTypeDescriptor> associatedTypeDescriptors = new ArrayList<>(); private List<AssociatedTypeDescriptor> associatedTypeDescriptors = new ArrayList<>();
private List<CaptureDescriptor> captureDescriptors = new ArrayList<>(); private List<CaptureDescriptor> captureDescriptors = new ArrayList<>();
private List<MultiPayloadEnumDescriptor> mpEnumDescriptors = new ArrayList<>(); private List<MultiPayloadEnumDescriptor> mpEnumDescriptors = new ArrayList<>();
private List<TargetTypeContextDescriptor> typeDescriptors = new ArrayList<>(); private Map<String, TargetTypeContextDescriptor> typeDescriptors = new HashMap<>();
private List<TargetProtocolDescriptor> protocolDescriptors = new ArrayList<>(); private List<TargetProtocolDescriptor> protocolDescriptors = new ArrayList<>();
private List<TargetProtocolConformanceDescriptor> protocolConformanceDescriptors = private List<TargetProtocolConformanceDescriptor> protocolConformanceDescriptors =
new ArrayList<>(); new ArrayList<>();
@@ -72,6 +71,69 @@ public class SwiftTypeMetadata {
parse(); parse();
} }
/**
* {@return the entry points}
*/
public List<EntryPoint> getEntryPoints() {
return entryPoints;
}
/**
* {@return the built-in type descriptors}
*/
public List<BuiltinTypeDescriptor> getBuiltinTypeDescriptors() {
return builtinTypeDescriptors;
}
/**
* {@return the field descriptors}
*/
public Map<Long, FieldDescriptor> getFieldDescriptors() {
return fieldDescriptors;
}
/**
* {@return the associated type descriptors}
*/
public List<AssociatedTypeDescriptor> getAssociatedTypeDescriptor() {
return associatedTypeDescriptors;
}
/**
* {@return the capture descriptors}
*/
public List<CaptureDescriptor> getCaptureDescriptors() {
return captureDescriptors;
}
/**
* {@return the multi-payload enum descriptors}
*/
public List<MultiPayloadEnumDescriptor> getMultiPayloadEnumDescriptors() {
return mpEnumDescriptors;
}
/**
* {@return the type descriptors}
*/
public Map<String, TargetTypeContextDescriptor> getTargetTypeContextDescriptors() {
return typeDescriptors;
}
/**
* {@return the target protocol descriptors}
*/
public List<TargetProtocolDescriptor> getTargetProtocolDescriptors() {
return protocolDescriptors;
}
/**
* {@return the target protocol conformance descriptors}
*/
public List<TargetProtocolConformanceDescriptor> getTargetProtocolConformanceDescriptors() {
return protocolConformanceDescriptors;
}
/** /**
* Parses the {@link SwiftTypeMetadata} * Parses the {@link SwiftTypeMetadata}
* *
@@ -137,7 +199,7 @@ public class SwiftTypeMetadata {
for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) { for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) {
Address blockStart = block.getStart(); Address blockStart = block.getStart();
reader.setPointerIndex(blockStart.getOffset()); reader.setPointerIndex(blockStart.getOffset());
int i = 0; int i = skipZeroEntries(reader, 0, block.getSize());
while (i + BuiltinTypeDescriptor.SIZE <= block.getSize()) { while (i + BuiltinTypeDescriptor.SIZE <= block.getSize()) {
monitor.checkCancelled(); monitor.checkCancelled();
BuiltinTypeDescriptor descriptor = new BuiltinTypeDescriptor(reader); BuiltinTypeDescriptor descriptor = new BuiltinTypeDescriptor(reader);
@@ -145,6 +207,7 @@ public class SwiftTypeMetadata {
markupList.add(new SwiftStructureInfo(descriptor, markupList.add(new SwiftStructureInfo(descriptor,
new SwiftStructureAddress(blockStart.add(i), null))); new SwiftStructureAddress(blockStart.add(i), null)));
i += BuiltinTypeDescriptor.SIZE; i += BuiltinTypeDescriptor.SIZE;
i = skipZeroEntries(reader, i, block.getSize());
} }
} }
} }
@@ -168,11 +231,11 @@ public class SwiftTypeMetadata {
for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) { for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) {
Address blockStart = block.getStart(); Address blockStart = block.getStart();
reader.setPointerIndex(blockStart.getOffset()); reader.setPointerIndex(blockStart.getOffset());
int i = 0; int i = skipZeroEntries(reader, 0, block.getSize());
while (i + FieldDescriptor.SIZE <= block.getSize()) { while (i + FieldDescriptor.SIZE <= block.getSize()) {
monitor.checkCancelled(); monitor.checkCancelled();
FieldDescriptor descriptor = new FieldDescriptor(reader); FieldDescriptor descriptor = new FieldDescriptor(reader);
fieldDescriptors.add(descriptor); fieldDescriptors.put(descriptor.getBase(), descriptor);
markupList.add(new SwiftStructureInfo(descriptor, markupList.add(new SwiftStructureInfo(descriptor,
new SwiftStructureAddress(blockStart.add(i), null))); new SwiftStructureAddress(blockStart.add(i), null)));
List<FieldRecord> records = descriptor.getFieldRecords(); List<FieldRecord> records = descriptor.getFieldRecords();
@@ -184,6 +247,7 @@ public class SwiftTypeMetadata {
null))); null)));
} }
i += descriptor.getNumFields() * FieldRecord.SIZE; i += descriptor.getNumFields() * FieldRecord.SIZE;
i = skipZeroEntries(reader, i, block.getSize());
} }
} }
} }
@@ -207,7 +271,7 @@ public class SwiftTypeMetadata {
for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) { for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) {
Address blockStart = block.getStart(); Address blockStart = block.getStart();
reader.setPointerIndex(blockStart.getOffset()); reader.setPointerIndex(blockStart.getOffset());
int i = 0; int i = skipZeroEntries(reader, 0, block.getSize());
while (i + AssociatedTypeDescriptor.SIZE <= block.getSize()) { while (i + AssociatedTypeDescriptor.SIZE <= block.getSize()) {
monitor.checkCancelled(); monitor.checkCancelled();
AssociatedTypeDescriptor descriptor = new AssociatedTypeDescriptor(reader); AssociatedTypeDescriptor descriptor = new AssociatedTypeDescriptor(reader);
@@ -223,6 +287,7 @@ public class SwiftTypeMetadata {
blockStart.add(i + j * AssociatedTypeRecord.SIZE), null))); blockStart.add(i + j * AssociatedTypeRecord.SIZE), null)));
} }
i += descriptor.getNumAssociatedTypes() * AssociatedTypeRecord.SIZE; i += descriptor.getNumAssociatedTypes() * AssociatedTypeRecord.SIZE;
i = skipZeroEntries(reader, i, block.getSize());
} }
} }
} }
@@ -246,7 +311,7 @@ public class SwiftTypeMetadata {
for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) { for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) {
Address blockStart = block.getStart(); Address blockStart = block.getStart();
reader.setPointerIndex(blockStart.getOffset()); reader.setPointerIndex(blockStart.getOffset());
int i = 0; int i = skipZeroEntries(reader, 0, block.getSize());
while (i + CaptureDescriptor.SIZE <= block.getSize()) { while (i + CaptureDescriptor.SIZE <= block.getSize()) {
monitor.checkCancelled(); monitor.checkCancelled();
CaptureDescriptor descriptor = new CaptureDescriptor(reader); CaptureDescriptor descriptor = new CaptureDescriptor(reader);
@@ -271,6 +336,7 @@ public class SwiftTypeMetadata {
blockStart.add(i + j * MetadataSourceRecord.SIZE), null))); blockStart.add(i + j * MetadataSourceRecord.SIZE), null)));
} }
i += descriptor.getNumMetadataSources() * MetadataSourceRecord.SIZE; i += descriptor.getNumMetadataSources() * MetadataSourceRecord.SIZE;
i = skipZeroEntries(reader, i, block.getSize());
} }
} }
} }
@@ -294,7 +360,7 @@ public class SwiftTypeMetadata {
for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) { for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) {
Address blockStart = block.getStart(); Address blockStart = block.getStart();
reader.setPointerIndex(blockStart.getOffset()); reader.setPointerIndex(blockStart.getOffset());
int i = 0; int i = skipZeroEntries(reader, 0, block.getSize());
while (i < block.getSize()) { while (i < block.getSize()) {
monitor.checkCancelled(); monitor.checkCancelled();
MultiPayloadEnumDescriptor descriptor = new MultiPayloadEnumDescriptor(reader); MultiPayloadEnumDescriptor descriptor = new MultiPayloadEnumDescriptor(reader);
@@ -302,6 +368,7 @@ public class SwiftTypeMetadata {
markupList.add(new SwiftStructureInfo(descriptor, markupList.add(new SwiftStructureInfo(descriptor,
new SwiftStructureAddress(blockStart.add(i), null))); new SwiftStructureAddress(blockStart.add(i), null)));
i += MultiPayloadEnumDescriptor.SIZE + descriptor.getContentsSize(); i += MultiPayloadEnumDescriptor.SIZE + descriptor.getContentsSize();
i = skipZeroEntries(reader, i, block.getSize());
} }
} }
} }
@@ -397,7 +464,7 @@ public class SwiftTypeMetadata {
yield null; yield null;
}; };
if (descriptor != null) { if (descriptor != null) {
typeDescriptors.add(descriptor); typeDescriptors.put(descriptor.getName(), descriptor);
markupList.add(new SwiftStructureInfo(descriptor, markupList.add(new SwiftStructureInfo(descriptor,
new SwiftStructureAddress(addrPair.structAddr(), addrPair.pointerAddr()))); new SwiftStructureAddress(addrPair.structAddr(), addrPair.pointerAddr())));
} }
@@ -409,7 +476,7 @@ public class SwiftTypeMetadata {
} }
/** /**
* Parses a table of pointers to {@link SwiftStructure}s found in the given section * Parses a table of pointers to {@link SwiftTypeMetadataStructure}s found in the given section
* *
* @param section The {@link SwiftSection} that contains the pointer table * @param section The {@link SwiftSection} that contains the pointer table
* @param reader A {@link BinaryReader} * @param reader A {@link BinaryReader}
@@ -428,11 +495,10 @@ public class SwiftTypeMetadata {
reader.setPointerIndex(blockAddr.getOffset() + i); reader.setPointerIndex(blockAddr.getOffset() + i);
Address pointerAddr = blockAddr.add(i); Address pointerAddr = blockAddr.add(i);
int offset = reader.readInt(pointerAddr.getOffset()); int offset = reader.readInt(pointerAddr.getOffset());
if (offset == 0) { if (offset != 0) {
break; Address structAddr = pointerAddr.add(offset);
result.add(new SwiftStructureAddress(structAddr, pointerAddr));
} }
Address structAddr = pointerAddr.add(offset);
result.add(new SwiftStructureAddress(structAddr, pointerAddr));
} }
} }
} }
@@ -454,7 +520,7 @@ public class SwiftTypeMetadata {
monitor.checkCancelled(); monitor.checkCancelled();
monitor.incrementProgress(1); monitor.incrementProgress(1);
try { try {
SwiftStructure struct = structInfo.struct(); SwiftTypeMetadataStructure struct = structInfo.struct();
DataType dt = struct.toDataType(); DataType dt = struct.toDataType();
DataUtilities.createData(program, structInfo.addr().structAddr(), dt, -1, DataUtilities.createData(program, structInfo.addr().structAddr(), dt, -1,
ClearDataMode.CLEAR_ALL_DEFAULT_CONFLICT_DATA); ClearDataMode.CLEAR_ALL_DEFAULT_CONFLICT_DATA);
@@ -465,12 +531,37 @@ public class SwiftTypeMetadata {
relativePtrDataType, -1, ClearDataMode.CLEAR_ALL_DEFAULT_CONFLICT_DATA); relativePtrDataType, -1, ClearDataMode.CLEAR_ALL_DEFAULT_CONFLICT_DATA);
} }
} }
catch (CodeUnitInsertionException | DuplicateNameException | IOException e) { catch (CodeUnitInsertionException e) {
// Probably just called more than once
}
catch (DuplicateNameException | IOException e) {
log("Failed to markup: " + structInfo); log("Failed to markup: " + structInfo);
} }
} }
} }
/**
* Reads past zeroed out entries in Swift type metadata sections
*
* @param reader A {@link BinaryReader} positioned within a type metadata section
* @param offset The current offset from the start of the type metadata section
* @param size The size of the type metadata section (in bytes)
* @return The offset from the start of the type metadata section that contains the next
* non-zero entry
* @throws IOException if an IO-related error occurred
*/
private int skipZeroEntries(BinaryReader reader, int offset, long size) throws IOException {
while (offset + 8 <= size) {
long possibleZero = reader.readNextLong();
if (possibleZero != 0) {
reader.setPointerIndex(reader.getPointerIndex() - 8);
return offset;
}
offset += 8;
}
return offset;
}
/** /**
* Convenience method to perform logging * Convenience method to perform logging
* *
@@ -481,22 +572,24 @@ public class SwiftTypeMetadata {
} }
/** /**
* The {@link Address} of a {@link SwiftStructure} and the optional {@link Address} of its * The {@link Address} of a {@link SwiftTypeMetadataStructure} and the optional {@link Address}
* pointer * of its pointer
* *
* @param structAddr The {@link Address} of a {@link SwiftStructure} * @param structAddr The {@link Address} of a {@link SwiftTypeMetadataStructure}
* @param pointerAddr The {@link Address} of a pointer to a {@link SwiftStructure} (could be * @param pointerAddr The {@link Address} of a pointer to a {@link SwiftTypeMetadataStructure}
* null if there is no associated pointer} * (could be null if there is no associated pointer}
*/ */
private record SwiftStructureAddress(Address structAddr, Address pointerAddr) {} private record SwiftStructureAddress(Address structAddr, Address pointerAddr) {}
/** /**
* Information about a {@link SwiftStructure} * Information about a {@link SwiftTypeMetadataStructure}
* *
* @param struct The {@link SwiftStructure} * @param struct The {@link SwiftTypeMetadataStructure}
* @param addr The {@link SwiftStructureAddress address} of the {@link SwiftStructure} * @param addr The {@link SwiftStructureAddress address} of the
* {@link SwiftTypeMetadataStructure}
*/ */
private record SwiftStructureInfo(SwiftStructure struct, SwiftStructureAddress addr) { private record SwiftStructureInfo(SwiftTypeMetadataStructure struct,
SwiftStructureAddress addr) {
@Override @Override
public String toString() { public String toString() {
@@ -0,0 +1,55 @@
/* ###
* 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 type metadata structures
*/
public abstract class SwiftTypeMetadataStructure implements StructConverter {
public static final String DATA_TYPE_CATEGORY = "/SwiftTypeMetadata";
private long base;
public SwiftTypeMetadataStructure(long base) {
this.base = base;
}
/**
* Gets the base "address" of this {@link SwiftTypeMetadataStructure}
*
* @return The base "address" of this {@link SwiftTypeMetadataStructure}
*/
public long getBase() {
return base;
}
/**
* Gets the name of the {@link SwiftTypeMetadataStructure}
*
* @return The name of the {@link SwiftTypeMetadataStructure}
*/
public abstract String getStructureName();
/**
* Gets a short description of the {@link SwiftTypeMetadataStructure}
*
* @return A short description of the {@link SwiftTypeMetadataStructure}
*/
public abstract String getDescription();
}
@@ -57,6 +57,23 @@ public class SwiftUtils {
return false; return false;
} }
/**
* Checks if the given {@List} of section names contains a Swift section name
*
* @param sectionNames The {@link List} of section names to check
* @return True if the given {@List} of section names contains a Swift section name; otherwise,
* false
*/
public static boolean isSwift(List<String> sectionNames) {
List<String> prefixes = List.of("__swift", "swift", ".sw5");
for (String sectionName : sectionNames) {
if (prefixes.stream().anyMatch(prefix -> sectionName.startsWith(prefix))) {
return true;
}
}
return false;
}
/** /**
* Gets a {@link List} of {@link MemoryBlock}s that match the given {@link SwiftSection} * Gets a {@link List} of {@link MemoryBlock}s that match the given {@link SwiftSection}
* *
@@ -20,7 +20,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.SwiftStructure; import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.app.util.bin.format.swift.SwiftUtils; import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
@@ -30,7 +30,7 @@ import ghidra.util.exception.DuplicateNameException;
* *
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a> * @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 { public final class AssociatedTypeDescriptor extends SwiftTypeMetadataStructure {
/** /**
* The size (in bytes) of an {@link AssociatedTypeDescriptor} structure * The size (in bytes) of an {@link AssociatedTypeDescriptor} structure
@@ -51,6 +51,7 @@ public final class AssociatedTypeDescriptor implements SwiftStructure {
* @throws IOException if there was an IO-related problem creating the structure * @throws IOException if there was an IO-related problem creating the structure
*/ */
public AssociatedTypeDescriptor(BinaryReader reader) throws IOException { public AssociatedTypeDescriptor(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
conformingTypeName = reader.readNext(SwiftUtils::relativeString); conformingTypeName = reader.readNext(SwiftUtils::relativeString);
protocolTypeName = reader.readNext(SwiftUtils::relativeString); protocolTypeName = reader.readNext(SwiftUtils::relativeString);
numAssociatedTypes = reader.readNextInt(); numAssociatedTypes = reader.readNextInt();
@@ -18,7 +18,7 @@ package ghidra.app.util.bin.format.swift.types;
import java.io.IOException; import java.io.IOException;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.SwiftStructure; import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.app.util.bin.format.swift.SwiftUtils; import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
@@ -28,7 +28,7 @@ import ghidra.util.exception.DuplicateNameException;
* *
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a> * @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 { public final class AssociatedTypeRecord extends SwiftTypeMetadataStructure {
/** /**
* The size (in bytes) of an {@link AssociatedTypeRecord} structure * The size (in bytes) of an {@link AssociatedTypeRecord} structure
@@ -45,6 +45,7 @@ public final class AssociatedTypeRecord implements SwiftStructure {
* @throws IOException if there was an IO-related problem creating the structure * @throws IOException if there was an IO-related problem creating the structure
*/ */
public AssociatedTypeRecord(BinaryReader reader) throws IOException { public AssociatedTypeRecord(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
name = reader.readNext(SwiftUtils::relativeString); name = reader.readNext(SwiftUtils::relativeString);
substitutedTypeName = reader.readNext(SwiftUtils::relativeString); substitutedTypeName = reader.readNext(SwiftUtils::relativeString);
} }
@@ -18,7 +18,8 @@ package ghidra.app.util.bin.format.swift.types;
import java.io.IOException; import java.io.IOException;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.*; import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
@@ -27,7 +28,7 @@ import ghidra.util.exception.DuplicateNameException;
* *
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a> * @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 { public final class BuiltinTypeDescriptor extends SwiftTypeMetadataStructure {
/** /**
* The size (in bytes) of a {@link BuiltinTypeDescriptor} structure * The size (in bytes) of a {@link BuiltinTypeDescriptor} structure
@@ -47,6 +48,7 @@ public final class BuiltinTypeDescriptor implements SwiftStructure {
* @throws IOException if there was an IO-related problem creating the structure * @throws IOException if there was an IO-related problem creating the structure
*/ */
public BuiltinTypeDescriptor(BinaryReader reader) throws IOException { public BuiltinTypeDescriptor(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
typeName = reader.readNext(SwiftUtils::relativeString); typeName = reader.readNext(SwiftUtils::relativeString);
size = reader.readNextInt(); size = reader.readNextInt();
alignmentAndFlags = reader.readNextInt(); alignmentAndFlags = reader.readNextInt();
@@ -20,10 +20,8 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.SwiftStructure; import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.program.model.data.CategoryPath; import ghidra.program.model.data.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
/** /**
@@ -31,7 +29,7 @@ import ghidra.util.exception.DuplicateNameException;
* *
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a> * @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 { public final class CaptureDescriptor extends SwiftTypeMetadataStructure {
/** /**
* The size (in bytes) of a {@link CaptureDescriptor} structure * The size (in bytes) of a {@link CaptureDescriptor} structure
@@ -52,6 +50,7 @@ public final class CaptureDescriptor implements SwiftStructure {
* @throws IOException if there was an IO-related problem creating the structure * @throws IOException if there was an IO-related problem creating the structure
*/ */
public CaptureDescriptor(BinaryReader reader) throws IOException { public CaptureDescriptor(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
numCaptureTypes = reader.readNextInt(); numCaptureTypes = reader.readNextInt();
numMetadataSources = reader.readNextInt(); numMetadataSources = reader.readNextInt();
numBindings = reader.readNextInt(); numBindings = reader.readNextInt();
@@ -18,7 +18,8 @@ package ghidra.app.util.bin.format.swift.types;
import java.io.IOException; import java.io.IOException;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.*; import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
@@ -27,7 +28,7 @@ import ghidra.util.exception.DuplicateNameException;
* *
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a> * @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 { public final class CaptureTypeRecord extends SwiftTypeMetadataStructure {
/** /**
* The size (in bytes) of a {@link CaptureTypeRecord} structure * The size (in bytes) of a {@link CaptureTypeRecord} structure
@@ -43,6 +44,7 @@ public final class CaptureTypeRecord implements SwiftStructure {
* @throws IOException if there was an IO-related problem creating the structure * @throws IOException if there was an IO-related problem creating the structure
*/ */
public CaptureTypeRecord(BinaryReader reader) throws IOException { public CaptureTypeRecord(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
mangledTypeName = reader.readNext(SwiftUtils::relativeString); mangledTypeName = reader.readNext(SwiftUtils::relativeString);
} }
@@ -18,7 +18,7 @@ package ghidra.app.util.bin.format.swift.types;
import java.io.IOException; import java.io.IOException;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.SwiftStructure; import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.app.util.bin.format.swift.SwiftUtils; import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
@@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
/** /**
* Represents a Swift entry point * Represents a Swift entry point
*/ */
public final class EntryPoint implements SwiftStructure { public final class EntryPoint extends SwiftTypeMetadataStructure {
/** /**
* The size (in bytes) of an {@link EntryPoint} structure * The size (in bytes) of an {@link EntryPoint} structure
@@ -42,6 +42,7 @@ public final class EntryPoint implements SwiftStructure {
* @throws IOException if there was an IO-related problem creating the structure * @throws IOException if there was an IO-related problem creating the structure
*/ */
public EntryPoint(BinaryReader reader) throws IOException { public EntryPoint(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
entryPoint = reader.readNextInt(); entryPoint = reader.readNextInt();
} }
@@ -20,7 +20,8 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.*; import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
@@ -29,7 +30,7 @@ import ghidra.util.exception.DuplicateNameException;
* *
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a> * @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 { public final class FieldDescriptor extends SwiftTypeMetadataStructure {
/** /**
* The size (in bytes) of a {@link FieldDescriptor} structure * The size (in bytes) of a {@link FieldDescriptor} structure
@@ -51,6 +52,7 @@ public final class FieldDescriptor implements SwiftStructure {
* @throws IOException if there was an IO-related problem creating the structure * @throws IOException if there was an IO-related problem creating the structure
*/ */
public FieldDescriptor(BinaryReader reader) throws IOException { public FieldDescriptor(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
mangledTypeName = reader.readNext(SwiftUtils::relativeString); mangledTypeName = reader.readNext(SwiftUtils::relativeString);
superclass = reader.readNextInt(); superclass = reader.readNextInt();
kind = reader.readNextUnsignedShort(); kind = reader.readNextUnsignedShort();
@@ -18,7 +18,8 @@ package ghidra.app.util.bin.format.swift.types;
import java.io.IOException; import java.io.IOException;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.*; import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
@@ -27,7 +28,7 @@ import ghidra.util.exception.DuplicateNameException;
* *
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a> * @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 { public final class FieldRecord extends SwiftTypeMetadataStructure {
/** /**
* The size (in bytes) of a {@link FieldRecord} structure * The size (in bytes) of a {@link FieldRecord} structure
@@ -45,6 +46,7 @@ public final class FieldRecord implements SwiftStructure {
* @throws IOException if there was an IO-related problem creating the structure * @throws IOException if there was an IO-related problem creating the structure
*/ */
public FieldRecord(BinaryReader reader) throws IOException { public FieldRecord(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
flags = reader.readNextInt(); flags = reader.readNextInt();
mangledTypeName = reader.readNext(SwiftUtils::relativeString); mangledTypeName = reader.readNext(SwiftUtils::relativeString);
fieldName = reader.readNext(SwiftUtils::relativeString); fieldName = reader.readNext(SwiftUtils::relativeString);
@@ -18,7 +18,8 @@ package ghidra.app.util.bin.format.swift.types;
import java.io.IOException; import java.io.IOException;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.*; import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
@@ -27,7 +28,7 @@ import ghidra.util.exception.DuplicateNameException;
* *
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a> * @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 { public final class MetadataSourceRecord extends SwiftTypeMetadataStructure {
/** /**
* The size (in bytes) of a {@link MetadataSourceRecord} structure * The size (in bytes) of a {@link MetadataSourceRecord} structure
@@ -44,6 +45,7 @@ public final class MetadataSourceRecord implements SwiftStructure {
* @throws IOException if there was an IO-related problem creating the structure * @throws IOException if there was an IO-related problem creating the structure
*/ */
public MetadataSourceRecord(BinaryReader reader) throws IOException { public MetadataSourceRecord(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
mangledTypeName = reader.readNext(SwiftUtils::relativeString); mangledTypeName = reader.readNext(SwiftUtils::relativeString);
mangledMetadataSource = reader.readNext(SwiftUtils::relativeString); mangledMetadataSource = reader.readNext(SwiftUtils::relativeString);
} }
@@ -18,7 +18,7 @@ package ghidra.app.util.bin.format.swift.types;
import java.io.IOException; import java.io.IOException;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.SwiftStructure; import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.app.util.bin.format.swift.SwiftUtils; import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
@@ -28,7 +28,7 @@ import ghidra.util.exception.DuplicateNameException;
* *
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a> * @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 { public final class MultiPayloadEnumDescriptor extends SwiftTypeMetadataStructure {
/** /**
* The size (in bytes) of a {@link MultiPayloadEnumDescriptor} structure. This size does not * The size (in bytes) of a {@link MultiPayloadEnumDescriptor} structure. This size does not
@@ -48,6 +48,7 @@ public final class MultiPayloadEnumDescriptor implements SwiftStructure {
* @throws IOException if there was an IO-related problem creating the structure * @throws IOException if there was an IO-related problem creating the structure
*/ */
public MultiPayloadEnumDescriptor(BinaryReader reader) throws IOException { public MultiPayloadEnumDescriptor(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
typeName = reader.readNext(SwiftUtils::relativeString); typeName = reader.readNext(SwiftUtils::relativeString);
int size = (reader.readNextInt() >> 16) & 0xffff; int size = (reader.readNextInt() >> 16) & 0xffff;
reader.setPointerIndex(reader.getPointerIndex() - 4); reader.setPointerIndex(reader.getPointerIndex() - 4);
@@ -19,9 +19,7 @@ import java.io.IOException;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.SwiftUtils; import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.CategoryPath; import ghidra.program.model.data.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
/** /**
@@ -18,7 +18,8 @@ package ghidra.app.util.bin.format.swift.types;
import java.io.IOException; import java.io.IOException;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.*; import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
@@ -27,7 +28,12 @@ import ghidra.util.exception.DuplicateNameException;
* *
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/ABI/Metadata.h">swift/ABI/Metadata.h</a> * @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 { public class TargetContextDescriptor extends SwiftTypeMetadataStructure {
/**
* The size (in bytes) of a {@link TargetContextDescriptor} structure
*/
public static final int SIZE = 8;
private int flags; private int flags;
private int parent; private int parent;
@@ -39,6 +45,7 @@ public class TargetContextDescriptor implements SwiftStructure {
* @throws IOException if there was an IO-related problem creating the structure * @throws IOException if there was an IO-related problem creating the structure
*/ */
public TargetContextDescriptor(BinaryReader reader) throws IOException { public TargetContextDescriptor(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
flags = reader.readNextInt(); flags = reader.readNextInt();
parent = reader.readNextInt(); parent = reader.readNextInt();
} }
@@ -18,7 +18,8 @@ package ghidra.app.util.bin.format.swift.types;
import java.io.IOException; import java.io.IOException;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.*; import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
@@ -27,7 +28,7 @@ import ghidra.util.exception.DuplicateNameException;
* *
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/ABI/Metadata.h">swift/ABI/Metadata.h</a> * @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 { public final class TargetProtocolConformanceDescriptor extends SwiftTypeMetadataStructure {
private int protocolDescriptor; private int protocolDescriptor;
private int nominalTypeDescriptor; private int nominalTypeDescriptor;
@@ -41,6 +42,7 @@ public final class TargetProtocolConformanceDescriptor implements SwiftStructure
* @throws IOException if there was an IO-related problem creating the structure * @throws IOException if there was an IO-related problem creating the structure
*/ */
public TargetProtocolConformanceDescriptor(BinaryReader reader) throws IOException { public TargetProtocolConformanceDescriptor(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
protocolDescriptor = reader.readNextInt(); protocolDescriptor = reader.readNextInt();
nominalTypeDescriptor = reader.readNextInt(); nominalTypeDescriptor = reader.readNextInt();
protocolWitnessTable = reader.readNextInt(); protocolWitnessTable = reader.readNextInt();
@@ -16,6 +16,7 @@
package ghidra.app.util.bin.format.swift.types; package ghidra.app.util.bin.format.swift.types;
import java.io.IOException; import java.io.IOException;
import java.util.Map;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.SwiftUtils; import ghidra.app.util.bin.format.swift.SwiftUtils;
@@ -73,6 +74,20 @@ public class TargetTypeContextDescriptor extends TargetContextDescriptor {
return fields; return fields;
} }
/**
* Gets this {@link TargetTypeContextDescriptor}'s {@link FieldDescriptor}
*
* @param fieldDescriptors A {@link Map} of {@link FieldDescriptor}'s keyed by their base
* addresses
* @return This {@link TargetTypeContextDescriptor}'s {@link FieldDescriptor}, or null if it
* doesn't have one
*/
public FieldDescriptor getFieldDescriptor(Map<Long, FieldDescriptor> fieldDescriptors) {
FieldDescriptor fieldDescriptor =
fieldDescriptors.get(getBase() + TargetContextDescriptor.SIZE + 8 + fields);
return fieldDescriptor != null ? fieldDescriptor : null;
}
@Override @Override
public String getStructureName() { public String getStructureName() {
return getMyStructureName(); return getMyStructureName();
@@ -73,6 +73,7 @@ public class DemangledDataType extends DemangledType {
public final static String LONG = "long"; public final static String LONG = "long";
public final static String LONG_LONG = "long long"; public final static String LONG_LONG = "long long";
public final static String FLOAT = "float"; public final static String FLOAT = "float";
public final static String FLOAT2 = "float2";
public final static String DOUBLE = "double"; public final static String DOUBLE = "double";
public final static String INT8 = "__int8"; public final static String INT8 = "__int8";
public final static String INT16 = "__int16"; public final static String INT16 = "__int16";
@@ -94,7 +95,7 @@ public class DemangledDataType extends DemangledType {
public final static String[] PRIMITIVES = public final static String[] PRIMITIVES =
{ VOID, BOOL, CHAR, WCHAR_T, WCHAR16, WCHAR32, SHORT, INT, INT0_T, LONG, { VOID, BOOL, CHAR, WCHAR_T, WCHAR16, WCHAR32, SHORT, INT, INT0_T, LONG,
LONG_LONG, FLOAT, DOUBLE, INT128, FLOAT128, LONG_DOUBLE, }; LONG_LONG, FLOAT, FLOAT2, DOUBLE, INT128, FLOAT128, LONG_DOUBLE, };
private int arrayDimensions = 0; private int arrayDimensions = 0;
private boolean isClass; private boolean isClass;
@@ -293,6 +294,9 @@ public class DemangledDataType extends DemangledType {
else if (FLOAT.equals(name)) { else if (FLOAT.equals(name)) {
dt = FloatDataType.dataType; dt = FloatDataType.dataType;
} }
else if (FLOAT2.equals(name)) {
dt = Float2DataType.dataType;
}
else if (FLOAT128.equals(name)) { else if (FLOAT128.equals(name)) {
dt = new TypedefDataType(FLOAT128, Float16DataType.dataType); dt = new TypedefDataType(FLOAT128, Float16DataType.dataType);
} }
@@ -54,7 +54,7 @@ public class DemangledFunction extends DemangledObject {
protected DemangledDataType returnType; protected DemangledDataType returnType;
protected String callingConvention;// __cdecl, __thiscall, etc. protected String callingConvention;// __cdecl, __thiscall, etc.
protected boolean thisPassedOnStack = true; protected boolean thisPassedOnStack = true;
protected List<DemangledDataType> parameters = new ArrayList<>(); protected List<DemangledParameter> parameters = new ArrayList<>();
protected DemangledTemplate template; protected DemangledTemplate template;
protected boolean isOverloadedOperator = false; protected boolean isOverloadedOperator = false;
protected SourceType signatureSourceType = SourceType.ANALYSIS; protected SourceType signatureSourceType = SourceType.ANALYSIS;
@@ -140,11 +140,15 @@ public class DemangledFunction extends DemangledObject {
this.isOverloadedOperator = isOverloadedOperator; this.isOverloadedOperator = isOverloadedOperator;
} }
public void addParameter(DemangledDataType parameter) { public void addParameter(DemangledParameter parameter) {
parameters.add(parameter); parameters.add(parameter);
} }
public List<DemangledDataType> getParameters() { public void addParameters(List<DemangledParameter> params) {
parameters.addAll(params);
}
public List<DemangledParameter> getParameters() {
return new ArrayList<>(parameters); return new ArrayList<>(parameters);
} }
@@ -323,7 +327,7 @@ public class DemangledFunction extends DemangledObject {
} }
protected void addParameters(StringBuilder buffer, boolean format) { protected void addParameters(StringBuilder buffer, boolean format) {
Iterator<DemangledDataType> paramIterator = parameters.iterator(); Iterator<DemangledParameter> paramIterator = parameters.iterator();
buffer.append('('); buffer.append('(');
int padLength = format ? buffer.length() : 0; int padLength = format ? buffer.length() : 0;
String pad = StringUtils.rightPad("", padLength); String pad = StringUtils.rightPad("", padLength);
@@ -332,7 +336,11 @@ public class DemangledFunction extends DemangledObject {
} }
while (paramIterator.hasNext()) { while (paramIterator.hasNext()) {
buffer.append(paramIterator.next().getSignature()); DemangledParameter param = paramIterator.next();
buffer.append(param.getType().getSignature());
if (param.getLabel() != null) {
buffer.append(" " + param.getLabel());
}
if (paramIterator.hasNext()) { if (paramIterator.hasNext()) {
buffer.append(','); buffer.append(',');
if (format) { if (format) {
@@ -353,9 +361,9 @@ public class DemangledFunction extends DemangledObject {
public String getParameterString() { public String getParameterString() {
StringBuffer buffer = new StringBuffer(); StringBuffer buffer = new StringBuffer();
buffer.append('('); buffer.append('(');
Iterator<DemangledDataType> dditer = parameters.iterator(); Iterator<DemangledParameter> dditer = parameters.iterator();
while (dditer.hasNext()) { while (dditer.hasNext()) {
buffer.append(dditer.next().getSignature()); buffer.append(dditer.next().getType().getSignature());
if (dditer.hasNext()) { if (dditer.hasNext()) {
buffer.append(','); buffer.append(',');
} }
@@ -576,13 +584,13 @@ public class DemangledFunction extends DemangledObject {
return false; return false;
} }
DemangledDataType lastType = parameters.get(parameters.size() - 1); DemangledDataType lastType = parameters.get(parameters.size() - 1).getType();
return lastType.isVarArgs(); return lastType.isVarArgs();
} }
private boolean hasVoidParams() { private boolean hasVoidParams() {
if (parameters.size() == 1) { if (parameters.size() == 1) {
DemangledDataType ddt = parameters.get(0); DemangledDataType ddt = parameters.get(0).getType();
return ddt.isVoid() && !ddt.isPointer(); return ddt.isVoid() && !ddt.isPointer();
} }
return false; return false;
@@ -634,7 +642,7 @@ public class DemangledFunction extends DemangledObject {
// If returnType is null check for constructor or destructor names // If returnType is null check for constructor or destructor names
if (THIS_CALL.equals(function.getCallingConventionName())) { if (THIS_CALL.equals(function.getCallingConventionName())) {
String n = getName(); String n = getName();
if (n.equals(namespace.getName())) { if (namespace != null && n.equals(namespace.getName())) {
// constructor // constructor
return DataType.DEFAULT; return DataType.DEFAULT;
} }
@@ -698,17 +706,18 @@ public class DemangledFunction extends DemangledObject {
private List<ParameterDefinitionImpl> convertMangledToParamDef(Program program) { private List<ParameterDefinitionImpl> convertMangledToParamDef(Program program) {
List<ParameterDefinitionImpl> args = new ArrayList<>(); List<ParameterDefinitionImpl> args = new ArrayList<>();
for (DemangledDataType param : parameters) { for (DemangledParameter param : parameters) {
// stop when a void parameter is hit. This probably the only defined parameter. // stop when a void parameter is hit. This probably the only defined parameter.
if (param.isVoid() && !param.isPointer()) { DemangledDataType type = param.getType();
if (type.isVoid() && !type.isPointer()) {
break; break;
} }
if (param.isVarArgs()) { if (type.isVarArgs()) {
break; break;
} }
DataType dt = param.getDataType(program.getDataTypeManager()); DataType dt = type.getDataType(program.getDataTypeManager());
args.add(new ParameterDefinitionImpl(null, dt, null)); args.add(new ParameterDefinitionImpl(param.getLabel(), dt, null));
} }
return args; return args;
} }
@@ -0,0 +1,52 @@
/* ###
* 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.demangler;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.Symbol;
import ghidra.util.task.TaskMonitor;
/**
* A class to represent a {@link DemangledObject} that should get represented as a Ghidra label
*/
public class DemangledLabel extends DemangledObject {
/**
* Creates a new {@link DemangledLabel}
*
* @param mangled The mangled string
* @param originalDemangled The natively demangled string
* @param name The label name
*/
public DemangledLabel(String mangled, String originalDemangled, String name) {
super(mangled, originalDemangled);
setName(name);
}
@Override
public boolean applyTo(Program program, Address address, DemanglerOptions options,
TaskMonitor monitor) throws Exception {
Symbol symbol = applyDemangledName(address, true, false, program);
return symbol != null;
}
@Override
public String getSignature(boolean format) {
return originalDemangled;
}
}
@@ -0,0 +1,93 @@
/* ###
* 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.demangler;
import java.util.ArrayList;
import java.util.List;
/**
* An convenience {@link Demangled} object that holds a {@link List} of other
* {@link Demangled} objects
*/
public class DemangledList extends ArrayList<Demangled> implements Demangled {
/**
* Creates a {@link DemangledList} and adds the given {@link List} to it
*
* @param demangledList The {@link List} of {@link Demangled} objects to add
*/
public DemangledList(List<Demangled> demangledList) {
super(demangledList);
}
/**
* {@return true if this contains any <code>null</code> elements; otherwise, false}
*/
public boolean containsNull() {
return stream().anyMatch(e -> e == null);
}
@Override
public String getMangledString() {
return null;
}
@Override
public String getOriginalDemangled() {
return null;
}
@Override
public String getName() {
return null;
}
@Override
public void setName(String name) {
// Nothing to do
}
@Override
public String getDemangledName() {
return null;
}
@Override
public Demangled getNamespace() {
return null;
}
@Override
public void setNamespace(Demangled ns) {
// Nothing to do
}
@Override
public String getNamespaceString() {
return null;
}
@Override
public String getNamespaceName() {
return null;
}
@Override
public String getSignature() {
return null;
}
}
@@ -0,0 +1,69 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.demangler;
/**
* A class to represent a demangled function parameter.
* <p>
* This extends {@link DemangledDataType} in order to associate an optional parameter label with
* its data type.
*/
public class DemangledParameter {
private DemangledDataType type;
private String label;
/**
* Creates a new {@link DemangledParameter} with the given type and no label
*
* @param type The parameter type
*/
public DemangledParameter(DemangledDataType type) {
this.type = type;
}
/**
* {@return the parameter's type}
*/
public DemangledDataType getType() {
return type;
}
/**
* {@return the parameter's label (could be null)}
*/
public String getLabel() {
return label;
}
/**
* Sets the parameter's label
*
* @param label The label (null for no label)
*/
public void setLabel(String label) {
this.label = label;
}
@Override
public String toString() {
String ret = type.toString();
if (label != null) {
ret += " " + label;
}
return ret;
}
}
@@ -0,0 +1,105 @@
/* ###
* 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.demangler;
import java.util.ArrayList;
import java.util.List;
import ghidra.program.model.data.*;
/**
* A class to represent a demangled structure
*/
public class DemangledStructure extends DemangledDataType {
/**
* A field of a {@link DemangledStructure}
*
* @param name The field name
* @param description The field description
* @param type The field {@link DemangledDataType type}
*/
public record Field(String name, String description, DemangledDataType type) {}
private List<Field> fields = new ArrayList<>();
private String categoryPath;
private boolean packed;
/**
* Creates a new {@link DemangledStructure}
*
* @param mangled The mangled string
* @param originalDemangled The natively demangled string
* @param name The structure name
* @param categoryPath The structure category path
* @param packed True if the structure should be packed; otherwise, false
*/
public DemangledStructure(String mangled, String originalDemangled, String name,
String categoryPath, boolean packed) {
super(mangled, originalDemangled, name);
setStruct();
this.categoryPath = categoryPath;
this.packed = packed;
}
/**
* Adds a new field to the structure. The field will not have a description.
*
* @param name The field name
* @param type The field {@link DemangledDataType type}
*/
public void addField(String name, DemangledDataType type) {
fields.add(new Field(name, null, type));
}
/**
* Adds a new field to the structure
*
* @param name The field name
* @param description The field description
* @param type The field {@link DemangledDataType type}
*/
public void addField(String name, String description, DemangledDataType type) {
fields.add(new Field(name, description, type));
}
/**
* Gets the {@link List} of {@link Field}s
*
* @return The {@link List} of {@link Field}s
*/
public List<Field> getFields() {
return fields;
}
@Override
public DataType getDataType(DataTypeManager dataTypeManager) {
String name = getName();
if (name == null) {
return DataType.DEFAULT;
}
StructureDataType struct = new StructureDataType(name, 0, dataTypeManager);
for (Field field : fields) {
struct.add(field.type().getDataType(dataTypeManager), field.name(),
field.description());
}
struct.setPackingEnabled(packed);
struct.setCategoryPath(new CategoryPath(categoryPath));
return struct;
}
}
@@ -24,6 +24,7 @@ import ghidra.app.util.Option;
import ghidra.app.util.bin.ByteProvider; import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.ByteProviderWrapper; import ghidra.app.util.bin.ByteProviderWrapper;
import ghidra.app.util.bin.format.macho.*; import ghidra.app.util.bin.format.macho.*;
import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.app.util.bin.format.ubi.*; import ghidra.app.util.bin.format.ubi.*;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
import ghidra.formats.gfilesystem.*; import ghidra.formats.gfilesystem.*;
@@ -60,7 +61,13 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
MachHeader machHeader = new MachHeader(provider); MachHeader machHeader = new MachHeader(provider);
String magic = String magic =
CpuTypes.getMagicString(machHeader.getCpuType(), machHeader.getCpuSubType()); CpuTypes.getMagicString(machHeader.getCpuType(), machHeader.getCpuSubType());
List<QueryResult> results = QueryOpinionService.query(MACH_O_NAME, magic, null); List<String> sectionNames = machHeader.parseSegments()
.stream()
.flatMap(seg -> seg.getSections().stream())
.map(section -> section.getSectionName())
.toList();
String compiler = SwiftUtils.isSwift(sectionNames) ? "swift" : null;
List<QueryResult> results = QueryOpinionService.query(MACH_O_NAME, magic, compiler);
for (QueryResult result : results) { for (QueryResult result : results) {
loadSpecs.add(new LoadSpec(this, machHeader.getImageBase(), result)); loadSpecs.add(new LoadSpec(this, machHeader.getImageBase(), result));
} }
@@ -37,6 +37,7 @@ import ghidra.app.util.bin.format.pe.ImageCor20Header.ImageCor20Flags;
import ghidra.app.util.bin.format.pe.PortableExecutable.SectionLayout; import ghidra.app.util.bin.format.pe.PortableExecutable.SectionLayout;
import ghidra.app.util.bin.format.pe.debug.DebugCOFFSymbol; import ghidra.app.util.bin.format.pe.debug.DebugCOFFSymbol;
import ghidra.app.util.bin.format.pe.debug.DebugDirectoryParser; import ghidra.app.util.bin.format.pe.debug.DebugDirectoryParser;
import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
import ghidra.framework.model.DomainObject; import ghidra.framework.model.DomainObject;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
@@ -904,6 +905,7 @@ public class PeLoader extends AbstractPeDebugLoader {
CLI("cli", "cli"), CLI("cli", "cli"),
Rustc(RustConstants.RUST_COMPILER, RustConstants.RUST_COMPILER), Rustc(RustConstants.RUST_COMPILER, RustConstants.RUST_COMPILER),
GOLANG("golang", "golang"), GOLANG("golang", "golang"),
Swift("swift", "swift"),
Unknown("unknown", "unknown"), Unknown("unknown", "unknown"),
// The following values represent the presence of ambiguous indicators // The following values represent the presence of ambiguous indicators
@@ -969,6 +971,15 @@ public class PeLoader extends AbstractPeDebugLoader {
} }
return CompilerEnum.Rustc; return CompilerEnum.Rustc;
} }
// Check for Swift
List<String> sectionNames =
Arrays.stream(pe.getNTHeader().getFileHeader().getSectionHeaders())
.map(section -> section.getName())
.toList();
if (SwiftUtils.isSwift(sectionNames)) {
return CompilerEnum.Swift;
}
// Check for managed code (.NET) // Check for managed code (.NET)
if (pe.getNTHeader().getOptionalHeader().isCLI()) { if (pe.getNTHeader().getOptionalHeader().isCLI()) {
@@ -485,7 +485,7 @@ public class GnuDemanglerParser {
// //
setNameAndNamespace(function, simpleName); setNameAndNamespace(function, simpleName);
for (DemangledDataType parameter : signatureParts.getParameters()) { for (DemangledParameter parameter : signatureParts.getParameters()) {
function.addParameter(parameter); function.addParameter(parameter);
} }
@@ -630,9 +630,9 @@ public class GnuDemanglerParser {
* Reason being, you need to take into account nested templates * Reason being, you need to take into account nested templates
* and function pointers. * and function pointers.
*/ */
private List<DemangledDataType> parseParameters(String parameterString) { private List<DemangledParameter> parseParameters(String parameterString) {
List<String> parameterStrings = tokenizeParameters(parameterString); List<String> parameterStrings = tokenizeParameters(parameterString);
List<DemangledDataType> parameters = convertIntoParameters(parameterStrings); List<DemangledParameter> parameters = convertIntoParameters(parameterStrings);
return parameters; return parameters;
} }
@@ -735,12 +735,12 @@ public class GnuDemanglerParser {
* This method converts each parameter string into * This method converts each parameter string into
* actual DemangledDataType objects. * actual DemangledDataType objects.
*/ */
private List<DemangledDataType> convertIntoParameters(List<String> parameterStrings) { private List<DemangledParameter> convertIntoParameters(List<String> parameterStrings) {
List<DemangledDataType> parameters = new ArrayList<>(); List<DemangledParameter> parameters = new ArrayList<>();
for (String parameter : parameterStrings) { for (String parameter : parameterStrings) {
DemangledDataType dt = parseParameter(parameter); DemangledDataType dt = parseParameter(parameter);
parameters.add(dt); parameters.add(new DemangledParameter(dt));
} }
return parameters; return parameters;
@@ -1311,10 +1311,10 @@ public class GnuDemanglerParser {
contents = string.substring(1, string.length() - 1); contents = string.substring(1, string.length() - 1);
} }
List<DemangledDataType> parameters = parseParameters(contents); List<DemangledParameter> parameters = parseParameters(contents);
DemangledTemplate template = new DemangledTemplate(); DemangledTemplate template = new DemangledTemplate();
for (DemangledDataType parameter : parameters) { for (DemangledParameter parameter : parameters) {
template.addParameter(parameter); template.addParameter(parameter.getType());
} }
return template; return template;
} }
@@ -1399,16 +1399,16 @@ public class GnuDemanglerParser {
return dfp; return dfp;
} }
private DemangledFunctionPointer createFunctionPointer(String paramerterString, private DemangledFunctionPointer createFunctionPointer(String parameterString,
String returnType) { String returnType) {
List<DemangledDataType> parameters = parseParameters(paramerterString); List<DemangledParameter> parameters = parseParameters(parameterString);
DemangledFunctionPointer dfp = new DemangledFunctionPointer(mangledSource, demangledSource); DemangledFunctionPointer dfp = new DemangledFunctionPointer(mangledSource, demangledSource);
DemangledDataType returnDataType = parseReturnType(returnType); DemangledDataType returnDataType = parseReturnType(returnType);
dfp.setReturnType(returnDataType); dfp.setReturnType(returnDataType);
for (DemangledDataType parameter : parameters) { for (DemangledParameter parameter : parameters) {
dfp.addParameter(parameter); dfp.addParameter(parameter.getType());
} }
return dfp; return dfp;
} }
@@ -1889,8 +1889,8 @@ public class GnuDemanglerParser {
// operator itself could be in a class namespace // operator itself could be in a class namespace
setNameAndNamespace(function, operatorText); setNameAndNamespace(function, operatorText);
List<DemangledDataType> parameters = parseParameters(parametersText); List<DemangledParameter> parameters = parseParameters(parametersText);
for (DemangledDataType parameter : parameters) { for (DemangledParameter parameter : parameters) {
function.addParameter(parameter); function.addParameter(parameter);
} }
@@ -2029,7 +2029,7 @@ public class GnuDemanglerParser {
private String name; private String name;
private String rawParameterPrefix; private String rawParameterPrefix;
private List<DemangledDataType> parameters; private List<DemangledParameter> parameters;
FunctionSignatureParts(String signatureString) { FunctionSignatureParts(String signatureString) {
@@ -2077,7 +2077,7 @@ public class GnuDemanglerParser {
return isFunction; return isFunction;
} }
List<DemangledDataType> getParameters() { List<DemangledParameter> getParameters() {
return parameters; return parameters;
} }
@@ -54,9 +54,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
assertName(object, "bob"); assertName(object, "bob");
DemangledFunction function = (DemangledFunction) object; DemangledFunction function = (DemangledFunction) object;
List<DemangledDataType> parameters = function.getParameters(); List<DemangledParameter> parameters = function.getParameters();
assertEquals(1, parameters.size()); assertEquals(1, parameters.size());
DemangledDataType p1 = parameters.get(0); DemangledDataType p1 = parameters.get(0).getType();
assertEquals("bob(int const[8] (*) [12])", p1.getOriginalDemangled()); assertEquals("bob(int const[8] (*) [12])", p1.getOriginalDemangled());
assertEquals("undefined bob(int const *[])", object.getSignature(false)); assertEquals("undefined bob(int const *[])", object.getSignature(false));
} }
@@ -113,9 +113,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
DemangledObject object = parser.parse("fake", "Layout::graphNew(short[][][][], char*)"); DemangledObject object = parser.parse("fake", "Layout::graphNew(short[][][][], char*)");
assertType(object, DemangledFunction.class); assertType(object, DemangledFunction.class);
DemangledFunction function = (DemangledFunction) object; DemangledFunction function = (DemangledFunction) object;
List<DemangledDataType> parameters = function.getParameters(); List<DemangledParameter> parameters = function.getParameters();
assertEquals(2, parameters.size()); assertEquals(2, parameters.size());
DemangledDataType p1 = parameters.get(0); DemangledDataType p1 = parameters.get(0).getType();
assertEquals(4, p1.getArrayDimensions()); assertEquals(4, p1.getArrayDimensions());
} }
@@ -153,12 +153,12 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
DemangledFunction method = (DemangledFunction) object; DemangledFunction method = (DemangledFunction) object;
List<DemangledDataType> parameters = method.getParameters(); List<DemangledParameter> parameters = method.getParameters();
assertEquals(4, parameters.size()); assertEquals(4, parameters.size());
assertEquals("unsigned long (*)(long const &)", parameters.get(0).getSignature()); assertEquals("unsigned long (*)(long const &)", parameters.get(0).getType().getSignature());
assertEquals("unsigned long", parameters.get(1).getSignature()); assertEquals("unsigned long", parameters.get(1).getType().getSignature());
assertEquals("unsigned long", parameters.get(2).getSignature()); assertEquals("unsigned long", parameters.get(2).getType().getSignature());
assertEquals("float", parameters.get(3).getSignature()); assertEquals("float", parameters.get(3).getType().getSignature());
} }
@Test @Test
@@ -176,9 +176,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
"_Rb_tree<Location,Location,std::_Identity<Location>,std::less<Location>,std::allocator<Location>>"); "_Rb_tree<Location,Location,std::_Identity<Location>,std::less<Location>,std::allocator<Location>>");
DemangledFunction function = (DemangledFunction) object; DemangledFunction function = (DemangledFunction) object;
List<DemangledDataType> parameters = function.getParameters(); List<DemangledParameter> parameters = function.getParameters();
assertEquals(1, parameters.size()); assertEquals(1, parameters.size());
assertEquals("Location const &", parameters.get(0).getSignature()); assertEquals("Location const &", parameters.get(0).getType().getSignature());
} }
@Test @Test
@@ -194,7 +194,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
assertType(object, DemangledFunction.class); assertType(object, DemangledFunction.class);
DemangledFunction function = (DemangledFunction) object; DemangledFunction function = (DemangledFunction) object;
List<DemangledDataType> parameters = function.getParameters(); List<DemangledParameter> parameters = function.getParameters();
assertEquals( assertEquals(
"__insertion_sort<__gnu_cxx::__normal_iterator<std::pair<unsigned_long,PcodeOp*>*,std::vector<std::pair<unsigned_long,PcodeOp*>,std::allocator<std::pair<unsigned_long,PcodeOp*>>>>,bool(*)(std::pair<unsigned_long,PcodeOp*>const&,std::pair<unsigned_long,PcodeOp*>const&)>", "__insertion_sort<__gnu_cxx::__normal_iterator<std::pair<unsigned_long,PcodeOp*>*,std::vector<std::pair<unsigned_long,PcodeOp*>,std::allocator<std::pair<unsigned_long,PcodeOp*>>>>,bool(*)(std::pair<unsigned_long,PcodeOp*>const&,std::pair<unsigned_long,PcodeOp*>const&)>",
@@ -211,9 +211,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
"bool (*)(std::pair<unsigned long,PcodeOp *> const &,std::pair<unsigned long,PcodeOp *> const &)", "bool (*)(std::pair<unsigned long,PcodeOp *> const &,std::pair<unsigned long,PcodeOp *> const &)",
parameters.get(2).toString()); parameters.get(2).toString());
assertType(parameters.get(2), DemangledFunctionPointer.class); assertType(parameters.get(2).getType(), DemangledFunctionPointer.class);
DemangledFunctionPointer fptr = (DemangledFunctionPointer) parameters.get(2); DemangledFunctionPointer fptr = (DemangledFunctionPointer) parameters.get(2).getType();
assertEquals("bool", fptr.getReturnType().getName()); assertEquals("bool", fptr.getReturnType().getName());
@@ -234,9 +234,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
assertEquals( assertEquals(
"undefined std::set<bbnode*,std::less<bbnode*>,std::allocator<bbnode*>>::insert(bbnode const * &)", "undefined std::set<bbnode*,std::less<bbnode*>,std::allocator<bbnode*>>::insert(bbnode const * &)",
method.getSignature(false)); method.getSignature(false));
List<DemangledDataType> parameters = method.getParameters(); List<DemangledParameter> parameters = method.getParameters();
assertEquals(1, parameters.size()); assertEquals(1, parameters.size());
assertEquals("bbnode const * &", parameters.get(0).getSignature()); assertEquals("bbnode const * &", parameters.get(0).getType().getSignature());
} }
@Test @Test
@@ -252,9 +252,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
DemangledFunction method = (DemangledFunction) object; DemangledFunction method = (DemangledFunction) object;
assertEquals("undefined Bar::Fred::Fred(int)", method.getSignature(false)); assertEquals("undefined Bar::Fred::Fred(int)", method.getSignature(false));
List<DemangledDataType> parameters = method.getParameters(); List<DemangledParameter> parameters = method.getParameters();
assertEquals(1, parameters.size()); assertEquals(1, parameters.size());
assertEquals("int", parameters.get(0).getSignature()); assertEquals("int", parameters.get(0).getType().getSignature());
} }
@Test @Test
@@ -428,9 +428,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
DemangledFunction function = (DemangledFunction) object; DemangledFunction function = (DemangledFunction) object;
assertEquals("undefined Foo::getBool(float)", function.getSignature(false)); assertEquals("undefined Foo::getBool(float)", function.getSignature(false));
List<DemangledDataType> parameters = function.getParameters(); List<DemangledParameter> parameters = function.getParameters();
assertEquals(1, parameters.size()); assertEquals(1, parameters.size());
assertEquals("float", parameters.get(0).getSignature()); assertEquals("float", parameters.get(0).getType().getSignature());
} }
@Test @Test
@@ -447,13 +447,13 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
DemangledFunction function = (DemangledFunction) object; DemangledFunction function = (DemangledFunction) object;
List<DemangledDataType> parameters = function.getParameters(); List<DemangledParameter> parameters = function.getParameters();
assertEquals(5, parameters.size()); assertEquals(5, parameters.size());
assertEquals("int", parameters.get(0).getSignature()); assertEquals("int", parameters.get(0).getType().getSignature());
assertEquals("double", parameters.get(1).getSignature()); assertEquals("double", parameters.get(1).getType().getSignature());
assertEquals("char", parameters.get(2).getSignature()); assertEquals("char", parameters.get(2).getType().getSignature());
assertEquals("long", parameters.get(3).getSignature()); assertEquals("long", parameters.get(3).getType().getSignature());
assertEquals("short", parameters.get(4).getSignature()); assertEquals("short", parameters.get(4).getType().getSignature());
} }
@Test @Test
@@ -827,13 +827,13 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
DemangledFunction method = (DemangledFunction) object; DemangledFunction method = (DemangledFunction) object;
List<DemangledDataType> parameters = method.getParameters(); List<DemangledParameter> parameters = method.getParameters();
assertEquals(5, parameters.size()); assertEquals(5, parameters.size());
assertEquals("SECTION_INFO *", parameters.get(0).getSignature()); assertEquals("SECTION_INFO *", parameters.get(0).getType().getSignature());
assertEquals("int *", parameters.get(1).getSignature()); assertEquals("int *", parameters.get(1).getType().getSignature());
assertEquals("int *[]", parameters.get(2).getSignature()); assertEquals("int *[]", parameters.get(2).getType().getSignature());
assertEquals("int", parameters.get(3).getSignature()); assertEquals("int", parameters.get(3).getType().getSignature());
assertEquals("short const *", parameters.get(4).getSignature()); assertEquals("short const *", parameters.get(4).getType().getSignature());
} }
@Test @Test
@@ -935,10 +935,10 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
"undefined Magick::operator<(Magick::Coordinate const &,Magick::Coordinate const &)", "undefined Magick::operator<(Magick::Coordinate const &,Magick::Coordinate const &)",
method.getSignature(false)); method.getSignature(false));
List<DemangledDataType> parameters = method.getParameters(); List<DemangledParameter> parameters = method.getParameters();
assertEquals(2, parameters.size()); assertEquals(2, parameters.size());
assertEquals("Magick::Coordinate const &", parameters.get(0).getSignature()); assertEquals("Magick::Coordinate const &", parameters.get(0).getType().getSignature());
assertEquals("Magick::Coordinate const &", parameters.get(1).getSignature()); assertEquals("Magick::Coordinate const &", parameters.get(1).getType().getSignature());
} }
@Test @Test
@@ -1072,9 +1072,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
assertEquals("undefined Magick::pageImage::operator()(Magick::Image &)", assertEquals("undefined Magick::pageImage::operator()(Magick::Image &)",
method.getSignature(false)); method.getSignature(false));
List<DemangledDataType> parameters = method.getParameters(); List<DemangledParameter> parameters = method.getParameters();
assertEquals(1, parameters.size()); assertEquals(1, parameters.size());
assertEquals("Magick::Image &", parameters.get(0).getSignature()); assertEquals("Magick::Image &", parameters.get(0).getType().getSignature());
} }
@Test @Test
@@ -1536,13 +1536,14 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
DemangledFunction df = (DemangledFunction) object; DemangledFunction df = (DemangledFunction) object;
List<DemangledDataType> parameters = df.getParameters(); List<DemangledParameter> parameters = df.getParameters();
assertEquals("Number of parameters", 1, parameters.size()); assertEquals("Number of parameters", 1, parameters.size());
assertEquals("Name of type parsed", "F", parameters.get(0).getName()); assertEquals("Name of type parsed", "F", parameters.get(0).getType().getName());
assertEquals("Param Type Name parsed", "WTF", parameters.get(0).getNamespace().toString()); assertEquals("Param Type Name parsed", "WTF",
parameters.get(0).getType().getNamespace().toString());
assertEquals("Param Template was parsed", assertEquals("Param Template was parsed",
"<WTF::F<void (Core::FileClient &)> (Core::File &)>", "<WTF::F<void (Core::FileClient &)> (Core::File &)>",
parameters.get(0).getTemplate().toString()); parameters.get(0).getType().getTemplate().toString());
assertEquals( assertEquals(
"undefined Core::AsyncFile::perform(WTF::F<WTF::F<void (Core::FileClient &)> (Core::File &)> &&)", "undefined Core::AsyncFile::perform(WTF::F<WTF::F<void (Core::FileClient &)> (Core::File &)> &&)",
@@ -1569,9 +1570,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
DemangledFunction df = (DemangledFunction) object; DemangledFunction df = (DemangledFunction) object;
List<DemangledDataType> parameters = df.getParameters(); List<DemangledParameter> parameters = df.getParameters();
assertEquals("Number of parameters", 1, parameters.size()); assertEquals("Number of parameters", 1, parameters.size());
DemangledDataType demangParamDT = parameters.get(0); DemangledDataType demangParamDT = parameters.get(0).getType();
assertEquals("Name of type parsed", "function", demangParamDT.getName()); assertEquals("Name of type parsed", "function", demangParamDT.getName());
assertEquals("Param Type Name parsed", "boost", demangParamDT.getNamespace().toString()); assertEquals("Param Type Name parsed", "boost", demangParamDT.getNamespace().toString());
@@ -1601,9 +1602,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
DemangledFunction df = (DemangledFunction) object; DemangledFunction df = (DemangledFunction) object;
List<DemangledDataType> parameters = df.getParameters(); List<DemangledParameter> parameters = df.getParameters();
assertEquals("Number of parameters", 1, parameters.size()); assertEquals("Number of parameters", 1, parameters.size());
DemangledDataType demangParamDT = parameters.get(0); DemangledDataType demangParamDT = parameters.get(0).getType();
assertEquals("Name of type parsed", "function", demangParamDT.getName()); assertEquals("Name of type parsed", "function", demangParamDT.getName());
assertEquals("Param Type Name parsed", "boost", demangParamDT.getNamespace().toString()); assertEquals("Param Type Name parsed", "boost", demangParamDT.getNamespace().toString());
@@ -1705,9 +1706,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
assertType(object, DemangledFunction.class); assertType(object, DemangledFunction.class);
DemangledFunction function = (DemangledFunction) object; DemangledFunction function = (DemangledFunction) object;
List<DemangledDataType> parameters = function.getParameters(); List<DemangledParameter> parameters = function.getParameters();
assertEquals(2, parameters.size()); assertEquals(2, parameters.size());
assertTrue(parameters.get(1).isVarArgs()); assertTrue(parameters.get(1).getType().isVarArgs());
assertEquals("undefined testVarArgs(int,...)", object.getSignature(false)); assertEquals("undefined testVarArgs(int,...)", object.getSignature(false));
} }
@@ -369,7 +369,8 @@ public class MDMangGhidra extends MDMang {
MDArgumentsList args = functionType.getArgumentsList(); MDArgumentsList args = functionType.getArgumentsList();
if (functionType.hasArgs() && args != null) { if (functionType.hasArgs() && args != null) {
for (int index = 0; index < args.getNumArgs(); index++) { for (int index = 0; index < args.getNumArgs(); index++) {
function.addParameter(processDataType(null, args.getArg(index))); function.addParameter(
new DemangledParameter(processDataType(null, args.getArg(index))));
} }
} }
if (functionType.isTypeCast()) { if (functionType.isTypeCast()) {
@@ -0,0 +1,26 @@
/* ###
* 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.
*/
apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle"
apply from: "$rootProject.projectDir/gradle/javaProject.gradle"
apply from: "$rootProject.projectDir/gradle/jacocoProject.gradle"
apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle"
apply plugin: 'eclipse'
eclipse.project.name = 'Features SwiftDemangler'
dependencies {
api project(":Base")
}
@@ -0,0 +1,2 @@
##VERSION: 2.0
Module.manifest||GHIDRA||||END|
@@ -0,0 +1,70 @@
/* ###
* 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.
*/
//Outputs the natively demangled Swift symbol found at the current address in expanded tree form.
//Mostly useful for debugging.
//@category Demangler
import ghidra.app.script.GhidraScript;
import ghidra.app.util.demangler.DemangledObject;
import ghidra.app.util.demangler.swift.*;
import ghidra.app.util.demangler.swift.SwiftNativeDemangler.SwiftNativeDemangledOutput;
import ghidra.program.model.symbol.*;
public class SwiftDemanglerScript extends GhidraScript {
@Override
protected void run() throws Exception {
SwiftDemangler demangler = new SwiftDemangler();
SwiftDemanglerOptions options = new SwiftDemanglerOptions();
if (!demangler.canDemangle(currentProgram)) {
println("Not a Swift program");
return;
}
println("-------------------------------------------------");
String mangled = null;
SymbolTable symbolTable = currentProgram.getSymbolTable();
for (Symbol symbol : symbolTable.getSymbols(currentAddress)) {
if (demangler.isSwiftMangledSymbol(symbol.getName())) {
mangled = symbol.getName();
break;
}
for (LabelHistory history : symbolTable.getLabelHistory(currentAddress)) {
if (demangler.isSwiftMangledSymbol(history.getLabelString())) {
mangled = history.getLabelString();
break;
}
}
}
if (mangled == null) {
println("No mangled Swift symbols found at " + currentAddress);
return;
}
SwiftNativeDemangler nativeDemangler = new SwiftNativeDemangler(options.getSwiftDir());
SwiftNativeDemangledOutput demangledOutput = nativeDemangler.demangle(mangled);
println(demangledOutput.toString());
DemangledObject demangledObject = demangler.demangle(mangled);
if (demangledObject != null) {
println(demangledObject.getClass().getSimpleName() + " " + mangled + " --> " +
demangledObject);
}
else {
println("Failed to demangle: " + mangled);
}
}
}
@@ -0,0 +1,127 @@
/* ###
* 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.File;
import java.io.IOException;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.OptionType;
import ghidra.framework.options.Options;
import ghidra.program.model.listing.Program;
import ghidra.util.HelpLocation;
/**
* An analyzer to demangle Swift mangled symbols
*/
public class SwiftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
private static final String NAME = "Demangler Swift";
private static final String DESCRIPTION =
"Demangles Swift symbols and applies appropriate datatype and calling conventions where possible. Requires Swift to be installed.";
private static final String OPTION_NAME_SWIFT_DIR = "Swift binary directory";
private static final String OPTION_DESCRIPTION_SWIFT_DIR =
"Path to the Swift installation binary directory, if not on PATH";
private static final String OPTION_NAME_INCOMPLETE_PREFIX =
"Use incomplete demangle label prefix (%s)"
.formatted(SwiftDemanglerOptions.INCOMPLETE_PREFIX);
private static final String OPTION_DESCRIPTION_INCOMPLETE_PREFIX =
"Prefix incomplete demangled labels with '%s'"
.formatted(SwiftDemanglerOptions.INCOMPLETE_PREFIX);
private static final String OPTION_NAME_UNSUPPORTED_PREFIX =
"Use unsupported demangle label prefix (%s)"
.formatted(SwiftDemanglerOptions.UNSUPPORTED_PREFIX);
private static final String OPTION_DESCRIPTION_UNSUPPORTED_PREFIX =
"Prefix unsupported demangled labels with '%s'"
.formatted(SwiftDemanglerOptions.UNSUPPORTED_PREFIX);
private File swiftDir;
private boolean useIncompletePrefix = true;
private boolean useUnsupportedPrefix = true;
private SwiftDemangler demangler = new SwiftDemangler();
/**
* Creates a new {@link SwiftDemanglerAnalyzer}
*/
public SwiftDemanglerAnalyzer() {
super(NAME, DESCRIPTION);
setDefaultEnablement(true);
}
@Override
public boolean canAnalyze(Program program) {
return demangler.canDemangle(program);
}
@Override
protected DemangledObject doDemangle(String mangled, DemanglerOptions options, MessageLog log)
throws DemangledException {
return demangler.demangle(mangled, options);
}
@Override
public void analysisEnded(Program program) {
demangler.clearCache();
}
@Override
public void registerOptions(Options options, Program program) {
HelpLocation help = new HelpLocation("AutoAnalysisPlugin", "Demangler_Analyzer");
options.registerOption(OPTION_NAME_SWIFT_DIR, OptionType.FILE_TYPE, swiftDir, help,
OPTION_DESCRIPTION_SWIFT_DIR);
options.registerOption(OPTION_NAME_INCOMPLETE_PREFIX, OptionType.BOOLEAN_TYPE,
useIncompletePrefix, help, OPTION_DESCRIPTION_INCOMPLETE_PREFIX);
options.registerOption(OPTION_NAME_UNSUPPORTED_PREFIX, OptionType.BOOLEAN_TYPE,
useUnsupportedPrefix, help, OPTION_DESCRIPTION_UNSUPPORTED_PREFIX);
}
@Override
protected boolean validateOptions(DemanglerOptions options, MessageLog log) {
if (options instanceof SwiftDemanglerOptions swiftDemanglerOptions) {
try {
new SwiftNativeDemangler(swiftDemanglerOptions.getSwiftDir());
return true;
}
catch (IOException e) {
log.appendMsg(e.getMessage());
log.appendMsg("You must have Swift installed to demangle Swift symbols.\n" +
"See the \"Demangler Swift\" analyzer options to configure.");
}
}
return false;
}
@Override
public void optionsChanged(Options options, Program program) {
swiftDir = options.getFile(OPTION_NAME_SWIFT_DIR, swiftDir);
useIncompletePrefix =
options.getBoolean(OPTION_NAME_INCOMPLETE_PREFIX, useIncompletePrefix);
useUnsupportedPrefix =
options.getBoolean(OPTION_NAME_UNSUPPORTED_PREFIX, useUnsupportedPrefix);
}
@Override
protected DemanglerOptions getOptions() {
SwiftDemanglerOptions swiftDemanglerOptions = new SwiftDemanglerOptions();
swiftDemanglerOptions.setSwiftDir(swiftDir);
swiftDemanglerOptions.setIncompletePrefix(useIncompletePrefix);
swiftDemanglerOptions.setUnsupportedPrefix(useUnsupportedPrefix);
return swiftDemanglerOptions;
}
}
@@ -13,28 +13,22 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package ghidra.app.util.bin.format.swift; package ghidra.app.util.demangler.swift;
import ghidra.app.util.bin.StructConverter; import ghidra.app.util.demangler.swift.nodes.SwiftNode;
/** /**
* Implemented by all Swift structures * Kinds of Swift demangling {@link SwiftNode}s
*
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/Demangling/DemangleNodes.def">DemangleNodes.def</a>
*/ */
public interface SwiftStructure extends StructConverter { public enum SwiftDemangledBuiltinType {
//@formatter:off
public static final String DATA_TYPE_CATEGORY = "/Swift";
/** Int1,
* Gets the name of the {@link SwiftStructure} Word,
* RawPointer,
* @return The name of the {@link SwiftStructure} Unsupported
*/
public String getStructureName(); //@formatter:on
/**
* Gets a short description of the {@link SwiftStructure}
*
* @return A short description of the {@link SwiftStructure}
*/
public String getDescription();
} }
@@ -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.demangler.swift;
import ghidra.app.util.demangler.swift.nodes.SwiftNode;
/**
* Kinds of Swift demangling {@link SwiftNode}s
*
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/Demangling/DemangleNodes.def">DemangleNodes.def</a>
*/
public enum SwiftDemangledNodeKind {
//@formatter:off
Allocator,
AnonymousDescriptor,
ArgumentTuple,
BoundGenericStructure,
BuiltinTypeName,
Class,
Constructor,
Deallocator,
DefaultArgumentInitializer,
DependentGenericParamType,
DependentGenericType,
Destructor,
DispatchThunk,
Enum,
Extension,
FirstElementMarker,
Function,
FunctionType,
GenericSpecialization,
Getter,
Global,
GlobalVariableOnceDeclList,
GlobalVariableOnceFunction,
Identifier,
InfixOperator,
Initializer,
InOut,
LabelList,
LazyProtocolWitnessTableAccessor,
LocalDeclName,
MergedFunction,
ModifyAccessor,
Module,
ModuleDescriptor,
NominalTypeDescriptor,
Number,
ObjCAttribute,
OutlinedConsume,
OutlinedCopy,
Owned,
PrivateDeclName,
Protocol,
ProtocolConformance,
ProtocolConformanceDescriptor,
ProtocolDescriptor,
ProtocolWitness,
ReflectionMetadataBuiltinDescriptor,
ReflectionMetadataFieldDescriptor,
ReturnType,
Setter,
Static,
Structure,
Subscript,
Suffix,
Tuple,
TupleElement,
TupleElementName,
Type,
TypeAlias,
TypeList,
TypeMetadataAccessFunction,
UnsafeMutableAddressor,
Unsupported,
Variable;
//@formatter:on
}
@@ -0,0 +1,170 @@
/* ###
* 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.demangler.swift;
import java.io.IOException;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import ghidra.app.util.demangler.swift.SwiftNativeDemangler.SwiftNativeDemangledOutput;
import ghidra.app.util.demangler.swift.nodes.SwiftNode;
import ghidra.app.util.demangler.swift.nodes.SwiftNode.NodeProperties;
import ghidra.app.util.demangler.swift.nodes.SwiftUnsupportedNode;
/**
* A Swift demangled symbol, structured as a tree of {@link SwiftNode nodes}
* <p>
* For example, the <code>Swift.print</code> function's mangled form is
* <code>_$ss5print_9separator10terminatoryypd_S2StF</code>, and its demangled tree is:
* <pre>
* kind=Global
* kind=Function
* kind=Module, text="Swift"
* kind=Identifier, text="print"
* kind=LabelList
* kind=FirstElementMarker
* kind=Identifier, text="separator"
* kind=Identifier, text="terminator"
* kind=Type
* kind=FunctionType
* kind=ArgumentTuple
* kind=Type
* kind=Tuple
* kind=TupleElement
* kind=VariadicMarker
* kind=Type
* kind=ProtocolList
* kind=TypeList
* kind=TupleElement
* kind=Type
* kind=Structure
* kind=Module, text="Swift"
* kind=Identifier, text="String"
* kind=TupleElement
* kind=Type
* kind=Structure
* kind=Module, text="Swift"
* kind=Identifier, text="String"
* kind=ReturnType
* kind=Type
* kind=Tuple
* </pre>
*/
public class SwiftDemangledTree {
private static final Pattern KIND_PATTERN = Pattern.compile("kind=([^,]+)");
private static final Pattern TEXT_PATTERN = Pattern.compile("text=\"(.+)\"");
private static final Pattern INDEX_PATTERN = Pattern.compile("index=(.+)");
private SwiftNode root;
private String demangledString;
/**
* Creates a new {@link SwiftDemangledTree}
*
* @param nativeDemangler The Swift native demangler
* @param mangled The mangled string
* @throws IOException If there was an IO-related error
*/
public SwiftDemangledTree(SwiftNativeDemangler nativeDemangler, String mangled)
throws IOException {
SwiftNativeDemangledOutput demangledOutput = nativeDemangler.demangle(mangled);
demangledString = demangledOutput.demangled();
Stack<SwiftNode> stack = new Stack<>();
for (String line : demangledOutput.tree()) {
int depth = depth(line);
String kind = match(line, KIND_PATTERN);
String text = match(line, TEXT_PATTERN);
String index = match(line, INDEX_PATTERN);
SwiftNode node;
try {
NodeProperties properties = new NodeProperties(SwiftDemangledNodeKind.valueOf(kind),
text, index, depth, mangled, demangledString);
node = SwiftNode.get(properties);
}
catch (IllegalArgumentException e) {
NodeProperties properties = new NodeProperties(SwiftDemangledNodeKind.Unsupported,
text, index, depth, mangled, demangledString);
node = new SwiftUnsupportedNode(kind, properties);
}
if (node.getDepth() == 0) {
root = node;
}
else {
if (node.getDepth() <= stack.peek().getDepth()) {
while (stack.peek().getDepth() > node.getDepth() - 1) {
stack.pop();
}
}
node.setParent(stack.peek());
stack.peek().getChildren().add(node);
}
stack.push(node);
}
}
/**
* Gets the root {@link SwiftNode} of the tree
*
* @return The root {@link SwiftNode} of the tree. Could be null if demangling finished
* gracefully but did not return a result.
*/
public SwiftNode getRoot() {
return root;
}
/**
* Gets the demangled string
*
* @return The demangled string. Could be null if demangling finished gracefully
* but did not return a result.
*/
public String getDemangledString() {
return demangledString;
}
@Override
public String toString() {
return SwiftNode.toString(root, true);
}
/**
* Gets the tree-depth of this {@link SwiftNode}
*
* @param line A line of output from <code>swift demangle --tree-only</code>
* @return The tree-depth of this {@link SwiftNode}
*/
private int depth(String line) {
int i = 0;
while (i < line.length() && line.charAt(i) == ' ') {
i++;
}
return i / 2;
}
/**
* Gets a matched pattern on the given line
*
* @param line The line to match against
* @param pattern The {@link Pattern} to match
* @return The matched string, or null if there was no match
*/
private String match(String line, Pattern pattern) {
Matcher matcher = pattern.matcher(line);
return matcher.find() ? matcher.group(1) : null;
}
}
@@ -0,0 +1,198 @@
/* ###
* 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.demangler.swift;
import java.io.IOException;
import java.util.*;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.datatypes.SwiftDataTypeUtils;
import ghidra.app.util.demangler.swift.nodes.SwiftNode;
import ghidra.app.util.importer.MessageLog;
import ghidra.program.model.listing.Program;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* A demangler for mangled Swift symbols
*/
public class SwiftDemangler implements Demangler {
private Program program;
private SwiftTypeMetadata typeMetadata;
private SwiftNativeDemangler nativeDemangler;
private SwiftDemanglerOptions options;
private Map<String, SwiftNode> cache;
private DemangledException initException;
@Override
public boolean canDemangle(Program p) {
this.program = p;
return SwiftUtils.isSwift(program);
}
@Override
public DemanglerOptions createDefaultOptions() {
return new SwiftDemanglerOptions();
}
@Override
public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns)
throws DemangledException {
return demangle(mangled);
}
/**
* Initializes class variables
*
* @param opt The options
* @throws DemangledException If there was an issue with initialization
*/
private void init(DemanglerOptions opt) throws DemangledException {
if (initException != null) {
throw initException;
}
if (program != null && typeMetadata == null) {
try {
program.setPreferredRootNamespaceCategoryPath(
SwiftDataTypeUtils.SWIFT_CATEGORY.getPath());
typeMetadata = new SwiftTypeMetadata(program, TaskMonitor.DUMMY, new MessageLog());
}
catch (CancelledException e) {
return;
}
catch (IOException e) {
initException = new DemangledException(e);
throw initException;
}
}
if (opt != null) {
options = getSwiftDemanglerOptions(opt);
}
if (nativeDemangler == null) {
try {
nativeDemangler = new SwiftNativeDemangler(options.getSwiftDir());
}
catch (IOException e) {
throw new DemangledException(e);
}
}
if (cache == null) {
cache = new HashMap<>();
}
}
/**
* Demangles the given mangled string
*
* @param mangled The mangled string
* @param originalDemangled The demangled string produced by the native Swift demangler
* @param meta The {@link SwiftTypeMetadata}, or null if unavailable
* @return The {@link Demangled} object, or null if the mangled string is not a supported Swift
* symbol
* @throws DemangledException if a problem occurred
*/
public Demangled demangle(String mangled, String originalDemangled, SwiftTypeMetadata meta)
throws DemangledException {
if (!isSwiftMangledSymbol(mangled)) {
return null;
}
try {
SwiftNode root;
if (cache.containsKey(mangled)) {
root = cache.get(mangled);
}
else {
SwiftDemangledTree tree = new SwiftDemangledTree(nativeDemangler, mangled);
root = tree.getRoot();
}
cache.put(mangled, root);
if (root == null) {
return null;
}
Demangled demangled = root.demangle(this, meta);
if (root.walkAndTest(node -> node.childWasSkipped())) {
demangled.setName(options.getIncompletePrefix() + demangled.getName());
}
return demangled;
}
catch (IOException e) {
throw new DemangledException(e);
}
}
@Override
public DemangledObject demangle(String mangled, DemanglerOptions opt)
throws DemangledException {
init(opt);
Demangled demangled = demangle(mangled, null, typeMetadata);
if (demangled instanceof DemangledFunction func) {
return func;
}
else if (demangled instanceof DemangledLabel label) {
return label;
}
else if (demangled instanceof DemangledUnknown unknown) {
return new DemangledLabel(mangled, unknown.getOriginalDemangled(),
options.getUnsupportedPrefix() + unknown.getOriginalDemangled());
}
return null;
}
/**
* Clears the cache
*/
public void clearCache() {
if (cache != null) {
cache.clear();
}
}
/**
* Checks to see whether the given symbol name is a mangled Swift symbol
*
* @param symbolName The symbol name to check
* @return True if the given symbol name is a mangled Swift symbol; otherwise, false
*/
public boolean isSwiftMangledSymbol(String symbolName) {
List<String> prefixes = List.of("$S", "$s", "_$S", "_$s", "_T");
return prefixes.stream().anyMatch(prefix -> symbolName.startsWith(prefix));
}
/**
* Gets the {@link SwiftDemanglerOptions} from the given {@link DemanglerOptions}
*
* @param opt The options
* @return The @link SwiftDemanglerOptions}
* @throws DemangledException If the given options are not {@link SwiftDemanglerOptions}
*/
public SwiftDemanglerOptions getSwiftDemanglerOptions(DemanglerOptions opt)
throws DemangledException {
if (!(opt instanceof SwiftDemanglerOptions)) {
opt = createDefaultOptions();
}
return (SwiftDemanglerOptions) opt;
}
}
@@ -0,0 +1,90 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.demangler.swift;
import java.io.File;
import ghidra.app.util.demangler.DemanglerOptions;
/**
* Swift demangler options
*/
public class SwiftDemanglerOptions extends DemanglerOptions {
public static final String INCOMPLETE_PREFIX = "$";
public static final String UNSUPPORTED_PREFIX = "$$";
private File swiftDir;
private boolean useIncompletePrefix;
private boolean useUnsupportedPrefix;
/**
* Gets the Swift directory
* <p>
* If the Swift directory is on the PATH environment variable, this may return null
*
* @return The Swift directory
*/
public File getSwiftDir() {
return swiftDir;
}
/**
* Sets the Swift directory
* <p>
* If the Swift directory is on the PATH environment variable, it is fine to set this to
* null
*
* @param swiftDir The Swift directory
*/
public void setSwiftDir(File swiftDir) {
this.swiftDir = swiftDir;
}
/**
* {@return the "incomplete prefix" character to use in label names}
*/
public String getIncompletePrefix() {
return useIncompletePrefix ? INCOMPLETE_PREFIX : "";
}
/**
* Sets whether or not to use an "incomplete prefix" character in label names
*
* @param incompletePrefix True if labels should include an "incomplete prefix" character
* in their name; otherwise, false
*/
public void setIncompletePrefix(boolean incompletePrefix) {
this.useIncompletePrefix = incompletePrefix;
}
/**
* {@return the "unsupported prefix" character to use in label names}
*/
public String getUnsupportedPrefix() {
return useUnsupportedPrefix ? UNSUPPORTED_PREFIX : "";
}
/**
* Sets whether or not to use an "unsupported prefix" character in label names
*
* @param unsupportedPrefix True if labels should include an "unsupported prefix" character
* in their name; otherwise, false
*/
public void setUnsupportedPrefix(boolean unsupportedPrefix) {
this.useUnsupportedPrefix = unsupportedPrefix;
}
}
@@ -0,0 +1,156 @@
/* ###
* 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.demangler.swift;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* A class used to launch the Swift native demangler.
* <p>
* The Swift native demangler binary comes in 2 forms, and can thus be invoked in 2 ways:
* <ul>
* <li>{@code ./swift demangle args}</li>
* <li>{@code ./swift-demangle args}</li>
* </ul>
*
* The latter is how it is done in the Windows version of Swift. We will refer to this version
* as the "standalone demangler binary".
*/
public class SwiftNativeDemangler {
private String nativeDemanglerPath;
private boolean standaloneDemanglerBinary;
/**
* The output of the native Swift demangler
*
* @param demangled The demangled string
* @param tree The lines of the demangled expanded tree
*/
public record SwiftNativeDemangledOutput(String demangled, List<String> tree) {
@Override
public String toString() {
return "%s\n%s".formatted(demangled != null ? demangled : "<NULL>",
tree.stream().collect(Collectors.joining("\n")));
}
}
/**
* Creates a new {@link SwiftNativeDemangler}
*
* @param swiftDir The Swift directory
* @throws IOException if there was a problem finding or running the Swift native demangler
*/
public SwiftNativeDemangler(File swiftDir) throws IOException {
List<String> demanglerNames = List.of("swift-demangle", "swift");
IOException ioe = null;
for (String demanglerName : demanglerNames) {
nativeDemanglerPath = demanglerName;
if (swiftDir != null) {
nativeDemanglerPath = swiftDir + File.separator + nativeDemanglerPath;
}
try {
int exitCode =
new ProcessBuilder(List.of(nativeDemanglerPath, "--version")).start()
.waitFor();
if (exitCode == 0) {
ioe = null;
standaloneDemanglerBinary =
new File(nativeDemanglerPath).getName().contains("-demangle");
break;
}
ioe = new IOException("Native Swift demangler exited with code: " + exitCode);
}
catch (IOException e) {
ioe = e;
}
catch (InterruptedException e) {
ioe = new IOException(e);
}
}
if (ioe != null) {
throw ioe;
}
}
/**
* Uses the Swift executable to demangle the given mangled string
*
* @param mangled The mangled string to demangle
* @return The {@link SwiftNativeDemangledOutput}
* @throws IOException If there was an IO-related issue
* @see SwiftDemangledTree
*/
public SwiftNativeDemangledOutput demangle(String mangled) throws IOException {
List<String> demanglerArgs = new ArrayList<>();
demanglerArgs.add("--compact"); // Compact mode (only emit the demangled names)
demanglerArgs.add("--expand"); // Expand mode (show node structure of the demangling)
try (BufferedReader reader = demangle(mangled, demanglerArgs)) {
String demangled = null;
List<String> treeLines = new ArrayList<>();
String line = reader.readLine().trim();
if (!line.startsWith("Demangling for")) {
throw new IOException("Unexpected output: " + line);
}
while ((line = reader.readLine()) != null) {
if (line.startsWith("<<NULL>>")) { // Not a demangleable string
break;
}
if (line.isBlank()) {
continue;
}
if (treeLines.isEmpty() && !line.trim().startsWith("kind")) {
// This case is mainly for when the mangled string has newline characters in it,
// which are printed in the first "Demangling for..." line. We want to skip
// those and get to the tree.
continue;
}
if (!treeLines.isEmpty() && !line.startsWith(" ")) {
// This case should grab the last line after the tree, which is the full
// demangled string
demangled = line;
break;
}
treeLines.add(line);
}
return new SwiftNativeDemangledOutput(demangled, treeLines);
}
}
/**
* Runs the Swift demangler to demangled the given mangled string with the given demangle
* options
*
* @param mangled The mangled string to demangle
* @param options Additional demangle options
* @return A {@link BufferedReader} used to read the output of the executed command
* @throws IOException If there was an IO-related issue
*/
private BufferedReader demangle(String mangled, List<String> options) throws IOException {
List<String> command = new ArrayList<>();
command.add(nativeDemanglerPath);
if (!standaloneDemanglerBinary) {
command.add("demangle");
}
command.addAll(options);
command.add(mangled);
Process p = new ProcessBuilder(command).redirectErrorStream(true).start();
return new BufferedReader(new InputStreamReader(p.getInputStream()));
}
}
@@ -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.util.demangler.swift.datatypes;
import ghidra.app.util.demangler.DemangledDataType;
/**
* A Swift array
*/
public class SwiftArray extends DemangledDataType {
private DemangledDataType boundType;
/**
* Creates a new Swift array bound to the "undefined" type
*
* @param mangled The mangled string
* @param originalDemangled The natively demangled string
*/
public SwiftArray(String mangled, String originalDemangled) {
super(mangled, originalDemangled, "Array");
setNamespace(SwiftDataTypeUtils.SWIFT_NAMESPACE);
setBoundType(
new DemangledDataType(mangled, originalDemangled, DemangledDataType.UNDEFINED));
setArray(1);
}
/**
* {@return the bound type}
*/
public DemangledDataType getBoundType() {
return boundType;
}
/**
* Sets the bound type
*
* @param type The bound type
*/
public void setBoundType(DemangledDataType type) {
boundType = type;
setName("Array<%s>".formatted(type.getName()));
}
}
@@ -0,0 +1,46 @@
/* ###
* 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.demangler.swift.datatypes;
import ghidra.app.util.demangler.DemangledDataType;
import ghidra.app.util.demangler.DemangledStructure;
/**
* A Swift character
*/
public class SwiftCharacter extends DemangledStructure {
/**
* Creates a new Swift character
*
* @param mangled The mangled string
* @param originalDemangled The natively demangled string
*/
public SwiftCharacter(String mangled, String originalDemangled) {
super(mangled, originalDemangled, "Character",
SwiftDataTypeUtils.getCategoryPath(SwiftDataTypeUtils.SWIFT_NAMESPACE).getPath(), true);
setNamespace(SwiftDataTypeUtils.SWIFT_NAMESPACE);
DemangledDataType stringDt = new DemangledDataType(mangled, null, DemangledDataType.CHAR);
stringDt.incrementPointerLevels();
DemangledDataType voidDt = new DemangledDataType(mangled, null, DemangledDataType.VOID);
voidDt.incrementPointerLevels();
addField("str", stringDt);
addField("bridgeObject", voidDt);
}
}
@@ -0,0 +1,91 @@
/* ###
* 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.demangler.swift.datatypes;
import java.util.*;
import ghidra.app.util.demangler.*;
import ghidra.program.model.data.CategoryPath;
/**
* Swift data type utilities
*/
public class SwiftDataTypeUtils {
/**
* Default path to store Swift data structures in the data type manager
*/
public static final CategoryPath SWIFT_CATEGORY = new CategoryPath("/Demangler");
/**
* A {@link Demangled} to represent the standard Swift namespace
*/
public static final Demangled SWIFT_NAMESPACE = new DemangledUnknown("", null, "Swift");
/**
* Checks to see if the given namespace is the standard Swift namespace
*
* @param namespace The namespace to check
* @return True if the given namespace is the standard Swift namespace; otherwise, false
*/
public static boolean isSwiftNamespace(Demangled namespace) {
return namespace != null && namespace.getName().equals(SWIFT_NAMESPACE.getName());
}
/**
* Gets a {@link CategoryPath} based on the given namespace
*
* @param namespace The namespace
* @return A {@link CategoryPath} based on the given namespace
*/
public static CategoryPath getCategoryPath(Demangled namespace) {
if (namespace == null) {
return SWIFT_CATEGORY;
}
LinkedList<String> path = new LinkedList<>();
while (namespace != null) {
path.addFirst(namespace.getNamespaceName());
namespace = namespace.getNamespace();
}
return new CategoryPath(SWIFT_CATEGORY, path);
}
/**
* Creates a {@link List} of {@link DemangledParameter parameters} found within the given
* {@link Demangled} object
*
* @param demangled A {@link Demangled} object
* @return A {@link List} of {@link DemangledParameter parameters} found within the given
* {@link Demangled} object
*/
public static List<DemangledParameter> extractParameters(Demangled demangled) {
List<DemangledParameter> params = new ArrayList<>();
if (demangled instanceof DemangledVariable variable) {
demangled = variable.getDataType();
}
if (demangled instanceof DemangledList list) {
for (Demangled d : list) {
if (d instanceof DemangledDataType type) {
params.add(new DemangledParameter(type));
}
}
}
else if (demangled instanceof DemangledDataType type) {
params.add(new DemangledParameter(type));
}
return params;
}
}
@@ -0,0 +1,52 @@
/* ###
* 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.demangler.swift.datatypes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangler;
/**
* A Swift structure
*/
public class SwiftEnum extends DemangledStructure {
/**
* Creates a new Swift enum
*
* @param mangled The mangled string
* @param originalDemangled The natively demangled string
* @param name The enum name
* @param namespace The enum namespace (could be null)
* @param typeMetadata The {@link SwiftTypeMetadata}, or null if it is not known
* @param demangler A {@link SwiftDemangler}
* @throws DemangledException if a problem occurred
*/
public SwiftEnum(String mangled, String originalDemangled, String name,
Demangled namespace, SwiftTypeMetadata typeMetadata, SwiftDemangler demangler)
throws DemangledException {
super(mangled, originalDemangled, name,
SwiftDataTypeUtils.getCategoryPath(namespace).getPath(), true);
setNamespace(namespace);
// The mangled output doesn't seem to indicate what field of the enum is being used, so
// it's not currently clear how to query the type metadata for real type information.
// Raw enums seem to just be bytes, so for now we'll just use a struct with 1 byte entry.
DemangledDataType dt =
new DemangledDataType(mangled, originalDemangled, DemangledDataType.INT8);
addField("value", null, dt);
}
}
@@ -0,0 +1,55 @@
/* ###
* 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.demangler.swift.datatypes;
import java.util.List;
import ghidra.app.util.demangler.*;
/**
* A Swift function
*/
public class SwiftFunction extends DemangledFunction {
/**
* Creates a new Swift function
*
* @param mangled The mangled string
* @param originalDemangled The natively demangled string
* @param name The function name
* @param namespace The function namespace (could be null)
* @param callingConvention The function calling convention (could be null)
*/
public SwiftFunction(String mangled, String originalDemangled, String name, Demangled namespace,
String callingConvention) {
super(mangled, originalDemangled, name);
setNamespace(namespace);
setCallingConvention(callingConvention);
}
public void setType(DemangledFunction type, Demangled labelList) {
setReturnType(type.getReturnType());
List<DemangledParameter> params = type.getParameters();
for (int i = 0; i < params.size(); i++) {
DemangledParameter param = params.get(i);
if (labelList instanceof DemangledList list && i < list.size() &&
list.get(i) instanceof DemangledLabel label) {
param.setLabel(label.getName());
}
addParameter(param);
}
}
}
@@ -0,0 +1,48 @@
/* ###
* 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.demangler.swift.datatypes;
import ghidra.app.util.demangler.DemangledDataType;
/**
* A Swift primitive
*/
public class SwiftPrimitive extends DemangledDataType {
/**
* Creates a new Swift primitive
*
* @param mangled The mangled string
* @param originalDemangled The natively demangled string
* @param name The primitive name
*/
public SwiftPrimitive(String mangled, String originalDemangled, String name) {
super(mangled, originalDemangled, name);
}
/**
* Creates a new Swift primitive
*
* @param mangled The mangled string
* @param originalDemangled The natively demangled string
* @param name The primitive name
* @param unsigned True if the primitive should be unsigned; otherwise, false
*/
public SwiftPrimitive(String mangled, String originalDemangled, String name, boolean unsigned) {
this(mangled, originalDemangled, name);
setUnsigned();
}
}
@@ -0,0 +1,46 @@
/* ###
* 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.demangler.swift.datatypes;
import ghidra.app.util.demangler.DemangledDataType;
import ghidra.app.util.demangler.DemangledStructure;
/**
* A Swift string
*/
public class SwiftString extends DemangledStructure {
/**
* Creates a new Swift string
*
* @param mangled The mangled string
* @param originalDemangled The natively demangled string
*/
public SwiftString(String mangled, String originalDemangled) {
super(mangled, originalDemangled, "String",
SwiftDataTypeUtils.getCategoryPath(SwiftDataTypeUtils.SWIFT_NAMESPACE).getPath(), true);
setNamespace(SwiftDataTypeUtils.SWIFT_NAMESPACE);
DemangledDataType stringDt = new DemangledDataType(mangled, null, DemangledDataType.CHAR);
stringDt.incrementPointerLevels();
DemangledDataType voidDt = new DemangledDataType(mangled, null, DemangledDataType.VOID);
voidDt.incrementPointerLevels();
addField("str", stringDt);
addField("bridgeObject", voidDt);
}
}
@@ -0,0 +1,66 @@
/* ###
* 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.demangler.swift.datatypes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.bin.format.swift.types.*;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangler;
/**
* A Swift structure
*/
public class SwiftStructure extends DemangledStructure {
/**
* Creates a new Swift structure
*
* @param mangled The mangled string
* @param originalDemangled The natively demangled string
* @param name The structure name
* @param namespace The structure namespace (could be null)
* @param typeMetadata The {@link SwiftTypeMetadata}, or null if it is not known
* @param demangler A {@link SwiftDemangler}
* @throws DemangledException if a problem occurred
*/
public SwiftStructure(String mangled, String originalDemangled, String name,
Demangled namespace, SwiftTypeMetadata typeMetadata, SwiftDemangler demangler)
throws DemangledException {
super(mangled, originalDemangled, name,
SwiftDataTypeUtils.getCategoryPath(namespace).getPath(), true);
setNamespace(namespace);
// Try to add structure fields from the type metadata
if (typeMetadata != null) {
TargetTypeContextDescriptor typeDescriptor =
typeMetadata.getTargetTypeContextDescriptors().get(name);
if (typeDescriptor != null) {
FieldDescriptor fieldDescriptor =
typeDescriptor.getFieldDescriptor(typeMetadata.getFieldDescriptors());
if (fieldDescriptor != null) {
for (FieldRecord fieldRecord : fieldDescriptor.getFieldRecords()) {
String mangledType = "_T" + fieldRecord.getMangledTypeName();
Demangled demangled =
demangler.demangle(mangledType, originalDemangled, typeMetadata);
if (demangled instanceof DemangledDataType ddt) {
addField(fieldRecord.getFieldName(), fieldRecord.getDescription(), ddt);
}
}
}
}
}
}
}
@@ -0,0 +1,53 @@
/* ###
* 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.demangler.swift.datatypes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangler;
/**
* A Swift tuple
*/
public class SwiftTuple extends SwiftStructure {
/**
* Creates a new Swift tuple
*
* @param mangled The mangled string
* @param originalDemangled The natively demangled string
* @param list The elements of the tuple
* @param typeMetadata The {@link SwiftTypeMetadata}, or null if it is not known
* @param demangler A {@link SwiftDemangler}
* @throws DemangledException if a problem occurred
*/
public SwiftTuple(String mangled, String originalDemangled, DemangledList list,
SwiftTypeMetadata typeMetadata, SwiftDemangler demangler) throws DemangledException {
super(mangled, originalDemangled, "tuple%d".formatted(list.size()), null, typeMetadata,
demangler);
int i = 0;
for (Demangled element : list) {
if (element instanceof DemangledDataType ddt) {
addField(Integer.toString(i), ddt);
}
else if (element instanceof DemangledVariable variable) {
addField(variable.getName(), variable.getDataType());
}
i++;
}
}
}

Some files were not shown because too many files have changed in this diff Show More