mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-06-01 11:55:59 +08:00
GP-3535: Improved Swift support
This commit is contained in:
+11
-1
@@ -31,6 +31,8 @@ public class SwiftTypeMetadataAnalyzer extends AbstractAnalyzer {
|
|||||||
private static final String NAME = "Swift Type Metadata Analyzer";
|
private static final String NAME = "Swift Type Metadata Analyzer";
|
||||||
private static final String DESCRIPTION = "Discovers Swift type metadata records.";
|
private static final String DESCRIPTION = "Discovers Swift type metadata records.";
|
||||||
|
|
||||||
|
private SwiftTypeMetadata typeMetadata;
|
||||||
|
|
||||||
public SwiftTypeMetadataAnalyzer() {
|
public SwiftTypeMetadataAnalyzer() {
|
||||||
super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER);
|
super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER);
|
||||||
setDefaultEnablement(true);
|
setDefaultEnablement(true);
|
||||||
@@ -45,8 +47,11 @@ public class SwiftTypeMetadataAnalyzer extends AbstractAnalyzer {
|
|||||||
@Override
|
@Override
|
||||||
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
|
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
|
if (typeMetadata != null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
SwiftTypeMetadata typeMetadata = new SwiftTypeMetadata(program, monitor, log);
|
typeMetadata = new SwiftTypeMetadata(program, monitor, log);
|
||||||
typeMetadata.markup();
|
typeMetadata.markup();
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
@@ -54,4 +59,9 @@ public class SwiftTypeMetadataAnalyzer extends AbstractAnalyzer {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void analysisEnded(Program program) {
|
||||||
|
typeMetadata = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -35,8 +35,9 @@ public enum SwiftSection {
|
|||||||
BLOCK_PROTOCS("__swift5_protos", "swift5_protocols", ".sw5prt"),
|
BLOCK_PROTOCS("__swift5_protos", "swift5_protocols", ".sw5prt"),
|
||||||
BLOCK_ACFUNCS("__swift5_acfuncs", "swift5_accessible_functions", ".sw5acfn"),
|
BLOCK_ACFUNCS("__swift5_acfuncs", "swift5_accessible_functions", ".sw5acfn"),
|
||||||
BLOCK_MPENUM("__swift5_mpenum", "swift5_mpenum", ".sw5mpen"),
|
BLOCK_MPENUM("__swift5_mpenum", "swift5_mpenum", ".sw5mpen"),
|
||||||
BLOCK_TYPES("__swift5_types", "swift5_types", ".sw5tymd"),
|
BLOCK_TYPES("__swift5_types", "swift5_type_metadata", ".sw5tymd"),
|
||||||
BLOCK_ENTRY("__swift5_entry", "swift5_entry", ".sw5entr");
|
BLOCK_ENTRY("__swift5_entry", "swift5_entry", ".sw5entr"),
|
||||||
|
BLOCK_SWIFTAST("__swift_ast", ".swift_ast", "swiftast");
|
||||||
|
|
||||||
private List<String> sectionNames;
|
private List<String> sectionNames;
|
||||||
|
|
||||||
|
|||||||
+120
-27
@@ -16,8 +16,7 @@
|
|||||||
package ghidra.app.util.bin.format.swift;
|
package ghidra.app.util.bin.format.swift;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import ghidra.app.util.bin.*;
|
import ghidra.app.util.bin.*;
|
||||||
import ghidra.app.util.bin.format.swift.types.*;
|
import ghidra.app.util.bin.format.swift.types.*;
|
||||||
@@ -43,11 +42,11 @@ public class SwiftTypeMetadata {
|
|||||||
|
|
||||||
private List<EntryPoint> entryPoints = new ArrayList<>();
|
private List<EntryPoint> entryPoints = new ArrayList<>();
|
||||||
private List<BuiltinTypeDescriptor> builtinTypeDescriptors = new ArrayList<>();
|
private List<BuiltinTypeDescriptor> builtinTypeDescriptors = new ArrayList<>();
|
||||||
private List<FieldDescriptor> fieldDescriptors = new ArrayList<>();
|
private Map<Long, FieldDescriptor> fieldDescriptors = new HashMap<>();
|
||||||
private List<AssociatedTypeDescriptor> associatedTypeDescriptors = new ArrayList<>();
|
private List<AssociatedTypeDescriptor> associatedTypeDescriptors = new ArrayList<>();
|
||||||
private List<CaptureDescriptor> captureDescriptors = new ArrayList<>();
|
private List<CaptureDescriptor> captureDescriptors = new ArrayList<>();
|
||||||
private List<MultiPayloadEnumDescriptor> mpEnumDescriptors = new ArrayList<>();
|
private List<MultiPayloadEnumDescriptor> mpEnumDescriptors = new ArrayList<>();
|
||||||
private List<TargetTypeContextDescriptor> typeDescriptors = new ArrayList<>();
|
private Map<String, TargetTypeContextDescriptor> typeDescriptors = new HashMap<>();
|
||||||
private List<TargetProtocolDescriptor> protocolDescriptors = new ArrayList<>();
|
private List<TargetProtocolDescriptor> protocolDescriptors = new ArrayList<>();
|
||||||
private List<TargetProtocolConformanceDescriptor> protocolConformanceDescriptors =
|
private List<TargetProtocolConformanceDescriptor> protocolConformanceDescriptors =
|
||||||
new ArrayList<>();
|
new ArrayList<>();
|
||||||
@@ -72,6 +71,69 @@ public class SwiftTypeMetadata {
|
|||||||
parse();
|
parse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the entry points}
|
||||||
|
*/
|
||||||
|
public List<EntryPoint> getEntryPoints() {
|
||||||
|
return entryPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the built-in type descriptors}
|
||||||
|
*/
|
||||||
|
public List<BuiltinTypeDescriptor> getBuiltinTypeDescriptors() {
|
||||||
|
return builtinTypeDescriptors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the field descriptors}
|
||||||
|
*/
|
||||||
|
public Map<Long, FieldDescriptor> getFieldDescriptors() {
|
||||||
|
return fieldDescriptors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the associated type descriptors}
|
||||||
|
*/
|
||||||
|
public List<AssociatedTypeDescriptor> getAssociatedTypeDescriptor() {
|
||||||
|
return associatedTypeDescriptors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the capture descriptors}
|
||||||
|
*/
|
||||||
|
public List<CaptureDescriptor> getCaptureDescriptors() {
|
||||||
|
return captureDescriptors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the multi-payload enum descriptors}
|
||||||
|
*/
|
||||||
|
public List<MultiPayloadEnumDescriptor> getMultiPayloadEnumDescriptors() {
|
||||||
|
return mpEnumDescriptors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the type descriptors}
|
||||||
|
*/
|
||||||
|
public Map<String, TargetTypeContextDescriptor> getTargetTypeContextDescriptors() {
|
||||||
|
return typeDescriptors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the target protocol descriptors}
|
||||||
|
*/
|
||||||
|
public List<TargetProtocolDescriptor> getTargetProtocolDescriptors() {
|
||||||
|
return protocolDescriptors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the target protocol conformance descriptors}
|
||||||
|
*/
|
||||||
|
public List<TargetProtocolConformanceDescriptor> getTargetProtocolConformanceDescriptors() {
|
||||||
|
return protocolConformanceDescriptors;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the {@link SwiftTypeMetadata}
|
* Parses the {@link SwiftTypeMetadata}
|
||||||
*
|
*
|
||||||
@@ -137,7 +199,7 @@ public class SwiftTypeMetadata {
|
|||||||
for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) {
|
for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) {
|
||||||
Address blockStart = block.getStart();
|
Address blockStart = block.getStart();
|
||||||
reader.setPointerIndex(blockStart.getOffset());
|
reader.setPointerIndex(blockStart.getOffset());
|
||||||
int i = 0;
|
int i = skipZeroEntries(reader, 0, block.getSize());
|
||||||
while (i + BuiltinTypeDescriptor.SIZE <= block.getSize()) {
|
while (i + BuiltinTypeDescriptor.SIZE <= block.getSize()) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
BuiltinTypeDescriptor descriptor = new BuiltinTypeDescriptor(reader);
|
BuiltinTypeDescriptor descriptor = new BuiltinTypeDescriptor(reader);
|
||||||
@@ -145,6 +207,7 @@ public class SwiftTypeMetadata {
|
|||||||
markupList.add(new SwiftStructureInfo(descriptor,
|
markupList.add(new SwiftStructureInfo(descriptor,
|
||||||
new SwiftStructureAddress(blockStart.add(i), null)));
|
new SwiftStructureAddress(blockStart.add(i), null)));
|
||||||
i += BuiltinTypeDescriptor.SIZE;
|
i += BuiltinTypeDescriptor.SIZE;
|
||||||
|
i = skipZeroEntries(reader, i, block.getSize());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,11 +231,11 @@ public class SwiftTypeMetadata {
|
|||||||
for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) {
|
for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) {
|
||||||
Address blockStart = block.getStart();
|
Address blockStart = block.getStart();
|
||||||
reader.setPointerIndex(blockStart.getOffset());
|
reader.setPointerIndex(blockStart.getOffset());
|
||||||
int i = 0;
|
int i = skipZeroEntries(reader, 0, block.getSize());
|
||||||
while (i + FieldDescriptor.SIZE <= block.getSize()) {
|
while (i + FieldDescriptor.SIZE <= block.getSize()) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
FieldDescriptor descriptor = new FieldDescriptor(reader);
|
FieldDescriptor descriptor = new FieldDescriptor(reader);
|
||||||
fieldDescriptors.add(descriptor);
|
fieldDescriptors.put(descriptor.getBase(), descriptor);
|
||||||
markupList.add(new SwiftStructureInfo(descriptor,
|
markupList.add(new SwiftStructureInfo(descriptor,
|
||||||
new SwiftStructureAddress(blockStart.add(i), null)));
|
new SwiftStructureAddress(blockStart.add(i), null)));
|
||||||
List<FieldRecord> records = descriptor.getFieldRecords();
|
List<FieldRecord> records = descriptor.getFieldRecords();
|
||||||
@@ -184,6 +247,7 @@ public class SwiftTypeMetadata {
|
|||||||
null)));
|
null)));
|
||||||
}
|
}
|
||||||
i += descriptor.getNumFields() * FieldRecord.SIZE;
|
i += descriptor.getNumFields() * FieldRecord.SIZE;
|
||||||
|
i = skipZeroEntries(reader, i, block.getSize());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -207,7 +271,7 @@ public class SwiftTypeMetadata {
|
|||||||
for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) {
|
for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) {
|
||||||
Address blockStart = block.getStart();
|
Address blockStart = block.getStart();
|
||||||
reader.setPointerIndex(blockStart.getOffset());
|
reader.setPointerIndex(blockStart.getOffset());
|
||||||
int i = 0;
|
int i = skipZeroEntries(reader, 0, block.getSize());
|
||||||
while (i + AssociatedTypeDescriptor.SIZE <= block.getSize()) {
|
while (i + AssociatedTypeDescriptor.SIZE <= block.getSize()) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
AssociatedTypeDescriptor descriptor = new AssociatedTypeDescriptor(reader);
|
AssociatedTypeDescriptor descriptor = new AssociatedTypeDescriptor(reader);
|
||||||
@@ -223,6 +287,7 @@ public class SwiftTypeMetadata {
|
|||||||
blockStart.add(i + j * AssociatedTypeRecord.SIZE), null)));
|
blockStart.add(i + j * AssociatedTypeRecord.SIZE), null)));
|
||||||
}
|
}
|
||||||
i += descriptor.getNumAssociatedTypes() * AssociatedTypeRecord.SIZE;
|
i += descriptor.getNumAssociatedTypes() * AssociatedTypeRecord.SIZE;
|
||||||
|
i = skipZeroEntries(reader, i, block.getSize());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -246,7 +311,7 @@ public class SwiftTypeMetadata {
|
|||||||
for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) {
|
for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) {
|
||||||
Address blockStart = block.getStart();
|
Address blockStart = block.getStart();
|
||||||
reader.setPointerIndex(blockStart.getOffset());
|
reader.setPointerIndex(blockStart.getOffset());
|
||||||
int i = 0;
|
int i = skipZeroEntries(reader, 0, block.getSize());
|
||||||
while (i + CaptureDescriptor.SIZE <= block.getSize()) {
|
while (i + CaptureDescriptor.SIZE <= block.getSize()) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
CaptureDescriptor descriptor = new CaptureDescriptor(reader);
|
CaptureDescriptor descriptor = new CaptureDescriptor(reader);
|
||||||
@@ -271,6 +336,7 @@ public class SwiftTypeMetadata {
|
|||||||
blockStart.add(i + j * MetadataSourceRecord.SIZE), null)));
|
blockStart.add(i + j * MetadataSourceRecord.SIZE), null)));
|
||||||
}
|
}
|
||||||
i += descriptor.getNumMetadataSources() * MetadataSourceRecord.SIZE;
|
i += descriptor.getNumMetadataSources() * MetadataSourceRecord.SIZE;
|
||||||
|
i = skipZeroEntries(reader, i, block.getSize());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -294,7 +360,7 @@ public class SwiftTypeMetadata {
|
|||||||
for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) {
|
for (MemoryBlock block : SwiftUtils.getSwiftBlocks(section, program)) {
|
||||||
Address blockStart = block.getStart();
|
Address blockStart = block.getStart();
|
||||||
reader.setPointerIndex(blockStart.getOffset());
|
reader.setPointerIndex(blockStart.getOffset());
|
||||||
int i = 0;
|
int i = skipZeroEntries(reader, 0, block.getSize());
|
||||||
while (i < block.getSize()) {
|
while (i < block.getSize()) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
MultiPayloadEnumDescriptor descriptor = new MultiPayloadEnumDescriptor(reader);
|
MultiPayloadEnumDescriptor descriptor = new MultiPayloadEnumDescriptor(reader);
|
||||||
@@ -302,6 +368,7 @@ public class SwiftTypeMetadata {
|
|||||||
markupList.add(new SwiftStructureInfo(descriptor,
|
markupList.add(new SwiftStructureInfo(descriptor,
|
||||||
new SwiftStructureAddress(blockStart.add(i), null)));
|
new SwiftStructureAddress(blockStart.add(i), null)));
|
||||||
i += MultiPayloadEnumDescriptor.SIZE + descriptor.getContentsSize();
|
i += MultiPayloadEnumDescriptor.SIZE + descriptor.getContentsSize();
|
||||||
|
i = skipZeroEntries(reader, i, block.getSize());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -397,7 +464,7 @@ public class SwiftTypeMetadata {
|
|||||||
yield null;
|
yield null;
|
||||||
};
|
};
|
||||||
if (descriptor != null) {
|
if (descriptor != null) {
|
||||||
typeDescriptors.add(descriptor);
|
typeDescriptors.put(descriptor.getName(), descriptor);
|
||||||
markupList.add(new SwiftStructureInfo(descriptor,
|
markupList.add(new SwiftStructureInfo(descriptor,
|
||||||
new SwiftStructureAddress(addrPair.structAddr(), addrPair.pointerAddr())));
|
new SwiftStructureAddress(addrPair.structAddr(), addrPair.pointerAddr())));
|
||||||
}
|
}
|
||||||
@@ -409,7 +476,7 @@ public class SwiftTypeMetadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a table of pointers to {@link SwiftStructure}s found in the given section
|
* Parses a table of pointers to {@link SwiftTypeMetadataStructure}s found in the given section
|
||||||
*
|
*
|
||||||
* @param section The {@link SwiftSection} that contains the pointer table
|
* @param section The {@link SwiftSection} that contains the pointer table
|
||||||
* @param reader A {@link BinaryReader}
|
* @param reader A {@link BinaryReader}
|
||||||
@@ -428,11 +495,10 @@ public class SwiftTypeMetadata {
|
|||||||
reader.setPointerIndex(blockAddr.getOffset() + i);
|
reader.setPointerIndex(blockAddr.getOffset() + i);
|
||||||
Address pointerAddr = blockAddr.add(i);
|
Address pointerAddr = blockAddr.add(i);
|
||||||
int offset = reader.readInt(pointerAddr.getOffset());
|
int offset = reader.readInt(pointerAddr.getOffset());
|
||||||
if (offset == 0) {
|
if (offset != 0) {
|
||||||
break;
|
Address structAddr = pointerAddr.add(offset);
|
||||||
|
result.add(new SwiftStructureAddress(structAddr, pointerAddr));
|
||||||
}
|
}
|
||||||
Address structAddr = pointerAddr.add(offset);
|
|
||||||
result.add(new SwiftStructureAddress(structAddr, pointerAddr));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -454,7 +520,7 @@ public class SwiftTypeMetadata {
|
|||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
monitor.incrementProgress(1);
|
monitor.incrementProgress(1);
|
||||||
try {
|
try {
|
||||||
SwiftStructure struct = structInfo.struct();
|
SwiftTypeMetadataStructure struct = structInfo.struct();
|
||||||
DataType dt = struct.toDataType();
|
DataType dt = struct.toDataType();
|
||||||
DataUtilities.createData(program, structInfo.addr().structAddr(), dt, -1,
|
DataUtilities.createData(program, structInfo.addr().structAddr(), dt, -1,
|
||||||
ClearDataMode.CLEAR_ALL_DEFAULT_CONFLICT_DATA);
|
ClearDataMode.CLEAR_ALL_DEFAULT_CONFLICT_DATA);
|
||||||
@@ -465,12 +531,37 @@ public class SwiftTypeMetadata {
|
|||||||
relativePtrDataType, -1, ClearDataMode.CLEAR_ALL_DEFAULT_CONFLICT_DATA);
|
relativePtrDataType, -1, ClearDataMode.CLEAR_ALL_DEFAULT_CONFLICT_DATA);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (CodeUnitInsertionException | DuplicateNameException | IOException e) {
|
catch (CodeUnitInsertionException e) {
|
||||||
|
// Probably just called more than once
|
||||||
|
}
|
||||||
|
catch (DuplicateNameException | IOException e) {
|
||||||
log("Failed to markup: " + structInfo);
|
log("Failed to markup: " + structInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads past zeroed out entries in Swift type metadata sections
|
||||||
|
*
|
||||||
|
* @param reader A {@link BinaryReader} positioned within a type metadata section
|
||||||
|
* @param offset The current offset from the start of the type metadata section
|
||||||
|
* @param size The size of the type metadata section (in bytes)
|
||||||
|
* @return The offset from the start of the type metadata section that contains the next
|
||||||
|
* non-zero entry
|
||||||
|
* @throws IOException if an IO-related error occurred
|
||||||
|
*/
|
||||||
|
private int skipZeroEntries(BinaryReader reader, int offset, long size) throws IOException {
|
||||||
|
while (offset + 8 <= size) {
|
||||||
|
long possibleZero = reader.readNextLong();
|
||||||
|
if (possibleZero != 0) {
|
||||||
|
reader.setPointerIndex(reader.getPointerIndex() - 8);
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
offset += 8;
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience method to perform logging
|
* Convenience method to perform logging
|
||||||
*
|
*
|
||||||
@@ -481,22 +572,24 @@ public class SwiftTypeMetadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link Address} of a {@link SwiftStructure} and the optional {@link Address} of its
|
* The {@link Address} of a {@link SwiftTypeMetadataStructure} and the optional {@link Address}
|
||||||
* pointer
|
* of its pointer
|
||||||
*
|
*
|
||||||
* @param structAddr The {@link Address} of a {@link SwiftStructure}
|
* @param structAddr The {@link Address} of a {@link SwiftTypeMetadataStructure}
|
||||||
* @param pointerAddr The {@link Address} of a pointer to a {@link SwiftStructure} (could be
|
* @param pointerAddr The {@link Address} of a pointer to a {@link SwiftTypeMetadataStructure}
|
||||||
* null if there is no associated pointer}
|
* (could be null if there is no associated pointer}
|
||||||
*/
|
*/
|
||||||
private record SwiftStructureAddress(Address structAddr, Address pointerAddr) {}
|
private record SwiftStructureAddress(Address structAddr, Address pointerAddr) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information about a {@link SwiftStructure}
|
* Information about a {@link SwiftTypeMetadataStructure}
|
||||||
*
|
*
|
||||||
* @param struct The {@link SwiftStructure}
|
* @param struct The {@link SwiftTypeMetadataStructure}
|
||||||
* @param addr The {@link SwiftStructureAddress address} of the {@link SwiftStructure}
|
* @param addr The {@link SwiftStructureAddress address} of the
|
||||||
|
* {@link SwiftTypeMetadataStructure}
|
||||||
*/
|
*/
|
||||||
private record SwiftStructureInfo(SwiftStructure struct, SwiftStructureAddress addr) {
|
private record SwiftStructureInfo(SwiftTypeMetadataStructure struct,
|
||||||
|
SwiftStructureAddress addr) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|||||||
+55
@@ -0,0 +1,55 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.util.bin.format.swift;
|
||||||
|
|
||||||
|
import ghidra.app.util.bin.StructConverter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implemented by all Swift type metadata structures
|
||||||
|
*/
|
||||||
|
public abstract class SwiftTypeMetadataStructure implements StructConverter {
|
||||||
|
|
||||||
|
public static final String DATA_TYPE_CATEGORY = "/SwiftTypeMetadata";
|
||||||
|
|
||||||
|
private long base;
|
||||||
|
|
||||||
|
public SwiftTypeMetadataStructure(long base) {
|
||||||
|
this.base = base;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the base "address" of this {@link SwiftTypeMetadataStructure}
|
||||||
|
*
|
||||||
|
* @return The base "address" of this {@link SwiftTypeMetadataStructure}
|
||||||
|
*/
|
||||||
|
public long getBase() {
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name of the {@link SwiftTypeMetadataStructure}
|
||||||
|
*
|
||||||
|
* @return The name of the {@link SwiftTypeMetadataStructure}
|
||||||
|
*/
|
||||||
|
public abstract String getStructureName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a short description of the {@link SwiftTypeMetadataStructure}
|
||||||
|
*
|
||||||
|
* @return A short description of the {@link SwiftTypeMetadataStructure}
|
||||||
|
*/
|
||||||
|
public abstract String getDescription();
|
||||||
|
}
|
||||||
@@ -57,6 +57,23 @@ public class SwiftUtils {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given {@List} of section names contains a Swift section name
|
||||||
|
*
|
||||||
|
* @param sectionNames The {@link List} of section names to check
|
||||||
|
* @return True if the given {@List} of section names contains a Swift section name; otherwise,
|
||||||
|
* false
|
||||||
|
*/
|
||||||
|
public static boolean isSwift(List<String> sectionNames) {
|
||||||
|
List<String> prefixes = List.of("__swift", "swift", ".sw5");
|
||||||
|
for (String sectionName : sectionNames) {
|
||||||
|
if (prefixes.stream().anyMatch(prefix -> sectionName.startsWith(prefix))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a {@link List} of {@link MemoryBlock}s that match the given {@link SwiftSection}
|
* Gets a {@link List} of {@link MemoryBlock}s that match the given {@link SwiftSection}
|
||||||
*
|
*
|
||||||
|
|||||||
+3
-2
@@ -20,7 +20,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.app.util.bin.BinaryReader;
|
import ghidra.app.util.bin.BinaryReader;
|
||||||
import ghidra.app.util.bin.format.swift.SwiftStructure;
|
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
|
||||||
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
@@ -30,7 +30,7 @@ import ghidra.util.exception.DuplicateNameException;
|
|||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
|
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
|
||||||
*/
|
*/
|
||||||
public final class AssociatedTypeDescriptor implements SwiftStructure {
|
public final class AssociatedTypeDescriptor extends SwiftTypeMetadataStructure {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The size (in bytes) of an {@link AssociatedTypeDescriptor} structure
|
* The size (in bytes) of an {@link AssociatedTypeDescriptor} structure
|
||||||
@@ -51,6 +51,7 @@ public final class AssociatedTypeDescriptor implements SwiftStructure {
|
|||||||
* @throws IOException if there was an IO-related problem creating the structure
|
* @throws IOException if there was an IO-related problem creating the structure
|
||||||
*/
|
*/
|
||||||
public AssociatedTypeDescriptor(BinaryReader reader) throws IOException {
|
public AssociatedTypeDescriptor(BinaryReader reader) throws IOException {
|
||||||
|
super(reader.getPointerIndex());
|
||||||
conformingTypeName = reader.readNext(SwiftUtils::relativeString);
|
conformingTypeName = reader.readNext(SwiftUtils::relativeString);
|
||||||
protocolTypeName = reader.readNext(SwiftUtils::relativeString);
|
protocolTypeName = reader.readNext(SwiftUtils::relativeString);
|
||||||
numAssociatedTypes = reader.readNextInt();
|
numAssociatedTypes = reader.readNextInt();
|
||||||
|
|||||||
+3
-2
@@ -18,7 +18,7 @@ package ghidra.app.util.bin.format.swift.types;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import ghidra.app.util.bin.BinaryReader;
|
import ghidra.app.util.bin.BinaryReader;
|
||||||
import ghidra.app.util.bin.format.swift.SwiftStructure;
|
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
|
||||||
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
@@ -28,7 +28,7 @@ import ghidra.util.exception.DuplicateNameException;
|
|||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
|
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
|
||||||
*/
|
*/
|
||||||
public final class AssociatedTypeRecord implements SwiftStructure {
|
public final class AssociatedTypeRecord extends SwiftTypeMetadataStructure {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The size (in bytes) of an {@link AssociatedTypeRecord} structure
|
* The size (in bytes) of an {@link AssociatedTypeRecord} structure
|
||||||
@@ -45,6 +45,7 @@ public final class AssociatedTypeRecord implements SwiftStructure {
|
|||||||
* @throws IOException if there was an IO-related problem creating the structure
|
* @throws IOException if there was an IO-related problem creating the structure
|
||||||
*/
|
*/
|
||||||
public AssociatedTypeRecord(BinaryReader reader) throws IOException {
|
public AssociatedTypeRecord(BinaryReader reader) throws IOException {
|
||||||
|
super(reader.getPointerIndex());
|
||||||
name = reader.readNext(SwiftUtils::relativeString);
|
name = reader.readNext(SwiftUtils::relativeString);
|
||||||
substitutedTypeName = reader.readNext(SwiftUtils::relativeString);
|
substitutedTypeName = reader.readNext(SwiftUtils::relativeString);
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -18,7 +18,8 @@ package ghidra.app.util.bin.format.swift.types;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import ghidra.app.util.bin.BinaryReader;
|
import ghidra.app.util.bin.BinaryReader;
|
||||||
import ghidra.app.util.bin.format.swift.*;
|
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
|
||||||
|
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ import ghidra.util.exception.DuplicateNameException;
|
|||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
|
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
|
||||||
*/
|
*/
|
||||||
public final class BuiltinTypeDescriptor implements SwiftStructure {
|
public final class BuiltinTypeDescriptor extends SwiftTypeMetadataStructure {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The size (in bytes) of a {@link BuiltinTypeDescriptor} structure
|
* The size (in bytes) of a {@link BuiltinTypeDescriptor} structure
|
||||||
@@ -47,6 +48,7 @@ public final class BuiltinTypeDescriptor implements SwiftStructure {
|
|||||||
* @throws IOException if there was an IO-related problem creating the structure
|
* @throws IOException if there was an IO-related problem creating the structure
|
||||||
*/
|
*/
|
||||||
public BuiltinTypeDescriptor(BinaryReader reader) throws IOException {
|
public BuiltinTypeDescriptor(BinaryReader reader) throws IOException {
|
||||||
|
super(reader.getPointerIndex());
|
||||||
typeName = reader.readNext(SwiftUtils::relativeString);
|
typeName = reader.readNext(SwiftUtils::relativeString);
|
||||||
size = reader.readNextInt();
|
size = reader.readNextInt();
|
||||||
alignmentAndFlags = reader.readNextInt();
|
alignmentAndFlags = reader.readNextInt();
|
||||||
|
|||||||
+4
-5
@@ -20,10 +20,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.app.util.bin.BinaryReader;
|
import ghidra.app.util.bin.BinaryReader;
|
||||||
import ghidra.app.util.bin.format.swift.SwiftStructure;
|
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
|
||||||
import ghidra.program.model.data.CategoryPath;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.data.DataType;
|
|
||||||
import ghidra.program.model.data.StructureDataType;
|
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,7 +29,7 @@ import ghidra.util.exception.DuplicateNameException;
|
|||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
|
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
|
||||||
*/
|
*/
|
||||||
public final class CaptureDescriptor implements SwiftStructure {
|
public final class CaptureDescriptor extends SwiftTypeMetadataStructure {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The size (in bytes) of a {@link CaptureDescriptor} structure
|
* The size (in bytes) of a {@link CaptureDescriptor} structure
|
||||||
@@ -52,6 +50,7 @@ public final class CaptureDescriptor implements SwiftStructure {
|
|||||||
* @throws IOException if there was an IO-related problem creating the structure
|
* @throws IOException if there was an IO-related problem creating the structure
|
||||||
*/
|
*/
|
||||||
public CaptureDescriptor(BinaryReader reader) throws IOException {
|
public CaptureDescriptor(BinaryReader reader) throws IOException {
|
||||||
|
super(reader.getPointerIndex());
|
||||||
numCaptureTypes = reader.readNextInt();
|
numCaptureTypes = reader.readNextInt();
|
||||||
numMetadataSources = reader.readNextInt();
|
numMetadataSources = reader.readNextInt();
|
||||||
numBindings = reader.readNextInt();
|
numBindings = reader.readNextInt();
|
||||||
|
|||||||
+4
-2
@@ -18,7 +18,8 @@ package ghidra.app.util.bin.format.swift.types;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import ghidra.app.util.bin.BinaryReader;
|
import ghidra.app.util.bin.BinaryReader;
|
||||||
import ghidra.app.util.bin.format.swift.*;
|
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
|
||||||
|
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ import ghidra.util.exception.DuplicateNameException;
|
|||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
|
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
|
||||||
*/
|
*/
|
||||||
public final class CaptureTypeRecord implements SwiftStructure {
|
public final class CaptureTypeRecord extends SwiftTypeMetadataStructure {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The size (in bytes) of a {@link CaptureTypeRecord} structure
|
* The size (in bytes) of a {@link CaptureTypeRecord} structure
|
||||||
@@ -43,6 +44,7 @@ public final class CaptureTypeRecord implements SwiftStructure {
|
|||||||
* @throws IOException if there was an IO-related problem creating the structure
|
* @throws IOException if there was an IO-related problem creating the structure
|
||||||
*/
|
*/
|
||||||
public CaptureTypeRecord(BinaryReader reader) throws IOException {
|
public CaptureTypeRecord(BinaryReader reader) throws IOException {
|
||||||
|
super(reader.getPointerIndex());
|
||||||
mangledTypeName = reader.readNext(SwiftUtils::relativeString);
|
mangledTypeName = reader.readNext(SwiftUtils::relativeString);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -18,7 +18,7 @@ package ghidra.app.util.bin.format.swift.types;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import ghidra.app.util.bin.BinaryReader;
|
import ghidra.app.util.bin.BinaryReader;
|
||||||
import ghidra.app.util.bin.format.swift.SwiftStructure;
|
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
|
||||||
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
@@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
|
|||||||
/**
|
/**
|
||||||
* Represents a Swift entry point
|
* Represents a Swift entry point
|
||||||
*/
|
*/
|
||||||
public final class EntryPoint implements SwiftStructure {
|
public final class EntryPoint extends SwiftTypeMetadataStructure {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The size (in bytes) of an {@link EntryPoint} structure
|
* The size (in bytes) of an {@link EntryPoint} structure
|
||||||
@@ -42,6 +42,7 @@ public final class EntryPoint implements SwiftStructure {
|
|||||||
* @throws IOException if there was an IO-related problem creating the structure
|
* @throws IOException if there was an IO-related problem creating the structure
|
||||||
*/
|
*/
|
||||||
public EntryPoint(BinaryReader reader) throws IOException {
|
public EntryPoint(BinaryReader reader) throws IOException {
|
||||||
|
super(reader.getPointerIndex());
|
||||||
entryPoint = reader.readNextInt();
|
entryPoint = reader.readNextInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -20,7 +20,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.app.util.bin.BinaryReader;
|
import ghidra.app.util.bin.BinaryReader;
|
||||||
import ghidra.app.util.bin.format.swift.*;
|
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
|
||||||
|
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
|
|
||||||
@@ -29,7 +30,7 @@ import ghidra.util.exception.DuplicateNameException;
|
|||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
|
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
|
||||||
*/
|
*/
|
||||||
public final class FieldDescriptor implements SwiftStructure {
|
public final class FieldDescriptor extends SwiftTypeMetadataStructure {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The size (in bytes) of a {@link FieldDescriptor} structure
|
* The size (in bytes) of a {@link FieldDescriptor} structure
|
||||||
@@ -51,6 +52,7 @@ public final class FieldDescriptor implements SwiftStructure {
|
|||||||
* @throws IOException if there was an IO-related problem creating the structure
|
* @throws IOException if there was an IO-related problem creating the structure
|
||||||
*/
|
*/
|
||||||
public FieldDescriptor(BinaryReader reader) throws IOException {
|
public FieldDescriptor(BinaryReader reader) throws IOException {
|
||||||
|
super(reader.getPointerIndex());
|
||||||
mangledTypeName = reader.readNext(SwiftUtils::relativeString);
|
mangledTypeName = reader.readNext(SwiftUtils::relativeString);
|
||||||
superclass = reader.readNextInt();
|
superclass = reader.readNextInt();
|
||||||
kind = reader.readNextUnsignedShort();
|
kind = reader.readNextUnsignedShort();
|
||||||
|
|||||||
+4
-2
@@ -18,7 +18,8 @@ package ghidra.app.util.bin.format.swift.types;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import ghidra.app.util.bin.BinaryReader;
|
import ghidra.app.util.bin.BinaryReader;
|
||||||
import ghidra.app.util.bin.format.swift.*;
|
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
|
||||||
|
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ import ghidra.util.exception.DuplicateNameException;
|
|||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
|
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
|
||||||
*/
|
*/
|
||||||
public final class FieldRecord implements SwiftStructure {
|
public final class FieldRecord extends SwiftTypeMetadataStructure {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The size (in bytes) of a {@link FieldRecord} structure
|
* The size (in bytes) of a {@link FieldRecord} structure
|
||||||
@@ -45,6 +46,7 @@ public final class FieldRecord implements SwiftStructure {
|
|||||||
* @throws IOException if there was an IO-related problem creating the structure
|
* @throws IOException if there was an IO-related problem creating the structure
|
||||||
*/
|
*/
|
||||||
public FieldRecord(BinaryReader reader) throws IOException {
|
public FieldRecord(BinaryReader reader) throws IOException {
|
||||||
|
super(reader.getPointerIndex());
|
||||||
flags = reader.readNextInt();
|
flags = reader.readNextInt();
|
||||||
mangledTypeName = reader.readNext(SwiftUtils::relativeString);
|
mangledTypeName = reader.readNext(SwiftUtils::relativeString);
|
||||||
fieldName = reader.readNext(SwiftUtils::relativeString);
|
fieldName = reader.readNext(SwiftUtils::relativeString);
|
||||||
|
|||||||
+4
-2
@@ -18,7 +18,8 @@ package ghidra.app.util.bin.format.swift.types;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import ghidra.app.util.bin.BinaryReader;
|
import ghidra.app.util.bin.BinaryReader;
|
||||||
import ghidra.app.util.bin.format.swift.*;
|
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
|
||||||
|
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ import ghidra.util.exception.DuplicateNameException;
|
|||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
|
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
|
||||||
*/
|
*/
|
||||||
public final class MetadataSourceRecord implements SwiftStructure {
|
public final class MetadataSourceRecord extends SwiftTypeMetadataStructure {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The size (in bytes) of a {@link MetadataSourceRecord} structure
|
* The size (in bytes) of a {@link MetadataSourceRecord} structure
|
||||||
@@ -44,6 +45,7 @@ public final class MetadataSourceRecord implements SwiftStructure {
|
|||||||
* @throws IOException if there was an IO-related problem creating the structure
|
* @throws IOException if there was an IO-related problem creating the structure
|
||||||
*/
|
*/
|
||||||
public MetadataSourceRecord(BinaryReader reader) throws IOException {
|
public MetadataSourceRecord(BinaryReader reader) throws IOException {
|
||||||
|
super(reader.getPointerIndex());
|
||||||
mangledTypeName = reader.readNext(SwiftUtils::relativeString);
|
mangledTypeName = reader.readNext(SwiftUtils::relativeString);
|
||||||
mangledMetadataSource = reader.readNext(SwiftUtils::relativeString);
|
mangledMetadataSource = reader.readNext(SwiftUtils::relativeString);
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -18,7 +18,7 @@ package ghidra.app.util.bin.format.swift.types;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import ghidra.app.util.bin.BinaryReader;
|
import ghidra.app.util.bin.BinaryReader;
|
||||||
import ghidra.app.util.bin.format.swift.SwiftStructure;
|
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
|
||||||
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
@@ -28,7 +28,7 @@ import ghidra.util.exception.DuplicateNameException;
|
|||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
|
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/RemoteInspection/Records.h">swift/RemoteInspection/Records.h</a>
|
||||||
*/
|
*/
|
||||||
public final class MultiPayloadEnumDescriptor implements SwiftStructure {
|
public final class MultiPayloadEnumDescriptor extends SwiftTypeMetadataStructure {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The size (in bytes) of a {@link MultiPayloadEnumDescriptor} structure. This size does not
|
* The size (in bytes) of a {@link MultiPayloadEnumDescriptor} structure. This size does not
|
||||||
@@ -48,6 +48,7 @@ public final class MultiPayloadEnumDescriptor implements SwiftStructure {
|
|||||||
* @throws IOException if there was an IO-related problem creating the structure
|
* @throws IOException if there was an IO-related problem creating the structure
|
||||||
*/
|
*/
|
||||||
public MultiPayloadEnumDescriptor(BinaryReader reader) throws IOException {
|
public MultiPayloadEnumDescriptor(BinaryReader reader) throws IOException {
|
||||||
|
super(reader.getPointerIndex());
|
||||||
typeName = reader.readNext(SwiftUtils::relativeString);
|
typeName = reader.readNext(SwiftUtils::relativeString);
|
||||||
int size = (reader.readNextInt() >> 16) & 0xffff;
|
int size = (reader.readNextInt() >> 16) & 0xffff;
|
||||||
reader.setPointerIndex(reader.getPointerIndex() - 4);
|
reader.setPointerIndex(reader.getPointerIndex() - 4);
|
||||||
|
|||||||
+1
-3
@@ -19,9 +19,7 @@ import java.io.IOException;
|
|||||||
|
|
||||||
import ghidra.app.util.bin.BinaryReader;
|
import ghidra.app.util.bin.BinaryReader;
|
||||||
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
||||||
import ghidra.program.model.data.CategoryPath;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.data.DataType;
|
|
||||||
import ghidra.program.model.data.StructureDataType;
|
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+9
-2
@@ -18,7 +18,8 @@ package ghidra.app.util.bin.format.swift.types;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import ghidra.app.util.bin.BinaryReader;
|
import ghidra.app.util.bin.BinaryReader;
|
||||||
import ghidra.app.util.bin.format.swift.*;
|
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
|
||||||
|
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
|
|
||||||
@@ -27,7 +28,12 @@ import ghidra.util.exception.DuplicateNameException;
|
|||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/ABI/Metadata.h">swift/ABI/Metadata.h</a>
|
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/ABI/Metadata.h">swift/ABI/Metadata.h</a>
|
||||||
*/
|
*/
|
||||||
public class TargetContextDescriptor implements SwiftStructure {
|
public class TargetContextDescriptor extends SwiftTypeMetadataStructure {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size (in bytes) of a {@link TargetContextDescriptor} structure
|
||||||
|
*/
|
||||||
|
public static final int SIZE = 8;
|
||||||
|
|
||||||
private int flags;
|
private int flags;
|
||||||
private int parent;
|
private int parent;
|
||||||
@@ -39,6 +45,7 @@ public class TargetContextDescriptor implements SwiftStructure {
|
|||||||
* @throws IOException if there was an IO-related problem creating the structure
|
* @throws IOException if there was an IO-related problem creating the structure
|
||||||
*/
|
*/
|
||||||
public TargetContextDescriptor(BinaryReader reader) throws IOException {
|
public TargetContextDescriptor(BinaryReader reader) throws IOException {
|
||||||
|
super(reader.getPointerIndex());
|
||||||
flags = reader.readNextInt();
|
flags = reader.readNextInt();
|
||||||
parent = reader.readNextInt();
|
parent = reader.readNextInt();
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -18,7 +18,8 @@ package ghidra.app.util.bin.format.swift.types;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import ghidra.app.util.bin.BinaryReader;
|
import ghidra.app.util.bin.BinaryReader;
|
||||||
import ghidra.app.util.bin.format.swift.*;
|
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
|
||||||
|
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ import ghidra.util.exception.DuplicateNameException;
|
|||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/ABI/Metadata.h">swift/ABI/Metadata.h</a>
|
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/ABI/Metadata.h">swift/ABI/Metadata.h</a>
|
||||||
*/
|
*/
|
||||||
public final class TargetProtocolConformanceDescriptor implements SwiftStructure {
|
public final class TargetProtocolConformanceDescriptor extends SwiftTypeMetadataStructure {
|
||||||
|
|
||||||
private int protocolDescriptor;
|
private int protocolDescriptor;
|
||||||
private int nominalTypeDescriptor;
|
private int nominalTypeDescriptor;
|
||||||
@@ -41,6 +42,7 @@ public final class TargetProtocolConformanceDescriptor implements SwiftStructure
|
|||||||
* @throws IOException if there was an IO-related problem creating the structure
|
* @throws IOException if there was an IO-related problem creating the structure
|
||||||
*/
|
*/
|
||||||
public TargetProtocolConformanceDescriptor(BinaryReader reader) throws IOException {
|
public TargetProtocolConformanceDescriptor(BinaryReader reader) throws IOException {
|
||||||
|
super(reader.getPointerIndex());
|
||||||
protocolDescriptor = reader.readNextInt();
|
protocolDescriptor = reader.readNextInt();
|
||||||
nominalTypeDescriptor = reader.readNextInt();
|
nominalTypeDescriptor = reader.readNextInt();
|
||||||
protocolWitnessTable = reader.readNextInt();
|
protocolWitnessTable = reader.readNextInt();
|
||||||
|
|||||||
+15
@@ -16,6 +16,7 @@
|
|||||||
package ghidra.app.util.bin.format.swift.types;
|
package ghidra.app.util.bin.format.swift.types;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import ghidra.app.util.bin.BinaryReader;
|
import ghidra.app.util.bin.BinaryReader;
|
||||||
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
||||||
@@ -73,6 +74,20 @@ public class TargetTypeContextDescriptor extends TargetContextDescriptor {
|
|||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets this {@link TargetTypeContextDescriptor}'s {@link FieldDescriptor}
|
||||||
|
*
|
||||||
|
* @param fieldDescriptors A {@link Map} of {@link FieldDescriptor}'s keyed by their base
|
||||||
|
* addresses
|
||||||
|
* @return This {@link TargetTypeContextDescriptor}'s {@link FieldDescriptor}, or null if it
|
||||||
|
* doesn't have one
|
||||||
|
*/
|
||||||
|
public FieldDescriptor getFieldDescriptor(Map<Long, FieldDescriptor> fieldDescriptors) {
|
||||||
|
FieldDescriptor fieldDescriptor =
|
||||||
|
fieldDescriptors.get(getBase() + TargetContextDescriptor.SIZE + 8 + fields);
|
||||||
|
return fieldDescriptor != null ? fieldDescriptor : null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getStructureName() {
|
public String getStructureName() {
|
||||||
return getMyStructureName();
|
return getMyStructureName();
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ public class DemangledDataType extends DemangledType {
|
|||||||
public final static String LONG = "long";
|
public final static String LONG = "long";
|
||||||
public final static String LONG_LONG = "long long";
|
public final static String LONG_LONG = "long long";
|
||||||
public final static String FLOAT = "float";
|
public final static String FLOAT = "float";
|
||||||
|
public final static String FLOAT2 = "float2";
|
||||||
public final static String DOUBLE = "double";
|
public final static String DOUBLE = "double";
|
||||||
public final static String INT8 = "__int8";
|
public final static String INT8 = "__int8";
|
||||||
public final static String INT16 = "__int16";
|
public final static String INT16 = "__int16";
|
||||||
@@ -94,7 +95,7 @@ public class DemangledDataType extends DemangledType {
|
|||||||
|
|
||||||
public final static String[] PRIMITIVES =
|
public final static String[] PRIMITIVES =
|
||||||
{ VOID, BOOL, CHAR, WCHAR_T, WCHAR16, WCHAR32, SHORT, INT, INT0_T, LONG,
|
{ VOID, BOOL, CHAR, WCHAR_T, WCHAR16, WCHAR32, SHORT, INT, INT0_T, LONG,
|
||||||
LONG_LONG, FLOAT, DOUBLE, INT128, FLOAT128, LONG_DOUBLE, };
|
LONG_LONG, FLOAT, FLOAT2, DOUBLE, INT128, FLOAT128, LONG_DOUBLE, };
|
||||||
|
|
||||||
private int arrayDimensions = 0;
|
private int arrayDimensions = 0;
|
||||||
private boolean isClass;
|
private boolean isClass;
|
||||||
@@ -293,6 +294,9 @@ public class DemangledDataType extends DemangledType {
|
|||||||
else if (FLOAT.equals(name)) {
|
else if (FLOAT.equals(name)) {
|
||||||
dt = FloatDataType.dataType;
|
dt = FloatDataType.dataType;
|
||||||
}
|
}
|
||||||
|
else if (FLOAT2.equals(name)) {
|
||||||
|
dt = Float2DataType.dataType;
|
||||||
|
}
|
||||||
else if (FLOAT128.equals(name)) {
|
else if (FLOAT128.equals(name)) {
|
||||||
dt = new TypedefDataType(FLOAT128, Float16DataType.dataType);
|
dt = new TypedefDataType(FLOAT128, Float16DataType.dataType);
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-15
@@ -54,7 +54,7 @@ public class DemangledFunction extends DemangledObject {
|
|||||||
protected DemangledDataType returnType;
|
protected DemangledDataType returnType;
|
||||||
protected String callingConvention;// __cdecl, __thiscall, etc.
|
protected String callingConvention;// __cdecl, __thiscall, etc.
|
||||||
protected boolean thisPassedOnStack = true;
|
protected boolean thisPassedOnStack = true;
|
||||||
protected List<DemangledDataType> parameters = new ArrayList<>();
|
protected List<DemangledParameter> parameters = new ArrayList<>();
|
||||||
protected DemangledTemplate template;
|
protected DemangledTemplate template;
|
||||||
protected boolean isOverloadedOperator = false;
|
protected boolean isOverloadedOperator = false;
|
||||||
protected SourceType signatureSourceType = SourceType.ANALYSIS;
|
protected SourceType signatureSourceType = SourceType.ANALYSIS;
|
||||||
@@ -140,11 +140,15 @@ public class DemangledFunction extends DemangledObject {
|
|||||||
this.isOverloadedOperator = isOverloadedOperator;
|
this.isOverloadedOperator = isOverloadedOperator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addParameter(DemangledDataType parameter) {
|
public void addParameter(DemangledParameter parameter) {
|
||||||
parameters.add(parameter);
|
parameters.add(parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DemangledDataType> getParameters() {
|
public void addParameters(List<DemangledParameter> params) {
|
||||||
|
parameters.addAll(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DemangledParameter> getParameters() {
|
||||||
return new ArrayList<>(parameters);
|
return new ArrayList<>(parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,7 +327,7 @@ public class DemangledFunction extends DemangledObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void addParameters(StringBuilder buffer, boolean format) {
|
protected void addParameters(StringBuilder buffer, boolean format) {
|
||||||
Iterator<DemangledDataType> paramIterator = parameters.iterator();
|
Iterator<DemangledParameter> paramIterator = parameters.iterator();
|
||||||
buffer.append('(');
|
buffer.append('(');
|
||||||
int padLength = format ? buffer.length() : 0;
|
int padLength = format ? buffer.length() : 0;
|
||||||
String pad = StringUtils.rightPad("", padLength);
|
String pad = StringUtils.rightPad("", padLength);
|
||||||
@@ -332,7 +336,11 @@ public class DemangledFunction extends DemangledObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (paramIterator.hasNext()) {
|
while (paramIterator.hasNext()) {
|
||||||
buffer.append(paramIterator.next().getSignature());
|
DemangledParameter param = paramIterator.next();
|
||||||
|
buffer.append(param.getType().getSignature());
|
||||||
|
if (param.getLabel() != null) {
|
||||||
|
buffer.append(" " + param.getLabel());
|
||||||
|
}
|
||||||
if (paramIterator.hasNext()) {
|
if (paramIterator.hasNext()) {
|
||||||
buffer.append(',');
|
buffer.append(',');
|
||||||
if (format) {
|
if (format) {
|
||||||
@@ -353,9 +361,9 @@ public class DemangledFunction extends DemangledObject {
|
|||||||
public String getParameterString() {
|
public String getParameterString() {
|
||||||
StringBuffer buffer = new StringBuffer();
|
StringBuffer buffer = new StringBuffer();
|
||||||
buffer.append('(');
|
buffer.append('(');
|
||||||
Iterator<DemangledDataType> dditer = parameters.iterator();
|
Iterator<DemangledParameter> dditer = parameters.iterator();
|
||||||
while (dditer.hasNext()) {
|
while (dditer.hasNext()) {
|
||||||
buffer.append(dditer.next().getSignature());
|
buffer.append(dditer.next().getType().getSignature());
|
||||||
if (dditer.hasNext()) {
|
if (dditer.hasNext()) {
|
||||||
buffer.append(',');
|
buffer.append(',');
|
||||||
}
|
}
|
||||||
@@ -576,13 +584,13 @@ public class DemangledFunction extends DemangledObject {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DemangledDataType lastType = parameters.get(parameters.size() - 1);
|
DemangledDataType lastType = parameters.get(parameters.size() - 1).getType();
|
||||||
return lastType.isVarArgs();
|
return lastType.isVarArgs();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasVoidParams() {
|
private boolean hasVoidParams() {
|
||||||
if (parameters.size() == 1) {
|
if (parameters.size() == 1) {
|
||||||
DemangledDataType ddt = parameters.get(0);
|
DemangledDataType ddt = parameters.get(0).getType();
|
||||||
return ddt.isVoid() && !ddt.isPointer();
|
return ddt.isVoid() && !ddt.isPointer();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -634,7 +642,7 @@ public class DemangledFunction extends DemangledObject {
|
|||||||
// If returnType is null check for constructor or destructor names
|
// If returnType is null check for constructor or destructor names
|
||||||
if (THIS_CALL.equals(function.getCallingConventionName())) {
|
if (THIS_CALL.equals(function.getCallingConventionName())) {
|
||||||
String n = getName();
|
String n = getName();
|
||||||
if (n.equals(namespace.getName())) {
|
if (namespace != null && n.equals(namespace.getName())) {
|
||||||
// constructor
|
// constructor
|
||||||
return DataType.DEFAULT;
|
return DataType.DEFAULT;
|
||||||
}
|
}
|
||||||
@@ -698,17 +706,18 @@ public class DemangledFunction extends DemangledObject {
|
|||||||
private List<ParameterDefinitionImpl> convertMangledToParamDef(Program program) {
|
private List<ParameterDefinitionImpl> convertMangledToParamDef(Program program) {
|
||||||
|
|
||||||
List<ParameterDefinitionImpl> args = new ArrayList<>();
|
List<ParameterDefinitionImpl> args = new ArrayList<>();
|
||||||
for (DemangledDataType param : parameters) {
|
for (DemangledParameter param : parameters) {
|
||||||
// stop when a void parameter is hit. This probably the only defined parameter.
|
// stop when a void parameter is hit. This probably the only defined parameter.
|
||||||
if (param.isVoid() && !param.isPointer()) {
|
DemangledDataType type = param.getType();
|
||||||
|
if (type.isVoid() && !type.isPointer()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (param.isVarArgs()) {
|
if (type.isVarArgs()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataType dt = param.getDataType(program.getDataTypeManager());
|
DataType dt = type.getDataType(program.getDataTypeManager());
|
||||||
args.add(new ParameterDefinitionImpl(null, dt, null));
|
args.add(new ParameterDefinitionImpl(param.getLabel(), dt, null));
|
||||||
}
|
}
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.util.demangler;
|
||||||
|
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.model.symbol.Symbol;
|
||||||
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class to represent a {@link DemangledObject} that should get represented as a Ghidra label
|
||||||
|
*/
|
||||||
|
public class DemangledLabel extends DemangledObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link DemangledLabel}
|
||||||
|
*
|
||||||
|
* @param mangled The mangled string
|
||||||
|
* @param originalDemangled The natively demangled string
|
||||||
|
* @param name The label name
|
||||||
|
*/
|
||||||
|
public DemangledLabel(String mangled, String originalDemangled, String name) {
|
||||||
|
super(mangled, originalDemangled);
|
||||||
|
setName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applyTo(Program program, Address address, DemanglerOptions options,
|
||||||
|
TaskMonitor monitor) throws Exception {
|
||||||
|
Symbol symbol = applyDemangledName(address, true, false, program);
|
||||||
|
return symbol != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSignature(boolean format) {
|
||||||
|
return originalDemangled;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.util.demangler;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An convenience {@link Demangled} object that holds a {@link List} of other
|
||||||
|
* {@link Demangled} objects
|
||||||
|
*/
|
||||||
|
public class DemangledList extends ArrayList<Demangled> implements Demangled {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link DemangledList} and adds the given {@link List} to it
|
||||||
|
*
|
||||||
|
* @param demangledList The {@link List} of {@link Demangled} objects to add
|
||||||
|
*/
|
||||||
|
public DemangledList(List<Demangled> demangledList) {
|
||||||
|
super(demangledList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return true if this contains any <code>null</code> elements; otherwise, false}
|
||||||
|
*/
|
||||||
|
public boolean containsNull() {
|
||||||
|
return stream().anyMatch(e -> e == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMangledString() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOriginalDemangled() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setName(String name) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDemangledName() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Demangled getNamespace() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNamespace(Demangled ns) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNamespaceString() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNamespaceName() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSignature() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.util.demangler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class to represent a demangled function parameter.
|
||||||
|
* <p>
|
||||||
|
* This extends {@link DemangledDataType} in order to associate an optional parameter label with
|
||||||
|
* its data type.
|
||||||
|
*/
|
||||||
|
public class DemangledParameter {
|
||||||
|
|
||||||
|
private DemangledDataType type;
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link DemangledParameter} with the given type and no label
|
||||||
|
*
|
||||||
|
* @param type The parameter type
|
||||||
|
*/
|
||||||
|
public DemangledParameter(DemangledDataType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the parameter's type}
|
||||||
|
*/
|
||||||
|
public DemangledDataType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the parameter's label (could be null)}
|
||||||
|
*/
|
||||||
|
public String getLabel() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the parameter's label
|
||||||
|
*
|
||||||
|
* @param label The label (null for no label)
|
||||||
|
*/
|
||||||
|
public void setLabel(String label) {
|
||||||
|
this.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
String ret = type.toString();
|
||||||
|
if (label != null) {
|
||||||
|
ret += " " + label;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.util.demangler;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ghidra.program.model.data.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class to represent a demangled structure
|
||||||
|
*/
|
||||||
|
public class DemangledStructure extends DemangledDataType {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A field of a {@link DemangledStructure}
|
||||||
|
*
|
||||||
|
* @param name The field name
|
||||||
|
* @param description The field description
|
||||||
|
* @param type The field {@link DemangledDataType type}
|
||||||
|
*/
|
||||||
|
public record Field(String name, String description, DemangledDataType type) {}
|
||||||
|
|
||||||
|
private List<Field> fields = new ArrayList<>();
|
||||||
|
private String categoryPath;
|
||||||
|
private boolean packed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link DemangledStructure}
|
||||||
|
*
|
||||||
|
* @param mangled The mangled string
|
||||||
|
* @param originalDemangled The natively demangled string
|
||||||
|
* @param name The structure name
|
||||||
|
* @param categoryPath The structure category path
|
||||||
|
* @param packed True if the structure should be packed; otherwise, false
|
||||||
|
*/
|
||||||
|
public DemangledStructure(String mangled, String originalDemangled, String name,
|
||||||
|
String categoryPath, boolean packed) {
|
||||||
|
super(mangled, originalDemangled, name);
|
||||||
|
setStruct();
|
||||||
|
this.categoryPath = categoryPath;
|
||||||
|
this.packed = packed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new field to the structure. The field will not have a description.
|
||||||
|
*
|
||||||
|
* @param name The field name
|
||||||
|
* @param type The field {@link DemangledDataType type}
|
||||||
|
*/
|
||||||
|
public void addField(String name, DemangledDataType type) {
|
||||||
|
fields.add(new Field(name, null, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new field to the structure
|
||||||
|
*
|
||||||
|
* @param name The field name
|
||||||
|
* @param description The field description
|
||||||
|
* @param type The field {@link DemangledDataType type}
|
||||||
|
*/
|
||||||
|
public void addField(String name, String description, DemangledDataType type) {
|
||||||
|
fields.add(new Field(name, description, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link List} of {@link Field}s
|
||||||
|
*
|
||||||
|
* @return The {@link List} of {@link Field}s
|
||||||
|
*/
|
||||||
|
public List<Field> getFields() {
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataType getDataType(DataTypeManager dataTypeManager) {
|
||||||
|
String name = getName();
|
||||||
|
if (name == null) {
|
||||||
|
return DataType.DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
StructureDataType struct = new StructureDataType(name, 0, dataTypeManager);
|
||||||
|
for (Field field : fields) {
|
||||||
|
struct.add(field.type().getDataType(dataTypeManager), field.name(),
|
||||||
|
field.description());
|
||||||
|
}
|
||||||
|
struct.setPackingEnabled(packed);
|
||||||
|
struct.setCategoryPath(new CategoryPath(categoryPath));
|
||||||
|
return struct;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@ import ghidra.app.util.Option;
|
|||||||
import ghidra.app.util.bin.ByteProvider;
|
import ghidra.app.util.bin.ByteProvider;
|
||||||
import ghidra.app.util.bin.ByteProviderWrapper;
|
import ghidra.app.util.bin.ByteProviderWrapper;
|
||||||
import ghidra.app.util.bin.format.macho.*;
|
import ghidra.app.util.bin.format.macho.*;
|
||||||
|
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
||||||
import ghidra.app.util.bin.format.ubi.*;
|
import ghidra.app.util.bin.format.ubi.*;
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.formats.gfilesystem.*;
|
import ghidra.formats.gfilesystem.*;
|
||||||
@@ -60,7 +61,13 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
|
|||||||
MachHeader machHeader = new MachHeader(provider);
|
MachHeader machHeader = new MachHeader(provider);
|
||||||
String magic =
|
String magic =
|
||||||
CpuTypes.getMagicString(machHeader.getCpuType(), machHeader.getCpuSubType());
|
CpuTypes.getMagicString(machHeader.getCpuType(), machHeader.getCpuSubType());
|
||||||
List<QueryResult> results = QueryOpinionService.query(MACH_O_NAME, magic, null);
|
List<String> sectionNames = machHeader.parseSegments()
|
||||||
|
.stream()
|
||||||
|
.flatMap(seg -> seg.getSections().stream())
|
||||||
|
.map(section -> section.getSectionName())
|
||||||
|
.toList();
|
||||||
|
String compiler = SwiftUtils.isSwift(sectionNames) ? "swift" : null;
|
||||||
|
List<QueryResult> results = QueryOpinionService.query(MACH_O_NAME, magic, compiler);
|
||||||
for (QueryResult result : results) {
|
for (QueryResult result : results) {
|
||||||
loadSpecs.add(new LoadSpec(this, machHeader.getImageBase(), result));
|
loadSpecs.add(new LoadSpec(this, machHeader.getImageBase(), result));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import ghidra.app.util.bin.format.pe.ImageCor20Header.ImageCor20Flags;
|
|||||||
import ghidra.app.util.bin.format.pe.PortableExecutable.SectionLayout;
|
import ghidra.app.util.bin.format.pe.PortableExecutable.SectionLayout;
|
||||||
import ghidra.app.util.bin.format.pe.debug.DebugCOFFSymbol;
|
import ghidra.app.util.bin.format.pe.debug.DebugCOFFSymbol;
|
||||||
import ghidra.app.util.bin.format.pe.debug.DebugDirectoryParser;
|
import ghidra.app.util.bin.format.pe.debug.DebugDirectoryParser;
|
||||||
|
import ghidra.app.util.bin.format.swift.SwiftUtils;
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.framework.model.DomainObject;
|
import ghidra.framework.model.DomainObject;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
@@ -904,6 +905,7 @@ public class PeLoader extends AbstractPeDebugLoader {
|
|||||||
CLI("cli", "cli"),
|
CLI("cli", "cli"),
|
||||||
Rustc(RustConstants.RUST_COMPILER, RustConstants.RUST_COMPILER),
|
Rustc(RustConstants.RUST_COMPILER, RustConstants.RUST_COMPILER),
|
||||||
GOLANG("golang", "golang"),
|
GOLANG("golang", "golang"),
|
||||||
|
Swift("swift", "swift"),
|
||||||
Unknown("unknown", "unknown"),
|
Unknown("unknown", "unknown"),
|
||||||
|
|
||||||
// The following values represent the presence of ambiguous indicators
|
// The following values represent the presence of ambiguous indicators
|
||||||
@@ -969,6 +971,15 @@ public class PeLoader extends AbstractPeDebugLoader {
|
|||||||
}
|
}
|
||||||
return CompilerEnum.Rustc;
|
return CompilerEnum.Rustc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for Swift
|
||||||
|
List<String> sectionNames =
|
||||||
|
Arrays.stream(pe.getNTHeader().getFileHeader().getSectionHeaders())
|
||||||
|
.map(section -> section.getName())
|
||||||
|
.toList();
|
||||||
|
if (SwiftUtils.isSwift(sectionNames)) {
|
||||||
|
return CompilerEnum.Swift;
|
||||||
|
}
|
||||||
|
|
||||||
// Check for managed code (.NET)
|
// Check for managed code (.NET)
|
||||||
if (pe.getNTHeader().getOptionalHeader().isCLI()) {
|
if (pe.getNTHeader().getOptionalHeader().isCLI()) {
|
||||||
|
|||||||
+17
-17
@@ -485,7 +485,7 @@ public class GnuDemanglerParser {
|
|||||||
//
|
//
|
||||||
setNameAndNamespace(function, simpleName);
|
setNameAndNamespace(function, simpleName);
|
||||||
|
|
||||||
for (DemangledDataType parameter : signatureParts.getParameters()) {
|
for (DemangledParameter parameter : signatureParts.getParameters()) {
|
||||||
function.addParameter(parameter);
|
function.addParameter(parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -630,9 +630,9 @@ public class GnuDemanglerParser {
|
|||||||
* Reason being, you need to take into account nested templates
|
* Reason being, you need to take into account nested templates
|
||||||
* and function pointers.
|
* and function pointers.
|
||||||
*/
|
*/
|
||||||
private List<DemangledDataType> parseParameters(String parameterString) {
|
private List<DemangledParameter> parseParameters(String parameterString) {
|
||||||
List<String> parameterStrings = tokenizeParameters(parameterString);
|
List<String> parameterStrings = tokenizeParameters(parameterString);
|
||||||
List<DemangledDataType> parameters = convertIntoParameters(parameterStrings);
|
List<DemangledParameter> parameters = convertIntoParameters(parameterStrings);
|
||||||
return parameters;
|
return parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -735,12 +735,12 @@ public class GnuDemanglerParser {
|
|||||||
* This method converts each parameter string into
|
* This method converts each parameter string into
|
||||||
* actual DemangledDataType objects.
|
* actual DemangledDataType objects.
|
||||||
*/
|
*/
|
||||||
private List<DemangledDataType> convertIntoParameters(List<String> parameterStrings) {
|
private List<DemangledParameter> convertIntoParameters(List<String> parameterStrings) {
|
||||||
List<DemangledDataType> parameters = new ArrayList<>();
|
List<DemangledParameter> parameters = new ArrayList<>();
|
||||||
|
|
||||||
for (String parameter : parameterStrings) {
|
for (String parameter : parameterStrings) {
|
||||||
DemangledDataType dt = parseParameter(parameter);
|
DemangledDataType dt = parseParameter(parameter);
|
||||||
parameters.add(dt);
|
parameters.add(new DemangledParameter(dt));
|
||||||
}
|
}
|
||||||
|
|
||||||
return parameters;
|
return parameters;
|
||||||
@@ -1311,10 +1311,10 @@ public class GnuDemanglerParser {
|
|||||||
contents = string.substring(1, string.length() - 1);
|
contents = string.substring(1, string.length() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<DemangledDataType> parameters = parseParameters(contents);
|
List<DemangledParameter> parameters = parseParameters(contents);
|
||||||
DemangledTemplate template = new DemangledTemplate();
|
DemangledTemplate template = new DemangledTemplate();
|
||||||
for (DemangledDataType parameter : parameters) {
|
for (DemangledParameter parameter : parameters) {
|
||||||
template.addParameter(parameter);
|
template.addParameter(parameter.getType());
|
||||||
}
|
}
|
||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
@@ -1399,16 +1399,16 @@ public class GnuDemanglerParser {
|
|||||||
return dfp;
|
return dfp;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DemangledFunctionPointer createFunctionPointer(String paramerterString,
|
private DemangledFunctionPointer createFunctionPointer(String parameterString,
|
||||||
String returnType) {
|
String returnType) {
|
||||||
|
|
||||||
List<DemangledDataType> parameters = parseParameters(paramerterString);
|
List<DemangledParameter> parameters = parseParameters(parameterString);
|
||||||
|
|
||||||
DemangledFunctionPointer dfp = new DemangledFunctionPointer(mangledSource, demangledSource);
|
DemangledFunctionPointer dfp = new DemangledFunctionPointer(mangledSource, demangledSource);
|
||||||
DemangledDataType returnDataType = parseReturnType(returnType);
|
DemangledDataType returnDataType = parseReturnType(returnType);
|
||||||
dfp.setReturnType(returnDataType);
|
dfp.setReturnType(returnDataType);
|
||||||
for (DemangledDataType parameter : parameters) {
|
for (DemangledParameter parameter : parameters) {
|
||||||
dfp.addParameter(parameter);
|
dfp.addParameter(parameter.getType());
|
||||||
}
|
}
|
||||||
return dfp;
|
return dfp;
|
||||||
}
|
}
|
||||||
@@ -1889,8 +1889,8 @@ public class GnuDemanglerParser {
|
|||||||
// operator itself could be in a class namespace
|
// operator itself could be in a class namespace
|
||||||
setNameAndNamespace(function, operatorText);
|
setNameAndNamespace(function, operatorText);
|
||||||
|
|
||||||
List<DemangledDataType> parameters = parseParameters(parametersText);
|
List<DemangledParameter> parameters = parseParameters(parametersText);
|
||||||
for (DemangledDataType parameter : parameters) {
|
for (DemangledParameter parameter : parameters) {
|
||||||
function.addParameter(parameter);
|
function.addParameter(parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2029,7 +2029,7 @@ public class GnuDemanglerParser {
|
|||||||
private String name;
|
private String name;
|
||||||
private String rawParameterPrefix;
|
private String rawParameterPrefix;
|
||||||
|
|
||||||
private List<DemangledDataType> parameters;
|
private List<DemangledParameter> parameters;
|
||||||
|
|
||||||
FunctionSignatureParts(String signatureString) {
|
FunctionSignatureParts(String signatureString) {
|
||||||
|
|
||||||
@@ -2077,7 +2077,7 @@ public class GnuDemanglerParser {
|
|||||||
return isFunction;
|
return isFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<DemangledDataType> getParameters() {
|
List<DemangledParameter> getParameters() {
|
||||||
return parameters;
|
return parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+48
-47
@@ -54,9 +54,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||||||
assertName(object, "bob");
|
assertName(object, "bob");
|
||||||
|
|
||||||
DemangledFunction function = (DemangledFunction) object;
|
DemangledFunction function = (DemangledFunction) object;
|
||||||
List<DemangledDataType> parameters = function.getParameters();
|
List<DemangledParameter> parameters = function.getParameters();
|
||||||
assertEquals(1, parameters.size());
|
assertEquals(1, parameters.size());
|
||||||
DemangledDataType p1 = parameters.get(0);
|
DemangledDataType p1 = parameters.get(0).getType();
|
||||||
assertEquals("bob(int const[8] (*) [12])", p1.getOriginalDemangled());
|
assertEquals("bob(int const[8] (*) [12])", p1.getOriginalDemangled());
|
||||||
assertEquals("undefined bob(int const *[])", object.getSignature(false));
|
assertEquals("undefined bob(int const *[])", object.getSignature(false));
|
||||||
}
|
}
|
||||||
@@ -113,9 +113,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||||||
DemangledObject object = parser.parse("fake", "Layout::graphNew(short[][][][], char*)");
|
DemangledObject object = parser.parse("fake", "Layout::graphNew(short[][][][], char*)");
|
||||||
assertType(object, DemangledFunction.class);
|
assertType(object, DemangledFunction.class);
|
||||||
DemangledFunction function = (DemangledFunction) object;
|
DemangledFunction function = (DemangledFunction) object;
|
||||||
List<DemangledDataType> parameters = function.getParameters();
|
List<DemangledParameter> parameters = function.getParameters();
|
||||||
assertEquals(2, parameters.size());
|
assertEquals(2, parameters.size());
|
||||||
DemangledDataType p1 = parameters.get(0);
|
DemangledDataType p1 = parameters.get(0).getType();
|
||||||
assertEquals(4, p1.getArrayDimensions());
|
assertEquals(4, p1.getArrayDimensions());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,12 +153,12 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||||||
|
|
||||||
DemangledFunction method = (DemangledFunction) object;
|
DemangledFunction method = (DemangledFunction) object;
|
||||||
|
|
||||||
List<DemangledDataType> parameters = method.getParameters();
|
List<DemangledParameter> parameters = method.getParameters();
|
||||||
assertEquals(4, parameters.size());
|
assertEquals(4, parameters.size());
|
||||||
assertEquals("unsigned long (*)(long const &)", parameters.get(0).getSignature());
|
assertEquals("unsigned long (*)(long const &)", parameters.get(0).getType().getSignature());
|
||||||
assertEquals("unsigned long", parameters.get(1).getSignature());
|
assertEquals("unsigned long", parameters.get(1).getType().getSignature());
|
||||||
assertEquals("unsigned long", parameters.get(2).getSignature());
|
assertEquals("unsigned long", parameters.get(2).getType().getSignature());
|
||||||
assertEquals("float", parameters.get(3).getSignature());
|
assertEquals("float", parameters.get(3).getType().getSignature());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -176,9 +176,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||||||
"_Rb_tree<Location,Location,std::_Identity<Location>,std::less<Location>,std::allocator<Location>>");
|
"_Rb_tree<Location,Location,std::_Identity<Location>,std::less<Location>,std::allocator<Location>>");
|
||||||
|
|
||||||
DemangledFunction function = (DemangledFunction) object;
|
DemangledFunction function = (DemangledFunction) object;
|
||||||
List<DemangledDataType> parameters = function.getParameters();
|
List<DemangledParameter> parameters = function.getParameters();
|
||||||
assertEquals(1, parameters.size());
|
assertEquals(1, parameters.size());
|
||||||
assertEquals("Location const &", parameters.get(0).getSignature());
|
assertEquals("Location const &", parameters.get(0).getType().getSignature());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -194,7 +194,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||||||
assertType(object, DemangledFunction.class);
|
assertType(object, DemangledFunction.class);
|
||||||
|
|
||||||
DemangledFunction function = (DemangledFunction) object;
|
DemangledFunction function = (DemangledFunction) object;
|
||||||
List<DemangledDataType> parameters = function.getParameters();
|
List<DemangledParameter> parameters = function.getParameters();
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
"__insertion_sort<__gnu_cxx::__normal_iterator<std::pair<unsigned_long,PcodeOp*>*,std::vector<std::pair<unsigned_long,PcodeOp*>,std::allocator<std::pair<unsigned_long,PcodeOp*>>>>,bool(*)(std::pair<unsigned_long,PcodeOp*>const&,std::pair<unsigned_long,PcodeOp*>const&)>",
|
"__insertion_sort<__gnu_cxx::__normal_iterator<std::pair<unsigned_long,PcodeOp*>*,std::vector<std::pair<unsigned_long,PcodeOp*>,std::allocator<std::pair<unsigned_long,PcodeOp*>>>>,bool(*)(std::pair<unsigned_long,PcodeOp*>const&,std::pair<unsigned_long,PcodeOp*>const&)>",
|
||||||
@@ -211,9 +211,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||||||
"bool (*)(std::pair<unsigned long,PcodeOp *> const &,std::pair<unsigned long,PcodeOp *> const &)",
|
"bool (*)(std::pair<unsigned long,PcodeOp *> const &,std::pair<unsigned long,PcodeOp *> const &)",
|
||||||
parameters.get(2).toString());
|
parameters.get(2).toString());
|
||||||
|
|
||||||
assertType(parameters.get(2), DemangledFunctionPointer.class);
|
assertType(parameters.get(2).getType(), DemangledFunctionPointer.class);
|
||||||
|
|
||||||
DemangledFunctionPointer fptr = (DemangledFunctionPointer) parameters.get(2);
|
DemangledFunctionPointer fptr = (DemangledFunctionPointer) parameters.get(2).getType();
|
||||||
|
|
||||||
assertEquals("bool", fptr.getReturnType().getName());
|
assertEquals("bool", fptr.getReturnType().getName());
|
||||||
|
|
||||||
@@ -234,9 +234,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||||||
assertEquals(
|
assertEquals(
|
||||||
"undefined std::set<bbnode*,std::less<bbnode*>,std::allocator<bbnode*>>::insert(bbnode const * &)",
|
"undefined std::set<bbnode*,std::less<bbnode*>,std::allocator<bbnode*>>::insert(bbnode const * &)",
|
||||||
method.getSignature(false));
|
method.getSignature(false));
|
||||||
List<DemangledDataType> parameters = method.getParameters();
|
List<DemangledParameter> parameters = method.getParameters();
|
||||||
assertEquals(1, parameters.size());
|
assertEquals(1, parameters.size());
|
||||||
assertEquals("bbnode const * &", parameters.get(0).getSignature());
|
assertEquals("bbnode const * &", parameters.get(0).getType().getSignature());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -252,9 +252,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||||||
DemangledFunction method = (DemangledFunction) object;
|
DemangledFunction method = (DemangledFunction) object;
|
||||||
assertEquals("undefined Bar::Fred::Fred(int)", method.getSignature(false));
|
assertEquals("undefined Bar::Fred::Fred(int)", method.getSignature(false));
|
||||||
|
|
||||||
List<DemangledDataType> parameters = method.getParameters();
|
List<DemangledParameter> parameters = method.getParameters();
|
||||||
assertEquals(1, parameters.size());
|
assertEquals(1, parameters.size());
|
||||||
assertEquals("int", parameters.get(0).getSignature());
|
assertEquals("int", parameters.get(0).getType().getSignature());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -428,9 +428,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||||||
DemangledFunction function = (DemangledFunction) object;
|
DemangledFunction function = (DemangledFunction) object;
|
||||||
assertEquals("undefined Foo::getBool(float)", function.getSignature(false));
|
assertEquals("undefined Foo::getBool(float)", function.getSignature(false));
|
||||||
|
|
||||||
List<DemangledDataType> parameters = function.getParameters();
|
List<DemangledParameter> parameters = function.getParameters();
|
||||||
assertEquals(1, parameters.size());
|
assertEquals(1, parameters.size());
|
||||||
assertEquals("float", parameters.get(0).getSignature());
|
assertEquals("float", parameters.get(0).getType().getSignature());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -447,13 +447,13 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||||||
|
|
||||||
DemangledFunction function = (DemangledFunction) object;
|
DemangledFunction function = (DemangledFunction) object;
|
||||||
|
|
||||||
List<DemangledDataType> parameters = function.getParameters();
|
List<DemangledParameter> parameters = function.getParameters();
|
||||||
assertEquals(5, parameters.size());
|
assertEquals(5, parameters.size());
|
||||||
assertEquals("int", parameters.get(0).getSignature());
|
assertEquals("int", parameters.get(0).getType().getSignature());
|
||||||
assertEquals("double", parameters.get(1).getSignature());
|
assertEquals("double", parameters.get(1).getType().getSignature());
|
||||||
assertEquals("char", parameters.get(2).getSignature());
|
assertEquals("char", parameters.get(2).getType().getSignature());
|
||||||
assertEquals("long", parameters.get(3).getSignature());
|
assertEquals("long", parameters.get(3).getType().getSignature());
|
||||||
assertEquals("short", parameters.get(4).getSignature());
|
assertEquals("short", parameters.get(4).getType().getSignature());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -827,13 +827,13 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||||||
|
|
||||||
DemangledFunction method = (DemangledFunction) object;
|
DemangledFunction method = (DemangledFunction) object;
|
||||||
|
|
||||||
List<DemangledDataType> parameters = method.getParameters();
|
List<DemangledParameter> parameters = method.getParameters();
|
||||||
assertEquals(5, parameters.size());
|
assertEquals(5, parameters.size());
|
||||||
assertEquals("SECTION_INFO *", parameters.get(0).getSignature());
|
assertEquals("SECTION_INFO *", parameters.get(0).getType().getSignature());
|
||||||
assertEquals("int *", parameters.get(1).getSignature());
|
assertEquals("int *", parameters.get(1).getType().getSignature());
|
||||||
assertEquals("int *[]", parameters.get(2).getSignature());
|
assertEquals("int *[]", parameters.get(2).getType().getSignature());
|
||||||
assertEquals("int", parameters.get(3).getSignature());
|
assertEquals("int", parameters.get(3).getType().getSignature());
|
||||||
assertEquals("short const *", parameters.get(4).getSignature());
|
assertEquals("short const *", parameters.get(4).getType().getSignature());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -935,10 +935,10 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||||||
"undefined Magick::operator<(Magick::Coordinate const &,Magick::Coordinate const &)",
|
"undefined Magick::operator<(Magick::Coordinate const &,Magick::Coordinate const &)",
|
||||||
method.getSignature(false));
|
method.getSignature(false));
|
||||||
|
|
||||||
List<DemangledDataType> parameters = method.getParameters();
|
List<DemangledParameter> parameters = method.getParameters();
|
||||||
assertEquals(2, parameters.size());
|
assertEquals(2, parameters.size());
|
||||||
assertEquals("Magick::Coordinate const &", parameters.get(0).getSignature());
|
assertEquals("Magick::Coordinate const &", parameters.get(0).getType().getSignature());
|
||||||
assertEquals("Magick::Coordinate const &", parameters.get(1).getSignature());
|
assertEquals("Magick::Coordinate const &", parameters.get(1).getType().getSignature());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1072,9 +1072,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||||||
assertEquals("undefined Magick::pageImage::operator()(Magick::Image &)",
|
assertEquals("undefined Magick::pageImage::operator()(Magick::Image &)",
|
||||||
method.getSignature(false));
|
method.getSignature(false));
|
||||||
|
|
||||||
List<DemangledDataType> parameters = method.getParameters();
|
List<DemangledParameter> parameters = method.getParameters();
|
||||||
assertEquals(1, parameters.size());
|
assertEquals(1, parameters.size());
|
||||||
assertEquals("Magick::Image &", parameters.get(0).getSignature());
|
assertEquals("Magick::Image &", parameters.get(0).getType().getSignature());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1536,13 +1536,14 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||||||
|
|
||||||
DemangledFunction df = (DemangledFunction) object;
|
DemangledFunction df = (DemangledFunction) object;
|
||||||
|
|
||||||
List<DemangledDataType> parameters = df.getParameters();
|
List<DemangledParameter> parameters = df.getParameters();
|
||||||
assertEquals("Number of parameters", 1, parameters.size());
|
assertEquals("Number of parameters", 1, parameters.size());
|
||||||
assertEquals("Name of type parsed", "F", parameters.get(0).getName());
|
assertEquals("Name of type parsed", "F", parameters.get(0).getType().getName());
|
||||||
assertEquals("Param Type Name parsed", "WTF", parameters.get(0).getNamespace().toString());
|
assertEquals("Param Type Name parsed", "WTF",
|
||||||
|
parameters.get(0).getType().getNamespace().toString());
|
||||||
assertEquals("Param Template was parsed",
|
assertEquals("Param Template was parsed",
|
||||||
"<WTF::F<void (Core::FileClient &)> (Core::File &)>",
|
"<WTF::F<void (Core::FileClient &)> (Core::File &)>",
|
||||||
parameters.get(0).getTemplate().toString());
|
parameters.get(0).getType().getTemplate().toString());
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
"undefined Core::AsyncFile::perform(WTF::F<WTF::F<void (Core::FileClient &)> (Core::File &)> &&)",
|
"undefined Core::AsyncFile::perform(WTF::F<WTF::F<void (Core::FileClient &)> (Core::File &)> &&)",
|
||||||
@@ -1569,9 +1570,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||||||
|
|
||||||
DemangledFunction df = (DemangledFunction) object;
|
DemangledFunction df = (DemangledFunction) object;
|
||||||
|
|
||||||
List<DemangledDataType> parameters = df.getParameters();
|
List<DemangledParameter> parameters = df.getParameters();
|
||||||
assertEquals("Number of parameters", 1, parameters.size());
|
assertEquals("Number of parameters", 1, parameters.size());
|
||||||
DemangledDataType demangParamDT = parameters.get(0);
|
DemangledDataType demangParamDT = parameters.get(0).getType();
|
||||||
|
|
||||||
assertEquals("Name of type parsed", "function", demangParamDT.getName());
|
assertEquals("Name of type parsed", "function", demangParamDT.getName());
|
||||||
assertEquals("Param Type Name parsed", "boost", demangParamDT.getNamespace().toString());
|
assertEquals("Param Type Name parsed", "boost", demangParamDT.getNamespace().toString());
|
||||||
@@ -1601,9 +1602,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||||||
|
|
||||||
DemangledFunction df = (DemangledFunction) object;
|
DemangledFunction df = (DemangledFunction) object;
|
||||||
|
|
||||||
List<DemangledDataType> parameters = df.getParameters();
|
List<DemangledParameter> parameters = df.getParameters();
|
||||||
assertEquals("Number of parameters", 1, parameters.size());
|
assertEquals("Number of parameters", 1, parameters.size());
|
||||||
DemangledDataType demangParamDT = parameters.get(0);
|
DemangledDataType demangParamDT = parameters.get(0).getType();
|
||||||
|
|
||||||
assertEquals("Name of type parsed", "function", demangParamDT.getName());
|
assertEquals("Name of type parsed", "function", demangParamDT.getName());
|
||||||
assertEquals("Param Type Name parsed", "boost", demangParamDT.getNamespace().toString());
|
assertEquals("Param Type Name parsed", "boost", demangParamDT.getNamespace().toString());
|
||||||
@@ -1705,9 +1706,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||||||
assertType(object, DemangledFunction.class);
|
assertType(object, DemangledFunction.class);
|
||||||
|
|
||||||
DemangledFunction function = (DemangledFunction) object;
|
DemangledFunction function = (DemangledFunction) object;
|
||||||
List<DemangledDataType> parameters = function.getParameters();
|
List<DemangledParameter> parameters = function.getParameters();
|
||||||
assertEquals(2, parameters.size());
|
assertEquals(2, parameters.size());
|
||||||
assertTrue(parameters.get(1).isVarArgs());
|
assertTrue(parameters.get(1).getType().isVarArgs());
|
||||||
|
|
||||||
assertEquals("undefined testVarArgs(int,...)", object.getSignature(false));
|
assertEquals("undefined testVarArgs(int,...)", object.getSignature(false));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -369,7 +369,8 @@ public class MDMangGhidra extends MDMang {
|
|||||||
MDArgumentsList args = functionType.getArgumentsList();
|
MDArgumentsList args = functionType.getArgumentsList();
|
||||||
if (functionType.hasArgs() && args != null) {
|
if (functionType.hasArgs() && args != null) {
|
||||||
for (int index = 0; index < args.getNumArgs(); index++) {
|
for (int index = 0; index < args.getNumArgs(); index++) {
|
||||||
function.addParameter(processDataType(null, args.getArg(index)));
|
function.addParameter(
|
||||||
|
new DemangledParameter(processDataType(null, args.getArg(index))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (functionType.isTypeCast()) {
|
if (functionType.isTypeCast()) {
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle"
|
||||||
|
apply from: "$rootProject.projectDir/gradle/javaProject.gradle"
|
||||||
|
apply from: "$rootProject.projectDir/gradle/jacocoProject.gradle"
|
||||||
|
apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle"
|
||||||
|
apply plugin: 'eclipse'
|
||||||
|
|
||||||
|
eclipse.project.name = 'Features SwiftDemangler'
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api project(":Base")
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
##VERSION: 2.0
|
||||||
|
Module.manifest||GHIDRA||||END|
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//Outputs the natively demangled Swift symbol found at the current address in expanded tree form.
|
||||||
|
//Mostly useful for debugging.
|
||||||
|
//@category Demangler
|
||||||
|
import ghidra.app.script.GhidraScript;
|
||||||
|
import ghidra.app.util.demangler.DemangledObject;
|
||||||
|
import ghidra.app.util.demangler.swift.*;
|
||||||
|
import ghidra.app.util.demangler.swift.SwiftNativeDemangler.SwiftNativeDemangledOutput;
|
||||||
|
import ghidra.program.model.symbol.*;
|
||||||
|
|
||||||
|
public class SwiftDemanglerScript extends GhidraScript {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void run() throws Exception {
|
||||||
|
SwiftDemangler demangler = new SwiftDemangler();
|
||||||
|
SwiftDemanglerOptions options = new SwiftDemanglerOptions();
|
||||||
|
if (!demangler.canDemangle(currentProgram)) {
|
||||||
|
println("Not a Swift program");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
println("-------------------------------------------------");
|
||||||
|
|
||||||
|
String mangled = null;
|
||||||
|
SymbolTable symbolTable = currentProgram.getSymbolTable();
|
||||||
|
for (Symbol symbol : symbolTable.getSymbols(currentAddress)) {
|
||||||
|
if (demangler.isSwiftMangledSymbol(symbol.getName())) {
|
||||||
|
mangled = symbol.getName();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (LabelHistory history : symbolTable.getLabelHistory(currentAddress)) {
|
||||||
|
if (demangler.isSwiftMangledSymbol(history.getLabelString())) {
|
||||||
|
mangled = history.getLabelString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mangled == null) {
|
||||||
|
println("No mangled Swift symbols found at " + currentAddress);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SwiftNativeDemangler nativeDemangler = new SwiftNativeDemangler(options.getSwiftDir());
|
||||||
|
SwiftNativeDemangledOutput demangledOutput = nativeDemangler.demangle(mangled);
|
||||||
|
println(demangledOutput.toString());
|
||||||
|
|
||||||
|
DemangledObject demangledObject = demangler.demangle(mangled);
|
||||||
|
if (demangledObject != null) {
|
||||||
|
println(demangledObject.getClass().getSimpleName() + " " + mangled + " --> " +
|
||||||
|
demangledObject);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
println("Failed to demangle: " + mangled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+127
@@ -0,0 +1,127 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.plugin.core.analysis;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import ghidra.app.util.demangler.*;
|
||||||
|
import ghidra.app.util.demangler.swift.*;
|
||||||
|
import ghidra.app.util.importer.MessageLog;
|
||||||
|
import ghidra.framework.options.OptionType;
|
||||||
|
import ghidra.framework.options.Options;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An analyzer to demangle Swift mangled symbols
|
||||||
|
*/
|
||||||
|
public class SwiftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
||||||
|
|
||||||
|
private static final String NAME = "Demangler Swift";
|
||||||
|
private static final String DESCRIPTION =
|
||||||
|
"Demangles Swift symbols and applies appropriate datatype and calling conventions where possible. Requires Swift to be installed.";
|
||||||
|
private static final String OPTION_NAME_SWIFT_DIR = "Swift binary directory";
|
||||||
|
private static final String OPTION_DESCRIPTION_SWIFT_DIR =
|
||||||
|
"Path to the Swift installation binary directory, if not on PATH";
|
||||||
|
|
||||||
|
private static final String OPTION_NAME_INCOMPLETE_PREFIX =
|
||||||
|
"Use incomplete demangle label prefix (%s)"
|
||||||
|
.formatted(SwiftDemanglerOptions.INCOMPLETE_PREFIX);
|
||||||
|
private static final String OPTION_DESCRIPTION_INCOMPLETE_PREFIX =
|
||||||
|
"Prefix incomplete demangled labels with '%s'"
|
||||||
|
.formatted(SwiftDemanglerOptions.INCOMPLETE_PREFIX);
|
||||||
|
private static final String OPTION_NAME_UNSUPPORTED_PREFIX =
|
||||||
|
"Use unsupported demangle label prefix (%s)"
|
||||||
|
.formatted(SwiftDemanglerOptions.UNSUPPORTED_PREFIX);
|
||||||
|
private static final String OPTION_DESCRIPTION_UNSUPPORTED_PREFIX =
|
||||||
|
"Prefix unsupported demangled labels with '%s'"
|
||||||
|
.formatted(SwiftDemanglerOptions.UNSUPPORTED_PREFIX);
|
||||||
|
|
||||||
|
private File swiftDir;
|
||||||
|
private boolean useIncompletePrefix = true;
|
||||||
|
private boolean useUnsupportedPrefix = true;
|
||||||
|
private SwiftDemangler demangler = new SwiftDemangler();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link SwiftDemanglerAnalyzer}
|
||||||
|
*/
|
||||||
|
public SwiftDemanglerAnalyzer() {
|
||||||
|
super(NAME, DESCRIPTION);
|
||||||
|
setDefaultEnablement(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canAnalyze(Program program) {
|
||||||
|
return demangler.canDemangle(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected DemangledObject doDemangle(String mangled, DemanglerOptions options, MessageLog log)
|
||||||
|
throws DemangledException {
|
||||||
|
return demangler.demangle(mangled, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void analysisEnded(Program program) {
|
||||||
|
demangler.clearCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerOptions(Options options, Program program) {
|
||||||
|
HelpLocation help = new HelpLocation("AutoAnalysisPlugin", "Demangler_Analyzer");
|
||||||
|
options.registerOption(OPTION_NAME_SWIFT_DIR, OptionType.FILE_TYPE, swiftDir, help,
|
||||||
|
OPTION_DESCRIPTION_SWIFT_DIR);
|
||||||
|
options.registerOption(OPTION_NAME_INCOMPLETE_PREFIX, OptionType.BOOLEAN_TYPE,
|
||||||
|
useIncompletePrefix, help, OPTION_DESCRIPTION_INCOMPLETE_PREFIX);
|
||||||
|
options.registerOption(OPTION_NAME_UNSUPPORTED_PREFIX, OptionType.BOOLEAN_TYPE,
|
||||||
|
useUnsupportedPrefix, help, OPTION_DESCRIPTION_UNSUPPORTED_PREFIX);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean validateOptions(DemanglerOptions options, MessageLog log) {
|
||||||
|
if (options instanceof SwiftDemanglerOptions swiftDemanglerOptions) {
|
||||||
|
try {
|
||||||
|
new SwiftNativeDemangler(swiftDemanglerOptions.getSwiftDir());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
log.appendMsg(e.getMessage());
|
||||||
|
log.appendMsg("You must have Swift installed to demangle Swift symbols.\n" +
|
||||||
|
"See the \"Demangler Swift\" analyzer options to configure.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void optionsChanged(Options options, Program program) {
|
||||||
|
swiftDir = options.getFile(OPTION_NAME_SWIFT_DIR, swiftDir);
|
||||||
|
useIncompletePrefix =
|
||||||
|
options.getBoolean(OPTION_NAME_INCOMPLETE_PREFIX, useIncompletePrefix);
|
||||||
|
useUnsupportedPrefix =
|
||||||
|
options.getBoolean(OPTION_NAME_UNSUPPORTED_PREFIX, useUnsupportedPrefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected DemanglerOptions getOptions() {
|
||||||
|
SwiftDemanglerOptions swiftDemanglerOptions = new SwiftDemanglerOptions();
|
||||||
|
swiftDemanglerOptions.setSwiftDir(swiftDir);
|
||||||
|
swiftDemanglerOptions.setIncompletePrefix(useIncompletePrefix);
|
||||||
|
swiftDemanglerOptions.setUnsupportedPrefix(useUnsupportedPrefix);
|
||||||
|
return swiftDemanglerOptions;
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
-19
@@ -13,28 +13,22 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.bin.format.swift;
|
package ghidra.app.util.demangler.swift;
|
||||||
|
|
||||||
import ghidra.app.util.bin.StructConverter;
|
import ghidra.app.util.demangler.swift.nodes.SwiftNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implemented by all Swift structures
|
* Kinds of Swift demangling {@link SwiftNode}s
|
||||||
|
*
|
||||||
|
* @see <a href="https://github.com/apple/swift/blob/main/include/swift/Demangling/DemangleNodes.def">DemangleNodes.def</a>
|
||||||
*/
|
*/
|
||||||
public interface SwiftStructure extends StructConverter {
|
public enum SwiftDemangledBuiltinType {
|
||||||
|
//@formatter:off
|
||||||
public static final String DATA_TYPE_CATEGORY = "/Swift";
|
|
||||||
|
|
||||||
/**
|
Int1,
|
||||||
* Gets the name of the {@link SwiftStructure}
|
Word,
|
||||||
*
|
RawPointer,
|
||||||
* @return The name of the {@link SwiftStructure}
|
Unsupported
|
||||||
*/
|
|
||||||
public String getStructureName();
|
//@formatter:on
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a short description of the {@link SwiftStructure}
|
|
||||||
*
|
|
||||||
* @return A short description of the {@link SwiftStructure}
|
|
||||||
*/
|
|
||||||
public String getDescription();
|
|
||||||
}
|
}
|
||||||
+94
@@ -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
|
||||||
|
}
|
||||||
+170
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
+198
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
+90
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
+156
@@ -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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
+57
@@ -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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
+46
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
+91
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
+52
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
+55
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+48
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
+46
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
+66
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+53
@@ -0,0 +1,53 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.util.demangler.swift.datatypes;
|
||||||
|
|
||||||
|
import ghidra.app.util.bin.format.swift.SwiftTypeMetadata;
|
||||||
|
import ghidra.app.util.demangler.*;
|
||||||
|
import ghidra.app.util.demangler.swift.SwiftDemangler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Swift tuple
|
||||||
|
*/
|
||||||
|
public class SwiftTuple extends SwiftStructure {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Swift tuple
|
||||||
|
*
|
||||||
|
* @param mangled The mangled string
|
||||||
|
* @param originalDemangled The natively demangled string
|
||||||
|
* @param list The elements of the tuple
|
||||||
|
* @param typeMetadata The {@link SwiftTypeMetadata}, or null if it is not known
|
||||||
|
* @param demangler A {@link SwiftDemangler}
|
||||||
|
* @throws DemangledException if a problem occurred
|
||||||
|
*/
|
||||||
|
public SwiftTuple(String mangled, String originalDemangled, DemangledList list,
|
||||||
|
SwiftTypeMetadata typeMetadata, SwiftDemangler demangler) throws DemangledException {
|
||||||
|
super(mangled, originalDemangled, "tuple%d".formatted(list.size()), null, typeMetadata,
|
||||||
|
demangler);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (Demangled element : list) {
|
||||||
|
if (element instanceof DemangledDataType ddt) {
|
||||||
|
addField(Integer.toString(i), ddt);
|
||||||
|
}
|
||||||
|
else if (element instanceof DemangledVariable variable) {
|
||||||
|
addField(variable.getName(), variable.getDataType());
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user