@@ -15,6 +15,33 @@ import (
1515
1616var ErrObjcSectionNotFound = errors .New ("missing required ObjC section" )
1717var ErrObjcSectionNEmpty = errors .New ("required ObjC section is empty" )
18+ var ErrObjcFragileRuntimeUnsupported = errors .New ("objective-c fragile runtime metadata is unsupported" )
19+
20+ var legacyObjCSectionNames = map [string ]struct {}{
21+ "__image_info" : {},
22+ "__module_info" : {},
23+ "__class" : {},
24+ "__meta_class" : {},
25+ "__protocol" : {},
26+ "__protocol_ext" : {},
27+ "__category" : {},
28+ "__class_vars" : {},
29+ "__instance_vars" : {},
30+ "__cls_refs" : {},
31+ "__message_refs" : {},
32+ "__symbols" : {},
33+ "__sel_refs" : {},
34+ "__string_object" : {},
35+ "__class_names" : {},
36+ "__meth_var_names" : {},
37+ "__meth_var_types" : {},
38+ "__selector_strs" : {},
39+ }
40+
41+ func isLegacyObjCSectionName (name string ) bool {
42+ _ , ok := legacyObjCSectionNames [strings .ToLower (name )]
43+ return ok
44+ }
1845
1946// TODO refactor into a pkg
2047
@@ -58,21 +85,43 @@ func (f *File) getCStringWithFallback(addr uint64, label string, allowSwift bool
5885 return "" , err
5986}
6087
61- // HasObjC returns true if MachO contains a __objc_imageinfo section
62- func (f * File ) HasObjC () bool {
63- for _ , s := range f .Segments () {
64- if strings .HasPrefix (s .Name , "__DATA" ) {
65- if sec := f .Section (s .Name , "__objc_imageinfo" ); sec != nil {
66- return true
88+ func (f * File ) hasObjCNonFragileRuntime () bool {
89+ f .detectObjCRuntimeKinds ()
90+ return f .objcHasNonFragileRuntime
91+ }
92+
93+ func (f * File ) hasObjCFragileRuntime () bool {
94+ f .detectObjCRuntimeKinds ()
95+ return f .objcHasFragileRuntime
96+ }
97+
98+ func (f * File ) detectObjCRuntimeKinds () {
99+ f .objcRuntimeOnce .Do (func () {
100+ for _ , sec := range f .Sections {
101+ if strings .HasPrefix (sec .Seg , "__DATA" ) && strings .HasPrefix (sec .Name , "__objc_" ) {
102+ f .objcHasNonFragileRuntime = true
103+ }
104+ if strings .EqualFold (sec .Seg , "__OBJC" ) && isLegacyObjCSectionName (sec .Name ) {
105+ f .objcHasFragileRuntime = true
106+ }
107+ if f .objcHasNonFragileRuntime && f .objcHasFragileRuntime {
108+ return
67109 }
68110 }
111+ })
112+ }
113+
114+ func (f * File ) ensureObjCNonFragileRuntime (api string ) error {
115+ f .detectObjCRuntimeKinds ()
116+ if f .objcHasFragileRuntime && ! f .objcHasNonFragileRuntime {
117+ return fmt .Errorf ("%s requires the Objective-C non-fragile runtime: %w" , api , ErrObjcFragileRuntimeUnsupported )
69118 }
70- if f . CPU == types . CPUI386 {
71- if sec := f . Section ( "__OBJC" , "__image_info" ); sec != nil {
72- return true
73- }
74- }
75- return false
119+ return nil
120+ }
121+
122+ // HasObjC returns true if MachO contains Objective-C metadata.
123+ func ( f * File ) HasObjC () bool {
124+ return f . hasObjCNonFragileRuntime () || f . hasObjCFragileRuntime ()
76125}
77126
78127// HasPlusLoadMethod returns true if MachO contains a __objc_nlclslist or __objc_nlcatlist section
@@ -100,6 +149,9 @@ func (f *File) HasObjCMessageReferences() bool {
100149 }
101150 }
102151 }
152+ if sec := f .Section ("__OBJC" , "__message_refs" ); sec != nil {
153+ return true
154+ }
103155 return false
104156}
105157
@@ -126,7 +178,7 @@ func (f *File) GetObjCToc() objc.Toc {
126178 case "__objc_selrefs" :
127179 oInfo .SelRefs = sec .Size / f .pointerSize ()
128180 }
129- } else if ( f . CPU == types . CPUI386 ) && strings .EqualFold (sec .Name , "__OBJC" ) {
181+ } else if strings .EqualFold (sec .Seg , "__OBJC" ) {
130182 if strings .EqualFold (sec .Name , "__message_refs" ) {
131183 oInfo .SelRefs += sec .SectionHeader .Size / 4
132184 } else if strings .EqualFold (sec .Name , "__class" ) {
@@ -144,6 +196,10 @@ func (f *File) GetObjCToc() objc.Toc {
144196
145197// GetObjCImageInfo returns the parsed __objc_imageinfo data
146198func (f * File ) GetObjCImageInfo () (* objc.ImageInfo , error ) {
199+ if err := f .ensureObjCNonFragileRuntime ("GetObjCImageInfo" ); err != nil {
200+ return nil , err
201+ }
202+
147203 var imgInfo objc.ImageInfo
148204 for _ , s := range f .Segments () {
149205 if strings .HasPrefix (s .Name , "__DATA" ) {
@@ -196,6 +252,10 @@ func (f *File) GetObjCClassInfo(vmaddr uint64) (*objc.ClassRO64, error) {
196252
197253// GetObjCClassNames returns a map of section data virtual memory address to their class names
198254func (f * File ) GetObjCClassNames () (map [uint64 ]string , error ) {
255+ if err := f .ensureObjCNonFragileRuntime ("GetObjCClassNames" ); err != nil {
256+ return nil , err
257+ }
258+
199259 class2vmaddr := make (map [uint64 ]string )
200260
201261 if sec := f .Section ("__TEXT" , "__objc_classname" ); sec != nil { // Names for locally implemented classes
@@ -230,6 +290,10 @@ func (f *File) GetObjCClassNames() (map[uint64]string, error) {
230290
231291// GetObjCMethodNames returns a map of section data virtual memory addresses to their method names
232292func (f * File ) GetObjCMethodNames () (map [uint64 ]string , error ) {
293+ if err := f .ensureObjCNonFragileRuntime ("GetObjCMethodNames" ); err != nil {
294+ return nil , err
295+ }
296+
233297 meth2vmaddr := make (map [uint64 ]string )
234298
235299 if sec := f .Section ("__TEXT" , "__objc_methname" ); sec != nil { // Method names for locally implemented methods
@@ -264,6 +328,10 @@ func (f *File) GetObjCMethodNames() (map[uint64]string, error) {
264328
265329// GetObjCClasses returns an array of Objective-C classes
266330func (f * File ) GetObjCClasses () ([]objc.Class , error ) {
331+ if err := f .ensureObjCNonFragileRuntime ("GetObjCClasses" ); err != nil {
332+ return nil , err
333+ }
334+
267335 var classes []objc.Class
268336
269337 for _ , s := range f .Segments () {
@@ -313,6 +381,10 @@ func (f *File) GetObjCClasses() ([]objc.Class, error) {
313381
314382// GetObjCNonLazyClasses returns an array of Objective-C classes that implement +load
315383func (f * File ) GetObjCNonLazyClasses () ([]objc.Class , error ) {
384+ if err := f .ensureObjCNonFragileRuntime ("GetObjCNonLazyClasses" ); err != nil {
385+ return nil , err
386+ }
387+
316388 var classes []objc.Class
317389
318390 for _ , s := range f .Segments () {
@@ -381,6 +453,9 @@ func (f *File) disablePreattachedCategories(vmaddr uint64) (uint64, error) {
381453
382454// GetObjCClass parses an Objective-C class at a given virtual memory address
383455func (f * File ) GetObjCClass (vmaddr uint64 ) (* objc.Class , error ) {
456+ if err := f .ensureObjCNonFragileRuntime ("GetObjCClass" ); err != nil {
457+ return nil , err
458+ }
384459
385460 if c , ok := f .GetObjC (vmaddr ); ok {
386461 return c .(* objc.Class ), nil
@@ -572,6 +647,9 @@ func (f *File) GetObjCClass(vmaddr uint64) (*objc.Class, error) {
572647// TODO: get rid of old GetObjCClass
573648// GetObjCClass parses an Objective-C class at a given virtual memory address
574649func (f * File ) GetObjCClass2 (vmaddr uint64 ) (* objc.Class , error ) {
650+ if err := f .ensureObjCNonFragileRuntime ("GetObjCClass2" ); err != nil {
651+ return nil , err
652+ }
575653
576654 if c , ok := f .GetObjC (vmaddr ); ok {
577655 return c .(* objc.Class ), nil
@@ -763,6 +841,10 @@ func (f *File) GetObjCClass2(vmaddr uint64) (*objc.Class, error) {
763841
764842// GetObjCCategories returns an array of Objective-C categories by parsing the __objc_catlist data
765843func (f * File ) GetObjCCategories () ([]objc.Category , error ) {
844+ if err := f .ensureObjCNonFragileRuntime ("GetObjCCategories" ); err != nil {
845+ return nil , err
846+ }
847+
766848 var categoryPtr objc.CategoryT
767849 var categories []objc.Category
768850
@@ -880,6 +962,10 @@ func (f *File) GetObjCCategories() ([]objc.Category, error) {
880962
881963// GetObjCNonLazyCategories returns an array of Objective-C classes that implement +load
882964func (f * File ) GetObjCNonLazyCategories () ([]objc.Category , error ) {
965+ if err := f .ensureObjCNonFragileRuntime ("GetObjCNonLazyCategories" ); err != nil {
966+ return nil , err
967+ }
968+
883969 var cats []objc.Category
884970
885971 for _ , s := range f .Segments () {
@@ -1099,6 +1185,9 @@ func (f *File) getObjcProtocol(vmaddr uint64) (proto *objc.Protocol, err error)
10991185
11001186// GetObjCProtocols returns the Objective-C protocols
11011187func (f * File ) GetObjCProtocols () ([]objc.Protocol , error ) {
1188+ if err := f .ensureObjCNonFragileRuntime ("GetObjCProtocols" ); err != nil {
1189+ return nil , err
1190+ }
11021191
11031192 var protocols []objc.Protocol
11041193
@@ -1133,6 +1222,10 @@ func (f *File) GetObjCProtocols() ([]objc.Protocol, error) {
11331222}
11341223
11351224func (f * File ) GetObjCMethods (vmaddr uint64 ) ([]objc.Method , error ) {
1225+ if err := f .ensureObjCNonFragileRuntime ("GetObjCMethods" ); err != nil {
1226+ return nil , err
1227+ }
1228+
11361229 if c , ok := f .GetObjC (vmaddr ); ok {
11371230 return c .([]objc.Method ), nil
11381231 }
@@ -1152,6 +1245,10 @@ func (f *File) GetObjCMethods(vmaddr uint64) ([]objc.Method, error) {
11521245
11531246// GetObjCMethodLists parses the method lists in the __objc_methlist section
11541247func (f * File ) GetObjCMethodLists () ([]objc.Method , error ) {
1248+ if err := f .ensureObjCNonFragileRuntime ("GetObjCMethodLists" ); err != nil {
1249+ return nil , err
1250+ }
1251+
11551252 var methods []objc.Method
11561253 var methodList objc.MethodList
11571254 var nextMethodListOffset uint64
@@ -1310,6 +1407,10 @@ func (f *File) forEachObjCMethod(methodListVMAddr uint64, handler func(uint64, o
13101407
13111408// GetObjCIvars returns the Objective-C instance variables
13121409func (f * File ) GetObjCIvars (vmaddr uint64 ) ([]objc.Ivar , error ) {
1410+ if err := f .ensureObjCNonFragileRuntime ("GetObjCIvars" ); err != nil {
1411+ return nil , err
1412+ }
1413+
13131414 return f .getObjCIvarsWithSwift (vmaddr , false )
13141415}
13151416
@@ -1394,6 +1495,10 @@ func (f *File) getObjCIvarsWithSwift(vmaddr uint64, allowSwift bool) ([]objc.Iva
13941495
13951496// GetObjCProperties returns the Objective-C properties
13961497func (f * File ) GetObjCProperties (vmaddr uint64 ) ([]objc.Property , error ) {
1498+ if err := f .ensureObjCNonFragileRuntime ("GetObjCProperties" ); err != nil {
1499+ return nil , err
1500+ }
1501+
13971502 return f .getObjCPropertiesWithSwift (vmaddr , false )
13981503}
13991504
@@ -1439,6 +1544,10 @@ func (f *File) getObjCPropertiesWithSwift(vmaddr uint64, allowSwift bool) ([]obj
14391544
14401545// GetObjCClassReferences returns a map of classes to their section data virtual memory address
14411546func (f * File ) GetObjCClassReferences () (map [uint64 ]* objc.Class , error ) {
1547+ if err := f .ensureObjCNonFragileRuntime ("GetObjCClassReferences" ); err != nil {
1548+ return nil , err
1549+ }
1550+
14421551 clsRefs := make (map [uint64 ]* objc.Class )
14431552
14441553 for _ , s := range f .Segments () {
@@ -1486,6 +1595,10 @@ func (f *File) GetObjCClassReferences() (map[uint64]*objc.Class, error) {
14861595
14871596// GetObjCSuperReferences returns a map of super classes to their section data virtual memory address
14881597func (f * File ) GetObjCSuperReferences () (map [uint64 ]* objc.Class , error ) {
1598+ if err := f .ensureObjCNonFragileRuntime ("GetObjCSuperReferences" ); err != nil {
1599+ return nil , err
1600+ }
1601+
14891602 clsRefs := make (map [uint64 ]* objc.Class )
14901603
14911604 for _ , s := range f .Segments () {
@@ -1532,6 +1645,10 @@ func (f *File) GetObjCSuperReferences() (map[uint64]*objc.Class, error) {
15321645
15331646// GetObjCProtoReferences returns a map of protocol names to their section data virtual memory address
15341647func (f * File ) GetObjCProtoReferences () (map [uint64 ]* objc.Protocol , error ) {
1648+ if err := f .ensureObjCNonFragileRuntime ("GetObjCProtoReferences" ); err != nil {
1649+ return nil , err
1650+ }
1651+
15351652 protRefs := make (map [uint64 ]* objc.Protocol )
15361653
15371654 for _ , s := range f .Segments () {
@@ -1569,6 +1686,10 @@ func (f *File) GetObjCProtoReferences() (map[uint64]*objc.Protocol, error) {
15691686
15701687// GetObjCSelectorReferences returns a map of selector names to their section data virtual memory address
15711688func (f * File ) GetObjCSelectorReferences () (map [uint64 ]* objc.Selector , error ) {
1689+ if err := f .ensureObjCNonFragileRuntime ("GetObjCSelectorReferences" ); err != nil {
1690+ return nil , err
1691+ }
1692+
15721693 selRefs := make (map [uint64 ]* objc.Selector )
15731694
15741695 for _ , s := range f .Segments () {
0 commit comments