Directory:
- 1: Superclass pointing analysis of ISA pointing and metaclasses
- 1.1 Isa Mask (ISA_MASK
- 1.2 ISA points to analysis
- 1.3 Meta-class superclass pointing analysis
- 2: Class structure analysis
- 2.1 ObjC 1.0 objC_class (deprecated)
- 2.2 ObjC 2.0 objC_class (based on objC4-818.2)
- 2.2.1 ObjC-runtime-old. h ObjC_class definition in objc-runtime-old.h
- 2.2.2 ObjC-Runtime-new. h Objc_class definition in objc-Runtime-new. h
- 2.3 Analysis of objC_class member variable Bits
- 2.3.1 Memory Translation
- 2.3.2 Class structure memory calculation
- 2.3.3 Obtaining class attributes
- 2.3.4 Obtaining instance methods of a class
- 2.3.5 Obtaining Member Variables of a Class (IVars)
- 2.3.6 Obtaining the class method of a class
- 2.3.7 Obtaining the protocol of the class
1:isa
Superclass pointing analysis of pointing and metaclasses
The book follows the nature of the object of the initial exploration of the underlying principle of OC (iii) Alloc exploration to continue to explore the principle of class.
1.1 isa
Mask (ISA_MASK
)
Alloc exploration has already introduced ISA_MASK and its use method. Next, we need to use ISA_MASK. The current source version is divided into three architectures:
x86_64: define ISA_MASK 0x00007ffffffffff8ULL // ULL: unsigned long long Unsigned long integer
arm64: define ISA_MASK 0x0000000ffffffff8ULL
arm64(simulators): define ISA_MASK 0x007ffffffffffff8ULL
Copy the code
1.2 isa
To analyze
Code examples:
#import <Foundation/Foundation.h>
#import "XJPerson.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
XJPerson *p = [XJPerson alloc];
NSLog(@ "% @",p);
}
return 0; } * * * * * * * * * * * * * * * * * * * * * * LLDB debugging result * * * * * * * * * * * * * * * * * * * * * * (LLDB)/x4gx p // Format the memory information of object P in hexadecimal format
0x10044f160: 0x001d800100008365 0x0000000000000000 // get the isa of object p
0x10044f170: 0x0000000000000000 0x0000000000000000
(lldb) p/x 0x001d800100008365 & 0x00007ffffffffff8 // use isa & ISA_MASK as above
(long) $1 = 0x0000000100008360 // Get the address of the class
(lldb) po 0x0000000100008360 / / the Po output
XJPerson / / get XJPerson
// Continue exploring
(lldb) x/4gx 0x0000000100008360 // Output the memory information of the XJPerson class in hexadecimal format
0x100008360: 0x0000000100008338 0x00007fff932d8118 // Get the XJPerson class ISA
0x100008370: 0x00007fff6bbb6140 0x0000802c00000000
(lldb) p/x 0x0000000100008338 & 0x00007ffffffffff8 // isa & ISA_MASK
(long) $3 = 0x0000000100008338 // Get a new address
(lldb) po 0x0000000100008338 / / the Po output
XJPerson // You can still get XJPerson
Copy the code
The XJPerson address is 0x0000000100008360 and 0x0000000100008338, respectively, and the XJPerson address is not the same. Let’s verify:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import "XJPerson.h"
//MARK: - Analyze the memory number of class objects
void xjTestClassNum(void){
Class class1 = [XJPerson class];
Class class2 = [XJPerson alloc].class;
Class class3 = object_getClass([XJPerson alloc]);
Class class4 = [XJPerson alloc].class;
NSLog(@"\n%p-\n%p-\n%p-\n%p",class1,class2,class3,class4);
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
xjTestClassNum();
}
return 0; } * * * * * * * * * * * * * * * * * * * * * * printing result * * * * * * * * * * * * * * * * * * * * * *2021- 06- 19 15:39:55.257537+0800 002- the isa [5557:148166]
0x100008360-
0x100008360-
0x100008360-
0x100008360
Program ended with exit code: 0
Copy the code
As you can see from the above example, no matter how many objects are generated, there is only one class. So why is the address Po output 0x0000000100008338 XJPerson? MachOView:
In addition to _OBJC_CLASS_$_XJPerson, a MachOView search class will also see _OBJC_METACLASS_$_XJPerson, which is the MetaClass. Our code does not actively generate metaclasses, indicating that the program actively generates them for us at runtime.
Now that you know the isa-> class object of an object and the ISA -> MetaClass of a class object, explore further:
// Omit some of the previous code and add the creation code for an instance object of the XJTeacher class, which inherits from XJPerson
// instantiate an object of class XJTeacher
XJTeacher *t = [XJTeacher alloc];
NSLog(@ "% @",t); * * * * * * * * * * * * * * * * * * * * * * LLDB debugging result * * * * * * * * * * * * * * * * * * * * * *// XJPerson LLDB debugging
// Omit some of the previous XJPerson class LLDB debugging
(lldb) po 0x0000000100008338 // The metaclass of the XJPerson class
XJPerson
(lldb) x/4gx 0x0000000100008338 // Format the memory information for the XJPerson metaclass in hexadecimal format
0x100008338: 0x00007fff932d80f0 0x00007fff932d80f0 // Get the ISA of the XJPerson metaclass
0x100008348: 0x0000000100406c50 0x0003e03500000007
(lldb) p/x 0x00007fff932d80f0 & 0x00007ffffffffff8 // isa & ISA_MASK
(long) $5 = 0x00007fff932d80f0 // Get the new address
(lldb) po 0x00007fff932d80f0 / / the Po output
NSObject // The output is NSObject, so is this a class or a metaclass
// XJTeacher LLDB debugging
(lldb) x/4gx t // Format the memory information of object T in hexadecimal format
0x100522330: 0x001d800100008315 0x0000000000000000 // Get the isa of object t
0x100522340: 0x0000000000000000 0x0000000000000000
(lldb) p/x 0x001d800100008315 & 0x00007ffffffffff8 // isa & ISA_MASK
(long) $1 = 0x0000000100008310 // Get the new address
(lldb) po 0x0000000100008310 / / the Po output
XJTeacher // The output is XJTeacher, i.e. class XJTeacher
(lldb) x/4gx 0x0000000100008310 // Format the memory information of the XJTeacher class in hexadecimal
0x100008310: 0x00000001000082e8 0x0000000100008360 // Get class XJTeacher ISA
0x100008320: 0x00007fff6bbb6140 0x0000802c00000000
(lldb) p/x 0x00000001000082e8 & 0x00007ffffffffff8 // isa & ISA_MASK
(long) $3 = 0x00000001000082e8 // Get the new address
(lldb) po 0x00000001000082e8 / / the Po output
XJTeacher // The output is XJTeacher, the metaclass XJTeacher
(lldb) x/4gx 0x00000001000082e8 // Format the memory information of the metaclass XJTeacher in hexadecimal
0x1000082e8: 0x00007fff932d80f0 0x0000000100008338 // get the metaclass XJTeacher isa
0x1000082f8: 0x00000001006433a0 0x0003e03500000007
(lldb) p/x 0x00007fff932d80f0 & 0x00007ffffffffff8 // isa & ISA_MASK
(long) $5 = 0x00007fff932d80f0
(lldb) po 0x00007fff932d80f0
NSObject // The output is NSObject, so is this a class or a metaclass
NSObject LLDB debugging
// Let's verify
(lldb) p/x [NSObject class] // Outputs the memory information of NSObject's class in hexadecimal
(Class) $7 = 0x00007fff932d8118 NSObject // Get the address of the root NSObject
(lldb) x/4gx 0x00007fff932d8118 // Format the memory information for the root NSObject class in hexadecimal
0x7fff932d8118: 0x00007fff932d80f0 0x0000000000000000 // Get the root class NSObject isa
0x7fff932d8128: 0x00000001004992d0 0x0001801000000003
(lldb) p/x 0x00007fff932d80f0 & 0x00007ffffffffff8 // isa & ISA_MASK
(long) $8 = 0x00007fff932d80f0 // Get the new address
(lldb) po 0x00007fff932d80f0 / / the Po output
NSObject // Output NSObject, the metaclass of the root class, RootMetaClass
// Continue validation
(lldb) x/4gx 0x00007fff932d80f0
0x7fff932d80f0: 0x00007fff932d80f0 0x00007fff932d8118
0x7fff932d8100: 0x0000000100643750 0x0005e03100000007
(lldb) p/x 0x00007fff932d80f0 & 0x00007ffffffffff8
(long) $18 = 0x00007fff932d80f0
(lldb) po 0x00007fff932d80f0
NSObject
Copy the code
Illustration:
Conclusion:
- The root class
NSObject
Classisa
Pointing to the class (Class
), the classisa
Pointing to metaclass (MetaClass
), metaclassisa
Point to the root metaclass (RootMetaClass
) instead of the parent metaclass. - The root class
NSObject
Classisa
Point to the root class (RootClass
) of the root classisa
Point to the root metaclass (RootMetaClass
). - A metaclass
isa
Again, it points to the root metaclass.
1.3 yuan classsuperclass
To analyze
Example code:
#pragmaMark - Superclass chain of metaclasses
void xjSuperclass(void) {
//NSObjcet instance object
NSObject *objectInstance = [NSObject alloc];
/ / NSObject class
Class object = object_getClass(objectInstance);
/ / NSobject metaclass
Class metaClass = object_getClass(object);
/ / NSObjct metaclass
Class rootMetaClass = object_getClass(metaClass);
NSLog(@"\n%p NSObject instance object \n%p NSObject class \n%p NSObject meta-class \n%p NSObject root metaclass \n",objectInstance,object,metaClass,rootMetaClass);
// The metaclass for XJPerson
Class personMetaClass = object_getClass(XJPerson.class);
NSLog(@"XJPerson metaclass: %@ - %p",personMetaClass, personMetaClass);
// The parent of the XJPerson metaclass
Class personSuperMetaclass = class_getSuperclass(personMetaClass);
NSLog(@"XJPerson metaclass parent: %@ - %p",personSuperMetaclass, personSuperMetaclass);
// XJTeacher's metaclass
Class teacherMetaClass = object_getClass(XJTeacher.class);
NSLog(@"XJTeacher metaclass: %@ - %p",teacherMetaClass,teacherMetaClass);
// the parent of the XJTeacher metaclass
Class childrenSuperMetaClass = class_getSuperclass(teacherMetaClass);
NSLog(@"XJTeacher metaclass parent: %@ - %p",childrenSuperMetaClass,childrenSuperMetaClass);
// The parent of the NSObject class
Class superObject = class_getSuperclass(NSObject.class);
NSLog(@"NSObject parent: %@ - %p",superObject,superObject);
//NSObject The parent of the root metaclass
Class rootSuperMetaObject = class_getSuperclass(rootMetaClass);
NSLog(@"NSObject Parent of root metaclass: %@ - %p",rootSuperMetaObject,rootSuperMetaObject); } * * * * * * * * * * * * * * * * * * * * * * printing result * * * * * * * * * * * * * * * * * * * * * *2021- 06- 19 23:10:35.443934+0800 002- the isa [12886:361372]
0x100644850 NSObjectInstance objects0x7fff932d8118 NSObjectclass0x7fff932d80f0 NSObjectThe metaclass0x7fff932d80f0 NSObjectA metaclass2021- 06- 19 23:10:35.444578+0800 002- the isa [12886:361372] XJPerson metaclass: XJPerson -0x100008338
2021- 06- 19 23:10:35.444650+0800 002- the isa [12886:361372Parent of the XJPerson metaclass:NSObject - 0x7fff932d80f0
2021- 06- 19 23:10:35.444800+0800 002- the isa [12886:361372] XJTeacher metaclass: XJTeacher -0x1000082e8
2021- 06- 19 23:10:35.444838+0800 002- the isa [12886:361372] XJTeacher metaclass parent: XJPerson -0x100008338
2021- 06- 19 23:10:35.444908+0800 002- the isa [12886:361372] NSObjectParent class: (null) -0x0
2021- 06- 19 23:10:35.444942+0800 002- the isa [12886:361372] NSObjectThe parent of the root metaclass:NSObject - 0x7fff932d8118
Copy the code
Conclusion:
- There are inheritance chains between metaclasses, just like classes.
- The parent of the root metaclass is the root class.
- The parent of the root class is nil.
Illustration:
2: Class structure analysis
Struct objc_class = objC4-818.2 struct objc_class = objC4-818.2
ObjC 1.0 2.1objc_class
(Deprecated)
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
#if! __OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE;
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
Copy the code
ObjC 2.0 2.2objc_class
(based onObjc4-818.2 -
)
2.2.1 objc runtime - old. H
In the fileobjc_class
The definition of
struct objc_class : objc_object {
Class superclass;
const char *name;
uint32_t version;
uint32_t info;
uint32_t instance_size;
struct old_ivar_list *ivars;
struct old_method_list **methodLists;
Cache cache;
struct old_protocol_list *protocols;
// CLS_EXT only
const uint8_t *ivar_layout;
struct old_class_ext *ext;
// For reasons of length, most code is omitted
}
Copy the code
2.2.2 objc runtime - new. H
In the fileobjc_class
The definition of
// This definition is used in the current version and our exploration is based on this definition
struct objc_class : objc_object {
objc_class(const objc_class&) = delete;
objc_class(objc_class&&) = delete;
void operator=(const objc_class&) = delete;
void operator=(objc_class&&) = delete;
// Class ISA; // 8 bytes, hidden variable isa, inherited from objc_object
Class superclass; / / 8 bytes
cache_t cache; // 16bytes, formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
// For reasons of length, most code is omitted
}
Copy the code
Illustration:
Objc-runtime-new. h contains four member variables: ISA (a hidden variable inherited from objc_Object), superclass, cache, and bits. (struct class_rw_t) (struct class_rw_t) (struct class_rw_t) (struct class_rw_t)
2.3 objc_class
Member variablesbits
The analysis of the
Case source:
@interface XJPerson : NSObject
{
NSString *_age;
CGFloat _height;
}
@property (nonatomic.copy) NSString *name;
@property (nonatomic.copy) NSString *hobby;
- (void)sayNB;
+ (void)say666;
+ (void)heiha;
@end
Copy the code
Given the name of the objc_class, to obtain the bits member variable of the objc_class, you need to use the memory translation method.
2.3.1 Memory Translation
Example:
Illustration:
Conclusion: After the first address of a data structure is known, the information of its elements can be obtained by means of memory translation.
2.3.2 Class structure memory calculation
You want to get the bits in the data from the first address translation to the corresponding position of bits, the isa is 8 bytes, known superclass is 8 bytes, now need to calculate the memory size of the cache, the cache data structures for cache_t structure, view its definition (methods exist area, Cache_t: cache_t: cache_t: cache_t: cache_t: cache_t: cache_t: cache_t: cache_t: cache_t: cache_t: cache_t
// Uintptr_t rename
typedef unsigned long uintptr_t; / / 8 bytes
// Mask_t rename, currently 64 bit environment, so 4 bytes
#if __LP64__
typedef uint32_t mask_t; // x86_64 & arm64 asm are less efficient with 16-bits
#else
typedef uint16_t mask_t;
#endif
struct cache_t { // The cache_t structure has been calculated to occupy 16 bytes of memory
private:
explicit_atomic<uintptr_t> _bucketsAndMaybeMask; / / 8 bytes
union { _originalPreoptCache and _originalPreoptCache are mutually exclusive; they are both 8 bytes
struct {
explicit_atomic<mask_t> _maybeMask; // uint32_t 4 bytes
#if __LP64__
uint16_t _flags; / / 2 bytes
#endif
uint16_t _occupied; / / 2 bytes
}; // Struct total 8 bytes
explicit_atomic<preopt_cache_t *> _originalPreoptCache; / / 8 bytes
};
// For reasons of length, most code is omitted
// The following are static variables and methods that do not take up space in the structure body
}
Copy the code
Illustration:
2.3.3 Obtaining class attributes
Property acquisition process: xjperson. class -> class_data_bits_t -> class_rw_T -> property_array_t -> property_list_t -> property_t.
LLDB debugging process:
(lldb) p/x XJPerson.class
// Get the address of the XJPerson object
(Class) $0 = 0x0000000100008380 XJPerson
(lldb) x/4gx 0x0000000100008380
// Get the first address of the XJPerson class object
0x100008380: 0x00000001000083a8 0x0000000100357140
0x100008390: 0x000000010104e040 0x0002802800000003
// Shift the first address by 32 bits
(lldb) p/x 0x100008380 + 0x20
// Get the class_datA_bits_t bits address
(long) $1 = 0x00000001000083a0
// Type change
(lldb) p (class_data_bits_t *)0x00000001000083a0
(class_data_bits_t *) $2 = 0x00000001000083a0
// Pointers access member variables, methods use '->', and structs use '. '.
// Use the data() function in the class_data_bits_t structure to retrieve class_rw_t *
(lldb) p $2->data()
(class_rw_t *) $3 = 0x000000010104e000
// Use the properties() function inside the class_rw_t structure to retrieve property_array_t
(lldb) p $3->properties()
(const property_array_t) $4 = {
list_array_tt<property_t, property_list_t, RawPtr> = {
= {
list = {
ptr = 0x0000000100008260
}
arrayAndFlag = 4295000672}}}/ / remove the list
(lldb) p $4.list
(const RawPtr<property_list_t>) $5 = {
ptr = 0x0000000100008260
}
// get property_list_t pointer
(lldb) p $5.ptr
(property_list_t *const) $6 = 0x0000000100008260
// The * is a value
(lldb) p *$6
// 得到property_list_t结构体实例,count为2
(property_list_t) $7 = {
entsize_list_tt<property_t, property_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 16, count = 2)}// Read the property value
(lldb) p $7.get(0)
(property_t) $8 = (name = "name", attributes = "T@\"NSString\",C,N,V_name")
(lldb) p $7.get(1)
(property_t) $9 = (name = "hobby", attributes = "T@\"NSString\",C,N,V_hobby")
(lldb)
Copy the code
Illustration:
2.3.4 Obtaining instance methods of a class
Instance methods, like properties, need to get class_rw_t, then call methods() to get the list of methods, and finally get method_t. But method_t has no member variables in the structure, so the direct output is empty. You need to get the big structure in method_t.
Instance method acquisition process: Xjperson. class -> class_data_bits_t -> class_rw_t -> method_array_t -> method_list_t -> method_t->big
Method_t
Objc4-818.2 -> objc-runtimenew.h ->726-861
struct method_t {
static const uint32_t smallMethodListFlag = 0x80000000;
method_t(const method_t &other) = delete;
// The representation of a "big" method. This is the traditional
// representation of three pointers storing the selector, types
// and implementation.
struct big {
SEL name;
const char *types;
MethodListIMP imp;
};
// For reasons of length, most code is omitted
}
Copy the code
LLDB debugging process:
(lldb) p/x XJPerson.class
// Get the address of the XJPerson object
(Class) $0 = 0x0000000100008380 XJPerson
(lldb) x/4gx 0x0000000100008380
// Get the first address of the XJPerson class object
0x100008380: 0x00000001000083a8 0x0000000100357140
0x100008390: 0x0000000100682630 0x0002802800000003
// Shift the first address by 32 bits
(lldb) p/x 0x100008380 + 0x20
// Get the class_datA_bits_t bits address
(long) $1 = 0x00000001000083a0
// Type change
(lldb) p/x (class_data_bits_t *)0x00000001000083a0
(class_data_bits_t *) $2 = 0x00000001000083a0
// Use the data() function in the class_data_bits_t structure to retrieve class_rw_t *
(lldb) p $2->data()
(class_rw_t *) $3 = 0x00000001006825f0
// Retrieve method_array_t using the methods() function in the class_rw_t structure
(lldb) p $3->methods()
(const method_array_t) $4 = {
list_array_tt<method_t, method_list_t, method_list_t_authed_ptr> = {
= {
list = {
ptr = 0x0000000100008160
}
arrayAndFlag = 4295000416}}}/ / remove the list
(lldb) p $4.list
(const method_list_t_authed_ptr<method_list_t>) $5 = {
ptr = 0x0000000100008160
}
// retrieve PTR, get method_list_t pointer
(lldb) p $5.ptr
(method_list_t *const) $6 = 0x0000000100008160
// The * is a value
(lldb) p *$6
// Get an instance of method_list_t with count 6
(method_list_t) $7 = {
entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (entsizeAndFlags = 27, count = 6)}// Get method_t with the get() function and read out the instance method information with the big() function
(lldb) p $7.get(0).big()
(method_t::big) $8 = {
name = "sayNB"
types = 0x0000000100003f7a "v16@0:8"
imp = 0x0000000100003d40 (KCObjcBuild`-[XJPerson sayNB])
}
(lldb) p $7.get(1).big()
(method_t::big) $9 = {
name = "hobby"
types = 0x0000000100003f72 "@ @ 0:8 16"
imp = 0x0000000100003db0 (KCObjcBuild`-[XJPerson hobby])
}
(lldb) p $7.get(2).big()
(method_t::big) $10 = {
name = "setHobby:"
types = 0x0000000100003f8e "v24@0:8@16"
imp = 0x0000000100003de0 (KCObjcBuild`-[XJPerson setHobby:])
}
(lldb) p $7.get(3).big()
(method_t::big) $11 = {
name = "init"
types = 0x0000000100003f72 "@ @ 0:8 16"
imp = 0x0000000100003ce0 (KCObjcBuild`-[XJPerson init])
}
(lldb) p $7.get(4).big()
(method_t::big) $12 = {
name = "name"
types = 0x0000000100003f72 "@ @ 0:8 16"
imp = 0x0000000100003d50 (KCObjcBuild`-[XJPerson name])
}
(lldb) p $7.get(5).big()
(method_t::big) $13 = {
name = "setName:"
types = 0x0000000100003f8e "v24@0:8@16"
imp = 0x0000000100003d80 (KCObjcBuild`-[XJPerson setName:])
}
(lldb)
Copy the code
Illustration:
2.3.5 Obtaining Member Variables of a Classivars
)
Member variables (IVars) : xjperson. class -> class_datA_bits_t -> class_rw_T -> class_ro_t -> ivar_list_t -> ivar_t.
Member variables (ivars), unlike attributes, reside in the class_ro_t structure.
Class_ro_t source code:
Objc4-818.2 -> objc-runtimenew.h ->1037-1171
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
#ifdef __LP64__
uint32_t reserved;
#endif
union {
const uint8_t * ivarLayout;
Class nonMetaclass;
};
explicit_atomic<const char *> name;
// With ptrauth, this is signed if it points to a small list, but
// may be unsigned if it points to a big list.
void *baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars; // Member variables
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
// For reasons of length, most code is omitted
}
Objc4-818.2 -> objC-runtimenew.h ->863-883
struct ivar_t {
#if __x86_64__
// *offset was originally 64-bit on some x86_64 platforms.
// We read and write only 32 bits of it.
// Some metadata provides all 64 bits. This is harmless for unsigned
// little-endian values.
// Some code uses all 64 bits. class_addIvar() over-allocates the
// offset for their benefit.
#endif
int32_t *offset;
const char *name;
const char *type;
// alignment is sometimes -1; use alignment() instead
uint32_t alignment_raw;
uint32_t size;
uint32_t alignment() const {
if (alignment_raw == ~(uint32_t)0) return 1U << WORD_SHIFT;
return 1<< alignment_raw; }};Copy the code
LLDB debugging process:
// Omit the process for getting class_rw_t
(class_rw_t *) $3 = 0x00000001007cfe30
// Call ro() of class_rw_t to get class_ro_t
(lldb) p $3->ro()
(const class_ro_t *) $4 = 0x0000000100008110
/ / value
(lldb) p *$4
// Get the class_ro_t structure
(const class_ro_t) $5 = {
flags = 0
instanceStart = 8
instanceSize = 40
reserved = 0
= {
ivarLayout = 0x0000000000000000
nonMetaclass = nil
}
name = {
std::__1::atomic<const char* > ="XJPerson" {
Value = 0x0000000100003e96 "XJPerson"
}
}
baseMethodList = 0x0000000100003de0
baseProtocols = nil
ivars = 0x0000000100008158 // Member variables
weakIvarLayout = 0x0000000000000000
baseProperties = 0x00000001000081e0
_swiftMetadataInitializer_NEVER_USE = {}
}
// the. Syntax retrieves the list of member variables
(lldb) p $5.ivars
// Get the ivar_list_t pointer
(const ivar_list_t *const) $6 = 0x0000000100008158
/ / value
(lldb) p *$6
// get ivar_list_t, count = 4
(const ivar_list_t) $7 = {
entsize_list_tt<ivar_t, ivar_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 32, count = 4)}// Get ivar_t via get()
(lldb) p $7.get(0)
(ivar_t) $8 = {
offset = 0x00000001000082bc
name = 0x0000000100003f10 "_age"
type = 0x0000000100003f55 "@\"NSString\""
alignment_raw = 3
size = 8
}
(lldb) p $7.get(1)
(ivar_t) $9 = {
offset = 0x00000001000082c0
name = 0x0000000100003f15 "_height"
type = 0x0000000100003f7c "d"
alignment_raw = 3
size = 8
}
(lldb) p $7.get(2)
(ivar_t) $10 = {
offset = 0x00000001000082c4
name = 0x0000000100003f1d "_name"
type = 0x0000000100003f55 "@\"NSString\""
alignment_raw = 3
size = 8
}
(lldb) p $7.get(3)
(ivar_t) $11 = {
offset = 0x00000001000082c8
name = 0x0000000100003f23 "_hobby"
type = 0x0000000100003f55 "@\"NSString\""
alignment_raw = 3
size = 8
}
Copy the code
Illustration:
2.3.6 Obtaining the class method of a class
Class methods exist in metaclass, so you need to get the metaclass first, and then get the list of metaclass methods, to get the class method.
Class method acquisition process: XJPerson.class -> Metaclass -> class_data_bits_t -> class_rw_t -> method_array_t -> method_list_t -> Method_t ->big
LLDB debugging process:
// M1 iMac debugging
(lldb) p/x XJPerson.class
(Class) $0 = 0x0000000100008328 XJPerson
(lldb) x/4gx 0x0000000100008328
0x100008328: 0x0000000100008350 0x0000000100379140
0x100008338: 0x000000010036d0f0 0x0000803000000000
(lldb) p/x 0x0000000100008350 & 0x0000000ffffffff8
(long) $1 = 0x0000000100008350
(lldb) x/4gx 0x0000000100008350
0x100008350: 0x00000001003790f0 0x00000001003790f0
0x100008360: 0x00010001009065f0 0x0002e03400000000
(lldb) p/x 0x100008350 + 0x20
(long) $2 = 0x0000000100008370
(lldb) p/x (class_data_bits_t *)0x0000000100008370
(class_data_bits_t *) $3 = 0x0000000100008370
(lldb) p $3->data()
(class_rw_t *) $4 = 0x0000000100a10e10
(lldb) p $4->methods()
(const method_array_t) $5 = {
list_array_tt<method_t, method_list_t, method_list_t_authed_ptr> = {
= {
list = {
ptr = 0x0000000100003db8
}
arrayAndFlag = 4294983096
}
}
}
(lldb) p $5.list
(const method_list_t_authed_ptr<method_list_t>) $6 = {
ptr = 0x0000000100003db8
}
(lldb) p $6.ptr
(method_list_t *const) $7 = 0x0000000100003db8
(lldb) p *$7
(method_list_t) $8 = {
entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (entsizeAndFlags = 2147483660, count = 2)
}
(lldb) p $8.get(0).small()
(method_t::small) $9 = {
name = (offset = 17608)
types = (offset = 419)
imp = (offset = - 272.)
}
(lldb) p $8.get(1).small()
(method_t::small) $10 = {
name = (offset = 17604)
types = (offset = 407)
imp = (offset = - 264.)
}
(lldb) p $8.get(0).getDescription()
(objc_method_description *) $9 = 0x0000000100717a80
(lldb) p *$9
(objc_method_description) $10 = (name = "say666", types = "v16@0:8")
(lldb) p *($8.get(1).getDescription())
(objc_method_description) $11 = (name = "heiha", types = "v16@0:8")
Copy the code
Illustration:
Conclusion: A class is a unique object of a metaclass, and a class method is an instance method of a metaclass.
2.3.7 Obtaining the protocol of the class
To obtain the protocol of a class, you must first comply with the protocol.
Protocol obtaining process: XJPerson.class -> class_data_bits_t -> class_rw_t -> protocol_array_t -> protocol_list_t -> protocol_ref_t -> protocol_t -> list_t -> big
Protocol_list_t, PROTOCOL_ref_t, protocol_t
Sample code to test:
LLDB debugging process:
(lldb) p/x XJPerson.class
(Class) $0 = 0x0000000100008778 XJPerson
(lldb) p/x 0x0000000100008778 + 0x20
(long) $1 = 0x0000000100008798
(lldb) p (class_data_bits_t *)0x0000000100008798
(class_data_bits_t *) $2 = 0x0000000100008798
(lldb) p $2->data()
(class_rw_t *) $3 = 0x00000001009c5d90
(lldb) p $3->protocols()
(const protocol_array_t) $4 = {
list_array_tt<unsigned long, protocol_list_t, RawPtr> = {
= {
list = {
ptr = 0x0000000100008168
}
arrayAndFlag = 4295000424
}
}
}
(lldb) p $4.list
(const RawPtr<protocol_list_t>) $5 = {
ptr = 0x0000000100008168
}
(lldb) p $5.ptr
(protocol_list_t *const) $6 = 0x0000000100008168
(lldb) p *$6
(protocol_list_t) $7 = (count = 2, list = protocol_ref_t [] @ 0x00000001196abc58)
(lldb) p $7.list[0]
(protocol_ref_t) $8 = 4295002064
(lldb) p (protocol_t *)4295002064
(protocol_t *) $9 = 0x00000001000087d0
p $9[0]
(protocol_t) $10 = {
objc_object = {
isa = {
bits = 4298608840
cls = Protocol
= {
nonpointer = 0
has_assoc = 0
has_cxx_dtor = 0
shiftcls = 537326105
magic = 0
weakly_referenced = 0
unused = 0
has_sidetable_rc = 0
extra_rc = 0
}
}
}
mangledName = 0x0000000100003e52 "XJPersonDelegate"
protocols = 0x00000001000085b0
instanceMethods = 0x00000001000085c8
classMethods = nil
optionalInstanceMethods = nil
optionalClassMethods = nil
instanceProperties = nil
size = 96
flags = 0
_extendedMethodTypes = 0x0000000100008600
_demangledName = 0x0000000000000000
_classProperties = nil
}
(lldb) p $10.instanceMethods
(method_list_t *) $11 = 0x00000001000085c8
(lldb) p $11->get(0).big()
(method_t::big) $12 = {
name = "delegateMethod1"
types = 0x0000000100003e77 "v16@0:8"
imp = 0x0000000000000000
}
(lldb) p $11->get(1).big()
(method_t::big) $13 = {
name = "delegateMethod2:"
types = 0x0000000100003ea9 "@ 24 @ 0:8 @ 16"
imp = 0x0000000000000000
}
(lldb) p $9[1]
(protocol_t) $14 = {
objc_object = {
isa = {
bits = 4298608840
cls = Protocol
= {
nonpointer = 0
has_assoc = 0
has_cxx_dtor = 0
shiftcls = 537326105
magic = 0
weakly_referenced = 0
unused = 0
has_sidetable_rc = 0
extra_rc = 0
}
}
}
mangledName = 0x0000000100003e36 "XJPersonDataSource"
protocols = 0x0000000100008278
instanceMethods = 0x0000000100008290
classMethods = nil
optionalInstanceMethods = nil
optionalClassMethods = nil
instanceProperties = nil
size = 96
flags = 0
_extendedMethodTypes = 0x00000001000082c8
_demangledName = 0x0000000000000000
_classProperties = nil
}
(lldb) p $14.instanceMethods
(method_list_t *) $15 = 0x0000000100008290
(lldb) p $15->get(0).big()
(method_t::big) $16 = {
name = "dataSourceMethod1"
types = 0x0000000100003e77 "v16@0:8"
imp = 0x0000000000000000
}
(lldb) p $15->get(1).big()
(method_t::big) $17 = {
name = "dataSourceMethod2:"
types = 0x0000000100003ea9 "@ 24 @ 0:8 @ 16"
imp = 0x0000000000000000
}
Copy the code
Illustration: