├── .github └── ISSUE_TEMPLATE │ └── bug_report.md ├── .gitignore ├── CDBalanceFormatter.h ├── CDBalanceFormatter.m ├── CDClassDump.h ├── CDClassDump.m ├── CDClassDumpVisitor.h ├── CDClassDumpVisitor.m ├── CDClassFrameworkVisitor.h ├── CDClassFrameworkVisitor.m ├── CDDataCursor.h ├── CDDataCursor.m ├── CDExtensions.h ├── CDFatArch.h ├── CDFatArch.m ├── CDFatFile.h ├── CDFatFile.m ├── CDFile.h ├── CDFile.m ├── CDFindMethodVisitor.h ├── CDFindMethodVisitor.m ├── CDLCBuildVersion.h ├── CDLCBuildVersion.m ├── CDLCDataInCode.h ├── CDLCDataInCode.m ├── CDLCDyldInfo.h ├── CDLCDyldInfo.m ├── CDLCDylib.h ├── CDLCDylib.m ├── CDLCDylinker.h ├── CDLCDylinker.m ├── CDLCDynamicSymbolTable.h ├── CDLCDynamicSymbolTable.m ├── CDLCEncryptionInfo.h ├── CDLCEncryptionInfo.m ├── CDLCFunctionStarts.h ├── CDLCFunctionStarts.m ├── CDLCLinkeditData.h ├── CDLCLinkeditData.m ├── CDLCMain.h ├── CDLCMain.m ├── CDLCPrebindChecksum.h ├── CDLCPrebindChecksum.m ├── CDLCPreboundDylib.h ├── CDLCPreboundDylib.m ├── CDLCRoutines32.h ├── CDLCRoutines32.m ├── CDLCRoutines64.h ├── CDLCRoutines64.m ├── CDLCRunPath.h ├── CDLCRunPath.m ├── CDLCSegment.h ├── CDLCSegment.m ├── CDLCSourceVersion.h ├── CDLCSourceVersion.m ├── CDLCSubClient.h ├── CDLCSubClient.m ├── CDLCSubFramework.h ├── CDLCSubFramework.m ├── CDLCSubLibrary.h ├── CDLCSubLibrary.m ├── CDLCSubUmbrella.h ├── CDLCSubUmbrella.m ├── CDLCSymbolTable.h ├── CDLCSymbolTable.m ├── CDLCTwoLevelHints.h ├── CDLCTwoLevelHints.m ├── CDLCUUID.h ├── CDLCUUID.m ├── CDLCUnixThread.h ├── CDLCUnixThread.m ├── CDLCUnknown.h ├── CDLCUnknown.m ├── CDLCVersionMinimum.h ├── CDLCVersionMinimum.m ├── CDLoadCommand.h ├── CDLoadCommand.m ├── CDMachOFile.h ├── CDMachOFile.m ├── CDMachOFileDataCursor.h ├── CDMachOFileDataCursor.m ├── CDMethodType.h ├── CDMethodType.m ├── CDMultiFileVisitor.h ├── CDMultiFileVisitor.m ├── CDOCCategory.h ├── CDOCCategory.m ├── CDOCClass.h ├── CDOCClass.m ├── CDOCClassReference.h ├── CDOCClassReference.m ├── CDOCInstanceVariable.h ├── CDOCInstanceVariable.m ├── CDOCMethod.h ├── CDOCMethod.m ├── CDOCModule.h ├── CDOCModule.m ├── CDOCProperty.h ├── CDOCProperty.m ├── CDOCProtocol.h ├── CDOCProtocol.m ├── CDOCSymtab.h ├── CDOCSymtab.m ├── CDObjectiveC1Processor.h ├── CDObjectiveC1Processor.m ├── CDObjectiveC2Processor.h ├── CDObjectiveC2Processor.m ├── CDObjectiveCProcessor.h ├── CDObjectiveCProcessor.m ├── CDProtocolUniquer.h ├── CDProtocolUniquer.m ├── CDRelocationInfo.h ├── CDRelocationInfo.m ├── CDSearchPathState.h ├── CDSearchPathState.m ├── CDSection.h ├── CDSection.m ├── CDStructureInfo.h ├── CDStructureInfo.m ├── CDStructureTable.h ├── CDStructureTable.m ├── CDSymbol.h ├── CDSymbol.m ├── CDTextClassDumpVisitor.h ├── CDTextClassDumpVisitor.m ├── CDTopoSortNode.h ├── CDTopoSortNode.m ├── CDTopologicalSortProtocol.h ├── CDType.h ├── CDType.m ├── CDTypeController.h ├── CDTypeController.m ├── CDTypeFormatter.h ├── CDTypeFormatter.m ├── CDTypeLexer.h ├── CDTypeLexer.m ├── CDTypeName.h ├── CDTypeName.m ├── CDTypeParser.h ├── CDTypeParser.m ├── CDUnitTests-Info.plist ├── CDVisitor.h ├── CDVisitor.m ├── CDVisitorPropertyState.h ├── CDVisitorPropertyState.m ├── CHANGELOG.md ├── Info.plist ├── MachObjC-Prefix.pch ├── Makefile ├── NSArray-CDExtensions.h ├── NSArray-CDExtensions.m ├── NSData-CDExtensions.h ├── NSData-CDExtensions.m ├── NSError-CDExtensions.h ├── NSError-CDExtensions.m ├── NSScanner-CDExtensions.h ├── NSScanner-CDExtensions.m ├── NSString-CDExtensions.h ├── NSString-CDExtensions.m ├── README.md ├── ULEB128.h ├── ULEB128.m ├── blowfish.c ├── blowfish.h ├── cd_objc2.h ├── class-dump-Prefix.pch ├── class-dump.m ├── control ├── ext.h └── keys.txt /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .theos 2 | .vscode 3 | packages -------------------------------------------------------------------------------- /CDBalanceFormatter.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @interface CDBalanceFormatter : NSObject 7 | 8 | - (id)initWithString:(NSString *)str; 9 | 10 | - (void)parse:(NSString *)open index:(NSUInteger)openIndex level:(NSUInteger)level; 11 | 12 | - (NSString *)format; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /CDBalanceFormatter.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDBalanceFormatter.h" 7 | 8 | static BOOL debug = NO; 9 | 10 | @implementation CDBalanceFormatter 11 | { 12 | NSScanner *_scanner; 13 | NSCharacterSet *_openCloseSet; 14 | 15 | NSMutableString *_result; 16 | } 17 | 18 | - (id)initWithString:(NSString *)str; 19 | { 20 | if ((self = [super init])) { 21 | _scanner = [[NSScanner alloc] initWithString:str]; 22 | _openCloseSet = [NSCharacterSet characterSetWithCharactersInString:@"{}<>()"]; 23 | 24 | _result = [[NSMutableString alloc] init]; 25 | } 26 | 27 | return self; 28 | } 29 | 30 | #pragma mark - 31 | 32 | - (void)parse:(NSString *)open index:(NSUInteger)openIndex level:(NSUInteger)level; 33 | { 34 | NSString *opens[] = { @"{", @"<", @"(", nil}; 35 | NSString *closes[] = { @"}", @">", @")", nil}; 36 | BOOL foundOpen = NO; 37 | BOOL foundClose = NO; 38 | 39 | while ([_scanner isAtEnd] == NO) { 40 | NSString *pre; 41 | 42 | if ([_scanner scanUpToCharactersFromSet:_openCloseSet intoString:&pre]) { 43 | if (debug) NSLog(@"pre = '%@'", pre); 44 | [_result appendFormat:@"%@%@\n", [NSString spacesIndentedToLevel:level], pre]; 45 | } 46 | if (debug) NSLog(@"remaining: '%@'", [[_scanner string] substringFromIndex:[_scanner scanLocation]]); 47 | 48 | foundOpen = foundClose = NO; 49 | for (NSUInteger index = 0; index < 3; index++) { 50 | if (debug) NSLog(@"Checking open %lu: '%@'", index, opens[index]); 51 | if ([_scanner scanString:opens[index] intoString:NULL]) { 52 | if (debug) NSLog(@"Start %@", opens[index]); 53 | [_result appendSpacesIndentedToLevel:level]; 54 | [_result appendString:opens[index]]; 55 | [_result appendString:@"\n"]; 56 | 57 | [self parse:opens[index] index:[_scanner scanLocation] - 1 level:level + 1]; 58 | 59 | [_result appendSpacesIndentedToLevel:level]; 60 | [_result appendString:closes[index]]; 61 | [_result appendString:@"\n"]; 62 | foundOpen = YES; 63 | break; 64 | } 65 | 66 | if (debug) NSLog(@"Checking close %lu: '%@'", index, closes[index]); 67 | if ([_scanner scanString:closes[index] intoString:NULL]) { 68 | if ([open isEqualToString:opens[index]]) { 69 | if (debug) NSLog(@"End %@", closes[index]); 70 | } else { 71 | NSLog(@"ERROR: Unmatched end %@", closes[index]); 72 | } 73 | foundClose = YES; 74 | break; 75 | } 76 | } 77 | 78 | if (foundOpen == NO && foundClose == NO) { 79 | if (debug) NSLog(@"Unknown @ %lu: %@", [_scanner scanLocation], [[_scanner string] substringFromIndex:[_scanner scanLocation]]); 80 | break; 81 | } 82 | 83 | if (foundClose) 84 | break; 85 | } 86 | } 87 | 88 | - (NSString *)format; 89 | { 90 | [self parse:nil index:0 level:0]; 91 | 92 | if (debug) NSLog(@"result:\n%@", _result); 93 | 94 | return [NSString stringWithString:_result]; 95 | } 96 | 97 | @end 98 | -------------------------------------------------------------------------------- /CDClassDump.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDFile.h" // For CDArch 7 | 8 | #define CLASS_DUMP_BASE_VERSION "1.0.1 (64 bit)" 9 | 10 | #ifdef DEBUG 11 | #define CLASS_DUMP_VERSION CLASS_DUMP_BASE_VERSION " (iOS port by DreamDevLost)(Debug version compiled " __DATE__ " " __TIME__ ")" 12 | #else 13 | #define CLASS_DUMP_VERSION CLASS_DUMP_BASE_VERSION 14 | #endif 15 | 16 | @class CDFile; 17 | @class CDTypeController; 18 | @class CDVisitor; 19 | @class CDSearchPathState; 20 | 21 | @interface CDClassDump : NSObject 22 | 23 | @property (readonly) CDSearchPathState *searchPathState; 24 | 25 | @property (assign) BOOL shouldProcessRecursively; 26 | @property (assign) BOOL shouldSortClasses; 27 | @property (assign) BOOL shouldSortClassesByInheritance; 28 | @property (assign) BOOL shouldSortMethods; 29 | @property (assign) BOOL shouldShowIvarOffsets; 30 | @property (assign) BOOL shouldShowMethodAddresses; 31 | @property (assign) BOOL shouldShowHeader; 32 | 33 | @property (strong) NSRegularExpression *regularExpression; 34 | - (BOOL)shouldShowName:(NSString *)name; 35 | 36 | @property (strong) NSString *sdkRoot; 37 | 38 | @property (readonly) NSArray *machOFiles; 39 | @property (readonly) NSArray *objcProcessors; 40 | 41 | @property (assign) CDArch targetArch; 42 | 43 | @property (nonatomic, readonly) BOOL containsObjectiveCData; 44 | @property (nonatomic, readonly) BOOL hasEncryptedFiles; 45 | @property (nonatomic, readonly) BOOL hasObjectiveCRuntimeInfo; 46 | 47 | @property (readonly) CDTypeController *typeController; 48 | 49 | - (BOOL)loadFile:(CDFile *)file error:(NSError **)error; 50 | - (void)processObjectiveCData; 51 | 52 | - (void)recursivelyVisit:(CDVisitor *)visitor; 53 | 54 | - (void)appendHeaderToString:(NSMutableString *)resultString; 55 | 56 | - (void)registerTypes; 57 | 58 | - (void)showHeader; 59 | - (void)showLoadCommands; 60 | 61 | @end 62 | 63 | extern NSString *CDErrorDomain_ClassDump; 64 | extern NSString *CDErrorKey_Exception; 65 | 66 | 67 | -------------------------------------------------------------------------------- /CDClassDumpVisitor.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDTextClassDumpVisitor.h" 7 | 8 | @interface CDClassDumpVisitor : CDTextClassDumpVisitor 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /CDClassFrameworkVisitor.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDVisitor.h" 7 | 8 | // This builds up a dictionary mapping class names to a framework names. 9 | // It is only used by CDMultiFileVisitor to generate individual imports when creating separate header files. 10 | 11 | // Some protocols appear in multiple frameworks. This just records the last framework that contained a reference, which 12 | // produces incorrect results. For example, -r AppKit.framework, and Foundation.framework is processed before several 13 | // others, including Symbolication. 14 | 15 | // If we follow framework dependancies, the earliest reference to NSCopying is CoreFoundation, but NSCopying is really 16 | // defined in Foundation. 17 | 18 | // But it turns out that we can just use forward references for protocols. 19 | 20 | @interface CDClassFrameworkVisitor : CDVisitor 21 | 22 | // NSString (class name) -> NSString (framework name) 23 | @property (nonatomic, readonly) NSDictionary *frameworkNamesByClassName; 24 | 25 | // NSString (protocol name) -> NSString (framework name) 26 | @property (nonatomic, readonly) NSDictionary *frameworkNamesByProtocolName; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /CDClassFrameworkVisitor.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDClassFrameworkVisitor.h" 7 | 8 | #import "CDMachOFile.h" 9 | #import "CDOCClass.h" 10 | #import "CDObjectiveCProcessor.h" 11 | #import "CDSymbol.h" 12 | #import "CDLCDylib.h" 13 | #import "CDOCCategory.h" 14 | #import "CDOCClassReference.h" 15 | 16 | @interface CDClassFrameworkVisitor () 17 | @property (strong) NSString *frameworkName; 18 | @end 19 | 20 | #pragma mark - 21 | 22 | @implementation CDClassFrameworkVisitor 23 | { 24 | NSMutableDictionary *_frameworkNamesByClassName; 25 | NSMutableDictionary *_frameworkNamesByProtocolName; 26 | NSString *_frameworkName; 27 | } 28 | 29 | - (id)init; 30 | { 31 | if ((self = [super init])) { 32 | _frameworkNamesByClassName = [[NSMutableDictionary alloc] init]; 33 | _frameworkNamesByProtocolName = [[NSMutableDictionary alloc] init]; 34 | } 35 | 36 | return self; 37 | } 38 | 39 | #pragma mark - 40 | 41 | - (void)willVisitObjectiveCProcessor:(CDObjectiveCProcessor *)processor; 42 | { 43 | self.frameworkName = processor.machOFile.importBaseName; 44 | } 45 | 46 | - (void)willVisitClass:(CDOCClass *)aClass; 47 | { 48 | [self addClassName:aClass.name referencedInFramework:self.frameworkName]; 49 | 50 | // We only need to add superclasses for external classes - classes defined in this binary will be visited on their own 51 | CDOCClassReference *superClassRef = [aClass superClassRef]; 52 | if ([superClassRef isExternalClass] && superClassRef.classSymbol != nil) { 53 | [self addClassForExternalSymbol:superClassRef.classSymbol]; 54 | } 55 | } 56 | 57 | - (void)willVisitProtocol:(CDOCProtocol *)protocol; 58 | { 59 | // TODO: (2012-02-28) Figure out what frameworks use each protocol, and try to pick the correct one. More difficult because, for example, NSCopying is found in many frameworks, and picking the last one isn't good enough. Perhaps a topological sort of the dependancies would be better. 60 | [self addProtocolName:protocol.name referencedInFramework:self.frameworkName]; 61 | } 62 | 63 | - (void)willVisitCategory:(CDOCCategory *)category; 64 | { 65 | CDOCClassReference *classRef = [category classRef]; 66 | if ([classRef isExternalClass] && classRef.classSymbol != nil) { 67 | [self addClassForExternalSymbol:classRef.classSymbol]; 68 | } 69 | } 70 | 71 | #pragma mark - 72 | 73 | - (void)addClassForExternalSymbol:(CDSymbol *)symbol; 74 | { 75 | NSString *frameworkName = CDImportNameForPath([[symbol dylibLoadCommand] path]); 76 | NSString *className = [CDSymbol classNameFromSymbolName:[symbol name]]; 77 | [self addClassName:className referencedInFramework:frameworkName]; 78 | } 79 | 80 | - (void)addClassName:(NSString *)name referencedInFramework:(NSString *)frameworkName; 81 | { 82 | if (name != nil && frameworkName != nil) 83 | _frameworkNamesByClassName[name] = frameworkName; 84 | } 85 | 86 | - (void)addProtocolName:(NSString *)name referencedInFramework:(NSString *)frameworkName; 87 | { 88 | if (name != nil && frameworkName != nil) 89 | _frameworkNamesByProtocolName[name] = frameworkName; 90 | } 91 | 92 | - (NSDictionary *)frameworkNamesByClassName; 93 | { 94 | return [_frameworkNamesByClassName copy]; 95 | } 96 | 97 | - (NSDictionary *)frameworkNamesByProtocolName; 98 | { 99 | return [_frameworkNamesByProtocolName copy]; 100 | } 101 | 102 | @end 103 | -------------------------------------------------------------------------------- /CDDataCursor.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @interface CDDataCursor : NSObject 7 | 8 | - (id)initWithData:(NSData *)data; 9 | 10 | @property (readonly) NSData *data; 11 | - (const void *)bytes; 12 | 13 | @property (nonatomic, assign) NSUInteger offset; 14 | 15 | - (void)advanceByLength:(NSUInteger)length; 16 | - (NSUInteger)remaining; 17 | 18 | - (uint8_t)readByte; 19 | 20 | - (uint16_t)readLittleInt16; 21 | - (uint32_t)readLittleInt32; 22 | - (uint64_t)readLittleInt64; 23 | 24 | - (uint16_t)readBigInt16; 25 | - (uint32_t)readBigInt32; 26 | - (uint64_t)readBigInt64; 27 | 28 | - (float)readLittleFloat32; 29 | - (float)readBigFloat32; 30 | 31 | - (double)readLittleFloat64; 32 | //- (double)readBigFloat64; 33 | 34 | - (void)appendBytesOfLength:(NSUInteger)length intoData:(NSMutableData *)data; 35 | - (void)readBytesOfLength:(NSUInteger)length intoBuffer:(void *)buf; 36 | - (BOOL)isAtEnd; 37 | 38 | - (NSString *)readCString; 39 | - (NSString *)readStringOfLength:(NSUInteger)length encoding:(NSStringEncoding)encoding; 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /CDExtensions.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDTopoSortNode.h" 7 | #import "NSArray-CDExtensions.h" 8 | #import "NSData-CDExtensions.h" 9 | #import "NSData-CDExtensions.h" 10 | #import "NSError-CDExtensions.h" 11 | #import "NSScanner-CDExtensions.h" 12 | #import "NSString-CDExtensions.h" 13 | -------------------------------------------------------------------------------- /CDFatArch.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDFile.h" // For CDArch 7 | 8 | @class CDDataCursor; 9 | @class CDFatFile, CDMachOFile; 10 | 11 | @interface CDFatArch : NSObject 12 | 13 | - (id)initWithMachOFile:(CDMachOFile *)machOFile; 14 | - (id)initWithDataCursor:(CDDataCursor *)cursor; 15 | 16 | @property (assign) cpu_type_t cputype; 17 | @property (assign) cpu_subtype_t cpusubtype; 18 | @property (assign) uint32_t offset; 19 | @property (assign) uint32_t size; 20 | @property (assign) uint32_t align; 21 | 22 | @property (nonatomic, readonly) cpu_type_t maskedCPUType; 23 | @property (nonatomic, readonly) cpu_subtype_t maskedCPUSubtype; 24 | @property (nonatomic, readonly) BOOL uses64BitABI; 25 | @property (nonatomic, readonly) BOOL uses64BitLibraries; 26 | 27 | @property (weak) CDFatFile *fatFile; 28 | 29 | @property (nonatomic, readonly) CDArch arch; 30 | @property (nonatomic, readonly) NSString *archName; 31 | 32 | @property (nonatomic, readonly) CDMachOFile *machOFile; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /CDFatArch.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDFatArch.h" 7 | 8 | #include 9 | #import "CDDataCursor.h" 10 | #import "CDFatFile.h" 11 | #import "CDMachOFile.h" 12 | 13 | @implementation CDFatArch 14 | { 15 | __weak CDFatFile *_fatFile; 16 | 17 | // This is essentially struct fat_arch, but this way our property accessors can be synthesized. 18 | cpu_type_t _cputype; 19 | cpu_subtype_t _cpusubtype; 20 | uint32_t _offset; 21 | uint32_t _size; 22 | uint32_t _align; 23 | 24 | CDMachOFile *_machOFile; // Lazily create this. 25 | } 26 | 27 | - (id)initWithMachOFile:(CDMachOFile *)machOFile; 28 | { 29 | if ((self = [super init])) { 30 | _machOFile = machOFile; 31 | NSParameterAssert([machOFile.data length] < 0x100000000); 32 | 33 | _cputype = _machOFile.cputype; 34 | _cpusubtype = _machOFile.cpusubtype; 35 | _offset = 0; // Would be filled in when this is written to disk 36 | _size = (uint32_t)[_machOFile.data length]; 37 | _align = 12; // 2**12 = 4096 (0x1000) 38 | } 39 | 40 | return self; 41 | } 42 | 43 | - (id)initWithDataCursor:(CDDataCursor *)cursor; 44 | { 45 | if ((self = [super init])) { 46 | _cputype = [cursor readBigInt32]; 47 | _cpusubtype = [cursor readBigInt32]; 48 | _offset = [cursor readBigInt32]; 49 | _size = [cursor readBigInt32]; 50 | _align = [cursor readBigInt32]; 51 | 52 | //NSLog(@"self: %@", self); 53 | } 54 | 55 | return self; 56 | } 57 | 58 | #pragma mark - Debugging 59 | 60 | - (NSString *)description; 61 | { 62 | return [NSString stringWithFormat:@"64 bit ABI? %d, cputype: 0x%08x, cpusubtype: 0x%08x, offset: 0x%08x (%8u), size: 0x%08x (%8u), align: 2^%u (%x), arch name: %@", 63 | self.uses64BitABI, self.cputype, self.cpusubtype, self.offset, self.offset, self.size, self.size, 64 | self.align, 1 << self.align, self.archName]; 65 | } 66 | 67 | #pragma mark - 68 | 69 | - (cpu_type_t)maskedCPUType; 70 | { 71 | return self.cputype & ~CPU_ARCH_MASK; 72 | } 73 | 74 | - (cpu_subtype_t)maskedCPUSubtype; 75 | { 76 | return self.cpusubtype & ~CPU_SUBTYPE_MASK; 77 | } 78 | 79 | - (BOOL)uses64BitABI; 80 | { 81 | return CDArchUses64BitABI(self.arch); 82 | } 83 | 84 | - (BOOL)uses64BitLibraries; 85 | { 86 | return CDArchUses64BitLibraries(self.arch); 87 | } 88 | 89 | - (CDArch)arch; 90 | { 91 | CDArch arch = { self.cputype, self.cpusubtype }; 92 | 93 | return arch; 94 | } 95 | 96 | // Must not return nil. 97 | - (NSString *)archName; 98 | { 99 | return CDNameForCPUType(self.cputype, self.cpusubtype); 100 | } 101 | 102 | - (CDMachOFile *)machOFile; 103 | { 104 | if (_machOFile == nil) { 105 | NSData *data = [NSData dataWithBytesNoCopy:((uint8_t *)[self.fatFile.data bytes] + self.offset) length:self.size freeWhenDone:NO]; 106 | _machOFile = [[CDMachOFile alloc] initWithData:data filename:self.fatFile.filename searchPathState:self.fatFile.searchPathState]; 107 | } 108 | 109 | return _machOFile; 110 | } 111 | 112 | @end 113 | -------------------------------------------------------------------------------- /CDFatFile.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDFile.h" 7 | 8 | @class CDFatArch; 9 | 10 | @interface CDFatFile : CDFile 11 | 12 | @property (readonly) NSMutableArray *arches; 13 | @property (nonatomic, readonly) NSArray *archNames; 14 | 15 | - (void)addArchitecture:(CDFatArch *)fatArch; 16 | - (BOOL)containsArchitecture:(CDArch)arch; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /CDFatFile.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDFatFile.h" 7 | 8 | #include 9 | #include 10 | 11 | #import "CDDataCursor.h" 12 | #import "CDFatArch.h" 13 | #import "CDMachOFile.h" 14 | 15 | @implementation CDFatFile 16 | { 17 | NSMutableArray *_arches; 18 | } 19 | 20 | - (id)init; 21 | { 22 | if ((self = [super init])) { 23 | _arches = [[NSMutableArray alloc] init]; 24 | } 25 | 26 | return self; 27 | } 28 | 29 | - (id)initWithData:(NSData *)data filename:(NSString *)filename searchPathState:(CDSearchPathState *)searchPathState; 30 | { 31 | if ((self = [super initWithData:data filename:filename searchPathState:searchPathState])) { 32 | CDDataCursor *cursor = [[CDDataCursor alloc] initWithData:data]; 33 | 34 | struct fat_header header; 35 | header.magic = [cursor readBigInt32]; 36 | 37 | //NSLog(@"(testing fat) magic: 0x%x", header.magic); 38 | if (header.magic != FAT_MAGIC) { 39 | return nil; 40 | } 41 | 42 | _arches = [[NSMutableArray alloc] init]; 43 | 44 | header.nfat_arch = [cursor readBigInt32]; 45 | //NSLog(@"nfat_arch: %u", header.nfat_arch); 46 | for (NSUInteger index = 0; index < header.nfat_arch; index++) { 47 | CDFatArch *arch = [[CDFatArch alloc] initWithDataCursor:cursor]; 48 | arch.fatFile = self; 49 | [_arches addObject:arch]; 50 | } 51 | } 52 | 53 | return self; 54 | } 55 | 56 | #pragma mark - Debugging 57 | 58 | - (NSString *)description; 59 | { 60 | return [NSString stringWithFormat:@"<%@:%p> %lu arches", NSStringFromClass([self class]), self, [self.arches count]]; 61 | } 62 | 63 | #pragma mark - 64 | 65 | 66 | // Case 1: no arch specified 67 | // - check main file for these, then lock down on that arch: 68 | // - local arch, 64 bit 69 | // - local arch, 32 bit 70 | // - any arch, 64 bit 71 | // - any arch, 32 bit 72 | // 73 | // Case 2: you specified a specific arch (i386, x86_64, ppc, ppc7400, ppc64, etc.) 74 | // - only that arch 75 | // 76 | // In either case, we can ignore the cpu subtype 77 | 78 | // Returns YES on success, NO on failure. 79 | - (BOOL)bestMatchForArch:(CDArch *)ioArchPtr; 80 | { 81 | cpu_type_t targetType = ioArchPtr->cputype & ~CPU_ARCH_MASK; 82 | 83 | // Target architecture, 64 bit 84 | for (CDFatArch *fatArch in self.arches) { 85 | if (fatArch.maskedCPUType == targetType && fatArch.uses64BitABI) { 86 | if (ioArchPtr != NULL) *ioArchPtr = fatArch.arch; 87 | return YES; 88 | } 89 | } 90 | 91 | // Target architecture, 32 bit 92 | for (CDFatArch *fatArch in self.arches) { 93 | if (fatArch.maskedCPUType == targetType && fatArch.uses64BitABI == NO) { 94 | if (ioArchPtr != NULL) *ioArchPtr = fatArch.arch; 95 | return YES; 96 | } 97 | } 98 | 99 | // Any architecture, 64 bit 100 | for (CDFatArch *fatArch in self.arches) { 101 | if (fatArch.uses64BitABI) { 102 | if (ioArchPtr != NULL) *ioArchPtr = fatArch.arch; 103 | return YES; 104 | } 105 | } 106 | 107 | // Any architecture, 32 bit 108 | for (CDFatArch *fatArch in self.arches) { 109 | if (fatArch.uses64BitABI == NO) { 110 | if (ioArchPtr != NULL) *ioArchPtr = fatArch.arch; 111 | return YES; 112 | } 113 | } 114 | 115 | // Any architecture 116 | if ([self.arches count] > 0) { 117 | if (ioArchPtr != NULL) *ioArchPtr = [self.arches[0] arch]; 118 | return YES; 119 | } 120 | 121 | return NO; 122 | } 123 | 124 | - (CDFatArch *)fatArchWithArch:(CDArch)cdarch; 125 | { 126 | for (CDFatArch *arch in self.arches) { 127 | if (arch.cputype == cdarch.cputype && arch.maskedCPUSubtype == (cdarch.cpusubtype & ~CPU_SUBTYPE_MASK)) 128 | return arch; 129 | } 130 | 131 | return nil; 132 | } 133 | 134 | - (CDMachOFile *)machOFileWithArch:(CDArch)cdarch; 135 | { 136 | return [[self fatArchWithArch:cdarch] machOFile]; 137 | } 138 | 139 | - (NSArray *)archNames; 140 | { 141 | NSMutableArray *archNames = [NSMutableArray array]; 142 | for (CDFatArch *arch in self.arches) 143 | [archNames addObject:arch.archName]; 144 | 145 | return archNames; 146 | } 147 | 148 | - (NSString *)architectureNameDescription; 149 | { 150 | return [self.archNames componentsJoinedByString:@", "]; 151 | } 152 | 153 | #pragma mark - 154 | 155 | - (void)addArchitecture:(CDFatArch *)fatArch; 156 | { 157 | fatArch.fatFile = self; 158 | [self.arches addObject:fatArch]; 159 | } 160 | 161 | - (BOOL)containsArchitecture:(CDArch)arch; 162 | { 163 | return [self fatArchWithArch:arch] != nil; 164 | } 165 | 166 | @end 167 | -------------------------------------------------------------------------------- /CDFile.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #include // For cpu_type_t, cpu_subtype_t 7 | 8 | typedef struct { 9 | cpu_type_t cputype; 10 | cpu_subtype_t cpusubtype; 11 | } CDArch; 12 | 13 | @class CDMachOFile, CDSearchPathState; 14 | 15 | NSString *CDImportNameForPath(NSString *path); 16 | NSString *CDNameForCPUType(cpu_type_t cputype, cpu_subtype_t cpusubtype); 17 | CDArch CDArchFromName(NSString *name); 18 | BOOL CDArchUses64BitABI(CDArch arch); 19 | BOOL CDArchUses64BitLibraries(CDArch arch); 20 | 21 | @interface CDFile : NSObject 22 | 23 | // Returns CDFatFile or CDMachOFile 24 | + (id)fileWithContentsOfFile:(NSString *)filename searchPathState:(CDSearchPathState *)searchPathState; 25 | 26 | - (id)initWithData:(NSData *)data filename:(NSString *)filename searchPathState:(CDSearchPathState *)searchPathState; 27 | 28 | @property (readonly) NSString *filename; 29 | @property (readonly) NSData *data; 30 | @property (readonly) CDSearchPathState *searchPathState; 31 | 32 | - (BOOL)bestMatchForLocalArch:(CDArch *)oArchPtr; 33 | - (BOOL)bestMatchForArch:(CDArch *)ioArchPtr; 34 | - (CDMachOFile *)machOFileWithArch:(CDArch)arch; 35 | 36 | @property (nonatomic, readonly) NSString *architectureNameDescription; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /CDFile.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDFile.h" 7 | 8 | #include 9 | #import "CDFatFile.h" 10 | #import "CDMachOFile.h" 11 | #import "CDSearchPathState.h" 12 | 13 | NSString *CDImportNameForPath(NSString *path) 14 | { 15 | NSString *name = [path lastPathComponent]; 16 | 17 | // Remove all extensions (make sure extensions like .a.dylib are covered) 18 | NSString *nameWithExtensions = name; 19 | for (NSInteger i = ([nameWithExtensions length] - 1); i >= 0; i--) { 20 | if ([nameWithExtensions characterAtIndex:i] == '.') 21 | name = [name substringToIndex:i]; 22 | } 23 | 24 | NSString *libPrefix = @"lib"; 25 | if ([name hasPrefix:libPrefix]) 26 | name = [name substringFromIndex:[libPrefix length]]; 27 | return name; 28 | } 29 | 30 | NSString *CDNameForCPUType(cpu_type_t cputype, cpu_subtype_t cpusubtype) 31 | { 32 | const NXArchInfo *archInfo = NXGetArchInfoFromCpuType(cputype, cpusubtype); 33 | if (archInfo != NULL) 34 | return [NSString stringWithUTF8String:archInfo->name]; 35 | 36 | // Special cases until the built-in function recognizes these. 37 | switch (cputype) { 38 | case CPU_TYPE_ARM: { 39 | switch (cpusubtype) { 40 | case 11: return @"armv7s"; // Not recognized in 10.8.4 41 | } 42 | break; 43 | } 44 | case CPU_TYPE_ARM | CPU_ARCH_ABI64: { 45 | switch (cpusubtype) { 46 | case CPU_SUBTYPE_ARM_ALL: return @"arm64"; // Not recognized in 10.8.4 47 | } 48 | break; 49 | } 50 | 51 | default: break; 52 | } 53 | 54 | return [NSString stringWithFormat:@"0x%x:0x%x", cputype, cpusubtype]; 55 | } 56 | 57 | CDArch CDArchFromName(NSString *name) 58 | { 59 | CDArch arch; 60 | 61 | arch.cputype = CPU_TYPE_ANY; 62 | arch.cpusubtype = 0; 63 | 64 | if (name == nil) 65 | return arch; 66 | 67 | const NXArchInfo *archInfo = NXGetArchInfoFromName([name UTF8String]); 68 | if (archInfo == NULL) { 69 | if ([name isEqualToString:@"armv7s"]) { // Not recognized in 10.8.4 70 | arch.cputype = CPU_TYPE_ARM; 71 | arch.cpusubtype = 11; 72 | } else if ([name isEqualToString:@"arm64"]) { // Not recognized in 10.8.4 73 | arch.cputype = CPU_TYPE_ARM | CPU_ARCH_ABI64; 74 | arch.cpusubtype = CPU_SUBTYPE_ARM_ALL; 75 | } else { 76 | NSString *ignore; 77 | 78 | NSScanner *scanner = [[NSScanner alloc] initWithString:name]; 79 | if ([scanner scanHexInt:(uint32_t *)&arch.cputype] 80 | && [scanner scanString:@":" intoString:&ignore] 81 | && [scanner scanHexInt:(uint32_t *)&arch.cpusubtype]) { 82 | // Great! 83 | //NSLog(@"scanned 0x%08x : 0x%08x from '%@'", arch.cputype, arch.cpusubtype, name); 84 | } else { 85 | arch.cputype = CPU_TYPE_ANY; 86 | arch.cpusubtype = 0; 87 | } 88 | } 89 | } else { 90 | arch.cputype = archInfo->cputype; 91 | arch.cpusubtype = archInfo->cpusubtype; 92 | } 93 | 94 | return arch; 95 | } 96 | 97 | BOOL CDArchUses64BitABI(CDArch arch) 98 | { 99 | return (arch.cputype & CPU_ARCH_ABI64) == CPU_ARCH_ABI64; 100 | } 101 | 102 | BOOL CDArchUses64BitLibraries(CDArch arch) 103 | { 104 | return (arch.cpusubtype & CPU_SUBTYPE_LIB64) == CPU_SUBTYPE_LIB64; 105 | } 106 | 107 | #pragma mark - 108 | 109 | @interface CDFile () 110 | @end 111 | 112 | #pragma mark - 113 | 114 | @implementation CDFile 115 | { 116 | NSString *_filename; 117 | NSData *_data; 118 | CDSearchPathState *_searchPathState; 119 | } 120 | 121 | // Returns CDFatFile or CDMachOFile 122 | + (id)fileWithContentsOfFile:(NSString *)filename searchPathState:(CDSearchPathState *)searchPathState; 123 | { 124 | NSData *data = [NSData dataWithContentsOfMappedFile:filename]; 125 | CDFatFile *fatFile = [[CDFatFile alloc] initWithData:data filename:filename searchPathState:searchPathState]; 126 | if (fatFile != nil) 127 | return fatFile; 128 | 129 | CDMachOFile *machOFile = [[CDMachOFile alloc] initWithData:data filename:filename searchPathState:searchPathState]; 130 | return machOFile; 131 | } 132 | 133 | - (id)initWithData:(NSData *)data filename:(NSString *)filename searchPathState:(CDSearchPathState *)searchPathState; 134 | { 135 | if ((self = [super init])) { 136 | // Otherwise reading the magic number fails. 137 | if ([data length] < 4) { 138 | return nil; 139 | } 140 | 141 | _filename = filename; 142 | _data = data; 143 | _searchPathState = searchPathState; 144 | } 145 | 146 | return self; 147 | } 148 | 149 | #pragma mark - 150 | 151 | // Return YES on success. If oArchPtr is not NULL, return the best match. 152 | // Return NO on failure, oArchPtr is untouched. 153 | 154 | - (BOOL)bestMatchForLocalArch:(CDArch *)oArchPtr; 155 | { 156 | const NXArchInfo *archInfo = NXGetLocalArchInfo(); 157 | if (archInfo == NULL) 158 | return NO; 159 | 160 | CDArch arch = { archInfo->cputype, archInfo->cpusubtype }; 161 | 162 | if ([self bestMatchForArch:&arch]) { 163 | if (oArchPtr != NULL) 164 | *oArchPtr = arch; 165 | return YES; 166 | } 167 | 168 | return NO; 169 | } 170 | 171 | - (BOOL)bestMatchForArch:(CDArch *)ioArchPtr; 172 | { 173 | return NO; 174 | } 175 | 176 | - (CDMachOFile *)machOFileWithArch:(CDArch)arch; 177 | { 178 | return nil; 179 | } 180 | 181 | - (NSString *)architectureNameDescription; 182 | { 183 | return nil; 184 | } 185 | 186 | @end 187 | -------------------------------------------------------------------------------- /CDFindMethodVisitor.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDVisitor.h" 7 | 8 | // This limits the output to methods matching the search string. Some context is included, so that you can see which class, category, or protocol 9 | // contains the method. 10 | 11 | @interface CDFindMethodVisitor : CDVisitor 12 | 13 | @property (strong) NSString *searchString; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /CDFindMethodVisitor.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDFindMethodVisitor.h" 7 | 8 | #import "CDClassDump.h" 9 | #import "CDObjectiveC1Processor.h" 10 | #import "CDMachOFile.h" 11 | #import "CDOCProtocol.h" 12 | #import "CDLCDylib.h" 13 | #import "CDOCClass.h" 14 | #import "CDOCCategory.h" 15 | #import "CDOCMethod.h" 16 | //#import "CDTypeController.h" 17 | 18 | @interface CDFindMethodVisitor () 19 | @property (readonly) NSMutableString *resultString; 20 | @property (nonatomic, strong) CDOCProtocol *context; 21 | @property (assign) BOOL hasShownContext; 22 | @end 23 | 24 | #pragma mark - 25 | 26 | @implementation CDFindMethodVisitor 27 | { 28 | NSString *_searchString; 29 | NSMutableString *_resultString; 30 | CDOCProtocol *_context; 31 | BOOL _hasShownContext; 32 | } 33 | 34 | - (id)init; 35 | { 36 | if ((self = [super init])) { 37 | _searchString = nil; 38 | _resultString = [[NSMutableString alloc] init]; 39 | _context = nil; 40 | _hasShownContext = NO; 41 | } 42 | 43 | return self; 44 | } 45 | 46 | #pragma mark - 47 | 48 | - (void)willBeginVisiting; 49 | { 50 | [self.classDump appendHeaderToString:self.resultString]; 51 | 52 | if (self.classDump.hasObjectiveCRuntimeInfo) { 53 | //[[classDump typeController] appendStructuresToString:resultString symbolReferences:nil]; 54 | //[resultString appendString:@"// [structures go here]\n"]; 55 | } 56 | } 57 | 58 | - (void)visitObjectiveCProcessor:(CDObjectiveCProcessor *)processor; 59 | { 60 | if (!self.classDump.hasObjectiveCRuntimeInfo) { 61 | [self.resultString appendString:@"//\n"]; 62 | [self.resultString appendString:@"// This file does not contain any Objective-C runtime information.\n"]; 63 | [self.resultString appendString:@"//\n"]; 64 | } 65 | } 66 | 67 | - (void)didEndVisiting; 68 | { 69 | [self writeResultToStandardOutput]; 70 | } 71 | 72 | - (void)writeResultToStandardOutput; 73 | { 74 | NSData *data = [self.resultString dataUsingEncoding:NSUTF8StringEncoding]; 75 | [(NSFileHandle *)[NSFileHandle fileHandleWithStandardOutput] writeData:data]; 76 | } 77 | 78 | - (void)willVisitProtocol:(CDOCProtocol *)protocol; 79 | { 80 | [self setContext:protocol]; 81 | } 82 | 83 | - (void)didVisitProtocol:(CDOCProtocol *)protocol; 84 | { 85 | if (self.hasShownContext) 86 | [self.resultString appendString:@"\n"]; 87 | } 88 | 89 | - (void)willVisitClass:(CDOCClass *)aClass; 90 | { 91 | [self setContext:aClass]; 92 | } 93 | 94 | - (void)didVisitClass:(CDOCClass *)aClass; 95 | { 96 | if (self.hasShownContext) 97 | [self.resultString appendString:@"\n"]; 98 | } 99 | 100 | - (void)willVisitIvarsOfClass:(CDOCClass *)aClass; 101 | { 102 | } 103 | 104 | - (void)didVisitIvarsOfClass:(CDOCClass *)aClass; 105 | { 106 | } 107 | 108 | - (void)willVisitCategory:(CDOCCategory *)category; 109 | { 110 | [self setContext:category]; 111 | } 112 | 113 | - (void)didVisitCategory:(CDOCCategory *)category; 114 | { 115 | if (self.hasShownContext) 116 | [self.resultString appendString:@"\n"]; 117 | } 118 | 119 | - (void)visitClassMethod:(CDOCMethod *)method; 120 | { 121 | NSRange range = [method.name rangeOfString:self.searchString]; 122 | if (range.length > 0) { 123 | [self showContextIfNecessary]; 124 | 125 | [self.resultString appendString:@"+ "]; 126 | [method appendToString:self.resultString typeController:self.classDump.typeController]; 127 | [self.resultString appendString:@"\n"]; 128 | } 129 | } 130 | 131 | - (void)visitInstanceMethod:(CDOCMethod *)method propertyState:(CDVisitorPropertyState *)propertyState; 132 | { 133 | NSRange range = [method.name rangeOfString:self.searchString]; 134 | if (range.length > 0) { 135 | [self showContextIfNecessary]; 136 | 137 | [self.resultString appendString:@"- "]; 138 | [method appendToString:self.resultString typeController:self.classDump.typeController]; 139 | [self.resultString appendString:@"\n"]; 140 | } 141 | } 142 | 143 | - (void)visitIvar:(CDOCInstanceVariable *)ivar; 144 | { 145 | } 146 | 147 | #pragma mark - 148 | 149 | - (void)setContext:(CDOCProtocol *)newContext; 150 | { 151 | if (newContext != _context) { 152 | _context = newContext; 153 | self.hasShownContext = NO; 154 | } 155 | } 156 | 157 | - (void)showContextIfNecessary; 158 | { 159 | if (self.hasShownContext == NO) { 160 | [self.resultString appendString:[self.context methodSearchContext]]; 161 | [self.resultString appendString:@"\n"]; 162 | self.hasShownContext = YES; 163 | } 164 | } 165 | 166 | @end 167 | -------------------------------------------------------------------------------- /CDLCBuildVersion.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @interface CDLCBuildVersion : CDLoadCommand 9 | 10 | @property (nonatomic, readonly) NSString *buildVersionString; 11 | @property (nonatomic, readonly) NSArray *toolStrings; 12 | @end 13 | -------------------------------------------------------------------------------- /CDLCBuildVersion.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCBuildVersion.h" 7 | 8 | #import "CDMachOFile.h" 9 | 10 | static NSString *NSStringFromBuildVersionPlatform(uint32_t platform) 11 | { 12 | return @"iOS"; 13 | /* switch (platform) { 14 | case PLATFORM_MACOS: return @"macOS"; 15 | case PLATFORM_IOS: return @"iOS"; 16 | case PLATFORM_TVOS: return @"tvOS"; 17 | case PLATFORM_WATCHOS: return @"watchOS"; 18 | case PLATFORM_BRIDGEOS: return @"bridgeOS"; 19 | case PLATFORM_IOSMAC: return @"iOS Mac"; 20 | case PLATFORM_IOSSIMULATOR: return @"iOS Simulator"; 21 | case PLATFORM_TVOSSIMULATOR: return @"tvOS Simulator"; 22 | case PLATFORM_WATCHOSSIMULATOR: return @"watchOS Simulator"; 23 | default: return [NSString stringWithFormat:@"Unknown platform %x", platform]; 24 | } */ 25 | } 26 | 27 | static NSString *NSStringFromBuildVersionTool(uint32_t tool) 28 | { 29 | switch (tool) { 30 | case TOOL_CLANG: return @"clang"; 31 | case TOOL_SWIFT: return @"swift"; 32 | case TOOL_LD: return @"ld"; 33 | default: return [NSString stringWithFormat:@"Unknown tool %x", tool]; 34 | } 35 | } 36 | 37 | static NSString *NSStringFromBuildVersionToolNotATuple(uint64_t tuple) 38 | { 39 | uint32_t tool = tuple >> 32; 40 | uint32_t version = tuple & 0xffffffff; 41 | return [NSString stringWithFormat:@"%@ %u.%u.%u", NSStringFromBuildVersionTool(tool), 42 | version >> 16, 43 | (version >> 8) & 0xff, 44 | version & 0xff]; 45 | } 46 | 47 | @implementation CDLCBuildVersion 48 | { 49 | struct build_version_command _buildVersionCommand; 50 | NSArray *_tools; 51 | } 52 | 53 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 54 | { 55 | if ((self = [super initWithDataCursor:cursor])) { 56 | _buildVersionCommand.cmd = [cursor readInt32]; 57 | _buildVersionCommand.cmdsize = [cursor readInt32]; 58 | _buildVersionCommand.platform = [cursor readInt32]; 59 | _buildVersionCommand.minos = [cursor readInt32]; 60 | _buildVersionCommand.sdk = [cursor readInt32]; 61 | _buildVersionCommand.ntools = [cursor readInt32]; 62 | NSMutableArray *tools = [NSMutableArray array]; 63 | for (NSUInteger index = 0; index < _buildVersionCommand.ntools; index++) { 64 | // ISO tuples. 65 | uint32_t tool = [cursor readInt32]; 66 | uint32_t version = [cursor readInt32]; 67 | uint64_t iso_tuples = ((uint64_t)tool << 32) | version; 68 | [tools addObject:@(iso_tuples)]; 69 | } 70 | _tools = [tools copy]; 71 | } 72 | 73 | return self; 74 | } 75 | 76 | #pragma mark - 77 | 78 | - (uint32_t)cmd; 79 | { 80 | return _buildVersionCommand.cmd; 81 | } 82 | 83 | - (uint32_t)cmdsize; 84 | { 85 | return _buildVersionCommand.cmdsize; 86 | } 87 | 88 | - (NSString *)buildVersionString; 89 | { 90 | return [NSString stringWithFormat:@"Platform: %@ %u.%u.%u, SDK: %u.%u.%u", 91 | NSStringFromBuildVersionPlatform(_buildVersionCommand.platform), 92 | _buildVersionCommand.minos >> 16, 93 | (_buildVersionCommand.minos >> 8) & 0xff, 94 | _buildVersionCommand.minos & 0xff, 95 | 96 | _buildVersionCommand.sdk >> 16, 97 | (_buildVersionCommand.sdk >> 8) & 0xff, 98 | _buildVersionCommand.sdk & 0xff]; 99 | } 100 | 101 | - (NSArray *)toolStrings; 102 | { 103 | NSMutableArray *tools = [NSMutableArray array]; 104 | // iso map 105 | for (NSNumber *tuple in _tools) { 106 | [tools addObject:NSStringFromBuildVersionToolNotATuple([tuple unsignedLongLongValue])]; 107 | } 108 | 109 | return [tools copy]; 110 | } 111 | 112 | - (void)appendToString:(NSMutableString *)resultString verbose:(BOOL)isVerbose; 113 | { 114 | [super appendToString:resultString verbose:isVerbose]; 115 | 116 | [resultString appendFormat:@" Build version: %@\n", self.buildVersionString]; 117 | } 118 | 119 | @end 120 | -------------------------------------------------------------------------------- /CDLCDataInCode.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCLinkeditData.h" 7 | 8 | @interface CDLCDataInCode : CDLCLinkeditData 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /CDLCDataInCode.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCDataInCode.h" 7 | 8 | #import "CDMachOFile.h" 9 | 10 | @implementation CDLCDataInCode 11 | { 12 | } 13 | 14 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 15 | { 16 | if ((self = [super initWithDataCursor:cursor])) { 17 | } 18 | 19 | return self; 20 | } 21 | 22 | #pragma mark - 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /CDLCDyldInfo.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @interface CDLCDyldInfo : CDLoadCommand 9 | 10 | - (NSString *)symbolNameForAddress:(NSUInteger)address; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /CDLCDylib.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @interface CDLCDylib : CDLoadCommand 9 | 10 | @property (readonly) NSString *path; 11 | @property (nonatomic, readonly) uint32_t timestamp; 12 | @property (nonatomic, readonly) uint32_t currentVersion; 13 | @property (nonatomic, readonly) uint32_t compatibilityVersion; 14 | 15 | @property (nonatomic, readonly) NSString *formattedCurrentVersion; 16 | @property (nonatomic, readonly) NSString *formattedCompatibilityVersion; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /CDLCDylib.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCDylib.h" 7 | 8 | #import "CDFatFile.h" 9 | #import "CDMachOFile.h" 10 | 11 | static NSString *CDDylibVersionString(uint32_t version) 12 | { 13 | return [NSString stringWithFormat:@"%d.%d.%d", version >> 16, (version >> 8) & 0xff, version & 0xff]; 14 | } 15 | 16 | @implementation CDLCDylib 17 | { 18 | struct dylib_command _dylibCommand; 19 | NSString *_path; 20 | } 21 | 22 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 23 | { 24 | if ((self = [super initWithDataCursor:cursor])) { 25 | _dylibCommand.cmd = [cursor readInt32]; 26 | _dylibCommand.cmdsize = [cursor readInt32]; 27 | 28 | _dylibCommand.dylib.name.offset = [cursor readInt32]; 29 | _dylibCommand.dylib.timestamp = [cursor readInt32]; 30 | _dylibCommand.dylib.current_version = [cursor readInt32]; 31 | _dylibCommand.dylib.compatibility_version = [cursor readInt32]; 32 | 33 | NSUInteger length = _dylibCommand.cmdsize - sizeof(_dylibCommand); 34 | //NSLog(@"expected length: %u", length); 35 | 36 | _path = [cursor readStringOfLength:length encoding:NSASCIIStringEncoding]; 37 | //NSLog(@"path: %@", path); 38 | } 39 | 40 | return self; 41 | } 42 | 43 | #pragma mark - 44 | 45 | - (uint32_t)cmd; 46 | { 47 | return _dylibCommand.cmd; 48 | } 49 | 50 | - (uint32_t)cmdsize; 51 | { 52 | return _dylibCommand.cmdsize; 53 | } 54 | 55 | - (uint32_t)timestamp; 56 | { 57 | return _dylibCommand.dylib.timestamp; 58 | } 59 | 60 | - (uint32_t)currentVersion; 61 | { 62 | return _dylibCommand.dylib.current_version; 63 | } 64 | 65 | - (uint32_t)compatibilityVersion; 66 | { 67 | return _dylibCommand.dylib.compatibility_version; 68 | } 69 | 70 | - (NSString *)formattedCurrentVersion; 71 | { 72 | return CDDylibVersionString(self.currentVersion); 73 | } 74 | 75 | - (NSString *)formattedCompatibilityVersion; 76 | { 77 | return CDDylibVersionString(self.compatibilityVersion); 78 | } 79 | 80 | #if 0 81 | - (NSString *)extraDescription; 82 | { 83 | return [NSString stringWithFormat:@"%@ (compatibility version %@, current version %@, timestamp %d [%@])", 84 | self.path, CDDylibVersionString(self.compatibilityVersion), CDDylibVersionString(self.currentVersion), 85 | self.timestamp, [NSDate dateWithTimeIntervalSince1970:self.timestamp]]; 86 | } 87 | #endif 88 | 89 | @end 90 | -------------------------------------------------------------------------------- /CDLCDylinker.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @interface CDLCDylinker : CDLoadCommand 9 | 10 | @property (readonly) NSString *name; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /CDLCDylinker.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCDylinker.h" 7 | 8 | @implementation CDLCDylinker 9 | { 10 | struct dylinker_command _dylinkerCommand; 11 | NSString *_name; 12 | } 13 | 14 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 15 | { 16 | if ((self = [super initWithDataCursor:cursor])) { 17 | _dylinkerCommand.cmd = [cursor readInt32]; 18 | _dylinkerCommand.cmdsize = [cursor readInt32]; 19 | 20 | _dylinkerCommand.name.offset = [cursor readInt32]; 21 | 22 | NSUInteger length = _dylinkerCommand.cmdsize - sizeof(_dylinkerCommand); 23 | //NSLog(@"expected length: %u", length); 24 | 25 | _name = [cursor readStringOfLength:length encoding:NSASCIIStringEncoding]; 26 | //NSLog(@"name: %@", name); 27 | } 28 | 29 | return self; 30 | } 31 | 32 | #pragma mark - 33 | 34 | - (uint32_t)cmd; 35 | { 36 | return _dylinkerCommand.cmd; 37 | } 38 | 39 | - (uint32_t)cmdsize; 40 | { 41 | return _dylinkerCommand.cmdsize; 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /CDLCDynamicSymbolTable.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @class CDRelocationInfo; 9 | 10 | @interface CDLCDynamicSymbolTable : CDLoadCommand 11 | 12 | - (void)loadSymbols; 13 | 14 | - (CDRelocationInfo *)relocationEntryWithOffset:(NSUInteger)offset; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /CDLCDynamicSymbolTable.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCDynamicSymbolTable.h" 7 | 8 | #import "CDFatFile.h" 9 | #import "CDMachOFile.h" 10 | #import "CDRelocationInfo.h" 11 | 12 | @implementation CDLCDynamicSymbolTable 13 | { 14 | struct dysymtab_command _dysymtab; 15 | 16 | NSArray *_externalRelocationEntries; 17 | } 18 | 19 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 20 | { 21 | if ((self = [super initWithDataCursor:cursor])) { 22 | _dysymtab.cmd = [cursor readInt32]; 23 | _dysymtab.cmdsize = [cursor readInt32]; 24 | 25 | _dysymtab.ilocalsym = [cursor readInt32]; 26 | _dysymtab.nlocalsym = [cursor readInt32]; 27 | _dysymtab.iextdefsym = [cursor readInt32]; 28 | _dysymtab.nextdefsym = [cursor readInt32]; 29 | _dysymtab.iundefsym = [cursor readInt32]; 30 | _dysymtab.nundefsym = [cursor readInt32]; 31 | _dysymtab.tocoff = [cursor readInt32]; 32 | _dysymtab.ntoc = [cursor readInt32]; 33 | _dysymtab.modtaboff = [cursor readInt32]; 34 | _dysymtab.nmodtab = [cursor readInt32]; 35 | _dysymtab.extrefsymoff = [cursor readInt32]; 36 | _dysymtab.nextrefsyms = [cursor readInt32]; 37 | _dysymtab.indirectsymoff = [cursor readInt32]; 38 | _dysymtab.nindirectsyms = [cursor readInt32]; 39 | _dysymtab.extreloff = [cursor readInt32]; 40 | _dysymtab.nextrel = [cursor readInt32]; 41 | _dysymtab.locreloff = [cursor readInt32]; 42 | _dysymtab.nlocrel = [cursor readInt32]; 43 | #if 0 44 | NSLog(@"ilocalsym: 0x%08x %d", dysymtab.ilocalsym, dysymtab.ilocalsym); 45 | NSLog(@"nlocalsym: 0x%08x %d", dysymtab.nlocalsym, dysymtab.nlocalsym); 46 | NSLog(@"iextdefsym: 0x%08x %d", dysymtab.iextdefsym, dysymtab.iextdefsym); 47 | NSLog(@"nextdefsym: 0x%08x %d", dysymtab.nextdefsym, dysymtab.nextdefsym); 48 | NSLog(@"iundefsym: 0x%08x %d", dysymtab.iundefsym, dysymtab.iundefsym); 49 | NSLog(@"nundefsym: 0x%08x %d", dysymtab.nundefsym, dysymtab.nundefsym); 50 | 51 | NSLog(@"tocoff: 0x%08x %d", dysymtab.tocoff, dysymtab.tocoff); 52 | NSLog(@"ntoc: 0x%08x %d", dysymtab.ntoc, dysymtab.ntoc); 53 | NSLog(@"modtaboff: 0x%08x %d", dysymtab.modtaboff, dysymtab.modtaboff); 54 | NSLog(@"nmodtab: 0x%08x %d", dysymtab.nmodtab, dysymtab.nmodtab); 55 | 56 | NSLog(@"extrefsymoff: 0x%08x %d", dysymtab.extrefsymoff, dysymtab.extrefsymoff); 57 | NSLog(@"nextrefsyms: 0x%08x %d", dysymtab.nextrefsyms, dysymtab.nextrefsyms); 58 | NSLog(@"indirectsymoff: 0x%08x %d", dysymtab.indirectsymoff, dysymtab.indirectsymoff); 59 | NSLog(@"nindirectsyms: 0x%08x %d", dysymtab.nindirectsyms, dysymtab.nindirectsyms); 60 | 61 | NSLog(@"extreloff: 0x%08x %d", dysymtab.extreloff, dysymtab.extreloff); 62 | NSLog(@"nextrel: 0x%08x %d", dysymtab.nextrel, dysymtab.nextrel); 63 | NSLog(@"locreloff: 0x%08x %d", dysymtab.locreloff, dysymtab.locreloff); 64 | NSLog(@"nlocrel: 0x%08x %d", dysymtab.nlocrel, dysymtab.nlocrel); 65 | #endif 66 | 67 | _externalRelocationEntries = [[NSMutableArray alloc] init]; 68 | } 69 | 70 | return self; 71 | } 72 | 73 | #pragma mark - 74 | 75 | - (uint32_t)cmd; 76 | { 77 | return _dysymtab.cmd; 78 | } 79 | 80 | - (uint32_t)cmdsize; 81 | { 82 | return _dysymtab.cmdsize; 83 | } 84 | 85 | - (void)loadSymbols; 86 | { 87 | NSMutableArray *externalRelocationEntries = [[NSMutableArray alloc] init]; 88 | 89 | CDMachOFileDataCursor *cursor = [[CDMachOFileDataCursor alloc] initWithFile:self.machOFile offset:_dysymtab.extreloff]; 90 | 91 | //NSLog(@"indirectsymoff: %lu", dysymtab.indirectsymoff); 92 | //NSLog(@"nindirectsyms: %lu", dysymtab.nindirectsyms); 93 | #if 0 94 | [cursor setOffset:[self.machOFile offset] + dysymtab.indirectsymoff]; 95 | for (uint32_t index = 0; index < dysymtab.nindirectsyms; index++) { 96 | // From loader.h: An indirect symbol table entry is simply a 32bit index into the symbol table to the symbol that the pointer or stub is referring to. 97 | uint32_t val = [cursor readInt32]; 98 | NSLog(@"%3u: %08x (%u)", index, val, val); 99 | } 100 | #endif 101 | 102 | //NSLog(@"extreloff: %lu", dysymtab.extreloff); 103 | //NSLog(@"nextrel: %lu", dysymtab.nextrel); 104 | 105 | //NSLog(@" address val symbolnum pcrel len ext type"); 106 | //NSLog(@"--- -------- -------- --------- ----- --- --- ----"); 107 | for (uint32_t index = 0; index < _dysymtab.nextrel; index++) { 108 | struct relocation_info rinfo; 109 | 110 | rinfo.r_address = [cursor readInt32]; 111 | uint32_t val = [cursor readInt32]; 112 | 113 | rinfo.r_symbolnum = val & 0x00ffffff; 114 | rinfo.r_pcrel = (val & 0x01000000) >> 24; 115 | rinfo.r_length = (val & 0x06000000) >> 25; 116 | rinfo.r_extern = (val & 0x08000000) >> 27; 117 | rinfo.r_type = (val & 0xf0000000) >> 28; 118 | #if 0 119 | NSLog(@"%3d: %08x %08x %08x %01x %01x %01x %01x", index, rinfo.r_address, val, 120 | rinfo.r_symbolnum, rinfo.r_pcrel, rinfo.r_length, rinfo.r_extern, rinfo.r_type); 121 | #endif 122 | 123 | CDRelocationInfo *ri = [[CDRelocationInfo alloc] initWithInfo:rinfo]; 124 | [externalRelocationEntries addObject:ri]; 125 | } 126 | 127 | //NSLog(@"externalRelocationEntries: %@", externalRelocationEntries); 128 | 129 | // r_address is purported to be the offset from the vmaddr of the first segment, but... 130 | // It seems to be from the first segment with r/w initprot. 131 | 132 | // it appears to be the offset from the vmaddr of the 3rd segment in t1s. 133 | // Actually, it really seems to be the offset from the vmaddr of the section indicated in the n_desc part of the nlist. 134 | // 0000000000000000 01 00 0500 0000000000000038 _OBJC_CLASS_$_NSObject 135 | // GET_LIBRARY_ORDINAL() from nlist.h for library. 136 | 137 | _externalRelocationEntries = [externalRelocationEntries copy]; 138 | } 139 | 140 | // Just search for externals. 141 | - (CDRelocationInfo *)relocationEntryWithOffset:(NSUInteger)offset; 142 | { 143 | for (CDRelocationInfo *info in _externalRelocationEntries) { 144 | if (info.isExtern && info.offset == offset) { 145 | return info; 146 | } 147 | } 148 | 149 | return nil; 150 | } 151 | 152 | @end 153 | -------------------------------------------------------------------------------- /CDLCEncryptionInfo.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @interface CDLCEncryptionInfo : CDLoadCommand 9 | 10 | @property (nonatomic, readonly) uint32_t cryptoff; 11 | @property (nonatomic, readonly) uint32_t cryptsize; 12 | @property (nonatomic, readonly) uint32_t cryptid; 13 | 14 | @property (nonatomic, readonly) BOOL isEncrypted; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /CDLCEncryptionInfo.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCEncryptionInfo.h" 7 | 8 | // This is used on iOS. 9 | 10 | @implementation CDLCEncryptionInfo 11 | { 12 | struct encryption_info_command_64 _encryptionInfoCommand; 13 | } 14 | 15 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 16 | { 17 | if ((self = [super initWithDataCursor:cursor])) { 18 | _encryptionInfoCommand.cmd = [cursor readInt32]; 19 | _encryptionInfoCommand.cmdsize = [cursor readInt32]; 20 | 21 | _encryptionInfoCommand.cryptoff = [cursor readInt32]; 22 | _encryptionInfoCommand.cryptsize = [cursor readInt32]; 23 | _encryptionInfoCommand.cryptid = [cursor readInt32]; 24 | if (_encryptionInfoCommand.cmd == LC_ENCRYPTION_INFO_64) { 25 | _encryptionInfoCommand.pad = [cursor readInt32]; 26 | } 27 | } 28 | 29 | return self; 30 | } 31 | 32 | #pragma mark - 33 | 34 | - (uint32_t)cmd; 35 | { 36 | return _encryptionInfoCommand.cmd; 37 | } 38 | 39 | - (uint32_t)cmdsize; 40 | { 41 | return _encryptionInfoCommand.cmdsize; 42 | } 43 | 44 | - (uint32_t)cryptoff; 45 | { 46 | return _encryptionInfoCommand.cryptoff; 47 | } 48 | 49 | - (uint32_t)cryptsize; 50 | { 51 | return _encryptionInfoCommand.cryptsize; 52 | } 53 | 54 | - (uint32_t)cryptid; 55 | { 56 | return _encryptionInfoCommand.cryptid; 57 | } 58 | 59 | - (BOOL)isEncrypted; 60 | { 61 | return _encryptionInfoCommand.cryptid != 0; 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /CDLCFunctionStarts.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCLinkeditData.h" 7 | 8 | @interface CDLCFunctionStarts : CDLCLinkeditData 9 | 10 | @property (nonatomic, readonly) NSArray *functionStarts; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /CDLCFunctionStarts.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCFunctionStarts.h" 7 | 8 | #import "ULEB128.h" 9 | 10 | @implementation CDLCFunctionStarts 11 | { 12 | NSArray *_functionStarts; 13 | } 14 | 15 | #pragma mark - 16 | 17 | - (NSArray *)functionStarts; 18 | { 19 | if (_functionStarts == nil) { 20 | NSData *functionStartsData = [self linkeditData]; 21 | const uint8_t *start = (uint8_t *)[functionStartsData bytes]; 22 | const uint8_t *end = start + [functionStartsData length]; 23 | uint64_t startAddress; 24 | uint64_t previousAddress = 0; 25 | NSMutableArray *functionStarts = [[NSMutableArray alloc] init]; 26 | while ((startAddress = read_uleb128(&start, end))) { 27 | [functionStarts addObject:@(startAddress + previousAddress)]; 28 | previousAddress += startAddress; 29 | } 30 | _functionStarts = [functionStarts copy]; 31 | } 32 | return _functionStarts; 33 | } 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /CDLCLinkeditData.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @interface CDLCLinkeditData : CDLoadCommand 9 | 10 | @property (nonatomic, readonly) NSData *linkeditData; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /CDLCLinkeditData.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCLinkeditData.h" 7 | 8 | #import "CDMachOFile.h" 9 | 10 | @implementation CDLCLinkeditData 11 | { 12 | struct linkedit_data_command _linkeditDataCommand; 13 | NSData *_linkeditData; 14 | } 15 | 16 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 17 | { 18 | if ((self = [super initWithDataCursor:cursor])) { 19 | _linkeditDataCommand.cmd = [cursor readInt32]; 20 | _linkeditDataCommand.cmdsize = [cursor readInt32]; 21 | 22 | _linkeditDataCommand.dataoff = [cursor readInt32]; 23 | _linkeditDataCommand.datasize = [cursor readInt32]; 24 | } 25 | 26 | return self; 27 | } 28 | 29 | #pragma mark - 30 | 31 | - (uint32_t)cmd; 32 | { 33 | return _linkeditDataCommand.cmd; 34 | } 35 | 36 | - (uint32_t)cmdsize; 37 | { 38 | return _linkeditDataCommand.cmdsize; 39 | } 40 | 41 | - (NSData *)linkeditData; 42 | { 43 | if (_linkeditData == NULL) { 44 | _linkeditData = [[NSData alloc] initWithBytes:[self.machOFile bytesAtOffset:_linkeditDataCommand.dataoff] length:_linkeditDataCommand.datasize]; 45 | } 46 | 47 | return _linkeditData; 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /CDLCMain.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @interface CDLCMain : CDLoadCommand 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /CDLCMain.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCMain.h" 7 | 8 | @implementation CDLCMain 9 | { 10 | struct entry_point_command _entryPointCommand; 11 | } 12 | 13 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 14 | { 15 | if ((self = [super initWithDataCursor:cursor])) { 16 | _entryPointCommand.cmd = [cursor readInt32]; 17 | _entryPointCommand.cmdsize = [cursor readInt32]; 18 | _entryPointCommand.entryoff = [cursor readInt64]; 19 | _entryPointCommand.stacksize = [cursor readInt64]; 20 | } 21 | 22 | return self; 23 | } 24 | 25 | #pragma mark - 26 | 27 | - (uint32_t)cmd; 28 | { 29 | return _entryPointCommand.cmd; 30 | } 31 | 32 | - (uint32_t)cmdsize; 33 | { 34 | return _entryPointCommand.cmdsize; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /CDLCPrebindChecksum.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @interface CDLCPrebindChecksum : CDLoadCommand 9 | 10 | @property (nonatomic, readonly) uint32_t cksum; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /CDLCPrebindChecksum.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCPrebindChecksum.h" 7 | 8 | @implementation CDLCPrebindChecksum 9 | { 10 | struct prebind_cksum_command _prebindChecksumCommand; 11 | } 12 | 13 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 14 | { 15 | if ((self = [super initWithDataCursor:cursor])) { 16 | _prebindChecksumCommand.cmd = [cursor readInt32]; 17 | _prebindChecksumCommand.cmdsize = [cursor readInt32]; 18 | _prebindChecksumCommand.cksum = [cursor readInt32]; 19 | } 20 | 21 | return self; 22 | } 23 | 24 | #pragma mark - 25 | 26 | - (uint32_t)cmd; 27 | { 28 | return _prebindChecksumCommand.cmd; 29 | } 30 | 31 | - (uint32_t)cmdsize; 32 | { 33 | return _prebindChecksumCommand.cmdsize; 34 | } 35 | 36 | - (uint32_t)cksum; 37 | { 38 | return _prebindChecksumCommand.cksum; 39 | } 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /CDLCPreboundDylib.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @interface CDLCPreboundDylib : CDLoadCommand 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /CDLCPreboundDylib.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCPreboundDylib.h" 7 | 8 | #import "CDFatFile.h" 9 | #import "CDMachOFile.h" 10 | 11 | @implementation CDLCPreboundDylib 12 | { 13 | struct prebound_dylib_command _preboundDylibCommand; 14 | } 15 | 16 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 17 | { 18 | if ((self = [super initWithDataCursor:cursor])) { 19 | //NSLog(@"current offset: %u", [cursor offset]); 20 | _preboundDylibCommand.cmd = [cursor readInt32]; 21 | _preboundDylibCommand.cmdsize = [cursor readInt32]; 22 | //NSLog(@"cmdsize: %u", preboundDylibCommand.cmdsize); 23 | 24 | _preboundDylibCommand.name.offset = [cursor readInt32]; 25 | _preboundDylibCommand.nmodules = [cursor readInt32]; 26 | _preboundDylibCommand.linked_modules.offset = [cursor readInt32]; 27 | 28 | if (_preboundDylibCommand.cmdsize > 20) { 29 | // Don't need this info right now. 30 | [cursor advanceByLength:_preboundDylibCommand.cmdsize - 20]; 31 | } 32 | } 33 | 34 | return self; 35 | } 36 | 37 | #pragma mark - 38 | 39 | - (uint32_t)cmd; 40 | { 41 | return _preboundDylibCommand.cmd; 42 | } 43 | 44 | - (uint32_t)cmdsize; 45 | { 46 | return _preboundDylibCommand.cmdsize; 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /CDLCRoutines32.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @interface CDLCRoutines32 : CDLoadCommand 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /CDLCRoutines32.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCRoutines32.h" 7 | 8 | @implementation CDLCRoutines32 9 | { 10 | struct routines_command _routinesCommand; 11 | } 12 | 13 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 14 | { 15 | if ((self = [super initWithDataCursor:cursor])) { 16 | _routinesCommand.cmd = [cursor readInt32]; 17 | _routinesCommand.cmdsize = [cursor readInt32]; 18 | 19 | _routinesCommand.init_address = [cursor readInt32]; 20 | _routinesCommand.init_module = [cursor readInt32]; 21 | _routinesCommand.reserved1 = [cursor readInt32]; 22 | _routinesCommand.reserved2 = [cursor readInt32]; 23 | _routinesCommand.reserved3 = [cursor readInt32]; 24 | _routinesCommand.reserved4 = [cursor readInt32]; 25 | _routinesCommand.reserved5 = [cursor readInt32]; 26 | _routinesCommand.reserved6 = [cursor readInt32]; 27 | } 28 | 29 | return self; 30 | } 31 | 32 | #pragma mark - 33 | 34 | - (uint32_t)cmd; 35 | { 36 | return _routinesCommand.cmd; 37 | } 38 | 39 | - (uint32_t)cmdsize; 40 | { 41 | return _routinesCommand.cmdsize; 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /CDLCRoutines64.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @interface CDLCRoutines64 : CDLoadCommand 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /CDLCRoutines64.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCRoutines64.h" 7 | 8 | @implementation CDLCRoutines64 9 | { 10 | struct routines_command_64 _routinesCommand; 11 | } 12 | 13 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 14 | { 15 | if ((self = [super initWithDataCursor:cursor])) { 16 | _routinesCommand.cmd = [cursor readInt32]; 17 | _routinesCommand.cmdsize = [cursor readInt32]; 18 | 19 | _routinesCommand.init_address = [cursor readInt64]; 20 | _routinesCommand.init_module = [cursor readInt64]; 21 | _routinesCommand.reserved1 = [cursor readInt64]; 22 | _routinesCommand.reserved2 = [cursor readInt64]; 23 | _routinesCommand.reserved3 = [cursor readInt64]; 24 | _routinesCommand.reserved4 = [cursor readInt64]; 25 | _routinesCommand.reserved5 = [cursor readInt64]; 26 | _routinesCommand.reserved6 = [cursor readInt64]; 27 | } 28 | 29 | return self; 30 | } 31 | 32 | #pragma mark - 33 | 34 | - (uint32_t)cmd; 35 | { 36 | return _routinesCommand.cmd; 37 | } 38 | 39 | - (uint32_t)cmdsize; 40 | { 41 | return _routinesCommand.cmdsize; 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /CDLCRunPath.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @interface CDLCRunPath : CDLoadCommand 9 | 10 | @property (readonly) NSString *path; 11 | @property (nonatomic, readonly) NSString *resolvedRunPath; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CDLCRunPath.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCRunPath.h" 7 | 8 | #import "CDMachOFile.h" 9 | #import "CDSearchPathState.h" 10 | 11 | @implementation CDLCRunPath 12 | { 13 | struct rpath_command _rpathCommand; 14 | NSString *_path; 15 | } 16 | 17 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 18 | { 19 | if ((self = [super initWithDataCursor:cursor])) { 20 | _rpathCommand.cmd = [cursor readInt32]; 21 | _rpathCommand.cmdsize = [cursor readInt32]; 22 | 23 | _rpathCommand.path.offset = [cursor readInt32]; 24 | 25 | NSUInteger length = _rpathCommand.cmdsize - sizeof(_rpathCommand); 26 | //NSLog(@"expected length: %u", length); 27 | 28 | _path = [cursor readStringOfLength:length encoding:NSASCIIStringEncoding]; 29 | //NSLog(@"path: %@", _path); 30 | } 31 | 32 | return self; 33 | } 34 | 35 | #pragma mark - 36 | 37 | - (uint32_t)cmd; 38 | { 39 | return _rpathCommand.cmd; 40 | } 41 | 42 | - (uint32_t)cmdsize; 43 | { 44 | return _rpathCommand.cmdsize; 45 | } 46 | 47 | - (NSString *)resolvedRunPath; 48 | { 49 | NSString *loaderPathPrefix = @"@loader_path"; 50 | NSString *executablePathPrefix = @"@executable_path"; 51 | 52 | if ([self.path hasPrefix:loaderPathPrefix]) { 53 | NSString *loaderPath = [self.machOFile.filename stringByDeletingLastPathComponent]; 54 | NSString *str = [[self.path stringByReplacingOccurrencesOfString:loaderPathPrefix withString:loaderPath] stringByStandardizingPath]; 55 | 56 | return str; 57 | } 58 | 59 | if ([self.path hasPrefix:executablePathPrefix]) { 60 | NSString *str = @""; 61 | NSString *executablePath = self.machOFile.searchPathState.executablePath; 62 | if (executablePath) 63 | str = [[self.path stringByReplacingOccurrencesOfString:executablePathPrefix withString:executablePath] stringByStandardizingPath]; 64 | 65 | return str; 66 | } 67 | 68 | return self.path; 69 | } 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /CDLCSegment.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @class CDSection; 9 | 10 | #define CDSegmentProtectedMagic_None 0 11 | #define CDSegmentProtectedMagic_AES 0xc2286295 12 | #define CDSegmentProtectedMagic_Blowfish 0x2e69cf40 13 | 14 | typedef enum : NSUInteger { 15 | CDSegmentEncryptionType_None = 0, 16 | CDSegmentEncryptionType_AES = 1, // 10.5 and earlier (AES) 17 | CDSegmentEncryptionType_Blowfish = 2, // 10.6 (Blowfish) 18 | CDSegmentEncryptionType_Unknown 19 | } CDSegmentEncryptionType; 20 | 21 | extern NSString *CDSegmentEncryptionTypeName(CDSegmentEncryptionType type); 22 | 23 | @interface CDLCSegment : CDLoadCommand 24 | 25 | @property (strong) NSString *name; 26 | @property (strong) NSArray *sections; 27 | 28 | @property (nonatomic, readonly) NSUInteger vmaddr; 29 | @property (nonatomic, readonly) NSUInteger fileoff; 30 | @property (nonatomic, readonly) NSUInteger filesize; 31 | @property (nonatomic, readonly) vm_prot_t initprot; 32 | @property (nonatomic, readonly) uint32_t flags; 33 | @property (nonatomic, readonly) BOOL isProtected; 34 | 35 | @property (nonatomic, readonly) CDSegmentEncryptionType encryptionType; 36 | @property (nonatomic, readonly) BOOL canDecrypt; 37 | 38 | - (NSString *)flagDescription; 39 | 40 | - (BOOL)containsAddress:(NSUInteger)address; 41 | - (CDSection *)sectionContainingAddress:(NSUInteger)address; 42 | - (CDSection *)sectionWithName:(NSString *)name; 43 | - (NSUInteger)fileOffsetForAddress:(NSUInteger)address; 44 | - (NSUInteger)segmentOffsetForAddress:(NSUInteger)address; 45 | 46 | - (void)writeSectionData; 47 | 48 | - (NSData *)decryptedData; 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /CDLCSourceVersion.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @interface CDLCSourceVersion : CDLoadCommand 9 | 10 | @property (nonatomic, readonly) NSString *sourceVersionString; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /CDLCSourceVersion.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCSourceVersion.h" 7 | 8 | #import "CDMachOFile.h" 9 | 10 | @implementation CDLCSourceVersion 11 | { 12 | struct source_version_command _sourceVersionCommand; 13 | } 14 | 15 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 16 | { 17 | if ((self = [super initWithDataCursor:cursor])) { 18 | _sourceVersionCommand.cmd = [cursor readInt32]; 19 | _sourceVersionCommand.cmdsize = [cursor readInt32]; 20 | _sourceVersionCommand.version = [cursor readInt64]; 21 | } 22 | 23 | return self; 24 | } 25 | 26 | #pragma mark - 27 | 28 | - (uint32_t)cmd; 29 | { 30 | return _sourceVersionCommand.cmd; 31 | } 32 | 33 | - (uint32_t)cmdsize; 34 | { 35 | return _sourceVersionCommand.cmdsize; 36 | } 37 | 38 | - (NSString *)sourceVersionString; 39 | { 40 | // A.B.C.D.E packed as a24.b10.c10.d10.e10 41 | uint32_t a = _sourceVersionCommand.version >> 40; 42 | uint32_t b = (_sourceVersionCommand.version >> 30) & 0x3ff; 43 | uint32_t c = (_sourceVersionCommand.version >> 20) & 0x3ff; 44 | uint32_t d = (_sourceVersionCommand.version >> 10) & 0x3ff; 45 | uint32_t e = _sourceVersionCommand.version & 0x3ff; 46 | 47 | return [NSString stringWithFormat:@"%u.%u.%u.%u.%u", a, b, c, d, e]; 48 | } 49 | 50 | - (void)appendToString:(NSMutableString *)resultString verbose:(BOOL)isVerbose; 51 | { 52 | [super appendToString:resultString verbose:isVerbose]; 53 | 54 | [resultString appendFormat:@" Source version: %@\n", self.sourceVersionString]; 55 | } 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /CDLCSubClient.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @interface CDLCSubClient : CDLoadCommand 9 | 10 | @property (readonly) NSString *name; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /CDLCSubClient.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCSubClient.h" 7 | 8 | @implementation CDLCSubClient 9 | { 10 | struct sub_client_command _command; 11 | NSString *_name; 12 | } 13 | 14 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 15 | { 16 | if ((self = [super initWithDataCursor:cursor])) { 17 | _command.cmd = [cursor readInt32]; 18 | _command.cmdsize = [cursor readInt32]; 19 | 20 | uint32_t strOffset = [cursor readInt32]; 21 | NSParameterAssert(strOffset == 12); 22 | 23 | NSUInteger length = _command.cmdsize - sizeof(_command); 24 | //NSLog(@"expected length: %u", length); 25 | 26 | _name = [cursor readStringOfLength:length encoding:NSASCIIStringEncoding]; 27 | //NSLog(@"name: %@", _name); 28 | } 29 | 30 | return self; 31 | } 32 | 33 | #pragma mark - 34 | 35 | - (uint32_t)cmd; 36 | { 37 | return _command.cmd; 38 | } 39 | 40 | - (uint32_t)cmdsize; 41 | { 42 | return _command.cmdsize; 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /CDLCSubFramework.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @interface CDLCSubFramework : CDLoadCommand 9 | 10 | @property (readonly) NSString *name; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /CDLCSubFramework.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCSubFramework.h" 7 | 8 | @implementation CDLCSubFramework 9 | { 10 | struct sub_framework_command _command; 11 | NSString *_name; 12 | } 13 | 14 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 15 | { 16 | if ((self = [super initWithDataCursor:cursor])) { 17 | _command.cmd = [cursor readInt32]; 18 | _command.cmdsize = [cursor readInt32]; 19 | 20 | uint32_t strOffset = [cursor readInt32]; 21 | NSParameterAssert(strOffset == 12); 22 | 23 | NSUInteger length = _command.cmdsize - sizeof(_command); 24 | //NSLog(@"expected length: %u", length); 25 | 26 | _name = [cursor readStringOfLength:length encoding:NSASCIIStringEncoding]; 27 | //NSLog(@"name: %@", _name); 28 | } 29 | 30 | return self; 31 | } 32 | 33 | #pragma mark - 34 | 35 | - (uint32_t)cmd; 36 | { 37 | return _command.cmd; 38 | } 39 | 40 | - (uint32_t)cmdsize; 41 | { 42 | return _command.cmdsize; 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /CDLCSubLibrary.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @interface CDLCSubLibrary : CDLoadCommand 9 | 10 | @property (readonly) NSString *name; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /CDLCSubLibrary.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCSubLibrary.h" 7 | 8 | @implementation CDLCSubLibrary 9 | { 10 | struct sub_library_command _command; 11 | NSString *_name; 12 | } 13 | 14 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 15 | { 16 | if ((self = [super initWithDataCursor:cursor])) { 17 | _command.cmd = [cursor readInt32]; 18 | _command.cmdsize = [cursor readInt32]; 19 | 20 | NSUInteger length = _command.cmdsize - sizeof(_command); 21 | //NSLog(@"expected length: %u", length); 22 | 23 | _name = [cursor readStringOfLength:length encoding:NSASCIIStringEncoding]; 24 | //NSLog(@"name: %@", _name); 25 | } 26 | 27 | return self; 28 | } 29 | 30 | #pragma mark - 31 | 32 | - (uint32_t)cmd; 33 | { 34 | return _command.cmd; 35 | } 36 | 37 | - (uint32_t)cmdsize; 38 | { 39 | return _command.cmdsize; 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /CDLCSubUmbrella.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @interface CDLCSubUmbrella : CDLoadCommand 9 | 10 | @property (readonly) NSString *name; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /CDLCSubUmbrella.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCSubUmbrella.h" 7 | 8 | @implementation CDLCSubUmbrella 9 | { 10 | struct sub_umbrella_command _command; 11 | NSString *_name; 12 | } 13 | 14 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 15 | { 16 | if ((self = [super initWithDataCursor:cursor])) { 17 | _command.cmd = [cursor readInt32]; 18 | _command.cmdsize = [cursor readInt32]; 19 | 20 | NSUInteger length = _command.cmdsize - sizeof(_command); 21 | //NSLog(@"expected length: %u", length); 22 | 23 | _name = [cursor readStringOfLength:length encoding:NSASCIIStringEncoding]; 24 | //NSLog(@"name: %@", _name); 25 | } 26 | 27 | return self; 28 | } 29 | 30 | #pragma mark - 31 | 32 | - (uint32_t)cmd; 33 | { 34 | return _command.cmd; 35 | } 36 | 37 | - (uint32_t)cmdsize; 38 | { 39 | return _command.cmdsize; 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /CDLCSymbolTable.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @class CDSymbol; 9 | 10 | @interface CDLCSymbolTable : CDLoadCommand 11 | 12 | - (void)loadSymbols; 13 | 14 | @property (nonatomic, readonly) uint32_t symoff; 15 | @property (nonatomic, readonly) uint32_t nsyms; 16 | @property (nonatomic, readonly) uint32_t stroff; 17 | @property (nonatomic, readonly) uint32_t strsize; 18 | 19 | @property (nonatomic, readonly) NSUInteger baseAddress; 20 | @property (nonatomic, readonly) NSArray *symbols; 21 | 22 | - (CDSymbol *)symbolForClassName:(NSString *)className; 23 | - (CDSymbol *)symbolForExternalClassName:(NSString *)className; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /CDLCTwoLevelHints.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @interface CDLCTwoLevelHints : CDLoadCommand 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /CDLCTwoLevelHints.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCTwoLevelHints.h" 7 | 8 | #import "CDMachOFile.h" 9 | 10 | @implementation CDLCTwoLevelHints 11 | { 12 | struct twolevel_hints_command _hintsCommand; 13 | } 14 | 15 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 16 | { 17 | if ((self = [super initWithDataCursor:cursor])) { 18 | _hintsCommand.cmd = [cursor readInt32]; 19 | _hintsCommand.cmdsize = [cursor readInt32]; 20 | _hintsCommand.offset = [cursor readInt32]; 21 | _hintsCommand.nhints = [cursor readInt32]; 22 | } 23 | 24 | return self; 25 | } 26 | 27 | #pragma mark - 28 | 29 | - (uint32_t)cmd; 30 | { 31 | return _hintsCommand.cmd; 32 | } 33 | 34 | - (uint32_t)cmdsize; 35 | { 36 | return _hintsCommand.cmdsize; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /CDLCUUID.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @interface CDLCUUID : CDLoadCommand 9 | 10 | @property (nonatomic, readonly) NSUUID *UUID; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /CDLCUUID.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCUUID.h" 7 | 8 | #import "CDMachOFile.h" 9 | 10 | @implementation CDLCUUID 11 | { 12 | struct uuid_command _uuidCommand; 13 | 14 | NSUUID *_UUID; 15 | } 16 | 17 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 18 | { 19 | if ((self = [super initWithDataCursor:cursor])) { 20 | _uuidCommand.cmd = [cursor readInt32]; 21 | _uuidCommand.cmdsize = [cursor readInt32]; 22 | for (NSUInteger index = 0; index < sizeof(_uuidCommand.uuid); index++) { 23 | _uuidCommand.uuid[index] = [cursor readByte]; 24 | } 25 | _UUID = [[NSUUID alloc] initWithUUIDBytes:_uuidCommand.uuid]; 26 | } 27 | 28 | return self; 29 | } 30 | 31 | #pragma mark - 32 | 33 | - (uint32_t)cmd; 34 | { 35 | return _uuidCommand.cmd; 36 | } 37 | 38 | - (uint32_t)cmdsize; 39 | { 40 | return _uuidCommand.cmdsize; 41 | } 42 | 43 | - (void)appendToString:(NSMutableString *)resultString verbose:(BOOL)isVerbose; 44 | { 45 | [super appendToString:resultString verbose:isVerbose]; 46 | 47 | [resultString appendString:@" uuid "]; 48 | [resultString appendString:[self.UUID UUIDString]]; 49 | [resultString appendString:@"\n"]; 50 | } 51 | 52 | - (NSString *)extraDescription; 53 | { 54 | return [self.UUID UUIDString]; 55 | } 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /CDLCUnixThread.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @interface CDLCUnixThread : CDLoadCommand 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /CDLCUnixThread.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCUnixThread.h" 7 | 8 | // For now, this is all I need. There is no data in here sensitive to its position in the file. 9 | 10 | @implementation CDLCUnixThread 11 | { 12 | struct load_command _loadCommand; 13 | 14 | NSData *_commandData; 15 | } 16 | 17 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 18 | { 19 | if ((self = [super initWithDataCursor:cursor])) { 20 | _loadCommand.cmd = [cursor readInt32]; 21 | _loadCommand.cmdsize = [cursor readInt32]; 22 | 23 | if (_loadCommand.cmdsize > 8) { 24 | NSMutableData *commandData = [[NSMutableData alloc] init]; 25 | [cursor appendBytesOfLength:_loadCommand.cmdsize - 8 intoData:commandData]; 26 | _commandData = [commandData copy]; 27 | } else { 28 | _commandData = nil; 29 | } 30 | } 31 | 32 | return self; 33 | } 34 | 35 | #pragma mark - 36 | 37 | - (uint32_t)cmd; 38 | { 39 | return _loadCommand.cmd; 40 | } 41 | 42 | - (uint32_t)cmdsize; 43 | { 44 | return _loadCommand.cmdsize; 45 | } 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /CDLCUnknown.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @interface CDLCUnknown : CDLoadCommand 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /CDLCUnknown.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCUnknown.h" 7 | 8 | static BOOL debug = NO; 9 | 10 | @implementation CDLCUnknown 11 | { 12 | struct load_command _loadCommand; 13 | 14 | NSData *_commandData; 15 | } 16 | 17 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 18 | { 19 | if ((self = [super initWithDataCursor:cursor])) { 20 | if (debug) NSLog(@"offset: %lu", [cursor offset]); 21 | _loadCommand.cmd = [cursor readInt32]; 22 | _loadCommand.cmdsize = [cursor readInt32]; 23 | if (debug) NSLog(@"cmdsize: %u", _loadCommand.cmdsize); 24 | 25 | if (_loadCommand.cmdsize > 8) { 26 | NSMutableData *commandData = [[NSMutableData alloc] init]; 27 | [cursor appendBytesOfLength:_loadCommand.cmdsize - 8 intoData:commandData]; 28 | _commandData = [commandData copy]; 29 | } else { 30 | _commandData = nil; 31 | } 32 | } 33 | 34 | return self; 35 | } 36 | 37 | #pragma mark - 38 | 39 | - (uint32_t)cmd; 40 | { 41 | return _loadCommand.cmd; 42 | } 43 | 44 | - (uint32_t)cmdsize; 45 | { 46 | return _loadCommand.cmdsize; 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /CDLCVersionMinimum.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLoadCommand.h" 7 | 8 | @interface CDLCVersionMinimum : CDLoadCommand 9 | 10 | @property (nonatomic, readonly) NSString *minimumVersionString; 11 | @property (nonatomic, readonly) NSString *SDKVersionString; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CDLCVersionMinimum.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDLCVersionMinimum.h" 7 | 8 | #import "CDMachOFile.h" 9 | 10 | @implementation CDLCVersionMinimum 11 | { 12 | struct version_min_command _versionMinCommand; 13 | } 14 | 15 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 16 | { 17 | if ((self = [super initWithDataCursor:cursor])) { 18 | _versionMinCommand.cmd = [cursor readInt32]; 19 | _versionMinCommand.cmdsize = [cursor readInt32]; 20 | _versionMinCommand.version = [cursor readInt32]; 21 | _versionMinCommand.sdk = [cursor readInt32]; 22 | } 23 | 24 | return self; 25 | } 26 | 27 | #pragma mark - 28 | 29 | - (uint32_t)cmd; 30 | { 31 | return _versionMinCommand.cmd; 32 | } 33 | 34 | - (uint32_t)cmdsize; 35 | { 36 | return _versionMinCommand.cmdsize; 37 | } 38 | 39 | - (NSString *)minimumVersionString; 40 | { 41 | uint32_t x = (_versionMinCommand.version >> 16); 42 | uint32_t y = (_versionMinCommand.version >> 8) & 0xff; 43 | uint32_t z = _versionMinCommand.version & 0xff; 44 | 45 | return [NSString stringWithFormat:@"%u.%u.%u", x, y, z]; 46 | } 47 | 48 | - (NSString *)SDKVersionString; 49 | { 50 | uint32_t x = (_versionMinCommand.sdk >> 16); 51 | uint32_t y = (_versionMinCommand.sdk >> 8) & 0xff; 52 | uint32_t z = _versionMinCommand.sdk & 0xff; 53 | 54 | return [NSString stringWithFormat:@"%u.%u.%u", x, y, z]; 55 | } 56 | 57 | - (void)appendToString:(NSMutableString *)resultString verbose:(BOOL)isVerbose; 58 | { 59 | [super appendToString:resultString verbose:isVerbose]; 60 | 61 | [resultString appendFormat:@" Minimum version: %@\n", self.minimumVersionString]; 62 | [resultString appendFormat:@" SDK version: %@\n", self.SDKVersionString]; 63 | } 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /CDLoadCommand.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | // Importing these here saves us from importing them in the implementation of every load command. 7 | #include 8 | #import "CDMachOFileDataCursor.h" 9 | 10 | @class CDMachOFile; 11 | 12 | @interface CDLoadCommand : NSObject 13 | 14 | + (id)loadCommandWithDataCursor:(CDMachOFileDataCursor *)cursor; 15 | 16 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; 17 | 18 | - (NSString *)extraDescription; 19 | 20 | @property (weak, readonly) CDMachOFile *machOFile; 21 | @property (readonly) NSUInteger commandOffset; 22 | 23 | @property (nonatomic, readonly) uint32_t cmd; 24 | @property (nonatomic, readonly) uint32_t cmdsize; 25 | @property (nonatomic, readonly) BOOL mustUnderstandToExecute; 26 | 27 | @property (nonatomic, readonly) NSString *commandName; 28 | 29 | - (void)appendToString:(NSMutableString *)resultString verbose:(BOOL)isVerbose; 30 | 31 | - (void)machOFileDidReadLoadCommands:(CDMachOFile *)machOFile; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /CDMachOFile.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDFile.h" 7 | 8 | #include // For cpu_type_t, cpu_subtype_t 9 | #include 10 | 11 | typedef enum : NSUInteger { 12 | CDByteOrder_LittleEndian = 0, 13 | CDByteOrder_BigEndian = 1, 14 | } CDByteOrder; 15 | 16 | @class CDLCSegment; 17 | @class CDLCBuildVersion, CDLCDyldInfo, CDLCDylib, CDMachOFile, CDLCSymbolTable, CDLCDynamicSymbolTable, CDLCVersionMinimum, CDLCSourceVersion; 18 | 19 | @interface CDMachOFile : CDFile 20 | 21 | @property (readonly) CDByteOrder byteOrder; 22 | 23 | @property (readonly) uint32_t magic; 24 | @property (assign) cpu_type_t cputype; 25 | @property (assign) cpu_subtype_t cpusubtype; 26 | @property (readonly) uint32_t filetype; 27 | @property (readonly) uint32_t flags; 28 | 29 | @property (nonatomic, readonly) cpu_type_t maskedCPUType; 30 | @property (nonatomic, readonly) cpu_subtype_t maskedCPUSubtype; 31 | 32 | @property (readonly) NSArray *loadCommands; 33 | @property (readonly) NSArray *dylibLoadCommands; 34 | @property (readonly) NSArray *segments; 35 | @property (readonly) NSArray *runPaths; 36 | @property (readonly) NSArray *runPathCommands; 37 | @property (readonly) NSArray *dyldEnvironment; 38 | @property (readonly) NSArray *reExportedDylibs; 39 | 40 | @property (strong) CDLCSymbolTable *symbolTable; 41 | @property (strong) CDLCDynamicSymbolTable *dynamicSymbolTable; 42 | @property (strong) CDLCDyldInfo *dyldInfo; 43 | @property (strong) CDLCDylib *dylibIdentifier; 44 | @property (strong) CDLCVersionMinimum *minVersionMacOSX; 45 | @property (strong) CDLCVersionMinimum *minVersionIOS; 46 | @property (strong) CDLCSourceVersion *sourceVersion; 47 | @property (strong) CDLCBuildVersion *buildVersion; 48 | 49 | @property (readonly) BOOL uses64BitABI; 50 | - (NSUInteger)ptrSize; 51 | 52 | - (NSString *)filetypeDescription; 53 | - (NSString *)flagDescription; 54 | 55 | - (CDLCSegment *)dataConstSegment; 56 | - (CDLCSegment *)segmentWithName:(NSString *)segmentName; 57 | - (CDLCSegment *)segmentContainingAddress:(NSUInteger)address; 58 | - (NSString *)stringAtAddress:(NSUInteger)address; 59 | 60 | - (NSUInteger)dataOffsetForAddress:(NSUInteger)address; 61 | 62 | - (const void *)bytes; 63 | - (const void *)bytesAtOffset:(NSUInteger)offset; 64 | 65 | @property (nonatomic, readonly) NSString *importBaseName; 66 | 67 | @property (nonatomic, readonly) BOOL isEncrypted; 68 | @property (nonatomic, readonly) BOOL hasProtectedSegments; 69 | @property (nonatomic, readonly) BOOL canDecryptAllSegments; 70 | 71 | - (NSString *)loadCommandString:(BOOL)isVerbose; 72 | - (NSString *)headerString:(BOOL)isVerbose; 73 | 74 | @property (nonatomic, readonly) NSUUID *UUID; 75 | @property (nonatomic, readonly) NSString *archName; 76 | 77 | - (Class)processorClass; 78 | - (void)logInfoForAddress:(NSUInteger)address; 79 | 80 | - (NSString *)externalClassNameForAddress:(NSUInteger)address; 81 | - (BOOL)hasRelocationEntryForAddress:(NSUInteger)address; 82 | 83 | // Checks compressed dyld info on 10.6 or later. 84 | - (BOOL)hasRelocationEntryForAddress2:(NSUInteger)address; 85 | - (NSString *)externalClassNameForAddress2:(NSUInteger)address; 86 | 87 | - (CDLCDylib *)dylibLoadCommandForLibraryOrdinal:(NSUInteger)ordinal; 88 | 89 | @property (nonatomic, readonly) BOOL hasObjectiveC1Data; 90 | @property (nonatomic, readonly) BOOL hasObjectiveC2Data; 91 | @property (nonatomic, readonly) Class processorClass; 92 | 93 | @end 94 | -------------------------------------------------------------------------------- /CDMachOFileDataCursor.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDDataCursor.h" 7 | 8 | @class CDMachOFile, CDSection; 9 | 10 | @interface CDMachOFileDataCursor : CDDataCursor 11 | 12 | - (id)initWithFile:(CDMachOFile *)machOFile; 13 | - (id)initWithFile:(CDMachOFile *)machOFile offset:(NSUInteger)offset; 14 | - (id)initWithFile:(CDMachOFile *)machOFile address:(NSUInteger)address; 15 | 16 | - (id)initWithSection:(CDSection *)section; 17 | 18 | @property (nonatomic, weak, readonly) CDMachOFile *machOFile; 19 | 20 | - (void)setAddress:(NSUInteger)address; 21 | 22 | // Read using the current byteOrder 23 | - (uint16_t)readInt16; 24 | - (uint32_t)readInt32; 25 | - (uint64_t)readInt64; 26 | 27 | - (uint32_t)peekInt32; 28 | 29 | // Read using the current byteOrder and ptrSize (from the machOFile) 30 | - (uint64_t)readPtr; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /CDMachOFileDataCursor.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDMachOFileDataCursor.h" 7 | 8 | #import "CDMachOFile.h" 9 | #import "CDLCSegment.h" 10 | #import "CDSection.h" 11 | 12 | @implementation CDMachOFileDataCursor 13 | { 14 | __weak CDMachOFile *_machOFile; 15 | NSUInteger _ptrSize; 16 | CDByteOrder _byteOrder; 17 | } 18 | 19 | - (id)initWithFile:(CDMachOFile *)machOFile; 20 | { 21 | return [self initWithFile:machOFile offset:0]; 22 | } 23 | 24 | - (id)initWithFile:(CDMachOFile *)machOFile offset:(NSUInteger)offset; 25 | { 26 | if ((self = [super initWithData:machOFile.data])) { 27 | self.machOFile = machOFile; 28 | [self setOffset:offset]; 29 | } 30 | 31 | return self; 32 | } 33 | 34 | - (id)initWithFile:(CDMachOFile *)machOFile address:(NSUInteger)address; 35 | { 36 | if ((self = [super initWithData:machOFile.data])) { 37 | self.machOFile = machOFile; 38 | [self setAddress:address]; 39 | } 40 | 41 | return self; 42 | } 43 | 44 | - (id)initWithSection:(CDSection *)section; 45 | { 46 | if ((self = [super initWithData:[section data]])) { 47 | self.machOFile = section.segment.machOFile; 48 | } 49 | 50 | return self; 51 | } 52 | 53 | #pragma mark - 54 | 55 | - (void)setMachOFile:(CDMachOFile *)machOFile; 56 | { 57 | _machOFile = machOFile; 58 | _ptrSize = machOFile.ptrSize; 59 | _byteOrder = machOFile.byteOrder; 60 | } 61 | 62 | - (void)setAddress:(NSUInteger)address; 63 | { 64 | NSUInteger dataOffset = [_machOFile dataOffsetForAddress:address]; 65 | [self setOffset:dataOffset]; 66 | } 67 | 68 | #pragma mark - Read using the current byteOrder 69 | 70 | - (uint16_t)readInt16; 71 | { 72 | if (_byteOrder == CDByteOrder_LittleEndian) 73 | return [self readLittleInt16]; 74 | 75 | return [self readBigInt16]; 76 | } 77 | 78 | - (uint32_t)readInt32; 79 | { 80 | if (_byteOrder == CDByteOrder_LittleEndian) 81 | return [self readLittleInt32]; 82 | 83 | return [self readBigInt32]; 84 | } 85 | 86 | - (uint64_t)readInt64; 87 | { 88 | if (_byteOrder == CDByteOrder_LittleEndian) 89 | return [self readLittleInt64]; 90 | 91 | return [self readBigInt64]; 92 | } 93 | 94 | - (uint32_t)peekInt32; 95 | { 96 | NSUInteger savedOffset = self.offset; 97 | uint32_t val = [self readInt32]; 98 | self.offset = savedOffset; 99 | 100 | return val; 101 | } 102 | 103 | - (uint64_t)readPtr; 104 | { 105 | switch (_ptrSize) { 106 | case sizeof(uint32_t): return [self readInt32]; 107 | case sizeof(uint64_t): return [self readInt64]; 108 | } 109 | [NSException raise:NSInternalInconsistencyException format:@"The ptrSize must be either 4 (32-bit) or 8 (64-bit)"]; 110 | return 0; 111 | } 112 | 113 | @end 114 | -------------------------------------------------------------------------------- /CDMethodType.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @class CDType; 7 | 8 | @interface CDMethodType : NSObject 9 | 10 | - (id)initWithType:(CDType *)type offset:(NSString *)offset; 11 | 12 | @property (readonly) CDType *type; 13 | @property (readonly) NSString *offset; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /CDMethodType.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDMethodType.h" 7 | 8 | #import "CDType.h" 9 | 10 | @implementation CDMethodType 11 | { 12 | CDType *_type; 13 | NSString *_offset; 14 | } 15 | 16 | - (id)initWithType:(CDType *)type offset:(NSString *)offset; 17 | { 18 | if ((self = [super init])) { 19 | _type = type; 20 | _offset = offset; 21 | } 22 | 23 | return self; 24 | } 25 | 26 | #pragma mark - Debugging 27 | 28 | - (NSString *)description; 29 | { 30 | return [NSString stringWithFormat:@"[%@] type: %@, offset: %@", NSStringFromClass([self class]), self.type, self.offset]; 31 | } 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /CDMultiFileVisitor.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDTextClassDumpVisitor.h" 7 | 8 | #import "CDTypeController.h" // For CDTypeControllerDelegate protocol 9 | 10 | // This generates separate files for each class. Files are created in the 'outputPath' directory. 11 | 12 | @interface CDMultiFileVisitor : CDTextClassDumpVisitor 13 | 14 | @property (strong) NSString *outputPath; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /CDOCCategory.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDOCProtocol.h" 7 | #import "CDTopologicalSortProtocol.h" 8 | 9 | @class CDOCClassReference; 10 | 11 | @interface CDOCCategory : CDOCProtocol 12 | 13 | @property (strong) CDOCClassReference *classRef; 14 | @property (strong, readonly) NSString *className; 15 | 16 | - (NSString *)methodSearchContext; 17 | - (void)recursivelyVisit:(CDVisitor *)visitor; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /CDOCCategory.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDOCCategory.h" 7 | 8 | #import "CDClassDump.h" 9 | #import "CDOCMethod.h" 10 | #import "CDVisitor.h" 11 | #import "CDVisitorPropertyState.h" 12 | #import "CDOCClass.h" 13 | #import "CDOCClassReference.h" 14 | 15 | @implementation CDOCCategory 16 | 17 | #pragma mark - Superclass overrides 18 | 19 | - (NSString *)sortableName; 20 | { 21 | return [NSString stringWithFormat:@"%@ (%@)", self.className, self.name]; 22 | } 23 | 24 | #pragma mark - 25 | 26 | - (NSString *)className 27 | { 28 | return [_classRef className]; 29 | } 30 | 31 | - (NSString *)methodSearchContext; 32 | { 33 | NSMutableString *resultString = [NSMutableString string]; 34 | 35 | [resultString appendFormat:@"@interface %@ (%@)", self.className, self.name]; 36 | 37 | if ([self.protocols count] > 0) 38 | [resultString appendFormat:@" <%@>", self.protocolsString]; 39 | 40 | return resultString; 41 | } 42 | 43 | - (void)recursivelyVisit:(CDVisitor *)visitor; 44 | { 45 | if ([visitor.classDump shouldShowName:self.name]) { 46 | CDVisitorPropertyState *propertyState = [[CDVisitorPropertyState alloc] initWithProperties:self.properties]; 47 | 48 | [visitor willVisitCategory:self]; 49 | 50 | //[aVisitor willVisitPropertiesOfCategory:self]; 51 | //[self visitProperties:aVisitor]; 52 | //[aVisitor didVisitPropertiesOfCategory:self]; 53 | 54 | [self visitMethods:visitor propertyState:propertyState]; 55 | // This can happen when... the accessors are implemented on the main class. Odd case, but we should still emit the remaining properties. 56 | // Should mostly be dynamic properties 57 | [visitor visitRemainingProperties:propertyState]; 58 | [visitor didVisitCategory:self]; 59 | } 60 | } 61 | 62 | #pragma mark - CDTopologicalSort protocol 63 | 64 | - (NSString *)identifier; 65 | { 66 | return self.sortableName; 67 | } 68 | 69 | - (NSArray *)dependancies; 70 | { 71 | if (self.className == nil) 72 | return @[]; 73 | 74 | return @[self.className]; 75 | } 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /CDOCClass.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDOCProtocol.h" 7 | 8 | #import "CDTopologicalSortProtocol.h" 9 | 10 | @class CDOCClassReference; 11 | 12 | @interface CDOCClass : CDOCProtocol 13 | 14 | @property (strong) CDOCClassReference *superClassRef; 15 | @property (copy, readonly) NSString *superClassName; 16 | @property (strong) NSArray *instanceVariables; 17 | @property (assign) BOOL isExported; 18 | @property (assign) BOOL isSwiftClass; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /CDOCClass.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDOCClass.h" 7 | 8 | #import "CDClassDump.h" 9 | #import "CDOCInstanceVariable.h" 10 | #import "CDOCMethod.h" 11 | #import "CDType.h" 12 | #import "CDTypeController.h" 13 | #import "CDTypeParser.h" 14 | #import "CDVisitor.h" 15 | #import "CDVisitorPropertyState.h" 16 | #import "CDOCClassReference.h" 17 | 18 | @implementation CDOCClass 19 | { 20 | NSArray *_instanceVariables; 21 | 22 | BOOL _isExported; 23 | } 24 | 25 | - (id)init; 26 | { 27 | if ((self = [super init])) { 28 | _isExported = YES; 29 | } 30 | 31 | return self; 32 | } 33 | 34 | #pragma mark - Debugging 35 | 36 | - (NSString *)description; 37 | { 38 | return [NSString stringWithFormat:@"%@, exported: %@", [super description], self.isExported ? @"YES" : @"NO"]; 39 | } 40 | 41 | #pragma mark - 42 | 43 | - (NSString *)superClassName; 44 | { 45 | return [_superClassRef className]; 46 | } 47 | 48 | - (void)registerTypesWithObject:(CDTypeController *)typeController phase:(NSUInteger)phase; 49 | { 50 | [super registerTypesWithObject:typeController phase:phase]; 51 | 52 | for (CDOCInstanceVariable *instanceVariable in self.instanceVariables) { 53 | [instanceVariable.type phase:phase registerTypesWithObject:typeController usedInMethod:NO]; 54 | } 55 | } 56 | 57 | - (NSString *)methodSearchContext; 58 | { 59 | NSMutableString *resultString = [NSMutableString string]; 60 | 61 | [resultString appendFormat:@"@interface %@", self.name]; 62 | if (self.superClassName != nil) 63 | [resultString appendFormat:@" : %@", self.superClassName]; 64 | 65 | if ([self.protocols count] > 0) 66 | [resultString appendFormat:@" <%@>", self.protocolsString]; 67 | 68 | return resultString; 69 | } 70 | 71 | - (void)recursivelyVisit:(CDVisitor *)visitor; 72 | { 73 | if ([visitor.classDump shouldShowName:self.name]) { 74 | CDVisitorPropertyState *propertyState = [[CDVisitorPropertyState alloc] initWithProperties:self.properties]; 75 | 76 | [visitor willVisitClass:self]; 77 | 78 | [visitor willVisitIvarsOfClass:self]; 79 | for (CDOCInstanceVariable *instanceVariable in self.instanceVariables) 80 | [visitor visitIvar:instanceVariable]; 81 | [visitor didVisitIvarsOfClass:self]; 82 | 83 | //[visitor willVisitPropertiesOfClass:self]; 84 | //[self visitProperties:visitor]; 85 | //[visitor didVisitPropertiesOfClass:self]; 86 | 87 | [self visitMethods:visitor propertyState:propertyState]; 88 | // Should mostly be dynamic properties 89 | [visitor visitRemainingProperties:propertyState]; 90 | [visitor didVisitClass:self]; 91 | } 92 | } 93 | 94 | #pragma mark - CDTopologicalSort protocol 95 | 96 | - (NSString *)identifier; 97 | { 98 | return self.name; 99 | } 100 | 101 | - (NSArray *)dependancies; 102 | { 103 | if (self.superClassName == nil) 104 | return @[]; 105 | 106 | return @[self.superClassName]; 107 | } 108 | 109 | @end 110 | -------------------------------------------------------------------------------- /CDOCClassReference.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import 7 | 8 | @class CDOCClass, CDSymbol; 9 | 10 | /*! 11 | * CDOCClassReference acts as a proxy object to a class that may be external. It can thus be repesented 12 | * as one of: a \c CDOCClass object (for internal classes), a \c CDSymbol object (for external classes), 13 | * or an \c NSString of the class name (for ObjC1 compatibility). The class name can then be inferred from 14 | * any of these representations. 15 | */ 16 | @interface CDOCClassReference : NSObject 17 | 18 | @property (strong) CDOCClass *classObject; 19 | @property (strong) CDSymbol *classSymbol; 20 | @property (nonatomic, copy) NSString *className; // inferred from classObject / classSymbol if not set directly 21 | @property (nonatomic, readonly, getter = isExternalClass) BOOL externalClass; 22 | 23 | - (instancetype)initWithClassObject:(CDOCClass *)classObject; 24 | - (instancetype)initWithClassSymbol:(CDSymbol *)symbol; 25 | - (instancetype)initWithClassName:(NSString *)className; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /CDOCClassReference.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDOCClassReference.h" 7 | #import "CDOCClass.h" 8 | #import "CDSymbol.h" 9 | 10 | @implementation CDOCClassReference 11 | 12 | - (instancetype)initWithClassSymbol:(CDSymbol *)symbol; 13 | { 14 | if ((self = [super init])) { 15 | _classSymbol = symbol; 16 | } 17 | 18 | return self; 19 | } 20 | 21 | - (instancetype)initWithClassObject:(CDOCClass *)classObject; 22 | { 23 | if ((self = [super init])) { 24 | _classObject = classObject; 25 | } 26 | 27 | return self; 28 | } 29 | 30 | - (instancetype)initWithClassName:(NSString *)className; 31 | { 32 | if ((self = [super init])) { 33 | _className = [className copy]; 34 | } 35 | 36 | return self; 37 | } 38 | 39 | - (NSString *)className; 40 | { 41 | if (_className != nil) 42 | return _className; 43 | else if (_classObject != nil) 44 | return [_classObject name]; 45 | else if (_classSymbol != nil) 46 | return [CDSymbol classNameFromSymbolName:[_classSymbol name]]; 47 | else 48 | return nil; 49 | } 50 | 51 | - (BOOL)isExternalClass; 52 | { 53 | return (!_classObject && (!_classSymbol || [_classSymbol isExternal])); 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /CDOCInstanceVariable.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @class CDType, CDTypeController; 7 | 8 | @interface CDOCInstanceVariable : NSObject 9 | 10 | - (id)initWithName:(NSString *)name typeString:(NSString *)typeString offset:(NSUInteger)offset; 11 | 12 | @property (readonly) NSString *name; 13 | @property (readonly) NSString *typeString; 14 | @property (readonly) NSUInteger offset; 15 | 16 | // Lazily parses the typeString. Returns nil and sets the parseError if parsing failed. Does not try to parse again in the event of an error. 17 | @property (nonatomic, readonly) CDType *type; 18 | 19 | // This is set after the typeString has been parsed if there was an error. Doesn't trigger parsing. 20 | @property (readonly) NSError *parseError; 21 | 22 | - (void)appendToString:(NSMutableString *)resultString typeController:(CDTypeController *)typeController; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /CDOCInstanceVariable.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDOCInstanceVariable.h" 7 | 8 | #import "CDClassDump.h" 9 | #import "CDTypeFormatter.h" 10 | #import "CDTypeParser.h" 11 | #import "CDTypeController.h" 12 | #import "CDType.h" 13 | 14 | @interface CDOCInstanceVariable () 15 | @property (assign) BOOL hasParsedType; 16 | @end 17 | 18 | #pragma mark - 19 | 20 | @implementation CDOCInstanceVariable 21 | { 22 | NSString *_name; 23 | NSString *_typeString; 24 | NSUInteger _offset; 25 | 26 | BOOL _hasParsedType; 27 | CDType *_type; 28 | NSError *_parseError; 29 | } 30 | 31 | - (id)initWithName:(NSString *)name typeString:(NSString *)typeString offset:(NSUInteger)offset; 32 | { 33 | if ((self = [super init])) { 34 | _name = name; 35 | _typeString = typeString; 36 | _offset = offset; 37 | 38 | _hasParsedType = NO; 39 | _type = nil; 40 | _parseError = nil; 41 | } 42 | 43 | return self; 44 | } 45 | 46 | #pragma mark - Debugging 47 | 48 | - (NSString *)description; 49 | { 50 | return [NSString stringWithFormat:@"[%@] name: %@, typeString: '%@', offset: %lu", 51 | NSStringFromClass([self class]), self.name, self.typeString, self.offset]; 52 | } 53 | 54 | #pragma mark - 55 | 56 | - (CDType *)type; 57 | { 58 | if (self.hasParsedType == NO && self.parseError == nil) { 59 | CDTypeParser *parser = [[CDTypeParser alloc] initWithString:self.typeString]; 60 | NSError *error; 61 | _type = [parser parseType:&error]; 62 | if (_type == nil) { 63 | NSLog(@"Warning: Parsing instance variable type failed, %@", self.name); 64 | _parseError = error; 65 | } else { 66 | self.hasParsedType = YES; 67 | } 68 | } 69 | 70 | return _type; 71 | } 72 | 73 | - (void)appendToString:(NSMutableString *)resultString typeController:(CDTypeController *)typeController; 74 | { 75 | CDType *type = [self type]; // Parses it, if necessary; 76 | if (self.parseError != nil) { 77 | if ([self.typeString length] > 0) { 78 | [resultString appendFormat:@" // Error: parsing type: '%@', name: %@", self.typeString, self.name]; 79 | } else { 80 | [resultString appendFormat:@" // Error: Empty type, name: %@", self.name]; 81 | } 82 | } else { 83 | NSString *formattedString = [[typeController ivarTypeFormatter] formatVariable:self.name type:type]; 84 | NSParameterAssert(formattedString != nil); 85 | [resultString appendString:formattedString]; 86 | [resultString appendString:@";"]; 87 | if ([typeController shouldShowIvarOffsets]) { 88 | [resultString appendFormat:@"\t// %ld = 0x%lx", self.offset, self.offset]; 89 | } 90 | } 91 | } 92 | 93 | @end 94 | -------------------------------------------------------------------------------- /CDOCMethod.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @class CDTypeController; 7 | 8 | @interface CDOCMethod : NSObject 9 | 10 | - (id)initWithName:(NSString *)name typeString:(NSString *)typeString; 11 | - (id)initWithName:(NSString *)name typeString:(NSString *)typeString address:(NSUInteger)address; 12 | 13 | @property (readonly) NSString *name; 14 | @property (readonly) NSString *typeString; 15 | @property (assign) NSUInteger address; 16 | 17 | - (NSArray *)parsedMethodTypes; 18 | 19 | - (void)appendToString:(NSMutableString *)resultString typeController:(CDTypeController *)typeController; 20 | 21 | - (NSComparisonResult)ascendingCompareByName:(CDOCMethod *)other; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /CDOCMethod.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDOCMethod.h" 7 | 8 | #import "CDClassDump.h" 9 | #import "CDTypeFormatter.h" 10 | #import "CDTypeParser.h" 11 | #import "CDTypeController.h" 12 | 13 | @implementation CDOCMethod 14 | { 15 | NSString *_name; 16 | NSString *_typeString; 17 | NSUInteger _address; 18 | 19 | BOOL _hasParsedType; 20 | NSArray *_parsedMethodTypes; 21 | } 22 | 23 | - (id)init; 24 | { 25 | [NSException raise:@"RejectUnusedImplementation" format:@"-initWithName:typeString:imp: is the designated initializer"]; 26 | return nil; 27 | } 28 | 29 | - (id)initWithName:(NSString *)name typeString:(NSString *)typeString; 30 | { 31 | return [self initWithName:name typeString:typeString address:0]; 32 | } 33 | 34 | - (id)initWithName:(NSString *)name typeString:(NSString *)typeString address:(NSUInteger)address; 35 | { 36 | if ((self = [super init])) { 37 | _name = name; 38 | _typeString = typeString; 39 | _address = address; 40 | 41 | _hasParsedType = NO; 42 | _parsedMethodTypes = nil; 43 | } 44 | 45 | return self; 46 | } 47 | 48 | #pragma mark - NSCopying 49 | 50 | - (id)copyWithZone:(NSZone *)zone; 51 | { 52 | return [[CDOCMethod alloc] initWithName:self.name typeString:self.typeString address:self.address]; 53 | } 54 | 55 | #pragma mark - Debugging 56 | 57 | - (NSString *)description; 58 | { 59 | return [NSString stringWithFormat:@"[%@] name: %@, typeString: %@, address: 0x%016lx", 60 | NSStringFromClass([self class]), self.name, self.typeString, self.address]; 61 | } 62 | 63 | #pragma mark - 64 | 65 | - (NSArray *)parsedMethodTypes; 66 | { 67 | if (_hasParsedType == NO) { 68 | NSError *error = nil; 69 | 70 | CDTypeParser *parser = [[CDTypeParser alloc] initWithString:self.typeString]; 71 | _parsedMethodTypes = [parser parseMethodType:&error]; 72 | if (_parsedMethodTypes == nil) 73 | NSLog(@"Warning: Parsing method types failed, %@", self.name); 74 | _hasParsedType = YES; 75 | } 76 | 77 | return _parsedMethodTypes; 78 | } 79 | 80 | - (void)appendToString:(NSMutableString *)resultString typeController:(CDTypeController *)typeController; 81 | { 82 | NSString *formattedString = [typeController.methodTypeFormatter formatMethodName:self.name typeString:self.typeString]; 83 | if (formattedString != nil) { 84 | [resultString appendString:formattedString]; 85 | [resultString appendString:@";"]; 86 | if (typeController.shouldShowMethodAddresses && self.address != 0) { 87 | if (typeController.targetArchUses64BitABI) 88 | [resultString appendFormat:@"\t// IMP=0x%016lx", self.address]; 89 | else 90 | [resultString appendFormat:@"\t// IMP=0x%08lx", self.address]; 91 | } 92 | } else 93 | [resultString appendFormat:@" // Error parsing type: %@, name: %@", self.typeString, self.name]; 94 | } 95 | 96 | #pragma mark - Sorting 97 | 98 | - (NSComparisonResult)ascendingCompareByName:(CDOCMethod *)other; 99 | { 100 | return [self.name compare:other.name]; 101 | } 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /CDOCModule.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @class CDOCSymtab; 7 | 8 | @interface CDOCModule : NSObject 9 | 10 | @property (assign) uint32_t version; 11 | @property (strong) NSString *name; 12 | @property (strong) CDOCSymtab *symtab; 13 | 14 | - (NSString *)formattedString; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /CDOCModule.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDOCModule.h" 7 | 8 | #import "CDObjectiveC1Processor.h" 9 | #import "CDOCSymtab.h" 10 | 11 | @implementation CDOCModule 12 | { 13 | uint32_t _version; 14 | NSString *_name; 15 | CDOCSymtab *_symtab; 16 | } 17 | 18 | - (id)init; 19 | { 20 | if ((self = [super init])) { 21 | _version = 0; 22 | _name = nil; 23 | _symtab = nil; 24 | } 25 | 26 | return self; 27 | } 28 | 29 | #pragma mark - Debugging 30 | 31 | - (NSString *)description; 32 | { 33 | return [NSString stringWithFormat:@"[%@] name: %@, version: %u, symtab: %@", NSStringFromClass([self class]), self.name, self.version, self.symtab]; 34 | } 35 | 36 | #pragma mark - 37 | 38 | - (NSString *)formattedString; 39 | { 40 | return [NSString stringWithFormat:@"//\n// %@\n//\n", self.name]; 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /CDOCProperty.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @class CDType; 7 | 8 | @interface CDOCProperty : NSObject 9 | 10 | - (id)initWithName:(NSString *)name attributes:(NSString *)attributes; 11 | 12 | @property (readonly) NSString *name; 13 | @property (readonly) NSString *attributeString; 14 | @property (readonly) CDType *type; 15 | @property (readonly) NSArray *attributes; 16 | 17 | @property (strong) NSString *attributeStringAfterType; 18 | 19 | @property (nonatomic, readonly) NSString *defaultGetter; 20 | @property (nonatomic, readonly) NSString *defaultSetter; 21 | 22 | @property (strong) NSString *customGetter; 23 | @property (strong) NSString *customSetter; 24 | 25 | @property (nonatomic, readonly) NSString *getter; 26 | @property (nonatomic, readonly) NSString *setter; 27 | 28 | @property (readonly) BOOL isReadOnly; 29 | @property (readonly) BOOL isDynamic; 30 | 31 | - (NSComparisonResult)ascendingCompareByName:(CDOCProperty *)other; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /CDOCProperty.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDOCProperty.h" 7 | 8 | #import "CDTypeParser.h" 9 | #import "CDTypeLexer.h" 10 | #import "CDType.h" 11 | #import "NSString-CDExtensions.h" 12 | 13 | // http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html 14 | 15 | static BOOL debug = NO; 16 | 17 | @interface CDOCProperty () 18 | @end 19 | 20 | #pragma mark - 21 | 22 | @implementation CDOCProperty 23 | { 24 | NSString *_name; 25 | NSString *_attributeString; 26 | 27 | CDType *_type; 28 | NSMutableArray *_attributes; 29 | 30 | BOOL _hasParsedAttributes; 31 | NSString *_attributeStringAfterType; 32 | NSString *_customGetter; 33 | NSString *_customSetter; 34 | 35 | BOOL _isReadOnly; 36 | BOOL _isDynamic; 37 | } 38 | 39 | - (id)initWithName:(NSString *)name attributes:(NSString *)attributes; 40 | { 41 | if ((self = [super init])) { 42 | _name = name; 43 | _attributeString = attributes; 44 | _type = nil; 45 | _attributes = [[NSMutableArray alloc] init]; 46 | 47 | _hasParsedAttributes = NO; 48 | _attributeStringAfterType = nil; 49 | _customGetter = nil; 50 | _customSetter = nil; 51 | 52 | _isReadOnly = NO; 53 | _isDynamic = NO; 54 | 55 | [self _parseAttributes]; 56 | } 57 | 58 | return self; 59 | } 60 | 61 | #pragma mark - Debugging 62 | 63 | - (NSString *)description; 64 | { 65 | return [NSString stringWithFormat:@"<%@:%p> name: %@, attributeString: %@", 66 | NSStringFromClass([self class]), self, 67 | self.name, self.attributeString]; 68 | } 69 | 70 | #pragma mark - 71 | 72 | - (NSString *)defaultGetter; 73 | { 74 | return self.name; 75 | } 76 | 77 | - (NSString *)defaultSetter; 78 | { 79 | return [NSString stringWithFormat:@"set%@:", [self.name capitalizeFirstCharacter]]; 80 | } 81 | 82 | - (NSString *)getter; 83 | { 84 | if (self.customGetter != nil) 85 | return self.customGetter; 86 | 87 | return self.defaultGetter; 88 | } 89 | 90 | - (NSString *)setter; 91 | { 92 | if (self.customSetter != nil) 93 | return self.customSetter; 94 | 95 | return self.defaultSetter; 96 | } 97 | 98 | #pragma mark - Sorting 99 | 100 | - (NSComparisonResult)ascendingCompareByName:(CDOCProperty *)other; 101 | { 102 | return [self.name compare:other.name]; 103 | } 104 | 105 | #pragma mark - 106 | 107 | // TODO: (2009-07-09) Really, I don't need to require the "T" at the start. 108 | - (void)_parseAttributes; 109 | { 110 | // On 10.6, Finder's TTaskErrorViewController class has a property with a nasty C++ type. I just knew someone would make this difficult. 111 | NSScanner *scanner = [[NSScanner alloc] initWithString:self.attributeString]; 112 | 113 | if ([scanner scanString:@"T" intoString:NULL]) { 114 | NSError *error = nil; 115 | NSRange typeRange; 116 | 117 | typeRange.location = [scanner scanLocation]; 118 | CDTypeParser *parser = [[CDTypeParser alloc] initWithString:[[scanner string] substringFromIndex:[scanner scanLocation]]]; 119 | _type = [parser parseType:&error]; 120 | if (_type != nil) { 121 | typeRange.length = [parser.lexer.scanner scanLocation]; 122 | 123 | NSString *str = [self.attributeString substringFromIndex:NSMaxRange(typeRange)]; 124 | 125 | // Filter out so we don't get an empty string as an attribute. 126 | if ([str hasPrefix:@","]) 127 | str = [str substringFromIndex:1]; 128 | 129 | self.attributeStringAfterType = str; 130 | if ([self.attributeStringAfterType length] > 0) { 131 | [_attributes addObjectsFromArray:[self.attributeStringAfterType componentsSeparatedByString:@","]]; 132 | } else { 133 | // For a simple case like "Ti", we'd get the empty string. 134 | // Then, using componentsSeparatedByString:, since it has no separator we'd get back an array containing the (empty) string 135 | } 136 | } 137 | } else { 138 | if (debug) NSLog(@"Error: Property attributes should begin with the type ('T') attribute, property name: %@", self.name); 139 | } 140 | 141 | for (NSString *attr in _attributes) { 142 | if ([attr hasPrefix:@"R"]) 143 | _isReadOnly = YES; 144 | else if ([attr hasPrefix:@"D"]) 145 | _isDynamic = YES; 146 | else if ([attr hasPrefix:@"G"]) 147 | self.customGetter = [attr substringFromIndex:1]; 148 | else if ([attr hasPrefix:@"S"]) 149 | self.customSetter = [attr substringFromIndex:1]; 150 | } 151 | 152 | _hasParsedAttributes = YES; 153 | // And then if parsedType is nil, we know we couldn't parse the type. 154 | } 155 | 156 | @end 157 | -------------------------------------------------------------------------------- /CDOCProtocol.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @class CDTypeController; 7 | @class CDVisitor, CDVisitorPropertyState; 8 | @class CDOCMethod, CDOCProperty; 9 | 10 | @interface CDOCProtocol : NSObject 11 | 12 | @property (strong) NSString *name; 13 | 14 | @property (readonly) NSArray *protocols; 15 | - (void)addProtocol:(CDOCProtocol *)protocol; 16 | - (void)removeProtocol:(CDOCProtocol *)protocol; 17 | @property (nonatomic, readonly) NSArray *protocolNames; 18 | @property (nonatomic, readonly) NSString *protocolsString; 19 | 20 | @property (nonatomic, readonly) NSArray *classMethods; // TODO: NSArray vs. NSMutableArray 21 | - (void)addClassMethod:(CDOCMethod *)method; 22 | 23 | @property (nonatomic, readonly) NSArray *instanceMethods; 24 | - (void)addInstanceMethod:(CDOCMethod *)method; 25 | 26 | @property (nonatomic, readonly) NSArray *optionalClassMethods; 27 | - (void)addOptionalClassMethod:(CDOCMethod *)method; 28 | 29 | @property (nonatomic, readonly) NSArray *optionalInstanceMethods; 30 | - (void)addOptionalInstanceMethod:(CDOCMethod *)method; 31 | 32 | @property (nonatomic, readonly) NSArray *properties; 33 | - (void)addProperty:(CDOCProperty *)property; 34 | 35 | @property (nonatomic, readonly) BOOL hasMethods; 36 | 37 | - (void)registerTypesWithObject:(CDTypeController *)typeController phase:(NSUInteger)phase; 38 | - (void)registerTypesFromMethods:(NSArray *)methods withObject:(CDTypeController *)typeController phase:(NSUInteger)phase; 39 | 40 | - (NSComparisonResult)ascendingCompareByName:(CDOCProtocol *)other; 41 | 42 | - (NSString *)methodSearchContext; 43 | - (void)recursivelyVisit:(CDVisitor *)visitor; 44 | 45 | - (void)visitMethods:(CDVisitor *)visitor propertyState:(CDVisitorPropertyState *)propertyState; 46 | 47 | - (void)mergeMethodsFromProtocol:(CDOCProtocol *)other; 48 | - (void)mergePropertiesFromProtocol:(CDOCProtocol *)other; 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /CDOCSymtab.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @class CDOCCategory, CDOCClass; 7 | 8 | @interface CDOCSymtab : NSObject 9 | 10 | @property (readonly) NSMutableArray *classes; 11 | - (void)addClass:(CDOCClass *)aClass; 12 | 13 | @property (readonly) NSMutableArray *categories; 14 | - (void)addCategory:(CDOCCategory *)category; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /CDOCSymtab.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDOCSymtab.h" 7 | 8 | #import "CDOCCategory.h" 9 | #import "CDOCClass.h" 10 | 11 | @implementation CDOCSymtab 12 | { 13 | NSMutableArray *_classes; 14 | NSMutableArray *_categories; 15 | } 16 | 17 | - (id)init; 18 | { 19 | if ((self = [super init])) { 20 | _classes = [[NSMutableArray alloc] init]; 21 | _categories = [[NSMutableArray alloc] init]; 22 | } 23 | 24 | return self; 25 | } 26 | 27 | #pragma mark - Debugging 28 | 29 | - (NSString *)description; 30 | { 31 | return [NSString stringWithFormat:@"[%@] classes: %@, categories: %@", NSStringFromClass([self class]), self.classes, self.categories]; 32 | } 33 | 34 | #pragma mark - 35 | 36 | - (void)addClass:(CDOCClass *)aClass; 37 | { 38 | [self.classes addObject:aClass]; 39 | } 40 | 41 | - (void)addCategory:(CDOCCategory *)category; 42 | { 43 | [self.categories addObject:category]; 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /CDObjectiveC1Processor.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDObjectiveCProcessor.h" 7 | 8 | @interface CDObjectiveC1Processor : CDObjectiveCProcessor 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /CDObjectiveC2Processor.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDObjectiveCProcessor.h" 7 | 8 | @interface CDObjectiveC2Processor : CDObjectiveCProcessor 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /CDObjectiveCProcessor.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @class CDMachOFile, CDSection, CDTypeController; 7 | @class CDVisitor; 8 | @class CDOCClass, CDOCCategory; 9 | @class CDProtocolUniquer; 10 | 11 | @interface CDObjectiveCProcessor : NSObject 12 | 13 | - (id)initWithMachOFile:(CDMachOFile *)machOFile; 14 | 15 | @property (readonly) CDMachOFile *machOFile; 16 | @property (nonatomic, readonly) BOOL hasObjectiveCData; 17 | 18 | @property (nonatomic, readonly) CDSection *objcImageInfoSection; 19 | @property (nonatomic, readonly) NSString *garbageCollectionStatus; 20 | 21 | - (void)addClass:(CDOCClass *)aClass withAddress:(uint64_t)address; 22 | - (CDOCClass *)classWithAddress:(uint64_t)address; 23 | 24 | - (void)addClassesFromArray:(NSArray *)array; 25 | - (void)addCategoriesFromArray:(NSArray *)array; 26 | 27 | - (void)addCategory:(CDOCCategory *)category; 28 | 29 | - (void)process; 30 | - (void)loadProtocols; 31 | - (void)loadClasses; 32 | - (void)loadCategories; 33 | 34 | - (void)registerTypesWithObject:(CDTypeController *)typeController phase:(NSUInteger)phase; 35 | - (void)recursivelyVisit:(CDVisitor *)visitor; 36 | 37 | - (NSArray *)protocolAddressListAtAddress:(uint64_t)address; 38 | 39 | @property (readonly) CDProtocolUniquer *protocolUniquer; 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /CDProtocolUniquer.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @class CDOCProtocol; 7 | 8 | @interface CDProtocolUniquer : NSObject 9 | 10 | // Gather 11 | - (CDOCProtocol *)protocolWithAddress:(uint64_t)address; 12 | - (void)setProtocol:(CDOCProtocol *)protocol withAddress:(uint64_t)address; 13 | 14 | // Process 15 | - (void)createUniquedProtocols; 16 | 17 | // Results 18 | - (NSArray *)uniqueProtocolsAtAddresses:(NSArray *)addresses; 19 | - (NSArray *)uniqueProtocolsSortedByName; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /CDProtocolUniquer.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDProtocolUniquer.h" 7 | 8 | #import "CDOCProtocol.h" 9 | #import "CDOCMethod.h" 10 | 11 | @implementation CDProtocolUniquer 12 | { 13 | NSMutableDictionary *_protocolsByAddress; // non-uniqued 14 | NSMutableDictionary *_uniqueProtocolsByName; 15 | NSMutableDictionary *_uniqueProtocolsByAddress; 16 | } 17 | 18 | - (id)init; 19 | { 20 | if ((self = [super init])) { 21 | _protocolsByAddress = [[NSMutableDictionary alloc] init]; 22 | _uniqueProtocolsByName = [[NSMutableDictionary alloc] init]; 23 | _uniqueProtocolsByAddress = [[NSMutableDictionary alloc] init]; 24 | } 25 | 26 | return self; 27 | } 28 | 29 | #pragma mark - Gather 30 | 31 | - (CDOCProtocol *)protocolWithAddress:(uint64_t)address; 32 | { 33 | NSNumber *key = [NSNumber numberWithUnsignedLongLong:address]; 34 | return _protocolsByAddress[key]; 35 | } 36 | 37 | - (void)setProtocol:(CDOCProtocol *)protocol withAddress:(uint64_t)address; 38 | { 39 | NSNumber *key = [NSNumber numberWithUnsignedLongLong:address]; 40 | _protocolsByAddress[key] = protocol; 41 | } 42 | 43 | #pragma mark - Process 44 | 45 | - (void)createUniquedProtocols; 46 | { 47 | [_uniqueProtocolsByName removeAllObjects]; 48 | [_uniqueProtocolsByAddress removeAllObjects]; 49 | 50 | // Now unique the protocols by name and store in protocolsByName 51 | 52 | for (NSNumber *key in [[_protocolsByAddress allKeys] sortedArrayUsingSelector:@selector(compare:)]) { 53 | CDOCProtocol *p1 = _protocolsByAddress[key]; 54 | CDOCProtocol *uniqueProtocol = _uniqueProtocolsByName[p1.name]; 55 | if (uniqueProtocol == nil) { 56 | uniqueProtocol = [[CDOCProtocol alloc] init]; 57 | [uniqueProtocol setName:[p1 name]]; 58 | _uniqueProtocolsByName[uniqueProtocol.name] = uniqueProtocol; 59 | // adopted protocols still not set, will want uniqued instances 60 | } else { 61 | } 62 | _uniqueProtocolsByAddress[key] = uniqueProtocol; 63 | } 64 | 65 | //NSLog(@"uniqued protocol names: %@", [[[protocolsByName allKeys] sortedArrayUsingSelector:@selector(compare:)] componentsJoinedByString:@", "]); 66 | 67 | // And finally fill in adopted protocols, instance and class methods. And properties. 68 | for (NSNumber *key in [[_protocolsByAddress allKeys] sortedArrayUsingSelector:@selector(compare:)]) { 69 | CDOCProtocol *p1 = _protocolsByAddress[key]; 70 | CDOCProtocol *uniqueProtocol = _uniqueProtocolsByName[p1.name]; 71 | 72 | // Add the uniqued adopted protocols 73 | for (CDOCProtocol *p2 in [p1 protocols]) 74 | [uniqueProtocol addProtocol:_uniqueProtocolsByName[p2.name]]; 75 | 76 | [uniqueProtocol mergeMethodsFromProtocol:p1]; 77 | [uniqueProtocol mergePropertiesFromProtocol:p1]; 78 | } 79 | 80 | //NSLog(@"protocolsByName: %@", protocolsByName); 81 | } 82 | 83 | #pragma mark - Results 84 | 85 | // These are useful after the call to -createUniqueProtocols 86 | 87 | - (NSArray *)uniqueProtocolsAtAddresses:(NSArray *)addresses; 88 | { 89 | NSMutableArray *protocols = [NSMutableArray array]; 90 | 91 | for (NSNumber *protocolAddress in addresses) { 92 | CDOCProtocol *uniqueProtocol = _uniqueProtocolsByAddress[protocolAddress]; 93 | if (uniqueProtocol != nil) 94 | [protocols addObject:uniqueProtocol]; 95 | } 96 | 97 | return [protocols copy]; 98 | } 99 | 100 | - (NSArray *)uniqueProtocolsSortedByName; 101 | { 102 | return [[_uniqueProtocolsByName allValues] sortedArrayUsingSelector:@selector(ascendingCompareByName:)]; 103 | } 104 | 105 | @end 106 | -------------------------------------------------------------------------------- /CDRelocationInfo.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #include 7 | 8 | typedef enum : NSUInteger { 9 | CDRelocationInfoSize_8Bit = 0, 10 | CDRelocationInfoSize_16Bit = 1, 11 | CDRelocationInfoSize_32Bit = 2, 12 | CDRelocationInfoSize_64Bit = 3, 13 | } CDRelocationSize; 14 | 15 | @interface CDRelocationInfo : NSObject 16 | 17 | - (id)initWithInfo:(struct relocation_info)info; 18 | 19 | @property (nonatomic, readonly) NSUInteger offset; 20 | @property (nonatomic, readonly) CDRelocationSize size; 21 | @property (nonatomic, readonly) uint32_t symbolnum; 22 | @property (nonatomic, readonly) BOOL isExtern; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /CDRelocationInfo.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDRelocationInfo.h" 7 | 8 | @implementation CDRelocationInfo 9 | { 10 | struct relocation_info _rinfo; 11 | } 12 | 13 | - (id)initWithInfo:(struct relocation_info)info; 14 | { 15 | if ((self = [super init])) { 16 | _rinfo = info; 17 | } 18 | 19 | return self; 20 | } 21 | 22 | #pragma mark - Debugging 23 | 24 | - (NSString *)description; 25 | { 26 | return [NSString stringWithFormat:@"<%@:%p> addr/off: %08x, sym #: %5u, pcrel? %u, len: %u, extern? %u, type: %x", 27 | NSStringFromClass([self class]), self, 28 | _rinfo.r_address, _rinfo.r_symbolnum, _rinfo.r_pcrel, _rinfo.r_length, _rinfo.r_extern, _rinfo.r_type]; 29 | } 30 | 31 | #pragma mark - 32 | 33 | - (NSUInteger)offset; 34 | { 35 | return _rinfo.r_address; 36 | } 37 | 38 | - (CDRelocationSize)size; 39 | { 40 | return _rinfo.r_length; 41 | } 42 | 43 | - (uint32_t)symbolnum; 44 | { 45 | return _rinfo.r_symbolnum; 46 | } 47 | 48 | - (BOOL)isExtern; 49 | { 50 | return _rinfo.r_extern == 1; 51 | } 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /CDSearchPathState.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @interface CDSearchPathState : NSObject 7 | 8 | @property (nonatomic, strong) NSString *executablePath; 9 | 10 | - (void)pushSearchPaths:(NSArray *)searchPaths; 11 | - (void)popSearchPaths; 12 | 13 | - (NSArray *)searchPaths; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /CDSearchPathState.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDSearchPathState.h" 7 | 8 | @interface CDSearchPathState () 9 | @property (readonly) NSMutableArray *searchPathStack; 10 | @end 11 | 12 | #pragma mark - 13 | 14 | @implementation CDSearchPathState 15 | { 16 | NSString *_executablePath; 17 | NSMutableArray *_searchPathStack; 18 | } 19 | 20 | - (id)init; 21 | { 22 | if ((self = [super init])) { 23 | _executablePath = nil; 24 | _searchPathStack = [[NSMutableArray alloc] init]; 25 | } 26 | 27 | return self; 28 | } 29 | 30 | #pragma mark - 31 | 32 | - (void)pushSearchPaths:(NSArray *)searchPaths; 33 | { 34 | [self.searchPathStack addObject:searchPaths]; 35 | } 36 | 37 | - (void)popSearchPaths; 38 | { 39 | if ([self.searchPathStack count] > 0) { 40 | [self.searchPathStack removeLastObject]; 41 | } else { 42 | NSLog(@"Warning: Unbalanced popSearchPaths"); 43 | } 44 | } 45 | 46 | - (NSArray *)searchPaths; 47 | { 48 | NSMutableArray *result = [NSMutableArray array]; 49 | for (NSArray *group in self.searchPathStack) { 50 | [result addObjectsFromArray:group]; 51 | } 52 | 53 | return [result copy]; 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /CDSection.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @class CDMachOFileDataCursor; 7 | @class CDLCSegment; 8 | 9 | @interface CDSection : NSObject 10 | 11 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor segment:(CDLCSegment *)segment; 12 | 13 | @property (weak, readonly) CDLCSegment *segment; 14 | 15 | @property (nonatomic, readonly) NSData *data; 16 | 17 | @property (nonatomic, readonly) NSString *segmentName; 18 | @property (nonatomic, readonly) NSString *sectionName; 19 | 20 | @property (nonatomic, readonly) NSUInteger addr; 21 | @property (nonatomic, readonly) NSUInteger size; 22 | 23 | - (BOOL)containsAddress:(NSUInteger)address; 24 | - (NSUInteger)fileOffsetForAddress:(NSUInteger)address; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /CDSection.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDSection.h" 7 | 8 | #include 9 | #import "CDMachOFile.h" 10 | #import "CDMachOFileDataCursor.h" 11 | #import "CDLCSegment.h" 12 | 13 | @implementation CDSection 14 | { 15 | struct section_64 _section; // 64-bit, also holding 32-bit 16 | } 17 | 18 | @synthesize data = _data; 19 | 20 | - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor segment:(CDLCSegment *)segment; 21 | { 22 | if ((self = [super init])) { 23 | _segment = segment; 24 | 25 | _sectionName = [cursor readStringOfLength:16 encoding:NSASCIIStringEncoding]; 26 | size_t sectionNameLength = [_sectionName lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; 27 | memcpy(_section.sectname, [_sectionName UTF8String], MIN(sectionNameLength, sizeof(_section.sectname))); 28 | size_t segmentNameLength = [_sectionName lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; 29 | _segmentName = [cursor readStringOfLength:16 encoding:NSASCIIStringEncoding]; 30 | memcpy(_section.segname, [_segmentName UTF8String], MIN(segmentNameLength, sizeof(_section.segname))); 31 | _section.addr = [cursor readPtr]; 32 | _section.size = [cursor readPtr]; 33 | _section.offset = [cursor readInt32]; 34 | uint32_t dyldOffset = (uint32_t)(_section.addr - segment.vmaddr + segment.fileoff); 35 | if (_section.offset > 0 && _section.offset != dyldOffset) { 36 | fprintf(stderr, "Warning: Invalid section offset 0x%08x replaced with 0x%08x in %s,%s\n", _section.offset, dyldOffset, [_segmentName UTF8String], [_sectionName UTF8String]); 37 | _section.offset = dyldOffset; 38 | } 39 | _section.align = [cursor readInt32]; 40 | _section.reloff = [cursor readInt32]; 41 | _section.nreloc = [cursor readInt32]; 42 | _section.flags = [cursor readInt32]; 43 | _section.reserved1 = [cursor readInt32]; 44 | _section.reserved2 = [cursor readInt32]; 45 | if (cursor.machOFile.uses64BitABI) { 46 | _section.reserved3 = [cursor readInt32]; 47 | } 48 | } 49 | 50 | return self; 51 | } 52 | 53 | #pragma mark - 54 | 55 | - (NSData *)data; 56 | { 57 | if (!_data) { 58 | _data = [[NSData alloc] initWithBytes:(uint8_t *)[self.segment.machOFile.data bytes] + _section.offset length:_section.size]; 59 | } 60 | return _data; 61 | } 62 | 63 | - (NSUInteger)addr; 64 | { 65 | return _section.addr; 66 | } 67 | 68 | - (NSUInteger)size; 69 | { 70 | return _section.size; 71 | } 72 | 73 | - (BOOL)containsAddress:(NSUInteger)address; 74 | { 75 | return (address >= _section.addr) && (address < _section.addr + _section.size); 76 | } 77 | 78 | - (NSUInteger)fileOffsetForAddress:(NSUInteger)address; 79 | { 80 | NSParameterAssert([self containsAddress:address]); 81 | return _section.offset + address - _section.addr; 82 | } 83 | 84 | #pragma mark - Debugging 85 | 86 | - (NSString *)description; 87 | { 88 | int padding = (int)self.segment.machOFile.ptrSize * 2; 89 | return [NSString stringWithFormat:@"<%@:%p> '%@,%-16s' addr: %0*llx, size: %0*llx", 90 | NSStringFromClass([self class]), self, 91 | self.segmentName, [self.sectionName UTF8String], 92 | padding, _section.addr, padding, _section.size]; 93 | } 94 | 95 | @end 96 | -------------------------------------------------------------------------------- /CDStructureInfo.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @class CDType; 7 | 8 | @interface CDStructureInfo : NSObject 9 | 10 | - (id)initWithType:(CDType *)type; 11 | 12 | - (NSString *)shortDescription; 13 | 14 | @property (readonly) CDType *type; 15 | 16 | @property (assign) NSUInteger referenceCount; 17 | - (void)addReferenceCount:(NSUInteger)count; 18 | 19 | @property (assign) BOOL isUsedInMethod; 20 | @property (strong) NSString *typedefName; 21 | 22 | - (void)generateTypedefName:(NSString *)baseName; 23 | 24 | @property (nonatomic, readonly) NSString *name; 25 | 26 | - (NSComparisonResult)ascendingCompareByStructureDepth:(CDStructureInfo *)other; 27 | - (NSComparisonResult)descendingCompareByStructureDepth:(CDStructureInfo *)other; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /CDStructureInfo.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDStructureInfo.h" 7 | 8 | #import "CDType.h" 9 | #import "CDTypeName.h" 10 | #import "NSString-CDExtensions.h" 11 | // If it's used in a method, then it should be declared at the top. (name or typedef) 12 | 13 | @implementation CDStructureInfo 14 | { 15 | CDType *_type; 16 | NSUInteger _referenceCount; 17 | BOOL _isUsedInMethod; 18 | NSString *_typedefName; 19 | } 20 | 21 | - (id)initWithType:(CDType *)type; 22 | { 23 | if ((self = [super init])) { 24 | _type = [type copy]; 25 | _referenceCount = 1; 26 | _isUsedInMethod = NO; 27 | _typedefName = nil; 28 | } 29 | 30 | return self; 31 | } 32 | 33 | #pragma mark - NSCopying 34 | 35 | - (id)copyWithZone:(NSZone *)zone; 36 | { 37 | CDStructureInfo *copy = [[CDStructureInfo alloc] initWithType:self.type]; // type gets copied 38 | copy.referenceCount = self.referenceCount; 39 | copy.isUsedInMethod = self.isUsedInMethod; 40 | copy.typedefName = self.typedefName; 41 | 42 | return copy; 43 | } 44 | 45 | #pragma mark - Debugging 46 | 47 | - (NSString *)description; 48 | { 49 | return [NSString stringWithFormat:@"<%@:%p> depth: %lu, refcount: %lu, isUsedInMethod: %u, type: %p", 50 | NSStringFromClass([self class]), self, 51 | self.type.structureDepth, self.referenceCount, self.isUsedInMethod, self.type]; 52 | } 53 | 54 | - (NSString *)shortDescription; 55 | { 56 | return [NSString stringWithFormat:@"%lu %lu m?%u %@ %@", self.type.structureDepth, self.referenceCount, self.isUsedInMethod, self.type.bareTypeString, self.type.typeString]; 57 | } 58 | 59 | #pragma mark - 60 | 61 | - (void)addReferenceCount:(NSUInteger)count; 62 | { 63 | self.referenceCount += count; 64 | } 65 | 66 | // Do this before generating member names. 67 | - (void)generateTypedefName:(NSString *)baseName; 68 | { 69 | NSString *digest = [self.type.typeString SHA1DigestString]; 70 | NSUInteger length = [digest length]; 71 | if (length > 8) 72 | digest = [digest substringFromIndex:length - 8]; 73 | 74 | self.typedefName = [NSString stringWithFormat:@"%@%@", baseName, digest]; 75 | //NSLog(@"typedefName: %@", self.typedefName); 76 | } 77 | 78 | - (NSString *)name; 79 | { 80 | return [self.type.typeName description]; 81 | } 82 | 83 | #pragma mark - Sorting 84 | 85 | // Structure depth, reallyBareTypeString, typeString 86 | - (NSComparisonResult)ascendingCompareByStructureDepth:(CDStructureInfo *)other; 87 | { 88 | NSUInteger thisDepth = self.type.structureDepth; 89 | NSUInteger otherDepth = other.type.structureDepth; 90 | 91 | if (thisDepth < otherDepth) return NSOrderedAscending; 92 | if (thisDepth > otherDepth) return NSOrderedDescending; 93 | 94 | NSString *str1 = self.type.reallyBareTypeString; 95 | NSString *str2 = other.type.reallyBareTypeString; 96 | NSComparisonResult result = [str1 compare:str2]; 97 | if (result == NSOrderedSame) { 98 | str1 = self.type.typeString; 99 | str2 = other.type.typeString; 100 | result = [str1 compare:str2]; 101 | } 102 | 103 | return result; 104 | } 105 | 106 | - (NSComparisonResult)descendingCompareByStructureDepth:(CDStructureInfo *)other; 107 | { 108 | NSUInteger thisDepth = self.type.structureDepth; 109 | NSUInteger otherDepth = other.type.structureDepth; 110 | 111 | if (thisDepth < otherDepth) return NSOrderedDescending; 112 | if (thisDepth > otherDepth) return NSOrderedAscending; 113 | 114 | NSString *str1 = self.type.reallyBareTypeString; 115 | NSString *str2 = other.type.reallyBareTypeString; 116 | NSComparisonResult result = -[str1 compare:str2]; 117 | if (result == NSOrderedSame) { 118 | str1 = self.type.typeString; 119 | str2 = other.type.typeString; 120 | result = -[str1 compare:str2]; 121 | } 122 | 123 | return result; 124 | } 125 | 126 | @end 127 | -------------------------------------------------------------------------------- /CDStructureTable.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @class CDType, CDTypeController, CDTypeFormatter; 7 | 8 | @interface CDStructureTable : NSObject 9 | 10 | @property (strong) NSString *identifier; 11 | @property (strong) NSString *anonymousBaseName; 12 | @property (assign) BOOL shouldDebug; 13 | 14 | @property (weak) CDTypeController *typeController; 15 | 16 | // Phase 0 17 | - (void)phase0RegisterStructure:(CDType *)structure usedInMethod:(BOOL)isUsedInMethod; 18 | - (void)finishPhase0; 19 | 20 | // Phase 1 21 | - (void)runPhase1; 22 | - (void)phase1RegisterStructure:(CDType *)structure; 23 | - (void)finishPhase1; 24 | @property (nonatomic, readonly) NSUInteger phase1_maxDepth; 25 | 26 | // Phase 2 27 | - (void)runPhase2AtDepth:(NSUInteger)depth; 28 | - (CDType *)phase2ReplacementForType:(CDType *)type; 29 | 30 | - (void)finishPhase2; 31 | 32 | // Phase 3 33 | - (void)phase2ReplacementOnPhase0; 34 | 35 | - (void)buildPhase3Exceptions; 36 | - (void)runPhase3; 37 | - (void)phase3RegisterStructure:(CDType *)structure 38 | count:(NSUInteger)referenceCount 39 | usedInMethod:(BOOL)isUsedInMethod; 40 | - (void)finishPhase3; 41 | - (CDType *)phase3ReplacementForType:(CDType *)type; 42 | 43 | // Other 44 | 45 | // Called by CDTypeController prior to calling the next two methods. 46 | - (void)generateTypedefNames; 47 | - (void)generateMemberNames; 48 | 49 | // Called by CDTypeController 50 | - (void)appendNamedStructuresToString:(NSMutableString *)resultString 51 | formatter:(CDTypeFormatter *)typeFormatter 52 | markName:(NSString *)markName; 53 | 54 | // Called by CDTypeController 55 | - (void)appendTypedefsToString:(NSMutableString *)resultString 56 | formatter:(CDTypeFormatter *)typeFormatter 57 | markName:(NSString *)markName; 58 | 59 | - (BOOL)shouldExpandType:(CDType *)type; 60 | - (NSString *)typedefNameForType:(CDType *)type; 61 | 62 | // Debugging 63 | - (void)debugName:(NSString *)name; 64 | - (void)debugAnon:(NSString *)str; 65 | - (void)logPhase0Info; 66 | - (void)logPhase2Info; 67 | - (void)logPhase3Info; 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /CDSymbol.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #include 7 | 8 | extern NSString *const ObjCClassSymbolPrefix; 9 | 10 | @class CDMachOFile, CDSection, CDLCDylib; 11 | 12 | @interface CDSymbol : NSObject 13 | 14 | - (id)initWithName:(NSString *)name machOFile:(CDMachOFile *)machOFile nlist32:(struct nlist)nlist32; 15 | - (id)initWithName:(NSString *)name machOFile:(CDMachOFile *)machOFile nlist64:(struct nlist_64)nlist64; 16 | 17 | @property (nonatomic, readonly) uint64_t value; 18 | @property (readonly) NSString *name; 19 | @property (nonatomic, readonly) CDSection *section; 20 | @property (nonatomic, readonly) CDLCDylib *dylibLoadCommand; 21 | 22 | @property (nonatomic, readonly) BOOL isExternal; 23 | @property (nonatomic, readonly) BOOL isPrivateExternal; 24 | @property (nonatomic, readonly) NSUInteger stab; 25 | @property (nonatomic, readonly) NSUInteger type; 26 | @property (nonatomic, readonly) BOOL isDefined; 27 | @property (nonatomic, readonly) BOOL isAbsolute; 28 | @property (nonatomic, readonly) BOOL isInSection; 29 | @property (nonatomic, readonly) BOOL isPrebound; 30 | @property (nonatomic, readonly) BOOL isIndirect; 31 | @property (nonatomic, readonly) BOOL isCommon; 32 | @property (nonatomic, readonly) BOOL isInTextSection; 33 | @property (nonatomic, readonly) BOOL isInDataSection; 34 | @property (nonatomic, readonly) BOOL isInBssSection; 35 | @property (nonatomic, readonly) NSUInteger referenceType; 36 | @property (nonatomic, readonly) NSString *referenceTypeName; 37 | @property (nonatomic, readonly) NSString *shortTypeDescription; 38 | @property (nonatomic, readonly) NSString *longTypeDescription; 39 | 40 | - (NSComparisonResult)compare:(CDSymbol *)other; 41 | - (NSComparisonResult)compareByName:(CDSymbol *)other; 42 | 43 | + (NSString *)classNameFromSymbolName:(NSString *)symbolName; 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /CDTextClassDumpVisitor.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDVisitor.h" 7 | 8 | // Has a mutable string for storing output, and method to write it to standard out. 9 | // symbol references are for... ? 10 | 11 | @interface CDTextClassDumpVisitor : CDVisitor 12 | 13 | @property (readonly) NSMutableString *resultString; 14 | 15 | - (void)writeResultToStandardOutput; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /CDTopoSortNode.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDTopologicalSortProtocol.h" 7 | 8 | typedef enum : NSUInteger { 9 | CDNodeColor_White = 0, 10 | CDNodeColor_Gray = 1, 11 | CDNodeColor_Black = 2, 12 | } CDNodeColor; 13 | 14 | @interface CDTopoSortNode : NSObject 15 | 16 | - (id)initWithObject:(id )object; 17 | 18 | @property (nonatomic, readonly) NSString *identifier; 19 | @property (readonly) id sortableObject; 20 | 21 | - (NSArray *)dependancies; 22 | - (void)addDependancy:(NSString *)identifier; 23 | - (void)removeDependancy:(NSString *)identifier; 24 | - (void)addDependanciesFromArray:(NSArray *)identifiers; 25 | @property (nonatomic, readonly) NSString *dependancyDescription; 26 | 27 | @property (assign) CDNodeColor color; 28 | 29 | - (NSComparisonResult)ascendingCompareByIdentifier:(CDTopoSortNode *)other; 30 | - (void)topologicallySortNodes:(NSDictionary *)nodesByIdentifier intoArray:(NSMutableArray *)sortedArray; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /CDTopoSortNode.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDTopoSortNode.h" 7 | 8 | @implementation CDTopoSortNode 9 | { 10 | id _sortableObject; 11 | 12 | NSMutableSet *_dependancies; 13 | CDNodeColor _color; 14 | } 15 | 16 | - (id)initWithObject:(id )object; 17 | { 18 | if ((self = [super init])) { 19 | _sortableObject = object; 20 | _dependancies = [[NSMutableSet alloc] init]; 21 | _color = CDNodeColor_White; 22 | 23 | [self addDependanciesFromArray:[_sortableObject dependancies]]; 24 | } 25 | 26 | return self; 27 | } 28 | 29 | #pragma mark - Debugging 30 | 31 | - (NSString *)description; 32 | { 33 | return [NSString stringWithFormat:@"%@ (%lu) depends on %@", self.identifier, self.color, self.dependancyDescription]; 34 | } 35 | 36 | #pragma mark - 37 | 38 | - (NSString *)identifier; 39 | { 40 | return self.sortableObject.identifier; 41 | } 42 | 43 | - (NSArray *)dependancies; 44 | { 45 | return [_dependancies allObjects]; 46 | } 47 | 48 | - (void)addDependancy:(NSString *)identifier; 49 | { 50 | [_dependancies addObject:identifier]; 51 | } 52 | 53 | - (void)removeDependancy:(NSString *)identifier; 54 | { 55 | [_dependancies removeObject:identifier]; 56 | } 57 | 58 | - (void)addDependanciesFromArray:(NSArray *)identifiers; 59 | { 60 | [_dependancies addObjectsFromArray:identifiers]; 61 | } 62 | 63 | - (NSString *)dependancyDescription; 64 | { 65 | return [[_dependancies allObjects] componentsJoinedByString:@", "]; 66 | } 67 | 68 | #pragma mark - Sorting 69 | 70 | - (NSComparisonResult)ascendingCompareByIdentifier:(CDTopoSortNode *)other; 71 | { 72 | return [self.identifier compare:other.identifier]; 73 | } 74 | 75 | - (void)topologicallySortNodes:(NSDictionary *)nodesByIdentifier intoArray:(NSMutableArray *)sortedArray; 76 | { 77 | NSArray *dependantIdentifiers = [self dependancies]; 78 | 79 | for (NSString *identifier in dependantIdentifiers) { 80 | CDTopoSortNode *node = nodesByIdentifier[identifier]; 81 | if (node.color == CDNodeColor_White) { 82 | node.color = CDNodeColor_Gray; 83 | [node topologicallySortNodes:nodesByIdentifier intoArray:sortedArray]; 84 | } else if (node.color == CDNodeColor_Gray) { 85 | NSLog(@"Warning: Possible circular reference? %@ -> %@", self.identifier, node.identifier); 86 | } 87 | } 88 | 89 | [sortedArray addObject:[self sortableObject]]; 90 | self.color = CDNodeColor_Black; 91 | } 92 | 93 | @end 94 | -------------------------------------------------------------------------------- /CDTopologicalSortProtocol.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | // A rather clunky way to avoid warnings in CDTopoSortNode.m regarding -retain not implemented by protocols 7 | @protocol CDTopologicalSort 8 | @property (nonatomic, readonly) NSString *identifier; 9 | @property (nonatomic, readonly) NSArray *dependancies; 10 | @end 11 | -------------------------------------------------------------------------------- /CDType.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @class CDTypeController, CDTypeFormatter, CDTypeName; 7 | 8 | @interface CDType : NSObject 9 | 10 | - (id)initSimpleType:(int)type; 11 | - (id)initIDType:(CDTypeName *)name; 12 | - (id)initIDType:(CDTypeName *)name withProtocols:(NSArray *)protocols; 13 | - (id)initIDTypeWithProtocols:(NSArray *)protocols; 14 | - (id)initStructType:(CDTypeName *)name members:(NSArray *)members; 15 | - (id)initUnionType:(CDTypeName *)name members:(NSArray *)members; 16 | - (id)initBitfieldType:(NSString *)bitfieldSize; 17 | - (id)initArrayType:(CDType *)type count:(NSString *)count; 18 | - (id)initPointerType:(CDType *)type; 19 | - (id)initFunctionPointerType; 20 | - (id)initBlockTypeWithTypes:(NSArray *)types; 21 | - (id)initModifier:(int)modifier type:(CDType *)type; 22 | 23 | @property (strong) NSString *variableName; 24 | 25 | @property (nonatomic, readonly) int primitiveType; 26 | @property (nonatomic, readonly) BOOL isIDType; 27 | @property (nonatomic, readonly) BOOL isNamedObject; 28 | @property (nonatomic, readonly) BOOL isTemplateType; 29 | 30 | @property (nonatomic, readonly) CDType *subtype; 31 | @property (nonatomic, readonly) CDTypeName *typeName; 32 | 33 | @property (nonatomic, readonly) NSArray *members; 34 | @property (nonatomic, readonly) NSArray *types; 35 | 36 | @property (nonatomic, readonly) int typeIgnoringModifiers; 37 | @property (nonatomic, readonly) NSUInteger structureDepth; 38 | 39 | - (NSString *)formattedString:(NSString *)previousName formatter:(CDTypeFormatter *)typeFormatter level:(NSUInteger)level; 40 | 41 | @property (nonatomic, readonly) NSString *typeString; 42 | @property (nonatomic, readonly) NSString *bareTypeString; 43 | @property (nonatomic, readonly) NSString *reallyBareTypeString; 44 | @property (nonatomic, readonly) NSString *keyTypeString; 45 | 46 | 47 | - (BOOL)canMergeWithType:(CDType *)otherType; 48 | - (void)mergeWithType:(CDType *)otherType; 49 | 50 | @property (nonatomic, readonly) NSArray *memberVariableNames; 51 | - (void)generateMemberNames; 52 | 53 | // Phase 0 54 | - (void)phase:(NSUInteger)phase registerTypesWithObject:(CDTypeController *)typeController usedInMethod:(BOOL)isUsedInMethod; 55 | - (void)phase0RecursivelyFixStructureNames:(BOOL)flag; 56 | 57 | // Phase 1 58 | - (void)phase1RegisterStructuresWithObject:(CDTypeController *)typeController; 59 | 60 | // Phase 2 61 | - (void)phase2MergeWithTypeController:(CDTypeController *)typeController debug:(BOOL)phase2Debug; 62 | 63 | // Phase 3 64 | - (void)phase3RegisterMembersWithTypeController:(CDTypeController *)typeController; 65 | - (void)phase3MergeWithTypeController:(CDTypeController *)typeController; 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /CDTypeController.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @protocol CDTypeControllerDelegate; 7 | 8 | @class CDClassDump, CDType, CDTypeFormatter; 9 | 10 | @interface CDTypeController : NSObject 11 | 12 | - (id)initWithClassDump:(CDClassDump *)classDump; 13 | 14 | @property (weak) id delegate; 15 | 16 | @property (readonly) CDTypeFormatter *ivarTypeFormatter; 17 | @property (readonly) CDTypeFormatter *methodTypeFormatter; 18 | @property (readonly) CDTypeFormatter *propertyTypeFormatter; 19 | @property (readonly) CDTypeFormatter *structDeclarationTypeFormatter; 20 | 21 | @property (nonatomic, readonly) BOOL shouldShowIvarOffsets; 22 | @property (nonatomic, readonly) BOOL shouldShowMethodAddresses; 23 | @property (nonatomic, readonly) BOOL targetArchUses64BitABI; 24 | 25 | @property (nonatomic, assign) BOOL hasUnknownFunctionPointers; 26 | @property (nonatomic, assign) BOOL hasUnknownBlocks; 27 | 28 | - (CDType *)typeFormatter:(CDTypeFormatter *)typeFormatter replacementForType:(CDType *)type; 29 | - (NSString *)typeFormatter:(CDTypeFormatter *)typeFormatter typedefNameForStructure:(CDType *)structureType level:(NSUInteger)level; 30 | - (void)typeFormatter:(CDTypeFormatter *)typeFormatter didReferenceClassName:(NSString *)name; 31 | - (void)typeFormatter:(CDTypeFormatter *)typeFormatter didReferenceProtocolNames:(NSArray *)names; 32 | 33 | - (void)appendStructuresToString:(NSMutableString *)resultString; 34 | 35 | // Phase 0 - initiated from -[CDClassDump registerTypes] 36 | - (void)phase0RegisterStructure:(CDType *)structure usedInMethod:(BOOL)isUsedInMethod; 37 | 38 | // Run phase 1+ 39 | - (void)workSomeMagic; 40 | 41 | // Phase 1 42 | - (void)phase1RegisterStructure:(CDType *)structure; 43 | 44 | - (void)endPhase:(NSUInteger)phase; 45 | 46 | - (CDType *)phase2ReplacementForType:(CDType *)type; 47 | 48 | - (void)phase3RegisterStructure:(CDType *)structure; 49 | - (CDType *)phase3ReplacementForType:(CDType *)type; 50 | 51 | - (BOOL)shouldShowName:(NSString *)name; 52 | - (BOOL)shouldExpandType:(CDType *)type; 53 | - (NSString *)typedefNameForType:(CDType *)type; 54 | 55 | @end 56 | 57 | #pragma mark - 58 | 59 | @protocol CDTypeControllerDelegate 60 | @optional 61 | - (void)typeController:(CDTypeController *)typeController didReferenceClassName:(NSString *)name; 62 | - (void)typeController:(CDTypeController *)typeController didReferenceProtocolNames:(NSArray *)names; 63 | @end 64 | -------------------------------------------------------------------------------- /CDTypeFormatter.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @class CDType, CDTypeController; 7 | 8 | @interface CDTypeFormatter : NSObject 9 | 10 | @property (weak) CDTypeController *typeController; 11 | 12 | @property (assign) NSUInteger baseLevel; 13 | @property (assign) BOOL shouldExpand; 14 | @property (assign) BOOL shouldAutoExpand; 15 | @property (assign) BOOL shouldShowLexing; 16 | 17 | - (NSString *)formatVariable:(NSString *)name type:(CDType *)type; 18 | - (NSString *)formatMethodName:(NSString *)name typeString:(NSString *)typeString; 19 | 20 | - (NSString *)typedefNameForStructure:(CDType *)structureType level:(NSUInteger)level; 21 | 22 | - (void)formattingDidReferenceClassName:(NSString *)name; 23 | - (void)formattingDidReferenceProtocolNames:(NSArray *)names; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /CDTypeLexer.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #define TK_EOS 0 7 | #define TK_NUMBER 257 8 | #define TK_IDENTIFIER 258 9 | #define T_NAMED_OBJECT 259 10 | #define TK_QUOTED_STRING 260 11 | #define TK_TEMPLATE_TYPE TK_IDENTIFIER 12 | #define T_FUNCTION_POINTER_TYPE 1001 13 | #define T_BLOCK_TYPE 1002 14 | 15 | typedef enum : NSUInteger { 16 | CDTypeLexerState_Normal = 0, 17 | CDTypeLexerState_Identifier = 1, 18 | CDTypeLexerState_TemplateTypes = 2, 19 | } CDTypeLexerState; 20 | 21 | @interface CDTypeLexer : NSObject 22 | 23 | - (id)initWithString:(NSString *)string; 24 | 25 | @property (readonly) NSScanner *scanner; 26 | @property (nonatomic, assign) CDTypeLexerState state; 27 | @property (assign) BOOL shouldShowLexing; 28 | 29 | @property (nonatomic, readonly) NSString *string; 30 | - (int)scanNextToken; 31 | 32 | @property (strong) NSString *lexText; 33 | 34 | @property (nonatomic, readonly) unichar peekChar; 35 | @property (nonatomic, readonly) NSString *remainingString; 36 | @property (nonatomic, readonly) NSString *peekIdentifier; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /CDTypeLexer.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDTypeLexer.h" 7 | 8 | #import "NSScanner-CDExtensions.h" 9 | 10 | static BOOL debug = NO; 11 | 12 | static NSString *CDTypeLexerStateName(CDTypeLexerState state) 13 | { 14 | switch (state) { 15 | case CDTypeLexerState_Normal: return @"Normal"; 16 | case CDTypeLexerState_Identifier: return @"Identifier"; 17 | case CDTypeLexerState_TemplateTypes: return @"Template"; 18 | } 19 | } 20 | 21 | @implementation CDTypeLexer 22 | { 23 | NSScanner *_scanner; 24 | CDTypeLexerState _state; 25 | NSString *_lexText; 26 | 27 | BOOL _shouldShowLexing; 28 | } 29 | 30 | - (id)initWithString:(NSString *)string; 31 | { 32 | if ((self = [super init])) { 33 | _scanner = [[NSScanner alloc] initWithString:string]; 34 | [_scanner setCharactersToBeSkipped:nil]; 35 | _state = CDTypeLexerState_Normal; 36 | _shouldShowLexing = debug; 37 | } 38 | 39 | return self; 40 | } 41 | 42 | #pragma mark - 43 | 44 | - (void)setState:(CDTypeLexerState)newState; 45 | { 46 | if (debug) NSLog(@"CDTypeLexer - changing state from %lu (%@) to %lu (%@)", _state, CDTypeLexerStateName(_state), newState, CDTypeLexerStateName(newState)); 47 | _state = newState; 48 | } 49 | 50 | - (NSString *)string; 51 | { 52 | return [_scanner string]; 53 | } 54 | 55 | - (int)scanNextToken; 56 | { 57 | NSString *str; 58 | unichar ch; 59 | 60 | _lexText = nil; 61 | 62 | if ([_scanner isAtEnd]) { 63 | if (_shouldShowLexing) NSLog(@"%s [state=%lu], token = TK_EOS", _cmd, _state); 64 | return TK_EOS; 65 | } 66 | 67 | if (_state == CDTypeLexerState_TemplateTypes) { 68 | // Skip whitespace, scan '<', ',', '>'. Everything else is lumped together as a string. 69 | [_scanner setCharactersToBeSkipped:[NSCharacterSet whitespaceCharacterSet]]; 70 | if ([_scanner scanString:@"<" intoString:NULL]) { 71 | if (_shouldShowLexing) NSLog(@"%s [state=%lu], token = %d '%c'", _cmd, _state, '<', '<'); 72 | return '<'; 73 | } 74 | 75 | if ([_scanner scanString:@">" intoString:NULL]) { 76 | if (_shouldShowLexing) NSLog(@"%s [state=%lu], token = %d '%c'", _cmd, _state, '>', '>'); 77 | return '>'; 78 | } 79 | 80 | if ([_scanner scanString:@"," intoString:NULL]) { 81 | if (_shouldShowLexing) NSLog(@"%s [state=%lu], token = %d '%c'", _cmd, _state, ',', ','); 82 | return ','; 83 | } 84 | 85 | if ([_scanner my_scanCharactersFromSet:[NSScanner cdTemplateTypeCharacterSet] intoString:&str]) { 86 | _lexText = str; 87 | if (_shouldShowLexing) NSLog(@"%s [state=%lu], token = TK_TEMPLATE_TYPE (%@)", _cmd, _state, _lexText); 88 | return TK_TEMPLATE_TYPE; 89 | } 90 | 91 | NSLog(@"Ooops, fell through in template types state."); 92 | } else if (_state == CDTypeLexerState_Identifier) { 93 | NSString *identifier; 94 | 95 | //NSLog(@"Scanning in identifier state."); 96 | [_scanner setCharactersToBeSkipped:nil]; 97 | 98 | if ([_scanner scanIdentifierIntoString:&identifier]) { 99 | _lexText = identifier; 100 | if (_shouldShowLexing) NSLog(@"%s [state=%lu], token = TK_IDENTIFIER (%@)", _cmd, _state, _lexText); 101 | _state = CDTypeLexerState_Normal; 102 | return TK_IDENTIFIER; 103 | } 104 | } else { 105 | [_scanner setCharactersToBeSkipped:nil]; 106 | 107 | if ([_scanner scanString:@"\"" intoString:NULL]) { 108 | if ([_scanner scanUpToString:@"\"" intoString:&str]) 109 | _lexText = str; 110 | else 111 | _lexText = @""; 112 | 113 | [_scanner scanString:@"\"" intoString:NULL]; 114 | if (_shouldShowLexing) NSLog(@"%s [state=%lu], token = TK_QUOTED_STRING (%@)", _cmd, _state, _lexText); 115 | return TK_QUOTED_STRING; 116 | } 117 | 118 | if ([_scanner my_scanCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] intoString:&str]) { 119 | _lexText = str; 120 | if (_shouldShowLexing) NSLog(@"%s [state=%lu], token = TK_NUMBER (%@)", _cmd, _state, _lexText); 121 | return TK_NUMBER; 122 | } 123 | 124 | if ([_scanner scanCharacter:&ch]) { 125 | if (_shouldShowLexing) NSLog(@"%s [state=%lu], token = %d '%c'", _cmd, _state, ch, ch); 126 | return ch; 127 | } 128 | } 129 | 130 | if (_shouldShowLexing) NSLog(@"%s [state=%lu], token = TK_EOS", _cmd, _state); 131 | 132 | return TK_EOS; 133 | } 134 | 135 | - (unichar)peekChar; 136 | { 137 | return [_scanner peekChar]; 138 | } 139 | 140 | - (NSString *)remainingString; 141 | { 142 | return [[_scanner string] substringFromIndex:[_scanner scanLocation]]; 143 | } 144 | 145 | - (NSString *)peekIdentifier; 146 | { 147 | NSScanner *peekScanner = [[NSScanner alloc] initWithString:[_scanner string]]; 148 | [peekScanner setScanLocation:[_scanner scanLocation]]; 149 | 150 | NSString *identifier; 151 | if ([peekScanner scanIdentifierIntoString:&identifier]) { 152 | return identifier; 153 | } 154 | 155 | return nil; 156 | } 157 | 158 | @end 159 | -------------------------------------------------------------------------------- /CDTypeName.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @interface CDTypeName : NSObject 7 | 8 | @property (strong) NSString *name; 9 | @property (readonly) NSMutableArray *templateTypes; 10 | @property (strong) NSString *suffix; 11 | @property (nonatomic, readonly) BOOL isTemplateType; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CDTypeName.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDTypeName.h" 7 | 8 | @implementation CDTypeName 9 | { 10 | NSString *_name; 11 | NSMutableArray *_templateTypes; 12 | NSString *_suffix; 13 | } 14 | 15 | - (id)init; 16 | { 17 | if ((self = [super init])) { 18 | _name = nil; 19 | _templateTypes = [[NSMutableArray alloc] init]; 20 | _suffix = nil; 21 | } 22 | 23 | return self; 24 | } 25 | 26 | #pragma mark - NSCopying 27 | 28 | - (id)copyWithZone:(NSZone *)zone; 29 | { 30 | CDTypeName *copy = [[CDTypeName alloc] init]; 31 | copy.name = self.name; 32 | copy.suffix = self.suffix; 33 | 34 | for (CDTypeName *subtype in self.templateTypes) { 35 | CDTypeName *subcopy = [subtype copy]; 36 | [copy.templateTypes addObject:subcopy]; 37 | } 38 | 39 | return copy; 40 | } 41 | 42 | #pragma mark - 43 | 44 | - (BOOL)isEqual:(id)otherObject; 45 | { 46 | if ([otherObject isKindOfClass:[self class]] == NO) 47 | return NO; 48 | 49 | return [[self description] isEqual:[otherObject description]]; 50 | } 51 | 52 | #pragma mark - Debugging 53 | 54 | - (NSString *)description; 55 | { 56 | if ([self.templateTypes count] == 0) { 57 | return self.name ? self.name : @""; 58 | } 59 | 60 | if (self.suffix != nil) 61 | return [NSString stringWithFormat:@"%@<%@>%@", self.name, [self.templateTypes componentsJoinedByString:@", "], self.suffix]; 62 | 63 | return [NSString stringWithFormat:@"%@<%@>", self.name, [self.templateTypes componentsJoinedByString:@", "]]; 64 | } 65 | 66 | #pragma mark - 67 | 68 | - (BOOL)isTemplateType; 69 | { 70 | return [self.templateTypes count] > 0; 71 | } 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /CDTypeParser.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @class CDType, CDTypeLexer; 7 | 8 | extern NSString *CDExceptionName_SyntaxError; 9 | extern NSString *CDErrorDomain_TypeParser; 10 | 11 | extern NSString *CDErrorKey_Type; 12 | extern NSString *CDErrorKey_RemainingString; 13 | extern NSString *CDErrorKey_MethodOrVariable; 14 | extern NSString *CDErrorKey_LocalizedLongDescription; 15 | 16 | #define CDTypeParserCode_Default 0 17 | #define CDTypeParserCode_SyntaxError 1 18 | 19 | @interface CDTypeParser : NSObject 20 | 21 | - (id)initWithString:(NSString *)string; 22 | 23 | @property (readonly) CDTypeLexer *lexer; 24 | 25 | - (NSArray *)parseMethodType:(NSError **)error; 26 | - (CDType *)parseType:(NSError **)error; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /CDUnitTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.stevenygard.CDUnitTests 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleSignature 16 | ???? 17 | CFBundleVersion 18 | 1.0 19 | 20 | 21 | -------------------------------------------------------------------------------- /CDVisitor.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @class CDClassDump, CDObjectiveCProcessor, CDOCProtocol, CDOCMethod, CDOCInstanceVariable, CDOCClass, CDOCCategory, CDOCProperty; 7 | @class CDVisitorPropertyState; 8 | 9 | @interface CDVisitor : NSObject 10 | 11 | @property (strong) CDClassDump *classDump; 12 | 13 | - (void)willBeginVisiting; 14 | - (void)didEndVisiting; 15 | 16 | - (void)willVisitObjectiveCProcessor:(CDObjectiveCProcessor *)processor; 17 | - (void)visitObjectiveCProcessor:(CDObjectiveCProcessor *)processor; 18 | - (void)didVisitObjectiveCProcessor:(CDObjectiveCProcessor *)processor; 19 | 20 | - (void)willVisitProtocol:(CDOCProtocol *)protocol; 21 | - (void)didVisitProtocol:(CDOCProtocol *)protocol; 22 | 23 | - (void)willVisitPropertiesOfProtocol:(CDOCProtocol *)protocol; 24 | - (void)didVisitPropertiesOfProtocol:(CDOCProtocol *)protocol; 25 | 26 | - (void)willVisitOptionalMethods; 27 | - (void)didVisitOptionalMethods; 28 | 29 | - (void)willVisitClass:(CDOCClass *)aClass; 30 | - (void)didVisitClass:(CDOCClass *)aClass; 31 | 32 | - (void)willVisitIvarsOfClass:(CDOCClass *)aClass; 33 | - (void)didVisitIvarsOfClass:(CDOCClass *)aClass; 34 | 35 | - (void)willVisitPropertiesOfClass:(CDOCClass *)aClass; 36 | - (void)didVisitPropertiesOfClass:(CDOCClass *)aClass; 37 | 38 | - (void)willVisitCategory:(CDOCCategory *)category; 39 | - (void)didVisitCategory:(CDOCCategory *)category; 40 | 41 | - (void)willVisitPropertiesOfCategory:(CDOCCategory *)category; 42 | - (void)didVisitPropertiesOfCategory:(CDOCCategory *)category; 43 | 44 | - (void)visitClassMethod:(CDOCMethod *)method; 45 | - (void)visitInstanceMethod:(CDOCMethod *)method propertyState:(CDVisitorPropertyState *)propertyState; 46 | - (void)visitIvar:(CDOCInstanceVariable *)ivar; 47 | - (void)visitProperty:(CDOCProperty *)property; 48 | 49 | - (void)visitRemainingProperties:(CDVisitorPropertyState *)propertyState; 50 | 51 | @property (assign) BOOL shouldShowStructureSection; 52 | @property (assign) BOOL shouldShowProtocolSection; 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /CDVisitor.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDVisitor.h" 7 | 8 | #import "CDClassDump.h" 9 | 10 | @implementation CDVisitor 11 | { 12 | CDClassDump *_classDump; 13 | BOOL _shouldShowStructureSection; 14 | BOOL _shouldShowProtocolSection; 15 | } 16 | 17 | - (id)init; 18 | { 19 | if ((self = [super init])) { 20 | _shouldShowStructureSection = YES; 21 | _shouldShowProtocolSection = YES; 22 | } 23 | 24 | return self; 25 | } 26 | 27 | #pragma mark - 28 | 29 | - (void)willBeginVisiting; 30 | { 31 | } 32 | 33 | - (void)didEndVisiting; 34 | { 35 | } 36 | 37 | // Called before visiting. 38 | - (void)willVisitObjectiveCProcessor:(CDObjectiveCProcessor *)processor; 39 | { 40 | } 41 | 42 | // This gets called before visiting the children, but only if it has children it will visit. 43 | - (void)visitObjectiveCProcessor:(CDObjectiveCProcessor *)processor; 44 | { 45 | } 46 | 47 | - (void)willVisitPropertiesOfProtocol:(CDOCProtocol *)protocol; 48 | { 49 | } 50 | 51 | - (void)didVisitPropertiesOfProtocol:(CDOCProtocol *)protocol; 52 | { 53 | } 54 | 55 | - (void)willVisitOptionalMethods; 56 | { 57 | } 58 | 59 | - (void)didVisitOptionalMethods; 60 | { 61 | } 62 | 63 | // Called after visiting. 64 | - (void)didVisitObjectiveCProcessor:(CDObjectiveCProcessor *)processor; 65 | { 66 | } 67 | 68 | - (void)willVisitProtocol:(CDOCProtocol *)protocol; 69 | { 70 | } 71 | 72 | - (void)didVisitProtocol:(CDOCProtocol *)protocol; 73 | { 74 | } 75 | 76 | - (void)willVisitClass:(CDOCClass *)aClass; 77 | { 78 | } 79 | 80 | - (void)didVisitClass:(CDOCClass *)aClass; 81 | { 82 | } 83 | 84 | - (void)willVisitIvarsOfClass:(CDOCClass *)aClass; 85 | { 86 | } 87 | 88 | - (void)didVisitIvarsOfClass:(CDOCClass *)aClass; 89 | { 90 | } 91 | 92 | - (void)willVisitPropertiesOfClass:(CDOCClass *)aClass; 93 | { 94 | } 95 | 96 | - (void)didVisitPropertiesOfClass:(CDOCClass *)aClass; 97 | { 98 | } 99 | 100 | - (void)willVisitCategory:(CDOCCategory *)category; 101 | { 102 | } 103 | 104 | - (void)didVisitCategory:(CDOCCategory *)category; 105 | { 106 | } 107 | 108 | - (void)willVisitPropertiesOfCategory:(CDOCCategory *)category; 109 | { 110 | } 111 | 112 | - (void)didVisitPropertiesOfCategory:(CDOCCategory *)category; 113 | { 114 | } 115 | 116 | - (void)visitClassMethod:(CDOCMethod *)method; 117 | { 118 | } 119 | 120 | - (void)visitInstanceMethod:(CDOCMethod *)method propertyState:(CDVisitorPropertyState *)propertyState; 121 | { 122 | } 123 | 124 | - (void)visitIvar:(CDOCInstanceVariable *)ivar; 125 | { 126 | } 127 | 128 | - (void)visitProperty:(CDOCProperty *)property; 129 | { 130 | } 131 | 132 | - (void)visitRemainingProperties:(CDVisitorPropertyState *)propertyState; 133 | { 134 | } 135 | 136 | @end 137 | -------------------------------------------------------------------------------- /CDVisitorPropertyState.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @class CDOCProperty; 7 | 8 | @interface CDVisitorPropertyState : NSObject 9 | 10 | - (id)initWithProperties:(NSArray *)properties; 11 | 12 | - (CDOCProperty *)propertyForAccessor:(NSString *)str; 13 | 14 | - (BOOL)hasUsedProperty:(CDOCProperty *)property; 15 | - (void)useProperty:(CDOCProperty *)property; 16 | 17 | @property (nonatomic, readonly) NSArray *remainingProperties; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /CDVisitorPropertyState.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "CDVisitorPropertyState.h" 7 | 8 | #import "CDOCProperty.h" 9 | 10 | @interface CDVisitorPropertyState () 11 | @end 12 | 13 | #pragma mark - 14 | 15 | @implementation CDVisitorPropertyState 16 | { 17 | NSMutableDictionary *_propertiesByAccessor; // NSString (accessor) -> CDOCProperty 18 | NSMutableDictionary *_propertiesByName; // NSString (property name) -> CDOCProperty 19 | } 20 | 21 | - (id)initWithProperties:(NSArray *)properties; 22 | { 23 | if ((self = [super init])) { 24 | _propertiesByAccessor = [[NSMutableDictionary alloc] init]; 25 | _propertiesByName = [[NSMutableDictionary alloc] init]; 26 | 27 | for (CDOCProperty *property in properties) { 28 | //NSLog(@"property: %@, getter: %@, setter: %@", [property name], [property getter], [property setter]); 29 | _propertiesByName[property.name] = property; 30 | _propertiesByAccessor[property.getter] = property; 31 | if (property.isReadOnly == NO) 32 | _propertiesByAccessor[property.setter] = property; 33 | } 34 | } 35 | 36 | return self; 37 | } 38 | 39 | #pragma mark - Debugging 40 | 41 | - (void)log; 42 | { 43 | NSLog(@"propertiesByAccessor: %@", _propertiesByAccessor); 44 | NSLog(@"propertiesByName: %@", _propertiesByName); 45 | } 46 | 47 | #pragma mark - 48 | 49 | - (CDOCProperty *)propertyForAccessor:(NSString *)str; 50 | { 51 | return _propertiesByAccessor[str]; 52 | } 53 | 54 | - (BOOL)hasUsedProperty:(CDOCProperty *)property; 55 | { 56 | return _propertiesByName[property.name] == nil; 57 | } 58 | 59 | - (void)useProperty:(CDOCProperty *)property; 60 | { 61 | [_propertiesByName removeObjectForKey:property.name]; 62 | } 63 | 64 | - (NSArray *)remainingProperties; 65 | { 66 | return [[_propertiesByName allValues] sortedArrayUsingSelector:@selector(ascendingCompareByName:)]; 67 | } 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleIdentifier 8 | com.stevenygard.class-dump 9 | CFBundleInfoDictionaryVersion 10 | 6.0 11 | CFBundleName 12 | class-dump 13 | 14 | 15 | -------------------------------------------------------------------------------- /MachObjC-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'libMachObjC' target in the 'class-dump' project. 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import "CDExtensions.h" 8 | #define _cmd __PRETTY_FUNCTION__ 9 | #endif 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GO_EASY_ON_ME=1 2 | THEOS_DEVICE_IP=192.168.15.12 3 | DEBUG=1 4 | FINALPACKAGE=0 5 | include $(THEOS)/makefiles/common.mk 6 | 7 | TOOL_NAME = classdumpios 8 | classdumpios_CFLAGS = -fobjc-arc -include ext.h 9 | #CDFatArch.m_CFLAGS = -fobjc-arc 10 | #CDTypeFormatter.m_CFLAGS = -fobjc-arc 11 | #CDSymbol.m_CFLAGS = -fobjc-arc 12 | #CDTypeController.m_CFLAGS = -fobjc-arc 13 | #CDLoadCommand.m_CFLAGS = -fobjc-arc 14 | #CDSection.m_CFLAGS = -fobjc-arc 15 | #CDStructureTable.m_CFLAGS = -fobjc-arc 16 | 17 | classdumpios_FRAMEWORKS = UIKit 18 | classdumpios_FILES = $(wildcard *.*m) 19 | 20 | include $(THEOS_MAKE_PATH)/tool.mk 21 | -------------------------------------------------------------------------------- /NSArray-CDExtensions.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @interface NSArray (CDExtensions) 7 | 8 | - (NSArray *)reversedArray; 9 | 10 | @end 11 | 12 | @interface NSArray (CDTopoSort) 13 | 14 | - (NSArray *)topologicallySortedArray; 15 | 16 | @end 17 | 18 | @interface NSMutableArray (CDTopoSort) 19 | 20 | - (void)sortTopologically; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /NSArray-CDExtensions.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "NSArray-CDExtensions.h" 7 | 8 | #import "CDTopologicalSortProtocol.h" 9 | #import "CDTopoSortNode.h" 10 | 11 | @implementation NSArray (CDExtensions) 12 | 13 | - (NSArray *)reversedArray; 14 | { 15 | return [[self reverseObjectEnumerator] allObjects]; 16 | } 17 | 18 | @end 19 | 20 | #pragma mark - 21 | 22 | @implementation NSArray (CDTopoSort) 23 | 24 | - (NSArray *)topologicallySortedArray; 25 | { 26 | NSMutableDictionary *nodesByName = [[NSMutableDictionary alloc] init]; 27 | 28 | for (id object in self) { 29 | CDTopoSortNode *node = [[CDTopoSortNode alloc] initWithObject:object]; 30 | [node addDependanciesFromArray:[object dependancies]]; 31 | 32 | if (nodesByName[node.identifier] != nil) 33 | NSLog(@"Warning: Duplicate identifier (%@) in %s", node.identifier, _cmd); 34 | nodesByName[node.identifier] = node; 35 | } 36 | 37 | NSMutableArray *sortedArray = [NSMutableArray array]; 38 | 39 | NSArray *allNodes = [[nodesByName allValues] sortedArrayUsingSelector:@selector(ascendingCompareByIdentifier:)]; 40 | for (CDTopoSortNode *node in allNodes) { 41 | if (node.color == CDNodeColor_White) 42 | [node topologicallySortNodes:nodesByName intoArray:sortedArray]; 43 | } 44 | 45 | 46 | return sortedArray; 47 | } 48 | 49 | @end 50 | 51 | #pragma mark - 52 | 53 | @implementation NSMutableArray (CDTopoSort) 54 | 55 | - (void)sortTopologically; 56 | { 57 | NSArray *sortedArray = [self topologicallySortedArray]; 58 | assert([self count] == [sortedArray count]); 59 | 60 | [self removeAllObjects]; 61 | [self addObjectsFromArray:sortedArray]; 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /NSData-CDExtensions.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @interface NSData (CDExtensions) 7 | 8 | - (NSString *)hexString; 9 | - (NSData *)SHA1Digest; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /NSData-CDExtensions.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "NSData-CDExtensions.h" 7 | 8 | #import 9 | 10 | @implementation NSData (CDExtensions) 11 | 12 | - (NSString *)hexString; 13 | { 14 | NSMutableString *str = [NSMutableString string]; 15 | const uint8_t *ptr = [self bytes]; 16 | for (NSUInteger index = 0; index < [self length]; index++) { 17 | [str appendFormat:@"%02x", *ptr++]; 18 | } 19 | 20 | return str; 21 | } 22 | 23 | - (NSData *)SHA1Digest; 24 | { 25 | NSParameterAssert([self length] <= UINT32_MAX); 26 | 27 | unsigned char digest[CC_SHA1_DIGEST_LENGTH]; 28 | CC_SHA1([self bytes], (CC_LONG)[self length], digest); 29 | 30 | return [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH]; 31 | } 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /NSError-CDExtensions.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @interface NSError (CDExtensions) 7 | 8 | @end 9 | 10 | extern NSString *NSErrorDomain_ClassDump; 11 | -------------------------------------------------------------------------------- /NSError-CDExtensions.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "NSError-CDExtensions.h" 7 | 8 | NSString *NSErrorDomain_ClassDump = @"com.stevenygard.MachObjC.ErrorDomain"; 9 | 10 | @implementation NSError (CDExtensions) 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /NSScanner-CDExtensions.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @interface NSScanner (CDExtensions) 7 | 8 | + (NSCharacterSet *)cdOtherCharacterSet; 9 | + (NSCharacterSet *)cdIdentifierStartCharacterSet; 10 | + (NSCharacterSet *)cdIdentifierCharacterSet; 11 | + (NSCharacterSet *)cdTemplateTypeCharacterSet; 12 | 13 | - (NSString *)peekCharacter; 14 | - (unichar)peekChar; 15 | - (BOOL)scanCharacter:(unichar *)value; 16 | - (BOOL)scanCharacterFromSet:(NSCharacterSet *)set intoString:(NSString **)value; 17 | - (BOOL)my_scanCharactersFromSet:(NSCharacterSet *)set intoString:(NSString **)value; 18 | 19 | - (BOOL)scanIdentifierIntoString:(NSString **)stringPointer; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /NSScanner-CDExtensions.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "NSScanner-CDExtensions.h" 7 | #import "NSString-CDExtensions.h" 8 | @implementation NSScanner (CDExtensions) 9 | 10 | // other: $_:* 11 | // start: alpha + other 12 | // remainder: alnum + other 13 | 14 | + (NSCharacterSet *)cdOtherCharacterSet; 15 | { 16 | static NSCharacterSet *otherCharacterSet = nil; 17 | 18 | if (otherCharacterSet == nil) 19 | otherCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"$_:*"]; 20 | 21 | return otherCharacterSet; 22 | } 23 | 24 | + (NSCharacterSet *)cdIdentifierStartCharacterSet; 25 | { 26 | static NSCharacterSet *identifierStartCharacterSet = nil; 27 | 28 | if (identifierStartCharacterSet == nil) { 29 | NSMutableCharacterSet *set = [[NSCharacterSet letterCharacterSet] mutableCopy]; 30 | [set formUnionWithCharacterSet:[NSScanner cdOtherCharacterSet]]; 31 | identifierStartCharacterSet = [set copy]; 32 | } 33 | 34 | return identifierStartCharacterSet; 35 | } 36 | 37 | + (NSCharacterSet *)cdIdentifierCharacterSet; 38 | { 39 | static NSCharacterSet *identifierCharacterSet = nil; 40 | 41 | if (identifierCharacterSet == nil) { 42 | NSMutableCharacterSet *set = [[NSCharacterSet alphanumericCharacterSet] mutableCopy]; 43 | [set formUnionWithCharacterSet:[NSScanner cdOtherCharacterSet]]; 44 | identifierCharacterSet = [set copy]; 45 | } 46 | 47 | return identifierCharacterSet; 48 | } 49 | 50 | + (NSCharacterSet *)cdTemplateTypeCharacterSet; 51 | { 52 | static NSCharacterSet *templateTypeCharacterSet = nil; 53 | 54 | if (templateTypeCharacterSet == nil) 55 | templateTypeCharacterSet = [[NSCharacterSet characterSetWithCharactersInString:@"<,>"] invertedSet]; 56 | 57 | return templateTypeCharacterSet; 58 | } 59 | 60 | - (NSString *)peekCharacter; 61 | { 62 | //[self skipCharacters]; 63 | 64 | if ([self isAtEnd]) 65 | return nil; 66 | 67 | return [[self string] substringWithRange:NSMakeRange([self scanLocation], 1)]; 68 | } 69 | 70 | - (unichar)peekChar; 71 | { 72 | return [[self string] characterAtIndex:[self scanLocation]]; 73 | } 74 | 75 | - (BOOL)scanCharacter:(unichar *)value; 76 | { 77 | //[self skipCharacters]; 78 | 79 | if ([self isAtEnd]) 80 | return NO; 81 | 82 | unichar ch = [[self string] characterAtIndex:[self scanLocation]]; 83 | if (value != NULL) 84 | *value = ch; 85 | 86 | [self setScanLocation:[self scanLocation] + 1]; 87 | 88 | return YES; 89 | } 90 | 91 | - (BOOL)scanCharacterFromSet:(NSCharacterSet *)set intoString:(NSString *__autoreleasing *)value; 92 | { 93 | //[self skipCharacters]; 94 | 95 | if ([self isAtEnd]) 96 | return NO; 97 | 98 | unichar ch = [[self string] characterAtIndex:[self scanLocation]]; 99 | if ([set characterIsMember:ch]) { 100 | if (value != NULL) { 101 | *value = [NSString stringWithUnichar:ch]; 102 | } 103 | 104 | [self setScanLocation:[self scanLocation] + 1]; 105 | return YES; 106 | } 107 | 108 | return NO; 109 | } 110 | 111 | // On 10.3 (7D24) the Foundation scanCharactersFromSet:intoString: inverts the set each call, creating an autoreleased CFCharacterSet. 112 | // This cuts the total CFCharacterSet allocations (when run on Foundation) from 161682 down to 17. 113 | 114 | // This works for my purposes, but I haven't tested it to make sure it's fully compatible with the standard version. 115 | 116 | - (BOOL)my_scanCharactersFromSet:(NSCharacterSet *)set intoString:(NSString *__autoreleasing *)value; 117 | { 118 | NSUInteger currentLocation = [self scanLocation]; 119 | 120 | // Skip over characters 121 | NSCharacterSet *skipSet = [self charactersToBeSkipped]; 122 | while ([self isAtEnd] == NO) { 123 | unichar ch = [[self string] characterAtIndex:currentLocation]; 124 | if ([skipSet characterIsMember:ch] == NO) 125 | break; 126 | 127 | currentLocation++; 128 | [self setScanLocation:currentLocation]; 129 | } 130 | 131 | NSRange matchedRange = NSMakeRange(currentLocation, 0); 132 | 133 | while ([self isAtEnd] == NO) { 134 | unichar ch = [[self string] characterAtIndex:currentLocation]; 135 | if ([set characterIsMember:ch] == NO) 136 | break; 137 | 138 | currentLocation++; 139 | [self setScanLocation:currentLocation]; 140 | } 141 | 142 | matchedRange.length = currentLocation - matchedRange.location; 143 | 144 | if (matchedRange.length == 0) 145 | return NO; 146 | 147 | if (value != NULL) { 148 | *value = [[self string] substringWithRange:matchedRange]; 149 | } 150 | 151 | return YES; 152 | } 153 | 154 | - (BOOL)scanIdentifierIntoString:(NSString *__autoreleasing *)stringPointer; 155 | { 156 | NSString *start, *remainder; 157 | 158 | if ([self scanString:@"?" intoString:stringPointer]) { 159 | return YES; 160 | } 161 | 162 | if ([self scanCharacterFromSet:[NSScanner cdIdentifierStartCharacterSet] intoString:&start]) { 163 | NSString *str; 164 | 165 | if ([self my_scanCharactersFromSet:[NSScanner cdIdentifierCharacterSet] intoString:&remainder]) { 166 | str = [start stringByAppendingString:remainder]; 167 | } else { 168 | str = start; 169 | } 170 | 171 | if (stringPointer != NULL) 172 | *stringPointer = str; 173 | 174 | return YES; 175 | } 176 | 177 | return NO; 178 | } 179 | 180 | @end 181 | -------------------------------------------------------------------------------- /NSString-CDExtensions.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | @interface NSString (CDExtensions) 7 | 8 | + (NSString *)stringWithFileSystemRepresentation:(const char *)str; 9 | + (NSString *)spacesIndentedToLevel:(NSUInteger)level; 10 | + (NSString *)spacesIndentedToLevel:(NSUInteger)level spacesPerLevel:(NSUInteger)spacesPerLevel; 11 | + (NSString *)stringWithUnichar:(unichar)character; 12 | 13 | - (BOOL)isFirstLetterUppercase; 14 | 15 | - (void)print; 16 | 17 | - (NSString *)executablePathForFilename; 18 | 19 | - (NSString *)SHA1DigestString; 20 | 21 | - (BOOL)hasUnderscoreCapitalPrefix; 22 | - (NSString *)capitalizeFirstCharacter; 23 | 24 | @end 25 | 26 | @interface NSMutableString (CDExtensions) 27 | 28 | - (void)appendSpacesIndentedToLevel:(NSUInteger)level; 29 | - (void)appendSpacesIndentedToLevel:(NSUInteger)level spacesPerLevel:(NSUInteger)spacesPerLevel; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /NSString-CDExtensions.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "NSString-CDExtensions.h" 7 | #import "NSData-CDExtensions.h" 8 | @implementation NSString (CDExtensions) 9 | 10 | + (NSString *)stringWithFileSystemRepresentation:(const char *)str; 11 | { 12 | // 2004-01-16: I'm don't understand why we need to pass in the length. 13 | return [[NSFileManager defaultManager] stringWithFileSystemRepresentation:str length:strlen(str)]; 14 | } 15 | 16 | + (NSString *)spacesIndentedToLevel:(NSUInteger)level; 17 | { 18 | return [self spacesIndentedToLevel:level spacesPerLevel:4]; 19 | } 20 | 21 | + (NSString *)spacesIndentedToLevel:(NSUInteger)level spacesPerLevel:(NSUInteger)spacesPerLevel; 22 | { 23 | NSString *spaces = @" "; 24 | 25 | NSParameterAssert(spacesPerLevel <= [spaces length]); 26 | NSString *levelSpaces = [spaces substringToIndex:spacesPerLevel]; 27 | 28 | NSMutableString *str = [NSMutableString string]; 29 | for (NSUInteger l = 0; l < level; l++) 30 | [str appendString:levelSpaces]; 31 | 32 | return str; 33 | } 34 | 35 | + (NSString *)stringWithUnichar:(unichar)character; 36 | { 37 | return [NSString stringWithCharacters:&character length:1]; 38 | } 39 | 40 | - (BOOL)isFirstLetterUppercase; 41 | { 42 | NSRange letterRange = [self rangeOfCharacterFromSet:[NSCharacterSet letterCharacterSet]]; 43 | if (letterRange.length == 0) 44 | return NO; 45 | 46 | return [[NSCharacterSet uppercaseLetterCharacterSet] characterIsMember:[self characterAtIndex:letterRange.location]]; 47 | } 48 | 49 | - (void)print; 50 | { 51 | NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding]; 52 | [(NSFileHandle *)[NSFileHandle fileHandleWithStandardOutput] writeData:data]; 53 | } 54 | 55 | - (NSString *)executablePathForFilename; 56 | { 57 | NSString *path; 58 | 59 | // I give up, all the methods dealing with paths seem to resolve symlinks with a vengence. 60 | NSBundle *bundle = [NSBundle bundleWithPath:self]; 61 | if (bundle != nil) { 62 | if ([bundle executablePath] == nil) 63 | return nil; 64 | 65 | path = [[[bundle executablePath] stringByResolvingSymlinksInPath] stringByStandardizingPath]; 66 | } else { 67 | path = [[self stringByResolvingSymlinksInPath] stringByStandardizingPath]; 68 | } 69 | 70 | return path; 71 | } 72 | 73 | - (NSString *)SHA1DigestString; 74 | { 75 | return [[[[self decomposedStringWithCanonicalMapping] dataUsingEncoding:NSUTF8StringEncoding] SHA1Digest] hexString]; 76 | } 77 | 78 | - (BOOL)hasUnderscoreCapitalPrefix; 79 | { 80 | if ([self length] < 2) 81 | return NO; 82 | 83 | return [self hasPrefix:@"_"] && [[NSCharacterSet uppercaseLetterCharacterSet] characterIsMember:[self characterAtIndex:1]]; 84 | } 85 | 86 | - (NSString *)capitalizeFirstCharacter; 87 | { 88 | if ([self length] < 2) 89 | return [self capitalizedString]; 90 | 91 | return [NSString stringWithFormat:@"%@%@", [[self substringToIndex:1] capitalizedString], [self substringFromIndex:1]]; 92 | } 93 | 94 | @end 95 | 96 | @implementation NSMutableString (CDExtensions) 97 | 98 | - (void)appendSpacesIndentedToLevel:(NSUInteger)level; 99 | { 100 | [self appendSpacesIndentedToLevel:level spacesPerLevel:4]; 101 | } 102 | 103 | - (void)appendSpacesIndentedToLevel:(NSUInteger)level spacesPerLevel:(NSUInteger)spacesPerLevel; 104 | { 105 | NSString *spaces = @" "; 106 | 107 | NSParameterAssert(spacesPerLevel <= [spaces length]); 108 | NSString *levelSpaces = [spaces substringToIndex:spacesPerLevel]; 109 | 110 | for (NSUInteger l = 0; l < level; l++) 111 | [self appendString:levelSpaces]; 112 | } 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | class-dump-ios 2 | ========== 3 | 4 | This is a port for Theos build by me. 5 | 6 | class-dump is a command-line utility for examining the Objective-C 7 | segment of Mach-O files. It generates declarations for the classes, 8 | categories and protocols. This is the same information provided by 9 | using 'otool -ov', but presented as normal Objective-C declarations. 10 | 11 | The latest version and information is available at: 12 | 13 | http://stevenygard.com/projects/class-dump 14 | 15 | Usage 16 | ----- 17 | 18 | class-dump-ios 1.0.1 (64 bit) 19 | Usage: classdumpios [options] 20 | 21 | where options are: 22 | -a show instance variable offsets 23 | -A show implementation addresses 24 | --arch choose a specific architecture from a universal binary (ppc, ppc64, i386, x86_64) 25 | -C only display classes matching regular expression 26 | -f find string in method name 27 | -H generate header files in current directory, or directory specified with -o 28 | -I sort classes, categories, and protocols by inheritance (overrides -s) 29 | -o output directory used for -H 30 | -r recursively expand frameworks and fixed VM shared libraries 31 | -s sort classes and categories by name 32 | -S sort methods by name 33 | -t suppress header in output, for testing 34 | --list-arches list the arches in the file, then exit 35 | --sdk-ios specify iOS SDK version (will look in /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk 36 | --sdk-mac specify Mac OS X version (will look in /Developer/SDKs/MacOSX.sdk 37 | --sdk-root specify the full SDK root path (or use --sdk-ios/--sdk-mac for a shortcut) 38 | 39 | - class-dump-ios AppKit: 40 | 41 | classdumpios /System/Library/Frameworks/AppKit.framework 42 | 43 | - class-dump-ios UIKit: 44 | 45 | classdumpios /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/UIKit.framework 46 | 47 | - class-dump-ios UIKit and all the frameworks it uses: 48 | 49 | classdumpios /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/UIKit.framework -r --sdk-ios 4.3 50 | 51 | - class-dump-ios UIKit (and all the frameworks it uses) from developer tools that have been installed in /Dev42 instead of /Developer: 52 | 53 | classdumpios /Dev42/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/UIKit.framework -r --sdk-root /Dev42/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk 54 | 55 | 56 | License 57 | ------- 58 | 59 | This file is part of class-dump, a utility for examining the 60 | Objective-C segment of Mach-O files. 61 | Copyright (C) 1997-2019 Steve Nygard. 62 | 63 | This program is free software; you can redistribute it and/or modify 64 | it under the terms of the GNU General Public License as published by 65 | the Free Software Foundation; either version 2 of the License, or 66 | (at your option) any later version. 67 | 68 | This program is distributed in the hope that it will be useful, 69 | but WITHOUT ANY WARRANTY; without even the implied warranty of 70 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 71 | GNU General Public License for more details. 72 | 73 | You should have received a copy of the GNU General Public License 74 | along with this program; if not, write to the Free Software 75 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -------------------------------------------------------------------------------- /ULEB128.h: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | // http://en.wikipedia.org/wiki/LEB128 7 | // http://web.mit.edu/rhel-doc/3/rhel-as-en-3/uleb128.html 8 | // uleb128 stands for "unsigned little endian base 128." 9 | // This is a compact, variable length representation of numbers used by the DWARF symbolic debugging format. 10 | 11 | // Top bit of byte is set until last byte. 12 | // Other 7 bits are the "slice". 13 | // Basically, it represents the low order bits 7 at a time, and can stop when the rest of the bits would be zero. 14 | // This needs to modify ptr. 15 | 16 | // For example, uleb with these bytes: e8 d7 15 17 | // 0xe8 = 1110 1000 18 | // 0xd7 = 1101 0111 19 | // 0x15 = 0001 0101 20 | 21 | // .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... 22 | // 0xe8 1 1101000 .... .... .... .... .... .... .... .... .... .... .... .... .... .... .110 1000 23 | // 0xd7 1 1010111 .... .... .... .... .... .... .... .... .... .... .... .... ..10 1011 1110 1000 24 | // 0x15 0 0010101 .... .... .... .... .... .... .... .... .... .... .... .... ..10 1011 1110 1000 25 | // 0x15 0 0010101 .... .... .... .... .... .... .... .... .... .... ...0 0101 0110 1011 1110 1000 26 | // Result is: 0x056be8 27 | // So... 24 bits to encode 64 bits 28 | 29 | uint64_t read_uleb128(const uint8_t **ptrptr, const uint8_t *end); 30 | 31 | int64_t read_sleb128(const uint8_t **ptrptr, const uint8_t *end); 32 | -------------------------------------------------------------------------------- /ULEB128.m: -------------------------------------------------------------------------------- 1 | // -*- mode: ObjC -*- 2 | 3 | // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. 4 | // Copyright (C) 1997-2019 Steve Nygard. 5 | 6 | #import "ULEB128.h" 7 | 8 | uint64_t read_uleb128(const uint8_t **ptrptr, const uint8_t *end) 9 | { 10 | const uint8_t *ptr = *ptrptr; 11 | uint64_t result = 0; 12 | int bit = 0; 13 | 14 | //NSLog(@"read_uleb128()"); 15 | do { 16 | NSCAssert(ptr != end, @"Malformed uleb128", nil); 17 | 18 | //NSLog(@"byte: %02x", *ptr); 19 | uint64_t slice = *ptr & 0x7f; 20 | 21 | if (bit >= 64 || slice << bit >> bit != slice) { 22 | NSLog(@"uleb128 too big"); 23 | exit(88); 24 | } else { 25 | result |= (slice << bit); 26 | bit += 7; 27 | } 28 | } 29 | while ((*ptr++ & 0x80) != 0); 30 | 31 | #if 0 32 | static NSUInteger maxlen = 0; 33 | if (maxlen < ptr - *ptrptr) { 34 | const uint8_t *ptr2 = *ptrptr; 35 | 36 | NSMutableArray *byteStrs = [NSMutableArray array]; 37 | do { 38 | [byteStrs addObject:[NSString stringWithFormat:@"%02x", *ptr2]]; 39 | } while (++ptr2 < ptr); 40 | //NSLog(@"max uleb length now: %u (%@)", ptr - *ptrptr, [byteStrs componentsJoinedByString:@" "]); 41 | //NSLog(@"sizeof(uint64_t): %u, sizeof(uintptr_t): %u", sizeof(uint64_t), sizeof(uintptr_t)); 42 | maxlen = ptr - *ptrptr; 43 | } 44 | #endif 45 | 46 | *ptrptr = ptr; 47 | return result; 48 | } 49 | 50 | int64_t read_sleb128(const uint8_t **ptrptr, const uint8_t *end) 51 | { 52 | const uint8_t *ptr = *ptrptr; 53 | 54 | int64_t result = 0; 55 | int bit = 0; 56 | uint8_t byte; 57 | 58 | //NSLog(@"read_sleb128()"); 59 | do { 60 | NSCAssert(ptr != end, @"Malformed sleb128", nil); 61 | 62 | byte = *ptr++; 63 | //NSLog(@"%02x", byte); 64 | result |= ((byte & 0x7f) << bit); 65 | bit += 7; 66 | } while ((byte & 0x80) != 0); 67 | 68 | //NSLog(@"result before sign extend: %ld", result); 69 | // sign extend negative numbers 70 | // This essentially clears out from -1 the low order bits we've already set, and combines that with our bits. 71 | if ( (byte & 0x40) != 0 ) 72 | result |= (-1LL) << bit; 73 | 74 | //NSLog(@"result after sign extend: %ld", result); 75 | 76 | //NSLog(@"ptr before: %p, after: %p", *ptrptr, ptr); 77 | *ptrptr = ptr; 78 | return result; 79 | } 80 | -------------------------------------------------------------------------------- /cd_objc2.h: -------------------------------------------------------------------------------- 1 | struct cd_objc2_list_header { 2 | uint32_t entsize; 3 | uint32_t count; 4 | }; 5 | 6 | struct cd_objc2_image_info { 7 | uint32_t version; 8 | uint32_t flags; 9 | }; 10 | 11 | 12 | // 13 | // 64-bit, also holding 32-bit 14 | // 15 | 16 | struct cd_objc2_class { 17 | uint64_t isa; 18 | uint64_t superclass; 19 | uint64_t cache; 20 | uint64_t vtable; 21 | uint64_t data; // points to class_ro_t 22 | uint64_t reserved1; 23 | uint64_t reserved2; 24 | uint64_t reserved3; 25 | }; 26 | 27 | struct cd_objc2_class_ro_t { 28 | uint32_t flags; 29 | uint32_t instanceStart; 30 | uint32_t instanceSize; 31 | uint32_t reserved; // *** this field does not exist in the 32-bit version *** 32 | uint64_t ivarLayout; 33 | uint64_t name; 34 | uint64_t baseMethods; 35 | uint64_t baseProtocols; 36 | uint64_t ivars; 37 | uint64_t weakIvarLayout; 38 | uint64_t baseProperties; 39 | }; 40 | 41 | struct cd_objc2_method { 42 | uint64_t name; 43 | uint64_t types; 44 | uint64_t imp; 45 | }; 46 | 47 | struct cd_objc2_ivar { 48 | uint64_t offset; 49 | uint64_t name; 50 | uint64_t type; 51 | uint32_t alignment; 52 | uint32_t size; 53 | }; 54 | 55 | struct cd_objc2_property { 56 | uint64_t name; 57 | uint64_t attributes; 58 | }; 59 | 60 | struct cd_objc2_protocol { 61 | uint64_t isa; 62 | uint64_t name; 63 | uint64_t protocols; 64 | uint64_t instanceMethods; 65 | uint64_t classMethods; 66 | uint64_t optionalInstanceMethods; 67 | uint64_t optionalClassMethods; 68 | uint64_t instanceProperties; // So far, always 0 69 | uint32_t size; // sizeof(cd_objc2_protocol) 70 | uint32_t flags; 71 | uint64_t extendedMethodTypes; 72 | }; 73 | 74 | struct cd_objc2_category { 75 | uint64_t name; 76 | uint64_t class; 77 | uint64_t instanceMethods; 78 | uint64_t classMethods; 79 | uint64_t protocols; 80 | uint64_t instanceProperties; 81 | uint64_t v7; 82 | uint64_t v8; 83 | }; 84 | -------------------------------------------------------------------------------- /class-dump-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'class-dump' target in the 'class-dump' project. 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import "CDExtensions.h" 8 | #define _cmd __PRETTY_FUNCTION__ 9 | #endif 10 | -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Package: io.github.ddv.class-dump-ios 2 | Name: class-dump-ios 3 | Depends: 4 | Version: 1.0.1 5 | Architecture: iphoneos-arm 6 | Description: class-dump is a command-line utility for examining the Objective-C segment of Mach-O files. It generates declarations for the classes, categories and protocols. This is the same information provided by using 'otool -ov', but presented as normal Objective-C declarations. 7 | Maintainer: DreamDevLost 8 | Author: DreamDevLost 9 | Section: System 10 | Tag: role::hacker 11 | -------------------------------------------------------------------------------- /ext.h: -------------------------------------------------------------------------------- 1 | #include "NSString-CDExtensions.h" 2 | #include "NSArray-CDExtensions.h" 3 | #include "NSData-CDExtensions.h" 4 | #include "NSError-CDExtensions.h" 5 | #include "NSScanner-CDExtensions.h" 6 | 7 | //#import "blowfish.h" -------------------------------------------------------------------------------- /keys.txt: -------------------------------------------------------------------------------- 1 | APPNAME=class-dump 2 | SHORT_DESCRIPTION=a utility for examining the Objective-C segment of Mach-O files 3 | OWNER=Steve Nygard 4 | COPYRIGHT=Copyright (C) 1997-2019 Steve Nygard. 5 | --------------------------------------------------------------------------------