blob: 200fcbe82e59e7bdc26a6ca1bf06127430252cad [file] [log] [blame]
// -*- 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 "CDClassDumpVisitor.h"
#include <mach-o/arch.h>
#import "CDClassDump.h"
#import "CDObjectiveCProcessor.h"
#import "CDMachOFile.h"
#import "CDLCBuildVersion.h"
#import "CDLCDylib.h"
#import "CDLCDylinker.h"
#import "CDLCEncryptionInfo.h"
#import "CDLCRunPath.h"
#import "CDLCSegment.h"
#import "CDLCSourceVersion.h"
#import "CDLCVersionMinimum.h"
#import "CDTypeController.h"
@implementation CDClassDumpVisitor
{
}
- (void)willBeginVisiting;
{
[super willBeginVisiting];
[self.classDump appendHeaderToString:self.resultString];
if (self.classDump.hasObjectiveCRuntimeInfo && self.shouldShowStructureSection) {
[self.classDump.typeController appendStructuresToString:self.resultString];
}
}
- (void)didEndVisiting;
{
[super didEndVisiting];
[self writeResultToStandardOutput];
}
- (void)visitObjectiveCProcessor:(CDObjectiveCProcessor *)processor;
{
CDMachOFile *machOFile = processor.machOFile;
[self.resultString appendString:@"#pragma mark -\n\n"];
[self.resultString appendString:@"//\n"];
[self.resultString appendFormat:@"// File: %@\n", machOFile.filename];
if (machOFile.UUID != nil) {
[self.resultString appendFormat:@"// UUID: %@\n", [machOFile.UUID UUIDString]];
}
[self.resultString appendString:@"//\n"];
[self.resultString appendFormat:@"// Arch: %@\n", CDNameForCPUType(machOFile.cputype, machOFile.cpusubtype)];
if (machOFile.filetype == MH_DYLIB) {
CDLCDylib *identifier = machOFile.dylibIdentifier;
if (identifier != nil) {
[self.resultString appendFormat:@"// Current version: %@\n", identifier.formattedCurrentVersion];
[self.resultString appendFormat:@"// Compatibility version: %@\n", identifier.formattedCompatibilityVersion];
}
}
if (machOFile.sourceVersion != nil)
[self.resultString appendFormat:@"// Source version: %@\n", machOFile.sourceVersion.sourceVersionString];
if (machOFile.buildVersion != nil) {
[self.resultString appendFormat:@"// Build version: %@\n", machOFile.buildVersion.buildVersionString];
[self.resultString appendFormat:@"// Tools: %@\n", [machOFile.buildVersion.toolStrings componentsJoinedByString:@"\n "]];
}
if (machOFile.minVersionMacOSX != nil) {
[self.resultString appendFormat:@"// Minimum Mac OS X version: %@\n", machOFile.minVersionMacOSX.minimumVersionString];
[self.resultString appendFormat:@"// SDK version: %@\n", machOFile.minVersionMacOSX.SDKVersionString];
}
if (machOFile.minVersionIOS != nil) {
[self.resultString appendFormat:@"// Minimum iOS version: %@\n", machOFile.minVersionIOS.minimumVersionString];
[self.resultString appendFormat:@"// SDK version: %@\n", machOFile.minVersionIOS.SDKVersionString];
}
if (processor.garbageCollectionStatus != nil) {
[self.resultString appendString:@"//\n"];
[self.resultString appendFormat:@"// Objective-C Garbage Collection: %@\n", processor.garbageCollectionStatus];
}
[machOFile.dyldEnvironment enumerateObjectsUsingBlock:^(CDLCDylinker *env, NSUInteger index, BOOL *stop){
if (index == 0) {
[self.resultString appendString:@"//\n"];
[self.resultString appendFormat:@"// dyld environment: %@\n", env.name];
} else {
[self.resultString appendFormat:@"// %@\n", env.name];
}
}];
if ([machOFile.runPathCommands count] > 0) {
[self.resultString appendString:@"//\n"];
for (CDLCRunPath *runPath in machOFile.runPathCommands) {
[self.resultString appendFormat:@"// Run path: %@\n", runPath.path];
[self.resultString appendFormat:@"// = %@\n", runPath.resolvedRunPath];
}
}
if (machOFile.isEncrypted) {
[self.resultString appendString:@"// This file is encrypted:\n"];
for (CDLoadCommand *loadCommand in machOFile.loadCommands) {
if ([loadCommand isKindOfClass:[CDLCEncryptionInfo class]]) {
CDLCEncryptionInfo *encryptionInfo = (CDLCEncryptionInfo *)loadCommand;
[self.resultString appendFormat:@"// cryptid: 0x%08x\n", encryptionInfo.cryptid];
[self.resultString appendFormat:@"// cryptoff: 0x%08x\n", encryptionInfo.cryptoff];
[self.resultString appendFormat:@"// cryptsize: 0x%08x\n", encryptionInfo.cryptsize];
}
}
} else if (machOFile.hasProtectedSegments) {
if (machOFile.canDecryptAllSegments) {
[self.resultString appendString:@"//\n"];
[self.resultString appendString:@"// This file has protected segments, decrypting.\n"];
} else {
[self.resultString appendString:@"//\n"];
[self.resultString appendString:@"// This file has protected segments that can't be decrypted:\n"];
[machOFile.loadCommands enumerateObjectsUsingBlock:^(CDLoadCommand *loadCommand, NSUInteger index, BOOL *stop){
if ([loadCommand isKindOfClass:[CDLCSegment class]]) {
CDLCSegment *segment = (CDLCSegment *)loadCommand;
if (segment.canDecrypt == NO) {
[self.resultString appendFormat:@"// Load command %lu, segment encryption: %@\n",
index, CDSegmentEncryptionTypeName(segment.encryptionType)];
}
}
}];
}
}
[self.resultString appendString:@"//\n\n"];
if (!self.classDump.hasObjectiveCRuntimeInfo) {
[self.resultString appendString:@"//\n"];
[self.resultString appendString:@"// This file does not contain any Objective-C runtime information.\n"];
[self.resultString appendString:@"//\n"];
}
}
@end