Index: class-dump/src/CDObjectiveCProcessor.m |
=================================================================== |
--- class-dump/src/CDObjectiveCProcessor.m (revision 0) |
+++ class-dump/src/CDObjectiveCProcessor.m (revision 0) |
@@ -0,0 +1,255 @@ |
+// -*- mode: ObjC -*- |
+ |
+// This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. |
+// Copyright (C) 1997-1998, 2000-2001, 2004-2010 Steve Nygard. |
+ |
+#import "CDObjectiveCProcessor.h" |
+ |
+#import "CDClassDump.h" |
+#import "CDMachOFile.h" |
+#import "CDVisitor.h" |
+#import "NSArray-Extensions.h" |
+#import "CDLCSegment.h" |
+#import "CDLCDynamicSymbolTable.h" |
+#import "CDLCSymbolTable.h" |
+#import "CDOCProtocol.h" |
+#import "CDTypeController.h" |
+ |
+// Note: sizeof(long long) == 8 on both 32-bit and 64-bit. sizeof(uint64_t) == 8. So use [NSNumber numberWithUnsignedLongLong:]. |
+ |
+@implementation CDObjectiveCProcessor |
+ |
+- (id)initWithMachOFile:(CDMachOFile *)aMachOFile; |
+{ |
+ if ([super init] == nil) |
+ return nil; |
+ |
+ machOFile = [aMachOFile retain]; |
+ classes = [[NSMutableArray alloc] init]; |
+ classesByAddress = [[NSMutableDictionary alloc] init]; |
+ categories = [[NSMutableArray alloc] init]; |
+ protocolsByName = [[NSMutableDictionary alloc] init]; |
+ protocolsByAddress = [[NSMutableDictionary alloc] init]; |
+ |
+ return self; |
+} |
+ |
+- (void)dealloc; |
+{ |
+ [machOFile release]; |
+ [classes release]; |
+ [classesByAddress release]; |
+ [categories release]; |
+ [protocolsByName release]; |
+ [protocolsByAddress release]; |
+ |
+ [super dealloc]; |
+} |
+ |
+- (CDMachOFile *)machOFile; |
+{ |
+ return machOFile; |
+} |
+ |
+- (BOOL)hasObjectiveCData; |
+{ |
+ return [machOFile hasObjectiveC1Data] || [machOFile hasObjectiveC2Data]; |
+} |
+ |
+- (void)process; |
+{ |
+ if ([machOFile isEncrypted] == NO && [machOFile canDecryptAllSegments]) { |
+ [[machOFile symbolTable] loadSymbols]; |
+ [[machOFile dynamicSymbolTable] loadSymbols]; |
+ |
+ [self loadProtocols]; |
+ |
+ // Load classes before categories, so we can get a dictionary of classes by address. |
+ [self loadClasses]; |
+ [self loadCategories]; |
+ } |
+} |
+ |
+- (void)loadProtocols; |
+{ |
+ // Implement in subclasses. |
+} |
+ |
+- (void)loadClasses; |
+{ |
+ // Implement in subclasses. |
+} |
+ |
+- (void)loadCategories; |
+{ |
+ // Implement in subclasses. |
+} |
+ |
+ |
+- (void)registerTypesWithObject:(CDTypeController *)typeController phase:(NSUInteger)phase; |
+{ |
+ for (CDOCClass *aClass in classes) |
+ [aClass registerTypesWithObject:typeController phase:phase]; |
+ |
+ for (CDOCCategory *category in categories) |
+ [category registerTypesWithObject:typeController phase:phase]; |
+ |
+ for (NSString *name in [[protocolsByName allKeys] sortedArrayUsingSelector:@selector(compare:)]) |
+ [[protocolsByName objectForKey:name] registerTypesWithObject:typeController phase:phase]; |
+} |
+ |
+- (NSString *)description; |
+{ |
+ return [NSString stringWithFormat:@"<%@:%p> machOFile: %@", |
+ NSStringFromClass([self class]), self, |
+ [machOFile filename]]; |
+} |
+ |
+- (void)recursivelyVisit:(CDVisitor *)aVisitor; |
+{ |
+ NSMutableArray *classesAndCategories; |
+ NSArray *protocolNames; |
+ |
+ classesAndCategories = [[NSMutableArray alloc] init]; |
+ [classesAndCategories addObjectsFromArray:classes]; |
+ [classesAndCategories addObjectsFromArray:categories]; |
+ |
+ // TODO: Sort protocols by dependency |
+ // TODO (2004-01-30): It looks like protocols might be defined in more than one file. i.e. NSObject. |
+ // TODO (2004-02-02): Looks like we need to record the order the protocols were encountered, or just always sort protocols |
+ protocolNames = [[protocolsByName allKeys] sortedArrayUsingSelector:@selector(compare:)]; |
+ |
+ [aVisitor willVisitObjectiveCProcessor:self]; |
+ |
+ // Skip if there are no protocols, classes, or categories to print. |
+ // But don't skip if the file is encrypted or has segments that can't be decrypted. |
+ if ([protocolNames count] > 0 || [classesAndCategories count] > 0 || [machOFile isEncrypted] || [machOFile canDecryptAllSegments] == NO) { |
+ [aVisitor visitObjectiveCProcessor:self]; |
+ } |
+ |
+ for (NSString *protocolName in protocolNames) { |
+ [[protocolsByName objectForKey:protocolName] recursivelyVisit:aVisitor]; |
+ } |
+ |
+ if ([[aVisitor classDump] shouldSortClassesByInheritance]) { |
+ [classesAndCategories sortTopologically]; |
+ } else if ([[aVisitor classDump] shouldSortClasses]) |
+ [classesAndCategories sortUsingSelector:@selector(ascendingCompareByName:)]; |
+ |
+ for (id aClassOrCategory in classesAndCategories) |
+ [aClassOrCategory recursivelyVisit:aVisitor]; |
+ |
+ [classesAndCategories release]; |
+ |
+ [aVisitor didVisitObjectiveCProcessor:self]; |
+} |
+ |
+- (void)createUniquedProtocols; |
+{ |
+ // Now unique the protocols by name and store in protocolsByName |
+ |
+ for (NSNumber *key in [[protocolsByAddress allKeys] sortedArrayUsingSelector:@selector(compare:)]) { |
+ CDOCProtocol *p1, *p2; |
+ |
+ p1 = [protocolsByAddress objectForKey:key]; |
+ p2 = [protocolsByName objectForKey:[p1 name]]; |
+ if (p2 == nil) { |
+ p2 = [[CDOCProtocol alloc] init]; |
+ [p2 setName:[p1 name]]; |
+ [protocolsByName setObject:p2 forKey:[p2 name]]; |
+ // adopted protocols still not set, will want uniqued instances |
+ [p2 release]; |
+ } else { |
+ } |
+ } |
+ |
+ //NSLog(@"uniqued protocol names: %@", [[[protocolsByName allKeys] sortedArrayUsingSelector:@selector(compare:)] componentsJoinedByString:@", "]); |
+ |
+ // And finally fill in adopted protocols, instance and class methods. And properties. |
+ for (NSNumber *key in [[protocolsByAddress allKeys] sortedArrayUsingSelector:@selector(compare:)]) { |
+ CDOCProtocol *p1, *uniqueProtocol; |
+ |
+ p1 = [protocolsByAddress objectForKey:key]; |
+ uniqueProtocol = [protocolsByName objectForKey:[p1 name]]; |
+ for (CDOCProtocol *p2 in [p1 protocols]) |
+ [uniqueProtocol addProtocol:[protocolsByName objectForKey:[p2 name]]]; |
+ |
+ if ([[uniqueProtocol classMethods] count] == 0) { |
+ for (CDOCMethod *method in [p1 classMethods]) |
+ [uniqueProtocol addClassMethod:method]; |
+ } else { |
+ NSParameterAssert([[p1 classMethods] count] == 0 || [[uniqueProtocol classMethods] count] == [[p1 classMethods] count]); |
+ } |
+ |
+ if ([[uniqueProtocol instanceMethods] count] == 0) { |
+ for (CDOCMethod *method in [p1 instanceMethods]) |
+ [uniqueProtocol addInstanceMethod:method]; |
+ } else { |
+ NSParameterAssert([[p1 instanceMethods] count] == 0 || [[uniqueProtocol instanceMethods] count] == [[p1 instanceMethods] count]); |
+ } |
+ |
+ if ([[uniqueProtocol optionalClassMethods] count] == 0) { |
+ for (CDOCMethod *method in [p1 optionalClassMethods]) |
+ [uniqueProtocol addOptionalClassMethod:method]; |
+ } else { |
+ NSParameterAssert([[p1 optionalClassMethods] count] == 0 || [[uniqueProtocol optionalClassMethods] count] == [[p1 optionalClassMethods] count]); |
+ } |
+ |
+ if ([[uniqueProtocol optionalInstanceMethods] count] == 0) { |
+ for (CDOCMethod *method in [p1 optionalInstanceMethods]) |
+ [uniqueProtocol addOptionalInstanceMethod:method]; |
+ } else { |
+ NSParameterAssert([[p1 optionalInstanceMethods] count] == 0 || [[uniqueProtocol optionalInstanceMethods] count] == [[p1 optionalInstanceMethods] count]); |
+ } |
+ |
+ if ([[uniqueProtocol properties] count] == 0) { |
+ for (CDOCProperty *property in [p1 properties]) |
+ [uniqueProtocol addProperty:property]; |
+ } else { |
+ NSParameterAssert([[p1 properties] count] == 0 || [[uniqueProtocol properties] count] == [[p1 properties] count]); |
+ } |
+ } |
+ |
+ //NSLog(@"protocolsByName: %@", protocolsByName); |
+} |
+ |
+- (NSData *)objcImageInfoData; |
+{ |
+ // Good for objc2. Use __OBJC segment for objc1. |
+ return [[[machOFile segmentWithName:@"__DATA"] sectionWithName:@"__objc_imageinfo"] data]; |
+} |
+ |
+- (NSString *)garbageCollectionStatus; |
+{ |
+ NSData *sectionData; |
+ CDDataCursor *cursor; |
+ uint32_t v1, v2; |
+ |
+ sectionData = [self objcImageInfoData]; |
+ if ([sectionData length] < 8) |
+ return @"Unknown"; |
+ |
+ cursor = [[CDDataCursor alloc] initWithData:sectionData]; |
+ [cursor setByteOrder:[machOFile byteOrder]]; |
+ |
+ v1 = [cursor readInt32]; |
+ v2 = [cursor readInt32]; |
+ //NSLog(@"%s: %08x %08x", _cmd, v1, v2); |
+ // v2 == 0 -> Objective-C Garbage Collection: Unsupported |
+ // v2 == 2 -> Supported |
+ // v2 == 6 -> Required |
+ NSParameterAssert(v2 == 0 || v2 == 2 || v2 == 6); |
+ |
+ [cursor release]; |
+ |
+ // These are probably bitfields that should be tested/masked... |
+ switch (v2) { |
+ case 0: return @"Unsupported"; |
+ case 2: return @"Supported"; |
+ case 6: return @"Required"; |
+ } |
+ |
+ return [NSString stringWithFormat:@"Unknown (0x%08x)", v2]; |
+} |
+ |
+@end |
Property changes on: class-dump/src/CDObjectiveCProcessor.m |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |