[Reflection] Implement swift_reflection_addImage which takes care of looking up reflection info on behalf of the client.

rdar://problem/37538580
This commit is contained in:
Mike Ash
2018-02-20 16:47:07 -05:00
parent 902e34a68e
commit 1dcdd939ca
5 changed files with 181 additions and 257 deletions

View File

@@ -54,10 +54,18 @@ swift_reflection_createReflectionContext(
void
swift_reflection_destroyReflectionContext(SwiftReflectionContextRef Context);
/// Add reflection information from a loaded Swift image.
/// Add reflection sections for a loaded Swift image.
void
swift_reflection_addImage(SwiftReflectionContextRef ContextRef, swift_addr_t imageStart);
swift_reflection_addReflectionInfo(SwiftReflectionContextRef ContextRef,
swift_reflection_info_t Info);
#ifdef __APPLE__
/// Add reflection information from a loaded Swift image.
/// Returns true on success, false if the image's memory couldn't be read.
int
swift_reflection_addImage(SwiftReflectionContextRef ContextRef,
swift_addr_t imageStart, uint64_t imageLength);
#endif
/// Returns a boolean indicating if the isa mask was successfully
/// read, in which case it is stored in the isaMask out parameter.

View File

@@ -26,6 +26,50 @@ extern "C" {
typedef uintptr_t swift_typeref_t;
/// \brief Represents one of the Swift reflection sections of an image.
typedef struct swift_reflection_section {
void *Begin;
void *End;
} swift_reflection_section_t;
/// \brief Represents the set of Swift reflection sections of an image.
/// Not all sections may be present.
typedef struct swift_reflection_info {
struct {
swift_reflection_section_t section;
uintptr_t offset;
} field;
struct {
swift_reflection_section_t section;
uintptr_t offset;
} associated_types;
struct {
swift_reflection_section_t section;
uintptr_t offset;
} builtin_types;
struct {
swift_reflection_section_t section;
uintptr_t offset;
} capture;
struct {
swift_reflection_section_t section;
uintptr_t offset;
} type_references;
struct {
swift_reflection_section_t section;
uintptr_t offset;
} reflection_strings;
// Start address in local and remote address spaces.
uintptr_t LocalStartAddress;
uintptr_t RemoteStartAddress;
} swift_reflection_info_t;
/// The layout kind of a Swift type.
typedef enum swift_layout_kind {
// Nothing is known about the size or contents of this value.

View File

@@ -45,96 +45,25 @@ public enum InstanceKind : UInt8 {
case Closure
}
/// Represents a section in a loaded image in this process.
internal struct Section {
/// The absolute start address of the section's data in this address space.
let startAddress: UnsafeRawPointer
/// The size of the section in bytes.
let size: UInt
}
/// Holds the addresses and sizes of sections related to reflection
internal struct ReflectionInfo : Sequence {
/// The name of the loaded image
internal let imageName: String
/// Reflection metadata sections
internal let fieldmd: Section?
internal let assocty: Section?
internal let builtin: Section?
internal let capture: Section?
internal let typeref: Section?
internal let reflstr: Section?
internal func makeIterator() -> AnyIterator<Section?> {
return AnyIterator([
fieldmd,
assocty,
builtin,
capture,
typeref,
reflstr
].makeIterator())
}
}
#if arch(x86_64) || arch(arm64)
typealias MachHeader = mach_header_64
#else
typealias MachHeader = mach_header
#endif
/// Get the location and size of a section in a binary.
///
/// - Parameter name: The name of the section
/// - Parameter imageHeader: A pointer to the Mach header describing the
/// image.
/// - Returns: A `Section` containing the address and size, or `nil` if there
/// is no section by the given name.
internal func getSectionInfo(_ name: String,
_ imageHeader: UnsafePointer<MachHeader>) -> Section? {
debugLog("BEGIN \(#function)"); defer { debugLog("END \(#function)") }
var size: UInt = 0
let address = getsectiondata(imageHeader, "__TEXT", name, &size)
guard let nonNullAddress = address else { return nil }
guard size != 0 else { return nil }
return Section(startAddress: nonNullAddress, size: size)
}
/// Get the Swift Reflection section locations for a loaded image.
///
/// An image of interest must have the following sections in the __DATA
/// segment:
/// - __swift5_fieldmd
/// - __swift5_assocty
/// - __swift5_builtin
/// - __swift5_capture
/// - __swift5_typeref
/// - __swift5_reflstr (optional, may have been stripped out)
/// Get the TEXT segment location and size for a loaded image.
///
/// - Parameter i: The index of the loaded image as reported by Dyld.
/// - Returns: A `ReflectionInfo` containing the locations of all of the
/// needed sections, or `nil` if the image doesn't contain all of them.
internal func getReflectionInfoForImage(atIndex i: UInt32) -> ReflectionInfo? {
/// - Returns: The image name, address, and size.
internal func getAddressInfoForImage(atIndex i: UInt32) ->
(name: String, address: UnsafeMutablePointer<UInt8>?, size: UInt) {
debugLog("BEGIN \(#function)"); defer { debugLog("END \(#function)") }
let header = unsafeBitCast(_dyld_get_image_header(i),
to: UnsafePointer<MachHeader>.self)
let imageName = _dyld_get_image_name(i)!
let fieldmd = getSectionInfo("__swift5_fieldmd", header)
let assocty = getSectionInfo("__swift5_assocty", header)
let builtin = getSectionInfo("__swift5_builtin", header)
let capture = getSectionInfo("__swift5_capture", header)
let typeref = getSectionInfo("__swift5_typeref", header)
let reflstr = getSectionInfo("__swift5_reflstr", header)
return ReflectionInfo(imageName: String(validatingUTF8: imageName)!,
fieldmd: fieldmd,
assocty: assocty,
builtin: builtin,
capture: capture,
typeref: typeref,
reflstr: reflstr)
let name = String(validatingUTF8: _dyld_get_image_name(i)!)!
var size: UInt = 0
let address = getsegmentdata(header, "__TEXT", &size)
return (name, address, size)
}
internal func sendBytes<T>(from address: UnsafePointer<T>, count: Int) {
@@ -179,18 +108,15 @@ internal func readUInt() -> UInt {
/// process.
internal func sendReflectionInfos() {
debugLog("BEGIN \(#function)"); defer { debugLog("END \(#function)") }
let infos = (0..<_dyld_image_count()).compactMap(getReflectionInfoForImage)
let infos = (0..<_dyld_image_count()).map(getAddressInfoForImage)
var numInfos = infos.count
debugLog("\(numInfos) reflection info bundles.")
precondition(numInfos >= 1)
sendBytes(from: &numInfos, count: MemoryLayout<UInt>.size)
for info in infos {
debugLog("Sending info for \(info.imageName)")
for section in info {
sendValue(section?.startAddress)
sendValue(section?.size ?? 0)
}
debugLog("\(infos.count) reflection info bundles.")
precondition(infos.count >= 1)
sendValue(infos.count)
for (name, address, size) in infos {
debugLog("Sending info for \(name)")
sendValue(address)
sendValue(size)
}
}
@@ -256,8 +182,7 @@ internal func sendPointerSize() {
/// This is the main "run loop" of the test harness.
///
/// The parent will necessarily need to:
/// - Get the addresses of all of the reflection sections for any swift dylibs
/// that are loaded, where applicable.
/// - Get the addresses of any swift dylibs that are loaded, where applicable.
/// - Get the address of the `instance`
/// - Get the pointer size of this process, which affects assumptions about the
/// the layout of runtime structures with pointer-sized fields.

View File

@@ -16,6 +16,10 @@
#include "swift/Runtime/Unreachable.h"
#include "swift/SwiftRemoteMirror/SwiftRemoteMirror.h"
#ifdef __APPLE__
#include <mach-o/getsect.h>
#endif
using namespace swift;
using namespace swift::reflection;
using namespace swift::remote;
@@ -23,6 +27,20 @@ using namespace swift::remote;
using NativeReflectionContext
= ReflectionContext<External<RuntimeTarget<sizeof(uintptr_t)>>>;
struct SwiftReflectionContext {
NativeReflectionContext *nativeContext;
SwiftReflectionContext(MemoryReaderImpl impl) {
auto Reader = std::make_shared<CMemoryReader>(impl);
nativeContext = new NativeReflectionContext(Reader);
}
~SwiftReflectionContext() {
delete nativeContext;
}
};
uint16_t
swift_reflection_getSupportedMetadataVersion() {
return SWIFT_REFLECTION_METADATA_VERSION;
@@ -44,28 +62,90 @@ swift_reflection_createReflectionContext(void *ReaderContext,
getSymbolAddress
};
auto Reader = std::make_shared<CMemoryReader>(ReaderImpl);
auto Context
= new swift::reflection::ReflectionContext<External<RuntimeTarget<sizeof(uintptr_t)>>>(Reader);
return reinterpret_cast<SwiftReflectionContextRef>(Context);
return new SwiftReflectionContext(ReaderImpl);
}
void swift_reflection_destroyReflectionContext(SwiftReflectionContextRef ContextRef) {
auto Context = reinterpret_cast<swift::reflection::ReflectionContext<InProcess> *>(ContextRef);
delete Context;
delete ContextRef;
}
void
swift_reflection_addReflectionInfo(SwiftReflectionContextRef ContextRef,
swift_reflection_info_t Info) {
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
auto Context = ContextRef->nativeContext;
Context->addReflectionInfo(*reinterpret_cast<ReflectionInfo *>(&Info));
}
#ifdef __APPLE__
#ifndef __LP64__
typedef const struct mach_header MachHeader;
#else
typedef const struct mach_header_64 MachHeader;
#endif
template <typename Section>
static bool findSection(MachHeader *Header, const char *Name,
Section &Sect) {
unsigned long Size;
auto Address = getsectiondata(Header, "__TEXT", Name, &Size);
if (!Address)
return false;
Sect.section.Begin = Address;
auto End = reinterpret_cast<uintptr_t>(Address) + Size;
Sect.section.End = reinterpret_cast<void *>(End);
Sect.offset = 0;
return true;
}
int
swift_reflection_addImage(SwiftReflectionContextRef ContextRef,
swift_addr_t imageStart, uint64_t imageLength) {
auto Context = ContextRef->nativeContext;
if (imageLength < sizeof(MachHeader)) {
return 0;
}
auto Buf = malloc(imageLength);
Context->getReader().readBytes(RemoteAddress(imageStart),
reinterpret_cast<uint8_t *>(Buf),
imageLength);
auto Header = reinterpret_cast<MachHeader *>(Buf);
if (Header->magic != MH_MAGIC && Header->magic != MH_MAGIC_64) {
return 0;
}
swift_reflection_info_t info = {};
// The docs say "not all sections may be present." We'll succeed if ANY of them are
// present. Not sure if that's the right thing to do.
bool success = false;
success = findSection(Header, "__swift5_fieldmd", info.field) || success;
success = findSection(Header, "__swift5_assocty", info.associated_types) || success;
success = findSection(Header, "__swift5_builtin", info.builtin_types) || success;
success = findSection(Header, "__swift5_capture", info.capture) || success;
success = findSection(Header, "__swift5_typeref", info.type_references) || success;
success = findSection(Header, "__swift5_reflstr", info.reflection_strings) || success;
if (success) {
info.LocalStartAddress = reinterpret_cast<uintptr_t>(Buf);
info.RemoteStartAddress = imageStart;
swift_reflection_addReflectionInfo(ContextRef, info);
return 1;
} else {
return 0;
}
}
#endif
int
swift_reflection_readIsaMask(SwiftReflectionContextRef ContextRef,
uintptr_t *outIsaMask) {
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
auto Context = ContextRef->nativeContext;
auto isaMask = Context->readIsaMask();
if (isaMask) {
*outIsaMask = *isaMask;
@@ -78,7 +158,7 @@ swift_reflection_readIsaMask(SwiftReflectionContextRef ContextRef,
swift_typeref_t
swift_reflection_typeRefForMetadata(SwiftReflectionContextRef ContextRef,
uintptr_t Metadata) {
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
auto Context = ContextRef->nativeContext;
auto TR = Context->readTypeFromMetadata(Metadata);
return reinterpret_cast<swift_typeref_t>(TR);
}
@@ -86,7 +166,7 @@ swift_reflection_typeRefForMetadata(SwiftReflectionContextRef ContextRef,
swift_typeref_t
swift_reflection_typeRefForInstance(SwiftReflectionContextRef ContextRef,
uintptr_t Object) {
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
auto Context = ContextRef->nativeContext;
auto MetadataAddress = Context->readMetadataFromInstance(Object);
if (!MetadataAddress)
return 0;
@@ -98,7 +178,7 @@ swift_typeref_t
swift_reflection_typeRefForMangledTypeName(SwiftReflectionContextRef ContextRef,
const char *MangledTypeName,
uint64_t Length) {
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
auto Context = ContextRef->nativeContext;
auto TR = Context->readTypeFromMangledName(MangledTypeName, Length);
return reinterpret_cast<swift_typeref_t>(TR);
}
@@ -223,7 +303,7 @@ static swift_childinfo_t convertChild(const TypeInfo *TI, unsigned Index) {
swift_typeinfo_t
swift_reflection_infoForTypeRef(SwiftReflectionContextRef ContextRef,
swift_typeref_t OpaqueTypeRef) {
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
auto Context = ContextRef->nativeContext;
auto TR = reinterpret_cast<const TypeRef *>(OpaqueTypeRef);
auto TI = Context->getTypeInfo(TR);
return convertTypeInfo(TI);
@@ -233,7 +313,7 @@ swift_childinfo_t
swift_reflection_childOfTypeRef(SwiftReflectionContextRef ContextRef,
swift_typeref_t OpaqueTypeRef,
unsigned Index) {
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
auto Context = ContextRef->nativeContext;
auto TR = reinterpret_cast<const TypeRef *>(OpaqueTypeRef);
auto *TI = Context->getTypeInfo(TR);
return convertChild(TI, Index);
@@ -242,7 +322,7 @@ swift_reflection_childOfTypeRef(SwiftReflectionContextRef ContextRef,
swift_typeinfo_t
swift_reflection_infoForMetadata(SwiftReflectionContextRef ContextRef,
uintptr_t Metadata) {
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
auto Context = ContextRef->nativeContext;
auto *TI = Context->getMetadataTypeInfo(Metadata);
return convertTypeInfo(TI);
}
@@ -251,7 +331,7 @@ swift_childinfo_t
swift_reflection_childOfMetadata(SwiftReflectionContextRef ContextRef,
uintptr_t Metadata,
unsigned Index) {
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
auto Context = ContextRef->nativeContext;
auto *TI = Context->getMetadataTypeInfo(Metadata);
return convertChild(TI, Index);
}
@@ -259,7 +339,7 @@ swift_reflection_childOfMetadata(SwiftReflectionContextRef ContextRef,
swift_typeinfo_t
swift_reflection_infoForInstance(SwiftReflectionContextRef ContextRef,
uintptr_t Object) {
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
auto Context = ContextRef->nativeContext;
auto *TI = Context->getInstanceTypeInfo(Object);
return convertTypeInfo(TI);
}
@@ -268,7 +348,7 @@ swift_childinfo_t
swift_reflection_childOfInstance(SwiftReflectionContextRef ContextRef,
uintptr_t Object,
unsigned Index) {
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
auto Context = ContextRef->nativeContext;
auto *TI = Context->getInstanceTypeInfo(Object);
return convertChild(TI, Index);
}
@@ -278,7 +358,7 @@ int swift_reflection_projectExistential(SwiftReflectionContextRef ContextRef,
swift_typeref_t ExistentialTypeRef,
swift_typeref_t *InstanceTypeRef,
swift_addr_t *StartOfInstanceData) {
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
auto Context = ContextRef->nativeContext;
auto ExistentialTR = reinterpret_cast<const TypeRef *>(ExistentialTypeRef);
auto RemoteExistentialAddress = RemoteAddress(ExistentialAddress);
const TypeRef *InstanceTR = nullptr;
@@ -307,7 +387,7 @@ void swift_reflection_dumpTypeRef(swift_typeref_t OpaqueTypeRef) {
void swift_reflection_dumpInfoForTypeRef(SwiftReflectionContextRef ContextRef,
swift_typeref_t OpaqueTypeRef) {
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
auto Context = ContextRef->nativeContext;
auto TR = reinterpret_cast<const TypeRef *>(OpaqueTypeRef);
auto TI = Context->getTypeInfo(TR);
if (TI == nullptr) {
@@ -319,7 +399,7 @@ void swift_reflection_dumpInfoForTypeRef(SwiftReflectionContextRef ContextRef,
void swift_reflection_dumpInfoForMetadata(SwiftReflectionContextRef ContextRef,
uintptr_t Metadata) {
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
auto Context = ContextRef->nativeContext;
auto TI = Context->getMetadataTypeInfo(Metadata);
if (TI == nullptr) {
std::cout << "<null type info>\n";
@@ -330,7 +410,7 @@ void swift_reflection_dumpInfoForMetadata(SwiftReflectionContextRef ContextRef,
void swift_reflection_dumpInfoForInstance(SwiftReflectionContextRef ContextRef,
uintptr_t Object) {
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
auto Context = ContextRef->nativeContext;
auto TI = Context->getInstanceTypeInfo(Object);
if (TI == nullptr) {
std::cout << "<null type info>\n";

View File

@@ -29,28 +29,11 @@
#include <string.h>
#include <unistd.h>
typedef struct RemoteSection {
uintptr_t StartAddress;
uintptr_t Size;
uintptr_t EndAddress;
} RemoteSection;
typedef struct PipeMemoryReader {
int to_child[2];
int from_child[2];
} PipeMemoryReader;
typedef struct RemoteReflectionInfo {
RemoteSection fieldmd;
RemoteSection assocty;
RemoteSection builtin;
RemoteSection capture;
RemoteSection typeref;
RemoteSection reflstr;
uintptr_t StartAddress;
size_t TotalSize;
} RemoteReflectionInfo;
static void errorAndExit(const char *message) {
fprintf(stderr, "%s\n", message);
abort();
@@ -61,77 +44,6 @@ static void errnoAndExit(const char *message) {
abort();
}
static swift_reflection_section_t
makeLocalSection(void *Buffer, RemoteSection Section,
RemoteReflectionInfo Info) {
if (Section.Size == 0) {
swift_reflection_section_t LS = {NULL, NULL};
return LS;
}
uintptr_t Base
= (uintptr_t)Buffer + Section.StartAddress - Info.StartAddress;
swift_reflection_section_t LS = {
(void *)Base,
(void *)(Base + Section.Size)
};
return LS;
}
static
uintptr_t getStartAddress(const RemoteSection Sections[], size_t Count) {
uintptr_t Start = 0;
for (size_t i = 0; i < Count; ++i) {
if (Sections[i].StartAddress != 0) {
if (Start != 0)
Start = MIN(Start, Sections[i].StartAddress);
else
Start = Sections[i].StartAddress;
}
}
return Start;
}
static
uintptr_t getEndAddress(const RemoteSection Sections[], size_t Count) {
uintptr_t End = 0;
for (size_t i = 0; i < Count; ++i) {
if (Sections[i].StartAddress != 0)
End = MAX(End, Sections[i].EndAddress);
}
return End;
}
static
RemoteReflectionInfo makeRemoteReflectionInfo(RemoteSection fieldmd,
RemoteSection assocty,
RemoteSection builtin,
RemoteSection capture,
RemoteSection typeref,
RemoteSection reflstr) {
RemoteReflectionInfo Info = {
fieldmd,
assocty,
builtin,
capture,
typeref,
reflstr,
0,
0
};
const RemoteSection Sections[6] = {
fieldmd, assocty, builtin, capture, typeref, reflstr
};
Info.StartAddress = getStartAddress(Sections, 6);
uintptr_t EndAddress = getEndAddress(Sections, 6);
Info.TotalSize = EndAddress - Info.StartAddress;
return Info;
}
static const size_t ReadEnd = 0;
static const size_t WriteEnd = 1;
@@ -247,18 +159,6 @@ PipeMemoryReader createPipeMemoryReader() {
return Reader;
}
static
RemoteSection makeRemoteSection(const PipeMemoryReader *Reader) {
uintptr_t Start;
size_t Size;
PipeMemoryReader_collectBytesFromPipe(Reader, &Start, sizeof(Start));
PipeMemoryReader_collectBytesFromPipe(Reader, &Size, sizeof(Size));
RemoteSection RS = {Start, Size, Start + Size};
return RS;
}
static void
PipeMemoryReader_receiveReflectionInfo(SwiftReflectionContextRef RC,
const PipeMemoryReader *Reader) {
@@ -270,50 +170,17 @@ PipeMemoryReader_receiveReflectionInfo(SwiftReflectionContextRef RC,
if (NumReflectionInfos == 0)
return;
RemoteReflectionInfo *RemoteInfos = calloc(NumReflectionInfos,
sizeof(RemoteReflectionInfo));
if (RemoteInfos == NULL)
errnoAndExit("malloc failed");
struct { uintptr_t Start, Size; } *Images;
Images = calloc(NumReflectionInfos, sizeof(*Images));
PipeMemoryReader_collectBytesFromPipe(Reader, Images,
NumReflectionInfos * sizeof(*Images));
for (size_t i = 0; i < NumReflectionInfos; ++i) {
RemoteInfos[i] = makeRemoteReflectionInfo(
makeRemoteSection(Reader),
makeRemoteSection(Reader),
makeRemoteSection(Reader),
makeRemoteSection(Reader),
makeRemoteSection(Reader),
makeRemoteSection(Reader));
swift_reflection_addImage(RC, Images[i].Start, Images[i].Size);
}
// Now pull in the remote sections into our address space.
for (size_t i = 0; i < NumReflectionInfos; ++i) {
RemoteReflectionInfo RemoteInfo = RemoteInfos[i];
void *Buffer = malloc(RemoteInfo.TotalSize);
int Success = PipeMemoryReader_readBytes((void *)Reader,
RemoteInfo.StartAddress,
Buffer,
RemoteInfo.TotalSize);
if (!Success)
errorAndExit("Couldn't read reflection information");
swift_reflection_info_t Info = {
{makeLocalSection(Buffer, RemoteInfo.fieldmd, RemoteInfo), 0},
{makeLocalSection(Buffer, RemoteInfo.assocty, RemoteInfo), 0},
{makeLocalSection(Buffer, RemoteInfo.builtin, RemoteInfo), 0},
{makeLocalSection(Buffer, RemoteInfo.capture, RemoteInfo), 0},
{makeLocalSection(Buffer, RemoteInfo.typeref, RemoteInfo), 0},
{makeLocalSection(Buffer, RemoteInfo.reflstr, RemoteInfo), 0},
/*LocalStartAddress*/ (uintptr_t) Buffer,
/*RemoteStartAddress*/ RemoteInfo.StartAddress,
};
swift_reflection_addReflectionInfo(RC, Info);
}
free(RemoteInfos);
free(Images);
}
uint64_t PipeMemoryReader_getStringLength(void *Context, swift_addr_t Address) {