| Index: class-dump/src/class-dump.m
|
| ===================================================================
|
| --- class-dump/src/class-dump.m (revision 0)
|
| +++ class-dump/src/class-dump.m (revision 0)
|
| @@ -0,0 +1,381 @@
|
| +// -*- mode: ObjC -*-
|
| +
|
| +// This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files.
|
| +// Copyright (C) 1997-1998, 2000-2001, 2004-2010 Steve Nygard.
|
| +
|
| +#include <stdio.h>
|
| +#include <libc.h>
|
| +#include <unistd.h>
|
| +#include <getopt.h>
|
| +#include <stdlib.h>
|
| +#include <mach-o/arch.h>
|
| +
|
| +#import <Foundation/Foundation.h>
|
| +#import "NSString-Extensions.h"
|
| +
|
| +#import "CDClassDump.h"
|
| +#import "CDFindMethodVisitor.h"
|
| +#import "CDClassDumpVisitor.h"
|
| +#import "CDMultiFileVisitor.h"
|
| +#import "CDFile.h"
|
| +#import "CDMachOFile.h"
|
| +#import "CDFatFile.h"
|
| +#import "CDObjectiveC2Processor64.h"
|
| +#import "CDFatArch.h"
|
| +#import "CDSearchPathState.h"
|
| +
|
| +void print_usage(void)
|
| +{
|
| + fprintf(stderr,
|
| + "class-dump %s\n"
|
| + "Usage: class-dump [options] <mach-o-file>\n"
|
| + "\n"
|
| + " where options are:\n"
|
| + " -a show instance variable offsets\n"
|
| + " -A show implementation addresses\n"
|
| + " --arch <arch> choose a specific architecture from a universal binary (ppc, ppc64, i386, x86_64)\n"
|
| + " -C <regex> only display classes matching regular expression\n"
|
| + " -f <str> find string in method name\n"
|
| + " -H generate header files in current directory, or directory specified with -o\n"
|
| + " -I sort classes, categories, and protocols by inheritance (overrides -s)\n"
|
| + " -o <dir> output directory used for -H\n"
|
| + " -r recursively expand frameworks and fixed VM shared libraries\n"
|
| + " -s sort classes and categories by name\n"
|
| + " -S sort methods by name\n"
|
| + " -t suppress header in output, for testing\n"
|
| + " --list-arches list the arches in the file, then exit\n"
|
| + " --sdk-root specify the SDK root path (full path, or 4.1, 4.0, 3.2, 10.6, 10.5, 3.1.3, 3.1.2, 3.1)\n"
|
| + ,
|
| + CLASS_DUMP_VERSION
|
| + );
|
| +}
|
| +
|
| +#define CD_OPT_ARCH 1
|
| +#define CD_OPT_LIST_ARCHES 2
|
| +#define CD_OPT_VERSION 3
|
| +#define CD_OPT_SDK_ROOT 4
|
| +
|
| +struct sdk_alias {
|
| + NSString *alias;
|
| + NSString *path;
|
| +};
|
| +
|
| +struct sdk_alias sdk_aliases[] = {
|
| + { @"3.0", @"/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk", },
|
| + { @"3.1", @"/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.1.sdk", },
|
| + { @"3.1.2", @"/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.1.2.sdk", },
|
| + { @"3.1.3", @"/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.1.3.sdk", },
|
| + { @"3.2", @"/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.2.sdk", },
|
| + { @"4.0", @"/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.0.sdk", },
|
| + { @"4.1", @"/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.1.sdk", },
|
| + { @"10.5", @"/Developer/SDKs/MacOSX10.5.sdk", },
|
| + { @"10.6", @"/Developer/SDKs/MacOSX10.6.sdk", },
|
| + { nil, nil, },
|
| +};
|
| +
|
| +// Keyed by alias, value is full path.
|
| +NSDictionary *sdkAliases(void)
|
| +{
|
| + static NSDictionary *aliases = nil;
|
| +
|
| + if (aliases == nil) {
|
| + NSMutableDictionary *dict;
|
| + struct sdk_alias *ptr = sdk_aliases;
|
| +
|
| + dict = [[NSMutableDictionary alloc] init];
|
| + while (ptr->alias != nil) {
|
| + [dict setObject:ptr->path forKey:ptr->alias];
|
| + ptr++;
|
| + }
|
| + aliases = [dict copy];
|
| + [dict release];
|
| + }
|
| +
|
| + return aliases;
|
| +}
|
| +
|
| +int main(int argc, char *argv[])
|
| +{
|
| + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
| + CDClassDump *classDump;
|
| + CDMultiFileVisitor *multiFileVisitor;
|
| + BOOL shouldFind = NO;
|
| + NSString *searchString = nil;
|
| + BOOL shouldGenerateSeparateHeaders = NO;
|
| + BOOL shouldListArches = NO;
|
| + BOOL shouldPrintVersion = NO;
|
| + CDArch targetArch;
|
| + BOOL hasSpecifiedArch = NO;
|
| +
|
| + int ch;
|
| + BOOL errorFlag = NO;
|
| +
|
| + struct option longopts[] = {
|
| + { "show-ivar-offsets", no_argument, NULL, 'a' },
|
| + { "show-imp-addr", no_argument, NULL, 'A' },
|
| + { "match", required_argument, NULL, 'C' },
|
| + { "find", required_argument, NULL, 'f' },
|
| + { "generate-multiple-files", no_argument, NULL, 'H' },
|
| + { "sort-by-inheritance", no_argument, NULL, 'I' },
|
| + { "output-dir", required_argument, NULL, 'o' },
|
| + { "recursive", no_argument, NULL, 'r' },
|
| + { "sort", no_argument, NULL, 's' },
|
| + { "sort-methods", no_argument, NULL, 'S' },
|
| + { "arch", required_argument, NULL, CD_OPT_ARCH },
|
| + { "list-arches", no_argument, NULL, CD_OPT_LIST_ARCHES },
|
| + { "suppress-header", no_argument, NULL, 't' },
|
| + { "version", no_argument, NULL, CD_OPT_VERSION },
|
| + { "sdk-root", required_argument, NULL, CD_OPT_SDK_ROOT },
|
| + { NULL, 0, NULL, 0 },
|
| + };
|
| +
|
| + if (argc == 1) {
|
| + print_usage();
|
| + exit(0);
|
| + }
|
| +
|
| + classDump = [[[CDClassDump alloc] init] autorelease];
|
| + multiFileVisitor = [[[CDMultiFileVisitor alloc] init] autorelease];
|
| + [multiFileVisitor setClassDump:classDump];
|
| +
|
| + while ( (ch = getopt_long(argc, argv, "aAC:f:HIo:rRsSt", longopts, NULL)) != -1) {
|
| + switch (ch) {
|
| + case CD_OPT_ARCH: {
|
| + NSString *name;
|
| +
|
| + name = [NSString stringWithUTF8String:optarg];
|
| + targetArch = CDArchFromName(name);
|
| + if (targetArch.cputype != CPU_TYPE_ANY)
|
| + hasSpecifiedArch = YES;
|
| + else {
|
| + fprintf(stderr, "Error: Unknown arch %s\n\n", optarg);
|
| + errorFlag = YES;
|
| + }
|
| + break;
|
| + }
|
| +
|
| + case CD_OPT_LIST_ARCHES:
|
| + shouldListArches = YES;
|
| + break;
|
| +
|
| + case CD_OPT_VERSION:
|
| + shouldPrintVersion = YES;
|
| + break;
|
| +
|
| + case CD_OPT_SDK_ROOT: {
|
| + NSString *root, *str;
|
| + NSDictionary *aliases = sdkAliases();
|
| +
|
| + root = [NSString stringWithUTF8String:optarg];
|
| + //NSLog(@"root: %@", root);
|
| + //NSLog(@"aliases: %@", aliases);
|
| + str = [aliases objectForKey:root];
|
| + if (str == nil) {
|
| + classDump.sdkRoot = root;
|
| + } else {
|
| + classDump.sdkRoot = str;
|
| + }
|
| +
|
| + break;
|
| + }
|
| +
|
| + case 'a':
|
| + [classDump setShouldShowIvarOffsets:YES];
|
| + break;
|
| +
|
| + case 'A':
|
| + [classDump setShouldShowMethodAddresses:YES];
|
| + break;
|
| +
|
| + case 'C': {
|
| + NSString *errorMessage;
|
| +
|
| + if ([classDump setRegex:optarg errorMessage:&errorMessage] == NO) {
|
| + fprintf(stderr, "class-dump: Error with regex: '%s'\n\n", [errorMessage UTF8String]);
|
| + errorFlag = YES;
|
| + }
|
| + // Last one wins now.
|
| + break;
|
| + }
|
| +
|
| + case 'f': {
|
| + shouldFind = YES;
|
| +
|
| + searchString = [NSString stringWithUTF8String:optarg];
|
| + break;
|
| + }
|
| +
|
| + case 'H':
|
| + shouldGenerateSeparateHeaders = YES;
|
| + break;
|
| +
|
| + case 'I':
|
| + [classDump setShouldSortClassesByInheritance:YES];
|
| + break;
|
| +
|
| + case 'o':
|
| + [multiFileVisitor setOutputPath:[NSString stringWithUTF8String:optarg]];
|
| + break;
|
| +
|
| + case 'r':
|
| + [classDump setShouldProcessRecursively:YES];
|
| + break;
|
| +
|
| + case 's':
|
| + [classDump setShouldSortClasses:YES];
|
| + break;
|
| +
|
| + case 'S':
|
| + [classDump setShouldSortMethods:YES];
|
| + break;
|
| +
|
| + case 't':
|
| + [classDump setShouldShowHeader:NO];
|
| + break;
|
| +
|
| + case '?':
|
| + default:
|
| + errorFlag = YES;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + if (errorFlag) {
|
| + print_usage();
|
| + exit(2);
|
| + }
|
| +
|
| + if (shouldPrintVersion) {
|
| + printf("class-dump %s compiled %s\n", CLASS_DUMP_VERSION, __DATE__ " " __TIME__);
|
| + exit(0);
|
| + }
|
| +
|
| + if (optind < argc) {
|
| + NSString *arg, *executablePath;
|
| +
|
| + arg = [NSString stringWithFileSystemRepresentation:argv[optind]];
|
| + executablePath = [arg executablePathForFilename];
|
| + if (shouldListArches) {
|
| + if (executablePath == nil) {
|
| + printf("none\n");
|
| + } else {
|
| + CDSearchPathState *searchPathState;
|
| + NSData *data;
|
| + id macho;
|
| +
|
| + searchPathState = [[[CDSearchPathState alloc] init] autorelease];
|
| + searchPathState.executablePath = executablePath;
|
| + data = [[NSData alloc] initWithContentsOfMappedFile:executablePath];
|
| + macho = [CDFile fileWithData:data filename:executablePath searchPathState:searchPathState];
|
| + if (macho == nil) {
|
| + printf("none\n");
|
| + } else {
|
| + if ([macho isKindOfClass:[CDMachOFile class]]) {
|
| + printf("%s\n", [[macho archName] UTF8String]);
|
| + } else if ([macho isKindOfClass:[CDFatFile class]]) {
|
| + printf("%s\n", [[[macho archNames] componentsJoinedByString:@" "] UTF8String]);
|
| + }
|
| + }
|
| + [data release];
|
| + }
|
| + } else {
|
| + CDFile *file;
|
| + NSData *data;
|
| +
|
| + if (executablePath == nil) {
|
| + fprintf(stderr, "class-dump: Input file (%s) doesn't contain an executable.\n", [arg fileSystemRepresentation]);
|
| + exit(1);
|
| + }
|
| +
|
| + data = [[NSData alloc] initWithContentsOfMappedFile:executablePath];
|
| + if (data == nil) {
|
| + NSFileManager *defaultManager = [NSFileManager defaultManager];
|
| +
|
| + if ([defaultManager fileExistsAtPath:executablePath]) {
|
| + fprintf(stderr, "class-dump: Input file (%s) is not readable (check read rights).\n", [executablePath UTF8String]);
|
| + } else {
|
| + fprintf(stderr, "class-dump: Input file (%s) does not exist.\n", [executablePath UTF8String]);
|
| + }
|
| +
|
| + exit(1);
|
| + }
|
| +
|
| + classDump.searchPathState.executablePath = [executablePath stringByDeletingLastPathComponent];
|
| + file = [CDFile fileWithData:data filename:executablePath searchPathState:classDump.searchPathState];
|
| + if (file == nil) {
|
| + fprintf(stderr, "class-dump: Input file (%s) is neither a Mach-O file nor a fat archive.\n", [executablePath UTF8String]);
|
| + [data release];
|
| + exit(1);
|
| + }
|
| +#if 0
|
| + {
|
| + CDFatFile *fat = file;
|
| + NSArray *a1;
|
| + NSUInteger count, index;
|
| +
|
| + a1 = [fat arches];
|
| + count = [a1 count];
|
| + for (index = 0; index < count; index++)
|
| + [[[a1 objectAtIndex:index] machOData] writeToFile:[NSString stringWithFormat:@"/tmp/arch-%u", index] atomically:NO];
|
| +
|
| + exit(99);
|
| + }
|
| +#endif
|
| + if (hasSpecifiedArch == NO) {
|
| + if ([file bestMatchForLocalArch:&targetArch] == NO) {
|
| + fprintf(stderr, "Error: Couldn't get local architecture\n");
|
| + exit(1);
|
| + }
|
| + //NSLog(@"No arch specified, best match for local arch is: (%08x, %08x)", targetArch.cputype, targetArch.cpusubtype);
|
| + } else {
|
| + //NSLog(@"chosen arch is: (%08x, %08x)", targetArch.cputype, targetArch.cpusubtype);
|
| + }
|
| +
|
| +#ifndef __LP64__
|
| + if (CDArchUses64BitABI(targetArch)) {
|
| + fprintf(stderr, "Error: Can't dump 64-bit files with 32-bit version of class-dump\n");
|
| + exit(1);
|
| + }
|
| +#endif
|
| +
|
| + [classDump setTargetArch:targetArch];
|
| + classDump.searchPathState.executablePath = [executablePath stringByDeletingLastPathComponent];
|
| +
|
| + if ([classDump loadFile:file]) {
|
| +#if 0
|
| + [classDump showHeader];
|
| + [classDump showLoadCommands];
|
| + exit(5);
|
| +#endif
|
| +
|
| + [classDump processObjectiveCData];
|
| + [classDump registerTypes];
|
| +
|
| + if (shouldFind) {
|
| + CDFindMethodVisitor *visitor;
|
| +
|
| + visitor = [[CDFindMethodVisitor alloc] init];
|
| + [visitor setClassDump:classDump];
|
| + [visitor setFindString:searchString];
|
| + [classDump recursivelyVisit:visitor];
|
| + [visitor release];
|
| + } else if (shouldGenerateSeparateHeaders) {
|
| + [classDump recursivelyVisit:multiFileVisitor];
|
| + } else {
|
| + CDClassDumpVisitor *visitor;
|
| +
|
| + visitor = [[CDClassDumpVisitor alloc] init];
|
| + [visitor setClassDump:classDump];
|
| + [classDump recursivelyVisit:visitor];
|
| + [visitor release];
|
| + }
|
| + }
|
| +
|
| + [data release];
|
| + }
|
| + }
|
| +
|
| + [pool release];
|
| +
|
| + return 0;
|
| +}
|
|
|
| Property changes on: class-dump/src/class-dump.m
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|