Clang-logos

From iPhone Development Wiki
Jump to: navigation, search

Clang-logos is an Objective-C extension for hooking class methods at runtime via MobileSubstrate. It is developed by Evan Swick.

Overview

Clang-logos builds upon the original Logos preprocessor, but brings quite a few features that the original Logos preprocessor isn't capable of. This is because clang-logos, as indicated by its name, is part of Clang, giving it the full power of the compiler. It isn't a preprocessor; hook code is compiled directly from Objective-C to LLVM IR.

Using Clang allows us to do many things that Perl is not capable of. Most notably, clang-logos can emulate instance variables. Using @synthesize inside of an @hook container will generate getters and setters for an object, using Objective-C associative references. Non-object types such as structs and scalars (int, float, etc) are automatically wrapped in NSValue (this is transparent to the user).

Clang-logos also inserts code to calculate the offset of instance variables at runtime, for ivars referenced within an @hook container. This eliminates the need for MSHookIvar.


Clang-logos is still under development, and many features are yet to come. The information below is subject to change.

Building clang-logos

Building clang-logos is the same as building normal Clang. The source can be downloaded from eswick's GitHub.

See the official documentation for instructions on building.

Usage

Examples

Clang-logos syntax is slightly different than original Logos.

For proper usage, header of the class you're hooking should be in an external file, separate from the file containing the hooks. This header typically comes from class-dump.

// SBIconView.h
@interface SBIconView : UIView { // Ivar declarations are no longer completely useless! (see below)
	SBIcon *_icon;
	SBIconLabelView *_labelView;
	....
}

+ (struct CGSize)defaultIconImageSize;
- (id)initWithDefaultSize;
- (BOOL)isInDock;
...

The hooking code should go in a normal Objective-C file, with an extension of .m / .mm

#import "SBIconView.h"

@interface SBIconView () // Declare a class extension; this is where your new declarations go

@property (nonatomic, retain) UIView *indicatorView;

@new // Methods declared after @new are added to the class at runtime
- (void)updateIndicatorVisibility;

@end


@hook SBIconView // Start a new hook
@synthesize indicatorView; // Generates getters and setters for the new property, "indicatorView"

- (id)initWithDefaultSize {
	
	self = @orig(); // Call the original method; parentheses *must* be specified
	
	if (self) {
		// Initialize our newly added property
		self.indicatorView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 5)];
		self.indicatorView.backgroundColor = [UIColor blackColor];
		
		CGSize defaultSize = [[self class] defaultIconImageSize];
		self.indicatorView.center = CGPointMake(defaultSize.width / 2, defaultSize.height + self.indicatorView.bounds.size.height);
		...
	}
	return self;
}


// This method was declared as 'new' in our class extension
- (void)updateIndicatorVisibility {
	self.indicatorView.hidden = ![self isInDock];
}

- (void)layoutSubviews {
	@orig();
	
	[self updateIndicatorVisibility]; // Call our new method

	if ([self isInDock]) {
		_labelView.hidden = true; // _labelView is an ivar! MSHookIvar no longer needed; the compiler inserts code to find the offset automatically
	}else{
		_labelView.hidden = false;
	}
}

@end

Running clang-logos

Compiling clang-logos source code is the same as compiling normal Objective-C, with one exception; the '-fobjc-logos' flag must be specified. When linking source compiled with clang-logos, it must be linked against libsubstrate.