diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..b9a2fb6f Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..9ef96044 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build + diff --git a/CDFatArch64.h b/CDFatArch64.h new file mode 100644 index 00000000..a567630d --- /dev/null +++ b/CDFatArch64.h @@ -0,0 +1,34 @@ +// -*- mode: ObjC -*- + +// This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. +// Copyright (C) 1997-2019 Steve Nygard. + +#import "CDFile.h" // For CDArch + +@class CDDataCursor; +@class CDFatFile, CDMachOFile; + +@interface CDFatArch64 : NSObject + +- (id)initWithMachOFile:(CDMachOFile *)machOFile bigendian:(bool)isBigEndian; +- (id)initWithDataCursor:(CDDataCursor *)cursor bigendian:(bool)isBigEndian; + +@property (assign) cpu_type_t cputype; +@property (assign) cpu_subtype_t cpusubtype; +@property (assign) uint64_t offset; +@property (assign) uint64_t size; +@property (assign) uint32_t align; + +@property (nonatomic, readonly) cpu_type_t maskedCPUType; +@property (nonatomic, readonly) cpu_subtype_t maskedCPUSubtype; +@property (nonatomic, readonly) BOOL uses64BitABI; +@property (nonatomic, readonly) BOOL uses64BitLibraries; + +@property (weak) CDFatFile *fatFile; + +@property (nonatomic, readonly) CDArch arch; +@property (nonatomic, readonly) NSString *archName; + +@property (nonatomic, readonly) CDMachOFile *machOFile; + +@end diff --git a/CDFatArch64.m b/CDFatArch64.m new file mode 100644 index 00000000..9727f3cb --- /dev/null +++ b/CDFatArch64.m @@ -0,0 +1,137 @@ +// -*- mode: ObjC -*- + +// This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. +// Copyright (C) 1997-2019 Steve Nygard. + +#import "CDFatArch64.h" + +#include +#import "CDDataCursor.h" +#import "CDFatFile.h" +#import "CDMachOFile.h" + +@implementation CDFatArch64 +{ + __weak CDFatFile *_fatFile; + bool _isSwapped; + + // This is essentially struct fat_arch, but this way our property accessors can be synthesized. + cpu_type_t _cputype; + cpu_subtype_t _cpusubtype; + uint64_t _offset; + uint64_t _size; + uint32_t _align; + uint32_t _reserved; + + CDMachOFile *_machOFile; // Lazily create this. +} + +- (id)initWithMachOFile:(CDMachOFile *)machOFile bigendian:(bool)isBigEndian +{ + if ((self = [super init])) { + _machOFile = machOFile; + + if (isBigEndian == true) { + _cputype = _machOFile.cputype; + _cpusubtype = _machOFile.cpusubtype; + _offset = 0; // Would be filled in when this is written to disk + _size = (uint64_t)[_machOFile.data length]; + _align = 12; // 2**12 = 4096 (0x1000) + _reserved = 0; + _isSwapped = false; + } else { + _cputype = OSSwapInt32(_machOFile.cputype); + _cpusubtype = OSSwapInt32(_machOFile.cpusubtype); + _offset = 0; // Would be filled in when this is written to disk + _size = OSSwapInt64((uint64_t)[_machOFile.data length]); + _align = 0x0C000000; // 2**12 = 4096 (0x1000) + _reserved = 0; + _isSwapped = true; + } + } + + return self; +} + +- (id)initWithDataCursor:(CDDataCursor *)cursor bigendian:(bool)isBigEndian +{ + if ((self = [super init])) { + if (isBigEndian == true) { + _cputype = [cursor readBigInt32]; + _cpusubtype = [cursor readBigInt32]; + _offset = [cursor readBigInt64]; + _size = [cursor readBigInt64]; + _align = [cursor readBigInt32]; + _reserved = [cursor readBigInt32]; + _isSwapped = false; + } else { + _cputype = [cursor readLittleInt32]; + _cpusubtype = [cursor readLittleInt32]; + _offset = [cursor readLittleInt64]; + _size = [cursor readLittleInt64]; + _align = [cursor readLittleInt32]; + _reserved = [cursor readLittleInt32]; + _isSwapped = true; + } + + //NSLog(@"self: %@", self); + } + + return self; +} + +#pragma mark - Debugging + +- (NSString *)description; +{ + return [NSString stringWithFormat:@"64 bit ABI? %d, cputype: 0x%08x, cpusubtype: 0x%08x, offset: 0x%16llx (%16llu), size: 0x%16llx (%16llu), align: 2^%u (%x), arch name: %@", + self.uses64BitABI, self.cputype, self.cpusubtype, self.offset, self.offset, self.size, self.size, + self.align, 1 << self.align, self.archName]; +} + +#pragma mark - + +- (cpu_type_t)maskedCPUType; +{ + return self.cputype & ~CPU_ARCH_MASK; +} + +- (cpu_subtype_t)maskedCPUSubtype; +{ + return self.cpusubtype & ~CPU_SUBTYPE_MASK; +} + +- (BOOL)uses64BitABI; +{ + return CDArchUses64BitABI(self.arch); +} + +- (BOOL)uses64BitLibraries; +{ + return CDArchUses64BitLibraries(self.arch); +} + +- (CDArch)arch; +{ + CDArch arch = { self.cputype, self.cpusubtype }; + + return arch; +} + +// Must not return nil. +- (NSString *)archName; +{ + return CDNameForCPUType(self.cputype, self.cpusubtype); +} + +- (CDMachOFile *)machOFile; +{ + if (_machOFile == nil) { + NSData *data = [NSData dataWithBytesNoCopy:((uint8_t *)[self.fatFile.data bytes] + self.offset) length:self.size freeWhenDone:NO]; + _machOFile = [[CDMachOFile alloc] initWithData:data filename:self.fatFile.filename searchPathState:self.fatFile.searchPathState isCache:NO]; + } + + return _machOFile; +} + +@end diff --git a/Source/.DS_Store b/Source/.DS_Store new file mode 100644 index 00000000..39f428e2 Binary files /dev/null and b/Source/.DS_Store differ diff --git a/Source/CDClassDump.m b/Source/CDClassDump.m index 882a9508..f7540cee 100644 --- a/Source/CDClassDump.m +++ b/Source/CDClassDump.m @@ -18,10 +18,14 @@ #import "CDTypeController.h" #import "CDSearchPathState.h" +#include + NSString *CDErrorDomain_ClassDump = @"CDErrorDomain_ClassDump"; NSString *CDErrorKey_Exception = @"CDErrorKey_Exception"; +extern NSString *cacheName; + @interface CDClassDump () @end @@ -201,6 +205,8 @@ - (void)recursivelyVisit:(CDVisitor *)visitor; [visitor didEndVisiting]; } +extern intptr_t _dyld_get_image_slide(const struct mach_header* mh); + - (CDMachOFile *)machOFileWithName:(NSString *)name; { NSString *adjustedName = nil; @@ -232,7 +238,13 @@ - (CDMachOFile *)machOFileWithName:(NSString *)name; CDMachOFile *machOFile = _machOFilesByName[adjustedName]; if (machOFile == nil) { - CDFile *file = [CDFile fileWithContentsOfFile:adjustedName searchPathState:self.searchPathState]; + CDFile *file = nil; + + if (cacheName != nil) + file = [CDFile fileWithContentsOfFile:adjustedName cache:cacheName searchPathState:self.searchPathState isCache:YES]; + + if (file == nil) + file = [CDFile fileWithContentsOfFile:adjustedName cache:nil searchPathState:self.searchPathState isCache:NO]; if (file == nil || [self loadFile:file error:NULL] == NO) NSLog(@"Warning: Failed to load: %@", adjustedName); diff --git a/Source/CDDataCursor.m b/Source/CDDataCursor.m index abd60a48..47b74f4f 100644 --- a/Source/CDDataCursor.m +++ b/Source/CDDataCursor.m @@ -30,15 +30,28 @@ - (const void *)bytes; - (void)setOffset:(NSUInteger)newOffset; { - if (newOffset <= [_data length]) { - _offset = newOffset; - } else { - [NSException raise:NSRangeException format:@"Trying to seek past end of data."]; + if (newOffset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + _offset = -'S'; + } + else + { + if (newOffset <= [_data length]) { + _offset = newOffset; + } else { + [NSException raise:NSRangeException format:@"Trying to seek past end of data."]; + } } } - (void)advanceByLength:(NSUInteger)length; { + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + _offset += 10; + return; + } + if (_offset + length <= [_data length]) { _offset += length; } else { @@ -57,6 +70,11 @@ - (uint8_t)readByte; { uint8_t result; + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + return 0; + } + if (_offset + sizeof(result) <= [_data length]) { result = OSReadLittleInt16([_data bytes], _offset) & 0xFF; _offset += sizeof(result); @@ -72,6 +90,11 @@ - (uint16_t)readLittleInt16; { uint16_t result; + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + return 0; + } + if (_offset + sizeof(result) <= [_data length]) { result = OSReadLittleInt16([_data bytes], _offset); _offset += sizeof(result); @@ -87,6 +110,11 @@ - (uint32_t)readLittleInt32; { uint32_t result; + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + return 0; + } + if (_offset + sizeof(result) <= [_data length]) { result = OSReadLittleInt32([_data bytes], _offset); _offset += sizeof(result); @@ -102,6 +130,11 @@ - (uint64_t)readLittleInt64; { uint64_t result; + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + return 0; + } + if (_offset + sizeof(result) <= [_data length]) { // uint8_t *ptr = [_data bytes] + _offset; // NSLog(@"%016llx: %02x %02x %02x %02x %02x %02x %02x %02x", _offset, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7]); @@ -119,6 +152,11 @@ - (uint16_t)readBigInt16; { uint16_t result; + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + return 0; + } + if (_offset + sizeof(result) <= [_data length]) { result = OSReadBigInt16([_data bytes], _offset); _offset += sizeof(result); @@ -134,6 +172,11 @@ - (uint32_t)readBigInt32; { uint32_t result; + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + return 0; + } + if (_offset + sizeof(result) <= [_data length]) { result = OSReadBigInt32([_data bytes], _offset); _offset += sizeof(result); @@ -149,6 +192,11 @@ - (uint64_t)readBigInt64; { uint64_t result; + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + return 0; + } + if (_offset + sizeof(result) <= [_data length]) { result = OSReadBigInt64([_data bytes], _offset); _offset += sizeof(result); @@ -192,6 +240,11 @@ - (double)readLittleFloat64; - (void)appendBytesOfLength:(NSUInteger)length intoData:(NSMutableData *)data; { + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + return; + } + if (_offset + length <= [_data length]) { [data appendBytes:(uint8_t *)[_data bytes] + _offset length:length]; _offset += length; @@ -202,6 +255,11 @@ - (void)appendBytesOfLength:(NSUInteger)length intoData:(NSMutableData *)data; - (void)readBytesOfLength:(NSUInteger)length intoBuffer:(void *)buf; { + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + return; + } + if (_offset + length <= [_data length]) { memcpy(buf, (uint8_t *)[_data bytes] + _offset, length); _offset += length; @@ -217,6 +275,11 @@ - (BOOL)isAtEnd; - (NSString *)readCString; { + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + return @"Swift"; + } + return [self readStringOfLength:strlen((const char *)[_data bytes] + _offset) encoding:NSASCIIStringEncoding]; } @@ -248,6 +311,11 @@ - (NSString *)readStringOfLength:(NSUInteger)length encoding:(NSStringEncoding)e return str; } } else { + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at 2 of %s",__cmd); + return @"Swift"; + } + [NSException raise:NSRangeException format:@"Trying to read past end in %s", __cmd]; } diff --git a/Source/CDFatArch.h b/Source/CDFatArch.h index 6d920f82..dafd6cec 100644 --- a/Source/CDFatArch.h +++ b/Source/CDFatArch.h @@ -10,8 +10,8 @@ @interface CDFatArch : NSObject -- (id)initWithMachOFile:(CDMachOFile *)machOFile; -- (id)initWithDataCursor:(CDDataCursor *)cursor; +- (id)initWithMachOFile:(CDMachOFile *)machOFile bigendian:(bool)isBigEndian; +- (id)initWithDataCursor:(CDDataCursor *)cursor bigendian:(bool)isBigEndian; @property (assign) cpu_type_t cputype; @property (assign) cpu_subtype_t cpusubtype; diff --git a/Source/CDFatArch.m b/Source/CDFatArch.m index cc7f2a17..827e9ea3 100644 --- a/Source/CDFatArch.m +++ b/Source/CDFatArch.m @@ -24,31 +24,47 @@ @implementation CDFatArch CDMachOFile *_machOFile; // Lazily create this. } -- (id)initWithMachOFile:(CDMachOFile *)machOFile; +- (id)initWithMachOFile:(CDMachOFile *)machOFile bigendian:(bool)isBigEndian { if ((self = [super init])) { _machOFile = machOFile; NSParameterAssert([machOFile.data length] < 0x100000000); - - _cputype = _machOFile.cputype; - _cpusubtype = _machOFile.cpusubtype; - _offset = 0; // Would be filled in when this is written to disk - _size = (uint32_t)[_machOFile.data length]; - _align = 12; // 2**12 = 4096 (0x1000) + + if (isBigEndian == false) { + _cputype = OSSwapInt32(_machOFile.cputype); + _cpusubtype = OSSwapInt32(_machOFile.cpusubtype); + _offset = 0; // Would be filled in when this is written to disk + _size = OSSwapInt32((uint32_t)[_machOFile.data length]); + _align = 0x0C000000; + } else { + _cputype = _machOFile.cputype; + _cpusubtype = _machOFile.cpusubtype; + _offset = 0; // Would be filled in when this is written to disk + _size = (uint32_t)[_machOFile.data length]; + _align = 12; // 2**12 = 4096 (0x1000) + } } return self; } -- (id)initWithDataCursor:(CDDataCursor *)cursor; +- (id)initWithDataCursor:(CDDataCursor *)cursor bigendian:(bool)isBigEndian { if ((self = [super init])) { - _cputype = [cursor readBigInt32]; - _cpusubtype = [cursor readBigInt32]; - _offset = [cursor readBigInt32]; - _size = [cursor readBigInt32]; - _align = [cursor readBigInt32]; - + if (isBigEndian == false) { + _cputype = [cursor readLittleInt32]; + _cpusubtype = [cursor readLittleInt32]; + _offset = [cursor readLittleInt32]; + _size = [cursor readLittleInt32]; + _align = [cursor readLittleInt32]; + } else { + _cputype = [cursor readBigInt32]; + _cpusubtype = [cursor readBigInt32]; + _offset = [cursor readBigInt32]; + _size = [cursor readBigInt32]; + _align = [cursor readBigInt32]; + } + //NSLog(@"self: %@", self); } @@ -103,7 +119,7 @@ - (CDMachOFile *)machOFile; { if (_machOFile == nil) { NSData *data = [NSData dataWithBytesNoCopy:((uint8_t *)[self.fatFile.data bytes] + self.offset) length:self.size freeWhenDone:NO]; - _machOFile = [[CDMachOFile alloc] initWithData:data filename:self.fatFile.filename searchPathState:self.fatFile.searchPathState]; + _machOFile = [[CDMachOFile alloc] initWithData:data filename:self.fatFile.filename searchPathState:self.fatFile.searchPathState isCache:NO]; } return _machOFile; diff --git a/Source/CDFatArch64.h b/Source/CDFatArch64.h new file mode 100644 index 00000000..a567630d --- /dev/null +++ b/Source/CDFatArch64.h @@ -0,0 +1,34 @@ +// -*- mode: ObjC -*- + +// This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. +// Copyright (C) 1997-2019 Steve Nygard. + +#import "CDFile.h" // For CDArch + +@class CDDataCursor; +@class CDFatFile, CDMachOFile; + +@interface CDFatArch64 : NSObject + +- (id)initWithMachOFile:(CDMachOFile *)machOFile bigendian:(bool)isBigEndian; +- (id)initWithDataCursor:(CDDataCursor *)cursor bigendian:(bool)isBigEndian; + +@property (assign) cpu_type_t cputype; +@property (assign) cpu_subtype_t cpusubtype; +@property (assign) uint64_t offset; +@property (assign) uint64_t size; +@property (assign) uint32_t align; + +@property (nonatomic, readonly) cpu_type_t maskedCPUType; +@property (nonatomic, readonly) cpu_subtype_t maskedCPUSubtype; +@property (nonatomic, readonly) BOOL uses64BitABI; +@property (nonatomic, readonly) BOOL uses64BitLibraries; + +@property (weak) CDFatFile *fatFile; + +@property (nonatomic, readonly) CDArch arch; +@property (nonatomic, readonly) NSString *archName; + +@property (nonatomic, readonly) CDMachOFile *machOFile; + +@end diff --git a/Source/CDFatArch64.m b/Source/CDFatArch64.m new file mode 100644 index 00000000..def75122 --- /dev/null +++ b/Source/CDFatArch64.m @@ -0,0 +1,112 @@ +// -*- mode: ObjC -*- + +// This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. +// Copyright (C) 1997-2019 Steve Nygard. + +#import "CDFatArch.h" + +#include +#import "CDDataCursor.h" +#import "CDFatFile.h" +#import "CDMachOFile.h" + +@implementation CDFatArch64 +{ + __weak CDFatFile *_fatFile; + + // This is essentially struct fat_arch, but this way our property accessors can be synthesized. + cpu_type_t _cputype; + cpu_subtype_t _cpusubtype; + uint64_t _offset; + uint64_t _size; + uint32_t _align; + + CDMachOFile *_machOFile; // Lazily create this. +} + +- (id)initWithMachOFile:(CDMachOFile *)machOFile; +{ + if ((self = [super init])) { + _machOFile = machOFile; + NSParameterAssert([machOFile.data length] < 0x100000000); + + _cputype = _machOFile.cputype; + _cpusubtype = _machOFile.cpusubtype; + _offset = 0; // Would be filled in when this is written to disk + _size = (uint64_t)[_machOFile.data length]; + _align = 12; // 2**12 = 4096 (0x1000) + } + + return self; +} + +- (id)initWithDataCursor:(CDDataCursor *)cursor; +{ + if ((self = [super init])) { + _cputype = [cursor readBigInt32]; + _cpusubtype = [cursor readBigInt32]; + _offset = [cursor readBigInt64]; + _size = [cursor readBigInt64]; + _align = [cursor readBigInt32]; + + //NSLog(@"self: %@", self); + } + + return self; +} + +#pragma mark - Debugging + +- (NSString *)description; +{ + 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: %@", + self.uses64BitABI, self.cputype, self.cpusubtype, self.offset, self.offset, self.size, self.size, + self.align, 1 << self.align, self.archName]; +} + +#pragma mark - + +- (cpu_type_t)maskedCPUType; +{ + return self.cputype & ~CPU_ARCH_MASK; +} + +- (cpu_subtype_t)maskedCPUSubtype; +{ + return self.cpusubtype & ~CPU_SUBTYPE_MASK; +} + +- (BOOL)uses64BitABI; +{ + return CDArchUses64BitABI(self.arch); +} + +- (BOOL)uses64BitLibraries; +{ + return CDArchUses64BitLibraries(self.arch); +} + +- (CDArch)arch; +{ + CDArch arch = { self.cputype, self.cpusubtype }; + + return arch; +} + +// Must not return nil. +- (NSString *)archName; +{ + return CDNameForCPUType(self.cputype, self.cpusubtype); +} + +- (CDMachOFile *)machOFile; +{ + if (_machOFile == nil) { + NSData *data = [NSData dataWithBytesNoCopy:((uint8_t *)[self.fatFile.data bytes] + self.offset) length:self.size freeWhenDone:NO]; + _machOFile = [[CDMachOFile alloc] initWithData:data filename:self.fatFile.filename searchPathState:self.fatFile.searchPathState]; + } + + return _machOFile; +} + +@end diff --git a/Source/CDFatFile.h b/Source/CDFatFile.h index d5a8d08c..95184ce3 100644 --- a/Source/CDFatFile.h +++ b/Source/CDFatFile.h @@ -5,14 +5,18 @@ #import "CDFile.h" -@class CDFatArch; +@class CDFatArch, CDFatArch64; @interface CDFatFile : CDFile @property (readonly) NSMutableArray *arches; @property (nonatomic, readonly) NSArray *archNames; +@property (nonatomic, readonly) bool isFat64; +@property (nonatomic, readonly) bool isSwapped; +@property (readonly) BOOL isCache; - (void)addArchitecture:(CDFatArch *)fatArch; +- (void)addArchitecture64:(CDFatArch64 *)fatArch; - (BOOL)containsArchitecture:(CDArch)arch; @end diff --git a/Source/CDFatFile.m b/Source/CDFatFile.m index 5b806ebb..da25da8e 100644 --- a/Source/CDFatFile.m +++ b/Source/CDFatFile.m @@ -9,12 +9,15 @@ #include #import "CDDataCursor.h" +#import "CDFatArch64.h" #import "CDFatArch.h" #import "CDMachOFile.h" @implementation CDFatFile { NSMutableArray *_arches; + bool _isFat64; + bool _isSwapped; } - (id)init; @@ -26,27 +29,56 @@ - (id)init; return self; } -- (id)initWithData:(NSData *)data filename:(NSString *)filename searchPathState:(CDSearchPathState *)searchPathState; +- (id)initWithData:(NSData *)data filename:(NSString *)filename searchPathState:(CDSearchPathState *)searchPathState isCache:(BOOL)aIsCache; { - if ((self = [super initWithData:data filename:filename searchPathState:searchPathState])) { + if ((self = [super initWithData:data filename:filename searchPathState:searchPathState isCache:aIsCache])) { CDDataCursor *cursor = [[CDDataCursor alloc] initWithData:data]; struct fat_header header; header.magic = [cursor readBigInt32]; - + + if ((header.magic == FAT_CIGAM) || (header.magic == FAT_CIGAM_64)) { + _isSwapped = true; + } else { + _isSwapped = false; + } + //NSLog(@"(testing fat) magic: 0x%x", header.magic); - if (header.magic != FAT_MAGIC) { + if ((header.magic != FAT_MAGIC) && (header.magic != FAT_MAGIC_64) && (header.magic != FAT_CIGAM) && (header.magic != FAT_CIGAM_64)) { return nil; } - + _arches = [[NSMutableArray alloc] init]; - - header.nfat_arch = [cursor readBigInt32]; + + if (_isSwapped == true) { + header.nfat_arch = [cursor readLittleInt32]; + } else { + header.nfat_arch = [cursor readBigInt32]; + } + //NSLog(@"nfat_arch: %u", header.nfat_arch); for (NSUInteger index = 0; index < header.nfat_arch; index++) { - CDFatArch *arch = [[CDFatArch alloc] initWithDataCursor:cursor]; - arch.fatFile = self; - [_arches addObject:arch]; + if (header.magic == FAT_MAGIC) { + CDFatArch *arch = [[CDFatArch alloc] initWithDataCursor:cursor bigendian:true]; + arch.fatFile = self; + [_arches addObject:arch]; + _isFat64 = false; + } else if (header.magic == FAT_CIGAM) { + CDFatArch *arch = [[CDFatArch alloc] initWithDataCursor:cursor bigendian:false]; + arch.fatFile = self; + [_arches addObject:arch]; + _isFat64 = false; + } else if (header.magic == FAT_CIGAM_64) { + CDFatArch64 *arch = [[CDFatArch64 alloc] initWithDataCursor:cursor bigendian:false]; + arch.fatFile = self; + [_arches addObject:arch]; + _isFat64 = true; + } else { + CDFatArch64 *arch = [[CDFatArch64 alloc] initWithDataCursor:cursor bigendian:true]; + arch.fatFile = self; + [_arches addObject:arch]; + _isFat64 = true; + } } } @@ -78,37 +110,77 @@ - (NSString *)description; // Returns YES on success, NO on failure. - (BOOL)bestMatchForArch:(CDArch *)ioArchPtr; { - cpu_type_t targetType = ioArchPtr->cputype & ~CPU_ARCH_MASK; + cpu_type_t targetType = 0; - // Target architecture, 64 bit - for (CDFatArch *fatArch in self.arches) { - if (fatArch.maskedCPUType == targetType && fatArch.uses64BitABI) { - if (ioArchPtr != NULL) *ioArchPtr = fatArch.arch; - return YES; - } + if (_isSwapped == true) { + targetType = OSSwapInt32(ioArchPtr->cputype) & OSSwapInt32(~CPU_ARCH_MASK); + } else { + targetType = ioArchPtr->cputype & ~CPU_ARCH_MASK; } - // Target architecture, 32 bit - for (CDFatArch *fatArch in self.arches) { - if (fatArch.maskedCPUType == targetType && fatArch.uses64BitABI == NO) { - if (ioArchPtr != NULL) *ioArchPtr = fatArch.arch; - return YES; + if (_isFat64 == false) { + // Target architecture, 64 bit + for (CDFatArch *fatArch in self.arches) { + if (fatArch.maskedCPUType == targetType && fatArch.uses64BitABI) { + if (ioArchPtr != NULL) *ioArchPtr = fatArch.arch; + return YES; + } } - } - // Any architecture, 64 bit - for (CDFatArch *fatArch in self.arches) { - if (fatArch.uses64BitABI) { - if (ioArchPtr != NULL) *ioArchPtr = fatArch.arch; - return YES; + // Target architecture, 32 bit + for (CDFatArch *fatArch in self.arches) { + if (fatArch.maskedCPUType == targetType && fatArch.uses64BitABI == NO) { + if (ioArchPtr != NULL) *ioArchPtr = fatArch.arch; + return YES; + } + } + + // Any architecture, 64 bit + for (CDFatArch *fatArch in self.arches) { + if (fatArch.uses64BitABI) { + if (ioArchPtr != NULL) *ioArchPtr = fatArch.arch; + return YES; + } + } + + // Any architecture, 32 bit + for (CDFatArch *fatArch in self.arches) { + if (fatArch.uses64BitABI == NO) { + if (ioArchPtr != NULL) *ioArchPtr = fatArch.arch; + return YES; + } + } + } else { + // Target architecture, 64 bit + for (CDFatArch64 *fatArch in self.arches) { + if (fatArch.maskedCPUType == targetType && fatArch.uses64BitABI) { + if (ioArchPtr != NULL) *ioArchPtr = fatArch.arch; + return YES; + } + } + + // Target architecture, 32 bit + for (CDFatArch64 *fatArch in self.arches) { + if (fatArch.maskedCPUType == targetType && fatArch.uses64BitABI == NO) { + if (ioArchPtr != NULL) *ioArchPtr = fatArch.arch; + return YES; + } + } + + // Any architecture, 64 bit + for (CDFatArch64 *fatArch in self.arches) { + if (fatArch.uses64BitABI) { + if (ioArchPtr != NULL) *ioArchPtr = fatArch.arch; + return YES; + } } - } - // Any architecture, 32 bit - for (CDFatArch *fatArch in self.arches) { - if (fatArch.uses64BitABI == NO) { - if (ioArchPtr != NULL) *ioArchPtr = fatArch.arch; - return YES; + // Any architecture, 32 bit + for (CDFatArch64 *fatArch in self.arches) { + if (fatArch.uses64BitABI == NO) { + if (ioArchPtr != NULL) *ioArchPtr = fatArch.arch; + return YES; + } } } @@ -121,6 +193,16 @@ - (BOOL)bestMatchForArch:(CDArch *)ioArchPtr; return NO; } +- (CDFatArch64 *)fatArchWithArch64:(CDArch)cdarch; +{ + for (CDFatArch64 *arch in self.arches) { + if (arch.cputype == cdarch.cputype && arch.maskedCPUSubtype == (cdarch.cpusubtype & ~CPU_SUBTYPE_MASK)) + return arch; + } + + return nil; +} + - (CDFatArch *)fatArchWithArch:(CDArch)cdarch; { for (CDFatArch *arch in self.arches) { @@ -133,6 +215,10 @@ - (CDFatArch *)fatArchWithArch:(CDArch)cdarch; - (CDMachOFile *)machOFileWithArch:(CDArch)cdarch; { + if (_isFat64 == true) { + return [[self fatArchWithArch64:cdarch] machOFile]; + } + return [[self fatArchWithArch:cdarch] machOFile]; } @@ -152,6 +238,12 @@ - (NSString *)architectureNameDescription; #pragma mark - +- (void)addArchitecture64:(CDFatArch64 *)fatArch; +{ + fatArch.fatFile = self; + [self.arches addObject:fatArch]; +} + - (void)addArchitecture:(CDFatArch *)fatArch; { fatArch.fatFile = self; @@ -160,6 +252,10 @@ - (void)addArchitecture:(CDFatArch *)fatArch; - (BOOL)containsArchitecture:(CDArch)arch; { + if (_isFat64 == true) { + return [self fatArchWithArch64:arch] != nil; + } + return [self fatArchWithArch:arch] != nil; } diff --git a/Source/CDFile.h b/Source/CDFile.h index 15e2930e..bdf1116f 100644 --- a/Source/CDFile.h +++ b/Source/CDFile.h @@ -21,9 +21,9 @@ BOOL CDArchUses64BitLibraries(CDArch arch); @interface CDFile : NSObject // Returns CDFatFile or CDMachOFile -+ (id)fileWithContentsOfFile:(NSString *)filename searchPathState:(CDSearchPathState *)searchPathState; ++ (id)fileWithContentsOfFile:(NSString *)filename cache:(NSString *)cache searchPathState:(CDSearchPathState *)searchPathState isCache:(BOOL)aIsCache; -- (id)initWithData:(NSData *)data filename:(NSString *)filename searchPathState:(CDSearchPathState *)searchPathState; +- (id)initWithData:(NSData *)data filename:(NSString *)filename searchPathState:(CDSearchPathState *)searchPathState isCache:(BOOL)aIsCache; @property (readonly) NSString *filename; @property (readonly) NSData *data; diff --git a/Source/CDFile.m b/Source/CDFile.m index 44a952c3..46aa6cec 100644 --- a/Source/CDFile.m +++ b/Source/CDFile.m @@ -41,9 +41,23 @@ } break; } - case CPU_TYPE_ARM | CPU_ARCH_ABI64: { + case CPU_TYPE_X86_64: { switch (cpusubtype) { - case CPU_SUBTYPE_ARM_ALL: return @"arm64"; // Not recognized in 10.8.4 + case CPU_SUBTYPE_X86_64_ALL: return @"x86_64"; // Not recognized in 10.8.4 + case CPU_SUBTYPE_X86_64_H: return @"x86_64h"; // Not recognized in 10.8.4 + } + break; + } + case CPU_TYPE_ARM64: { + switch (cpusubtype) { + case CPU_SUBTYPE_ARM64_ALL: return @"arm64"; // Not recognized in 10.8.4 + case CPU_SUBTYPE_ARM64E: return @"arm64e"; // Not recognized in 10.8.4 + } + break; + } + case CPU_TYPE_ARM64_32: { + switch (cpusubtype) { + case CPU_SUBTYPE_ARM64_32_ALL: return @"arm64_32"; // Not recognized in 10.8.4 } break; } @@ -66,12 +80,27 @@ CDArch CDArchFromName(NSString *name) const NXArchInfo *archInfo = NXGetArchInfoFromName([name UTF8String]); if (archInfo == NULL) { - if ([name isEqualToString:@"armv7s"]) { // Not recognized in 10.8.4 + if ([name isEqualToString:@"arm64"]) { // Not recognized in 10.8.4 + arch.cputype = CPU_TYPE_ARM64; + arch.cpusubtype = CPU_SUBTYPE_ARM64_ALL; + } else if ([name isEqualToString:@"arm64e"]) { // Not recognized in 10.8.4 + arch.cputype = CPU_TYPE_ARM64; + arch.cpusubtype = CPU_SUBTYPE_ARM64E; + } else if ([name isEqualToString:@"arm64_32"]) { // Not recognized in 10.8.4 + arch.cputype = CPU_TYPE_ARM64_32; + arch.cpusubtype = CPU_SUBTYPE_ARM64_32_ALL; + } else if ([name isEqualToString:@"armv7s"]) { // Not recognized in 10.8.4 arch.cputype = CPU_TYPE_ARM; arch.cpusubtype = 11; - } else if ([name isEqualToString:@"arm64"]) { // Not recognized in 10.8.4 - arch.cputype = CPU_TYPE_ARM | CPU_ARCH_ABI64; - arch.cpusubtype = CPU_SUBTYPE_ARM_ALL; + } else if ([name isEqualToString:@"x86_64"]) { // Not recognized in 10.8.4 + arch.cputype = CPU_TYPE_X86_64; + arch.cpusubtype = CPU_SUBTYPE_X86_64_ALL; + } else if ([name isEqualToString:@"x86_64h"]) { // Not recognized in 10.8.4 + arch.cputype = CPU_TYPE_X86_64; + arch.cpusubtype = CPU_SUBTYPE_X86_64_H; + } else if ([name isEqualToString:@"i386"]) { // Not recognized in 10.8.4 + arch.cputype = CPU_TYPE_I386; + arch.cpusubtype = CPU_SUBTYPE_I386_ALL; } else { NSString *ignore; @@ -116,21 +145,37 @@ @implementation CDFile NSString *_filename; NSData *_data; CDSearchPathState *_searchPathState; + BOOL isCache; } // Returns CDFatFile or CDMachOFile -+ (id)fileWithContentsOfFile:(NSString *)filename searchPathState:(CDSearchPathState *)searchPathState; ++ (id)fileWithContentsOfFile:(NSString *)filename cache:(NSString *)cache searchPathState:(CDSearchPathState *)searchPathState isCache:(BOOL)aIsCache; { - NSData *data = [NSData dataWithContentsOfMappedFile:filename]; - CDFatFile *fatFile = [[CDFatFile alloc] initWithData:data filename:filename searchPathState:searchPathState]; +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101000 + NSData *data = nil; + + if (cache != nil) + data = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:cache] options:NSDataReadingMappedIfSafe error:nil]; + else + data = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:filename] options:NSDataReadingMappedIfSafe error:nil]; +#else + NSData *data = nil; + + if (cache != nil) + data = [NSData dataWithContentsOfMappedFile:cache]; + else + data = [NSData dataWithContentsOfMappedFile:filename]; +#endif + + CDFatFile *fatFile = [[CDFatFile alloc] initWithData:data filename:filename searchPathState:searchPathState isCache:aIsCache]; if (fatFile != nil) return fatFile; - CDMachOFile *machOFile = [[CDMachOFile alloc] initWithData:data filename:filename searchPathState:searchPathState]; + CDMachOFile *machOFile = [[CDMachOFile alloc] initWithData:data filename:filename searchPathState:searchPathState isCache:aIsCache]; return machOFile; } -- (id)initWithData:(NSData *)data filename:(NSString *)filename searchPathState:(CDSearchPathState *)searchPathState; +- (id)initWithData:(NSData *)data filename:(NSString *)filename searchPathState:(CDSearchPathState *)searchPathState isCache:(BOOL)aIsCache; { if ((self = [super init])) { // Otherwise reading the magic number fails. @@ -141,6 +186,7 @@ - (id)initWithData:(NSData *)data filename:(NSString *)filename searchPathState: _filename = filename; _data = data; _searchPathState = searchPathState; + isCache = aIsCache; } return self; diff --git a/Source/CDLCBuildVersion.m b/Source/CDLCBuildVersion.m index a635c82d..4644aab6 100644 --- a/Source/CDLCBuildVersion.m +++ b/Source/CDLCBuildVersion.m @@ -10,15 +10,38 @@ static NSString *NSStringFromBuildVersionPlatform(uint32_t platform) { switch (platform) { - case PLATFORM_MACOS: return @"macOS"; - case PLATFORM_IOS: return @"iOS"; - case PLATFORM_TVOS: return @"tvOS"; - case PLATFORM_WATCHOS: return @"watchOS"; - case PLATFORM_BRIDGEOS: return @"bridgeOS"; - case PLATFORM_IOSMAC: return @"iOS Mac"; - case PLATFORM_IOSSIMULATOR: return @"iOS Simulator"; - case PLATFORM_TVOSSIMULATOR: return @"tvOS Simulator"; - case PLATFORM_WATCHOSSIMULATOR: return @"watchOS Simulator"; + case PLATFORM_ANY: return @"any"; + case PLATFORM_MACOS: return @"macOS"; + case PLATFORM_IOS: return @"iOS"; + case PLATFORM_TVOS: return @"tvOS"; + case PLATFORM_WATCHOS: return @"watchOS"; + case PLATFORM_BRIDGEOS: return @"bridgeOS"; +#ifndef PLATFORM_IOSMAC + case PLATFORM_MACCATALYST: return @"macCatalyst"; +#else /* PLATFORM_IOSMAC */ + case PLATFORM_IOSMAC: return @"iOS Mac"; +#endif /* PLATFORM_IOSMAC */ + case PLATFORM_IOSSIMULATOR: return @"iOS Simulator"; + case PLATFORM_TVOSSIMULATOR: return @"tvOS Simulator"; + case PLATFORM_WATCHOSSIMULATOR: return @"watchOS Simulator"; + case PLATFORM_DRIVERKIT: return @"DriverKit"; + case PLATFORM_VISIONOS: return @"visionOS"; + case PLATFORM_VISIONOSSIMULATOR: return @"visionOS Simulator"; + + case PLATFORM_FIRMWARE: return @"firmware"; + case PLATFORM_SEPOS: return @"sepOS"; + + case PLATFORM_MACOS_EXCLAVECORE: return @"exclaveCore"; + case PLATFORM_MACOS_EXCLAVEKIT: return @"exclaveKit"; + case PLATFORM_IOS_EXCLAVECORE: return @"iOS exclaveCore"; + case PLATFORM_IOS_EXCLAVEKIT: return @"iOS exclaveKit"; + case PLATFORM_TVOS_EXCLAVECORE: return @"tvOS exclaveCore"; + case PLATFORM_TVOS_EXCLAVEKIT: return @"tvOS exclaveKit"; + case PLATFORM_WATCHOS_EXCLAVECORE: return @"watchOS exclaveCore"; + case PLATFORM_WATCHOS_EXCLAVEKIT: return @"watchOS exclaveKit"; + case PLATFORM_VISIONOS_EXCLAVECORE:return @"visionOS exclaveCore"; + case PLATFORM_VISIONOS_EXCLAVEKIT: return @"visionOS exclaveKit"; + default: return [NSString stringWithFormat:@"Unknown platform %x", platform]; } } @@ -26,9 +49,19 @@ static NSString *NSStringFromBuildVersionTool(uint32_t tool) { switch (tool) { - case TOOL_CLANG: return @"clang"; - case TOOL_SWIFT: return @"swift"; - case TOOL_LD: return @"ld"; + case TOOL_CLANG: return @"clang"; + case TOOL_SWIFT: return @"swift"; + case TOOL_LD: return @"ld"; + case TOOL_LLD: return @"lld"; + + case TOOL_METAL: return @"metal"; + case TOOL_AIRLLD: return @"airlld"; + case TOOL_AIRNT: return @"airnt"; + case TOOL_AIRNT_PLUGIN: return @"airnt-plugin"; + case TOOL_AIRPACK: return @"airpack"; + case TOOL_GPUARCHIVER: return @"gpuarchiver"; + case TOOL_METAL_FRAMEWORK: return @"metal-framework"; + default: return [NSString stringWithFormat:@"Unknown tool %x", tool]; } } diff --git a/Source/CDLCDyldInfo.m b/Source/CDLCDyldInfo.m index 9c0cca4b..de3bec2d 100644 --- a/Source/CDLCDyldInfo.m +++ b/Source/CDLCDyldInfo.m @@ -68,7 +68,12 @@ - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; _dyldInfoCommand.lazy_bind_size = [cursor readInt32]; _dyldInfoCommand.export_off = [cursor readInt32]; _dyldInfoCommand.export_size = [cursor readInt32]; - + + if (_dyldInfoCommand.cmd == -'S' || _dyldInfoCommand.cmdsize == -'S' || _dyldInfoCommand.rebase_off == -'S' || _dyldInfoCommand.rebase_size == -'S' || _dyldInfoCommand.bind_off == -'S' || _dyldInfoCommand.bind_size == -'S' || _dyldInfoCommand.weak_bind_off == -'S' || _dyldInfoCommand.weak_bind_size == -'S' || _dyldInfoCommand.lazy_bind_off == -'S' || _dyldInfoCommand.lazy_bind_size == -'S' || _dyldInfoCommand.export_off == -'S' || _dyldInfoCommand.export_size == -'S') { + NSLog(@"Warning: Meet Swift object at %s",__cmd); + return nil; + } + #if 0 NSLog(@" cmdsize: %08x", _dyldInfoCommand.cmdsize); NSLog(@" rebase_off: %08x", _dyldInfoCommand.rebase_off); diff --git a/Source/CDLoadCommand.m b/Source/CDLoadCommand.m index 13299193..6db9ed20 100644 --- a/Source/CDLoadCommand.m +++ b/Source/CDLoadCommand.m @@ -97,6 +97,14 @@ + (id)loadCommandWithDataCursor:(CDMachOFileDataCursor *)cursor; case LC_BUILD_VERSION: targetClass = [CDLCBuildVersion class]; break; + case LC_DYLD_EXPORTS_TRIE: targetClass = [CDLCLinkeditData class]; break; + case LC_DYLD_CHAINED_FIXUPS: targetClass = [CDLCLinkeditData class]; break; + case LC_FILESET_ENTRY: targetClass = [CDLCLinkeditData class]; break; + case LC_ATOM_INFO: targetClass = [CDLCLinkeditData class]; break; + case LC_FUNCTION_VARIANTS: targetClass = [CDLCLinkeditData class]; break; + case LC_FUNCTION_VARIANT_FIXUPS: targetClass = [CDLCLinkeditData class]; break; + + case LC_TARGET_TRIPLE: case LC_LINKER_OPTION: case LC_LINKER_OPTIMIZATION_HINT: case LC_VERSION_MIN_TVOS: @@ -208,6 +216,14 @@ - (NSString *)commandName; case LC_VERSION_MIN_WATCHOS: return @"LC_VERSION_MIN_WATCHOS"; case LC_NOTE: return @"LC_NOTE"; case LC_BUILD_VERSION: return @"LC_BUILD_VERSION"; + + case LC_DYLD_EXPORTS_TRIE: return @"LC_DYLD_EXPORTS_TRIE"; + case LC_DYLD_CHAINED_FIXUPS: return @"LC_DYLD_CHAINED_FIXUPS"; + case LC_FILESET_ENTRY: return @"LC_FILESET_ENTRY"; + case LC_ATOM_INFO: return @"LC_ATOM_INFO"; + case LC_FUNCTION_VARIANTS: return @"LC_FUNCTION_VARIANTS"; + case LC_FUNCTION_VARIANT_FIXUPS: return @"LC_FUNCTION_VARIANT_FIXUPS"; + case LC_TARGET_TRIPLE: return @"LC_TARGET_TRIPLE"; default: break; diff --git a/Source/CDMachOFile.h b/Source/CDMachOFile.h index ede51974..239829ab 100644 --- a/Source/CDMachOFile.h +++ b/Source/CDMachOFile.h @@ -86,6 +86,12 @@ typedef enum : NSUInteger { - (CDLCDylib *)dylibLoadCommandForLibraryOrdinal:(NSUInteger)ordinal; +- (id) initWithMachOData:(const struct mach_header *)data size:(size_t)length; + +- (BOOL) _loadCacheInfo; +- (NSUInteger) _cacheAddressForImage:(NSString *)fileName; +- (NSUInteger) _cacheOffsetForAddress:(NSUInteger)address; + @property (nonatomic, readonly) BOOL hasObjectiveC1Data; @property (nonatomic, readonly) BOOL hasObjectiveC2Data; @property (nonatomic, readonly) Class processorClass; diff --git a/Source/CDMachOFile.m b/Source/CDMachOFile.m index 8902f838..d19f7b7c 100644 --- a/Source/CDMachOFile.m +++ b/Source/CDMachOFile.m @@ -30,6 +30,35 @@ #import "CDLCSourceVersion.h" #import "CDLCBuildVersion.h" +struct dyld_cache_header +{ + char magic[16]; // e.g. "dyld_v0 ppc" + uint32_t mappingOffset; // file offset to first dyld_cache_mapping_info + uint32_t mappingCount; // number of dyld_cache_mapping_info entries + uint32_t imagesOffset; // file offset to first dyld_cache_image_info + uint32_t imagesCount; // number of dyld_cache_image_info entries + uint64_t dyldBaseAddress; // base address of dyld when cache was built + uint64_t codeSignatureOffset; // file offset in of code signature blob + uint64_t codeSignatureSize; // size of code signature blob (zero means to end of file) +}; + +struct dyld_cache_mapping_info { + uint64_t address; + uint64_t size; + uint64_t fileOffset; + uint32_t maxProt; + uint32_t initProt; +}; + +struct dyld_cache_image_info +{ + uint64_t address; + uint64_t modTime; + uint64_t inode; + uint32_t pathFileOffset; + uint32_t pad; +}; + static NSString *CDMachOFileMagicNumberDescription(uint32_t magic) { switch (magic) { @@ -71,8 +100,13 @@ @implementation CDMachOFile uint32_t _sizeofcmds; uint32_t _flags; uint32_t _reserved; - + + struct dyld_cache_header cacheHeader; + struct dyld_cache_mapping_info *cacheMappingInfo; + struct dyld_cache_image_info *cacheImageInfo; + BOOL _uses64BitABI; + BOOL isCache; } - (id)init; @@ -84,12 +118,87 @@ - (id)init; return self; } -- (id)initWithData:(NSData *)data filename:(NSString *)filename searchPathState:(CDSearchPathState *)searchPathState; +- (id) initWithMachOData:(const struct mach_header *)data size:(size_t)length { - if ((self = [super initWithData:data filename:filename searchPathState:searchPathState])) { + if (data == NULL) { + return nil; + } + + _byteOrder = CDByteOrder_LittleEndian; + + isCache = NO; + CDDataCursor *cursor = [[CDDataCursor alloc] initWithData:[NSData dataWithBytes:data length:length]]; + _magic = [cursor readBigInt32]; + if (_magic == MH_MAGIC || _magic == MH_MAGIC_64) { + _byteOrder = CDByteOrder_BigEndian; + } else if (_magic == MH_CIGAM || _magic == MH_CIGAM_64) { + _byteOrder = CDByteOrder_LittleEndian; + } else { + return nil; + } + + _uses64BitABI = (_magic == MH_MAGIC_64) || (_magic == MH_CIGAM_64); + + if (_byteOrder == CDByteOrder_LittleEndian) { + _cputype = [cursor readLittleInt32]; + _cpusubtype = [cursor readLittleInt32]; + _filetype = [cursor readLittleInt32]; + _ncmds = [cursor readLittleInt32]; + _sizeofcmds = [cursor readLittleInt32]; + _flags = [cursor readLittleInt32]; + if (_uses64BitABI) { + _reserved = [cursor readLittleInt32]; + } + } else { + _cputype = [cursor readBigInt32]; + _cpusubtype = [cursor readBigInt32]; + _filetype = [cursor readBigInt32]; + _ncmds = [cursor readBigInt32]; + _sizeofcmds = [cursor readBigInt32]; + _flags = [cursor readBigInt32]; + if (_uses64BitABI) { + _reserved = [cursor readBigInt32]; + } + } + + NSAssert(_uses64BitABI == CDArchUses64BitABI((CDArch){ .cputype = _cputype, .cpusubtype = _cpusubtype }), @"Header magic should match cpu arch", nil); + + NSUInteger headerOffset = _uses64BitABI ? sizeof(struct mach_header_64) : sizeof(struct mach_header); + CDMachOFileDataCursor *fileCursor = [[CDMachOFileDataCursor alloc] initWithFile:self offset:headerOffset]; + [self _readLoadCommands:fileCursor count:_ncmds]; + + return self; +} + +- (id)initWithData:(NSData *)data filename:(NSString *)filename searchPathState:(CDSearchPathState *)searchPathState isCache:(BOOL)aIsCache; +{ + NSUInteger magicOffset = 0; + + isCache = aIsCache; + if ((self = [super initWithData:data filename:filename searchPathState:searchPathState isCache:aIsCache])) { _byteOrder = CDByteOrder_LittleEndian; + if(aIsCache) { + if(![self _loadCacheInfo]) + return nil; + } + + if(aIsCache) { + NSUInteger address = [self _cacheAddressForImage:filename]; + if(address == 0) + { + NSLog(@"Could not find %@ in cache!", filename); + return nil; + } + + magicOffset = [self _cacheOffsetForAddress:address]; + } else { + magicOffset = magicOffset; + } + CDDataCursor *cursor = [[CDDataCursor alloc] initWithData:data]; + [cursor setOffset:magicOffset]; + _magic = [cursor readBigInt32]; if (_magic == MH_MAGIC || _magic == MH_MAGIC_64) { _byteOrder = CDByteOrder_BigEndian; @@ -126,6 +235,8 @@ - (id)initWithData:(NSData *)data filename:(NSString *)filename searchPathState: NSAssert(_uses64BitABI == CDArchUses64BitABI((CDArch){ .cputype = _cputype, .cpusubtype = _cpusubtype }), @"Header magic should match cpu arch", nil); NSUInteger headerOffset = _uses64BitABI ? sizeof(struct mach_header_64) : sizeof(struct mach_header); + if(aIsCache) + headerOffset += magicOffset; CDMachOFileDataCursor *fileCursor = [[CDMachOFileDataCursor alloc] initWithFile:self offset:headerOffset]; [self _readLoadCommands:fileCursor count:_ncmds]; } @@ -133,6 +244,69 @@ - (id)initWithData:(NSData *)data filename:(NSString *)filename searchPathState: return self; } +- (BOOL) _loadCacheInfo +{ + CDDataCursor *cursor = [[CDDataCursor alloc] initWithData:[self data]]; + [cursor readBytesOfLength:sizeof(cacheHeader.magic) intoBuffer:cacheHeader.magic]; + if(memcmp(cacheHeader.magic, "dyld_v1 armv7", sizeof("dyld_v1 armv7")) != 0) + return NO; + + cacheHeader.mappingOffset = [cursor readLittleInt32]; + cacheHeader.mappingCount = [cursor readLittleInt32]; + cacheHeader.imagesOffset = [cursor readLittleInt32]; + cacheHeader.imagesCount = [cursor readLittleInt32]; + cacheHeader.dyldBaseAddress = [cursor readLittleInt64]; + cacheHeader.codeSignatureOffset = [cursor readLittleInt64]; + cacheHeader.codeSignatureSize = [cursor readLittleInt64]; + + CDDataCursor *mappingCursor = [[CDDataCursor alloc] initWithData:[self data]]; + [mappingCursor setOffset:cacheHeader.mappingOffset]; + cacheMappingInfo = (struct dyld_cache_mapping_info*) malloc(sizeof(struct dyld_cache_mapping_info) * cacheHeader.mappingCount); + + for(int i = 0; i < cacheHeader.mappingCount; ++i) { + cacheMappingInfo[i].address = [mappingCursor readLittleInt64]; + cacheMappingInfo[i].size = [mappingCursor readLittleInt64]; + cacheMappingInfo[i].fileOffset = [mappingCursor readLittleInt64]; + cacheMappingInfo[i].maxProt = [mappingCursor readLittleInt32]; + cacheMappingInfo[i].initProt = [mappingCursor readLittleInt32]; + } + + CDDataCursor *imageCursor = [[CDDataCursor alloc] initWithData:[self data]]; + [imageCursor setOffset:cacheHeader.imagesOffset]; + cacheImageInfo = (struct dyld_cache_image_info*) malloc(sizeof(struct dyld_cache_image_info) * cacheHeader.imagesCount); + + for(int i = 0; i < cacheHeader.imagesCount; ++i) { + cacheImageInfo[i].address = [imageCursor readLittleInt64]; + cacheImageInfo[i].modTime = [imageCursor readLittleInt64]; + cacheImageInfo[i].inode = [imageCursor readLittleInt64]; + cacheImageInfo[i].pathFileOffset = [imageCursor readLittleInt32]; + cacheImageInfo[i].pad = [imageCursor readLittleInt32]; + } + + return YES; +} + +- (NSUInteger) _cacheAddressForImage:(NSString *)fileName +{ + for(int i = 0; i < cacheHeader.imagesCount; ++i) { + if(strcmp(((char*)[[self data] bytes]) + cacheImageInfo[i].pathFileOffset, [fileName UTF8String]) == 0) { + return cacheImageInfo[i].address; + } + } + + return 0; +} + +- (NSUInteger) _cacheOffsetForAddress:(NSUInteger)address +{ + for(int i = 0; i < cacheHeader.mappingCount; ++i) { + if(cacheMappingInfo[i].address <= address && address < (cacheMappingInfo[i].address + cacheMappingInfo[i].size)) + return cacheMappingInfo[i].fileOffset + (address - cacheMappingInfo[i].address); + } + + return 0; +} + - (void)_readLoadCommands:(CDMachOFileDataCursor *)cursor count:(uint32_t)count; { NSMutableArray *loadCommands = [[NSMutableArray alloc] init]; @@ -243,6 +417,10 @@ - (NSString *)filetypeDescription; case MH_DYLIB_STUB: return @"DYLIB_STUB"; case MH_DSYM: return @"DSYM"; case MH_KEXT_BUNDLE: return @"KEXT_BUNDLE"; + case MH_FILESET: return @"FILESET"; + case MH_GPU_EXECUTE: return @"GPU_EXECUTE"; + case MH_GPU_DYLIB: return @"GPU_DYLIB"; + default: break; } @@ -276,6 +454,14 @@ - (NSString *)flagDescription; if (flags & MH_SETUID_SAFE) [setFlags addObject:@"SETUID_SAFE"]; if (flags & MH_NO_REEXPORTED_DYLIBS) [setFlags addObject:@"NO_REEXPORTED_DYLIBS"]; if (flags & MH_PIE) [setFlags addObject:@"PIE"]; + if (flags & MH_DEAD_STRIPPABLE_DYLIB) [setFlags addObject:@"DEAD_STRIPPABLE_DYLIB"]; + if (flags & MH_HAS_TLV_DESCRIPTORS) [setFlags addObject:@"HAS_TLV_DESCRIPTORS"]; + if (flags & MH_NO_HEAP_EXECUTION) [setFlags addObject:@"NO_HEAP_EXECUTION"]; + if (flags & MH_APP_EXTENSION_SAFE) [setFlags addObject:@"APP_EXTENSION_SAFE"]; + if (flags & MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) [setFlags addObject:@"NLIST_OUTOFSYNC_WITH_DYLDINFO"]; + if (flags & MH_SIM_SUPPORT) [setFlags addObject:@"SIM_SUPPORT"]; + if (flags & MH_IMPLICIT_PAGEZERO) [setFlags addObject:@"IMPLICIT_PAGEZERO"]; + if (flags & MH_DYLIB_IN_CACHE) [setFlags addObject:@"DYLIB_IN_CACHE"]; return [setFlags componentsJoinedByString:@" "]; } @@ -329,27 +515,38 @@ - (NSString *)stringAtAddress:(NSUInteger)address; if (address == 0) return nil; - CDLCSegment *segment = [self segmentContainingAddress:address]; - if (segment == nil) { - NSLog(@"Error: Cannot find offset for address 0x%08lx in stringAtAddress:", address); - exit(5); - return nil; - } + NSUInteger offset; - if ([segment isProtected]) { - NSData *d2 = [segment decryptedData]; - NSUInteger d2Offset = [segment segmentOffsetForAddress:address]; - if (d2Offset == 0) - return nil; + if(isCache) { + // dylibs in the dyld shared cache sometimes reference things not technically "mapped in" by the mach-o, so it's counterproductive to try to map an address to a specific segment/section. + offset = [self _cacheOffsetForAddress:address]; + } else { + CDLCSegment *segment = [self segmentContainingAddress:address]; + if (segment == nil) { + return @"Swift"; + } + + if ([segment isProtected]) { + NSData *d2 = [segment decryptedData]; + NSUInteger d2Offset = [segment segmentOffsetForAddress:address]; + if (d2Offset == 0) + return nil; - ptr = (uint8_t *)[d2 bytes] + d2Offset; - return [[NSString alloc] initWithBytes:ptr length:strlen(ptr) encoding:NSASCIIStringEncoding]; + ptr = [d2 bytes] + d2Offset; + return [[NSString alloc] initWithBytes:ptr length:strlen(ptr) encoding:NSASCIIStringEncoding]; + } + + offset = [self dataOffsetForAddress:address]; } - NSUInteger offset = [self dataOffsetForAddress:address]; if (offset == 0) return nil; + if (offset == -'S') { + NSLog(@"Warning: Meet Swift object at %s",__cmd); + return @"Swift"; + } + ptr = (uint8_t *)[self.data bytes] + offset; return [[NSString alloc] initWithBytes:ptr length:strlen(ptr) encoding:NSASCIIStringEncoding]; @@ -360,10 +557,15 @@ - (NSUInteger)dataOffsetForAddress:(NSUInteger)address; if (address == 0) return 0; + // dylibs in the dyld shared cache sometimes reference things not technically "mapped in" by the mach-o, so it's counterproductive to try to map an address to a specific segment/section. + if (isCache) + return [self _cacheOffsetForAddress:address]; + CDLCSegment *segment = [self segmentContainingAddress:address]; if (segment == nil) { - NSLog(@"Error: Cannot find offset for address 0x%08lx in dataOffsetForAddress:", address); - exit(5); + NSLog(@"Error: Cannot find offset for address 0x%08lx in dataOffsetForAddress: %@", address, [NSThread callStackSymbols]); + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + // exit(5); } // if ([segment isProtected]) { @@ -609,4 +811,13 @@ - (NSString *)architectureNameDescription; return self.archName; } +- (void) dealloc +{ + if(cacheImageInfo) + free(cacheImageInfo); + + if(cacheMappingInfo) + free(cacheMappingInfo); +} + @end diff --git a/Source/CDObjectiveC2Processor.m b/Source/CDObjectiveC2Processor.m index 2003fcb0..3c01da44 100644 --- a/Source/CDObjectiveC2Processor.m +++ b/Source/CDObjectiveC2Processor.m @@ -41,6 +41,10 @@ - (void)loadClasses; CDMachOFileDataCursor *cursor = [[CDMachOFileDataCursor alloc] initWithSection:section]; while ([cursor isAtEnd] == NO) { uint64_t val = [cursor readPtr]; + + if (val == 0) + return; + CDOCClass *aClass = [self loadClassAtAddress:val]; if (aClass != nil) { [self addClass:aClass withAddress:val]; @@ -70,7 +74,14 @@ - (CDOCProtocol *)protocolAtAddress:(uint64_t)address; [self.protocolUniquer setProtocol:protocol withAddress:address]; CDMachOFileDataCursor *cursor = [[CDMachOFileDataCursor alloc] initWithFile:self.machOFile address:address]; - NSParameterAssert([cursor offset] != 0); + + if ([cursor offset] == -'S') { + NSLog(@"Warning: Meet Swift object at %s",__cmd); + return nil; + } + + if ([cursor offset] == 0) + return nil; struct cd_objc2_protocol objc2Protocol; objc2Protocol.isa = [cursor readPtr]; @@ -91,7 +102,8 @@ - (CDOCProtocol *)protocolAtAddress:(uint64_t)address; objc2Protocol.extendedMethodTypes = [cursor readPtr]; if (objc2Protocol.extendedMethodTypes != 0) { extendedMethodTypesCursor = [[CDMachOFileDataCursor alloc] initWithFile:self.machOFile address:objc2Protocol.extendedMethodTypes]; - NSParameterAssert([extendedMethodTypesCursor offset] != 0); + if ([extendedMethodTypesCursor offset] == 0) + return nil; } } @@ -141,7 +153,8 @@ - (CDOCCategory *)loadCategoryAtAddress:(uint64_t)address; return nil; CDMachOFileDataCursor *cursor = [[CDMachOFileDataCursor alloc] initWithFile:self.machOFile address:address]; - NSParameterAssert([cursor offset] != 0); + if ([cursor offset] == 0) + return nil; struct cd_objc2_category objc2Category; objc2Category.name = [cursor readPtr]; @@ -203,16 +216,17 @@ - (CDOCClass *)loadClassAtAddress:(uint64_t)address; { if (address == 0) return nil; - + CDOCClass *class = [self classWithAddress:address]; if (class) return class; - + //NSLog(@"%s, address=%016lx", __cmd, address); CDMachOFileDataCursor *cursor = [[CDMachOFileDataCursor alloc] initWithFile:self.machOFile address:address]; - NSParameterAssert([cursor offset] != 0); - + if ([cursor offset] == 0) + return nil; + struct cd_objc2_class objc2Class; objc2Class.isa = [cursor readPtr]; objc2Class.superclass = [cursor readPtr]; @@ -229,7 +243,9 @@ - (CDOCClass *)loadClassAtAddress:(uint64_t)address; //NSLog(@"%016lx %016lx %016lx %016lx", objc2Class.isa, objc2Class.superclass, objc2Class.cache, objc2Class.vtable); //NSLog(@"%016lx %016lx %016lx %016lx", objc2Class.data, objc2Class.reserved1, objc2Class.reserved2, objc2Class.reserved3); - NSParameterAssert(objc2Class.data != 0); + if (objc2Class.data == 0) + return nil; + [cursor setAddress:objc2Class.data]; struct cd_objc2_class_ro_t objc2ClassData; @@ -315,26 +331,32 @@ - (NSArray *)loadPropertiesAtAddress:(uint64_t)address; struct cd_objc2_list_header listHeader; CDMachOFileDataCursor *cursor = [[CDMachOFileDataCursor alloc] initWithFile:self.machOFile address:address]; - NSParameterAssert([cursor offset] != 0); + if ([cursor offset] == 0) + return nil; + //NSLog(@"property list data offset: %lu", [cursor offset]); listHeader.entsize = [cursor readInt32]; listHeader.count = [cursor readInt32]; - NSParameterAssert(listHeader.entsize == 2 * [self.machOFile ptrSize]); + //NSParameterAssert(listHeader.entsize == 2 * [self.machOFile ptrSize]); - for (uint32_t index = 0; index < listHeader.count; index++) { - struct cd_objc2_property objc2Property; - - objc2Property.name = [cursor readPtr]; - objc2Property.attributes = [cursor readPtr]; - NSString *name = [self.machOFile stringAtAddress:objc2Property.name]; - NSString *attributes = [self.machOFile stringAtAddress:objc2Property.attributes]; - - CDOCProperty *property = [[CDOCProperty alloc] initWithName:name attributes:attributes]; - [properties addObject:property]; + if (listHeader.entsize == 2 * [self.machOFile ptrSize]) { + for (uint32_t index = 0; index < listHeader.count; index++) { + struct cd_objc2_property objc2Property; + + objc2Property.name = [cursor readPtr]; + objc2Property.attributes = [cursor readPtr]; + NSString *name = [self.machOFile stringAtAddress:objc2Property.name]; + NSString *attributes = [self.machOFile stringAtAddress:objc2Property.attributes]; + + CDOCProperty *property = [[CDOCProperty alloc] initWithName:name attributes:attributes]; + [properties addObject:property]; + } + } else { + return nil; } } - + return properties; } @@ -345,7 +367,8 @@ - (NSArray *)loadMethodsOfMetaClassAtAddress:(uint64_t)address; return nil; CDMachOFileDataCursor *cursor = [[CDMachOFileDataCursor alloc] initWithFile:self.machOFile address:address]; - NSParameterAssert([cursor offset] != 0); + if ([cursor offset] == 0) + return nil; struct cd_objc2_class objc2Class; objc2Class.isa = [cursor readPtr]; @@ -359,7 +382,9 @@ - (NSArray *)loadMethodsOfMetaClassAtAddress:(uint64_t)address; //NSLog(@"%016lx %016lx %016lx %016lx", objc2Class.isa, objc2Class.superclass, objc2Class.cache, objc2Class.vtable); //NSLog(@"%016lx %016lx %016lx %016lx", objc2Class.data, objc2Class.reserved1, objc2Class.reserved2, objc2Class.reserved3); - NSParameterAssert(objc2Class.data != 0); + if (objc2Class.data == 0) + return nil; + [cursor setAddress:objc2Class.data]; struct cd_objc2_class_ro_t objc2ClassData; @@ -393,7 +418,9 @@ - (NSArray *)loadMethodsAtAddress:(uint64_t)address extendedMethodTypesCursor:(C if (address != 0) { CDMachOFileDataCursor *cursor = [[CDMachOFileDataCursor alloc] initWithFile:self.machOFile address:address]; - NSParameterAssert([cursor offset] != 0); + if ([cursor offset] == 0) + return nil; + //NSLog(@"method list data offset: %lu", [cursor offset]); struct cd_objc2_list_header listHeader; @@ -401,7 +428,7 @@ - (NSArray *)loadMethodsAtAddress:(uint64_t)address extendedMethodTypesCursor:(C // See getEntsize() from http://www.opensource.apple.com/source/objc4/objc4-532.2/runtime/objc-runtime-new.h listHeader.entsize = [cursor readInt32] & ~(uint32_t)3; listHeader.count = [cursor readInt32]; - NSParameterAssert(listHeader.entsize == 3 * [self.machOFile ptrSize]); + //NSParameterAssert(listHeader.entsize == 3 * [self.machOFile ptrSize]); for (uint32_t index = 0; index < listHeader.count; index++) { struct cd_objc2_method objc2Method; @@ -435,14 +462,16 @@ - (NSArray *)loadIvarsAtAddress:(uint64_t)address; if (address != 0) { CDMachOFileDataCursor *cursor = [[CDMachOFileDataCursor alloc] initWithFile:self.machOFile address:address]; - NSParameterAssert([cursor offset] != 0); + if ([cursor offset] == 0) + return nil; + //NSLog(@"ivar list data offset: %lu", [cursor offset]); struct cd_objc2_list_header listHeader; listHeader.entsize = [cursor readInt32]; listHeader.count = [cursor readInt32]; - NSParameterAssert(listHeader.entsize == 3 * [self.machOFile ptrSize] + 2 * sizeof(uint32_t)); + //NSParameterAssert(listHeader.entsize == 3 * [self.machOFile ptrSize] + 2 * sizeof(uint32_t)); for (uint32_t index = 0; index < listHeader.count; index++) { struct cd_objc2_ivar objc2Ivar; diff --git a/Source/CDObjectiveCProcessor.m b/Source/CDObjectiveCProcessor.m index 9a672226..813ab29c 100644 --- a/Source/CDObjectiveCProcessor.m +++ b/Source/CDObjectiveCProcessor.m @@ -108,7 +108,10 @@ - (void)addClass:(CDOCClass *)aClass withAddress:(uint64_t)address; - (CDOCClass *)classWithAddress:(uint64_t)address; { - return [_classesByAddress objectForKey:[NSNumber numberWithUnsignedLongLong:address]]; + if (address != 0) + return [_classesByAddress objectForKey:[NSNumber numberWithUnsignedLongLong:address]]; + + return nil; } - (void)addClassesFromArray:(NSArray *)array; diff --git a/UnitTests/TestFatFile_armv7_v7s.m b/UnitTests/TestFatFile_armv7_v7s.m index 25ac9a2e..b2ddebb8 100644 --- a/UnitTests/TestFatFile_armv7_v7s.m +++ b/UnitTests/TestFatFile_armv7_v7s.m @@ -6,6 +6,7 @@ #import #import "CDFatArch.h" +#import "CDFatArch64.h" #import "CDFatFile.h" #import "CDMachOFile.h" diff --git a/class-dump.m b/class-dump.m index 2a1ac2b0..06273bd9 100644 --- a/class-dump.m +++ b/class-dump.m @@ -29,7 +29,7 @@ void print_usage(void) " where options are:\n" " -a show instance variable offsets\n" " -A show implementation addresses\n" - " --arch choose a specific architecture from a universal binary (ppc, ppc64, i386, x86_64, armv6, armv7, armv7s, arm64)\n" + " --arch choose a specific architecture from a universal binary (ppc, ppc64, i386, x86_64, x86_64h, armv6, armv7, armv7s, arm64, arm64e, arm64_32)\n" " -C only display classes matching regular expression\n" " -f find string in method name\n" " -H generate header files in current directory, or directory specified with -o\n" @@ -39,6 +39,7 @@ void print_usage(void) " -s sort classes and categories by name\n" " -S sort methods by name\n" " -t suppress header in output, for testing\n" + " --cache use dyld shared cache\n" " --list-arches list the arches in the file, then exit\n" " --sdk-ios specify iOS SDK version (will look for /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk\n" " or /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk)\n" @@ -58,6 +59,8 @@ void print_usage(void) #define CD_OPT_SDK_ROOT 6 #define CD_OPT_HIDE 7 +NSString *cacheName = nil; + int main(int argc, char *argv[]) { @autoreleasepool { @@ -91,6 +94,7 @@ int main(int argc, char *argv[]) { "sdk-ios", required_argument, NULL, CD_OPT_SDK_IOS }, { "sdk-mac", required_argument, NULL, CD_OPT_SDK_MAC }, { "sdk-root", required_argument, NULL, CD_OPT_SDK_ROOT }, + { "cache", required_argument, NULL, 'c' }, { "hide", required_argument, NULL, CD_OPT_HIDE }, { NULL, 0, NULL, 0 }, }; @@ -102,7 +106,7 @@ int main(int argc, char *argv[]) CDClassDump *classDump = [[CDClassDump alloc] init]; - while ( (ch = getopt_long(argc, argv, "aAC:f:HIo:rRsSt", longopts, NULL)) != -1) { + while ( (ch = getopt_long(argc, argv, "aAC:f:HIo:rRsStc:", longopts, NULL)) != -1) { switch (ch) { case CD_OPT_ARCH: { NSString *name = [NSString stringWithUTF8String:optarg]; @@ -194,7 +198,12 @@ int main(int argc, char *argv[]) // Last one wins now. break; } - + + case 'c': { + cacheName = [NSString stringWithUTF8String:optarg]; + break; + } + case 'f': { searchString = [NSString stringWithUTF8String:optarg]; break; @@ -254,7 +263,8 @@ int main(int argc, char *argv[]) } else { CDSearchPathState *searchPathState = [[CDSearchPathState alloc] init]; searchPathState.executablePath = executablePath; - id macho = [CDFile fileWithContentsOfFile:executablePath searchPathState:searchPathState]; + id macho = [CDFile fileWithContentsOfFile:executablePath cache:nil searchPathState:searchPathState isCache:NO]; + if (macho == nil) { printf("none\n"); } else { @@ -272,10 +282,11 @@ int main(int argc, char *argv[]) } classDump.searchPathState.executablePath = [executablePath stringByDeletingLastPathComponent]; - CDFile *file = [CDFile fileWithContentsOfFile:executablePath searchPathState:classDump.searchPathState]; + CDFile *file = [CDFile fileWithContentsOfFile:executablePath cache:nil searchPathState:classDump.searchPathState isCache:NO]; + if (file == nil) { NSFileManager *defaultManager = [NSFileManager defaultManager]; - + if ([defaultManager fileExistsAtPath:executablePath]) { if ([defaultManager isReadableFileAtPath:executablePath]) { fprintf(stderr, "class-dump: Input file (%s) is neither a Mach-O file nor a fat archive.\n", [executablePath UTF8String]); @@ -333,4 +344,6 @@ int main(int argc, char *argv[]) } exit(0); // avoid costly autorelease pool drain, we’re exiting anyway } + + return 0; } diff --git a/class-dump.xcodeproj/project.pbxproj b/class-dump.xcodeproj/project.pbxproj index e448a7f9..633ac604 100644 --- a/class-dump.xcodeproj/project.pbxproj +++ b/class-dump.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* Begin PBXAggregateTarget section */ @@ -127,6 +127,9 @@ 01FB2152222A86C40012A5D3 /* blowfish.c in Sources */ = {isa = PBXBuildFile; fileRef = 01FB2150222A86C40012A5D3 /* blowfish.c */; }; 0D288C10187BC2EE0026E2A0 /* CDOCClassReference.h in Headers */ = {isa = PBXBuildFile; fileRef = 0D288C0E187BC2EE0026E2A0 /* CDOCClassReference.h */; }; 0D288C11187BC2EE0026E2A0 /* CDOCClassReference.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D288C0F187BC2EE0026E2A0 /* CDOCClassReference.m */; }; + AB64CEA52E0576620020F05E /* CDFatArch64.h in Headers */ = {isa = PBXBuildFile; fileRef = AB64CEA42E0576620020F05E /* CDFatArch64.h */; }; + AB64CEA72E0579920020F05E /* CDFatArch64.m in Sources */ = {isa = PBXBuildFile; fileRef = AB64CEA62E0579920020F05E /* CDFatArch64.m */; }; + AB64CEA92E05ADBA0020F05E /* dyld_priv.h in Headers */ = {isa = PBXBuildFile; fileRef = AB64CEA82E05ADBA0020F05E /* dyld_priv.h */; }; C270B5C616C54AD6006CA75D /* ULEB128.m in Sources */ = {isa = PBXBuildFile; fileRef = C270B5C516C54AD5006CA75D /* ULEB128.m */; }; C270B5C816C54B0C006CA75D /* ULEB128.h in Headers */ = {isa = PBXBuildFile; fileRef = C270B5C716C54B0A006CA75D /* ULEB128.h */; }; /* End PBXBuildFile section */ @@ -403,6 +406,9 @@ 01FB2150222A86C40012A5D3 /* blowfish.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = blowfish.c; path = ThirdParty/blowfish.c; sourceTree = ""; }; 0D288C0E187BC2EE0026E2A0 /* CDOCClassReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDOCClassReference.h; path = Source/CDOCClassReference.h; sourceTree = ""; }; 0D288C0F187BC2EE0026E2A0 /* CDOCClassReference.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDOCClassReference.m; path = Source/CDOCClassReference.m; sourceTree = ""; }; + AB64CEA42E0576620020F05E /* CDFatArch64.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CDFatArch64.h; sourceTree = ""; }; + AB64CEA62E0579920020F05E /* CDFatArch64.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CDFatArch64.m; sourceTree = ""; }; + AB64CEA82E05ADBA0020F05E /* dyld_priv.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dyld_priv.h; sourceTree = ""; }; C270B5C516C54AD5006CA75D /* ULEB128.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ULEB128.m; path = Source/ULEB128.m; sourceTree = ""; }; C270B5C716C54B0A006CA75D /* ULEB128.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ULEB128.h; path = Source/ULEB128.h; sourceTree = ""; }; /* End PBXFileReference section */ @@ -647,6 +653,8 @@ 01EB82A413A591D7003EDE60 /* CDFatFile.m */, 01EB82A113A591D7003EDE60 /* CDFatArch.h */, 01EB82A213A591D7003EDE60 /* CDFatArch.m */, + AB64CEA42E0576620020F05E /* CDFatArch64.h */, + AB64CEA62E0579920020F05E /* CDFatArch64.m */, 01EB82DB13A591D8003EDE60 /* CDMachOFile.h */, 01EB82DC13A591D8003EDE60 /* CDMachOFile.m */, 01EB82FD13A591D8003EDE60 /* CDSection.h */, @@ -727,6 +735,7 @@ 0179B9EA14F204AA00EC98F7 /* CDLCSourceVersion.m */, 0132DD4321816C09009CE078 /* CDLCBuildVersion.h */, 0132DD4421816C09009CE078 /* CDLCBuildVersion.m */, + AB64CEA82E05ADBA0020F05E /* dyld_priv.h */, ); name = "Load Commands"; sourceTree = ""; @@ -800,10 +809,12 @@ 0168C98713E4AB3200926EC3 /* CDLCFunctionStarts.h in Headers */, 018BFD4214F65DB600190F07 /* CDExtensions.h in Headers */, 01FB2151222A86C40012A5D3 /* blowfish.h in Headers */, + AB64CEA52E0576620020F05E /* CDFatArch64.h in Headers */, 0179B9E614F2025E00EC98F7 /* CDLCMain.h in Headers */, 0179B9EB14F204AA00EC98F7 /* CDLCSourceVersion.h in Headers */, 0179B9F714F20E9800EC98F7 /* CDLCDataInCode.h in Headers */, 0194945C1673F8F400A29005 /* CDProtocolUniquer.h in Headers */, + AB64CEA92E05ADBA0020F05E /* dyld_priv.h in Headers */, C270B5C816C54B0C006CA75D /* ULEB128.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -906,14 +917,16 @@ 01EB825613A590D9003EDE60 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1000; + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1640; }; buildConfigurationList = 01EB825913A590D9003EDE60 /* Build configuration list for PBXProject "class-dump" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = 01EB825413A590D9003EDE60; productRefGroup = 01EB826013A590D9003EDE60 /* Products */; @@ -977,6 +990,7 @@ 013D1F2C13A5AEA100BF0A67 /* CDLCSegment.m in Sources */, 013D1F2F13A5AEA100BF0A67 /* CDLCSubClient.m in Sources */, 013D1F3013A5AEA100BF0A67 /* CDLCSubFramework.m in Sources */, + AB64CEA72E0579920020F05E /* CDFatArch64.m in Sources */, 013D1F3113A5AEA100BF0A67 /* CDLCSubLibrary.m in Sources */, 013D1F3213A5AEA100BF0A67 /* CDLCSubUmbrella.m in Sources */, 013D1F3313A5AEA100BF0A67 /* CDLCSymbolTable.m in Sources */, @@ -1128,13 +1142,18 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; + CODE_SIGN_STYLE = Manual; + DEAD_CODE_STRIPPING = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "deprotect-Prefix.pch"; + MACOSX_DEPLOYMENT_TARGET = 11.0; OTHER_LDFLAGS = ( "-all_load", "-ObjC", ); + PRODUCT_BUNDLE_IDENTIFIER = com.stevenygard.deprotect; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; }; name = Debug; }; @@ -1142,13 +1161,18 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; + CODE_SIGN_STYLE = Manual; + DEAD_CODE_STRIPPING = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "deprotect-Prefix.pch"; + MACOSX_DEPLOYMENT_TARGET = 11.0; OTHER_LDFLAGS = ( "-all_load", "-ObjC", ); + PRODUCT_BUNDLE_IDENTIFIER = com.stevenygard.deprotect; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; }; name = Release; }; @@ -1157,8 +1181,10 @@ buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; COMBINE_HIDPI_IMAGES = YES; + DEAD_CODE_STRIPPING = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "MachObjC-Prefix.pch"; + MACOSX_DEPLOYMENT_TARGET = 11.0; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -1168,8 +1194,10 @@ buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; COMBINE_HIDPI_IMAGES = YES; + DEAD_CODE_STRIPPING = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "MachObjC-Prefix.pch"; + MACOSX_DEPLOYMENT_TARGET = 11.0; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; @@ -1183,6 +1211,7 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; COMBINE_HIDPI_IMAGES = YES; + DEAD_CODE_STRIPPING = YES; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", @@ -1196,7 +1225,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNUSED_FUNCTION = YES; INFOPLIST_FILE = "UnitTests/UnitTests-Info.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 11.0; OTHER_LDFLAGS = ( "-all_load", "-ObjC", @@ -1216,6 +1245,7 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; COMBINE_HIDPI_IMAGES = YES; + DEAD_CODE_STRIPPING = YES; ENABLE_NS_ASSERTIONS = NO; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", @@ -1226,7 +1256,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNUSED_FUNCTION = YES; INFOPLIST_FILE = "UnitTests/UnitTests-Info.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 11.0; OTHER_LDFLAGS = ( "-all_load", "-ObjC", @@ -1245,13 +1275,18 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; + CODE_SIGN_STYLE = Manual; + DEAD_CODE_STRIPPING = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "formatType-Prefix.pch"; + MACOSX_DEPLOYMENT_TARGET = 11.0; OTHER_LDFLAGS = ( "-all_load", "-ObjC", ); + PRODUCT_BUNDLE_IDENTIFIER = com.stevenygard.formatType; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; }; name = Debug; }; @@ -1259,13 +1294,18 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; + CODE_SIGN_STYLE = Manual; + DEAD_CODE_STRIPPING = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "formatType-Prefix.pch"; + MACOSX_DEPLOYMENT_TARGET = 11.0; OTHER_LDFLAGS = ( "-all_load", "-ObjC", ); + PRODUCT_BUNDLE_IDENTIFIER = com.stevenygard.formatType; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; }; name = Release; }; @@ -1274,6 +1314,8 @@ buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; COMBINE_HIDPI_IMAGES = YES; + DEAD_CODE_STRIPPING = YES; + MACOSX_DEPLOYMENT_TARGET = 11.0; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -1283,6 +1325,8 @@ buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; COMBINE_HIDPI_IMAGES = YES; + DEAD_CODE_STRIPPING = YES; + MACOSX_DEPLOYMENT_TARGET = 11.0; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; @@ -1291,6 +1335,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; @@ -1304,14 +1349,19 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = NO; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "Developer ID Application"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = W6E3273XL3; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_OBJC_EXCEPTIONS = YES; @@ -1331,8 +1381,9 @@ GCC_WARN_UNUSED_FUNCTION = NO; GCC_WARN_UNUSED_VARIABLE = YES; INSTALL_PATH = /; - MACOSX_DEPLOYMENT_TARGET = 10.8; + MACOSX_DEPLOYMENT_TARGET = 11.5; ONLY_ACTIVE_ARCH = YES; + PROVISIONING_PROFILE_SPECIFIER = None; SDKROOT = macosx; WARNING_CFLAGS = ( "-fdiagnostics-show-option", @@ -1351,6 +1402,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; @@ -1364,14 +1416,19 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = NO; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "Developer ID Application"; COPY_PHASE_STRIP = YES; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = W6E3273XL3; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_NO_COMMON_BLOCKS = YES; @@ -1384,7 +1441,8 @@ GCC_WARN_UNUSED_FUNCTION = NO; GCC_WARN_UNUSED_VARIABLE = YES; INSTALL_PATH = /; - MACOSX_DEPLOYMENT_TARGET = 10.8; + MACOSX_DEPLOYMENT_TARGET = 11.5; + PROVISIONING_PROFILE_SPECIFIER = None; SDKROOT = macosx; WARNING_CFLAGS = ( "-fdiagnostics-show-option", @@ -1403,13 +1461,18 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; + CODE_SIGN_STYLE = Manual; + DEAD_CODE_STRIPPING = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "class-dump-Prefix.pch"; + MACOSX_DEPLOYMENT_TARGET = 11.0; OTHER_LDFLAGS = ( "-all_load", "-ObjC", ); + PRODUCT_BUNDLE_IDENTIFIER = "com.stevenygard.class-dump"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; }; name = Debug; }; @@ -1417,8 +1480,11 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; + CODE_SIGN_STYLE = Manual; + DEAD_CODE_STRIPPING = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "class-dump-Prefix.pch"; + MACOSX_DEPLOYMENT_TARGET = 11.0; OTHER_LDFLAGS = ( "-all_load", "-ObjC", @@ -1427,7 +1493,9 @@ "___info_plist", Info.plist, ); + PRODUCT_BUNDLE_IDENTIFIER = "com.stevenygard.class-dump"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; }; name = Release; }; diff --git a/class-dump.xcodeproj/project.xcworkspace/xcuserdata/andyvand.xcuserdatad/IDEFindNavigatorScopes.plist b/class-dump.xcodeproj/project.xcworkspace/xcuserdata/andyvand.xcuserdatad/IDEFindNavigatorScopes.plist new file mode 100644 index 00000000..5dd5da85 --- /dev/null +++ b/class-dump.xcodeproj/project.xcworkspace/xcuserdata/andyvand.xcuserdatad/IDEFindNavigatorScopes.plist @@ -0,0 +1,5 @@ + + + + + diff --git a/class-dump.xcodeproj/project.xcworkspace/xcuserdata/andyvand.xcuserdatad/UserInterfaceState.xcuserstate b/class-dump.xcodeproj/project.xcworkspace/xcuserdata/andyvand.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 00000000..bc7cbdd8 Binary files /dev/null and b/class-dump.xcodeproj/project.xcworkspace/xcuserdata/andyvand.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/class-dump.xcodeproj/xcshareddata/xcschemes/all.xcscheme b/class-dump.xcodeproj/xcshareddata/xcschemes/all.xcscheme new file mode 100644 index 00000000..b985ef87 --- /dev/null +++ b/class-dump.xcodeproj/xcshareddata/xcschemes/all.xcscheme @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/class-dump.xcodeproj/xcuserdata/andyvand.xcuserdatad/xcschemes/xcschememanagement.plist b/class-dump.xcodeproj/xcuserdata/andyvand.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 00000000..60cec4fe --- /dev/null +++ b/class-dump.xcodeproj/xcuserdata/andyvand.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,47 @@ + + + + + SchemeUserState + + MachObjC.xcscheme_^#shared#^_ + + orderHint + 3 + + all.xcscheme_^#shared#^_ + + orderHint + 0 + + class-dump.xcscheme_^#shared#^_ + + orderHint + 4 + + deprotect.xcscheme_^#shared#^_ + + orderHint + 1 + + formatType.xcscheme_^#shared#^_ + + orderHint + 2 + + + SuppressBuildableAutocreation + + 0165B8B01827137D00CC647F + + primary + + + 01B02D2E13A5B5D50047BC53 + + primary + + + + + diff --git a/default.profraw b/default.profraw new file mode 100644 index 00000000..55b6a815 Binary files /dev/null and b/default.profraw differ diff --git a/deprotect.m b/deprotect.m index e10921b0..7e5e3147 100644 --- a/deprotect.m +++ b/deprotect.m @@ -24,7 +24,7 @@ void print_usage(void) "Usage: deprotect [options] \n" "\n" " where options are:\n" - " --arch choose a specific architecture from a universal binary (ppc, ppc64, i386, x86_64, armv6, armv7, armv7s, arm64)\n" + " --arch choose a specific architecture from a universal binary (ppc, ppc64, i386, x86_64, x86_64h, armv6, armv7, armv7s, arm64, arm64e, arm64_32)\n" , CLASS_DUMP_VERSION ); @@ -124,7 +124,7 @@ int main(int argc, char *argv[]) NSString *inputFile = [NSString stringWithFileSystemRepresentation:argv[0]]; NSString *outputFile = [NSString stringWithFileSystemRepresentation:argv[1]]; - CDFile *file = [CDFile fileWithContentsOfFile:inputFile searchPathState:nil]; + CDFile *file = [CDFile fileWithContentsOfFile:inputFile cache:nil searchPathState:nil isCache:NO]; if (file == nil) { fprintf(stderr, "Error: input file is neither a Mach-O file nor a fat archive.\n"); exit(EX_DATAERR);