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.
6 #import "CDLoadCommand.h"
8 #import "CDLCBuildVersion.h"
9 #import "CDLCDyldInfo.h"
11 #import "CDLCDylinker.h"
12 #import "CDLCDynamicSymbolTable.h"
13 #import "CDLCEncryptionInfo.h"
14 #import "CDLCFunctionStarts.h"
15 #import "CDLCLinkeditData.h"
16 #import "CDLCPrebindChecksum.h"
17 #import "CDLCPreboundDylib.h"
18 #import "CDLCRoutines32.h"
19 #import "CDLCRoutines64.h"
20 #import "CDLCRunPath.h"
21 #import "CDLCSegment.h"
22 #import "CDLCSubClient.h"
23 #import "CDLCSubFramework.h"
24 #import "CDLCSubLibrary.h"
25 #import "CDLCSubUmbrella.h"
26 #import "CDLCSymbolTable.h"
27 #import "CDLCTwoLevelHints.h"
28 #import "CDLCUnixThread.h"
30 #import "CDLCUnknown.h"
31 #import "CDLCVersionMinimum.h"
32 #import "CDMachOFile.h"
35 #import "CDLCDataInCode.h"
36 #import "CDLCSourceVersion.h"
38 @implementation CDLoadCommand
40 __weak CDMachOFile *_machOFile;
41 NSUInteger _commandOffset;
44 + (id)loadCommandWithDataCursor:(CDMachOFileDataCursor *)cursor;
46 Class targetClass = [CDLCUnknown class];
48 uint32_t val = [cursor peekInt32];
51 case LC_SEGMENT: targetClass = [CDLCSegment class]; break;
52 case LC_SEGMENT_64: targetClass = [CDLCSegment class]; break;
53 case LC_SYMTAB: targetClass = [CDLCSymbolTable class]; break;
54 //case LC_SYMSEG: // obsolete
55 //case LC_THREAD: // not used?
56 case LC_UNIXTHREAD: targetClass = [CDLCUnixThread class]; break;
57 //case LC_LOADFVMLIB: // not used?
58 //case LC_IDFVMLIB: // not used?
59 //case LC_IDENT: // not used?
60 //case LC_FVMFILE: // not used?
61 //case LC_PREPAGE: // not used
62 case LC_DYSYMTAB: targetClass = [CDLCDynamicSymbolTable class]; break;
63 case LC_LOAD_DYLIB: targetClass = [CDLCDylib class]; break;
64 case LC_ID_DYLIB: targetClass = [CDLCDylib class]; break;
65 case LC_LOAD_DYLINKER: targetClass = [CDLCDylinker class]; break;
66 case LC_ID_DYLINKER: targetClass = [CDLCDylinker class]; break;
67 case LC_PREBOUND_DYLIB: targetClass = [CDLCPreboundDylib class]; break;
68 case LC_ROUTINES: targetClass = [CDLCRoutines32 class]; break;
69 case LC_SUB_FRAMEWORK: targetClass = [CDLCSubFramework class]; break;
70 //case LC_SUB_UMBRELLA: targetClass = [CDLCSubUmbrella class]; break;
71 case LC_SUB_CLIENT: targetClass = [CDLCSubClient class]; break;
72 //case LC_SUB_LIBRARY: targetClass = [CDLCSubLibrary class]; break;
73 case LC_TWOLEVEL_HINTS: targetClass = [CDLCTwoLevelHints class]; break;
74 case LC_PREBIND_CKSUM: targetClass = [CDLCPrebindChecksum class]; break;
75 case LC_LOAD_WEAK_DYLIB: targetClass = [CDLCDylib class]; break;
76 case LC_ROUTINES_64: targetClass = [CDLCRoutines64 class]; break;
77 case LC_UUID: targetClass = [CDLCUUID class]; break;
78 case LC_RPATH: targetClass = [CDLCRunPath class]; break;
79 case LC_CODE_SIGNATURE: targetClass = [CDLCLinkeditData class]; break;
80 case LC_SEGMENT_SPLIT_INFO: targetClass = [CDLCLinkeditData class]; break;
81 case LC_REEXPORT_DYLIB: targetClass = [CDLCDylib class]; break;
82 case LC_LAZY_LOAD_DYLIB: targetClass = [CDLCDylib class]; break;
83 case LC_ENCRYPTION_INFO:
84 case LC_ENCRYPTION_INFO_64: targetClass = [CDLCEncryptionInfo class]; break;
85 case LC_DYLD_INFO: targetClass = [CDLCDyldInfo class]; break;
86 case LC_DYLD_INFO_ONLY: targetClass = [CDLCDyldInfo class]; break;
88 case LC_LOAD_UPWARD_DYLIB: targetClass = [CDLCDylib class]; break;
89 case LC_VERSION_MIN_MACOSX: targetClass = [CDLCVersionMinimum class]; break;
90 case LC_VERSION_MIN_IPHONEOS: targetClass = [CDLCVersionMinimum class]; break;
91 case LC_FUNCTION_STARTS: targetClass = [CDLCFunctionStarts class]; break;
92 case LC_DYLD_ENVIRONMENT: targetClass = [CDLCDylinker class]; break;
93 case LC_MAIN: targetClass = [CDLCMain class]; break;
94 case LC_DATA_IN_CODE: targetClass = [CDLCDataInCode class]; break;
95 case LC_SOURCE_VERSION: targetClass = [CDLCSourceVersion class]; break;
96 case LC_DYLIB_CODE_SIGN_DRS: targetClass = [CDLCLinkeditData class]; break; // Designated Requirements
98 case LC_BUILD_VERSION: targetClass = [CDLCBuildVersion class]; break;
100 case LC_LINKER_OPTION:
101 case LC_LINKER_OPTIMIZATION_HINT:
102 case LC_VERSION_MIN_TVOS:
103 case LC_VERSION_MIN_WATCHOS:
107 NSLog(@"Unknown load command: 0x%08x", val);
110 //NSLog(@"targetClass: %@", NSStringFromClass(targetClass));
112 return [[targetClass alloc] initWithDataCursor:cursor];
115 - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor;
117 if ((self = [super init])) {
118 _machOFile = [cursor machOFile];
119 _commandOffset = [cursor offset];
125 #pragma mark - Debugging
127 - (NSString *)description;
129 return [NSString stringWithFormat:@"<%@:%p> cmd: 0x%08x (%@), cmdsize: %d // %@",
130 NSStringFromClass([self class]), self,
131 self.cmd, self.commandName, self.cmdsize, [self extraDescription]];
134 - (NSString *)extraDescription;
143 // Implement in subclasses
144 [NSException raise:NSGenericException format:@"Must implement method in subclasses."];
150 // Implement in subclasses
151 [NSException raise:NSGenericException format:@"Must implement method in subclasses."];
155 - (BOOL)mustUnderstandToExecute;
157 return (self.cmd & LC_REQ_DYLD) != 0;
160 - (NSString *)commandName;
163 case LC_SEGMENT: return @"LC_SEGMENT";
164 case LC_SYMTAB: return @"LC_SYMTAB";
165 case LC_SYMSEG: return @"LC_SYMSEG";
166 case LC_THREAD: return @"LC_THREAD";
167 case LC_UNIXTHREAD: return @"LC_UNIXTHREAD";
168 case LC_LOADFVMLIB: return @"LC_LOADFVMLIB";
169 case LC_IDFVMLIB: return @"LC_IDFVMLIB";
170 case LC_IDENT: return @"LC_IDENT";
171 case LC_FVMFILE: return @"LC_FVMFILE";
172 case LC_PREPAGE: return @"LC_PREPAGE";
173 case LC_DYSYMTAB: return @"LC_DYSYMTAB";
174 case LC_LOAD_DYLIB: return @"LC_LOAD_DYLIB";
175 case LC_ID_DYLIB: return @"LC_ID_DYLIB";
176 case LC_LOAD_DYLINKER: return @"LC_LOAD_DYLINKER";
177 case LC_ID_DYLINKER: return @"LC_ID_DYLINKER";
178 case LC_PREBOUND_DYLIB: return @"LC_PREBOUND_DYLIB";
179 case LC_ROUTINES: return @"LC_ROUTINES";
180 case LC_SUB_FRAMEWORK: return @"LC_SUB_FRAMEWORK";
181 case LC_SUB_UMBRELLA: return @"LC_SUB_UMBRELLA";
182 case LC_SUB_CLIENT: return @"LC_SUB_CLIENT";
183 case LC_SUB_LIBRARY: return @"LC_SUB_LIBRARY";
184 case LC_TWOLEVEL_HINTS: return @"LC_TWOLEVEL_HINTS";
185 case LC_PREBIND_CKSUM: return @"LC_PREBIND_CKSUM";
187 case LC_LOAD_WEAK_DYLIB: return @"LC_LOAD_WEAK_DYLIB";
188 case LC_SEGMENT_64: return @"LC_SEGMENT_64";
189 case LC_ROUTINES_64: return @"LC_ROUTINES_64";
190 case LC_UUID: return @"LC_UUID";
191 case LC_RPATH: return @"LC_RPATH";
192 case LC_CODE_SIGNATURE: return @"LC_CODE_SIGNATURE";
193 case LC_SEGMENT_SPLIT_INFO: return @"LC_SEGMENT_SPLIT_INFO";
194 case LC_REEXPORT_DYLIB: return @"LC_REEXPORT_DYLIB";
195 case LC_LAZY_LOAD_DYLIB: return @"LC_LAZY_LOAD_DYLIB";
196 case LC_ENCRYPTION_INFO: return @"LC_ENCRYPTION_INFO";
197 case LC_DYLD_INFO: return @"LC_DYLD_INFO";
198 case LC_DYLD_INFO_ONLY: return @"LC_DYLD_INFO_ONLY";
199 case LC_LOAD_UPWARD_DYLIB: return @"LC_LOAD_UPWARD_DYLIB";
200 case LC_VERSION_MIN_MACOSX: return @"LC_VERSION_MIN_MACOSX";
201 case LC_VERSION_MIN_IPHONEOS: return @"LC_VERSION_MIN_IPHONEOS";
202 case LC_FUNCTION_STARTS: return @"LC_FUNCTION_STARTS";
203 case LC_DYLD_ENVIRONMENT: return @"LC_DYLD_ENVIRONMENT";
205 case LC_LINKER_OPTION: return @"LC_LINKER_OPTION";
206 case LC_LINKER_OPTIMIZATION_HINT: return @"LC_LINKER_OPTIMIZATION_HINT";
207 case LC_VERSION_MIN_TVOS: return @"LC_VERSION_MIN_TVOS";
208 case LC_VERSION_MIN_WATCHOS: return @"LC_VERSION_MIN_WATCHOS";
209 case LC_NOTE: return @"LC_NOTE";
210 case LC_BUILD_VERSION: return @"LC_BUILD_VERSION";
216 return [NSString stringWithFormat:@"0x%08x", [self cmd]];
219 - (void)appendToString:(NSMutableString *)resultString verbose:(BOOL)isVerbose;
221 [resultString appendFormat:@" cmd %@", [self commandName]];
222 if (self.mustUnderstandToExecute)
223 [resultString appendFormat:@" (must understand to execute)"];
224 [resultString appendFormat:@"\n"];
225 [resultString appendFormat:@" cmdsize %u\n", [self cmdsize]];
228 - (void)machOFileDidReadLoadCommands:(CDMachOFile *)machOFile;