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;
+ }
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/InvertibleProtocolSet.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/InvertibleProtocolSet.java
new file mode 100644
index 0000000000..2cc3d8232a
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/InvertibleProtocolSet.java
@@ -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 swift/ABI/InvertibleProtocols.h
+ */
+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;
+ }
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MultiPayloadEnumDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MultiPayloadEnumDescriptor.java
index af967f4277..09e9bae54d 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MultiPayloadEnumDescriptor.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/MultiPayloadEnumDescriptor.java
@@ -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}
+ *
+ * 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();
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetClassDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetClassDescriptor.java
index 736f705ee5..4f9719ea4e 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetClassDescriptor.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetClassDescriptor.java
@@ -51,6 +51,7 @@ public final class TargetClassDescriptor extends TargetTypeContextDescriptor {
private TargetOverrideTableHeader overrideHeader;
private List 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 getTrailingObjects() {
List 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;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetEnumDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetEnumDescriptor.java
index c1101bfd47..f8980792b2 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetEnumDescriptor.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetEnumDescriptor.java
@@ -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 getTrailingObjects() {
List 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;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetStructDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetStructDescriptor.java
index 0983358c87..012e23d470 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetStructDescriptor.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/swift/types/TargetStructDescriptor.java
@@ -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 getTrailingObjects() {
List 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;
}