我们上篇讲到了还原 MacO 文件信息,那么我们这篇来看下如何参考 Swift 源码来还原 StructMetadata 信息,达到打印出属性名称、类型、值的作用
StructMetadata定义
TagerStructMetadata
我们通过Swift 源码及Swift类和结构体(二) 的了解,来还原 StructMetadata 信息。
-
- 在源码中直接搜
StructMetadata可以发现是TargetStructMetadata别名。
- 在源码中直接搜
- 2. 在
TargetStructMetadata中看到是 继承自TargetValueMetadata, 并有一个Description属性。
-
- 在
TargetValueMetadata中看到是 继承自TargetMetadata, 并有一个Kind属性
- 在
通过Kind属性的查看,得知其是一个 UInt64(64位机器,32位机器则为UInt32) 指针.
固初步能得到 TagerStructMetadata的结构为
struct TagerStructMetadata {
var kind:UnsafePointer<UInt64>
var typeDescription: UnsafeMutablePointer
}
TargetValueTypeDescriptor
-
- 我们在
TagerStructMetadata中看到Description属性是通过getDescription来获取的,并其 泛型类型是TargetStructDescriptor通过对类TargetStructDescriptor解读,发现两个属性,并其继承自TargetValueTypeDescriptor
- 我们在
uint32_t NumFields;
uint32_t FieldOffsetVectorOffset;
-
- 在 类
TargetValueTypeDescriptor中又发现 三个属性
- 在 类
TargetRelativeDirectPointer<Runtime, const char, /*nullable*/ false> Name;
TargetRelativeDirectPointer<Runtime, MetadataResponse(...), /*Nullable*/ true> AccessFunctionPtr;
TargetRelativeDirectPointer<Runtime, const reflection::FieldDescriptor, /*nullable*/ true> Fields;
-
- 而类
TargetValueTypeDescriptor又继承自TargetContextDescriptor,在TargetContextDescriptor中 也有两个属性
- 而类
ContextDescriptorFlags Flags;
TargetRelativeContextPointer<Runtime> Parent;
固整体 我们得知
struct TargetValueTypeDescriptor {
var flags: UInt32
var parent: UInt32
var name: TargetRelativeDirectPointer<CChar>
var accessFunctionPtr: TargetRelativeDirectPointer<UnsafeRawPointer>
var fieldDescriptor: TargetRelativeDirectPointer<FieldDescriptor>
var numFields: UInt32
var fieldOffsetVectorOffset: Int32
}
FieldDescriptor
在这个结构体里 FieldDescriptor 通过以上的方法步骤可以得到
struct FieldDescriptor {
var mangledTypeName: TargetRelativeDirectPointer<CChar>
var superclass: TargetRelativeDirectPointer<CChar>
var kind: UInt16
var fieldRecordSize: UInt16
var numFields: UInt32
var fields: FiledRecordBuffer<FieldRecord>
}
FieldRecord
在这个结构体里 FieldDescriptor 里 用到了 FieldRecord,同样可以得到
struct FieldRecord {
var flags: UInt32
var mangledTypeName: TargetRelativeDirectPointer<CChar>
var fieldName: TargetRelativeDirectPointer<CChar>
}
StructMetadata完整实现
综合整理后得到如下代码
protocol BrigeProtocol {}
extension BrigeProtocol {
static func get(from pointer: UnsafeRawPointer) -> Any {
pointer.assumingMemoryBound(to: Self.self).pointee
}
}
//协议的Metadata:
//协议见证表
struct BrigeProtocolMetadata {
let type: Any.Type
let witness: Int
}
func customCast(type: Any.Type) -> BrigeProtocol.Type {
let container = BrigeProtocolMetadata(type: type, witness: 0)
let protocolType = BrigeProtocol.Type.self
let cast = unsafeBitCast(container, to: protocolType)
return cast
}
struct TagerStructMetadata {
var kind:UnsafePointer<UInt64>
var typeDescription: UnsafeMutablePointer<TargetValueTypeDescriptor>
}
struct TargetValueTypeDescriptor {
var flags: UInt32
var parent: UInt32
var name: TargetRelativeDirectPointer<CChar>
var accessFunctionPtr: TargetRelativeDirectPointer<UnsafeRawPointer>
var fieldDescriptor: TargetRelativeDirectPointer<FieldDescriptor>
var numFields: UInt32
var fieldOffsetVectorOffset: Int32
func getFieldOffsets(_ metadata: UnsafeRawPointer) -> UnsafePointer<Int32>{
print("self.fieldOffsetVectorOffset \(self.fieldOffsetVectorOffset)" )
return metadata.assumingMemoryBound(to: Int32.self).advanced(by: numericCast(self.fieldOffsetVectorOffset)*2)
}
var genericArgumentOffset: Int {
return 2
}
}
struct TargetRelativeDirectPointer<Pointee>{
var offset: Int32
mutating func getmeasureRelativeOffset() -> UnsafeMutablePointer<Pointee>{
let offset = self.offset
return withUnsafePointer(to: &self) { p in
return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: Pointee.self))
}
}
}
struct FieldDescriptor {
var mangledTypeName: TargetRelativeDirectPointer<CChar>
var superclass: TargetRelativeDirectPointer<CChar>
var kind: UInt16
var fieldRecordSize: UInt16
var numFields: UInt32
var fields: FiledRecordBuffer<FieldRecord>
}
struct FieldRecord {
var flags: UInt32
var mangledTypeName: TargetRelativeDirectPointer<CChar>
var fieldName: TargetRelativeDirectPointer<CChar>
}
struct FiledRecordBuffer<Element>{
var element: Element
mutating func buffer(n: Int) -> UnsafeBufferPointer<Element> {
return withUnsafePointer(to: &self) {
let ptr = $0.withMemoryRebound(to: Element.self, capacity: 1) { start in
return start
}
return UnsafeBufferPointer(start: ptr, count: n)
}
}
mutating func index(of i: Int) -> UnsafeMutablePointer<Element> {
return withUnsafePointer(to: &self) {
return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: Element.self).advanced(by: i))
}
}
}
struct Teacher {
let age: Int = 18
let name: String = "32"
let name2: String = "33"
let sex: Bool = true
}
var t = Teacher()
//结构体放入 TagerStructMetadata 这个自定义的metadata
let ptr = unsafeBitCast(Teacher.self as Any.Type, to: UnsafeMutablePointer<TagerStructMetadata>.self)
//结构体名称
let namePtr = ptr.pointee.typeDescription.pointee.name.getmeasureRelativeOffset()
print("当前结构体名称: \(String(cString: namePtr))")
//结构体的属性数量
let numFileds = ptr.pointee.typeDescription.pointee.numFields
print("当前结构体属性的个数: \(numFileds)")
//属性值的偏移量metadata.
let offsets = ptr.pointee.typeDescription.pointee.getFieldOffsets(UnsafeRawPointer(ptr))//不用多次绑定 .assumingMemoryBound(to: UInt32.self)
//桥接 系统中 C++ 的方法,得到真实的Type类型
@_silgen_name("swift_getTypeByMangledNameInContext")
func swift_LI_getTypeByMangledNameInContext(typeName: UnsafeRawPointer, len: Int, context: UnsafeRawPointer, generic: UnsafeRawPointer) -> UnsafeRawPointer
print("======= start fetch filed ======")
for i in 0..<numFileds{
let fieldDespritor = ptr.pointee.typeDescription.pointee.fieldDescriptor.getmeasureRelativeOffset().pointee.fields.index(of: Int(i)).pointee.fieldName.getmeasureRelativeOffset()
print("--- filed: \(String(cString: fieldDespritor)) info begin ----")
let fieldOffset = offsets[Int(i)]
print("属性偏移地址: \(fieldOffset)")
//Int ,String
let typeMangleName = ptr.pointee.typeDescription.pointee.fieldDescriptor.getmeasureRelativeOffset().pointee.fields.index(of: Int(i)).pointee.mangledTypeName.getmeasureRelativeOffset()
print("混编的类型名称:\(String(cString: typeMangleName))")
let genericVector = UnsafeRawPointer(ptr).advanced(by: ptr.pointee.typeDescription.pointee.genericArgumentOffset * MemoryLayout<UnsafeRawPointer>.size).assumingMemoryBound(to: Any.Type.self)
//HandJSON
let fieldType = swift_LI_getTypeByMangledNameInContext(
typeName: typeMangleName,
len: 256,
context: UnsafeRawPointer(ptr.pointee.typeDescription),
generic: UnsafeRawPointer(genericVector)!.assumingMemoryBound(to: Optional<UnsafeRawPointer>.self))
//比较难理解,参考 HandJSON
let type = unsafeBitCast(fieldType, to: Any.Type.self)
let value = customCast(type: type)
let instanceAddress = withUnsafePointer(to: &t) {
return UnsafeRawPointer($0).assumingMemoryBound(to: Int8.self)
}
print("fieldType:\(type) \nfieldValue: \(value.get(from: UnsafeRawPointer(UnsafeRawPointer(instanceAddress).advanced(by: numericCast(fieldOffset))))) ")
print("--- filed: \(String(cString: fieldDespritor)) info end ---- \n")
}
在这代码中 genericArgumentOffset 函数返回了2 , 这个我们通过源码可以找到这个描述, 在64位机器下经过测量
let uLong = MemoryLayout<TargetStructMetadata>.size
let uInt = MemoryLayout<UInt64>.size
print("long \(uLong) uInt \(uInt)")
打印结果
long 16 uInt 8
Program ended with exit code: 0
至于 getFieldOffsets 函数 中 fieldOffsetVectorOffset 函数为啥要 *2 ,我们在 HandJSON 中 找到答案,也是因为64位机器还是32位机器的原因
StructMetadata实现结果
运行上面的完整实例后,得到如下信息
至此我们已经完成了对Swift源码的
StructMetadata 的还原及验证