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

View file

@ -31,6 +31,8 @@ public class SwiftTypeMetadataAnalyzer extends AbstractAnalyzer {
private static final String NAME = "Swift Type Metadata Analyzer";
private static final String DESCRIPTION = "Discovers Swift type metadata records.";
private SwiftTypeMetadata typeMetadata;
public SwiftTypeMetadataAnalyzer() {
super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER);
setDefaultEnablement(true);
@ -45,8 +47,11 @@ public class SwiftTypeMetadataAnalyzer extends AbstractAnalyzer {
@Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {
if (typeMetadata != null) {
return true;
}
try {
SwiftTypeMetadata typeMetadata = new SwiftTypeMetadata(program, monitor, log);
typeMetadata = new SwiftTypeMetadata(program, monitor, log);
typeMetadata.markup();
}
catch (IOException e) {
@ -54,4 +59,9 @@ public class SwiftTypeMetadataAnalyzer extends AbstractAnalyzer {
}
return true;
}
@Override
public void analysisEnded(Program program) {
typeMetadata = null;
}
}

View file

@ -35,8 +35,9 @@ public enum SwiftSection {
BLOCK_PROTOCS("__swift5_protos", "swift5_protocols", ".sw5prt"),
BLOCK_ACFUNCS("__swift5_acfuncs", "swift5_accessible_functions", ".sw5acfn"),
BLOCK_MPENUM("__swift5_mpenum", "swift5_mpenum", ".sw5mpen"),
BLOCK_TYPES("__swift5_types", "swift5_types", ".sw5tymd"),
BLOCK_ENTRY("__swift5_entry", "swift5_entry", ".sw5entr");
BLOCK_TYPES("__swift5_types", "swift5_type_metadata", ".sw5tymd"),
BLOCK_ENTRY("__swift5_entry", "swift5_entry", ".sw5entr"),
BLOCK_SWIFTAST("__swift_ast", ".swift_ast", "swiftast");
private List<String> sectionNames;

View file

@ -16,8 +16,7 @@
package ghidra.app.util.bin.format.swift;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
import ghidra.app.util.bin.*;
import ghidra.app.util.bin.format.swift.types.*;
@ -43,11 +42,11 @@ public class SwiftTypeMetadata {
private List<EntryPoint> entryPoints = 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<CaptureDescriptor> captureDescriptors = 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<TargetProtocolConformanceDescriptor> protocolConformanceDescriptors =
new ArrayList<>();
@ -72,6 +71,69 @@ public class SwiftTypeMetadata {
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}
*
@ -137,7 +199,7 @@ public class SwiftTypeMetadata {
for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) {
Address blockStart = block.getStart();
reader.setPointerIndex(blockStart.getOffset());
int i = 0;
int i = skipZeroEntries(reader, 0, block.getSize());
while (i + BuiltinTypeDescriptor.SIZE <= block.getSize()) {
monitor.checkCancelled();
BuiltinTypeDescriptor descriptor = new BuiltinTypeDescriptor(reader);
@ -145,6 +207,7 @@ public class SwiftTypeMetadata {
markupList.add(new SwiftStructureInfo(descriptor,
new SwiftStructureAddress(blockStart.add(i), null)));
i += BuiltinTypeDescriptor.SIZE;
i = skipZeroEntries(reader, i, block.getSize());
}
}
}
@ -168,11 +231,11 @@ public class SwiftTypeMetadata {
for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) {
Address blockStart = block.getStart();
reader.setPointerIndex(blockStart.getOffset());
int i = 0;
int i = skipZeroEntries(reader, 0, block.getSize());
while (i + FieldDescriptor.SIZE <= block.getSize()) {
monitor.checkCancelled();
FieldDescriptor descriptor = new FieldDescriptor(reader);
fieldDescriptors.add(descriptor);
fieldDescriptors.put(descriptor.getBase(), descriptor);
markupList.add(new SwiftStructureInfo(descriptor,
new SwiftStructureAddress(blockStart.add(i), null)));
List<FieldRecord> records = descriptor.getFieldRecords();
@ -184,6 +247,7 @@ public class SwiftTypeMetadata {
null)));
}
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)) {
Address blockStart = block.getStart();
reader.setPointerIndex(blockStart.getOffset());
int i = 0;
int i = skipZeroEntries(reader, 0, block.getSize());
while (i + AssociatedTypeDescriptor.SIZE <= block.getSize()) {
monitor.checkCancelled();
AssociatedTypeDescriptor descriptor = new AssociatedTypeDescriptor(reader);
@ -223,6 +287,7 @@ public class SwiftTypeMetadata {
blockStart.add(i + j * AssociatedTypeRecord.SIZE), null)));
}
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)) {
Address blockStart = block.getStart();
reader.setPointerIndex(blockStart.getOffset());
int i = 0;
int i = skipZeroEntries(reader, 0, block.getSize());
while (i + CaptureDescriptor.SIZE <= block.getSize()) {
monitor.checkCancelled();
CaptureDescriptor descriptor = new CaptureDescriptor(reader);
@ -271,6 +336,7 @@ public class SwiftTypeMetadata {
blockStart.add(i + j * MetadataSourceRecord.SIZE), null)));
}
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)) {
Address blockStart = block.getStart();
reader.setPointerIndex(blockStart.getOffset());
int i = 0;
int i = skipZeroEntries(reader, 0, block.getSize());
while (i < block.getSize()) {
monitor.checkCancelled();
MultiPayloadEnumDescriptor descriptor = new MultiPayloadEnumDescriptor(reader);
@ -302,6 +368,7 @@ public class SwiftTypeMetadata {
markupList.add(new SwiftStructureInfo(descriptor,
new SwiftStructureAddress(blockStart.add(i), null)));
i += MultiPayloadEnumDescriptor.SIZE + descriptor.getContentsSize();
i = skipZeroEntries(reader, i, block.getSize());
}
}
}
@ -397,7 +464,7 @@ public class SwiftTypeMetadata {
yield null;
};
if (descriptor != null) {
typeDescriptors.add(descriptor);
typeDescriptors.put(descriptor.getName(), descriptor);
markupList.add(new SwiftStructureInfo(descriptor,
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 reader A {@link BinaryReader}
@ -428,14 +495,13 @@ public class SwiftTypeMetadata {
reader.setPointerIndex(blockAddr.getOffset() + i);
Address pointerAddr = blockAddr.add(i);
int offset = reader.readInt(pointerAddr.getOffset());
if (offset == 0) {
break;
}
if (offset != 0) {
Address structAddr = pointerAddr.add(offset);
result.add(new SwiftStructureAddress(structAddr, pointerAddr));
}
}
}
}
catch (IOException e) {
log("Failed to parse Swift struction pointers from section '" + section + "'");
}
@ -454,7 +520,7 @@ public class SwiftTypeMetadata {
monitor.checkCancelled();
monitor.incrementProgress(1);
try {
SwiftStructure struct = structInfo.struct();
SwiftTypeMetadataStructure struct = structInfo.struct();
DataType dt = struct.toDataType();
DataUtilities.createData(program, structInfo.addr().structAddr(), dt, -1,
ClearDataMode.CLEAR_ALL_DEFAULT_CONFLICT_DATA);
@ -465,12 +531,37 @@ public class SwiftTypeMetadata {
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);
}
}
}
/**
* 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
*
@ -481,22 +572,24 @@ public class SwiftTypeMetadata {
}
/**
* The {@link Address} of a {@link SwiftStructure} and the optional {@link Address} of its
* pointer
* The {@link Address} of a {@link SwiftTypeMetadataStructure} and the optional {@link Address}
* of its pointer
*
* @param structAddr The {@link Address} of a {@link SwiftStructure}
* @param pointerAddr The {@link Address} of a pointer to a {@link SwiftStructure} (could be
* null if there is no associated pointer}
* @param structAddr The {@link Address} of a {@link SwiftTypeMetadataStructure}
* @param pointerAddr The {@link Address} of a pointer to a {@link SwiftTypeMetadataStructure}
* (could be null if there is no associated pointer}
*/
private record SwiftStructureAddress(Address structAddr, Address pointerAddr) {}
/**
* Information about a {@link SwiftStructure}
* Information about a {@link SwiftTypeMetadataStructure}
*
* @param struct The {@link SwiftStructure}
* @param addr The {@link SwiftStructureAddress address} of the {@link SwiftStructure}
* @param struct The {@link SwiftTypeMetadataStructure}
* @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
public String toString() {

View file

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

View file

@ -57,6 +57,23 @@ public class SwiftUtils {
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}
*

View file

@ -20,7 +20,7 @@ import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.SwiftStructure;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.*;
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>
*/
public final class AssociatedTypeDescriptor implements SwiftStructure {
public final class AssociatedTypeDescriptor extends SwiftTypeMetadataStructure {
/**
* 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
*/
public AssociatedTypeDescriptor(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
conformingTypeName = reader.readNext(SwiftUtils::relativeString);
protocolTypeName = reader.readNext(SwiftUtils::relativeString);
numAssociatedTypes = reader.readNextInt();

View file

@ -18,7 +18,7 @@ package ghidra.app.util.bin.format.swift.types;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.SwiftStructure;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.*;
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>
*/
public final class AssociatedTypeRecord implements SwiftStructure {
public final class AssociatedTypeRecord extends SwiftTypeMetadataStructure {
/**
* 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
*/
public AssociatedTypeRecord(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
name = reader.readNext(SwiftUtils::relativeString);
substitutedTypeName = reader.readNext(SwiftUtils::relativeString);
}

View file

@ -18,7 +18,8 @@ package ghidra.app.util.bin.format.swift.types;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.*;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.*;
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>
*/
public final class BuiltinTypeDescriptor implements SwiftStructure {
public final class BuiltinTypeDescriptor extends SwiftTypeMetadataStructure {
/**
* 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
*/
public BuiltinTypeDescriptor(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
typeName = reader.readNext(SwiftUtils::relativeString);
size = reader.readNextInt();
alignmentAndFlags = reader.readNextInt();

View file

@ -20,10 +20,8 @@ import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.SwiftStructure;
import ghidra.program.model.data.CategoryPath;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.program.model.data.*;
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>
*/
public final class CaptureDescriptor implements SwiftStructure {
public final class CaptureDescriptor extends SwiftTypeMetadataStructure {
/**
* 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
*/
public CaptureDescriptor(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
numCaptureTypes = reader.readNextInt();
numMetadataSources = reader.readNextInt();
numBindings = reader.readNextInt();

View file

@ -18,7 +18,8 @@ package ghidra.app.util.bin.format.swift.types;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.*;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.*;
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>
*/
public final class CaptureTypeRecord implements SwiftStructure {
public final class CaptureTypeRecord extends SwiftTypeMetadataStructure {
/**
* 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
*/
public CaptureTypeRecord(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
mangledTypeName = reader.readNext(SwiftUtils::relativeString);
}

View file

@ -18,7 +18,7 @@ package ghidra.app.util.bin.format.swift.types;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.SwiftStructure;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.DataType;
import ghidra.util.exception.DuplicateNameException;
@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
/**
* 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
@ -42,6 +42,7 @@ public final class EntryPoint implements SwiftStructure {
* @throws IOException if there was an IO-related problem creating the structure
*/
public EntryPoint(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
entryPoint = reader.readNextInt();
}

View file

@ -20,7 +20,8 @@ import java.util.ArrayList;
import java.util.List;
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.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>
*/
public final class FieldDescriptor implements SwiftStructure {
public final class FieldDescriptor extends SwiftTypeMetadataStructure {
/**
* 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
*/
public FieldDescriptor(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
mangledTypeName = reader.readNext(SwiftUtils::relativeString);
superclass = reader.readNextInt();
kind = reader.readNextUnsignedShort();

View file

@ -18,7 +18,8 @@ package ghidra.app.util.bin.format.swift.types;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.*;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.*;
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>
*/
public final class FieldRecord implements SwiftStructure {
public final class FieldRecord extends SwiftTypeMetadataStructure {
/**
* 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
*/
public FieldRecord(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
flags = reader.readNextInt();
mangledTypeName = reader.readNext(SwiftUtils::relativeString);
fieldName = reader.readNext(SwiftUtils::relativeString);

View file

@ -18,7 +18,8 @@ package ghidra.app.util.bin.format.swift.types;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.*;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.*;
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>
*/
public final class MetadataSourceRecord implements SwiftStructure {
public final class MetadataSourceRecord extends SwiftTypeMetadataStructure {
/**
* 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
*/
public MetadataSourceRecord(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
mangledTypeName = reader.readNext(SwiftUtils::relativeString);
mangledMetadataSource = reader.readNext(SwiftUtils::relativeString);
}

View file

@ -18,7 +18,7 @@ package ghidra.app.util.bin.format.swift.types;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.SwiftStructure;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.DataType;
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>
*/
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
@ -48,6 +48,7 @@ public final class MultiPayloadEnumDescriptor implements SwiftStructure {
* @throws IOException if there was an IO-related problem creating the structure
*/
public MultiPayloadEnumDescriptor(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
typeName = reader.readNext(SwiftUtils::relativeString);
int size = (reader.readNextInt() >> 16) & 0xffff;
reader.setPointerIndex(reader.getPointerIndex() - 4);

View file

@ -19,9 +19,7 @@ import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.CategoryPath;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**

View file

@ -18,7 +18,8 @@ package ghidra.app.util.bin.format.swift.types;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.*;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.*;
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>
*/
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 parent;
@ -39,6 +45,7 @@ public class TargetContextDescriptor implements SwiftStructure {
* @throws IOException if there was an IO-related problem creating the structure
*/
public TargetContextDescriptor(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
flags = reader.readNextInt();
parent = reader.readNextInt();
}

View file

@ -18,7 +18,8 @@ package ghidra.app.util.bin.format.swift.types;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.*;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.app.util.bin.format.swift.SwiftUtils;
import ghidra.program.model.data.*;
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>
*/
public final class TargetProtocolConformanceDescriptor implements SwiftStructure {
public final class TargetProtocolConformanceDescriptor extends SwiftTypeMetadataStructure {
private int protocolDescriptor;
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
*/
public TargetProtocolConformanceDescriptor(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
protocolDescriptor = reader.readNextInt();
nominalTypeDescriptor = reader.readNextInt();
protocolWitnessTable = reader.readNextInt();

View file

@ -16,6 +16,7 @@
package ghidra.app.util.bin.format.swift.types;
import java.io.IOException;
import java.util.Map;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.SwiftUtils;
@ -73,6 +74,20 @@ public class TargetTypeContextDescriptor extends TargetContextDescriptor {
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
public String getStructureName() {
return getMyStructureName();

View file

@ -73,6 +73,7 @@ public class DemangledDataType extends DemangledType {
public final static String LONG = "long";
public final static String LONG_LONG = "long long";
public final static String FLOAT = "float";
public final static String FLOAT2 = "float2";
public final static String DOUBLE = "double";
public final static String INT8 = "__int8";
public final static String INT16 = "__int16";
@ -94,7 +95,7 @@ public class DemangledDataType extends DemangledType {
public final static String[] PRIMITIVES =
{ 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 boolean isClass;
@ -293,6 +294,9 @@ public class DemangledDataType extends DemangledType {
else if (FLOAT.equals(name)) {
dt = FloatDataType.dataType;
}
else if (FLOAT2.equals(name)) {
dt = Float2DataType.dataType;
}
else if (FLOAT128.equals(name)) {
dt = new TypedefDataType(FLOAT128, Float16DataType.dataType);
}

View file

@ -54,7 +54,7 @@ public class DemangledFunction extends DemangledObject {
protected DemangledDataType returnType;
protected String callingConvention;// __cdecl, __thiscall, etc.
protected boolean thisPassedOnStack = true;
protected List<DemangledDataType> parameters = new ArrayList<>();
protected List<DemangledParameter> parameters = new ArrayList<>();
protected DemangledTemplate template;
protected boolean isOverloadedOperator = false;
protected SourceType signatureSourceType = SourceType.ANALYSIS;
@ -140,11 +140,15 @@ public class DemangledFunction extends DemangledObject {
this.isOverloadedOperator = isOverloadedOperator;
}
public void addParameter(DemangledDataType parameter) {
public void addParameter(DemangledParameter 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);
}
@ -323,7 +327,7 @@ public class DemangledFunction extends DemangledObject {
}
protected void addParameters(StringBuilder buffer, boolean format) {
Iterator<DemangledDataType> paramIterator = parameters.iterator();
Iterator<DemangledParameter> paramIterator = parameters.iterator();
buffer.append('(');
int padLength = format ? buffer.length() : 0;
String pad = StringUtils.rightPad("", padLength);
@ -332,7 +336,11 @@ public class DemangledFunction extends DemangledObject {
}
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()) {
buffer.append(',');
if (format) {
@ -353,9 +361,9 @@ public class DemangledFunction extends DemangledObject {
public String getParameterString() {
StringBuffer buffer = new StringBuffer();
buffer.append('(');
Iterator<DemangledDataType> dditer = parameters.iterator();
Iterator<DemangledParameter> dditer = parameters.iterator();
while (dditer.hasNext()) {
buffer.append(dditer.next().getSignature());
buffer.append(dditer.next().getType().getSignature());
if (dditer.hasNext()) {
buffer.append(',');
}
@ -576,13 +584,13 @@ public class DemangledFunction extends DemangledObject {
return false;
}
DemangledDataType lastType = parameters.get(parameters.size() - 1);
DemangledDataType lastType = parameters.get(parameters.size() - 1).getType();
return lastType.isVarArgs();
}
private boolean hasVoidParams() {
if (parameters.size() == 1) {
DemangledDataType ddt = parameters.get(0);
DemangledDataType ddt = parameters.get(0).getType();
return ddt.isVoid() && !ddt.isPointer();
}
return false;
@ -634,7 +642,7 @@ public class DemangledFunction extends DemangledObject {
// If returnType is null check for constructor or destructor names
if (THIS_CALL.equals(function.getCallingConventionName())) {
String n = getName();
if (n.equals(namespace.getName())) {
if (namespace != null && n.equals(namespace.getName())) {
// constructor
return DataType.DEFAULT;
}
@ -698,17 +706,18 @@ public class DemangledFunction extends DemangledObject {
private List<ParameterDefinitionImpl> convertMangledToParamDef(Program program) {
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.
if (param.isVoid() && !param.isPointer()) {
DemangledDataType type = param.getType();
if (type.isVoid() && !type.isPointer()) {
break;
}
if (param.isVarArgs()) {
if (type.isVarArgs()) {
break;
}
DataType dt = param.getDataType(program.getDataTypeManager());
args.add(new ParameterDefinitionImpl(null, dt, null));
DataType dt = type.getDataType(program.getDataTypeManager());
args.add(new ParameterDefinitionImpl(param.getLabel(), dt, null));
}
return args;
}

View file

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

View file

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

View file

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

View file

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

View file

@ -24,6 +24,7 @@ import ghidra.app.util.Option;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.ByteProviderWrapper;
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.importer.MessageLog;
import ghidra.formats.gfilesystem.*;
@ -60,7 +61,13 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
MachHeader machHeader = new MachHeader(provider);
String magic =
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) {
loadSpecs.add(new LoadSpec(this, machHeader.getImageBase(), result));
}

View file

@ -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.debug.DebugCOFFSymbol;
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.framework.model.DomainObject;
import ghidra.framework.options.Options;
@ -904,6 +905,7 @@ public class PeLoader extends AbstractPeDebugLoader {
CLI("cli", "cli"),
Rustc(RustConstants.RUST_COMPILER, RustConstants.RUST_COMPILER),
GOLANG("golang", "golang"),
Swift("swift", "swift"),
Unknown("unknown", "unknown"),
// The following values represent the presence of ambiguous indicators
@ -970,6 +972,15 @@ public class PeLoader extends AbstractPeDebugLoader {
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)
if (pe.getNTHeader().getOptionalHeader().isCLI()) {
return CompilerEnum.CLI;

View file

@ -485,7 +485,7 @@ public class GnuDemanglerParser {
//
setNameAndNamespace(function, simpleName);
for (DemangledDataType parameter : signatureParts.getParameters()) {
for (DemangledParameter parameter : signatureParts.getParameters()) {
function.addParameter(parameter);
}
@ -630,9 +630,9 @@ public class GnuDemanglerParser {
* Reason being, you need to take into account nested templates
* and function pointers.
*/
private List<DemangledDataType> parseParameters(String parameterString) {
private List<DemangledParameter> parseParameters(String parameterString) {
List<String> parameterStrings = tokenizeParameters(parameterString);
List<DemangledDataType> parameters = convertIntoParameters(parameterStrings);
List<DemangledParameter> parameters = convertIntoParameters(parameterStrings);
return parameters;
}
@ -735,12 +735,12 @@ public class GnuDemanglerParser {
* This method converts each parameter string into
* actual DemangledDataType objects.
*/
private List<DemangledDataType> convertIntoParameters(List<String> parameterStrings) {
List<DemangledDataType> parameters = new ArrayList<>();
private List<DemangledParameter> convertIntoParameters(List<String> parameterStrings) {
List<DemangledParameter> parameters = new ArrayList<>();
for (String parameter : parameterStrings) {
DemangledDataType dt = parseParameter(parameter);
parameters.add(dt);
parameters.add(new DemangledParameter(dt));
}
return parameters;
@ -1311,10 +1311,10 @@ public class GnuDemanglerParser {
contents = string.substring(1, string.length() - 1);
}
List<DemangledDataType> parameters = parseParameters(contents);
List<DemangledParameter> parameters = parseParameters(contents);
DemangledTemplate template = new DemangledTemplate();
for (DemangledDataType parameter : parameters) {
template.addParameter(parameter);
for (DemangledParameter parameter : parameters) {
template.addParameter(parameter.getType());
}
return template;
}
@ -1399,16 +1399,16 @@ public class GnuDemanglerParser {
return dfp;
}
private DemangledFunctionPointer createFunctionPointer(String paramerterString,
private DemangledFunctionPointer createFunctionPointer(String parameterString,
String returnType) {
List<DemangledDataType> parameters = parseParameters(paramerterString);
List<DemangledParameter> parameters = parseParameters(parameterString);
DemangledFunctionPointer dfp = new DemangledFunctionPointer(mangledSource, demangledSource);
DemangledDataType returnDataType = parseReturnType(returnType);
dfp.setReturnType(returnDataType);
for (DemangledDataType parameter : parameters) {
dfp.addParameter(parameter);
for (DemangledParameter parameter : parameters) {
dfp.addParameter(parameter.getType());
}
return dfp;
}
@ -1889,8 +1889,8 @@ public class GnuDemanglerParser {
// operator itself could be in a class namespace
setNameAndNamespace(function, operatorText);
List<DemangledDataType> parameters = parseParameters(parametersText);
for (DemangledDataType parameter : parameters) {
List<DemangledParameter> parameters = parseParameters(parametersText);
for (DemangledParameter parameter : parameters) {
function.addParameter(parameter);
}
@ -2029,7 +2029,7 @@ public class GnuDemanglerParser {
private String name;
private String rawParameterPrefix;
private List<DemangledDataType> parameters;
private List<DemangledParameter> parameters;
FunctionSignatureParts(String signatureString) {
@ -2077,7 +2077,7 @@ public class GnuDemanglerParser {
return isFunction;
}
List<DemangledDataType> getParameters() {
List<DemangledParameter> getParameters() {
return parameters;
}

View file

@ -54,9 +54,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
assertName(object, "bob");
DemangledFunction function = (DemangledFunction) object;
List<DemangledDataType> parameters = function.getParameters();
List<DemangledParameter> parameters = function.getParameters();
assertEquals(1, parameters.size());
DemangledDataType p1 = parameters.get(0);
DemangledDataType p1 = parameters.get(0).getType();
assertEquals("bob(int const[8] (*) [12])", p1.getOriginalDemangled());
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*)");
assertType(object, DemangledFunction.class);
DemangledFunction function = (DemangledFunction) object;
List<DemangledDataType> parameters = function.getParameters();
List<DemangledParameter> parameters = function.getParameters();
assertEquals(2, parameters.size());
DemangledDataType p1 = parameters.get(0);
DemangledDataType p1 = parameters.get(0).getType();
assertEquals(4, p1.getArrayDimensions());
}
@ -153,12 +153,12 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
DemangledFunction method = (DemangledFunction) object;
List<DemangledDataType> parameters = method.getParameters();
List<DemangledParameter> parameters = method.getParameters();
assertEquals(4, parameters.size());
assertEquals("unsigned long (*)(long const &)", parameters.get(0).getSignature());
assertEquals("unsigned long", parameters.get(1).getSignature());
assertEquals("unsigned long", parameters.get(2).getSignature());
assertEquals("float", parameters.get(3).getSignature());
assertEquals("unsigned long (*)(long const &)", parameters.get(0).getType().getSignature());
assertEquals("unsigned long", parameters.get(1).getType().getSignature());
assertEquals("unsigned long", parameters.get(2).getType().getSignature());
assertEquals("float", parameters.get(3).getType().getSignature());
}
@Test
@ -176,9 +176,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
"_Rb_tree<Location,Location,std::_Identity<Location>,std::less<Location>,std::allocator<Location>>");
DemangledFunction function = (DemangledFunction) object;
List<DemangledDataType> parameters = function.getParameters();
List<DemangledParameter> parameters = function.getParameters();
assertEquals(1, parameters.size());
assertEquals("Location const &", parameters.get(0).getSignature());
assertEquals("Location const &", parameters.get(0).getType().getSignature());
}
@Test
@ -194,7 +194,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
assertType(object, DemangledFunction.class);
DemangledFunction function = (DemangledFunction) object;
List<DemangledDataType> parameters = function.getParameters();
List<DemangledParameter> parameters = function.getParameters();
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&)>",
@ -211,9 +211,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
"bool (*)(std::pair<unsigned long,PcodeOp *> const &,std::pair<unsigned long,PcodeOp *> const &)",
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());
@ -234,9 +234,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
assertEquals(
"undefined std::set<bbnode*,std::less<bbnode*>,std::allocator<bbnode*>>::insert(bbnode const * &)",
method.getSignature(false));
List<DemangledDataType> parameters = method.getParameters();
List<DemangledParameter> parameters = method.getParameters();
assertEquals(1, parameters.size());
assertEquals("bbnode const * &", parameters.get(0).getSignature());
assertEquals("bbnode const * &", parameters.get(0).getType().getSignature());
}
@Test
@ -252,9 +252,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
DemangledFunction method = (DemangledFunction) object;
assertEquals("undefined Bar::Fred::Fred(int)", method.getSignature(false));
List<DemangledDataType> parameters = method.getParameters();
List<DemangledParameter> parameters = method.getParameters();
assertEquals(1, parameters.size());
assertEquals("int", parameters.get(0).getSignature());
assertEquals("int", parameters.get(0).getType().getSignature());
}
@Test
@ -428,9 +428,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
DemangledFunction function = (DemangledFunction) object;
assertEquals("undefined Foo::getBool(float)", function.getSignature(false));
List<DemangledDataType> parameters = function.getParameters();
List<DemangledParameter> parameters = function.getParameters();
assertEquals(1, parameters.size());
assertEquals("float", parameters.get(0).getSignature());
assertEquals("float", parameters.get(0).getType().getSignature());
}
@Test
@ -447,13 +447,13 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
DemangledFunction function = (DemangledFunction) object;
List<DemangledDataType> parameters = function.getParameters();
List<DemangledParameter> parameters = function.getParameters();
assertEquals(5, parameters.size());
assertEquals("int", parameters.get(0).getSignature());
assertEquals("double", parameters.get(1).getSignature());
assertEquals("char", parameters.get(2).getSignature());
assertEquals("long", parameters.get(3).getSignature());
assertEquals("short", parameters.get(4).getSignature());
assertEquals("int", parameters.get(0).getType().getSignature());
assertEquals("double", parameters.get(1).getType().getSignature());
assertEquals("char", parameters.get(2).getType().getSignature());
assertEquals("long", parameters.get(3).getType().getSignature());
assertEquals("short", parameters.get(4).getType().getSignature());
}
@Test
@ -827,13 +827,13 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
DemangledFunction method = (DemangledFunction) object;
List<DemangledDataType> parameters = method.getParameters();
List<DemangledParameter> parameters = method.getParameters();
assertEquals(5, parameters.size());
assertEquals("SECTION_INFO *", parameters.get(0).getSignature());
assertEquals("int *", parameters.get(1).getSignature());
assertEquals("int *[]", parameters.get(2).getSignature());
assertEquals("int", parameters.get(3).getSignature());
assertEquals("short const *", parameters.get(4).getSignature());
assertEquals("SECTION_INFO *", parameters.get(0).getType().getSignature());
assertEquals("int *", parameters.get(1).getType().getSignature());
assertEquals("int *[]", parameters.get(2).getType().getSignature());
assertEquals("int", parameters.get(3).getType().getSignature());
assertEquals("short const *", parameters.get(4).getType().getSignature());
}
@Test
@ -935,10 +935,10 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
"undefined Magick::operator<(Magick::Coordinate const &,Magick::Coordinate const &)",
method.getSignature(false));
List<DemangledDataType> parameters = method.getParameters();
List<DemangledParameter> parameters = method.getParameters();
assertEquals(2, parameters.size());
assertEquals("Magick::Coordinate const &", parameters.get(0).getSignature());
assertEquals("Magick::Coordinate const &", parameters.get(1).getSignature());
assertEquals("Magick::Coordinate const &", parameters.get(0).getType().getSignature());
assertEquals("Magick::Coordinate const &", parameters.get(1).getType().getSignature());
}
@Test
@ -1072,9 +1072,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
assertEquals("undefined Magick::pageImage::operator()(Magick::Image &)",
method.getSignature(false));
List<DemangledDataType> parameters = method.getParameters();
List<DemangledParameter> parameters = method.getParameters();
assertEquals(1, parameters.size());
assertEquals("Magick::Image &", parameters.get(0).getSignature());
assertEquals("Magick::Image &", parameters.get(0).getType().getSignature());
}
@Test
@ -1536,13 +1536,14 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
DemangledFunction df = (DemangledFunction) object;
List<DemangledDataType> parameters = df.getParameters();
List<DemangledParameter> parameters = df.getParameters();
assertEquals("Number of parameters", 1, parameters.size());
assertEquals("Name of type parsed", "F", parameters.get(0).getName());
assertEquals("Param Type Name parsed", "WTF", parameters.get(0).getNamespace().toString());
assertEquals("Name of type parsed", "F", parameters.get(0).getType().getName());
assertEquals("Param Type Name parsed", "WTF",
parameters.get(0).getType().getNamespace().toString());
assertEquals("Param Template was parsed",
"<WTF::F<void (Core::FileClient &)> (Core::File &)>",
parameters.get(0).getTemplate().toString());
parameters.get(0).getType().getTemplate().toString());
assertEquals(
"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;
List<DemangledDataType> parameters = df.getParameters();
List<DemangledParameter> parameters = df.getParameters();
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("Param Type Name parsed", "boost", demangParamDT.getNamespace().toString());
@ -1601,9 +1602,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
DemangledFunction df = (DemangledFunction) object;
List<DemangledDataType> parameters = df.getParameters();
List<DemangledParameter> parameters = df.getParameters();
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("Param Type Name parsed", "boost", demangParamDT.getNamespace().toString());
@ -1705,9 +1706,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
assertType(object, DemangledFunction.class);
DemangledFunction function = (DemangledFunction) object;
List<DemangledDataType> parameters = function.getParameters();
List<DemangledParameter> parameters = function.getParameters();
assertEquals(2, parameters.size());
assertTrue(parameters.get(1).isVarArgs());
assertTrue(parameters.get(1).getType().isVarArgs());
assertEquals("undefined testVarArgs(int,...)", object.getSignature(false));
}

View file

@ -369,7 +369,8 @@ public class MDMangGhidra extends MDMang {
MDArgumentsList args = functionType.getArgumentsList();
if (functionType.hasArgs() && args != null) {
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()) {

View file

@ -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")
}

View file

@ -0,0 +1,2 @@
##VERSION: 2.0
Module.manifest||GHIDRA||||END|

View file

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

View file

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

View file

@ -13,28 +13,22 @@
* See the License for the specific language governing permissions and
* 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
*/
public interface SwiftStructure extends StructConverter {
public static final String DATA_TYPE_CATEGORY = "/Swift";
/**
* Gets the name of the {@link SwiftStructure}
* Kinds of Swift demangling {@link SwiftNode}s
*
* @return The name of the {@link SwiftStructure}
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/Demangling/DemangleNodes.def">DemangleNodes.def</a>
*/
public String getStructureName();
public enum SwiftDemangledBuiltinType {
//@formatter:off
/**
* Gets a short description of the {@link SwiftStructure}
*
* @return A short description of the {@link SwiftStructure}
*/
public String getDescription();
Int1,
Word,
RawPointer,
Unsupported
//@formatter:on
}

View file

@ -0,0 +1,94 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.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
}

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,57 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.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()));
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,87 @@
/* ###
* 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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.Demangled;
import ghidra.app.util.demangler.DemangledException;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.datatypes.SwiftFunction;
import ghidra.program.model.lang.CompilerSpec;
/**
* A {@link SwiftDemangledNodeKind#Allocator} {@link SwiftNode}
*/
public class SwiftAllocatorNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
String name = null;
Demangled namespace = null;
Demangled type = null;
Demangled labelList = null;
String callingConvention = CompilerSpec.CALLING_CONVENTION_default;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Class:
namespace = child.demangle(demangler, typeMetadata);
name = "__allocating_init";
callingConvention = CompilerSpec.CALLING_CONVENTION_thiscall;
break;
case Extension:
namespace = child.demangle(demangler, typeMetadata);
if (child.hasChild(SwiftDemangledNodeKind.Class)) {
name = "__allocating_init";
callingConvention = CompilerSpec.CALLING_CONVENTION_thiscall;
}
else if (child.hasChild(SwiftDemangledNodeKind.Protocol) ||
child.hasChild(SwiftDemangledNodeKind.Structure)) {
name = "init";
}
else {
return getUnknown();
}
break;
case Enum:
case Protocol:
case Structure:
namespace = child.demangle(demangler, typeMetadata);
name = "init";
break;
case Type:
type = child.demangle(demangler, typeMetadata);
break;
case LabelList:
labelList = child.demangle(demangler, typeMetadata);
break;
default:
skip(child);
break;
}
}
if (name == null) {
return getUnknown();
}
SwiftFunction function = new SwiftFunction(properties.mangled(),
properties.originalDemangled(), name, namespace, callingConvention);
if (type instanceof SwiftFunction functionType) {
function.setType(functionType, labelList);
}
return function;
}
}

View file

@ -0,0 +1,71 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.demangler.swift.nodes;
import java.util.stream.Collectors;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.datatypes.SwiftArray;
/**
* A {@link SwiftDemangledNodeKind#BoundGenericStructure} {@link SwiftNode}
*/
public class SwiftBoundGenericStructureNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
Demangled type = null;
Demangled typeList = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Type:
type = child.demangle(demangler, typeMetadata);
break;
case TypeList:
typeList = child.demangle(demangler, typeMetadata);
break;
default:
skip(child);
break;
}
}
if (type instanceof SwiftArray arr) {
if (typeList instanceof DemangledList list && !list.isEmpty()) {
Demangled first = list.get(0);
if (first instanceof DemangledDataType ddt) {
arr.setBoundType(ddt);
}
}
return arr;
}
if (typeList instanceof DemangledList list) {
String typeNames = list
.stream()
.map(e -> e.getName())
.collect(Collectors.joining(","));
type.setName("%s<%s>".formatted(type.getName(), typeNames));
return type;
}
return getUnknown();
}
}

View file

@ -0,0 +1,49 @@
/* ###
* 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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.Demangled;
import ghidra.app.util.demangler.DemangledDataType;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
/**
* A {@link SwiftDemangledNodeKind#BuiltinTypeName} {@link SwiftNode}
*/
public class SwiftBuiltinTypeNameNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata) {
String orig = getText();
String name = switch (orig) {
case "Builtin.Int1":
yield DemangledDataType.INT8;
case "Builtin.Word":
yield DemangledDataType.INT16;
case "Builtin.RawPointer":
yield DemangledDataType.VOID;
default:
yield orig;
};
DemangledDataType type =
new DemangledDataType(properties.mangled(), properties.originalDemangled(), name);
if (orig.equals("Builtin.RawPointer")) {
type.incrementPointerLevels();
}
return type;
}
}

View file

@ -0,0 +1,64 @@
/* ###
* 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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
/**
* A {@link SwiftDemangledNodeKind#Class} {@link SwiftNode}
*/
public class SwiftClassNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
String name = null;
Demangled namespace = null;
Demangled privateDeclNamespace = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Identifier:
name = child.getText();
break;
case PrivateDeclName:
Demangled temp = child.demangle(demangler, typeMetadata);
name = temp.getName();
privateDeclNamespace = temp.getNamespace();
break;
case Class:
case Module:
case Structure:
namespace = child.demangle(demangler, typeMetadata);
break;
default:
skip(child);
break;
}
}
if (name == null) {
return getUnknown();
}
DemangledDataType type =
new DemangledDataType(properties.mangled(), properties.originalDemangled(), name);
type.setNamespace(SwiftNode.join(namespace, privateDeclNamespace));
type.setClass();
type.incrementPointerLevels();
return type;
}
}

View file

@ -0,0 +1,65 @@
/* ###
* 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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.datatypes.SwiftFunction;
import ghidra.program.model.lang.CompilerSpec;
/**
* A {@link SwiftDemangledNodeKind#Constructor} {@link SwiftNode}
*/
public class SwiftConstructorNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
String name = null;
Demangled namespace = null;
Demangled type = null;
Demangled labelList = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Class:
namespace = child.demangle(demangler, typeMetadata);
name = "init";
break;
case Type:
type = child.demangle(demangler, typeMetadata);
break;
case LabelList:
labelList = child.demangle(demangler, typeMetadata);
break;
default:
skip(child);
break;
}
}
if (name == null) {
return getUnknown();
}
SwiftFunction function =
new SwiftFunction(properties.mangled(), properties.originalDemangled(), name, namespace,
CompilerSpec.CALLING_CONVENTION_thiscall);
if (type instanceof DemangledFunction functionType) {
function.setType(functionType, labelList);
}
return function;
}
}

View file

@ -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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.Demangled;
import ghidra.app.util.demangler.DemangledException;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.datatypes.SwiftFunction;
import ghidra.program.model.lang.CompilerSpec;
/**
* A {@link SwiftDemangledNodeKind#Deallocator} {@link SwiftNode}
*/
public class SwiftDeallocatorNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
String name = null;
Demangled namespace = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Class:
namespace = child.demangle(demangler, typeMetadata);
name = "__deallocating_init";
break;
default:
skip(child);
break;
}
}
if (name == null) {
return getUnknown();
}
return new SwiftFunction(properties.mangled(), properties.originalDemangled(), name,
namespace, CompilerSpec.CALLING_CONVENTION_thiscall);
}
}

View file

@ -0,0 +1,35 @@
/* ###
* 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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.Demangled;
import ghidra.app.util.demangler.DemangledDataType;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
/**
* A {@link SwiftDemangledNodeKind#DependentGenericParamType} {@link SwiftNode}
*/
public class SwiftDependentGenericParamTypeNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata) {
// We don't really support this yet
return new DemangledDataType(properties.mangled(), properties.originalDemangled(),
DemangledDataType.UNDEFINED);
}
}

View file

@ -0,0 +1,45 @@
/* ###
* 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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.Demangled;
import ghidra.app.util.demangler.DemangledException;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
/**
* A {@link SwiftDemangledNodeKind#DependentGenericType} {@link SwiftNode}
*/
public class SwiftDependentGenericTypeNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
Demangled type = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Type:
type = child.demangle(demangler, typeMetadata);
break;
default:
skip(child);
break;
}
}
return type;
}
}

View file

@ -0,0 +1,57 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.demangler.swift.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.datatypes.SwiftFunction;
import ghidra.program.model.lang.CompilerSpec;
/**
* A {@link SwiftDemangledNodeKind#Destructor} {@link SwiftNode}
*/
public class SwiftDestructorNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
String name = null;
Demangled namespace = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Class:
namespace = child.demangle(demangler, typeMetadata);
name = "deinit";
break;
default:
skip(child);
break;
}
}
if (name == null) {
return getUnknown();
}
SwiftFunction function =
new SwiftFunction(properties.mangled(), properties.originalDemangled(), name, namespace,
CompilerSpec.CALLING_CONVENTION_thiscall);
if (namespace instanceof DemangledDataType type) {
function.setReturnType(type);
}
return function;
}
}

View file

@ -0,0 +1,63 @@
/* ###
* 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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.Demangled;
import ghidra.app.util.demangler.DemangledException;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.datatypes.SwiftEnum;
/**
* A {@link SwiftDemangledNodeKind#Enum} {@link SwiftNode}
*/
public class SwiftEnumNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
String name = null;
Demangled namespace = null;
Demangled privateDeclNamespace = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Identifier:
name = child.getText();
break;
case PrivateDeclName:
Demangled temp = child.demangle(demangler, typeMetadata);
name = temp.getName();
privateDeclNamespace = temp.getNamespace();
break;
case Class:
case Extension:
case Module:
case Structure:
namespace = child.demangle(demangler, typeMetadata);
break;
default:
skip(child);
break;
}
}
if (name == null) {
return getUnknown();
}
return new SwiftEnum(properties.mangled(), properties.originalDemangled(), name,
SwiftNode.join(namespace, privateDeclNamespace), typeMetadata, demangler);
}
}

View file

@ -0,0 +1,63 @@
/* ###
* 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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.Demangled;
import ghidra.app.util.demangler.DemangledException;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
/**
* A {@link SwiftDemangledNodeKind#Extension} {@link SwiftNode}
*/
public class SwiftExtensionNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
Demangled namespace = null;
Demangled type = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Module:
namespace = child.demangle(demangler, typeMetadata);
namespace.setName("(extension_" + namespace.getName() + ")");
break;
case Class:
case Enum:
case Protocol:
case Structure:
type = child.demangle(demangler, typeMetadata);
break;
default:
skip(child);
break;
}
}
if (type == null || namespace == null) {
return getUnknown();
}
Demangled typeNamespace = type.getNamespace();
if (typeNamespace != null) {
typeNamespace.setNamespace(namespace);
}
else {
type.setNamespace(namespace);
}
return type;
}
}

View file

@ -0,0 +1,81 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.demangler.swift.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.datatypes.SwiftFunction;
import ghidra.program.model.lang.CompilerSpec;
/**
* A {@link SwiftDemangledNodeKind#Function} {@link SwiftNode}
*/
public class SwiftFunctionNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
String name = null;
Demangled namespace = null;
Demangled type = null;
Demangled labelList = null;
String callingConvention = CompilerSpec.CALLING_CONVENTION_default;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Identifier:
name = child.getText();
break;
case InfixOperator:
name = child.getText() + " infix";
break;
case LocalDeclName:
name = child.demangle(demangler, typeMetadata).getName();
break;
case Class:
callingConvention = CompilerSpec.CALLING_CONVENTION_thiscall;
// Fall through
case Enum:
case Extension:
case Function:
case Module:
case Protocol:
case Structure:
namespace = child.demangle(demangler, typeMetadata);
break;
case Type:
type = child.demangle(demangler, typeMetadata);
break;
case LabelList:
labelList = child.demangle(demangler, typeMetadata);
break;
default:
skip(child);
break;
}
}
if (name == null) {
return getUnknown();
}
SwiftFunction function = new SwiftFunction(properties.mangled(),
properties.originalDemangled(), name, namespace, callingConvention);
if (type instanceof DemangledFunction functionType) {
function.setType(functionType, labelList);
}
return function;
}
}

View file

@ -0,0 +1,104 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.demangler.swift.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.datatypes.*;
import ghidra.program.model.lang.CompilerSpec;
/**
* A {@link SwiftDemangledNodeKind#FunctionType} {@link SwiftNode}
*/
public class SwiftFunctionTypeNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
Demangled argumentTuple = null;
Demangled returnType = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case ArgumentTuple:
argumentTuple = child.demangle(demangler, typeMetadata);
break;
case ReturnType:
returnType = child.demangle(demangler, typeMetadata);
break;
default:
skip(child);
break;
}
}
SwiftFunction function =
new SwiftFunction(properties.mangled(), properties.originalDemangled(), "<unknown>",
null, CompilerSpec.CALLING_CONVENTION_default);
// Parameters
function.addParameters(SwiftDataTypeUtils.extractParameters(argumentTuple));
// Seems like when calling a struct (or enum) method, the "this" struct is passed after the
// explicit parameters
SwiftNode functionAncestor =
getFirstAncestor(SwiftDemangledNodeKind.Function, SwiftDemangledNodeKind.Getter);
if (functionAncestor != null) {
if (functionAncestor.getKind().equals(SwiftDemangledNodeKind.Getter)) {
functionAncestor = functionAncestor.getChildren().get(0);
}
SwiftNode struct = functionAncestor.getChild(SwiftDemangledNodeKind.Structure);
SwiftNode enumm = functionAncestor.getChild(SwiftDemangledNodeKind.Enum);
if (struct != null) {
if (struct.demangle(demangler, typeMetadata) instanceof DemangledDataType type) {
function.addParameter(new DemangledParameter(type));
}
}
else if (enumm != null) {
if (enumm.demangle(demangler, typeMetadata) instanceof DemangledDataType type) {
function.addParameter(new DemangledParameter(type));
// Enums are currently represented as single field structures, but in reality,
// there could be more fields. Add a varargs parameter so these other fields
// can show up in the decompiler.
DemangledDataType varargs = new DemangledDataType(properties.mangled(),
properties.originalDemangled(), DemangledDataType.UNDEFINED);
varargs.setVarArgs();
function.addParameter(new DemangledParameter(varargs));
}
}
}
// Return type
if (returnType instanceof DemangledDataType type) {
function.setReturnType(type);
}
else if (returnType instanceof DemangledList list && list.size() > 0) {
if (list.containsNull()) {
DemangledDataType dt = new DemangledDataType(properties.mangled(),
properties.originalDemangled(), DemangledDataType.UNDEFINED);
dt.incrementPointerLevels();
function.setReturnType(dt);
}
else {
SwiftTuple tuple = new SwiftTuple(properties.mangled(),
properties.originalDemangled(), list, typeMetadata, demangler);
function.setReturnType(tuple);
}
}
return function;
}
}

View file

@ -0,0 +1,68 @@
/* ###
* 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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.datatypes.SwiftDataTypeUtils;
import ghidra.app.util.demangler.swift.datatypes.SwiftFunction;
import ghidra.program.model.lang.CompilerSpec;
/**
* A {@link SwiftDemangledNodeKind#Getter} {@link SwiftNode}
*/
public class SwiftGetterNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
Demangled demangled = null;
String name = "get_";
String callingConvention = CompilerSpec.CALLING_CONVENTION_default;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Subscript:
demangled = child.demangle(demangler, typeMetadata);
break;
case Variable:
demangled = child.demangle(demangler, typeMetadata);
if (child.hasChild(SwiftDemangledNodeKind.Class)) {
callingConvention = CompilerSpec.CALLING_CONVENTION_thiscall;
}
break;
default:
skip(child);
break;
}
}
if (demangled instanceof DemangledFunction function) {
function.setName(name + function.getName());
function.setCallingConvention(callingConvention);
return function;
}
if (demangled instanceof DemangledVariable variable) {
SwiftFunction function =
new SwiftFunction(properties.mangled(), properties.originalDemangled(),
name + variable.getName(), variable.getNamespace(), callingConvention);
function.addParameters(SwiftDataTypeUtils.extractParameters(variable.getNamespace()));
function.setReturnType(variable.getDataType());
return function;
}
return getUnknown();
}
}

View file

@ -0,0 +1,60 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.demangler.swift.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.Demangled;
import ghidra.app.util.demangler.DemangledException;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.datatypes.SwiftPrimitive;
import ghidra.program.model.data.DataUtilities;
/**
* A {@link SwiftDemangledNodeKind#Global} {@link SwiftNode}
*/
public class SwiftGlobalNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
Demangled demangled = null;
Demangled suffix = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case GenericSpecialization:
case MergedFunction:
case ObjCAttribute:
continue;
case Suffix:
suffix = child.demangle(demangler, typeMetadata);
break;
default:
demangled = child.demangle(demangler, typeMetadata);
break;
}
}
if (demangled == null) {
return getUnknown();
}
if (suffix != null && !(demangled instanceof SwiftPrimitive) &&
DataUtilities.isValidDataTypeName(suffix.getName())) {
// Some suffix names aren't renderable, so validate them
demangled.setName(demangled.getName() + suffix.getName());
}
return demangled;
}
}

View file

@ -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.nodes;
import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
/**
* A {@link SwiftDemangledNodeKind#GlobalVariableOnceDeclList} {@link SwiftNode}
*/
public class SwiftGlobalVariableOnceDeclListNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
List<Demangled> elements = new ArrayList<>();
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Identifier:
elements.add(child.demangle(demangler, typeMetadata));
break;
default:
skip(child);
break;
}
}
return new DemangledList(elements);
}
}

View file

@ -0,0 +1,63 @@
/* ###
* 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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.datatypes.SwiftFunction;
import ghidra.program.model.lang.CompilerSpec;
/**
* A {@link SwiftDemangledNodeKind#GlobalVariableOnceFunction} {@link SwiftNode}
*/
public class SwiftGlobalVariableOnceFunctionNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
Demangled namespace = null;
DemangledList names = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case GlobalVariableOnceDeclList:
Demangled demangled = child.demangle(demangler, typeMetadata);
if (demangled instanceof DemangledList list) {
names = list;
}
break;
case Structure:
namespace = child.demangle(demangler, typeMetadata);
break;
default:
skip(child);
break;
}
}
StringBuilder name = new StringBuilder("one_time_init");
if (names != null) {
if (!names.isEmpty()) {
name.append("_for");
}
for (Demangled entry : names) {
name.append("_" + entry.getDemangledName());
}
}
return new SwiftFunction(properties.mangled(), properties.originalDemangled(),
name.toString(), namespace, CompilerSpec.CALLING_CONVENTION_default);
}
}

View file

@ -0,0 +1,37 @@
/* ###
* 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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
/**
* A {@link SwiftDemangledNodeKind#InOut} {@link SwiftNode}
*/
public class SwiftInOutNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
Demangled demangled = demangleFirstChild(demangler, typeMetadata);
if (demangled instanceof DemangledDataType type) {
type.incrementPointerLevels();
}
return demangled;
}
}

View file

@ -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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.Demangled;
import ghidra.app.util.demangler.DemangledException;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.datatypes.SwiftFunction;
import ghidra.program.model.lang.CompilerSpec;
/**
* A {@link SwiftDemangledNodeKind#Initializer} {@link SwiftNode}
*/
public class SwiftInitializerNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
String name = null;
Demangled namespace = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Variable:
namespace = child.demangle(demangler, typeMetadata);
name = "init";
break;
default:
skip(child);
break;
}
}
if (name == null) {
return getUnknown();
}
return new SwiftFunction(properties.mangled(), properties.originalDemangled(), name,
namespace, CompilerSpec.CALLING_CONVENTION_default);
}
}

View file

@ -0,0 +1,51 @@
/* ###
* 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.nodes;
import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
/**
* A {@link SwiftDemangledNodeKind#LabelList} {@link SwiftNode}
*/
public class SwiftLabelListNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
List<Demangled> elements = new ArrayList<>();
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Identifier:
elements.add(child.demangle(demangler, typeMetadata));
break;
case FirstElementMarker:
elements.add(new DemangledUnknown(properties.mangled(),
properties.originalDemangled(), ""));
break;
default:
skip(child);
break;
}
}
return new DemangledList(elements);
}
}

View file

@ -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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.Demangled;
import ghidra.app.util.demangler.DemangledException;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.datatypes.SwiftFunction;
import ghidra.program.model.lang.CompilerSpec;
/**
* A {@link SwiftDemangledNodeKind#LazyProtocolWitnessTableAccessor} {@link SwiftNode}
*/
public class SwiftLazyProtocolWitnessTableAccessorNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
String name = null;
Demangled namespace = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Type:
namespace = child.demangle(demangler, typeMetadata);
name = "lazy_protocol_witness_table_accessor";
break;
default:
skip(child);
break;
}
}
if (name == null) {
return getUnknown();
}
return new SwiftFunction(properties.mangled(), properties.originalDemangled(), name,
namespace, CompilerSpec.CALLING_CONVENTION_default);
}
}

View file

@ -0,0 +1,59 @@
/* ###
* 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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
/**
* A {@link SwiftDemangledNodeKind#LocalDeclName} {@link SwiftNode}
*/
public class SwiftLocalDeclNameNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
String name = null;
Long number = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Identifier:
name = child.getText();
break;
case Number:
try {
number = Long.decode(child.getIndex());
}
catch (NumberFormatException e) {
throw new DemangledException(e);
}
break;
default:
skip(child);
break;
}
}
if (name == null) {
return getUnknown();
}
if (number != null) {
name += "#" + (number + 1);
}
return new DemangledLabel(properties.mangled(), properties.originalDemangled(), name);
}
}

View file

@ -0,0 +1,64 @@
/* ###
* 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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.datatypes.SwiftDataTypeUtils;
import ghidra.app.util.demangler.swift.datatypes.SwiftFunction;
import ghidra.program.model.lang.CompilerSpec;
/**
* A {@link SwiftDemangledNodeKind#ModifyAccessor} {@link SwiftNode}
*/
public class SwiftModifyAccessorNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
Demangled demangled = null;
String name = "modify_";
String callingConvention = CompilerSpec.CALLING_CONVENTION_thiscall;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Subscript:
demangled = child.demangle(demangler, typeMetadata);
break;
case Variable:
demangled = child.demangle(demangler, typeMetadata);
break;
default:
skip(child);
break;
}
}
if (demangled instanceof DemangledFunction function) {
function.setName(name + function.getName());
function.setCallingConvention(callingConvention);
return function;
}
if (demangled instanceof DemangledVariable variable) {
SwiftFunction function =
new SwiftFunction(properties.mangled(), properties.originalDemangled(),
name + variable.getName(), variable.getNamespace(), callingConvention);
function.addParameters(SwiftDataTypeUtils.extractParameters(variable));
return function;
}
return getUnknown();
}
}

View file

@ -0,0 +1,378 @@
/* ###
* 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.nodes;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.nodes.generic.*;
/**
* A single Swift demangled symbol tree node
*/
public abstract class SwiftNode {
protected NodeProperties properties;
private SwiftNode parent;
private List<SwiftNode> children = new ArrayList<>();
private boolean childSkipped = false;
/**
* Represents {@link SwiftNode} properties
*
* @param kind The {@link SwiftDemangledNodeKind kind} of {@link SwiftNode}
* @param text The text attribute, or null if it does not exist
* @param index The index attribute, or null if it does not exist
* @param depth The depth of the {@link SwiftNode} in the demangled symbol tree (root depth is
* 0)
* @param mangled The mangled string associated with this {@link SwiftNode}
* @param originalDemangled The natively demangled string
*/
public record NodeProperties(SwiftDemangledNodeKind kind, String text, String index,
int depth, String mangled, String originalDemangled) {}
/**
* Gets a new {@link SwiftNode} with the given with the given {@link NodeProperties}
*
* @param props The {@link NodeProperties}
* @return A {@link SwiftNode} with the given {@link NodeProperties}
*/
public static SwiftNode get(NodeProperties props) {
SwiftNode node = switch (props.kind()) {
case Allocator -> new SwiftAllocatorNode();
case AnonymousDescriptor -> new SwiftGenericDescriptorNode();
case ArgumentTuple -> new SwiftGenericPassthroughNode();
case BoundGenericStructure -> new SwiftBoundGenericStructureNode();
case BuiltinTypeName -> new SwiftBuiltinTypeNameNode();
case Class -> new SwiftClassNode();
case Constructor -> new SwiftConstructorNode();
case Deallocator -> new SwiftDeallocatorNode();
case DefaultArgumentInitializer -> new SwiftGenericPassthroughNode();
case DependentGenericParamType -> new SwiftDependentGenericParamTypeNode();
case DependentGenericType -> new SwiftDependentGenericTypeNode();
case Destructor -> new SwiftDestructorNode();
case DispatchThunk -> new SwiftGenericPassthroughNode();
case Enum -> new SwiftEnumNode();
case Extension -> new ghidra.app.util.demangler.swift.nodes.SwiftExtensionNode();
case Function -> new SwiftFunctionNode();
case FunctionType -> new SwiftFunctionTypeNode();
case GenericSpecialization -> new SwiftGenericTextNode();
case Getter -> new SwiftGetterNode();
case Global -> new SwiftGlobalNode();
case GlobalVariableOnceDeclList -> new SwiftGlobalVariableOnceDeclListNode();
case GlobalVariableOnceFunction -> new SwiftGlobalVariableOnceFunctionNode();
case Identifier -> new SwiftGenericTextNode();
case InfixOperator -> new SwiftGenericTextNode();
case Initializer -> new SwiftInitializerNode();
case InOut -> new SwiftInOutNode();
case LabelList -> new SwiftLabelListNode();
case LazyProtocolWitnessTableAccessor -> new SwiftLazyProtocolWitnessTableAccessorNode();
case LocalDeclName -> new SwiftLocalDeclNameNode();
case MergedFunction -> new SwiftGenericPassthroughNode();
case ModifyAccessor -> new SwiftModifyAccessorNode();
case Module -> new SwiftGenericTextNode();
case ModuleDescriptor -> new SwiftGenericDescriptorNode();
case NominalTypeDescriptor -> new SwiftGenericDescriptorNode();
case Number -> new SwiftGenericIndexNode();
case ObjCAttribute -> new SwiftGenericTextNode();
case OutlinedConsume -> new SwiftOutlinedConsumeNode();
case OutlinedCopy -> new SwiftOutlinedCopyNode();
case Owned -> new SwiftGenericPassthroughNode();
case PrivateDeclName -> new SwiftPrivateDeclNameNode();
case Protocol -> new SwiftProtocolNode();
case ProtocolConformance -> new SwiftProtocolConformanceNode();
case ProtocolConformanceDescriptor -> new SwiftGenericDescriptorNode();
case ProtocolDescriptor -> new SwiftGenericDescriptorNode();
case ProtocolWitness -> new SwiftGenericPassthroughNode();
case ReflectionMetadataBuiltinDescriptor -> new SwiftGenericDescriptorNode();
case ReflectionMetadataFieldDescriptor -> new SwiftGenericDescriptorNode();
case ReturnType -> new SwiftGenericPassthroughNode();
case Setter -> new SwiftSetterNode();
case Static -> new SwiftGenericPassthroughNode();
case Structure -> new SwiftStructureNode();
case Subscript -> new SwiftSubscriptNode();
case Suffix -> new SwiftGenericTextNode();
case Tuple -> new SwiftTupleNode();
case TupleElement -> new SwiftTupleElementNode();
case TupleElementName -> new SwiftGenericTextNode();
case Type -> new SwiftTypeNode();
case TypeAlias -> new SwiftTypeAliasNode();
case TypeList -> new SwiftTypeListNode();
case TypeMetadataAccessFunction -> new SwiftTypeMetadataAccessFunctionNode();
case UnsafeMutableAddressor -> new SwiftUnsafeMutableAddressorNode();
case Variable -> new SwiftVariableNode();
default -> new SwiftUnsupportedNode(props.kind().toString(), props);
};
node.properties = props;
return node;
}
/**
* Demangles this {@link SwiftNode}
*
* @param demangler The {@link SwiftDemangler}
* @param typeMetadata The {@link SwiftTypeMetadata}, or null if it is not known
* @return The demangled {@link SwiftNode}
* @throws DemangledException if a problem occurred
*/
public abstract Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException;
/**
* Gets the {@link SwiftDemangledNodeKind kind} of {@link SwiftNode}
*
* @return The {@link SwiftDemangledNodeKind kind} of {@link SwiftNode}
*/
public SwiftDemangledNodeKind getKind() {
return properties.kind();
}
/**
* Gets the "text" property
*
* @return The "text" attribute, or null if it does not exist
*/
public String getText() {
return properties.text();
}
/**
* Gets the "index" property
*
* @return The "index" attribute, or null if it does not exist
*/
public String getIndex() {
return properties.index();
}
/**
* Gets the depth of the {@link SwiftNode} in the demangled symbol tree (root depth is 0)
*
* @return The depth of the {@link SwiftNode} in the demangled symbol tree (root depth is 0)
*/
public int getDepth() {
return properties.depth();
}
/**
* Gets the parent {@link SwiftNode}
*
* @return The parent {@link SwiftNode}, or null if this is the root {@link SwiftNode}
*/
public SwiftNode getParent() {
return parent;
}
/**
* Sets the parent {@link SwiftNode}
*
* @param parent The parent {@link SwiftNode}
*/
public void setParent(SwiftNode parent) {
this.parent = parent;
}
/**
* Gets the {@link List} of child {@link SwiftNode}s
*
* @return The {@link List} of child {@link SwiftNode} (original, not a copy)
*/
public List<SwiftNode> getChildren() {
return children;
}
/**
* Walks down the tree rooted at this {@link SwiftNode}, returning true if the given condition
* is met on any {@link SwiftNode} encountered
*
* @param predicate The condition to test for
* @return True if the given condition is true on any {@link SwiftNode} encountered; otherwise,
* false
*/
public boolean walkAndTest(Predicate<SwiftNode> predicate) {
if (predicate.test(this)) {
return true;
}
for (SwiftNode child : children) {
if (child.walkAndTest(predicate)) {
return true;
}
}
return false;
}
/**
* Checks to see if the {@link SwiftNode} has any direct children of the given
* {@link SwiftDemangledNodeKind kind}
*
* @param childKind The {@link SwiftDemangledNodeKind kind} of child to check for
* @return True if the {@link SwiftNode} has any direct children of the given
* {@link SwiftDemangledNodeKind kind}; otherwise false
*/
public boolean hasChild(SwiftDemangledNodeKind childKind) {
return children.stream().anyMatch(child -> child.getKind().equals(childKind));
}
/**
* Gets the first direct child {@link SwiftNode} of the given
* {@link SwiftDemangledNodeKind kind}
*
* @param childKind The {@link SwiftDemangledNodeKind kind} of child to get
* @return The first direct child {@link SwiftNode} of the given
* {@link SwiftDemangledNodeKind kind}, or null if one could not be found
*/
public SwiftNode getChild(SwiftDemangledNodeKind childKind) {
return children.stream()
.filter(child -> child.getKind().equals(childKind))
.findFirst()
.orElse(null);
}
/**
* Gets the first ancestor {@link SwiftNode} of the given kind(s)
*
* @param ancestorKinds The ancestor kinds
* @return The first ancestor {@link SwiftNode} of the given kind
*/
public SwiftNode getFirstAncestor(SwiftDemangledNodeKind... ancestorKinds) {
if (ancestorKinds != null && ancestorKinds.length > 0) {
for (SwiftNode p = parent; p != null; p = p.getParent()) {
for (SwiftDemangledNodeKind ancestorKind : ancestorKinds) {
if (p.getKind().equals(ancestorKind)) {
return p;
}
}
}
}
return null;
}
/**
* Called when this {@link SwiftNode} skipped processing a child during the demangling process.
* Used to identify and/or debug missing implementations.
*
* @param child The skipped child {@link SwiftNode}
*/
public void skip(SwiftNode child) {
childSkipped = true;
}
/**
* Returns whether or not this {@link SwiftNode} skipped processing any children during the
* demangling process
*
* @return True if a child {@link SwiftNode} was skipped; otherwise, false
*/
public boolean childWasSkipped() {
return childSkipped;
}
/**
* Gets a new {@link DemangledUnknown} created from this {@link SwiftNode}
*
* @return A new {@link DemangledUnknown} created from this {@link SwiftNode}
*/
public DemangledUnknown getUnknown() {
return new DemangledUnknown(properties.mangled(), properties.originalDemangled(),
properties.originalDemangled());
}
/**
* Joins the first {@link Demangled} with the second. The name of the first will become the
* top-level namespace of the second.
*
* @param a The first {@link Demangled} to join
* @param b The second {@link Demangled} to join
* @return The joined {@link Demangled}s
*/
public static Demangled join(Demangled a, Demangled b) {
if (a == null) {
return b;
}
if (b == null) {
return a;
}
Demangled topNamespace = b;
while (topNamespace.getNamespace() != null) {
topNamespace = topNamespace.getNamespace();
}
topNamespace.setNamespace(a);
return b;
}
/**
* Converts the given {@link SwiftNode} to a string
*
* @param node The {@link SwiftNode} to convert to a string
* @param recurse True if the {@link SwiftNode} should be recursed; otherwise, false
* @return The given {@link SwiftNode} in string form
*/
public static String toString(SwiftNode node, boolean recurse) {
StringBuilder sb = new StringBuilder(node.toString());
if (recurse) {
sb.append("\n");
for (SwiftNode child : node.getChildren()) {
sb.append(toString(child, true));
}
}
return sb.toString();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(" ".repeat(properties.depth() * 2));
sb.append("kind=" + properties.kind());
if (properties.text() != null) {
sb.append(", text=\"" + properties.text() + "\"");
}
if (properties.index() != null) {
sb.append(", index=" + properties.index() + "");
}
return sb.toString();
}
/**
* Demangles the first child {@link SwiftNode}, if it exists
*
* @param demangler The {@link SwiftDemangler}
* @param typeMetadata The {@link SwiftTypeMetadata}, or null if it is not known
* @return The demangled first child {@link SwiftNode}
* @throws DemangledException if there are no children or another problem occurred
*/
protected Demangled demangleFirstChild(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
Demangled first = null;
for (int i = 0; i < children.size(); i++) {
SwiftNode child = children.get(i);
if (i == 0) {
first = child.demangle(demangler, typeMetadata);
}
else {
child.skip(child);
}
}
if (first == null) {
throw new DemangledException("No children");
}
return first;
}
}

View file

@ -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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.datatypes.SwiftFunction;
import ghidra.program.model.lang.CompilerSpec;
/**
* A {@link SwiftDemangledNodeKind#OutlinedConsume} {@link SwiftNode}
*/
public class SwiftOutlinedConsumeNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
Demangled type = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Type:
type = child.demangle(demangler, typeMetadata);
break;
default:
skip(child);
break;
}
}
SwiftFunction function =
new SwiftFunction(properties.mangled(), properties.originalDemangled(),
"outlined_consume", null, CompilerSpec.CALLING_CONVENTION_default);
if (type instanceof DemangledDataType dt) {
function.addParameter(new DemangledParameter(dt));
}
return function;
}
}

View file

@ -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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.datatypes.SwiftFunction;
import ghidra.program.model.lang.CompilerSpec;
/**
* A {@link SwiftDemangledNodeKind#OutlinedCopy} {@link SwiftNode}
*/
public class SwiftOutlinedCopyNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
Demangled type = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Type:
type = child.demangle(demangler, typeMetadata);
break;
default:
skip(child);
break;
}
}
SwiftFunction function =
new SwiftFunction(properties.mangled(), properties.originalDemangled(),
"outlined_copy", null, CompilerSpec.CALLING_CONVENTION_default);
if (type instanceof DemangledDataType dt) {
function.addParameter(new DemangledParameter(dt));
}
return function;
}
}

View file

@ -0,0 +1,61 @@
/* ###
* 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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
/**
* A {@link SwiftDemangledNodeKind#PrivateDeclName} {@link SwiftNode}
*/
public class SwiftPrivateDeclNameNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
String name = null;
Demangled namespace = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Identifier:
if (namespace == null) {
namespace = child.demangle(demangler, typeMetadata);
}
else {
name = child.getText();
}
break;
default:
skip(child);
break;
}
}
if (name == null) {
if (namespace == null) {
return getUnknown();
}
name = namespace.getNamespace().getName();
namespace = null;
}
DemangledUnknown demangled =
new DemangledUnknown(properties.mangled(), properties.originalDemangled(), name);
demangled.setNamespace(namespace);
return demangled;
}
}

View file

@ -0,0 +1,60 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.demangler.swift.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
/**
* A {@link SwiftDemangledNodeKind#ProtocolConformance} {@link SwiftNode}
*/
public class SwiftProtocolConformanceNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
Demangled type1 = null;
Demangled type2 = null;
Demangled namespace = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Module:
namespace = child.demangle(demangler, typeMetadata);
break;
case Type:
if (type1 == null) {
type1 = child.demangle(demangler, typeMetadata);
}
else {
type2 = child.demangle(demangler, typeMetadata);
}
break;
default:
skip(child);
break;
}
}
if (type1 == null && type2 == null) {
return getUnknown();
}
DemangledUnknown demangled = new DemangledUnknown(properties.mangled(),
properties.originalDemangled(), SwiftNode.join(type2, type1).getNamespaceString());
demangled.setNamespace(namespace);
return demangled;
}
}

View file

@ -0,0 +1,54 @@
/* ###
* 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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
/**
* A {@link SwiftDemangledNodeKind#Protocol} {@link SwiftNode}
*/
public class SwiftProtocolNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
String name = null;
Demangled namespace = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Identifier:
name = child.getText();
break;
case Module:
namespace = child.demangle(demangler, typeMetadata);
break;
default:
skip(child);
break;
}
}
if (name == null) {
return getUnknown();
}
DemangledUnknown demangled =
new DemangledUnknown(properties.mangled(), properties.originalDemangled(), name);
demangled.setNamespace(namespace);
return demangled;
}
}

View file

@ -0,0 +1,64 @@
/* ###
* 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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.datatypes.SwiftDataTypeUtils;
import ghidra.app.util.demangler.swift.datatypes.SwiftFunction;
import ghidra.program.model.lang.CompilerSpec;
/**
* A {@link SwiftDemangledNodeKind#Setter} {@link SwiftNode}
*/
public class SwiftSetterNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
Demangled demangled = null;
String name = "set_";
String callingConvention = CompilerSpec.CALLING_CONVENTION_thiscall;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Subscript:
demangled = child.demangle(demangler, typeMetadata);
break;
case Variable:
demangled = child.demangle(demangler, typeMetadata);
break;
default:
skip(child);
break;
}
}
if (demangled instanceof DemangledFunction function) {
function.setName(name + function.getName());
function.setCallingConvention(callingConvention);
return function;
}
if (demangled instanceof DemangledVariable variable) {
SwiftFunction function =
new SwiftFunction(properties.mangled(), properties.originalDemangled(),
name + variable.getName(), variable.getNamespace(), callingConvention);
function.addParameters(SwiftDataTypeUtils.extractParameters(variable));
return function;
}
return getUnknown();
}
}

View file

@ -0,0 +1,101 @@
/* ###
* 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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.datatypes.*;
/**
* A {@link SwiftDemangledNodeKind#Structure} {@link SwiftNode}
*/
public class SwiftStructureNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
String name = null;
Demangled namespace = null;
Demangled privateDeclNamespace = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Identifier:
name = child.getText();
break;
case PrivateDeclName:
Demangled temp = child.demangle(demangler, typeMetadata);
name = temp.getName();
privateDeclNamespace = temp.getNamespace();
break;
case Class:
case Module:
case Structure:
namespace = child.demangle(demangler, typeMetadata);
break;
default:
skip(child);
break;
}
}
if (name == null) {
return getUnknown();
}
String mangled = properties.mangled();
String orig = properties.originalDemangled();
if (SwiftDataTypeUtils.isSwiftNamespace(namespace)) {
DemangledDataType type = switch (name) {
case "Bool" -> new SwiftPrimitive(mangled, orig, DemangledDataType.BOOL);
case "Int" -> new SwiftPrimitive(mangled, orig, DemangledDataType.INT);
case "Int8" -> new SwiftPrimitive(mangled, orig, DemangledDataType.INT8);
case "Int16" -> new SwiftPrimitive(mangled, orig, DemangledDataType.INT16);
case "Int32" -> new SwiftPrimitive(mangled, orig, DemangledDataType.INT32);
case "Int64" -> new SwiftPrimitive(mangled, orig, DemangledDataType.INT64);
case "UInt" -> new SwiftPrimitive(mangled, orig, DemangledDataType.INT, true);
case "UInt8" -> new SwiftPrimitive(mangled, orig, DemangledDataType.INT8, true);
case "UInt16" -> new SwiftPrimitive(mangled, orig, DemangledDataType.INT16, true);
case "UInt32" -> new SwiftPrimitive(mangled, orig, DemangledDataType.INT32, true);
case "UInt64" -> new SwiftPrimitive(mangled, orig, DemangledDataType.INT64, true);
case "Float" -> new SwiftPrimitive(mangled, orig, DemangledDataType.FLOAT);
case "Float16" -> new SwiftPrimitive(mangled, orig, DemangledDataType.FLOAT2);
case "Double" -> new SwiftPrimitive(mangled, orig, DemangledDataType.DOUBLE);
case "Array" -> new SwiftArray(mangled, orig);
case "Character" -> new SwiftCharacter(mangled, orig);
case "String" -> new SwiftString(mangled, orig);
default -> null;
};
if (type != null) {
return type;
}
}
SwiftStructure struct = new SwiftStructure(mangled, orig, name,
SwiftNode.join(namespace, privateDeclNamespace), typeMetadata, demangler);
// The structure has no fields, which behaves poorly in the decompiler. Give it one
// undefined* field instead.
if (struct.getFields().isEmpty()) {
DemangledDataType undefined =
new DemangledDataType(mangled, orig, DemangledDataType.UNDEFINED);
undefined.incrementPointerLevels();
struct.addField("unknown", null, undefined);
}
return struct;
}
}

View file

@ -0,0 +1,68 @@
/* ###
* 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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.datatypes.SwiftFunction;
import ghidra.program.model.lang.CompilerSpec;
/**
* A {@link SwiftDemangledNodeKind#Subscript} {@link SwiftNode}
*/
public class SwiftSubscriptNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
String name = null;
Demangled namespace = null;
Demangled type = null;
Demangled labelList = null;
String callingConvention = CompilerSpec.CALLING_CONVENTION_default;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Class:
callingConvention = CompilerSpec.CALLING_CONVENTION_thiscall;
// Fall through
case Structure:
namespace = child.demangle(demangler, typeMetadata);
name = "subscript";
break;
case LabelList:
labelList = child.demangle(demangler, typeMetadata);
break;
case Type:
type = child.demangle(demangler, typeMetadata);
break;
default:
skip(child);
break;
}
}
if (name == null) {
return getUnknown();
}
SwiftFunction function = new SwiftFunction(properties.mangled(),
properties.originalDemangled(), name, namespace, callingConvention);
if (type instanceof DemangledFunction functionType) {
function.setType(functionType, labelList);
}
return function;
}
}

View file

@ -0,0 +1,58 @@
/* ###
* 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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
/**
* A {@link SwiftDemangledNodeKind#TupleElement} {@link SwiftNode}
*/
public class SwiftTupleElementNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
Demangled type = null;
String name = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case TupleElementName:
name = child.getText();
break;
case Type:
type = child.demangle(demangler, typeMetadata);
break;
default:
skip(child);
break;
}
}
if (type == null) {
return getUnknown();
}
if (name != null && type instanceof DemangledDataType ddt) {
DemangledVariable variable =
new DemangledVariable(properties.mangled(), properties.originalDemangled(), name);
variable.setDatatype(ddt);
return variable;
}
return type;
}
}

View file

@ -0,0 +1,47 @@
/* ###
* 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.nodes;
import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
/**
* A {@link SwiftDemangledNodeKind#Tuple} {@link SwiftNode}
*/
public class SwiftTupleNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
List<Demangled> elements = new ArrayList<>();
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case TupleElement:
elements.add(child.demangle(demangler, typeMetadata));
break;
default:
skip(child);
break;
}
}
return new DemangledList(elements);
}
}

View file

@ -0,0 +1,56 @@
/* ###
* 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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
/**
* A {@link SwiftDemangledNodeKind#TypeAlias} {@link SwiftNode}
*/
public class SwiftTypeAliasNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
String name = null;
Demangled namespace = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Identifier:
name = child.getText();
break;
case Module:
namespace = child.demangle(demangler, typeMetadata);
break;
default:
skip(child);
break;
}
}
if (name == null) {
return getUnknown();
}
DemangledDataType type =
new DemangledDataType(properties.mangled(), properties.originalDemangled(), name);
type.setNamespace(namespace);
type.setClass();
return type;
}
}

View file

@ -0,0 +1,47 @@
/* ###
* 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.nodes;
import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
/**
* A {@link SwiftDemangledNodeKind#TypeList} {@link SwiftNode}
*/
public class SwiftTypeListNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
List<Demangled> elements = new ArrayList<>();
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Type:
elements.add(child.demangle(demangler, typeMetadata));
break;
default:
skip(child);
break;
}
}
return new DemangledList(elements);
}
}

View file

@ -0,0 +1,58 @@
/* ###
* 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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.datatypes.SwiftFunction;
import ghidra.program.model.lang.CompilerSpec;
/**
* A {@link SwiftDemangledNodeKind#TypeMetadataAccessFunction} {@link SwiftNode}
*/
public class SwiftTypeMetadataAccessFunctionNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
String name = null;
Demangled namespace = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Type:
namespace = child.demangle(demangler, typeMetadata);
name = "typeMetadataAccessor";
break;
default:
skip(child);
break;
}
}
if (name == null) {
return getUnknown();
}
SwiftFunction function =
new SwiftFunction(properties.mangled(), properties.originalDemangled(), name, namespace,
CompilerSpec.CALLING_CONVENTION_default);
if (namespace instanceof DemangledDataType type) {
function.setReturnType(type);
}
return function;
}
}

View file

@ -0,0 +1,34 @@
/* ###
* 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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.Demangled;
import ghidra.app.util.demangler.DemangledException;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
/**
* A {@link SwiftDemangledNodeKind#Type} {@link SwiftNode}
*/
public class SwiftTypeNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
return demangleFirstChild(demangler, typeMetadata);
}
}

View file

@ -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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.Demangled;
import ghidra.app.util.demangler.DemangledException;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.datatypes.SwiftFunction;
import ghidra.program.model.lang.CompilerSpec;
/**
* A {@link SwiftDemangledNodeKind#UnsafeMutableAddressor} {@link SwiftNode}
*/
public class SwiftUnsafeMutableAddressorNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
String name = null;
Demangled namespace = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Variable:
namespace = child.demangle(demangler, typeMetadata);
name = "unsafeMutableAddressor";
break;
default:
skip(child);
break;
}
}
if (name == null) {
return getUnknown();
}
return new SwiftFunction(properties.mangled(), properties.originalDemangled(), name,
namespace, CompilerSpec.CALLING_CONVENTION_default);
}
}

View file

@ -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.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.Demangled;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
/**
* A {@link SwiftDemangledNodeKind#Unsupported} {@link SwiftNode}
*/
public class SwiftUnsupportedNode extends SwiftNode {
private String originalKind;
/**
* Create a new {@link SwiftUnsupportedNode} {@link SwiftNode}
*
* @param originalKind The original {@link SwiftDemangledNodeKind kind} of {@link SwiftNode} that is
* not supported
* @param props The {@link ghidra.app.util.demangler.swift.nodes.SwiftNode.NodeProperties}
*/
public SwiftUnsupportedNode(String originalKind, NodeProperties props) {
this.originalKind = originalKind;
this.properties = props;
}
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata) {
skip(this);
return getUnknown();
}
@Override
public String toString() {
return super.toString() + " (" + originalKind + ")";
}
}

View file

@ -0,0 +1,72 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.demangler.swift.nodes;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangledNodeKind;
import ghidra.app.util.demangler.swift.SwiftDemangler;
/**
* A {@link SwiftDemangledNodeKind#Variable} {@link SwiftNode}
*/
public class SwiftVariableNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
String name = null;
Demangled namespace = null;
Demangled privateDeclNamespace = null;
Demangled type = null;
for (SwiftNode child : getChildren()) {
switch (child.getKind()) {
case Identifier:
name = child.getText();
break;
case PrivateDeclName:
Demangled temp = child.demangle(demangler, typeMetadata);
name = temp.getName();
privateDeclNamespace = temp.getNamespace();
break;
case Class:
case Enum:
case Extension:
case Module:
case Protocol:
case Structure:
namespace = child.demangle(demangler, typeMetadata);
break;
case Type:
type = child.demangle(demangler, typeMetadata);
break;
default:
skip(child);
break;
}
}
if (name == null) {
return getUnknown();
}
DemangledVariable variable =
new DemangledVariable(properties.mangled(), properties.originalDemangled(), name);
if (type instanceof DemangledDataType ddt) {
variable.setDatatype(ddt);
}
variable.setNamespace(SwiftNode.join(namespace, privateDeclNamespace));
return variable;
}
}

View file

@ -0,0 +1,35 @@
/* ###
* 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.nodes.generic;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.nodes.SwiftNode;
/**
* A {@link SwiftNode} to represent a generic descriptor
*/
public class SwiftGenericDescriptorNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
Demangled demangled = demangleFirstChild(demangler, typeMetadata);
return new DemangledLabel(properties.mangled(), properties.originalDemangled(),
demangled.getNamespaceString());
}
}

View file

@ -0,0 +1,34 @@
/* ###
* 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.nodes.generic;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.Demangled;
import ghidra.app.util.demangler.DemangledLabel;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.nodes.SwiftNode;
/**
* A {@link SwiftNode} that just contains an index
*/
public class SwiftGenericIndexNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata) {
return new DemangledLabel(properties.mangled(), properties.originalDemangled(),
getIndex());
}
}

View file

@ -0,0 +1,34 @@
/* ###
* 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.nodes.generic;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.Demangled;
import ghidra.app.util.demangler.DemangledException;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.nodes.SwiftNode;
/**
* A {@link SwiftNode} that simply passes through to its child {@link SwiftNode}
*/
public class SwiftGenericPassthroughNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata)
throws DemangledException {
return demangleFirstChild(demangler, typeMetadata);
}
}

View file

@ -0,0 +1,34 @@
/* ###
* 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.nodes.generic;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
import ghidra.app.util.demangler.Demangled;
import ghidra.app.util.demangler.DemangledLabel;
import ghidra.app.util.demangler.swift.SwiftDemangler;
import ghidra.app.util.demangler.swift.nodes.SwiftNode;
/**
* A {@link SwiftNode} that just contains text
*/
public class SwiftGenericTextNode extends SwiftNode {
@Override
public Demangled demangle(SwiftDemangler demangler, SwiftTypeMetadata typeMetadata) {
return new DemangledLabel(properties.mangled(), properties.originalDemangled(),
getText());
}
}

View file

@ -0,0 +1,705 @@
/* ###
* 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 static org.junit.Assert.*;
import static org.junit.Assume.*;
import java.io.IOException;
import org.junit.Before;
import org.junit.Test;
import generic.test.AbstractGenericTest;
import ghidra.app.util.demangler.DemangledFunction;
import ghidra.app.util.demangler.DemangledStructure;
import ghidra.util.exception.AssertException;
/**
* Unit tests for the {@link SwiftDemangler}. Requires Swift to be installed on the test system.
* If it is not, these tests will be skipped.
*/
public class SwiftDemanglerTest extends AbstractGenericTest {
private SwiftDemangler demangler;
@Before
public void setUp() throws Exception {
demangler = new SwiftDemangler();
// Ghidra does not ship the native Swift demangler binary, so it may not be present to run
// these tests. In this scenario, we just want these tests skipped (as opposed to failing).
try {
new SwiftNativeDemangler(new SwiftDemanglerOptions().getSwiftDir());
}
catch (IOException e) {
assumeNoException(e); // skip test, don't fail
}
}
@Test
public void testFunctionAndTypes() throws Exception {
/*-********************************************************************
kind=Global
kind=Function
kind=Module, text="SwiftDemanglerTest"
kind=Identifier, text="testJunitFunctionAndTypes"
kind=LabelList
kind=FirstElementMarker
kind=Identifier, text="label2"
kind=FirstElementMarker
kind=FirstElementMarker
kind=FirstElementMarker
kind=FirstElementMarker
kind=FirstElementMarker
kind=FirstElementMarker
kind=FirstElementMarker
kind=FirstElementMarker
kind=FirstElementMarker
kind=FirstElementMarker
kind=FirstElementMarker
kind=Identifier, text="label14"
kind=FirstElementMarker
kind=FirstElementMarker
kind=FirstElementMarker
kind=FirstElementMarker
kind=Type
kind=FunctionType
kind=ArgumentTuple
kind=Type
kind=Tuple
kind=TupleElement
kind=Type
kind=InOut
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int8"
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int16"
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int32"
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int64"
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="UInt"
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="UInt8"
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="UInt16"
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="UInt32"
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="UInt64"
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Float"
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Float"
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Double"
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Double"
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="String"
kind=TupleElement
kind=Type
kind=BoundGenericStructure
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Array"
kind=TypeList
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Bool"
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Character"
kind=ReturnType
kind=Type
kind=Tuple
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Float"
SwiftDemanglerTest.testJunitFunctionAndTypes(_: inout Swift.Int, label2: Swift.Int8, _: Swift.Int16, _: Swift.Int32, _: Swift.Int64, _: Swift.UInt, _: Swift.UInt8, _: Swift.UInt16, _: Swift.UInt32, _: Swift.UInt64, _: Swift.Float, _: Swift.Float, _: Swift.Double, label14: Swift.Double, _: Swift.String, _: [Swift.Int], _: Swift.Bool, _: Swift.Character) -> (Swift.Int, Swift.Float)
**********************************************************************/
String mangled =
"_$s18SwiftDemanglerTest25testJunitFunctionAndTypes_6label2___________7label14____Si_SftSiz_s4Int8Vs5Int16Vs5Int32Vs5Int64VSus5UInt8Vs6UInt16Vs6UInt32Vs6UInt64VS2fS2dSSSaySiGSbSJtF";
String demangled =
"struct tuple2 default SwiftDemanglerTest::testJunitFunctionAndTypes(int *,__int8 label2,__int16,__int32,__int64,unsigned int,unsigned __int8,unsigned __int16,unsigned __int32,unsigned __int64,float,float,double,double label14,struct Swift::String,Swift::Array<int>[],bool,struct Swift::Character)";
if (!(demangler.demangle(mangled) instanceof DemangledFunction function)) {
throw new AssertException("Demangled object is not a function");
}
assertEquals(demangled, function.toString());
if (!(function.getReturnType() instanceof DemangledStructure struct)) {
throw new AssertException("Demangled return type is not a structure");
}
assertEquals(struct.getFields().size(), 2);
assertEquals(struct.getFields().get(0).type().toString(), "int");
assertEquals(struct.getFields().get(1).type().toString(), "float");
}
@Test
public void testStructureAllocator() throws Exception {
/*-********************************************************************
kind=Global
kind=Allocator
kind=Structure
kind=Module, text="SwiftDemanglerTest"
kind=Identifier, text="MyStructure"
kind=LabelList
kind=Identifier, text="label1"
kind=Type
kind=FunctionType
kind=ArgumentTuple
kind=Type
kind=Tuple
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
kind=ReturnType
kind=Type
kind=Structure
kind=Module, text="SwiftDemanglerTest"
kind=Identifier, text="MyStructure"
SwiftDemanglerTest.MyStructure.init(label1: Swift.Int) -> SwiftDemanglerTest.MyStructure
**********************************************************************/
String mangled = "_$s18SwiftDemanglerTest11MyStructureV6label1ACSi_tcfC";
String demangled =
"struct SwiftDemanglerTest::MyStructure default SwiftDemanglerTest::MyStructure::init(int label1)";
if (!(demangler.demangle(mangled) instanceof DemangledFunction function)) {
throw new AssertException("Demangled object is not a function");
}
assertEquals(demangled, function.toString());
}
@Test
public void testStructureFunction() throws Exception {
/*-********************************************************************
kind=Global
kind=Function
kind=Structure
kind=Module, text="SwiftDemanglerTest"
kind=Identifier, text="MyStructure"
kind=Identifier, text="myMethod"
kind=LabelList
kind=Identifier, text="label1"
kind=Identifier, text="label2"
kind=Type
kind=FunctionType
kind=ArgumentTuple
kind=Type
kind=Tuple
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
kind=ReturnType
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
SwiftDemanglerTest.MyStructure.myMethod(label1: Swift.Int, label2: Swift.Int) -> Swift.Int
**********************************************************************/
String mangled = "_$s18SwiftDemanglerTest11MyStructureV8myMethod6label16label2S2i_SitF";
String demangled =
"int default SwiftDemanglerTest::MyStructure::myMethod(int label1,int label2,struct SwiftDemanglerTest::MyStructure)";
if (!(demangler.demangle(mangled) instanceof DemangledFunction function)) {
throw new AssertException("Demangled object is not a function");
}
assertEquals(demangled, function.toString());
}
@Test
public void testStructureGetter() throws Exception {
/*-********************************************************************
kind=Global
kind=Getter
kind=Variable
kind=Structure
kind=Module, text="SwiftDemanglerTest"
kind=Identifier, text="MyStructure"
kind=Identifier, text="z"
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
SwiftDemanglerTest.MyStructure.z.getter : Swift.Int
**********************************************************************/
String mangled = "_$s18SwiftDemanglerTest11MyStructureV1zSivg";
String demangled =
"int default SwiftDemanglerTest::MyStructure::get_z(struct SwiftDemanglerTest::MyStructure)";
if (!(demangler.demangle(mangled) instanceof DemangledFunction function)) {
throw new AssertException("Demangled object is not a function");
}
assertEquals(demangled, function.toString());
}
@Test
public void testStructureSetter() throws Exception {
/*-********************************************************************
kind=Global
kind=Setter
kind=Variable
kind=Structure
kind=Module, text="SwiftDemanglerTest"
kind=Identifier, text="MyStructure"
kind=Identifier, text="z"
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
SwiftDemanglerTest.MyStructure.z.setter : Swift.Int
**********************************************************************/
String mangled = "_$s18SwiftDemanglerTest11MyStructureV1zSivs";
String demangled = "__thiscall SwiftDemanglerTest::MyStructure::set_z(int)";
if (!(demangler.demangle(mangled) instanceof DemangledFunction function)) {
throw new AssertException("Demangled object is not a function");
}
assertEquals(demangled, function.toString());
}
@Test
public void testStructureSubscriptGetter() throws Exception {
/*-********************************************************************
kind=Global
kind=Getter
kind=Subscript
kind=Structure
kind=Module, text="SwiftDemanglerTest"
kind=Identifier, text="MyStructure"
kind=LabelList
kind=Type
kind=FunctionType
kind=ArgumentTuple
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
kind=ReturnType
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
SwiftDemanglerTest.MyStructure.subscript.getter : (Swift.Int) -> Swift.Int
**********************************************************************/
String mangled = "_$s18SwiftDemanglerTest11MyStructureVyS2icig";
String demangled =
"int default SwiftDemanglerTest::MyStructure::get_subscript(int,struct SwiftDemanglerTest::MyStructure)";
if (!(demangler.demangle(mangled) instanceof DemangledFunction function)) {
throw new AssertException("Demangled object is not a function");
}
assertEquals(demangled, function.toString());
}
@Test
public void testStructureSubscriptSetter() throws Exception {
/*-********************************************************************
kind=Global
kind=Setter
kind=Subscript
kind=Structure
kind=Module, text="SwiftDemanglerTest"
kind=Identifier, text="MyStructure"
kind=LabelList
kind=Type
kind=FunctionType
kind=ArgumentTuple
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
kind=ReturnType
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
SwiftDemanglerTest.MyStructure.subscript.setter : (Swift.Int) -> Swift.Int
**********************************************************************/
String mangled = "_$s18SwiftDemanglerTest11MyStructureVyS2icis";
String demangled = "int __thiscall SwiftDemanglerTest::MyStructure::set_subscript(int)";
if (!(demangler.demangle(mangled) instanceof DemangledFunction function)) {
throw new AssertException("Demangled object is not a function");
}
assertEquals(demangled, function.toString());
}
@Test
public void testClassTypeMetadataAccessor() throws Exception {
/*-********************************************************************
kind=Global
kind=TypeMetadataAccessFunction
kind=Type
kind=Class
kind=Module, text="SwiftDemanglerTest"
kind=Identifier, text="MyClass"
type metadata accessor for SwiftDemanglerTest.MyClass
**********************************************************************/
String mangled = "_$s18SwiftDemanglerTest7MyClassCMa";
String demangled =
"class SwiftDemanglerTest::MyClass * default SwiftDemanglerTest::MyClass::typeMetadataAccessor(void)";
if (!(demangler.demangle(mangled) instanceof DemangledFunction function)) {
throw new AssertException("Demangled object is not a function");
}
assertEquals(demangled, function.toString());
}
@Test
public void testClassAllocator() throws Exception {
/*-********************************************************************
kind=Global
kind=Allocator
kind=Class
kind=Module, text="SwiftDemanglerTest"
kind=Identifier, text="MyClass"
kind=LabelList
kind=Identifier, text="label1"
kind=Type
kind=FunctionType
kind=ArgumentTuple
kind=Type
kind=Tuple
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
kind=ReturnType
kind=Type
kind=Class
kind=Module, text="SwiftDemanglerTest"
kind=Identifier, text="MyClass"
SwiftDemanglerTest.MyClass.__allocating_init(label1: Swift.Int) -> SwiftDemanglerTest.MyClass
**********************************************************************/
String mangled = "_$s18SwiftDemanglerTest7MyClassC6label1ACSi_tcfC";
String demangled =
"class SwiftDemanglerTest::MyClass * __thiscall SwiftDemanglerTest::MyClass::__allocating_init(int label1)";
if (!(demangler.demangle(mangled) instanceof DemangledFunction function)) {
throw new AssertException("Demangled object is not a function");
}
assertEquals(demangled, function.toString());
}
@Test
public void testClassConstructor() throws Exception {
/*-********************************************************************
kind=Global
kind=Constructor
kind=Class
kind=Module, text="SwiftDemanglerTest"
kind=Identifier, text="MyClass"
kind=LabelList
kind=Identifier, text="label1"
kind=Type
kind=FunctionType
kind=ArgumentTuple
kind=Type
kind=Tuple
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
kind=ReturnType
kind=Type
kind=Class
kind=Module, text="SwiftDemanglerTest"
kind=Identifier, text="MyClass"
SwiftDemanglerTest.MyClass.init(label1: Swift.Int) -> SwiftDemanglerTest.MyClass
**********************************************************************/
String mangled = "_$s18SwiftDemanglerTest7MyClassC6label1ACSi_tcfc";
String demangled =
"class SwiftDemanglerTest::MyClass * __thiscall SwiftDemanglerTest::MyClass::init(int label1)";
if (!(demangler.demangle(mangled) instanceof DemangledFunction function)) {
throw new AssertException("Demangled object is not a function");
}
assertEquals(demangled, function.toString());
}
@Test
public void testClassFunction() throws Exception {
/*-********************************************************************
kind=Global
kind=Function
kind=Class
kind=Module, text="SwiftDemanglerTest"
kind=Identifier, text="MyClass"
kind=Identifier, text="myMethod"
kind=LabelList
kind=Identifier, text="label1"
kind=Identifier, text="label2"
kind=Type
kind=FunctionType
kind=ArgumentTuple
kind=Type
kind=Tuple
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
kind=ReturnType
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
SwiftDemanglerTest.MyClass.myMethod(label1: Swift.Int, label2: Swift.Int) -> Swift.Int
**********************************************************************/
String mangled = "_$s18SwiftDemanglerTest7MyClassC8myMethod6label16label2S2i_SitF";
String demangled =
"int __thiscall SwiftDemanglerTest::MyClass::myMethod(int label1,int label2)";
if (!(demangler.demangle(mangled) instanceof DemangledFunction function)) {
throw new AssertException("Demangled object is not a function");
}
assertEquals(demangled, function.toString());
}
@Test
public void testClassGetter() throws Exception {
/*-********************************************************************
kind=Global
kind=Getter
kind=Variable
kind=Class
kind=Module, text="SwiftDemanglerTest"
kind=Identifier, text="MyClass"
kind=Identifier, text="z"
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
SwiftDemanglerTest.MyClass.z.getter : Swift.Int
**********************************************************************/
String mangled = "_$s18SwiftDemanglerTest7MyClassC1zSivg";
String demangled =
"int __thiscall SwiftDemanglerTest::MyClass::get_z(class SwiftDemanglerTest::MyClass *)";
if (!(demangler.demangle(mangled) instanceof DemangledFunction function)) {
throw new AssertException("Demangled object is not a function");
}
assertEquals(demangled, function.toString());
}
@Test
public void testClassSetter() throws Exception {
/*-********************************************************************
kind=Global
kind=Setter
kind=Variable
kind=Class
kind=Module, text="SwiftDemanglerTest"
kind=Identifier, text="MyClass"
kind=Identifier, text="z"
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
SwiftDemanglerTest.MyClass.z.setter : Swift.Int
**********************************************************************/
String mangled = "_$s18SwiftDemanglerTest7MyClassC1zSivs";
String demangled = "__thiscall SwiftDemanglerTest::MyClass::set_z(int)";
if (!(demangler.demangle(mangled) instanceof DemangledFunction function)) {
throw new AssertException("Demangled object is not a function");
}
assertEquals(demangled, function.toString());
}
@Test
public void testClassModifyAccessor() throws Exception {
/*-********************************************************************
kind=Global
kind=ModifyAccessor
kind=Variable
kind=Class
kind=Module, text="SwiftDemanglerTest"
kind=Identifier, text="MyClass"
kind=Identifier, text="z"
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
SwiftDemanglerTest.MyClass.z.modify : Swift.Int
**********************************************************************/
String mangled = "_$s18SwiftDemanglerTest7MyClassC1zSivM";
String demangled = "__thiscall SwiftDemanglerTest::MyClass::modify_z(int)";
if (!(demangler.demangle(mangled) instanceof DemangledFunction function)) {
throw new AssertException("Demangled object is not a function");
}
assertEquals(demangled, function.toString());
}
@Test
public void testClassDeallocator() throws Exception {
/*-********************************************************************
kind=Global
kind=Deallocator
kind=Class
kind=Module, text="SwiftDemanglerTest"
kind=Identifier, text="MyClass"
SwiftDemanglerTest.MyClass.__deallocating_deinit
**********************************************************************/
String mangled = "_$s18SwiftDemanglerTest7MyClassCfD";
String demangled = "__thiscall SwiftDemanglerTest::MyClass::__deallocating_init(void)";
if (!(demangler.demangle(mangled) instanceof DemangledFunction function)) {
throw new AssertException("Demangled object is not a function");
}
assertEquals(demangled, function.toString());
}
@Test
public void testClassDestructor() throws Exception {
/*-********************************************************************
kind=Global
kind=Destructor
kind=Class
kind=Module, text="SwiftDemanglerTest"
kind=Identifier, text="MyClass"
SwiftDemanglerTest.MyClass.deinit
**********************************************************************/
String mangled = "_$s18SwiftDemanglerTest7MyClassCfd";
String demangled =
"class SwiftDemanglerTest::MyClass * __thiscall SwiftDemanglerTest::MyClass::deinit(void)";
if (!(demangler.demangle(mangled) instanceof DemangledFunction function)) {
throw new AssertException("Demangled object is not a function");
}
assertEquals(demangled, function.toString());
}
@Test
public void testEnumFunction() throws Exception {
/*-********************************************************************
kind=Global
kind=Function
kind=Enum
kind=Module, text="SwiftDemanglerTest"
kind=Identifier, text="MyAssociatedEnum"
kind=Identifier, text="myMethod"
kind=LabelList
kind=Identifier, text="label1"
kind=Type
kind=FunctionType
kind=ArgumentTuple
kind=Type
kind=Tuple
kind=TupleElement
kind=Type
kind=Structure
kind=Module, text="Swift"
kind=Identifier, text="Int"
kind=ReturnType
kind=Type
kind=Enum
kind=Module, text="SwiftDemanglerTest"
kind=Identifier, text="MyAssociatedEnum"
SwiftDemanglerTest.MyAssociatedEnum.myMethod(label1: Swift.Int) -> SwiftDemanglerTest.MyAssociatedEnum
**********************************************************************/
String mangled = "_$s18SwiftDemanglerTest16MyAssociatedEnumO8myMethod6label1ACSi_tF";
String demangled =
"struct SwiftDemanglerTest::MyAssociatedEnum default SwiftDemanglerTest::MyAssociatedEnum::myMethod(int label1,struct SwiftDemanglerTest::MyAssociatedEnum,undefined)";
if (!(demangler.demangle(mangled) instanceof DemangledFunction function)) {
throw new AssertException("Demangled object is not a function");
}
assertEquals(demangled, function.toString());
}
}

View file

@ -12,6 +12,7 @@ data/languages/AARCH64_AMXext.sinc||GHIDRA||||END|
data/languages/AARCH64_AppleSilicon.slaspec||GHIDRA||||END|
data/languages/AARCH64_base_PACoptions.sinc||GHIDRA||||END|
data/languages/AARCH64_ilp32.cspec||GHIDRA||||END|
data/languages/AARCH64_swift.cspec||GHIDRA||||END|
data/languages/AARCH64_win.cspec||GHIDRA||||END|
data/languages/AARCH64base.sinc||GHIDRA||||END|
data/languages/AARCH64instructions.sinc||GHIDRA||||END|

View file

@ -9,6 +9,9 @@
<constraint primary="16777228" processor="AARCH64" endian="little" size="64" variant="AppleSilicon" />
<constraint primary="33554444" processor="AARCH64" endian="little" size="32" variant="ilp32" />
</constraint>
<constraint loader="Mac OS X Mach-O" compilerSpecID="swift">
<constraint primary="16777228" secondary="swift" processor="AARCH64" endian="little" size="64" variant="AppleSilicon" />
</constraint>
<constraint loader="DYLD Cache" compilerSpecID="default">
<constraint primary="AARCH64" processor="AARCH64" endian="little" size="64" variant="AppleSilicon" />
<constraint primary="ARM64_32" processor="AARCH64" endian="little" size="32" variant="ilp32" />

View file

@ -0,0 +1,393 @@
<?xml version="1.0" encoding="UTF-8"?>
<compiler_spec>
<data_organization>
<absolute_max_alignment value="0" />
<machine_alignment value="4" />
<default_alignment value="2" />
<default_pointer_alignment value="8" />
<pointer_size value="8" />
<wchar_size value="4" />
<short_size value="2" />
<integer_size value="8" />
<long_size value="8" />
<long_long_size value="8" />
<float_size value="4" />
<double_size value="8" />
<long_double_size value="8" />
<size_alignment_map>
<entry size="1" alignment="1" />
<entry size="2" alignment="2" />
<entry size="4" alignment="4" />
<entry size="8" alignment="8" />
</size_alignment_map>
</data_organization>
<global>
<range space="ram"/>
</global>
<stackpointer register="sp" space="ram"/>
<funcptr align="4"/> <!-- Function pointers are word aligned and leastsig bit may encode otherstuff -->
<prefersplit style="inhalf">
<register name="q0"/>
<register name="q1"/>
<register name="q2"/>
<register name="q3"/>
<register name="q4"/>
<register name="q5"/>
<register name="q6"/>
<register name="q7"/>
<register name="q8"/>
<register name="q9"/>
<register name="q10"/>
<register name="q11"/>
<register name="q12"/>
<register name="q13"/>
<register name="q14"/>
<register name="q15"/>
<register name="q16"/>
<register name="q17"/>
<register name="q18"/>
<register name="q19"/>
<register name="q20"/>
<register name="q21"/>
<register name="q22"/>
<register name="q23"/>
<register name="q24"/>
<register name="q25"/>
<register name="q26"/>
<register name="q27"/>
<register name="q28"/>
<register name="q29"/>
<register name="q30"/>
</prefersplit>
<default_proto>
<prototype name="__swiftcall" extrapop="0" stackshift="0">
<!-- https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64 -->
<input>
<pentry minsize="8" maxsize="8" storage="hiddenret">
<register name="x8"/>
</pentry>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d0"/>
</pentry>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d1"/>
</pentry>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d2"/>
</pentry>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d3"/>
</pentry>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d4"/>
</pentry>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d5"/>
</pentry>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d6"/>
</pentry>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d7"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x0"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x1"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x2"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x3"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x4"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x5"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x6"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x7"/>
</pentry>
<pentry minsize="1" maxsize="500" align="4">
<addr offset="0" space="stack"/>
</pentry>
<rule>
<datatype name="struct" minsize="9"/>
<join/>
</rule>
</input>
<output>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d0"/>
</pentry>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d1"/>
</pentry>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d2"/>
</pentry>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d3"/>
</pentry>
<pentry minsize="1" maxsize="8">
<register name="x0"/>
</pentry>
<pentry minsize="1" maxsize="8">
<register name="x1"/>
</pentry>
<pentry minsize="1" maxsize="8">
<register name="x2"/>
</pentry>
<pentry minsize="1" maxsize="8">
<register name="x3"/>
</pentry>
<rule>
<datatype name="homogeneous-float-aggregate"/>
<join_per_primitive storage="float"/>
</rule>
<rule>
<datatype name="float"/>
<consume storage="float"/>
</rule>
<rule>
<datatype name="any" minsize="1" maxsize="32"/>
<join/>
</rule>
<rule>
<datatype name="any" minsize="33"/>
<hidden_return voidlock="true"/>
</rule>
</output>
<unaffected>
<register name="x19"/>
<register name="x20"/>
<register name="x21"/>
<register name="x22"/>
<register name="x23"/>
<register name="x24"/>
<register name="x25"/>
<register name="x26"/>
<register name="x27"/>
<register name="x28"/>
<register name="x29"/>
<register name="x30"/>
<register name="sp"/>
<!-- vectors -->
<register name="d8"/>
<register name="d9"/>
<register name="d10"/>
<register name="d11"/>
<register name="d12"/>
<register name="d13"/>
<register name="d14"/>
<register name="d15"/>
</unaffected>
<killedbycall>
<!-- x8: indirect result location register, which is not
reflected in the pentry list -->
<register name="x8"/>
<register name="x9"/>
<register name="x10"/>
<register name="x11"/>
<register name="x12"/>
<register name="x13"/>
<register name="x14"/>
<register name="x15"/>
<register name="x16"/>
<register name="x17"/>
<register name="x18"/>
<!-- vectors -->
<register name="d16"/>
<register name="d17"/>
<register name="d18"/>
<register name="d19"/>
<register name="d20"/>
<register name="d21"/>
<register name="d22"/>
<register name="d23"/>
<register name="d24"/>
<register name="d25"/>
<register name="d26"/>
<register name="d27"/>
<register name="d28"/>
<register name="d29"/>
<register name="d30"/>
<register name="d31"/>
</killedbycall>
</prototype>
</default_proto>
<prototype name="__thiscall" extrapop="0" stackshift="0">
<!-- https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64 -->
<input>
<pentry minsize="8" maxsize="8" storage="hiddenret">
<register name="x8"/>
</pentry>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d0"/>
</pentry>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d1"/>
</pentry>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d2"/>
</pentry>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d3"/>
</pentry>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d4"/>
</pentry>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d5"/>
</pentry>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d6"/>
</pentry>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d7"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x20"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x0"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x1"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x2"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x3"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x4"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x5"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x6"/>
</pentry>
<pentry minsize="1" maxsize="8" extension="zero">
<register name="x7"/>
</pentry>
<pentry minsize="1" maxsize="500" align="4">
<addr offset="0" space="stack"/>
</pentry>
<rule>
<datatype name="struct" minsize="9"/>
<join/>
</rule>
</input>
<output>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d0"/>
</pentry>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d1"/>
</pentry>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d2"/>
</pentry>
<pentry minsize="2" maxsize="8" metatype="float">
<register name="d3"/>
</pentry>
<pentry minsize="1" maxsize="8">
<register name="x0"/>
</pentry>
<pentry minsize="1" maxsize="8">
<register name="x1"/>
</pentry>
<pentry minsize="1" maxsize="8">
<register name="x2"/>
</pentry>
<pentry minsize="1" maxsize="8">
<register name="x3"/>
</pentry>
<rule>
<datatype name="homogeneous-float-aggregate"/>
<join_per_primitive storage="float"/>
</rule>
<rule>
<datatype name="float"/>
<consume storage="float"/>
</rule>
<rule>
<datatype name="any" minsize="1" maxsize="32"/>
<join/>
</rule>
<rule>
<datatype name="any" minsize="33"/>
<hidden_return voidlock="true"/>
</rule>
</output>
<unaffected>
<register name="x19"/>
<register name="x21"/>
<register name="x22"/>
<register name="x23"/>
<register name="x24"/>
<register name="x25"/>
<register name="x26"/>
<register name="x27"/>
<register name="x28"/>
<register name="x29"/>
<register name="x30"/>
<register name="sp"/>
<!-- vectors -->
<register name="d8"/>
<register name="d9"/>
<register name="d10"/>
<register name="d11"/>
<register name="d12"/>
<register name="d13"/>
<register name="d14"/>
<register name="d15"/>
</unaffected>
<killedbycall>
<!-- x8: indirect result location register, which is not
reflected in the pentry list -->
<register name="x8"/>
<register name="x9"/>
<register name="x10"/>
<register name="x11"/>
<register name="x12"/>
<register name="x13"/>
<register name="x14"/>
<register name="x15"/>
<register name="x16"/>
<register name="x17"/>
<register name="x18"/>
<!-- vectors -->
<register name="d16"/>
<register name="d17"/>
<register name="d18"/>
<register name="d19"/>
<register name="d20"/>
<register name="d21"/>
<register name="d22"/>
<register name="d23"/>
<register name="d24"/>
<register name="d25"/>
<register name="d26"/>
<register name="d27"/>
<register name="d28"/>
<register name="d29"/>
<register name="d30"/>
<register name="d31"/>
</killedbycall>
</prototype>
</compiler_spec>

View file

@ -11,6 +11,7 @@
id="AARCH64:LE:64:AppleSilicon">
<description>AppleSilicon ARM v8.5-A LE instructions, LE data, AMX extensions</description>
<compiler name="default" spec="AARCH64.cspec" id="default"/>
<compiler name="Swift" spec="AARCH64_swift.cspec" id="swift"/>
<external_name tool="gnu" name="aarch64"/>
<external_name tool="gnu" name="aarch64:ilp32"/>
<external_name tool="DWARF.register.mapping.file" name="AARCH64.dwarf"/>

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