Skip to content

Commit

Permalink
Merge pull request nygard#39 from aricha/master
Browse files Browse the repository at this point in the history
Improved header import generation and forward declaration for classes, protocols, and categories
  • Loading branch information
nygard committed Feb 11, 2014
2 parents f7c4e0a + ef5465f commit 5038762
Show file tree
Hide file tree
Showing 27 changed files with 364 additions and 61 deletions.
5 changes: 4 additions & 1 deletion Source/CDClassFrameworkVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
@interface CDClassFrameworkVisitor : CDVisitor

// NSString (class name) -> NSString (framework name)
@property (nonatomic, readonly) NSDictionary *frameworkNamesByClassName;
@property (nonatomic, readonly) NSDictionary *frameworkNamesByClassName;

// NSString (protocol name) -> NSString (framework name)
@property (nonatomic, readonly) NSDictionary *frameworkNamesByProtocolName;

@end
44 changes: 44 additions & 0 deletions Source/CDClassFrameworkVisitor.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
#import "CDMachOFile.h"
#import "CDOCClass.h"
#import "CDObjectiveCProcessor.h"
#import "CDSymbol.h"
#import "CDLCDylib.h"
#import "CDOCCategory.h"
#import "CDOCClassReference.h"

@interface CDClassFrameworkVisitor ()
@property (strong) NSString *frameworkName;
Expand All @@ -18,13 +22,15 @@ @interface CDClassFrameworkVisitor ()
@implementation CDClassFrameworkVisitor
{
NSMutableDictionary *_frameworkNamesByClassName;
NSMutableDictionary *_frameworkNamesByProtocolName;
NSString *_frameworkName;
}

- (id)init;
{
if ((self = [super init])) {
_frameworkNamesByClassName = [[NSMutableDictionary alloc] init];
_frameworkNamesByProtocolName = [[NSMutableDictionary alloc] init];
}

return self;
Expand All @@ -40,19 +46,57 @@ - (void)willVisitObjectiveCProcessor:(CDObjectiveCProcessor *)processor;
- (void)willVisitClass:(CDOCClass *)aClass;
{
[self addClassName:aClass.name referencedInFramework:self.frameworkName];

// We only need to add superclasses for external classes - classes defined in this binary will be visited on their own
CDOCClassReference *superClassRef = [aClass superClassRef];
if ([superClassRef isExternalClass] && superClassRef.classSymbol) {
[self addClassForExternalSymbol:superClassRef.classSymbol];
}
}

- (void)willVisitProtocol:(CDOCProtocol *)protocol
{
// TODO: (2012-02-28) Figure out what frameworks use each protocol, and try to pick the correct one. More difficult because, for example, NSCopying is found in many frameworks, and picking the last one isn't good enough. Perhaps a topological sort of the dependancies would be better.
[self addProtocolName:protocol.name referencedInFramework:self.frameworkName];
}

- (void)willVisitCategory:(CDOCCategory *)category
{
CDOCClassReference *classRef = [category classRef];
if ([classRef isExternalClass] && classRef.classSymbol) {
[self addClassForExternalSymbol:classRef.classSymbol];
}
}

#pragma mark -

- (void)addClassForExternalSymbol:(CDSymbol *)symbol
{
NSString *frameworkName = CDImportNameForPath([[symbol dylibLoadCommand] path]);
NSString *className = [CDSymbol classNameFromSymbolName:[symbol name]];
[self addClassName:className referencedInFramework:frameworkName];
}

- (void)addClassName:(NSString *)name referencedInFramework:(NSString *)frameworkName;
{
if (name != nil && frameworkName != nil)
_frameworkNamesByClassName[name] = frameworkName;
}

- (void)addProtocolName:(NSString *)name referencedInFramework:(NSString *)frameworkName
{
if (name != nil && frameworkName != nil)
_frameworkNamesByProtocolName[name] = frameworkName;
}

- (NSDictionary *)frameworkNamesByClassName;
{
return [_frameworkNamesByClassName copy];
}

- (NSDictionary *)frameworkNamesByProtocolName
{
return [_frameworkNamesByProtocolName copy];
}

@end
1 change: 1 addition & 0 deletions Source/CDFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ typedef struct {

@class CDMachOFile, CDSearchPathState;

NSString *CDImportNameForPath(NSString *path);
NSString *CDNameForCPUType(cpu_type_t cputype, cpu_subtype_t cpusubtype);
CDArch CDArchFromName(NSString *name);
BOOL CDArchUses64BitABI(CDArch arch);
Expand Down
17 changes: 17 additions & 0 deletions Source/CDFile.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,23 @@
#import "CDMachOFile.h"
#import "CDSearchPathState.h"

NSString *CDImportNameForPath(NSString *path)
{
NSString *name = [path lastPathComponent];

// Remove all extensions (make sure extensions like .a.dylib are covered)
NSString *nameWithExtensions = name;
for (NSInteger i = ([nameWithExtensions length] - 1); i >= 0; i--) {
if ([nameWithExtensions characterAtIndex:i] == '.')
name = [name substringToIndex:i];
}

NSString *libPrefix = @"lib";
if ([name hasPrefix:libPrefix])
name = [name substringFromIndex:[libPrefix length]];
return name;
}

NSString *CDNameForCPUType(cpu_type_t cputype, cpu_subtype_t cpusubtype)
{
const NXArchInfo *archInfo = NXGetArchInfoFromCpuType(cputype, cpusubtype);
Expand Down
1 change: 1 addition & 0 deletions Source/CDLCSymbolTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@
@property (nonatomic, readonly) NSArray *symbols;

- (CDSymbol *)symbolForClassName:(NSString *)className;
- (CDSymbol *)symbolForExternalClassName:(NSString *)className;

@end
35 changes: 23 additions & 12 deletions Source/CDLCSymbolTable.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#import "CDMachOFile.h"
#import "CDSymbol.h"
#import "CDLCSegment.h"
#import "CDLCDylib.h"

@implementation CDLCSymbolTable
{
Expand All @@ -18,6 +19,7 @@ @implementation CDLCSymbolTable
NSUInteger _baseAddress;

NSDictionary *_classSymbols;
NSDictionary *_externalClassSymbols;

struct {
unsigned int didFindBaseAddress:1;
Expand Down Expand Up @@ -98,13 +100,26 @@ - (void)loadSymbols;

NSMutableArray *symbols = [[NSMutableArray alloc] init];
NSMutableDictionary *classSymbols = [[NSMutableDictionary alloc] init];
NSMutableDictionary *externalClassSymbols = [[NSMutableDictionary alloc] init];

CDMachOFileDataCursor *cursor = [[CDMachOFileDataCursor alloc] initWithFile:self.machOFile offset:_symtabCommand.symoff];
//NSLog(@"offset= %lu", [cursor offset]);
//NSLog(@"stroff= %lu", symtabCommand.stroff);
//NSLog(@"strsize= %lu", symtabCommand.strsize);

const char *strtab = (char *)[self.machOFile.data bytes] + _symtabCommand.stroff;

void (^addSymbol)(NSString *, CDSymbol *) = ^(NSString *name, CDSymbol *symbol) {
[symbols addObject:symbol];

NSString *className = [CDSymbol classNameFromSymbolName:symbol.name];
if (className) {
if (symbol.value != 0)
classSymbols[className] = symbol;
else
externalClassSymbols[className] = symbol;
}
};

if (![self.machOFile uses64BitABI]) {
//NSLog(@"32 bit...");
Expand All @@ -127,12 +142,7 @@ - (void)loadSymbols;
NSString *str = [[NSString alloc] initWithBytes:ptr length:strlen(ptr) encoding:NSASCIIStringEncoding];

CDSymbol *symbol = [[CDSymbol alloc] initWithName:str machOFile:self.machOFile nlist32:nlist];
[symbols addObject:symbol];

if ([str hasPrefix:ObjCClassSymbolPrefix] && symbol.value != 0) {
NSString *className = [str substringFromIndex:[ObjCClassSymbolPrefix length]];
classSymbols[className] = symbol;
}
addSymbol(str, symbol);
}

//NSLog(@"Loaded %lu 32-bit symbols", [symbols count]);
Expand All @@ -155,19 +165,15 @@ - (void)loadSymbols;
NSString *str = [[NSString alloc] initWithBytes:ptr length:strlen(ptr) encoding:NSASCIIStringEncoding];

CDSymbol *symbol = [[CDSymbol alloc] initWithName:str machOFile:self.machOFile nlist64:nlist];
[symbols addObject:symbol];

if ([str hasPrefix:ObjCClassSymbolPrefix] && symbol.value != 0) {
NSString *className = [str substringFromIndex:[ObjCClassSymbolPrefix length]];
classSymbols[className] = symbol;
}
addSymbol(str, symbol);
}

//NSLog(@"Loaded %lu 64-bit symbols", [symbols count]);
}

_symbols = [symbols copy];
_classSymbols = [classSymbols copy];
_externalClassSymbols = [externalClassSymbols copy];

//NSLog(@"symbols: %@", _symbols);
}
Expand Down Expand Up @@ -207,4 +213,9 @@ - (CDSymbol *)symbolForClassName:(NSString *)className;
return _classSymbols[className];
}

- (CDSymbol *)symbolForExternalClassName:(NSString *)className
{
return _externalClassSymbols[className];
}

@end
2 changes: 2 additions & 0 deletions Source/CDMachOFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ typedef enum : NSUInteger {
- (BOOL)hasRelocationEntryForAddress2:(NSUInteger)address;
- (NSString *)externalClassNameForAddress2:(NSUInteger)address;

- (CDLCDylib *)dylibLoadCommandForLibraryOrdinal:(NSUInteger)ordinal;

@property (nonatomic, readonly) BOOL hasObjectiveC1Data;
@property (nonatomic, readonly) BOOL hasObjectiveC2Data;
@property (nonatomic, readonly) Class processorClass;
Expand Down
27 changes: 20 additions & 7 deletions Source/CDMachOFile.m
Original file line number Diff line number Diff line change
Expand Up @@ -381,13 +381,7 @@ - (const void *)bytesAtOffset:(NSUInteger)offset;
- (NSString *)importBaseName;
{
if ([self filetype] == MH_DYLIB) {
NSString *str = [self.filename lastPathComponent];
if ([str hasPrefix:@"lib"]) {
NSArray *components = [[str substringFromIndex:3] componentsSeparatedByString:@"."];
str = components[0];
}

return str;
return CDImportNameForPath(self.filename);
}

return nil;
Expand Down Expand Up @@ -576,6 +570,25 @@ - (Class)processorClass;
return [CDObjectiveC1Processor class];
}

- (CDLCDylib *)dylibLoadCommandForLibraryOrdinal:(NSUInteger)libraryOrdinal
{
if (libraryOrdinal == SELF_LIBRARY_ORDINAL || libraryOrdinal >= MAX_LIBRARY_ORDINAL)
return nil;

NSArray *loadCommands = _dylibLoadCommands;
if (_dylibIdentifier) {
// Remove our own ID (LC_ID_DYLIB) so that we calculate the correct offset
NSMutableArray *remainingLoadCommands = [loadCommands mutableCopy];
[remainingLoadCommands removeObject:_dylibIdentifier];
loadCommands = remainingLoadCommands;
}

if (libraryOrdinal - 1 < [loadCommands count]) // Ordinals start from 1
return loadCommands[libraryOrdinal - 1];
else
return nil;
}

- (NSString *)architectureNameDescription;
{
return self.archName;
Expand Down
Loading

0 comments on commit 5038762

Please sign in to comment.