preface

Now that we’ve explored alloc, let’s look at ISA analysis to metaclasses

oneisaGo bitmap and inheritance chain

onelldbdebugging

So let’s just run the demo

LGPerson *test = [LGPerson alloc]; The break point is NSLog at sign"% @",test);
Copy the code

1. Run the following command on the LLDB terminal to obtain the IP address of the instance

    po test
    <LGPerson: 0x10500de60> Get the memory address of the instance objectCopy the code

2. Print memory

x/4gx 0x10500de60
0x10500de60(memory address):0x011d800100008365(How to prove that this is ISA)0x0000000000000000
0x10500de70: 0x0000000000000000 0x0000000000000000
Copy the code

3. Get the address pointed to by class ISA

p/x 0x011d800100008365 & 0x00007ffffffffff8
(unsigned long long) $2 = 0x0000000100008360Get the memory address of the classCopy the code

4. Print the class name

 po 0x0000000100008360LGPerson (gets the class name)Copy the code

Here we can explore the isa-> (LGPerson: 0x0000000100008360) class of the instance object. We’ll keep you going

5. Print the memory of the class

x/4gx 0x0000000100008360
0x100008360: 0x0000000100008338(isa) 0x00007fff88bdfcc8
0x100008370: 0x0000000100641640 0x0002802c00000003
Copy the code

6. Get the address pointed to by class ISA

p/x 0x0000000100008338 & 0x00007ffffffffff8
$8 = 0x0000000100008338Get the memory address of the classCopy the code

7. Print the class name

 po 0x0000000100008338LGPerson (gets the class name)Copy the code

Here we can explore (LGPerson: 0x0000000100008360) ISA -> (LGPerson: 0x0000000100008338)

8. Run another demo

    Class class1 = [LGPerson class];
    Class class2 = [LGPerson alloc].class;
    Class class3 = object_getClass([LGPerson alloc]);
    Class class4 = [LGPerson alloc].class;
    NSLog(@"\n%p-\n%p-\n%p-\n%p",class1,class2,class3,class4); Print result address:0x100008360-
                0x100008360-
                0x100008360-
                0x100008360And LGPerson:0x0000000100008360On the rightCopy the code

9. Look at the Mach-o file LGPerson: 0x0000000100008338, which should be metaclass

Where does isa point to (LGPerson: 0x0000000100008338)

10. Print the memory of the metaclass

x/4gx 0x0000000100008338
0x100008338: 0x00007fff88bdfca0(isa)0x00007fff88bdfca0
0x100008348: 0x00000001006419d0 0x0002e03500000003
Copy the code

11. Get the address that metaclass ISA points to

p/x 0x00007fff88bdfca0 & 0x00007ffffffffff8ULL
(unsigned long long) $10 = 0x00007fff88bdfca0Get the memory address of the classCopy the code

12. Print the class name

po 0x00007fff88bdfca0
NSObject
Copy the code

Here we can explore (LGPerson: 0x0000000100008338) isa points to the root metaclass (NSObject)

Print the memory of the root metaclass

x/4gx 0x00007fff88bdfca0
0x7fff88bdfca0: 0x00007fff88bdfca0 0x00007fff88bdfcc8
0x7fff88bdfcb0: 0x0000000100641b10 0x0003e03100000007
Copy the code

14. Get the address pointed to by the root metaclass isa

 p/x 0x00007fff88bdfca0 & 0x00007ffffffffff8
(unsigned long long) $12 = 0x00007fff88bdfca0Get the memory address of the classCopy the code

15. Print the class name

po 0x00007fff88bdfca0
NSObject
Copy the code

At this point we can explore that the ROOT metaclass (NSObject) isa points to itself

Summary: Object ISA -> class (LGPerson: 0x0000000100008360) ISA -> metaclass (LGPerson: 0x0000000100008338) ISA -> Root metaclass (NSObject) ISA -> Root metaclass

16. We print nsobject.class directly

p/x NSObject.class
(Class) $14 = 0x00007fff88bdfcc8NSObject prints the memory of the class x/4gx0x00007fff88bdfcc8
0x7fff88bdfcc8: 0x00007fff88bdfca0 0x0000000000000000
0x7fff88bdfcd8: 0x0000000105007bd0 0x0002801000000003Prints the address p/x of the class0x00007fff88bdfca0 & 0x00007ffffffffff8
(long) $15 = 0x00007fff88bdfca0Print the name Po of the class0x00007fff88bdfca0
NSObject
Copy the code

Summary: root class ISA -> root metaclass ISA -> root metaclass

Two. Code debuggingisatowards

1. NSObject instance object demo

We create LGPerson instance object to demonstrate:

3. Because LGTeacher inherits from LGPerson, LGTeacher instance object demonstrates:

Let’s explore how inherited ISA points to direct up code

Three. Code debuggingisaInheritance to

A. Class inheritanceisaPoint to the

1. Let’s first look at the ISA pointing to nsobject. class

Let’s take a look at the ISA pointing to lgperson. class

3. Let’s seeLGTeacher.classtheisaPoint to the

4. Let’s seeLGXiaowen.classtheisaPoint to the

Two. Metaclass inheritanceisaPoint to the

1. Let’s first look at the ISA pointing to the nsobject. class metaclass

2. Let’s seeLGPerson.classmetaclassisaPoint to the

3. Let’s seeLGTeacher.classmetaclassisaPoint to the

4. Let’s seeLGXiaowen.classmetaclassisaPoint to the

In combination with the above analysis, the following conclusions are drawn as follows

Source code analysis class structure

Pointer and memory translation

  // Array pointer
        int c[4] = {1.2.3.4};
        int *d   = c;
        NSLog(@"%p - %p - %p",&c,&c[0],&c[1]);
        NSLog(@"%p - %p - %p",d,d+1,d+2);

        for (int i = 0; i<4; i++) {
            int value =  *(d+i);
            NSLog(@"%d",value); } print out:002- Memory offset [38980:1658739] 0x7ffeefbff3c0 - 0x7ffeefbff3c0 - 0x7ffeefbff3c4

2021-06-20 13:41:36.896925+0800 002- Memory offset [38980:1658739] 0x7ffeefbff3c0 - 0x7ffeefbff3c4 - 0x7ffeefbff3c8

2021-06-20 13:41:37.939247+0800 002- Memory offset [38980:1658739] 1
2021-06-20 13:42:19.343718+0800 002- Memory offset [38980:1658739] 2
2021-06-20 13:42:19.343888+0800 002- Memory offset [38980:1658739] 3
2021-06-20 13:42:19.343959+0800 002- Memory offset [38980:1658739] 4

Copy the code

Get the value of the array based on the shift of the pointer memory so that we can get the value of the member variable in the class based on the first address of the class

Four. Class structure memory calculation

x/4gx LGPerson.class
0x100008380: 0x00000001000083a8 0x000000010036a140
0x100008390: 0x0000000101052a80 0x0002802800000003
0x00000001000083a8: corresponds to Class ISA0x000000010036a140: corresponds to Class superclass0x0000000101052a80: corresponds to cache_t cache0x0002802800000003: corresponds to cache_t cacheCopy the code

ISA(8 bytes)->superclass(8 bytes)->cache(how much)

cache = 8+8 = 16So it shifts tobitsNeed to move32

5. LLDB analysis class structure

1. Get the LGPerson properties

Look for the LGPerson member variable in class_rw_t

(lldb) x/4gx LGPerson.class
0x100008380: 0x00000001000083a8 0x000000010036a140
0x100008390: 0x0000000100764050 0x0002802800000003
(lldb) p (class_data_bits_t *) 0x1000083a0  // Get class_data_bits_t +32
(class_data_bits_t *) $1 = 0x00000001000083a0
(lldb) p $1->data() / / get class_rw_t
(class_rw_t *) $2 = 0x0000000100764010
(lldb) p * $2   / / check class_rw_t
(class_rw_t) $3 = {
  flags = 2148007936
  witness = 1
  ro_or_rw_ext = {
    std::__1::atomic<unsigned long> = {
      Value = 4295000344
    }
  }
  firstSubclass = nil
  nextSiblingClass = NSUUID
  
}

// Get the attribute
(lldb) p $2.properties() / / check class_rw_t. The properties ()
(const property_array_t) $4 = {
  list_array_tt<property_t, property_list_t, RawPtr> = {
     = {
     `list` = {
        ptr = 0x0000000100008260
      }
      arrayAndFlag = 4295000672
    }
  }
}
  Fix-it applied, fixed expression was: 
    $2->properties()
(lldb) p $4.list // Return from above
(const RawPtr<property_list_t>) $5 = {
  `ptr` = 0x0000000100008260
}
(lldb) p $5.ptr
(property_list_t *const) $6 = 0x0000000100008260
(lldb) p *$6
(property_list_t) $7 = {
  `entsize_list_tt`<property_t, property_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 16, count = 4)
}
(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,V_hobby")
(lldb) p $7.get(2)
(property_t) $10 = (name = "desc", attributes = "T@\"NSString\",V_desc")
(lldb) p $7.get(3)
(property_t) $11 = (name = "idcard", attributes = "T@\"NSString\",N,V_idcard")
Copy the code

2. Methods for obtaining object instances

(lldb) p/x LGPerson.class
(Class) $0 = 0x0000000100008920 LGPerson
(lldb) p (class_data_bits_t *) 0x0000000100008940 / / get class_data_bits_t
(class_data_bits_t *) $1 = 0x0000000100008940
(lldb) p $1->data()
(class_rw_t *) $2 = 0x0000000100724a80 / / get class_rw_t
(lldb) p $2.methods()
(const method_array_t) $3 = {
  list_array_tt<method_t, method_list_t, method_list_t_authed_ptr> = {
     = {
      list = {
        ptr = 0x00000001000081f8
      }
      arrayAndFlag = 4295000568
    }
  }
}
  Fix-it applied, fixed expression was: 
    $2->methods()
(lldb) p $3.list.ptr
(method_list_t *const) $4 = 0x00000001000081f8
(lldb) p * $4
(method_list_t) $5 = {
  entsize_list_tt<method_t, method_list_t, 4294901763.method_t::pointer_modifier> = (entsizeAndFlags = 27, count = 10)
}
(lldb) p $5.get(0).big()
(method_t::big) $6 = {
  name = "hobby"
  types = 0x0000000100003e78 "@ @ 0:8 16"
  imp = 0x0000000100003aa0 (KCObjcBuild`-[LGPerson hobby]) } (lldb) p $5.get(1).big() (method_t::big) $7 = { name = "sayNB" types = 0x0000000100003e80 "v16@0:8" imp = 0x0000000100003a30 (KCObjcBuild`-[LGPerson sayNB])
}
(lldb)  p $5.get(2).big()
(method_t::big) $8 = {
  name = "setHobby:"
  types = 0x0000000100003ec4 "v24@0:8@16"
  imp = 0x0000000100003ad0 (KCObjcBuild`-[LGPerson setHobby:]) } (lldb) p $5.get(3).big() (method_t::big) $9 = { name = "idcard" types = 0x0000000100003e78 "@16@0:8" imp = 0x0000000100003b40 (KCObjcBuild`-[LGPerson idcard])
}
(lldb)  p $5.get(4).big()
(method_t::big) $10 = {
  name = "setIdcard:"
  types = 0x0000000100003ec4 "v24@0:8@16"
  imp = 0x0000000100003b60 (KCObjcBuild`-[LGPerson setIdcard:]) } (lldb) p $5.get(5).big() (method_t::big) $11 = { name = "init" types = 0x0000000100003e78 "@16@0:8" imp = 0x00000001000039d0 (KCObjcBuild`-[LGPerson init])
}
(lldb)  p $5.get(6).big()
(method_t::big) $12 = {
  name = "name"
  types = 0x0000000100003e78 "@ @ 0:8 16"
  imp = 0x0000000100003a40 (KCObjcBuild`-[LGPerson name]) } (lldb) p $5.get(7).big() (method_t::big) $13 = { name = "setName:" types = 0x0000000100003ec4 "v24@0:8@16" imp = 0x0000000100003a70 (KCObjcBuild`-[LGPerson setName:])
}
(lldb)  p $5.get(8).big()
(method_t::big) $14 = {
  name = "desc"
  types = 0x0000000100003e78 "@ @ 0:8 16"
  imp = 0x0000000100003b00 (KCObjcBuild`-[LGPerson desc]) } (lldb) p $5.get(9).big() (method_t::big) $15 = { name = "setDesc:" types = 0x0000000100003ec4 "v24@0:8@16" imp = 0x0000000100003b20 (KCObjcBuild`-[LGPerson setDesc:])
}
Copy the code

3. Obtain the protocol method

(lldb) p/x LGPerson.class
(Class) $0 = 0x00000001000089d8 LGPerson
(lldb) p (class_data_bits_t *)0x00000001000089f8
(class_data_bits_t *) $1 = 0x00000001000089f8
(lldb) p $1->data()
(class_rw_t *) $2 = 0x000000010064eb80
(lldb) p $2.protocols()
(const protocol_array_t) $3 = {
  list_array_tt<unsigned long, protocol_list_t, RawPtr> = {
     = {
      list = {
        ptr = 0x00000001000082f0
      }
      arrayAndFlag = 4295000816
    }
  }
}
  Fix-it applied, fixed expression was: 
    $2->protocols()
(lldb) p $3.list.ptr
(protocol_list_t *const) $4 = 0x00000001000082f0
(lldb) p $4.list[0]
(protocol_ref_t) $5 = 4295002672
  Fix-it applied, fixed expression was: 
    $4->list[0]
(lldb) p (protocol_t *)$5
(protocol_t *) $6 = 0x0000000100008a30
(lldb) p * $6 
(protocol_t) $7 = {
  objc_object = {
    isa = {
      bits = 4298547400
      cls = Protocol
       = {
        nonpointer = 0
        has_assoc = 0
        has_cxx_dtor = 0
        shiftcls = 537318425
        magic = 0
        weakly_referenced = 0
        unused = 0
        has_sidetable_rc = 0
        extra_rc = 0
      }
    }
  }
  mangledName = 0x0000000100003c0a "proDelegate"
  protocols = 0x0000000100008488
  instanceMethods = 0x00000001000084a0
  classMethods = 0x0000000100008520
  optionalInstanceMethods = nil
  optionalClassMethods = nil
  instanceProperties = 0x0000000100008540
  size = 96
  flags = 0
  _extendedMethodTypes = 0x0000000100008568
  _demangledName = 0x0000000000000000
  _classProperties = nil
}
(lldb) p $7.instanceMethods // Instance method
(method_list_t *) $8 = 0x00000001000084a0
(lldb) p $8.get(0).big()
(method_t::big) $9 = {
  name = "aaaTest:"
  types = 0x0000000100003edb "v24@0:8@16"
  imp = 0x0000000000000000
}
  Fix-it applied, fixed expression was: 
    $8->get(0).big()
(lldb) p $8.get(1).big()
(method_t::big) $10 = {
  name = "name"
  types = 0x0000000100003e6a "@ @ 0:8 16"
  imp = 0x0000000000000000
}
  Fix-it applied, fixed expression was: 
    $8->get(1).big()
(lldb) p $8.get(2).big()
(method_t::big) $11 = {
  name = "setName:"
  types = 0x0000000100003edb "v24@0:8@16"
  imp = 0x0000000000000000
}
  Fix-it applied, fixed expression was: 
    $8->get(2).big()
(lldb) p $8.get(3).big()
(method_t::big) $12 = {
  name = "age"
  types = 0x0000000100003ec8 "i16@0:8"
  imp = 0x0000000000000000
}
  Fix-it applied, fixed expression was: 
    $8->get(3).big()
(lldb) p $8.get(4).big()
(method_t::big) $13 = {
  name = "setAge:"
  types = 0x0000000100003ed0 "v20@0:8i16"
  imp = 0x0000000000000000
}
  Fix-it applied, fixed expression was: 
    $8->get(4).big()
    
(lldb) p $7.classMethods / / class methods
(method_list_t *) $14 = 0x0000000100008520
(lldb) p $14.get(0).big()
(method_t::big) $15 = {
  name = "aaaTest:"
  types = 0x0000000100003edb "v24@0:8@16"
  imp = 0x0000000000000000
}
  Fix-it applied, fixed expression was: 
    $14->get(0).big()
    
(lldb) p $7.instanceProperties / / property
(property_list_t *) $16 = 0x0000000100008540
(lldb) p * $16
(property_list_t) $17 = {
  entsize_list_tt<property_t, property_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 16, count = 2)
}
(lldb) p $17.get(0)
(property_t) $18 = (name = "name", attributes = "T@\"NSString\",&,N")
(lldb) p $17.get(1)
(property_t) $19 = (name = "age", attributes = "Ti,N")
(lldb) p $17.get(2)
Copy the code