mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Add extraction protocol conformance descriptor extraction, as read from an object file image, to TypeRefBuilder.
This commit is contained in:
@@ -79,6 +79,16 @@ struct RuntimeTarget<4> {
|
||||
using StoredSize = uint32_t;
|
||||
using StoredPointerDifference = int32_t;
|
||||
static constexpr size_t PointerSize = 4;
|
||||
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
static constexpr bool ObjCInterop = true;
|
||||
template <typename T>
|
||||
using TargetAnyClassMetadata = TargetAnyClassMetadataObjCInterop<T>;
|
||||
#else
|
||||
static constexpr bool ObjCInterop = false;
|
||||
template <typename T>
|
||||
using TargetAnyClassMetadata = TargetAnyClassMetadata<T>;
|
||||
#endif
|
||||
};
|
||||
|
||||
template <>
|
||||
@@ -91,6 +101,16 @@ struct RuntimeTarget<8> {
|
||||
using StoredSize = uint64_t;
|
||||
using StoredPointerDifference = int64_t;
|
||||
static constexpr size_t PointerSize = 8;
|
||||
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
static constexpr bool ObjCInterop = true;
|
||||
template <typename T>
|
||||
using TargetAnyClassMetadata = TargetAnyClassMetadataObjCInterop<T>;
|
||||
#else
|
||||
static constexpr bool ObjCInterop = false;
|
||||
template <typename T>
|
||||
using TargetAnyClassMetadata = TargetAnyClassMetadata<T>;
|
||||
#endif
|
||||
};
|
||||
|
||||
namespace reflection {
|
||||
@@ -540,6 +560,14 @@ namespace {
|
||||
|
||||
using TypeContextDescriptor = TargetTypeContextDescriptor<InProcess>;
|
||||
|
||||
template<unsigned PointerSize>
|
||||
using ExternalTypeContextDescriptor
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
= TargetTypeContextDescriptor<External<WithObjCInterop<RuntimeTarget<PointerSize>>>>;
|
||||
#else
|
||||
= TargetTypeContextDescriptor<External<NoObjCInterop<RuntimeTarget<PointerSize>>>>;
|
||||
#endif
|
||||
|
||||
// FIXME: https://bugs.swift.org/browse/SR-1155
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Winvalid-offsetof"
|
||||
@@ -2107,6 +2135,14 @@ using ProtocolRequirement = TargetProtocolRequirement<InProcess>;
|
||||
template<typename Runtime> struct TargetProtocolDescriptor;
|
||||
using ProtocolDescriptor = TargetProtocolDescriptor<InProcess>;
|
||||
|
||||
template<unsigned PointerSize>
|
||||
using ExternalProtocolDescriptor
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
= TargetProtocolDescriptor<External<WithObjCInterop<RuntimeTarget<PointerSize>>>>;
|
||||
#else
|
||||
= TargetProtocolDescriptor<External<NoObjCInterop<RuntimeTarget<PointerSize>>>>;
|
||||
#endif
|
||||
|
||||
/// A witness table for a protocol.
|
||||
///
|
||||
/// With the exception of the initial protocol conformance descriptor,
|
||||
@@ -2722,6 +2758,16 @@ public:
|
||||
return TypeRef.getTypeDescriptor(getTypeKind());
|
||||
}
|
||||
|
||||
constexpr inline auto
|
||||
getTypeDescriptorOffset() const -> typename Runtime::StoredSize {
|
||||
return offsetof(typename std::remove_reference<decltype(*this)>::type, TypeRef);
|
||||
}
|
||||
|
||||
constexpr inline auto
|
||||
getProtocolDescriptorOffset() const -> typename Runtime::StoredSize {
|
||||
return offsetof(typename std::remove_reference<decltype(*this)>::type, Protocol);
|
||||
}
|
||||
|
||||
TargetContextDescriptor<Runtime> * __ptrauth_swift_type_descriptor *
|
||||
_getTypeDescriptorLocation() const {
|
||||
if (getTypeKind() != TypeReferenceKind::IndirectTypeDescriptor)
|
||||
@@ -2840,9 +2886,21 @@ using TargetProtocolConformanceRecord =
|
||||
|
||||
using ProtocolConformanceRecord = TargetProtocolConformanceRecord<InProcess>;
|
||||
|
||||
template<unsigned PointerSize>
|
||||
using ExternalProtocolConformanceDescriptor
|
||||
= TargetProtocolConformanceDescriptor<External<RuntimeTarget<8>>>;
|
||||
using ExternalProtocolConformanceRecord = TargetProtocolConformanceRecord<External<RuntimeTarget<8>>>;
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
= TargetProtocolConformanceDescriptor<External<WithObjCInterop<RuntimeTarget<PointerSize>>>>;
|
||||
#else
|
||||
= TargetProtocolConformanceDescriptor<External<NoObjCInterop<RuntimeTarget<PointerSize>>>>;
|
||||
#endif
|
||||
|
||||
template<unsigned PointerSize>
|
||||
using ExternalProtocolConformanceRecord
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
= TargetProtocolConformanceRecord<External<WithObjCInterop<RuntimeTarget<PointerSize>>>>;
|
||||
#else
|
||||
= TargetProtocolConformanceRecord<External<NoObjCInterop<RuntimeTarget<PointerSize>>>>;
|
||||
#endif
|
||||
|
||||
template<typename Runtime>
|
||||
struct TargetGenericContext;
|
||||
@@ -2893,6 +2951,13 @@ private:
|
||||
};
|
||||
|
||||
using ContextDescriptor = TargetContextDescriptor<InProcess>;
|
||||
template<unsigned PointerSize>
|
||||
using ExternalContextDescriptor
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
= TargetContextDescriptor<External<WithObjCInterop<RuntimeTarget<PointerSize>>>>;
|
||||
#else
|
||||
= TargetContextDescriptor<External<NoObjCInterop<RuntimeTarget<PointerSize>>>>;
|
||||
#endif
|
||||
|
||||
inline bool isCImportedModuleName(llvm::StringRef name) {
|
||||
// This does not include MANGLING_MODULE_CLANG_IMPORTER because that's
|
||||
@@ -3417,6 +3482,11 @@ public:
|
||||
NumRequirements};
|
||||
}
|
||||
|
||||
constexpr inline auto
|
||||
getNameOffset() const -> typename Runtime::StoredSize {
|
||||
return offsetof(typename std::remove_reference<decltype(*this)>::type, Name);
|
||||
}
|
||||
|
||||
/// Retrieve the requirement base descriptor address.
|
||||
ConstTargetPointer<Runtime, TargetProtocolRequirement<Runtime>>
|
||||
getRequirementBaseDescriptor() const {
|
||||
@@ -4081,6 +4151,11 @@ public:
|
||||
/// type's metadata. The returned value is measured in sizeof(StoredPointer).
|
||||
int32_t getGenericArgumentOffset() const;
|
||||
|
||||
constexpr inline auto
|
||||
getNameOffset() const -> typename Runtime::StoredSize {
|
||||
return offsetof(typename std::remove_reference<decltype(*this)>::type, Name);
|
||||
}
|
||||
|
||||
/// Return the start of the generic arguments array in the nominal
|
||||
/// type's metadata. The returned value is measured in sizeof(StoredPointer).
|
||||
const TargetMetadata<Runtime> * const *getGenericArguments(
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
namespace swift {
|
||||
|
||||
/// Represents the seven reflection sections used by Swift
|
||||
/// Represents the eight reflection sections used by Swift
|
||||
enum ReflectionSectionKind : uint8_t {
|
||||
fieldmd,
|
||||
assocty,
|
||||
@@ -20,7 +20,8 @@ enum ReflectionSectionKind : uint8_t {
|
||||
capture,
|
||||
typeref,
|
||||
reflstr,
|
||||
conform
|
||||
conform,
|
||||
protocs
|
||||
};
|
||||
|
||||
/// Abstract base class responsible for providing the correct reflection section
|
||||
@@ -50,6 +51,8 @@ public:
|
||||
return "__swift5_reflstr";
|
||||
case conform:
|
||||
return "__swift5_proto";
|
||||
case protocs:
|
||||
return "__swift5_protos";
|
||||
}
|
||||
llvm_unreachable("Section type not found.");
|
||||
}
|
||||
@@ -73,7 +76,9 @@ public:
|
||||
case reflstr:
|
||||
return "swift5_reflstr";
|
||||
case conform:
|
||||
return "swift5_proto";
|
||||
return "swift5_protocol_conformances";
|
||||
case protocs:
|
||||
return "swift5_protocols";
|
||||
}
|
||||
llvm_unreachable("Section type not found.");
|
||||
}
|
||||
@@ -97,7 +102,9 @@ public:
|
||||
case reflstr:
|
||||
return ".sw5rfst";
|
||||
case conform:
|
||||
return ".sw5cnfrm"; // TODO: Figure out the real name
|
||||
return ".sw5prtc$B";
|
||||
case protocs:
|
||||
return ".sw5prt$B";
|
||||
}
|
||||
llvm_unreachable("Section not found.");
|
||||
}
|
||||
|
||||
@@ -442,6 +442,17 @@ public:
|
||||
return reinterpret_cast<PointerTy>(absolute);
|
||||
}
|
||||
|
||||
/// Apply the offset to a parameter, instead of `this`.
|
||||
PointerTy getRelative(void *base) const & {
|
||||
// Check for null.
|
||||
if (Nullable && RelativeOffset == 0)
|
||||
return nullptr;
|
||||
|
||||
// The value is addressed relative to `base`.
|
||||
uintptr_t absolute = detail::applyRelativeOffset(base, RelativeOffset);
|
||||
return reinterpret_cast<PointerTy>(absolute);
|
||||
}
|
||||
|
||||
/// A zero relative offset encodes a null reference.
|
||||
bool isNull() const & {
|
||||
return RelativeOffset == 0;
|
||||
@@ -476,6 +487,10 @@ public:
|
||||
return this->get();
|
||||
}
|
||||
|
||||
const typename super::ValueTy* getRelative(void *base) const & {
|
||||
return this->super::getRelative(base);
|
||||
}
|
||||
|
||||
using super::isNull;
|
||||
};
|
||||
|
||||
|
||||
@@ -221,6 +221,22 @@ public:
|
||||
SectionsBuf + (I * sizeof(typename T::Section)));
|
||||
if (strncmp(S->sectname, Name.data(), strlen(Name.data())) != 0)
|
||||
continue;
|
||||
|
||||
// The above check verifies that `Name` is a prefix to the examined
|
||||
// section name, to allow for matching of sections with a suffix
|
||||
// like `_TEXT`, etc.
|
||||
// "__swift5_proto" section name is a substring of "__swift5_protos",
|
||||
// Ensure we don't return the latter when looking for the former.
|
||||
SwiftObjectFileFormatMachO ObjectFileFormat;
|
||||
if (Name.data() ==
|
||||
ObjectFileFormat.getSectionName(ReflectionSectionKind::conform)) {
|
||||
auto protocolsSectionName =
|
||||
ObjectFileFormat.getSectionName(ReflectionSectionKind::protocs);
|
||||
if (strncmp(S->sectname, protocolsSectionName.data(),
|
||||
strlen(protocolsSectionName.data())) == 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
auto RemoteSecStart = S->addr + Slide;
|
||||
auto LocalSectBuf =
|
||||
this->getReader().readBytes(RemoteAddress(RemoteSecStart), S->size);
|
||||
|
||||
@@ -192,23 +192,8 @@ public:
|
||||
+ CR->NumMetadataSources * sizeof(MetadataSourceRecord);
|
||||
}
|
||||
};
|
||||
|
||||
class ConformanceRecordIterator
|
||||
: public ReflectionSectionIteratorBase<ConformanceRecordIterator,
|
||||
ExternalProtocolConformanceRecord> {
|
||||
public:
|
||||
ConformanceRecordIterator(RemoteRef<void> Cur, uint64_t Size)
|
||||
: ReflectionSectionIteratorBase(Cur, Size)
|
||||
{}
|
||||
|
||||
static uint64_t getCurrentRecordSize(RemoteRef<ExternalProtocolConformanceRecord> CD){
|
||||
return sizeof(ExternalProtocolConformanceRecord);
|
||||
}
|
||||
};
|
||||
|
||||
using CaptureSection = ReflectionSection<CaptureDescriptorIterator>;
|
||||
using GenericSection = ReflectionSection<const void *>;
|
||||
using ConformanceSection = ReflectionSection<ConformanceRecordIterator>;
|
||||
|
||||
struct ReflectionInfo {
|
||||
FieldSection Field;
|
||||
@@ -217,7 +202,7 @@ struct ReflectionInfo {
|
||||
CaptureSection Capture;
|
||||
GenericSection TypeReference;
|
||||
GenericSection ReflectionString;
|
||||
ConformanceSection Conformance;
|
||||
GenericSection Conformance;
|
||||
};
|
||||
|
||||
struct ClosureContextInfo {
|
||||
@@ -252,6 +237,17 @@ struct FieldTypeInfo {
|
||||
}
|
||||
};
|
||||
|
||||
/// Info about a protocol conformance read out from an Image
|
||||
struct ProtocolConformanceInfo {
|
||||
std::string typeName;
|
||||
std::string protocolName;
|
||||
|
||||
// TODO:
|
||||
// const TypeRef *type;
|
||||
// std::string mangledTypeName;
|
||||
// std::string mangledProtocolName;
|
||||
};
|
||||
|
||||
/// An implementation of MetadataReader's BuilderType concept for
|
||||
/// building TypeRefs, and parsing field metadata from any images
|
||||
/// it has been made aware of.
|
||||
@@ -686,14 +682,23 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
using RefDemangler = std::function<Demangle::Node * (RemoteRef<char>, bool)>;
|
||||
using UnderlyingTypeReader = std::function<const TypeRef* (uint64_t, unsigned)>;
|
||||
using ByteReader = std::function<remote::MemoryReader::ReadBytesResult (remote::RemoteAddress, unsigned)>;
|
||||
using StringReader = std::function<bool (remote::RemoteAddress, std::string &)>;
|
||||
using PointerReader = std::function<llvm::Optional<remote::RemoteAbsolutePointer> (remote::RemoteAddress, unsigned)>;
|
||||
|
||||
// These fields are captured from the MetadataReader template passed into the
|
||||
// TypeRefBuilder struct, to isolate its template-ness from the rest of
|
||||
// TypeRefBuilder.
|
||||
unsigned PointerSize;
|
||||
std::function<Demangle::Node * (RemoteRef<char>, bool)>
|
||||
TypeRefDemangler;
|
||||
std::function<const TypeRef* (uint64_t, unsigned)>
|
||||
OpaqueUnderlyingTypeReader;
|
||||
RefDemangler TypeRefDemangler;
|
||||
UnderlyingTypeReader OpaqueUnderlyingTypeReader;
|
||||
|
||||
// Opaque fields captured from the MetadataReader's MemoryReader
|
||||
ByteReader OpaqueByteReader;
|
||||
StringReader OpaqueStringReader;
|
||||
PointerReader OpaquePointerReader;
|
||||
|
||||
public:
|
||||
template<typename Runtime>
|
||||
@@ -710,6 +715,15 @@ public:
|
||||
[&reader](uint64_t descriptorAddr, unsigned ordinal) -> const TypeRef* {
|
||||
return reader.readUnderlyingTypeForOpaqueTypeDescriptor(
|
||||
descriptorAddr, ordinal).getType();
|
||||
}),
|
||||
OpaqueByteReader([&reader](remote::RemoteAddress address, unsigned size) -> remote::MemoryReader::ReadBytesResult {
|
||||
return reader.Reader->readBytes(address, size);
|
||||
}),
|
||||
OpaqueStringReader([&reader](remote::RemoteAddress address, std::string &dest) -> bool {
|
||||
return reader.Reader->readString(address, dest);
|
||||
}),
|
||||
OpaquePointerReader([&reader](remote::RemoteAddress address, unsigned size) -> llvm::Optional<remote::RemoteAbsolutePointer> {
|
||||
return reader.Reader->readPointer(address, size);
|
||||
})
|
||||
{}
|
||||
|
||||
@@ -749,16 +763,290 @@ public:
|
||||
/// Dumping typerefs, field declarations, associated types
|
||||
///
|
||||
|
||||
void dumpTypeRef(RemoteRef<char> MangledName,
|
||||
std::ostream &stream, bool printTypeName = false);
|
||||
void dumpTypeRef(RemoteRef<char> MangledName, std::ostream &stream,
|
||||
bool printTypeName = false);
|
||||
void dumpFieldSection(std::ostream &stream);
|
||||
void dumpAssociatedTypeSection(std::ostream &stream);
|
||||
void dumpBuiltinTypeSection(std::ostream &stream);
|
||||
void dumpCaptureSection(std::ostream &stream);
|
||||
void dumpConformanceSection(std::ostream &stream);
|
||||
void dumpAllSections(std::ostream &stream);
|
||||
|
||||
///
|
||||
/// Extraction of protocol conformances
|
||||
///
|
||||
|
||||
private:
|
||||
/// Reader of protocol descriptors from Images
|
||||
template <unsigned PointerSize>
|
||||
struct ProtocolConformanceDescriptorReader {
|
||||
std::string Error;
|
||||
ByteReader OpaqueByteReader;
|
||||
StringReader OpaqueStringReader;
|
||||
PointerReader OpaquePointerReader;
|
||||
|
||||
ProtocolConformanceDescriptorReader(ByteReader byteReader,
|
||||
StringReader stringReader,
|
||||
PointerReader pointerReader)
|
||||
: Error(""), OpaqueByteReader(byteReader),
|
||||
OpaqueStringReader(stringReader), OpaquePointerReader(pointerReader) {
|
||||
}
|
||||
|
||||
std::string getConformingTypeName(
|
||||
const char *conformanceDescriptorAddress,
|
||||
const ExternalProtocolConformanceDescriptor<PointerSize>
|
||||
&conformanceDescriptor) {
|
||||
std::string typeName;
|
||||
// Compute the address of the type descriptor as follows:
|
||||
// - Compute the address of the TypeRef field in the protocol
|
||||
// descriptor
|
||||
// - Read the TypeRef field to compute the offset to the type
|
||||
// descriptor
|
||||
// - Address of the type descriptor is found at the (2) offset from the
|
||||
// conformance descriptor address
|
||||
auto contextDescriptorFieldAddress = detail::applyRelativeOffset(
|
||||
conformanceDescriptorAddress,
|
||||
(int32_t)conformanceDescriptor.getTypeDescriptorOffset());
|
||||
auto contextDescriptorOffsetBytes =
|
||||
OpaqueByteReader(remote::RemoteAddress(contextDescriptorFieldAddress),
|
||||
sizeof(uint32_t));
|
||||
if (!contextDescriptorOffsetBytes.get()) {
|
||||
Error = "Failed to read type descriptor field in conformance descriptor.";
|
||||
return typeName;
|
||||
}
|
||||
auto contextDescriptorOffset =
|
||||
(const uint32_t *)contextDescriptorOffsetBytes.get();
|
||||
|
||||
// Read the type descriptor itself using the address computed above
|
||||
auto contextDescriptorAddress = detail::applyRelativeOffset(
|
||||
(const char *)contextDescriptorFieldAddress,
|
||||
(int32_t)*contextDescriptorOffset);
|
||||
auto contextDescriptorBytes =
|
||||
OpaqueByteReader(remote::RemoteAddress(contextDescriptorAddress),
|
||||
sizeof(ExternalContextDescriptor<PointerSize>));
|
||||
if (!contextDescriptorBytes.get()) {
|
||||
Error = "Failed to read context descriptor.";
|
||||
return typeName;
|
||||
}
|
||||
const ExternalContextDescriptor<PointerSize> *contextDescriptor =
|
||||
(const ExternalContextDescriptor<PointerSize> *)
|
||||
contextDescriptorBytes.get();
|
||||
|
||||
auto typeDescriptor =
|
||||
dyn_cast<ExternalTypeContextDescriptor<PointerSize>>(
|
||||
contextDescriptor);
|
||||
if (!typeDescriptor) {
|
||||
Error = "Unexpected type of context descriptor.";
|
||||
return typeName;
|
||||
}
|
||||
|
||||
// Compute the address of the type descriptor's name field and read the
|
||||
// offset
|
||||
auto typeNameOffsetAddress =
|
||||
detail::applyRelativeOffset((const char *)contextDescriptorAddress,
|
||||
(int32_t)typeDescriptor->getNameOffset());
|
||||
auto typeNameOfsetBytes = OpaqueByteReader(
|
||||
remote::RemoteAddress(typeNameOffsetAddress), sizeof(uint32_t));
|
||||
if (!typeNameOfsetBytes.get()) {
|
||||
Error = "Failed to read type name offset in a type descriptor.";
|
||||
return typeName;
|
||||
}
|
||||
auto typeNameOffset = (const uint32_t *)typeNameOfsetBytes.get();
|
||||
|
||||
// Using the offset above, compute the address of the name field itsel
|
||||
// and read it.
|
||||
auto typeNameAddress = detail::applyRelativeOffset(
|
||||
(const char *)typeNameOffsetAddress, (int32_t)*typeNameOffset);
|
||||
OpaqueStringReader(remote::RemoteAddress(typeNameAddress), typeName);
|
||||
return typeName;
|
||||
}
|
||||
|
||||
std::string getConformanceProtocol(
|
||||
const char *conformanceDescriptorAddress,
|
||||
const ExternalProtocolConformanceDescriptor<PointerSize>
|
||||
&conformanceDescriptor) {
|
||||
std::string protocolName = "";
|
||||
auto protocolDescriptorFieldAddress = detail::applyRelativeOffset(
|
||||
conformanceDescriptorAddress,
|
||||
(int32_t)conformanceDescriptor.getProtocolDescriptorOffset());
|
||||
|
||||
auto protocolDescriptorOffsetBytes = OpaqueByteReader(
|
||||
remote::RemoteAddress(protocolDescriptorFieldAddress),
|
||||
sizeof(uint32_t));
|
||||
if (!protocolDescriptorOffsetBytes.get()) {
|
||||
Error = "Error reading protocol descriptor field in conformance descriptor.";
|
||||
return protocolName;
|
||||
}
|
||||
auto protocolDescriptorOffset =
|
||||
(const uint32_t *)protocolDescriptorOffsetBytes.get();
|
||||
|
||||
auto protocolDescriptorTarget = detail::applyRelativeOffset(
|
||||
(const char *)protocolDescriptorFieldAddress,
|
||||
(int32_t)*protocolDescriptorOffset);
|
||||
|
||||
// If indirect, attempt to get symbol name from external bindings
|
||||
if ((uint64_t)protocolDescriptorTarget & 0x1) {
|
||||
auto adjustedProtocolDescriptorTarget =
|
||||
(const void *)((uint64_t)protocolDescriptorTarget & ~(0x1));
|
||||
if (auto symbol = OpaquePointerReader(
|
||||
remote::RemoteAddress(adjustedProtocolDescriptorTarget), 8)) {
|
||||
|
||||
Demangle::Context Ctx;
|
||||
auto demangledRoot =
|
||||
Ctx.demangleSymbolAsNode(symbol->getSymbol().str());
|
||||
assert(demangledRoot->getKind() == Node::Kind::Global);
|
||||
assert(demangledRoot->getChild(0)->getKind() ==
|
||||
Node::Kind::ProtocolDescriptor);
|
||||
protocolName = nodeToString(demangledRoot->getChild(0)->getChild(0));
|
||||
} else {
|
||||
Error = "Error reading external protocol address.";
|
||||
return protocolName;
|
||||
}
|
||||
// If direct, read the protocol descriptor and get symbol name
|
||||
} else {
|
||||
auto protocolDescriptorBytes =
|
||||
OpaqueByteReader(remote::RemoteAddress(protocolDescriptorTarget),
|
||||
sizeof(ExternalProtocolDescriptor<PointerSize>));
|
||||
if (!protocolDescriptorBytes.get()) {
|
||||
Error = "Error reading protocol descriptor.";
|
||||
return protocolName;
|
||||
}
|
||||
const ExternalProtocolDescriptor<PointerSize> *protocolDescriptor =
|
||||
(const ExternalProtocolDescriptor<PointerSize> *)
|
||||
protocolDescriptorBytes.get();
|
||||
|
||||
// Compute the address of the protocol descriptor's name field and read
|
||||
// the offset
|
||||
auto protocolNameOffsetAddress = detail::applyRelativeOffset(
|
||||
(const char *)protocolDescriptorTarget,
|
||||
(int32_t)protocolDescriptor->getNameOffset());
|
||||
auto protocolNameOfsetBytes = OpaqueByteReader(
|
||||
remote::RemoteAddress(protocolNameOffsetAddress), sizeof(uint32_t));
|
||||
if (!protocolNameOfsetBytes.get()) {
|
||||
Error = "Failed to read type name offset in a protocol descriptor.";
|
||||
return protocolName;
|
||||
}
|
||||
auto protocolNameOffset =
|
||||
(const uint32_t *)protocolNameOfsetBytes.get();
|
||||
|
||||
// Using the offset above, compute the address of the name field itsel
|
||||
// and read it.
|
||||
auto protocolNameAddress =
|
||||
detail::applyRelativeOffset((const char *)protocolNameOffsetAddress,
|
||||
(int32_t)*protocolNameOffset);
|
||||
OpaqueStringReader(remote::RemoteAddress(protocolNameAddress),
|
||||
protocolName);
|
||||
}
|
||||
|
||||
return protocolName;
|
||||
}
|
||||
|
||||
/// Given the address of a conformance descriptor, attempt to read it.
|
||||
ProtocolConformanceInfo
|
||||
readConformanceDescriptor(RemoteRef<void> conformanceRecordRef) {
|
||||
const ExternalProtocolConformanceRecord<PointerSize> *CD =
|
||||
(const ExternalProtocolConformanceRecord<PointerSize> *)
|
||||
conformanceRecordRef.getLocalBuffer();
|
||||
// Read the Protocol Conformance Descriptor by getting its address from
|
||||
// the conformance record.
|
||||
auto conformanceDescriptorAddress = (const char *)CD->getRelative(
|
||||
(void *)conformanceRecordRef.getAddressData());
|
||||
|
||||
auto descriptorBytes = OpaqueByteReader(
|
||||
remote::RemoteAddress(conformanceDescriptorAddress),
|
||||
sizeof(ExternalProtocolConformanceDescriptor<PointerSize>));
|
||||
if (!descriptorBytes.get()) {
|
||||
Error = "Failed to read protocol conformance descriptor.";
|
||||
return ProtocolConformanceInfo();
|
||||
}
|
||||
const ExternalProtocolConformanceDescriptor<PointerSize>
|
||||
*conformanceDescriptorPtr =
|
||||
(const ExternalProtocolConformanceDescriptor<PointerSize> *)
|
||||
descriptorBytes.get();
|
||||
|
||||
auto conformingTypeName = getConformingTypeName(
|
||||
conformanceDescriptorAddress, *conformanceDescriptorPtr);
|
||||
auto conformanceProtocol = getConformanceProtocol(
|
||||
conformanceDescriptorAddress, *conformanceDescriptorPtr);
|
||||
|
||||
return ProtocolConformanceInfo{conformingTypeName,
|
||||
conformanceProtocol};
|
||||
}
|
||||
|
||||
bool hasError() {
|
||||
return !Error.empty();
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
template <unsigned PointerSize>
|
||||
void dumpConformanceSection(std::ostream &stream) {
|
||||
// Collect all conformances and aggregate them per-conforming-type.
|
||||
std::unordered_map<std::string, std::vector<std::string>> typeConformances;
|
||||
ProtocolConformanceDescriptorReader<PointerSize> conformanceReader(
|
||||
OpaqueByteReader, OpaqueStringReader, OpaquePointerReader);
|
||||
|
||||
for (const auto §ion : ReflectionInfos) {
|
||||
auto ConformanceBegin = section.Conformance.startAddress();
|
||||
auto ConformanceEnd = section.Conformance.endAddress();
|
||||
for (auto conformanceAddr = ConformanceBegin;
|
||||
conformanceAddr != ConformanceEnd;
|
||||
conformanceAddr = conformanceAddr.atByteOffset(4)) {
|
||||
auto conformanceInfo =
|
||||
conformanceReader.readConformanceDescriptor(conformanceAddr);
|
||||
if (conformanceReader.hasError()) {
|
||||
stream << "Error reading conformance descriptor: "
|
||||
<< conformanceReader.Error << "\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (typeConformances.count(conformanceInfo.typeName) != 0) {
|
||||
typeConformances[conformanceInfo.typeName].push_back(
|
||||
conformanceInfo.protocolName);
|
||||
} else {
|
||||
typeConformances.emplace(
|
||||
conformanceInfo.typeName,
|
||||
std::vector<std::string>{conformanceInfo.protocolName});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &pair : typeConformances) {
|
||||
stream << pair.first << " : ";
|
||||
bool first = true;
|
||||
for (auto &protocol : pair.second) {
|
||||
if (!first) {
|
||||
stream << ", ";
|
||||
}
|
||||
first = false;
|
||||
stream << protocol;
|
||||
}
|
||||
stream << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned PointerSize>
|
||||
void dumpAllSections(std::ostream &stream) {
|
||||
stream << "FIELDS:\n";
|
||||
stream << "=======\n";
|
||||
dumpFieldSection(stream);
|
||||
stream << "\n";
|
||||
stream << "ASSOCIATED TYPES:\n";
|
||||
stream << "=================\n";
|
||||
dumpAssociatedTypeSection(stream);
|
||||
stream << "\n";
|
||||
stream << "BUILTIN TYPES:\n";
|
||||
stream << "==============\n";
|
||||
dumpBuiltinTypeSection(stream);
|
||||
stream << "\n";
|
||||
stream << "CAPTURE DESCRIPTORS:\n";
|
||||
stream << "====================\n";
|
||||
dumpCaptureSection(stream);
|
||||
stream << "\n";
|
||||
stream << "CONFORMANCES:\n";
|
||||
stream << "=============\n";
|
||||
dumpConformanceSection<PointerSize>(stream);
|
||||
stream << "\n";
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace reflection
|
||||
} // end namespace swift
|
||||
|
||||
@@ -126,6 +126,7 @@ struct ReflectionContextHolder {
|
||||
ReflectionContextOwner Owner;
|
||||
reflection::TypeRefBuilder &Builder;
|
||||
ObjectMemoryReader &Reader;
|
||||
uint8_t PointerSize;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
add_swift_host_library(swiftStaticMirror STATIC
|
||||
ObjectFileContext.cpp)
|
||||
|
||||
|
||||
@@ -496,7 +496,7 @@ ObjectMemoryReader::resolvePointer(reflection::RemoteAddress Addr,
|
||||
|
||||
template <typename Runtime>
|
||||
ReflectionContextHolder makeReflectionContextForMetadataReader(
|
||||
std::shared_ptr<ObjectMemoryReader> reader) {
|
||||
std::shared_ptr<ObjectMemoryReader> reader, uint8_t pointerSize) {
|
||||
using ReflectionContext = reflection::ReflectionContext<Runtime>;
|
||||
auto context = new ReflectionContext(reader);
|
||||
auto &builder = context->getBuilder();
|
||||
@@ -505,11 +505,7 @@ ReflectionContextHolder makeReflectionContextForMetadataReader(
|
||||
}
|
||||
return {ReflectionContextOwner(
|
||||
context, [](void *x) { delete (ReflectionContext *)x; }),
|
||||
builder, *reader};
|
||||
}
|
||||
|
||||
uint8_t queryPointerSize(const std::vector<const ObjectFile *> &objectFiles) {
|
||||
|
||||
builder, *reader, pointerSize};
|
||||
}
|
||||
|
||||
ReflectionContextHolder makeReflectionContextForObjectFiles(
|
||||
@@ -521,6 +517,7 @@ ReflectionContextHolder makeReflectionContextForObjectFiles(
|
||||
&pointerSize);
|
||||
|
||||
switch (pointerSize) {
|
||||
case 4:
|
||||
return makeReflectionContextForMetadataReader<
|
||||
// FIXME: This could be configurable.
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
@@ -528,7 +525,7 @@ ReflectionContextHolder makeReflectionContextForObjectFiles(
|
||||
#else
|
||||
External<NoObjCInterop<RuntimeTarget<4>>>
|
||||
#endif
|
||||
>(std::move(Reader));
|
||||
>(std::move(Reader), pointerSize);
|
||||
case 8:
|
||||
return makeReflectionContextForMetadataReader<
|
||||
// FIXME: This could be configurable.
|
||||
@@ -537,7 +534,7 @@ ReflectionContextHolder makeReflectionContextForObjectFiles(
|
||||
#else
|
||||
External<NoObjCInterop<RuntimeTarget<8>>>
|
||||
#endif
|
||||
>(std::move(Reader));
|
||||
>(std::move(Reader), pointerSize);
|
||||
default:
|
||||
fputs("unsupported word size in object file\n", stderr);
|
||||
abort();
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#if SWIFT_ENABLE_REFLECTION
|
||||
|
||||
#include "swift/Reflection/TypeRefBuilder.h"
|
||||
|
||||
#include "swift/Demangling/Demangle.h"
|
||||
#include "swift/Reflection/Records.h"
|
||||
#include "swift/Reflection/TypeLowering.h"
|
||||
@@ -29,6 +28,7 @@
|
||||
|
||||
using namespace swift;
|
||||
using namespace reflection;
|
||||
using ReadBytesResult = swift::remote::MemoryReader::ReadBytesResult;
|
||||
|
||||
TypeRefBuilder::BuiltType
|
||||
TypeRefBuilder::decodeMangledType(Node *node, bool forRequirement) {
|
||||
@@ -496,61 +496,4 @@ void TypeRefBuilder::dumpCaptureSection(std::ostream &stream) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Given the address of a conformance descriptor, attempt to read it.
|
||||
static void readConformanceDescriptor(const ExternalProtocolConformanceRecord &record) {
|
||||
|
||||
// Read the flags to figure out how much space we should read.
|
||||
// ContextDescriptorFlags flags;
|
||||
// if (!Reader->readBytes(RemoteAddress(address), (uint8_t*)&flags,
|
||||
// sizeof(flags)))
|
||||
// return nullptr;
|
||||
}
|
||||
|
||||
void TypeRefBuilder::dumpConformanceSection(std::ostream &stream) {
|
||||
for (const auto §ion : ReflectionInfos) {
|
||||
for (const auto conformanceRecord : section.Conformance) {
|
||||
stream << "dummy\n";
|
||||
readConformanceDescriptor(conformanceRecord->get());
|
||||
|
||||
// switch (auto kind = conformance->getTypeKind()) {
|
||||
// case TypeReferenceKind::DirectObjCClassName:
|
||||
// stream << "DirectObjCClassName\n";
|
||||
// break;
|
||||
//
|
||||
// case TypeReferenceKind::IndirectObjCClass:
|
||||
// stream << "IndirectObjCClass\n";
|
||||
// break;
|
||||
//
|
||||
// case TypeReferenceKind::DirectTypeDescriptor:
|
||||
// case TypeReferenceKind::IndirectTypeDescriptor:
|
||||
// stream << "TypeDescriptor\n";
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TypeRefBuilder::dumpAllSections(std::ostream &stream) {
|
||||
stream << "FIELDS:\n";
|
||||
stream << "=======\n";
|
||||
dumpFieldSection(stream);
|
||||
stream << "\n";
|
||||
stream << "ASSOCIATED TYPES:\n";
|
||||
stream << "=================\n";
|
||||
dumpAssociatedTypeSection(stream);
|
||||
stream << "\n";
|
||||
stream << "BUILTIN TYPES:\n";
|
||||
stream << "==============\n";
|
||||
dumpBuiltinTypeSection(stream);
|
||||
stream << "\n";
|
||||
stream << "CAPTURE DESCRIPTORS:\n";
|
||||
stream << "====================\n";
|
||||
dumpCaptureSection(stream);
|
||||
stream << "\n";
|
||||
stream << "CONFORMANCES:\n";
|
||||
stream << "=============\n";
|
||||
dumpConformanceSection(stream);
|
||||
stream << "\n";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -217,7 +217,7 @@ swift_reflection_addReflectionInfo(SwiftReflectionContextRef ContextRef,
|
||||
sectionFromInfo<const void *>(Info, Info.type_references),
|
||||
sectionFromInfo<const void *>(Info, Info.reflection_strings),
|
||||
// TODO: Conformance section
|
||||
ConformanceSection(RemoteRef<void>(), 0)};
|
||||
ReflectionSection<const void *>(nullptr, 0)};
|
||||
|
||||
Context->addReflectionInfo(ContextInfo);
|
||||
}
|
||||
@@ -238,7 +238,7 @@ void swift_reflection_addReflectionMappingInfo(
|
||||
reflectionSectionFromLocalAndRemote<const void *>(Info.type_references),
|
||||
reflectionSectionFromLocalAndRemote<const void *>(Info.reflection_strings),
|
||||
// TODO: Conformance section
|
||||
ConformanceSection(RemoteRef<void>(), 0)};
|
||||
ReflectionSection<const void *>(nullptr, 0)};
|
||||
|
||||
Context->addReflectionInfo(ContextInfo);
|
||||
}
|
||||
|
||||
4
test/Reflection/Inputs/Conformances.swift
Normal file
4
test/Reflection/Inputs/Conformances.swift
Normal file
@@ -0,0 +1,4 @@
|
||||
public protocol MyProto {}
|
||||
struct StructA : MyProto, Hashable {
|
||||
var x: Int
|
||||
}
|
||||
8
test/Reflection/conformance_descriptors.swift
Normal file
8
test/Reflection/conformance_descriptors.swift
Normal file
@@ -0,0 +1,8 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
|
||||
// RUN: %target-build-swift -Xfrontend -enable-anonymous-context-mangled-names %S/Inputs/ConcreteTypes.swift %S/Inputs/Conformances.swift -parse-as-library -emit-module -emit-library -module-name TypesToReflect -o %t/Conformances
|
||||
// RUN: %target-swift-reflection-dump -binary-filename %t/Conformances | %FileCheck %s
|
||||
|
||||
// CHECK: CONFORMANCES:
|
||||
// CHECK: =============
|
||||
// CHECK: StructA : MyProto, Swift.Hashable, Swift.Equatable
|
||||
@@ -115,7 +115,17 @@ static int doDumpReflectionSections(ArrayRef<std::string> BinaryFilenames,
|
||||
switch (Action) {
|
||||
case ActionType::DumpReflectionSections:
|
||||
// Dump everything
|
||||
builder.dumpAllSections(stream);
|
||||
switch (context.PointerSize) {
|
||||
case 4:
|
||||
builder.dumpAllSections<4>(stream);
|
||||
break;
|
||||
case 8:
|
||||
builder.dumpAllSections<8>(stream);
|
||||
break;
|
||||
default:
|
||||
fputs("unsupported word size in object file\n", stderr);
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
case ActionType::DumpTypeLowering: {
|
||||
for (std::string Line; std::getline(std::cin, Line);) {
|
||||
|
||||
Reference in New Issue
Block a user