GP-6281: Swift type metadata fixes (#8607)

This commit is contained in:
Ryan Kurtz
2025-12-31 19:40:44 -05:00
parent 07fabc6b66
commit 26e9bc6780
8 changed files with 226 additions and 6 deletions

View File

@@ -35,7 +35,7 @@ public enum SwiftSection {
BLOCK_PROTOCS("__swift5_protos", "swift5_protocols", ".sw5prt"),
BLOCK_ACFUNCS("__swift5_acfuncs", "swift5_accessible_functions", ".sw5acfn"),
BLOCK_MPENUM("__swift5_mpenum", "swift5_mpenum", ".sw5mpen"),
BLOCK_TYPES("__swift5_types", "swift5_type_metadata", ".sw5tymd"),
BLOCK_TYPES("__swift5_types", "__swift5_types2", "swift5_type_metadata", ".sw5tymd"),
BLOCK_ENTRY("__swift5_entry", "swift5_entry", ".sw5entr"),
BLOCK_SWIFTAST("__swift_ast", ".swift_ast", "swiftast");

View File

@@ -361,7 +361,11 @@ public class SwiftTypeMetadata {
Address blockStart = block.getStart();
reader.setPointerIndex(blockStart.getOffset());
int i = skipZeroEntries(reader, 0, block.getSize());
while (i < block.getSize()) {
while (i + MultiPayloadEnumDescriptor.PEEK_SIZE <= block.getSize()) {
int contentsSize = MultiPayloadEnumDescriptor.peekContentsSize(reader);
if (i + MultiPayloadEnumDescriptor.SIZE + contentsSize > block.getSize()) {
break;
}
monitor.checkCancelled();
MultiPayloadEnumDescriptor descriptor = new MultiPayloadEnumDescriptor(reader);
mpEnumDescriptors.add(descriptor);

View File

@@ -0,0 +1,85 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.bin.format.swift.types;
import java.io.IOException;
import java.util.*;
import ghidra.app.util.bin.StructConverter;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.EnumDataType;
import ghidra.util.exception.DuplicateNameException;
/**
* Swift {@code InvertibleProtocolKind} values
*
* @see <a href="https://github.com/swiftlang/swift/blob/main/include/swift/ABI/InvertibleProtocols.h">swift/ABI/InvertibleProtocols.h</a>
* @see <a href="https://github.com/swiftlang/swift/blob/main/include/swift/ABI/InvertibleProtocols.def">swift/ABI/InvertibleProtocols.def</a>
*/
public enum InvertibleProtocolKind implements StructConverter {
Copyable(0),
Escapable(1);
private int bit;
/**
* Creates a new {@link InvertibleProtocolKind}
*
* @param bit The bit number that represents the kind
*/
private InvertibleProtocolKind(int bit) {
this.bit = bit;
}
/**
* {@return the bit number that represents the kind}
*/
public int getBit() {
return bit;
}
/**
* {@return the {@link Set} of {@link InvertibleProtocolKind}s that map to the given kind value}
*
* @param value The kind value to get the value of
*/
public static Set<InvertibleProtocolKind> valueOf(short value) {
Set<InvertibleProtocolKind> set = new HashSet<>();
for (int i = 0; i < 16; i++) {
final int bitPos = i;
int bit = (value >> bitPos) & 0x1;
if (bit != 0) {
Arrays.stream(values())
.filter(e -> e.getBit() == bitPos)
.findFirst()
.ifPresent(set::add);
}
}
return set;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
EnumDataType dt = new EnumDataType(SwiftTypeMetadataStructure.CATEGORY_PATH,
InvertibleProtocolKind.class.getSimpleName(), 2);
for (InvertibleProtocolKind kind : values()) {
dt.add(kind.name(), 1 << kind.getBit());
}
return dt;
}
}

View File

@@ -0,0 +1,74 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.bin.format.swift.types;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.swift.SwiftTypeMetadataStructure;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
/**
* Represents a Swift {@code InvertibleProtocolSet} structure
*
* @see <a href="https://github.com/swiftlang/swift/blob/main/include/swift/ABI/InvertibleProtocols.h">swift/ABI/InvertibleProtocols.h</a>
*/
public class InvertibleProtocolSet extends SwiftTypeMetadataStructure {
/**
* The size (in bytes) of a {@link InvertibleProtocolSet} structure
*/
public static final int SIZE = 2;
private short bits;
/**
* Create a new {@link InvertibleProtocolSet}
*
* @param reader A {@link BinaryReader} positioned at the start of the structure
* @throws IOException if there was an IO-related problem creating the structure
*/
public InvertibleProtocolSet(BinaryReader reader) throws IOException {
super(reader.getPointerIndex());
bits = reader.readNextShort();
}
/**
* {@return the raw bits}
*/
public short getRawBits() {
return bits;
}
@Override
public String getStructureName() {
return InvertibleProtocolSet.class.getSimpleName();
}
@Override
public String getDescription() {
return "invertible protocol set";
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType struct = new StructureDataType(CATEGORY_PATH, getStructureName(), 0);
struct.add(InvertibleProtocolKind.values()[0].toDataType(), "bits", "The storage bits");
return struct;
}
}

View File

@@ -38,6 +38,11 @@ public final class MultiPayloadEnumDescriptor extends SwiftTypeMetadataStructure
*/
public static final int SIZE = 4;
/**
* How many bytes it requires to peek at size of the {@code contents} array
*/
public static final int PEEK_SIZE = 8;
private String typeName;
private int[] contents;
@@ -70,12 +75,31 @@ public final class MultiPayloadEnumDescriptor extends SwiftTypeMetadataStructure
}
/**
* {@return The size of the contents in bytes}
* {@return the size of the contents in bytes}
*/
public long getContentsSize() {
return contents.length * Integer.BYTES;
}
/**
* {@return the size of the contents in bytes, without reading the contents}
* <p>
* This method will leave the {@link BinaryReader}'s position unaffected.
*
* @param reader A {@link BinaryReader} positioned at the start of the structure
* @throws IOException if there was an IO-related problem creating the structure
*/
public static int peekContentsSize(BinaryReader reader) throws IOException {
long origIndex = reader.getPointerIndex();
try {
reader.readNext(SwiftUtils::relativeString);
return (reader.readNextInt() >> 16) & 0xffff;
}
finally {
reader.setPointerIndex(origIndex);
}
}
@Override
public String getStructureName() {
return MultiPayloadEnumDescriptor.class.getSimpleName();

View File

@@ -51,6 +51,7 @@ public final class TargetClassDescriptor extends TargetTypeContextDescriptor {
private TargetOverrideTableHeader overrideHeader;
private List<TargetMethodOverrideDescriptor> methodOverrideDescriptors = new ArrayList<>();
private TargetObjCResilientClassStubInfo objcResilientClassStub;
private InvertibleProtocolSet invertibleProtocolSet;
/**
* Creates a new {@link TargetClassDescriptor}
@@ -113,7 +114,7 @@ public final class TargetClassDescriptor extends TargetTypeContextDescriptor {
}
if (flags.hasInvertableProtocols()) {
throw new IOException("Unimplemented InvertibleProtocolSet detected.");
invertibleProtocolSet = new InvertibleProtocolSet(reader);
}
if (!flags.isGeneric() &&
@@ -256,6 +257,13 @@ public final class TargetClassDescriptor extends TargetTypeContextDescriptor {
return objcResilientClassStub;
}
/**
* {@return the {@link InvertibleProtocolSet}, or {@code null} if it doens't exist}
*/
public InvertibleProtocolSet getInvertibleProtocolSet() {
return invertibleProtocolSet;
}
@Override
public List<SwiftTypeMetadataStructure> getTrailingObjects() {
List<SwiftTypeMetadataStructure> ret = new ArrayList<>();
@@ -283,6 +291,9 @@ public final class TargetClassDescriptor extends TargetTypeContextDescriptor {
if (objcResilientClassStub != null) {
ret.add(objcResilientClassStub);
}
if (invertibleProtocolSet != null) {
ret.add(invertibleProtocolSet);
}
return ret;
}

View File

@@ -39,6 +39,7 @@ public final class TargetEnumDescriptor extends TargetTypeContextDescriptor {
private TargetTypeGenericContextDescriptorHeader genericHeader;
private TargetSingletonMetadataInitialization singleton;
private TargetForeignMetadataInitialization foreign;
private InvertibleProtocolSet invertibleProtocolSet;
/**
* Creates a new {@link TargetEnumDescriptor}
@@ -72,7 +73,7 @@ public final class TargetEnumDescriptor extends TargetTypeContextDescriptor {
}
if (flags.hasInvertableProtocols()) {
throw new IOException("Unimplemented InvertibleProtocolSet detected.");
invertibleProtocolSet = new InvertibleProtocolSet(reader);
}
if (!flags.isGeneric() &&
@@ -122,6 +123,13 @@ public final class TargetEnumDescriptor extends TargetTypeContextDescriptor {
return foreign;
}
/**
* {@return the {@link InvertibleProtocolSet}, or {@code null} if it doens't exist}
*/
public InvertibleProtocolSet getInvertibleProtocolSet() {
return invertibleProtocolSet;
}
@Override
public List<SwiftTypeMetadataStructure> getTrailingObjects() {
List<SwiftTypeMetadataStructure> ret = new ArrayList<>();
@@ -135,6 +143,9 @@ public final class TargetEnumDescriptor extends TargetTypeContextDescriptor {
if (foreign != null) {
ret.add(foreign);
}
if (invertibleProtocolSet != null) {
ret.add(invertibleProtocolSet);
}
return ret;
}

View File

@@ -39,6 +39,7 @@ public final class TargetStructDescriptor extends TargetTypeContextDescriptor {
private TargetTypeGenericContextDescriptorHeader genericHeader;
private TargetSingletonMetadataInitialization singleton;
private TargetForeignMetadataInitialization foreign;
private InvertibleProtocolSet invertibleProtocolSet;
/**
* Creates a new {@link TargetStructDescriptor}
@@ -72,7 +73,7 @@ public final class TargetStructDescriptor extends TargetTypeContextDescriptor {
}
if (flags.hasInvertableProtocols()) {
throw new IOException("Unimplemented InvertibleProtocolSet detected.");
invertibleProtocolSet = new InvertibleProtocolSet(reader);
}
if (!flags.isGeneric() &&
@@ -121,6 +122,13 @@ public final class TargetStructDescriptor extends TargetTypeContextDescriptor {
return foreign;
}
/**
* {@return the {@link InvertibleProtocolSet}, or {@code null} if it doens't exist}
*/
public InvertibleProtocolSet getInvertibleProtocolSet() {
return invertibleProtocolSet;
}
@Override
public List<SwiftTypeMetadataStructure> getTrailingObjects() {
List<SwiftTypeMetadataStructure> ret = new ArrayList<>();
@@ -134,6 +142,9 @@ public final class TargetStructDescriptor extends TargetTypeContextDescriptor {
if (foreign != null) {
ret.add(foreign);
}
if (invertibleProtocolSet != null) {
ret.add(invertibleProtocolSet);
}
return ret;
}