init project

添加初始项目
This commit is contained in:
DKJone
2019-01-23 11:38:18 +08:00
parent ae931fb755
commit b2ddc1ad24
40 changed files with 8411 additions and 7 deletions
@@ -0,0 +1,108 @@
// weibo: http://weibo.com/xiaoqing28
// blog: http://www.alonemonkey.com
//
// AntiAntiDebug.m
// MonkeyDev
//
// Created by AloneMonkey on 2016/12/10.
// Copyright © 2017年 MonkeyDev. All rights reserved.
//
#if TARGET_OS_SIMULATOR
#error Do not support the simulator, please use the real iPhone Device.
#endif
#import "fishhook.h"
#import <Foundation/Foundation.h>
#import <sys/sysctl.h>
typedef int (*ptrace_ptr_t)(int _request,pid_t _pid, caddr_t _addr,int _data);
typedef void* (*dlsym_ptr_t)(void * __handle, const char* __symbol);
typedef int (*syscall_ptr_t)(int, ...);
typedef int (*sysctl_ptr_t)(int *,u_int, void*, size_t*,void*, size_t);
static ptrace_ptr_t orig_ptrace = NULL;
static dlsym_ptr_t orig_dlsym = NULL;
static sysctl_ptr_t orig_sysctl = NULL;
static syscall_ptr_t orig_syscall = NULL;
int my_ptrace(int _request, pid_t _pid, caddr_t _addr, int _data);
void* my_dlsym(void* __handle, const char* __symbol);
int my_sysctl(int * name, u_int namelen, void * info, size_t * infosize, void * newinfo, size_t newinfosize);
int my_syscall(int code, va_list args);
int my_ptrace(int _request, pid_t _pid, caddr_t _addr, int _data){
if(_request != 31){
return orig_ptrace(_request,_pid,_addr,_data);
}
NSLog(@"[AntiAntiDebug] - ptrace request is PT_DENY_ATTACH");
return 0;
}
void* my_dlsym(void* __handle, const char* __symbol){
if(strcmp(__symbol, "ptrace") != 0){
return orig_dlsym(__handle, __symbol);
}
NSLog(@"[AntiAntiDebug] - dlsym get ptrace symbol");
return my_ptrace;
}
typedef struct kinfo_proc _kinfo_proc;
int my_sysctl(int * name, u_int namelen, void * info, size_t * infosize, void * newinfo, size_t newinfosize){
if(namelen == 4 && name[0] == CTL_KERN && name[1] == KERN_PROC && name[2] == KERN_PROC_PID && info && infosize && ((int)*infosize == sizeof(_kinfo_proc))){
int ret = orig_sysctl(name, namelen, info, infosize, newinfo, newinfosize);
struct kinfo_proc *info_ptr = (struct kinfo_proc *)info;
if(info_ptr && (info_ptr->kp_proc.p_flag & P_TRACED) != 0){
NSLog(@"[AntiAntiDebug] - sysctl query trace status.");
info_ptr->kp_proc.p_flag ^= P_TRACED;
if((info_ptr->kp_proc.p_flag & P_TRACED) == 0){
NSLog(@"trace status reomve success!");
}
}
return ret;
}
return orig_sysctl(name, namelen, info, infosize, newinfo, newinfosize);
}
int my_syscall(int code, va_list args){
int request;
va_list newArgs;
va_copy(newArgs, args);
if(code == 26){
#ifdef __LP64__
__asm__(
"ldr %w[result], [fp, #0x10]\n"
: [result] "=r" (request)
:
:
);
#else
request = va_arg(args, int);
#endif
if(request == 31){
NSLog(@"[AntiAntiDebug] - syscall call ptrace, and request is PT_DENY_ATTACH");
return 0;
}
}
return orig_syscall(code, newArgs);
}
__attribute__((constructor)) static void entry(){
NSLog(@"[AntiAntiDebug Init]");
rebind_symbols((struct rebinding[1]){{"ptrace", my_ptrace, (void*)&orig_ptrace}},1);
rebind_symbols((struct rebinding[1]){{"dlsym", my_dlsym, (void*)&orig_dlsym}},1);
//some app will crash with _dyld_debugger_notification
// rebind_symbols((struct rebinding[1]){{"sysctl", my_sysctl, (void*)&orig_sysctl}},1);
rebind_symbols((struct rebinding[1]){{"syscall", my_syscall, (void*)&orig_syscall}},1);
}
@@ -0,0 +1,85 @@
// weibo: http://weibo.com/xiaoqing28
// blog: http://www.alonemonkey.com
//
// MDConfigManager.h
// MonkeyDev
//
// Created by AloneMonkey on 2018/4/24.
// Copyright © 2018年 AloneMonkey. All rights reserved.
//
#import <Foundation/Foundation.h>
#define MDCONFIG_CYCRIPT_KEY @"Cycript"
#define MDCONFIG_LOADATLAUNCH_KEY @"LoadAtLaunch"
#define MDCONFIG_TRACE_KEY @"MethodTrace"
#define MDCONFIG_LOG_LEVEL_KEY @"LogLevel"
#define MDCONFIG_LOG_WHEN_KEY @"LogWhen"
#define MDCONFIG_LOG_REGEX_STRING_KEY @"LogRegexString" // 仅LogWhen=MDTraceLogWhenRegexString有效
#define MDCONFIG_TRACE_FLAG_KEY @"TraceFlag"
#define MDCONFIG_TRACE_OBJECT_KEY @"TraceObject"
#define MDCONFIG_CLASS_REGEX_STRING_KEY @"ClassRegexString" // 仅TraceObject=MDTraceObjectRegexClass有效
#define MDCONFIG_CORE_CLASS_LIST @"CORE_CLASS_LIST"
#define MDCONFIG_USER_CLASS_LIST @"USER_CLASS_LIST"
#define MDCONFIG_TRACE_MODE_KEY @"TraceMode"
#define MDCONFIG_METHOD_WHITE_LIST_KEY @"MethodWhiteList"
#define MDCONFIG_METHOD_BLACK_LIST_KEY @"MethodBlackList"
// Trace日志级别
typedef NS_ENUM(NSUInteger, MDTraceLogLevel) {
MDTraceLogLeveError = 0, // 错误
MDTraceLogLeveDebug = 1, // 调试
MDTraceLogLeveMax
};
// Trace日志输出时机
typedef NS_ENUM(NSUInteger, MDTraceLogWhen) {
MDTraceLogWhenStartup = 0, // 启动即输出日志
MDTraceLogWhenVolume = 1, // 根据音量键控制输出日志(增加音量:输出日志;降低音量:关闭日志;默认时关闭日志)
MDTraceLogWhenRegexString = 2, // 日志包含指定正则字符串才输出日志
MDTraceLogWhenMax
};
// Trace控制位(尽量在该处扩展)
typedef NS_OPTIONS(NSUInteger, MDTraceFlag) {
MDTraceFlagDoesNotUseDescription = 1 << 0, // 跳过调用对象description方法,避免不正规的description实现导致递归
MDTraceFlagDumpClassListInfo = 1 << 1, // 打印类列表信息,便于调试
MDTraceFlagDumpClassMethod = 1 << 2, // 打印某个类的方法(不包括父类方法),便于调试
MDTraceFlagDumpSuperClassMethod = 1 << 3, // 打印某个类的父类方法(包括递归父类的方法),便于调试
MDTraceFlagMask = 0xF,
MDTraceFlagDefault = 0,
};
// Trace对象
typedef NS_ENUM(NSUInteger, MDTraceObject) {
// 屏蔽trace所有类
MDTraceObjectNone = 0,
// trace引擎指定类的方法(仅测试验证使用),仅需要考虑CORE_CLASS_LIST
MDTraceObjectCoreClass = 1,
// trace用户指定类的方法,需要考虑USER_CLASS_LIST + "USER_CLASS_LIST和CORE_CLASS_LIST交集"
MDTraceObjectUserClass = 2,
// trace用户指定类 + 正则匹配类的方法,需要考虑USER_CLASS_LIST + "USER_CLASS_LIST和CORE_CLASS_LIST交集" +
// "匹配ClassRegexString的CLASS_LIST和CORE_CLASS_LIST交集"
MDTraceObjectRegexClass = 3,
MDTraceObjectMax
};
// Trace模式
typedef NS_ENUM(NSUInteger, MDTraceMode) {
MDTraceModeOff = 0, // 屏蔽trace方法
MDTraceModeAll = 1, // trace所有方法
MDTraceModeIncludeWhiteList = 2, // trace包含"白名单方法列表"的方法
MDTraceModeExcludeBlackList = 3, // trace排除"黑名单方法列表"的方法
MDTraceModeMax
};
@interface MDConfigManager : NSObject
+ (instancetype)sharedInstance;
- (NSDictionary*)readConfigByKey:(NSString*) key;
@end
@@ -0,0 +1,48 @@
// weibo: http://weibo.com/xiaoqing28
// blog: http://www.alonemonkey.com
//
// MDConfigManager.m
// MonkeyDev
//
// Created by AloneMonkey on 2018/4/24.
// Copyright © 2018年 AloneMonkey. All rights reserved.
//
#define CONFIG_FILE_NAME @"MDConfig"
#import "MDConfigManager.h"
@implementation MDConfigManager{
NSString* _filepath;
}
+ (instancetype)sharedInstance{
static MDConfigManager *sharedInstance = nil;
if (!sharedInstance){
sharedInstance = [[MDConfigManager alloc] init];
}
return sharedInstance;
}
- (BOOL)isActive{
_filepath = [[NSBundle mainBundle] pathForResource:CONFIG_FILE_NAME ofType:@"plist"];
if(_filepath == nil){
return NO;
}
return YES;
}
- (NSDictionary*) readConfigByKey:(NSString*) key{
if([self isActive]){
NSDictionary* contentDict = [NSDictionary dictionaryWithContentsOfFile:_filepath];
if([contentDict.allKeys containsObject:key]){
return contentDict[key];
}else{
return nil;
}
}else{
return nil;
}
}
@end
@@ -0,0 +1,40 @@
// weibo: http://weibo.com/xiaoqing28
// blog: http://www.alonemonkey.com
//
// MDCycriptManager.h
// MonkeyDev
//
// Created by AloneMonkey on 2018/3/8.
// Copyright © 2018年 AloneMonkey. All rights reserved.
//
#ifndef __OPTIMIZE__
#import <Foundation/Foundation.h>
#define PORT 6666
@interface MDCycriptManager : NSObject
+ (instancetype)sharedInstance;
/**
Download script by config.plist
@param update Force update of all scripts
*/
-(void)loadCycript:(BOOL) update;
/**
eval javascript by cycript
@param cycript javascript string
@param error error happened
@return eval result
*/
-(NSString*)evaluateCycript:(NSString*) cycript error:(NSError **) error;
@end
#endif
@@ -0,0 +1,306 @@
// weibo: http://weibo.com/xiaoqing28
// blog: http://www.alonemonkey.com
//
// MDCycriptManager.m
// MonkeyDev
//
// Created by AloneMonkey on 2018/3/8.
// Copyright © 2018年 AloneMonkey. All rights reserved.
//
#ifndef __OPTIMIZE__
#import "MDCycriptManager.h"
#import "MDConfigManager.h"
#import <ifaddrs.h>
#import <arpa/inet.h>
#import <net/if.h>
#import <pthread.h>
#import <JavaScriptCore/JavaScriptCore.h>
#define IOS_CELLULAR @"pdp_ip0"
#define IOS_WIFI @"en0"
#define IP_ADDR_IPv4 @"ipv4"
#define IP_ADDR_IPv6 @"ipv6"
#define MDLog(fmt, ...) NSLog((@"[Cycript] " fmt), ##__VA_ARGS__)
extern JSGlobalContextRef CYGetJSContext(void);
extern void CydgetMemoryParse(const uint16_t **data, size_t *size);
NSString * const CYErrorLineKey = @"CYErrorLineKey";
NSString * const CYErrorNameKey = @"CYErrorNameKey";
NSString * const CYErrorMessageKey = @"CYErrorMessageKey";
@interface MDSettingObject : NSObject
@property (nonatomic, assign) NSInteger priority;
@property (nonatomic, copy) NSString* url;
@property (nonatomic, copy) NSString* content;
@property (nonatomic, assign) BOOL loadAtLaunch;
-(instancetype)initWithDicationary:(NSDictionary*) dictionary;
@end
@implementation MDSettingObject
-(instancetype)initWithDicationary:(NSDictionary *)dictionary{
self = [super init];
if(self){
self.priority = [dictionary[@"priority"] integerValue];
self.url = dictionary[@"url"];
self.content = dictionary[@"content"];
self.loadAtLaunch = [dictionary objectForKey:MDCONFIG_LOADATLAUNCH_KEY] && [dictionary[MDCONFIG_LOADATLAUNCH_KEY] boolValue];
}
return self;
}
@end
@interface MDCycriptManager()
@property (nonatomic, strong) NSDictionary* configItem;
@property (nonatomic, copy) NSString* cycriptDirectory;
@property (nonatomic, strong) NSMutableArray* downloading;
@property (nonatomic, strong) NSMutableDictionary* loadAtLaunchModules;
@end
@implementation MDCycriptManager
+ (instancetype)sharedInstance{
static MDCycriptManager *sharedInstance = nil;
if (!sharedInstance){
sharedInstance = [[MDCycriptManager alloc] init];
}
return sharedInstance;
}
- (instancetype)init
{
self = [super init];
if (self) {
_loadAtLaunchModules = [NSMutableDictionary dictionary];
_downloading = [NSMutableArray array];
[self check];
[self readConfigFile];
}
return self;
}
-(void)check{
NSString* ip = [self getIPAddress];
if(ip != nil){
printf("\nDownload cycript(https://cydia.saurik.com/api/latest/3) then run: ./cycript -r %s:%d\n\n", [ip UTF8String], PORT);
}else{
printf("\nPlease connect wifi before using cycript!\n\n");
}
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *documentsPath =[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES) firstObject];
_cycriptDirectory = [documentsPath stringByAppendingPathComponent:@"cycript"];
[fileManager createDirectoryAtPath:_cycriptDirectory withIntermediateDirectories:YES attributes:nil error:nil];
}
-(NSArray*)sortedArray:(NSDictionary*) dictionary{
NSMutableArray* result = [NSMutableArray arrayWithCapacity:10];
NSArray* sortedArray = [dictionary.allKeys sortedArrayUsingComparator:^NSComparisonResult(NSNumber* _Nonnull number1, NSNumber* _Nonnull number2) {
if ([number1 integerValue] > [number2 integerValue])
return NSOrderedDescending;
return NSOrderedAscending;
}];
for (NSNumber* item in sortedArray) {
[result addObject:dictionary[item]];
}
return [result copy];
}
-(void)readConfigFile{
MDConfigManager * configManager = [MDConfigManager sharedInstance];
_configItem = [configManager readConfigByKey:MDCONFIG_CYCRIPT_KEY];
}
-(void)loadCycript:(BOOL) update{
NSFileManager *fileManager = [NSFileManager defaultManager];
if(_configItem && _configItem.count > 0){
BOOL download = NO;
for (NSString* moduleName in _configItem.allKeys) {
MDSettingObject * item = [[MDSettingObject alloc] initWithDicationary:_configItem[moduleName]];
NSString *fullPath = [[_cycriptDirectory stringByAppendingPathComponent:moduleName] stringByAppendingPathExtension:@"cy"];
if(item.url){
if(![fileManager fileExistsAtPath:fullPath] || update){
download = YES;
[self.downloading addObject:moduleName];
[self downLoadUrl:item.url saveName:moduleName];
}
}
if(item.content){
if(![fileManager fileExistsAtPath:fullPath] || update){
NSString* writeContent = [NSString stringWithFormat:@"(function(exports) { %@ })(exports);", item.content];
[writeContent writeToFile:fullPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
}
}
if(item.loadAtLaunch){
[_loadAtLaunchModules setObject:fullPath forKey:@(item.priority)];
}
}
if(!download){
[self finishDownload];
}
}
}
-(void)finishDownload{
MDLog(@"Finish download all script!");
NSArray* sortedArray = [self sortedArray:_loadAtLaunchModules];
for (NSString* fullPath in sortedArray) {
NSError* error;
[self evaluateCycript:[NSString stringWithFormat:@"require('%@');",fullPath] error:&error];
if(error.code != 0){
MDLog(@"%@", error.localizedDescription);
}
}
}
-(void)downLoadUrl:(NSString*) urlString saveName:(NSString*) filename{
__weak typeof(self) weakSelf = self;
NSURLSession *session = [NSURLSession sharedSession];
NSURL *url = [NSURL URLWithString:urlString];
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:url completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if(error){
MDLog(@"Failed download script [%@]: %@", filename, error.localizedDescription);
}else{
NSString *fullPath = [[weakSelf.cycriptDirectory stringByAppendingPathComponent:filename] stringByAppendingPathExtension:@"cy"];
[[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];
MDLog(@"Successful download script [%@]", filename);
}
[weakSelf.downloading removeObject:filename];
if(!weakSelf.downloading.count){
[weakSelf finishDownload];
}
}];
[downloadTask resume];
}
-(NSString *)evaluateCycript:(NSString *)cycript error:(NSError *__autoreleasing *)error{
NSString *resultString = nil;
static pthread_mutex_t cycript_metex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&cycript_metex); {
JSGlobalContextRef context = CYGetJSContext();
size_t length = cycript.length;
unichar *buffer = malloc(length * sizeof(unichar));
[cycript getCharacters:buffer range:NSMakeRange(0, length)];
const uint16_t *characters = buffer;
CydgetMemoryParse(&characters, &length);
JSStringRef expression = JSStringCreateWithCharacters(characters, length);
// Evaluate the Javascript
JSValueRef exception = NULL;
JSValueRef result = JSEvaluateScript(context, expression, NULL, NULL, 0, &exception);
JSStringRelease(expression);
// If a result was returned, convert it into an NSString
if (result) {
JSStringRef string = JSValueToStringCopy(context, result, &exception);
if (string) {
resultString = (__bridge_transfer NSString *)JSStringCopyCFString(kCFAllocatorDefault, string);
JSStringRelease(string);
}
}
// If an exception was thrown, convert it into an NSError
if (exception && error) {
JSObjectRef exceptionObject = JSValueToObject(context, exception, NULL);
NSInteger line = (NSInteger)JSValueToNumber(context, JSObjectGetProperty(context, exceptionObject, JSStringCreateWithUTF8CString("line"), NULL), NULL);
JSStringRef string = JSValueToStringCopy(context, JSObjectGetProperty(context, exceptionObject, JSStringCreateWithUTF8CString("name"), NULL), NULL);
NSString *name = (__bridge_transfer NSString *)JSStringCopyCFString(kCFAllocatorDefault, string);
JSStringRelease(string);
string = JSValueToStringCopy(context, JSObjectGetProperty(context, exceptionObject, JSStringCreateWithUTF8CString("message"), NULL), NULL);
NSString *message = (__bridge_transfer NSString *)JSStringCopyCFString(kCFAllocatorDefault, string);
JSStringRelease(string);
string = JSValueToStringCopy(context, exception, NULL);
NSString *description = (__bridge_transfer NSString *)JSStringCopyCFString(kCFAllocatorDefault, string);
JSStringRelease(string);
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
[userInfo setValue:@(line) forKey:CYErrorLineKey];
[userInfo setValue:name forKey:CYErrorNameKey];
[userInfo setValue:message forKey:CYErrorMessageKey];
[userInfo setValue:description forKey:NSLocalizedDescriptionKey];
*error = [NSError errorWithDomain:@"CYContextDomain" code:0 userInfo:userInfo];
}
}pthread_mutex_unlock(&cycript_metex);
return resultString;
}
- (NSString *)getIPAddress{
NSDictionary *addresses = [self getIPAddresses];
if([addresses.allKeys containsObject:IOS_WIFI @"/" IP_ADDR_IPv4]){
return addresses[IOS_WIFI @"/" IP_ADDR_IPv4];
}
return nil;
}
- (NSDictionary *)getIPAddresses{
NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:8];
// retrieve the current interfaces - returns 0 on success
struct ifaddrs *interfaces;
if(!getifaddrs(&interfaces)) {
// Loop through linked list of interfaces
struct ifaddrs *interface;
for(interface=interfaces; interface; interface=interface->ifa_next) {
if(!(interface->ifa_flags & IFF_UP) /* || (interface->ifa_flags & IFF_LOOPBACK) */ ) {
continue; // deeply nested code harder to read
}
const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr;
char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ];
if(addr && (addr->sin_family==AF_INET || addr->sin_family==AF_INET6)) {
NSString *name = [NSString stringWithUTF8String:interface->ifa_name];
NSString *type;
if(addr->sin_family == AF_INET) {
if(inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN)) {
type = IP_ADDR_IPv4;
}
} else {
const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)interface->ifa_addr;
if(inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, INET6_ADDRSTRLEN)) {
type = IP_ADDR_IPv6;
}
}
if(type) {
NSString *key = [NSString stringWithFormat:@"%@/%@", name, type];
addresses[key] = [NSString stringWithUTF8String:addrBuf];
}
}
}
// Free memory
freeifaddrs(interfaces);
}
return [addresses count] ? addresses : nil;
}
@end
#endif
@@ -0,0 +1,30 @@
// weibo: http://weibo.com/xiaoqing28
// blog: http://www.alonemonkey.com
//
// MDMethodTrace.h
// MonkeyDev
//
// Created by AloneMonkey on 2017/9/7.
// Copyright © 2017年 AloneMonkey. All rights reserved.
//
#ifndef MethodTrace_h
#define MethodTrace_h
#define TRACE_README @"\n📚--------------------OCMethodTrace(Usage)-------------------📚\nhttps://github.com/omxcodec/OCMethodTrace/blob/master/README.md\n📚--------------------OCMethodTrace(Usage)-------------------📚"
#import <UIKit/UIKit.h>
@interface MDMethodTrace : NSObject
+ (instancetype)sharedInstance;
- (void)addClassTrace:(NSString *) className;
- (void)addClassTrace:(NSString *)className methodName:(NSString *)methodName;
- (void)addClassTrace:(NSString *)className methodList:(NSArray *)methodList;
@end
#endif /* MethodTrace_h */
@@ -0,0 +1,923 @@
// weibo: http://weibo.com/xiaoqing28
// blog: http://www.alonemonkey.com
//
// MDMethodTrace.m
// MonkeyDev
//
// Created by AloneMonkey on 2017/9/6.
// Copyright © 2017年 AloneMonkey. All rights reserved.
//
#import "MDMethodTrace.h"
#import <objc/runtime.h>
#import <AVFoundation/AVFoundation.h>
#import "MDConfigManager.h"
#import "OCMethodTrace.h"
//#define USE_DDLOG // 使用外部日志系统,日志多的时候特别有用
#ifdef USE_DDLOG
#import "CocoaLumberjack.h"
static const int ddLogLevel = DDLogLevelVerbose;
#define MDLog(fmt, ...) DDLogDebug((@"[MethodTrace] " fmt), ##__VA_ARGS__)
#else
//#define MDLog(fmt, ...) NSLog((@"[MethodTrace] " fmt), ##__VA_ARGS__)
#define MDLog(fmt, ...) printf("[MethodTrace] %s\n",[[NSString stringWithFormat:fmt, ##__VA_ARGS__] UTF8String]);
#endif
#define SAFE_CHECK(_object, _type) (_type *)[[self class] safeCheck:_object class:[_type class]]
#define MDFatal(fmt, ...) [NSException raise:@"MDMethodTrace" format:fmt, ##__VA_ARGS__]
// 指定ClassInfo源
typedef NS_ENUM(NSUInteger, MDTraceSource) {
MDTraceSourceCore = 0, // 引擎指定(引擎指OCMethodTrace内部实现框架)
MDTraceSourceUser = 1, // 用户指定
MDTraceSourceMerge = 2, // 引擎和用户合并
MDTraceSourceMax
};
////////////////////////////////////////////////////////////////////////////////
#pragma mark - Class Define
@interface MDTraceClassInfo : NSObject
@property (nonatomic, strong) NSString *name; // 类名
@property (nonatomic, assign) MDTraceSource source; // 指定源
@property (nonatomic, assign) MDTraceMode mode; // trace模式
@property (nonatomic, assign) MDTraceFlag flag; // flag
@property (nonatomic, strong) NSMutableArray *methodList; // 黑名单或者白名单,根据mode决定
// 解析类配置,无key则加key,设置默认值,并校验值类型
+ (instancetype)infoWithName:(NSString *)name source:(MDTraceSource)source config:(NSDictionary *)config;
// 根据类型返回引擎指定的默认ClassInfo
+ (instancetype)defaultCoreClassInfo:(NSString *)name;
// 根据类型返回用户指定的默认ClassInfo
+ (instancetype)defaultUserClassInfo:(NSString *)name;
// 安全检查
+ (id)safeCheck:(id)content class:(Class)cls;
// 数组相减: arrayA - arrayB
+ (NSArray *)minusWithArrayA:(NSArray *)arrayA arrayB:(NSArray *)arrayB;
// 数组相加: arrayA + arrayB,可去重,相同元素只保留一个
+ (NSArray *)unionWithArrayA:(NSArray *)arrayA arrayB:(NSArray *)arrayB;
// 合并引擎和用户ClassInfo,合并时core的优先级比user大,具体见函数内部实现
+ (MDTraceClassInfo *)mergeInfoWithCoreInfo:(MDTraceClassInfo *)coreInfo userInfo:(MDTraceClassInfo *)userInfo;
// 合并引擎和用户config
+ (MDTraceClassInfo *)mergeInfoWithName:(NSString *)name coreConfig:(NSDictionary *)coreConfig userConfig:(NSDictionary *)userConfig;
@end
@interface MDMethodTrace () <OCMethodTraceDelegate>
@property (nonatomic, strong) NSMutableDictionary *config;
@property (nonatomic, assign) MDTraceLogLevel logLevel; // 日志级别
@property (nonatomic, assign) MDTraceLogWhen logWhen; // 日志输出时机
@property (nonatomic, strong) NSString *logRegexString; // 日志正则匹配字符串,仅当logWhen=MDTraceLogWhenRegexString有效
@property (nonatomic, assign) NSInteger numberOfPendingLog; // logRegexString匹配后,待输出afer日志个数
@property (nonatomic, assign) CGFloat lastSystemVolume; // 上一次系统音量
@property (nonatomic, assign) MDTraceFlag traceFlag; // 控制trace行为的一些特殊flag
@property (nonatomic, assign) MDTraceObject traceObject; // trace对象
@property (nonatomic, strong) NSString *classRegexString; // 类正则匹配字符串
@property (nonatomic, strong) NSMutableArray *coreClassInfoList; // 引擎类信息列表
@property (nonatomic, strong) NSMutableArray *userClassInfoList; // 用户类信息列表
@property (nonatomic, strong) NSMutableArray *regexClassInfoList; // 正则类信息列表
// 解析配置文件
- (void)parseConfig:(NSDictionary *)config;
@end
////////////////////////////////////////////////////////////////////////////////
#pragma mark - MDTraceClassInfo
@implementation MDTraceClassInfo
- (instancetype)init
{
self = [super init];
if (self) {
self.name = @"NoName";
self.source = MDTraceSourceUser;
self.mode = MDTraceModeAll;
self.flag = MDTraceFlagDefault;
self.methodList = [NSMutableArray array];
}
return self;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p name: %@ source: %tu mode: %tu flag: %tu methodList: %@>",
NSStringFromClass([self class]), self, _name, _source, _mode, _flag, _methodList];
}
+ (instancetype)infoWithName:(NSString *)name source:(MDTraceSource)source config:(NSDictionary *)config
{
// 无对应字典说明用户没有指定类,不处理
if (nil == config) {
return nil;
}
MDTraceClassInfo *info = [[MDTraceClassInfo alloc] init];
info.name = name;
info.source = source;
// 1 mode
info.mode = info.source == MDTraceSourceCore ? MDTraceModeOff: MDTraceModeAll;
if (![config valueForKey:MDCONFIG_TRACE_MODE_KEY]) {
// MDLog(@"Cannot find class %@ %@, set it to default %d", info.name, MDCONFIG_TRACE_MODE_KEY, (int)info.mode);
} else {
info.mode = [SAFE_CHECK(config[MDCONFIG_TRACE_MODE_KEY], NSNumber) integerValue];
}
// 2 flag
info.flag = MDTraceFlagDefault;
if (![config valueForKey:MDCONFIG_TRACE_FLAG_KEY]) {
// MDLog(@"Cannot find class %@ %@, set it to default %d", info.name, MDCONFIG_TRACE_FLAG_KEY, (int)info.flag);
} else {
info.flag = [SAFE_CHECK(config[MDCONFIG_TRACE_FLAG_KEY], NSNumber) integerValue];
}
// 3 whiteList
if ([config valueForKey:MDCONFIG_METHOD_WHITE_LIST_KEY]) {
id methodList = config[MDCONFIG_METHOD_WHITE_LIST_KEY];
if (![methodList isKindOfClass:[NSArray class]]) {
MDFatal(@"Class %@ %@ should be array", info.name, MDCONFIG_METHOD_WHITE_LIST_KEY);
} else if (info.mode == MDTraceModeIncludeWhiteList) {
info.methodList = methodList;
}
}
// 4 blackList
if ([config valueForKey:MDCONFIG_METHOD_BLACK_LIST_KEY]) {
id methodList = config[MDCONFIG_METHOD_BLACK_LIST_KEY];
if (![methodList isKindOfClass:[NSArray class]]) {
MDFatal(@"Class %@ %@ should be array", info.name, MDCONFIG_METHOD_BLACK_LIST_KEY);
} else if (info.mode == MDTraceModeExcludeBlackList) {
info.methodList = methodList;
}
}
return info;
}
+ (instancetype)defaultCoreClassInfo:(NSString *)name
{
MDTraceClassInfo *info = [[MDTraceClassInfo alloc] init];
info.name = name;
info.source = MDTraceSourceCore;
info.mode = MDTraceModeOff;
return info;
}
+ (instancetype)defaultUserClassInfo:(NSString *)name
{
MDTraceClassInfo *info = [[MDTraceClassInfo alloc] init];
info.name = name;
info.source = MDTraceSourceUser;
info.mode = MDTraceModeAll;
return info;
}
+ (id)safeCheck:(id)content class:(Class)cls
{
if ([content isKindOfClass:cls]) {
return content;
}
MDFatal(@"safeCheck failed, content(%@) should be class(%@) type", content, NSStringFromClass(cls));
return nil;
}
+ (NSArray *)minusWithArrayA:(NSArray *)arrayA arrayB:(NSArray *)arrayB
{
NSMutableOrderedSet *setA = [NSMutableOrderedSet orderedSetWithArray:arrayA];
NSMutableOrderedSet *setB = [NSMutableOrderedSet orderedSetWithArray:arrayB];
[setA minusOrderedSet:setB];
return [setA array];
}
+ (NSArray *)unionWithArrayA:(NSArray *)arrayA arrayB:(NSArray *)arrayB
{
NSMutableOrderedSet *setA = [NSMutableOrderedSet orderedSetWithArray:arrayA];
NSMutableOrderedSet *setB = [NSMutableOrderedSet orderedSetWithArray:arrayB];
[setA unionOrderedSet:setB];
return [setA array];
}
- (void)setSource:(MDTraceSource)source
{
NSAssert(source >= MDTraceSourceCore && source < MDTraceSourceMax, @"invalid TraceSource");
_source = source;
}
- (void)setMode:(MDTraceMode)mode
{
NSAssert(mode >= MDTraceModeOff && mode < MDTraceModeMax, @"invalid TraceMode");
_mode = mode;
}
- (void)setFlag:(MDTraceFlag)flag
{
NSAssert(flag >= MDTraceModeOff && flag <= MDTraceFlagMask, @"invalid TraceFlag");
_flag = flag;
}
- (id)copyWithZone:(NSZone *)zone
{
MDTraceClassInfo *info = [[self.class allocWithZone:zone] init];
info.name = self.name;
info.source = self.source;
info.mode = self.mode;
info.flag = self.flag;
info.methodList = [NSMutableArray arrayWithArray:self.methodList];
return info;
}
+ (MDTraceClassInfo *)mergeInfoWithCoreInfo:(MDTraceClassInfo *)coreInfo userInfo:(MDTraceClassInfo *)userInfo
{
if (nil == coreInfo && nil == userInfo) {
NSAssert(0, @"invalid info");
return nil;
}
MDTraceClassInfo *mergeInfo = nil;
if (nil != coreInfo && nil == userInfo) {
NSAssert(coreInfo.source == MDTraceSourceCore, @"invalid core source");
mergeInfo = [coreInfo copy];
} else if (nil == coreInfo && nil != userInfo) {
NSAssert(userInfo.source == MDTraceSourceUser, @"invalid user source");
mergeInfo = [userInfo copy];
} else {
NSAssert([coreInfo.name isEqualToString:userInfo.name], @"invalid name");
NSAssert(coreInfo.source == MDTraceSourceCore, @"invalid core source");
NSAssert(coreInfo.mode == MDTraceModeOff || coreInfo.mode == MDTraceModeExcludeBlackList, @"invalid core mode");
NSAssert(userInfo.source == MDTraceSourceUser, @"invalid user source");
mergeInfo = [[MDTraceClassInfo alloc] init];
mergeInfo.name = coreInfo.name;
mergeInfo.source = MDTraceSourceMerge;
mergeInfo.flag = coreInfo.flag | userInfo.flag;
// core优先级比user优先级高
if (coreInfo.mode == MDTraceModeOff) {
// core关闭则无需关心user配置
mergeInfo.mode = MDTraceModeOff;
} else if (coreInfo.mode == MDTraceModeExcludeBlackList) {
switch (userInfo.mode) {
case MDTraceModeOff:
// user关闭就不trace这个类
mergeInfo.mode = MDTraceModeOff;
break;
case MDTraceModeAll:
// 排除core指定的黑名单
mergeInfo.mode = MDTraceModeExcludeBlackList;
[mergeInfo.methodList addObjectsFromArray:coreInfo.methodList];
break;
case MDTraceModeIncludeWhiteList:
// user白名单排除掉core黑名单
mergeInfo.mode = MDTraceModeIncludeWhiteList;
[mergeInfo.methodList addObjectsFromArray:[[self class] minusWithArrayA:userInfo.methodList arrayB:coreInfo.methodList]];
break;
case MDTraceModeExcludeBlackList:
// user黑名单加上core黑名单
mergeInfo.mode = MDTraceModeExcludeBlackList;
[mergeInfo.methodList addObjectsFromArray:[[self class] unionWithArrayA:userInfo.methodList arrayB:coreInfo.methodList]];
break;
default:
break;
}
}
}
return mergeInfo;
}
+ (MDTraceClassInfo *)mergeInfoWithName:(NSString *)name coreConfig:(NSDictionary *)coreConfig userConfig:(NSDictionary *)userConfig;
{
MDTraceClassInfo *coreInfo = [MDTraceClassInfo infoWithName:name source:MDTraceSourceCore config:coreConfig];
MDTraceClassInfo *userInfo = [MDTraceClassInfo infoWithName:name source:MDTraceSourceUser config:userConfig];
return [MDTraceClassInfo mergeInfoWithCoreInfo:coreInfo userInfo:userInfo];
}
@end
////////////////////////////////////////////////////////////////////////////////
#pragma mark - MDMethodTrace
@implementation MDMethodTrace
+ (instancetype)sharedInstance {
static MDMethodTrace *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[MDMethodTrace alloc] init];
});
return sharedInstance;
}
- (instancetype)init
{
self = [super init];
if (self) {
self.logLevel = MDTraceLogLeveDebug;
self.logWhen = MDTraceLogWhenStartup;
self.traceFlag = MDTraceFlagDefault;
self.traceObject = MDTraceObjectNone;
self.coreClassInfoList = [[NSMutableArray alloc] init];
self.userClassInfoList = [[NSMutableArray alloc] init];
self.regexClassInfoList = [[NSMutableArray alloc] init];
}
return self;
}
- (void)dealloc
{
#if !TARGET_OS_SIMULATOR
[self removeVolumeObserver];
#endif
}
#pragma mark - Trace utils
+ (NSString *)docPath
{
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
}
// 安全检查
+ (id)safeCheck:(id)content class:(Class)cls
{
if ([content isKindOfClass:cls]) {
return content;
}
MDFatal(@"safeCheck failed, content(%@) should be class(%@) type", content, NSStringFromClass(cls));
return nil;
}
// 正则匹配 optionss是否需要更多参数???
// FIXME -[NSString rangeOfString:options:NSRegularExpressionSearch]在实际运行中会死循环,不太明白原因
+ (BOOL)isMatchRegexString:(NSString *)regexString inputString:(NSString *)inputString
{
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexString options:NSRegularExpressionDotMatchesLineSeparators | NSRegularExpressionAnchorsMatchLines error:&error];
NSTextCheckingResult *result = [regex firstMatchInString:inputString options:0 range:NSMakeRange(0, [inputString length])];
return nil != result;
}
// 获取object名称
+ (NSString *)NSStringFromTraceObject:(MDTraceObject)traceObject
{
NSString *name;
switch (traceObject) {
case MDTraceObjectNone:
name = @"未指定类";
break;
case MDTraceObjectCoreClass:
name = @"引擎类";
break;
case MDTraceObjectUserClass:
name = @"用户类";
break;
case MDTraceObjectRegexClass:
name = @"正则类";
break;
default:
NSAssert1(0, @"Unkown trace object: %tu", traceObject);
break;
}
return name;
}
// 判断object是否属于测试模式
+ (BOOL)isTestTraceObject:(MDTraceObject)traceObject
{
return (traceObject == MDTraceObjectCoreClass);
}
// 获取当前classInfoList
- (NSArray *)classInfoList
{
if (self.traceObject == MDTraceObjectCoreClass) {
return self.coreClassInfoList;
} else if (self.traceObject == MDTraceObjectUserClass) {
return self.userClassInfoList;
} else if (self.traceObject == MDTraceObjectRegexClass) {
return self.regexClassInfoList;
}
return nil;
}
// 查找某个类是否存在classInfoList中
- (MDTraceClassInfo *)infoInClassInfoList:(NSString *)className
{
for (MDTraceClassInfo *info in [self classInfoList]) {
if ([info.name isEqualToString:className]) {
return info;
}
}
return nil;
}
// dump输出ClassListInfo
- (void)dumpClassListInfo
{
if (!(self.traceFlag & MDTraceFlagDumpClassListInfo)) {
return;
}
MDLog(@"Dump %@ class list info: ", [[self class] NSStringFromTraceObject:self.traceObject]);
MDLog(@"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
NSArray *classInfoList = [self classInfoList];
for (int i = 0; i < classInfoList.count; i++) {
MDLog(@"ClassList[%05d]: %@", i, classInfoList[i]);
}
MDLog(@"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
}
// dump类所有方法信息
- (void)dumpClassMethodInfo:(MDTraceClassInfo *)classInfo
{
if (!(self.traceFlag & MDTraceFlagDumpClassMethod || classInfo.flag & MDTraceFlagDumpClassMethod)) {
return;
}
MDLog(@"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
Class cls = NSClassFromString(classInfo.name);
while (nil != cls) {
unsigned int numMethods = 0;
Method *methodList = class_copyMethodList(cls, &numMethods);
if (NULL != methodList) {
for (unsigned int i = 0; i < numMethods; i ++) {
MDLog(@"-Class[%@] method[%03d]: %@", cls, i, [[self class] methodInfo:methodList[i]]);
}
}
Class metaClass = object_getClass(cls);
methodList = class_copyMethodList(metaClass, &numMethods);
if (NULL != methodList) {
for (unsigned int i = 0; i < numMethods; i ++) {
MDLog(@"+Class[%@] method[%03d]: %@", cls, i, [[self class] methodInfo:methodList[i]]);
}
}
if (!(self.traceFlag & MDTraceFlagDumpSuperClassMethod || classInfo.flag & MDTraceFlagDumpSuperClassMethod)) {
break;
}
cls = [cls superclass];
}
MDLog(@"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
}
// 某方法信息
+ (NSString *)methodInfo:(Method)method
{
return [NSString stringWithFormat:@"name[%s] IMP[%p]", sel_getName(method_getName(method)), method_getImplementation(method)];
}
#pragma mark - Trace log
// 初始化日志系统
- (void)initLogger
{
#ifdef USE_DDLOG
// 外部Lumberjack logger, 日志存放于目录"~/Library/Caches/Logs"
[DDLog addLogger:[DDTTYLogger sharedInstance]]; // TTY = Xcode 控制台
// [[DDTTYLogger sharedInstance] setColorsEnabled:YES];
// [DDLog addLogger:[DDASLLogger sharedInstance]]; // ASL = Apple System Logs 苹果系统日志
DDFileLogger *fileLogger = [[DDFileLogger alloc] init]; // 本地文件日志
fileLogger.doNotReuseLogFiles = YES;
fileLogger.logFileManager.maximumNumberOfLogFiles = 1; // 永远创建一个文件,便于观察日志
fileLogger.maximumFileSize = 0;
fileLogger.rollingFrequency = 0;
[DDLog addLogger:fileLogger];
#endif
// 内部logger
[[OCMethodTrace sharedInstance] setLogLevel:self.logLevel == MDTraceLogLeveError ? OMTLogLevelError : OMTLogLevelDebug];
[[OCMethodTrace sharedInstance] setDelegate:self];
}
// trace开关
- (void)enableTrace:(BOOL)enable
{
if (!enable) {
[OCMethodTrace sharedInstance].disableTrace = YES;
} else {
if (self.logWhen == MDTraceLogWhenVolume) {
#if TARGET_OS_SIMULATOR
[OCMethodTrace sharedInstance].disableTrace = NO;
self.logWhen = MDTraceLogWhenStartup;
MDLog(@"Volume control log is not supported when simulator, reset logWhen to %tu", self.logWhen);
#else
self.lastSystemVolume = [[AVAudioSession sharedInstance] outputVolume];
// 需要异步注册通知,否则无法工作
dispatch_async(dispatch_get_main_queue(), ^{
[self addVolumeObserver];
});
#endif
} else {
[OCMethodTrace sharedInstance].disableTrace = NO;
}
}
}
#if !TARGET_OS_SIMULATOR
- (void)addVolumeObserver
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(onSystemVolumeChanged:) name:@"AVSystemController_SystemVolumeDidChangeNotification"
object:nil];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}
- (void)removeVolumeObserver
{
[[NSNotificationCenter defaultCenter] removeObserver:self
name:@"AVSystemController_SystemVolumeDidChangeNotification"
object:nil];
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
}
- (void)onSystemVolumeChanged:(NSNotification *)notification
{
NSString *category = notification.userInfo[@"AVSystemController_AudioCategoryNotificationParameter"];
NSString *changeReason = notification.userInfo[@"AVSystemController_AudioVolumeChangeReasonNotificationParameter"];
if (![category isEqualToString:@"Audio/Video"] || ![changeReason isEqualToString:@"ExplicitVolumeChange"]) {
return;
}
CGFloat volume = [[notification userInfo][@"AVSystemController_AudioVolumeNotificationParameter"] floatValue];
[OCMethodTrace sharedInstance].disableTrace = volume < self.lastSystemVolume; // 音量升高触发日志输出
self.lastSystemVolume = volume;
}
#endif
#pragma mark - Trace parse config
- (void)parseConfig:(NSDictionary *)config
{
if (nil == config) {
return;
}
MDLog(TRACE_README);
self.config = [NSMutableDictionary dictionaryWithDictionary:config];
self.logLevel = [SAFE_CHECK(self.config[MDCONFIG_LOG_LEVEL_KEY], NSNumber) unsignedIntegerValue];
self.logWhen = [SAFE_CHECK(self.config[MDCONFIG_LOG_WHEN_KEY], NSNumber) unsignedIntegerValue];
self.traceFlag = [SAFE_CHECK(self.config[MDCONFIG_TRACE_FLAG_KEY], NSNumber) unsignedIntegerValue];
self.traceObject = [SAFE_CHECK(self.config[MDCONFIG_TRACE_OBJECT_KEY], NSNumber) unsignedIntegerValue];
MDLog(@"logLevel: %tu: logWhen: %tu traceFlag: %tu traceObject: %tu(%@%@)",
self.logLevel, self.logWhen, self.traceFlag, self.traceObject,
[[self class] NSStringFromTraceObject:self.traceObject],
[[self class] isTestTraceObject:self.traceObject] ? @"(仅测试验证使用,不建议开启)" : @"");
// 检查配置有效性
[self checkConfig];
// 初始化日志
[self initLogger];
// 屏蔽trace输出。避免hook准备过程中导致的递归调用
[self enableTrace:NO];
// 实际hook类的各种方法
[self traceClassObject];
// 恢复trace输出
[self enableTrace:YES];
}
- (void)checkConfig
{
NSAssert(self.logLevel >= MDTraceLogLeveError && self.logLevel < MDTraceLogLeveMax, @"invalid loglevel");
NSAssert(self.logWhen >= MDTraceLogWhenStartup && self.logWhen < MDTraceLogWhenMax, @"invalid logWhen");
NSAssert(self.traceFlag >= 0 && self.traceFlag <= MDTraceFlagMask, @"invalid traceFlag");
NSAssert(self.traceObject >= MDTraceObjectNone && self.traceObject < MDTraceObjectMax, @"invalid traceObject");
if (self.logWhen == MDTraceLogWhenRegexString) {
self.logRegexString = SAFE_CHECK(self.config[MDCONFIG_LOG_REGEX_STRING_KEY], NSString);
if (self.logRegexString.length == 0) {
MDFatal(@"LogRegexString is nil");
}
MDLog(@"LogRegexString: %@", self.logRegexString);
}
if (self.traceObject == MDTraceObjectRegexClass) {
self.classRegexString = SAFE_CHECK(self.config[MDCONFIG_CLASS_REGEX_STRING_KEY], NSString);
if (self.classRegexString.length == 0) {
MDFatal(@"ClassRegexString is nil");
}
MDLog(@"ClassRegexString: %@", self.classRegexString);
}
}
- (void)traceClassObject
{
if (self.traceObject == MDTraceObjectNone) {
MDLog(@"Method Trace is disabled");
return;
}
[self parseClassListInfo];
[self dumpClassListInfo];
[self traceClassListInfo];
}
- (void)parseClassListInfo
{
id object = nil;
NSDictionary *coreClassListDict = nil;
NSDictionary *userClassListDict = nil;
NSMutableArray *classList = [[NSMutableArray alloc] init];
NSMutableArray *regexClassList = [[NSMutableArray alloc] init];
object = [self.config valueForKey:MDCONFIG_CORE_CLASS_LIST];
if (nil != object) {
coreClassListDict = SAFE_CHECK(object, NSDictionary);
}
object = [self.config valueForKey:MDCONFIG_USER_CLASS_LIST];
if (nil != object) {
userClassListDict = SAFE_CHECK(object, NSDictionary);
}
// 1 获取真实存在的类
int numberOfClasses = objc_getClassList(NULL, 0);
Class *tmpClassList = (Class *)malloc(sizeof(Class) * numberOfClasses);
if (NULL != tmpClassList) {
objc_getClassList(tmpClassList, numberOfClasses);
for (int i = 0; i < numberOfClasses; i++) {
NSString *className = NSStringFromClass(tmpClassList[i]);
[classList addObject:className];
if (self.traceObject == MDTraceObjectRegexClass && [[self class] isMatchRegexString:self.classRegexString inputString:className]) {
// 多次匹配可能是重复类,需要去重
if (![regexClassList containsObject:className]) {
[regexClassList addObject:className];
}
}
}
free(tmpClassList);
}
// 2 获取classInfo
if (self.traceObject == MDTraceObjectCoreClass) {
// 2.1 core
for (NSString *className in coreClassListDict.allKeys) {
if (![classList containsObject:className]) {
MDLog(@"Cannot find class %@", className);
continue;
}
NSDictionary *coreConfig = coreClassListDict[className];
MDTraceClassInfo *coreInfo = [MDTraceClassInfo infoWithName:className source:MDTraceSourceCore config:coreConfig];
[self.coreClassInfoList addObject:coreInfo];
}
} else if (self.traceObject == MDTraceObjectUserClass) {
// 2.2 user,注意,user需要跟core合并,优先级:core > user
for (NSString *className in userClassListDict.allKeys) {
if (![classList containsObject:className]) {
MDLog(@"Cannot find class %@", className);
continue;
}
NSDictionary *coreConfig = coreClassListDict[className];
NSDictionary *userConfig = userClassListDict[className];
MDTraceClassInfo *mergeinfo = [MDTraceClassInfo mergeInfoWithName:className coreConfig:coreConfig userConfig:userConfig];
[self.userClassInfoList addObject:mergeinfo];
}
} else if (self.traceObject == MDTraceObjectRegexClass) {
// 2.3 regex, 优先级:core > user > regex
// 2.3.1 user需要跟core合并,优先级:core > user
for (NSString *className in userClassListDict.allKeys) {
if (![classList containsObject:className]) {
MDLog(@"Cannot find class %@", className);
continue;
}
NSDictionary *coreConfig = coreClassListDict[className];
NSDictionary *userConfig = userClassListDict[className];
MDTraceClassInfo *mergeinfo = [MDTraceClassInfo mergeInfoWithName:className coreConfig:coreConfig userConfig:userConfig];
[self.regexClassInfoList addObject:mergeinfo];
}
// 2.3.2 regex需要跟core合并,优先级:core > regex。regex匹配的类可理解成更低优先级的user类
NSDictionary *defaultUserConfig = [[NSDictionary alloc] init];
for (NSString *className in regexClassList) {
if (nil == [self infoInClassInfoList:className]) {
NSDictionary *coreConfig = coreClassListDict[className];
MDTraceClassInfo *mergeinfo = [MDTraceClassInfo mergeInfoWithName:className coreConfig:coreConfig userConfig:defaultUserConfig];
[self.regexClassInfoList addObject:mergeinfo];
}
}
}
}
- (void)traceClassListInfo
{
MDLog(@" ");
MDLog(@"////////////////////////////////////////////////////////////////////////////////");
MDLog(@" ");
NSArray *classInfoList = [self classInfoList];
for (int i = 0; i < classInfoList.count; i++) {
MDTraceClassInfo *info = classInfoList[i];
if (nil != objc_getClass([info.name UTF8String])) {
MDLog(@"ClassList[%05d]: %@", i, info.name);
[self traceClass:info];
} else {
MDLog(@"Cannot find class %@", info.name);
}
}
MDLog(@" ");
MDLog(@"////////////////////////////////////////////////////////////////////////////////");
MDLog(@" ");
}
- (void)traceClass:(MDTraceClassInfo *)classInfo
{
if (nil == classInfo) {
return;
}
[self dumpClassMethodInfo:classInfo];
if (classInfo.mode == MDTraceModeOff) {
} else if (classInfo.mode == MDTraceModeAll) {
[self addClassTrace:classInfo.name];
} else if (classInfo.mode == MDTraceModeIncludeWhiteList) {
[self addClassTrace:classInfo.name methodList:classInfo.methodList white:YES];
} else if (classInfo.mode == MDTraceModeExcludeBlackList) {
[self addClassTrace:classInfo.name methodList:classInfo.methodList white:NO];
}
[self dumpClassMethodInfo:classInfo];
}
#pragma mark - Trace method
- (void)addClassTrace:(NSString *)className{
[self addClassTrace:className methodList:nil];
}
- (void)addClassTrace:(NSString *)className methodName:(NSString *)methodName {
[self addClassTrace:className methodList:@[methodName]];
}
- (void)addClassTrace:(NSString *)className methodList:(NSArray*)methodList {
[self addClassTrace:className methodList:methodList white:YES];
}
- (void)addClassTrace:(NSString *)className methodList:(NSArray *)methodList white:(BOOL)white {
Class targetClass = objc_getClass([className UTF8String]);
if (targetClass != nil) {
[[OCMethodTrace sharedInstance] traceMethodWithClass:NSClassFromString(className) condition:^BOOL(SEL sel) {
if (methodList == nil || methodList.count == 0) {
return YES;
}
for (id object in methodList) {
NSString *methodName = SAFE_CHECK(object, NSString);
// 方法可以是正则表达式
if ([[self class] isMatchRegexString:methodName inputString:NSStringFromSelector(sel)]) {
return white;
}
}
return !white;
} before:^(id target, Class cls, SEL sel, NSArray *args, int deep) {
NSString *selector = NSStringFromSelector(sel);
NSMutableString *selectorString = [NSMutableString new];
if ([selector containsString:@":"]) {
NSArray *selectorArrary = [selector componentsSeparatedByString:@":"];
selectorArrary = [selectorArrary filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"length > 0"]];
for (int i = 0; i < selectorArrary.count; i++) {
[selectorString appendFormat:@"%@:%@ ", selectorArrary[i], args[i]];
}
} else {
[selectorString appendString:selector];
}
NSMutableString *deepString = [NSMutableString new];
for (int i = 0; i < deep; i++) {
[deepString appendString:@"-"];
}
// [obj class]则分两种情况:
// 1 当obj为实例对象时,[obj class]中class是实例方法:- (Class)class,返回的obj对象中的isa指针;
// 2 当obj为类对象(包括元类和根类以及根元类)时,调用的是类方法:+ (Class)class,返回的结果为其本身。
NSString *prefix = target == [target class] ? @"+" : @"-";
// target不是强引用,如果打印接口异步,可能未实际调用description就被释放了,所以提前获取desc,保证线程安全
NSString *description = [self descriptionWithTarget:target class:cls selector:sel targetPosition:OMTTargetPositionBeforeSelf];
NSString *logString = nil;
if ([target class] != [cls class]) {
// 如果是子类调用基类方法,则()内打印基类名
logString = [NSString stringWithFormat:@"%@%@[%@(%@) %@]", deepString, prefix, description, NSStringFromClass(cls), selectorString];
} else {
logString = [NSString stringWithFormat:@"%@%@[%@ %@]", deepString, prefix, description, selectorString];
}
if (self.logWhen == MDTraceLogWhenStartup ||
self.logWhen == MDTraceLogWhenVolume ||
(self.logWhen == MDTraceLogWhenRegexString && [[self class] isMatchRegexString:self.logRegexString inputString:logString])) {
self.numberOfPendingLog++;
MDLog(@"%@", logString);
}
} after:^(id target, Class cls, SEL sel, id ret, int deep, NSTimeInterval interval) {
// 因为多线程并发,numberOfPendingLog变量维护的输出状态有可能并不是那么准,但是打印调试可以容忍
if (self.numberOfPendingLog > 0) {
self.numberOfPendingLog--;
NSMutableString *deepString = [NSMutableString new];
for (int i = 0; i < deep; i++) {
[deepString appendString:@"-"];
}
NSString *prefix = target == [target class] ? @"+" : @"-";
MDLog(@"%@%@ret:%@", deepString, prefix, ret);
}
}];
} else {
MDLog(@"Canot find class %@", className);
}
}
#pragma mark - OCMethodTraceDelegate
- (NSString *)descriptionWithTarget:(id)target class:(Class)cls selector:(SEL)sel targetPosition:(OMTTargetPosition)targetPosition
{
if (nil == target) {
return @"nil";
}
NSString *targetClassName = NSStringFromClass([target class]);
// 全局跳过对象description方法
if (self.traceFlag & MDTraceFlagDoesNotUseDescription) {
return [NSString stringWithFormat:@"<%@: %p>", targetClassName, target];
}
// 类跳过对象description方法,粒度更小一点
MDTraceClassInfo *info = [self infoInClassInfoList:targetClassName];
BOOL doesNotUseDescription = (nil != info && info.flag & MDTraceFlagDoesNotUseDescription);
if (!doesNotUseDescription) {
// 构造初始化函数特殊处理, 系统类初始化比较喜欢"_init"这样的方式
NSString *selectorName = NSStringFromSelector(sel);
BOOL isAllocFunc = [selectorName hasPrefix:@"new"] || [selectorName hasPrefix:@"alloc"];
BOOL maybeInitFunc = [selectorName hasPrefix:@"init"] || [selectorName hasPrefix:@"_init"];
BOOL isDeallocFunc = [selectorName isEqualToString:@"dealloc"];
if (isAllocFunc || maybeInitFunc) {
switch (targetPosition) {
case OMTTargetPositionBeforeSelf:
// 调用构造函数时,此时实例还没初始化完全,不能调用description
doesNotUseDescription = YES;
break;
case OMTTargetPositionBeforeArgument:
break;
case OMTTargetPositionAfterSelf:
case OMTTargetPositionAfterReturnValue:
if (isAllocFunc) {
doesNotUseDescription = YES;
} else if (maybeInitFunc) {
// 调用构造函数时,可能是调用父类的构造函数,此时实例还没初始化完全,不能调用description
if (![targetClassName isEqualToString:NSStringFromClass(cls)]) {
doesNotUseDescription = YES;
}
}
break;
default:
break;
}
} else if (isDeallocFunc) {
// 析构函数所有只打印指针,因为dealloc after时,对象已被释放
doesNotUseDescription = YES;
}
}
return doesNotUseDescription ? [NSString stringWithFormat:@"<%@: %p>", targetClassName, target] : [target description];
}
- (void)log:(OMTLogLevel)level format:(NSString *)format, ...
{
va_list args;
if (format) {
va_start(args, format);
NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
va_end(args);
MDLog(@"%@", message);
}
}
@end
////////////////////////////////////////////////////////////////////////////////
#pragma mark - Entry
static __attribute__((constructor)) void entry()
{
NSDictionary *config = [[MDConfigManager sharedInstance] readConfigByKey:MDCONFIG_TRACE_KEY];
[[MDMethodTrace sharedInstance] parseConfig:config];
}
@@ -0,0 +1,6 @@
// *** DO NOT EDIT THIS FILE! ***
// This file is generated by Logos processing using dkhelperDylib.xm during each build.
// Logos by Dustin Howett
// See http://iphonedevwiki.net/index.php/Logos
@@ -0,0 +1,60 @@
// See http://iphonedevwiki.net/index.php/Logos
#import <UIKit/UIKit.h>
@interface CustomViewController
@property (nonatomic, copy) NSString* newProperty;
+ (void)classMethod;
- (NSString*)getMyName;
- (void)newMethod:(NSString*) output;
@end
%hook CustomViewController
+ (void)classMethod
{
%log;
%orig;
}
%new
-(void)newMethod:(NSString*) output{
NSLog(@"This is a new method : %@", output);
}
%new
- (id)newProperty {
return objc_getAssociatedObject(self, @selector(newProperty));
}
%new
- (void)setNewProperty:(id)value {
objc_setAssociatedObject(self, @selector(newProperty), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString*)getMyName
{
%log;
NSString* password = MSHookIvar<NSString*>(self,"_password");
NSLog(@"password:%@", password);
[%c(CustomViewController) classMethod];
[self newMethod:@"output"];
self.newProperty = @"newProperty";
NSLog(@"newProperty : %@", self.newProperty);
return %orig();
}
%end
+30
View File
@@ -0,0 +1,30 @@
// weibo: http://weibo.com/xiaoqing28
// blog: http://www.alonemonkey.com
//
// LLDBTools.h
// MonkeyDev
//
// Created by AloneMonkey on 2018/3/8.
// Copyright © 2018年 AloneMonkey. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <mach/vm_types.h>
//(lldb) po pviews()
NSString* pvc(void);
NSString* pviews(void);
NSString* pactions(vm_address_t address);
NSString* pblock(vm_address_t address);
NSString* methods(const char * classname);
NSString* ivars(vm_address_t address);
NSString* choose(const char* classname);
NSString* vmmap();
+432
View File
@@ -0,0 +1,432 @@
// weibo: http://weibo.com/xiaoqing28
// blog: http://www.alonemonkey.com
//
// LLDBTools.m
// MonkeyDev
//
// Created by AloneMonkey on 2018/3/8.
// Copyright © 2018年 AloneMonkey. All rights reserved.
//
#pragma GCC diagnostic ignored "-Wundeclared-selector"
#import "LLDBTools.h"
#import <set>
#import <mach/mach_types.h>
#import <malloc/malloc.h>
#import <objc/runtime.h>
#import <mach/mach_init.h>
#import <mach/mach_error.h>
enum {
BLOCK_HAS_COPY_DISPOSE = (1 << 25),
BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code
BLOCK_IS_GLOBAL = (1 << 28),
BLOCK_HAS_STRET = (1 << 29), // IFF BLOCK_HAS_SIGNATURE
BLOCK_HAS_SIGNATURE = (1 << 30),
};
struct Block_literal_1 {
void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor_1 {
unsigned long int reserved; // NULL
unsigned long int size; // sizeof(struct Block_literal_1)
// optional helper functions
void (*copy_helper)(void *dst, void *src); // IFF (1<<25)
void (*dispose_helper)(void *src); // IFF (1<<25)
// required ABI.2010.3.16
const char *signature; // IFF (1<<30)
} *descriptor;
// imported variables
};
NSString* decode(NSString* code);
NSArray* choose_inner(const char * classname);
char * protection_bits_to_rwx (vm_prot_t p);
const char * unparse_inheritance (vm_inherit_t i);
char * behavior_to_text (vm_behavior_t b);
NSString* decode(NSString* code){
NSDictionary * encodeMap = @{
@"c": @"char",
@"i": @"int",
@"s": @"short",
@"l": @"long",
@"q": @"long long",
@"C": @"unsigned char",
@"I": @"unsigned int",
@"S": @"unsigned short",
@"L": @"unsigned long",
@"Q": @"unsigned long long",
@"f": @"float",
@"d": @"double",
@"B": @"bool",
@"v": @"void",
@"*": @"char *",
@"@": @"id",
@"#": @"Class",
@":": @"SEL"
};
if(encodeMap[code]){
return encodeMap[code];
}else if([code characterAtIndex:0] == '@'){
if([code characterAtIndex:1] == '?'){
return code;
}else if([code characterAtIndex:2] == '<'){
return [NSString stringWithFormat:@"id%@", [[code substringWithRange:NSMakeRange(2, code.length-3)] stringByReplacingOccurrencesOfString:@"><" withString:@", "]];
}else{
return [NSString stringWithFormat:@"%@ *", [code substringWithRange:NSMakeRange(2, code.length-3)]];
}
}else if([code characterAtIndex:0] == '^'){
return [NSString stringWithFormat:@"%@ *", decode([code substringFromIndex:1])];
}
return code;
}
NSString* pvc(){
return [[[UIWindow performSelector:@selector(keyWindow)] performSelector:@selector(rootViewController)] performSelector:@selector(_printHierarchy)];
}
NSString* pviews(){
return [[[UIApplication sharedApplication] keyWindow] performSelector:@selector(recursiveDescription)];
}
NSString* pactions(vm_address_t address){
NSMutableString* result = [NSMutableString new];
UIControl* control = (__bridge UIControl*)(void*)address;
NSArray* targets = [[control allTargets] allObjects];
for (id item in targets) {
NSArray* actions = [control actionsForTarget:item forControlEvent:0];
[result appendFormat:@"<%s: 0x%lx>: %@\n", object_getClassName(item), (unsigned long)item, [actions componentsJoinedByString:@","]];
}
return result;
}
NSString* pblock(vm_address_t address){
struct Block_literal_1 real = *((struct Block_literal_1 *)(void*)address);
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:[NSNumber numberWithLong:(long)real.invoke] forKey:@"invoke"];
if (real.flags & BLOCK_HAS_SIGNATURE) {
char *signature;
if (real.flags & BLOCK_HAS_COPY_DISPOSE) {
signature = (char *)(real.descriptor)->signature;
} else {
signature = (char *)(real.descriptor)->copy_helper;
}
NSMethodSignature *sig = [NSMethodSignature signatureWithObjCTypes:signature];
NSMutableArray *types = [NSMutableArray array];
[types addObject:[NSString stringWithUTF8String:(char *)[sig methodReturnType]]];
for (NSUInteger i = 0; i < sig.numberOfArguments; i++) {
char *type = (char *)[sig getArgumentTypeAtIndex:i];
[types addObject:[NSString stringWithUTF8String:type]];
}
[dict setObject:types forKey:@"signature"];
}
NSMutableArray* sigArr = dict[@"signature"];
if(!sigArr){
return [NSString stringWithFormat:@"Imp: 0x%lx", [dict[@"invoke"] longValue]];
}else{
NSMutableString* sig = [NSMutableString stringWithFormat:@"%@ ^(", decode(sigArr[0])];
for (int i = 2; i < sigArr.count; i++) {
if(i == sigArr.count - 1){
[sig appendFormat:@"%@", decode(sigArr[i])];
}else{
[sig appendFormat:@"%@ ,", decode(sigArr[i])];
}
}
[sig appendString:@");"];
return [NSString stringWithFormat:@"Imp: 0x%lx Signature: %s", [dict[@"invoke"] longValue], [sig UTF8String]];
}
}
struct CYChoice {
std::set<Class> query_;
std::set<id> results_;
};
struct CYObjectStruct {
Class isa_;
};
static void choose_(task_t task, void *baton, unsigned type, vm_range_t *ranges, unsigned count) {
CYChoice *choice(reinterpret_cast<CYChoice *>(baton));
for (unsigned i(0); i != count; ++i) {
vm_range_t &range(ranges[i]);
void *data(reinterpret_cast<void *>(range.address));
size_t size(range.size);
if (size < sizeof(CYObjectStruct))
continue;
uintptr_t *pointers(reinterpret_cast<uintptr_t *>(data));
#ifdef __arm64__
Class isa = (__bridge Class)((void *)(pointers[0] & 0x1fffffff8));
#else
Class isa =(__bridge Class)(void *)pointers[0];
#endif
std::set<Class>::const_iterator result(choice->query_.find(isa));
if (result == choice->query_.end())
continue;
size_t needed(class_getInstanceSize(*result));
// XXX: if (size < needed)
size_t boundary(496);
#ifdef __LP64__
boundary *= 2;
#endif
if ((needed <= boundary && (needed + 15) / 16 * 16 != size) || (needed > boundary && (needed + 511) / 512 * 512 != size))
continue;
choice->results_.insert((__bridge id)(data));
}
}
static Class *CYCopyClassList(size_t &size) {
size = objc_getClassList(NULL, 0);
Class *data(reinterpret_cast<Class *>(malloc(sizeof(Class) * size)));
for (;;) {
size_t writ(objc_getClassList(data, (int)size));
if (writ <= size) {
size = writ;
return data;
}
Class *copy(reinterpret_cast<Class *>(realloc(data, sizeof(Class) * writ)));
if (copy == NULL) {
free(data);
return NULL;
}
data = copy;
size = writ;
}
}
static kern_return_t CYReadMemory(task_t task, vm_address_t address, vm_size_t size, void **data) {
*data = reinterpret_cast<void *>(address);
return KERN_SUCCESS;
}
NSArray* choose_inner(const char * classname){
Class _class = NSClassFromString([NSString stringWithUTF8String:classname]);
vm_address_t *zones = NULL;
unsigned size = 0;
//获取所有的zone信息 堆上的区域
kern_return_t error = malloc_get_all_zones(mach_task_self(), &CYReadMemory, &zones, &size);
assert(error == KERN_SUCCESS);
size_t number;
Class *classes(CYCopyClassList(number));
assert(classes != NULL);
CYChoice choice;
//找到目标Class
for (size_t i(0); i != number; ++i)
for (Class current(classes[i]); current != Nil; current = class_getSuperclass(current))
if (current == _class) {
choice.query_.insert(classes[i]);
break;
}
for (unsigned i(0); i != size; ++i) {
const malloc_zone_t *zone(reinterpret_cast<const malloc_zone_t *>(zones[i]));
if (zone == NULL || zone->introspect == NULL)
continue;
//枚举堆上的对象
zone->introspect->enumerator(mach_task_self(), &choice, MALLOC_PTR_IN_USE_RANGE_TYPE, zones[i], &CYReadMemory, &choose_);
}
NSMutableArray * result = [[NSMutableArray alloc] init];
for (auto iter = choice.results_.begin(); iter != choice.results_.end(); iter++) {
[result addObject:(id)*iter];
}
return result;
}
NSString* choose(const char* classname){
NSMutableString* result = [NSMutableString new];
NSArray* results = choose_inner(classname);
[result appendFormat:@"Find %lu instance objects in memory!\n" , (unsigned long)results.count];
for (id item in results) {
[result appendFormat:@"<%s: 0x%llx>\n", object_getClassName(item), (long long)item];
}
return result;
}
NSString* methods(const char * classname){
return [objc_getClass(classname) performSelector:@selector(_shortMethodDescription)];
}
NSString* ivars(vm_address_t address){
id target = (__bridge id)(void*)address;
return [target performSelector:@selector(_ivarDescription)];
}
char * protection_bits_to_rwx (vm_prot_t p){
static char returned[4];
returned[0] = (p & VM_PROT_READ ? 'r' : '-');
returned[1] = (p & VM_PROT_WRITE ? 'w' : '-');
returned[2] = (p & VM_PROT_EXECUTE ? 'x' : '-');
returned[3] = '\0';
// memory leak here. No biggy
return (strdup(returned));
}
const char * unparse_inheritance (vm_inherit_t i){
switch (i){
case VM_INHERIT_SHARE:
return "share";
case VM_INHERIT_COPY:
return "copy";
case VM_INHERIT_NONE:
return "none";
default:
return "???";
}
}
char * behavior_to_text (vm_behavior_t b){
switch (b){
case VM_BEHAVIOR_DEFAULT: return((char*)"default");
case VM_BEHAVIOR_RANDOM: return((char*)"random");
case VM_BEHAVIOR_SEQUENTIAL: return((char*)"fwd-seq");
case VM_BEHAVIOR_RSEQNTL: return((char*)"rev-seq");
case VM_BEHAVIOR_WILLNEED: return((char*)"will-need");
case VM_BEHAVIOR_DONTNEED: return((char*)"will-need");
case VM_BEHAVIOR_FREE: return((char*)"free-nowb");
case VM_BEHAVIOR_ZERO_WIRED_PAGES: return((char*)"zero-wire");
case VM_BEHAVIOR_REUSABLE: return((char*)"reusable");
case VM_BEHAVIOR_REUSE: return((char*)"reuse");
case VM_BEHAVIOR_CAN_REUSE: return((char*)"canreuse");
default: return ((char*)"?");
}
}
__BEGIN_DECLS
extern kern_return_t mach_vm_region
(
vm_map_t target_task,
mach_vm_address_t *address,
mach_vm_size_t *size,
vm_region_flavor_t flavor,
vm_region_info_t info,
mach_msg_type_number_t *infoCnt,
mach_port_t *object_name
);
__END_DECLS
NSString* vmmap(){
vm_region_basic_info_data_t info, prev_info;
mach_vm_address_t address = 1, prev_address;
mach_vm_size_t size, prev_size;
mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
mach_port_t object_name;
int nsubregions = 0;
kern_return_t kr = mach_vm_region(mach_task_self(), &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)&info, &count, &object_name);
NSMutableString* result = [[NSMutableString alloc] init];
if(kr != KERN_SUCCESS){
[result appendFormat:@"mach_vm_region: Error %d - %s", kr, mach_error_string(kr)];
return [result copy];
}
//保存之前查到的info
memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_t));
prev_address = address;
prev_size = size;
nsubregions = 1;
while (true) {
int print = 0, done = 0;
address = prev_address + prev_size;
if (address == 0){
print = done = 1;
}
if (!done){
kr = mach_vm_region (mach_task_self(), &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)&info, &count, &object_name);
if (kr != KERN_SUCCESS){
[result appendFormat:@"mach_vm_region failed for address %llu - Error: %x\n",address, (kr)];
print = done = 1;
}
}
//等于才是连续的内存,不等于才打印
if (address != prev_address + prev_size)
print = 1;
//或者权限信息改变了也打印
if ((info.protection != prev_info.protection)
|| (info.max_protection != prev_info.max_protection)
|| (info.inheritance != prev_info.inheritance)
|| (info.shared != prev_info.reserved)
|| (info.reserved != prev_info.reserved))
print = 1;
if (print){
char *print_size_unit = NULL;
mach_vm_size_t print_size = prev_size;
if (print_size > 1024) { print_size /= 1024; print_size_unit = (char*)"K"; }
if (print_size > 1024) { print_size /= 1024; print_size_unit = (char*)"M"; }
if (print_size > 1024) { print_size /= 1024; print_size_unit = (char*)"G"; }
[result appendFormat:@" %p-%p [%llu%s](%s/%s; %s, %s, %s) %s",
(void*)(prev_address),
(void*)(prev_address + prev_size),
print_size,
print_size_unit,
protection_bits_to_rwx (prev_info.protection),
protection_bits_to_rwx (prev_info.max_protection),
unparse_inheritance (prev_info.inheritance),
prev_info.shared ? "shared" : "private",
prev_info.reserved ? "reserved" : "not-reserved",
behavior_to_text (prev_info.behavior)];
if (nsubregions > 1)
[result appendFormat:@" (%d sub-regions)", nsubregions];
[result appendFormat:@"\n"];
prev_address = address;
prev_size = size;
memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_t));
nsubregions = 1;
}else{
prev_size += size;
nsubregions++;
}
if (done)
break;
}
return [result copy];
}
@@ -0,0 +1,89 @@
/*
* OCMethodTrace.h
* OCMethodTrace
*
* https://github.com/omxcodec/OCMethodTrace.git
*
* Copyright (C) 2018 Michael Chen <omxcodec@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <Foundation/Foundation.h>
// 方法跟踪条件block
// @param sel 方法名
typedef BOOL (^OMTConditionBlock)(SEL sel);
// 方法调用前会调用该block
// @param target 跟踪目标对象
// @param cls 调用方法所在的类(可以是target所在的类,也可以是target的父类)
// @param sel 方法名
// @param args 参数列表
// @param deep 调用层次
typedef void (^OMTBeforeBlock)(id target, Class cls, SEL sel, NSArray *args, int deep);
// 方法调用后会调用该block
// @param target 跟踪目标对象
// @param cls 调用方法所在的类(可以是target所在的类,也可以是target的父类)
// @param sel 方法名
// @param ret 返回值
// @param deep 调用层次
// @param interval 执行方法的ms耗时
typedef void (^OMTAfterBlock)(id target, Class cls, SEL sel, id ret, int deep, NSTimeInterval interval);
// target位置
typedef NS_ENUM(NSUInteger, OMTTargetPosition) {
OMTTargetPositionBeforeSelf = 0, // before-调用者self
OMTTargetPositionBeforeArgument, // before-参数
OMTTargetPositionAfterSelf, // after-调用者self
OMTTargetPositionAfterReturnValue, // after-返回值
OMTTargetPositionMax,
};
// 日志级别
typedef NS_ENUM(NSUInteger, OMTLogLevel) {
OMTLogLevelError = 0,
OMTLogLevelDebug,
OMTLogLevelMax,
};
@protocol OCMethodTraceDelegate <NSObject>
@optional
// 获取target的description回调
- (NSString *)descriptionWithTarget:(id)target class:(Class)cls selector:(SEL)sel targetPosition:(OMTTargetPosition)targetPosition;
// 日志回调
- (void)log:(OMTLogLevel)level format:(NSString *)format, ... NS_FORMAT_FUNCTION(2,3);
@end
@interface OCMethodTrace : NSObject
@property (nonatomic, assign) BOOL disableTrace; // 屏蔽before和after调用,hook完成后默认打开
@property (nonatomic, weak) id<OCMethodTraceDelegate> delegate; // 回调
@property (nonatomic, assign) OMTLogLevel logLevel; // 日志级别,默认OMTLogLevelDebug
+ (OCMethodTrace *)sharedInstance;
// 跟踪打印目标(实例或类)方法调用
// @param cls 跟踪打印目标类
// @param condition 判断是否跟踪方法的block
// @param before 被跟踪的方法调用前会调用该block
// @param after 被跟踪的方法调用后会调用该block
- (void)traceMethodWithClass:(Class)cls
condition:(OMTConditionBlock)condition
before:(OMTBeforeBlock)before
after:(OMTAfterBlock)after;
@end
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,26 @@
/*
* OCSelectorTrampolines.mm
* OCMethodTrace
*
* https://github.com/omxcodec/OCMethodTrace.git
*
* Copyright (C) 2018 Michael Chen <omxcodec@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <Foundation/Foundation.h>
FOUNDATION_EXTERN IMP imp_implementationWithSelector(SEL aSel, const char *signature);
FOUNDATION_EXTERN SEL imp_getSelector(IMP anImp);
FOUNDATION_EXTERN BOOL imp_removeSelector(IMP anImp);
@@ -0,0 +1,449 @@
/*
* OCSelectorTrampolines.mm
* OCMethodTrace
*
* https://github.com/omxcodec/OCMethodTrace.git
*
* Copyright (C) 2018 Michael Chen <omxcodec@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "OCSelectorTrampolines.h"
#import <objc/runtime.h>
#import <objc/message.h>
#import <mach/mach.h>
#import <pthread.h>
// Define SUPPORT_STRET on architectures that need separate struct-return ABI.
#if defined(__arm64__)
# define SUPPORT_STRET 0
#else
# define SUPPORT_STRET 1
#endif
#define _ost_fatal(fmt, ...) [NSException raise:@"OCSelectorTrampolines" format:fmt, ##__VA_ARGS__]
// symbols defined in assembly files
// Don't use the symbols directly; they're thumb-biased on some ARM archs.
#define TRAMP(tramp) \
static inline __unused uintptr_t tramp(void) { \
extern void *_##tramp; \
return ((uintptr_t)&_##tramp) & ~1UL; \
}
// Scalar return
TRAMP(a1a2_selectorTrampHead); // trampoline header code
TRAMP(a1a2_firstSelectorTramp); // first trampoline
TRAMP(a1a2_selectorTrampEnd); // after the last trampoline
#if SUPPORT_STRET
// Struct return
TRAMP(a2a3_selectorTrampHead);
TRAMP(a2a3_firstSelectorTramp);
TRAMP(a2a3_selectorTrampEnd);
#endif
// argument mode identifier
typedef enum {
ReturnValueInRegisterArgumentMode,
#if SUPPORT_STRET
ReturnValueOnStackArgumentMode,
#endif
ArgumentModeCount
} ArgumentMode;
// We must take care with our data layout on architectures that support
// multiple page sizes.
//
// The trampoline template in __TEXT is sized and aligned with PAGE_MAX_SIZE.
// On some platforms this requires additional linker flags.
//
// When we allocate a page pair, we use PAGE_MAX_SIZE size.
// This allows trampoline code to find its data by subtracting PAGE_MAX_SIZE.
//
// When we allocate a page pair, we use the process's page alignment.
// This simplifies allocation because we don't need to force greater than
// default alignment when running with small pages, but it also means
// the trampoline code MUST NOT look for its data by masking with PAGE_MAX_MASK.
struct TrampolineSelectorPagePair
{
IMP msgSend; // msg send hander
TrampolineSelectorPagePair *nextPagePair; // linked list of all pages
TrampolineSelectorPagePair *nextAvailablePage; // linked list of pages with available slots
uintptr_t nextAvailable; // index of next available slot, endIndex() if no more available
// Payload data: selector and free list.
// Bytes parallel with trampoline header code are the fields above or unused
// uint8_t selectors[ PAGE_MAX_SIZE - sizeof(TrampolineSelectorPagePair) ]
// Code: trampoline header followed by trampolines.
// uint8_t trampolines[PAGE_MAX_SIZE];
// Per-trampoline selector data format:
// initial value is 0 while page data is filled sequentially
// when filled, value is reference to selector
// when empty, value is index of next available slot OR 0 if never used yet
union Payload {
SEL selector;
uintptr_t nextAvailable; // free list
};
static uintptr_t headerSize() {
return (uintptr_t) (a1a2_firstSelectorTramp() - a1a2_selectorTrampHead());
}
static uintptr_t slotSize() {
return 8;
}
static uintptr_t startIndex() {
// headerSize is assumed to be slot-aligned
return headerSize() / slotSize();
}
static uintptr_t endIndex() {
return (uintptr_t)PAGE_MAX_SIZE / slotSize();
}
static bool validIndex(uintptr_t index) {
return (index >= startIndex() && index < endIndex());
}
Payload *payload(uintptr_t index) {
assert(validIndex(index));
return (Payload *)((char *)this + index*slotSize());
}
IMP trampoline(uintptr_t index) {
assert(validIndex(index));
char *imp = (char *)this + index*slotSize() + PAGE_MAX_SIZE;
#if __arm__
imp++; // trampoline is Thumb instructions
#endif
return (IMP)imp;
}
uintptr_t indexForTrampoline(IMP tramp) {
uintptr_t tramp0 = (uintptr_t)this + PAGE_MAX_SIZE;
uintptr_t start = tramp0 + headerSize();
uintptr_t end = tramp0 + PAGE_MAX_SIZE;
uintptr_t address = (uintptr_t)tramp;
if (address >= start && address < end) {
return (uintptr_t)(address - tramp0) / slotSize();
}
return 0;
}
static void check() {
assert(TrampolineSelectorPagePair::slotSize() == 8);
assert(TrampolineSelectorPagePair::headerSize() >= sizeof(TrampolineSelectorPagePair));
assert(TrampolineSelectorPagePair::headerSize() % TrampolineSelectorPagePair::slotSize() == 0);
// _objc_inform("%p %p %p", a1a2_selectorTrampHead(), a1a2_firstSelectorTramp(),
// a1a2_selectorTrampEnd());
assert(a1a2_selectorTrampHead() % PAGE_SIZE == 0); // not PAGE_MAX_SIZE
assert(a1a2_selectorTrampHead() + PAGE_MAX_SIZE == a1a2_selectorTrampEnd());
#if SUPPORT_STRET
// _objc_inform("%p %p %p", a2a3_selectorTrampHead(), a2a3_firstSelectorTramp(),
// a2a3_selectorTrampEnd());
assert(a2a3_selectorTrampHead() % PAGE_SIZE == 0); // not PAGE_MAX_SIZE
assert(a2a3_selectorTrampHead() + PAGE_MAX_SIZE == a2a3_selectorTrampEnd());
#endif
#if __arm__
// make sure trampolines are Thumb
extern void *_a1a2_firstSelectorTramp;
extern void *_a2a3_firstSelectorTramp;
assert(((uintptr_t)&_a1a2_firstSelectorTramp) % 2 == 1);
assert(((uintptr_t)&_a2a3_firstSelectorTramp) % 2 == 1);
#endif
}
};
// two sets of trampoline pages; one for stack returns and one for register returns
static TrampolineSelectorPagePair *headPagePairs[ArgumentModeCount];
#pragma mark Utility Functions
static pthread_rwlock_t trampolinesLock = PTHREAD_RWLOCK_INITIALIZER;
static inline void _lock() {
int err = pthread_rwlock_wrlock(&trampolinesLock);
if (err) _ost_fatal(@"pthread_rwlock_wrlock failed (%d)", err);
}
static inline void _unlock() {
int err = pthread_rwlock_unlock(&trampolinesLock);
if (err) _ost_fatal(@"pthread_rwlock_unlock failed (%d)", err);
}
static inline void _assert_locked() {
}
#pragma mark Trampoline Management Functions
static TrampolineSelectorPagePair *_allocateTrampolinesAndData(ArgumentMode aMode)
{
_assert_locked();
vm_address_t dataAddress;
TrampolineSelectorPagePair::check();
TrampolineSelectorPagePair *headPagePair = headPagePairs[aMode];
assert(headPagePair == nil || headPagePair->nextAvailablePage == nil);
kern_return_t result;
result = vm_allocate(mach_task_self(), &dataAddress, PAGE_MAX_SIZE * 2,
VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_FOUNDATION));
if (result != KERN_SUCCESS) {
_ost_fatal(@"vm_allocate trampolines failed (%d)", result);
}
vm_address_t codeAddress = dataAddress + PAGE_MAX_SIZE;
uintptr_t codePage = NULL;
IMP sendImp = NULL;
switch(aMode) {
case ReturnValueInRegisterArgumentMode:
codePage = a1a2_selectorTrampHead();
sendImp = objc_msgSend;
break;
#if SUPPORT_STRET
case ReturnValueOnStackArgumentMode:
codePage = a2a3_selectorTrampHead();
sendImp = objc_msgSend_stret;
break;
#endif
default:
_ost_fatal(@"unknown return mode %d", (int)aMode);
break;
}
vm_prot_t currentProtection, maxProtection;
result = vm_remap(mach_task_self(), &codeAddress, PAGE_MAX_SIZE,
0, VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
mach_task_self(), codePage, TRUE,
&currentProtection, &maxProtection, VM_INHERIT_SHARE);
if (result != KERN_SUCCESS) {
// vm_deallocate(mach_task_self(), dataAddress, PAGE_MAX_SIZE * 2);
_ost_fatal(@"vm_remap trampolines failed (%d)", result);
}
TrampolineSelectorPagePair *pagePair = (TrampolineSelectorPagePair *) dataAddress;
pagePair->nextAvailable = pagePair->startIndex();
pagePair->nextPagePair = nil;
pagePair->nextAvailablePage = nil;
pagePair->msgSend = sendImp;
if (headPagePair) {
TrampolineSelectorPagePair *lastPagePair = headPagePair;
while(lastPagePair->nextPagePair) {
lastPagePair = lastPagePair->nextPagePair;
}
lastPagePair->nextPagePair = pagePair;
headPagePairs[aMode]->nextAvailablePage = pagePair;
} else {
headPagePairs[aMode] = pagePair;
}
return pagePair;
}
static TrampolineSelectorPagePair *
_getOrAllocatePagePairWithNextAvailable(ArgumentMode aMode)
{
_assert_locked();
TrampolineSelectorPagePair *headPagePair = headPagePairs[aMode];
if (!headPagePair)
return _allocateTrampolinesAndData(aMode);
// make sure head page is filled first
if (headPagePair->nextAvailable != headPagePair->endIndex())
return headPagePair;
if (headPagePair->nextAvailablePage) // check if there is a page w/a hole
return headPagePair->nextAvailablePage;
return _allocateTrampolinesAndData(aMode); // tack on a new one
}
static TrampolineSelectorPagePair *
_pageAndIndexContainingIMP(IMP anImp, uintptr_t *outIndex,
TrampolineSelectorPagePair **outHeadPagePair)
{
_assert_locked();
for (int arg = 0; arg < ArgumentModeCount; arg++) {
for (TrampolineSelectorPagePair *pagePair = headPagePairs[arg];
pagePair;
pagePair = pagePair->nextPagePair)
{
uintptr_t index = pagePair->indexForTrampoline(anImp);
if (index) {
if (outIndex) *outIndex = index;
if (outHeadPagePair) *outHeadPagePair = headPagePairs[arg];
return pagePair;
}
}
}
return nil;
}
static ArgumentMode
_argumentModeForSignature(const char *signature)
{
ArgumentMode aMode = ReturnValueInRegisterArgumentMode;
#if SUPPORT_STRET
if (signature && signature[0] == '{') {
@try {
// In some cases that returns struct, we should use the '_stret' API:
// http://sealiesoftware.com/blog/archive/2008/10/30/objc_explain_objc_msgSend_stret.html
// NSMethodSignature knows the detail but has no API to return, we can only get the info from debugDescription.
NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:signature];
if ([methodSignature.debugDescription rangeOfString:@"is special struct return? YES"].location != NSNotFound) {
aMode = ReturnValueOnStackArgumentMode;
}
} @catch (__unused NSException *e) {}
}
#endif
return aMode;
}
#pragma mark Public API
IMP imp_implementationWithSelector(SEL aSel, const char *signature)
{
IMP returnIMP;
_lock();
ArgumentMode aMode = _argumentModeForSignature(signature);
TrampolineSelectorPagePair *pagePair =
_getOrAllocatePagePairWithNextAvailable(aMode);
if (!headPagePairs[aMode])
headPagePairs[aMode] = pagePair;
uintptr_t index = pagePair->nextAvailable;
assert(index >= pagePair->startIndex() && index < pagePair->endIndex());
TrampolineSelectorPagePair::Payload *payload = pagePair->payload(index);
uintptr_t nextAvailableIndex = payload->nextAvailable;
if (nextAvailableIndex == 0) {
// First time through (unused slots are zero). Fill sequentially.
// If the page is now full this will now be endIndex(), handled below.
nextAvailableIndex = index + 1;
}
pagePair->nextAvailable = nextAvailableIndex;
if (nextAvailableIndex == pagePair->endIndex()) {
// PagePair is now full (free list or wilderness exhausted)
// Remove from available page linked list
TrampolineSelectorPagePair *iterator = headPagePairs[aMode];
while(iterator && (iterator->nextAvailablePage != pagePair)) {
iterator = iterator->nextAvailablePage;
}
if (iterator) {
iterator->nextAvailablePage = pagePair->nextAvailablePage;
pagePair->nextAvailablePage = nil;
}
}
payload->selector = aSel;
returnIMP = pagePair->trampoline(index);
_unlock();
return returnIMP;
}
SEL imp_getSelector(IMP anImp) {
uintptr_t index;
TrampolineSelectorPagePair *pagePair;
if (!anImp) return nil;
_lock();
pagePair = _pageAndIndexContainingIMP(anImp, &index, nil);
if (!pagePair) {
_unlock();
return nil;
}
TrampolineSelectorPagePair::Payload *payload = pagePair->payload(index);
if (payload->nextAvailable <= TrampolineSelectorPagePair::endIndex()) {
// unallocated
_unlock();
return nil;
}
_unlock();
return payload->selector;
}
BOOL imp_removeSelector(IMP anImp) {
TrampolineSelectorPagePair *pagePair;
TrampolineSelectorPagePair *headPagePair;
uintptr_t index;
if (!anImp) return NO;
_lock();
pagePair = _pageAndIndexContainingIMP(anImp, &index, &headPagePair);
if (!pagePair) {
_unlock();
return NO;
}
TrampolineSelectorPagePair::Payload *payload = pagePair->payload(index);
payload->nextAvailable = pagePair->nextAvailable;
pagePair->nextAvailable = index;
// make sure this page is on available linked list
TrampolineSelectorPagePair *pagePairIterator = headPagePair;
// see if page is the next available page for any existing pages
while (pagePairIterator->nextAvailablePage &&
pagePairIterator->nextAvailablePage != pagePair)
{
pagePairIterator = pagePairIterator->nextAvailablePage;
}
if (! pagePairIterator->nextAvailablePage) {
// if iteration stopped because nextAvail was nil
// add to end of list.
pagePairIterator->nextAvailablePage = pagePair;
pagePair->nextAvailablePage = nil;
}
_unlock();
return YES;
}
@@ -0,0 +1,166 @@
/*
* a1a2-selectortramps-arm.s
* OCMethodTrace
*
* https://github.com/omxcodec/OCMethodTrace.git
*
* Copyright (C) 2018 Michael Chen <omxcodec@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if __arm__
#include <arm/arch.h>
#include <mach/vm_param.h>
.syntax unified
.text
.private_extern __a1a2_selectorTrampHead
.private_extern __a1a2_firstSelectorTramp
.private_extern __a1a2_selectorTrampEnd
// Trampoline machinery assumes the trampolines are Thumb function pointers
#if !__thumb2__
# error sorry
#endif
.thumb
.thumb_func __a1a2_selectorTrampHead
.thumb_func __a1a2_firstSelectorTramp
.thumb_func __a1a2_selectorTrampEnd
.align PAGE_MAX_SHIFT
__a1a2_selectorTrampHead:
// Trampoline's data is one page before the trampoline text.
// Also correct PC bias of 4 bytes.
// 1. selector
sub r12, #PAGE_MAX_SIZE
ldr r1, [r12, #-4] // selector -> _cmd
// 2. msgSend
mov r12, pc
sub r12, #PAGE_MAX_SIZE
ldr pc, [r12, #-12] // tail call msgSend
// not reached
nop
// Align trampolines to 8 bytes
.align 3
.macro TrampolineEntry
mov r12, pc
b __a1a2_selectorTrampHead
.align 3
.endmacro
.macro TrampolineEntryX16
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
.endmacro
.macro TrampolineEntryX256
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
.endmacro
.private_extern __a1a2_firstSelectorTramp
__a1a2_firstSelectorTramp:
// 2048-3 trampolines to fill 16K page
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
// TrampolineEntry
// TrampolineEntry
// TrampolineEntry
.private_extern __a1a2_selectorTrampEnd
__a1a2_selectorTrampEnd:
#endif
@@ -0,0 +1,156 @@
/*
* a1a2-selectortramps-arm64.s
* OCMethodTrace
*
* https://github.com/omxcodec/OCMethodTrace.git
*
* Copyright (C) 2018 Michael Chen <omxcodec@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if __arm64__
#include <mach/vm_param.h>
.text
.private_extern __a1a2_selectorTrampHead
.private_extern __a1a2_firstSelectorTramp
.private_extern __a1a2_selectorTrampEnd
msgSend:
.quad 0
.align PAGE_MAX_SHIFT
__a1a2_selectorTrampHead:
L_a1a2_selectorTrampHead:
// 1. selector
ldr x1, [x17] // selector -> _cmd
// 2. msgSend
adr x17, L_a1a2_selectorTrampHead
sub x17, x17, #PAGE_MAX_SIZE
ldr x16, [x17]
br x16 // tail call msgSend
// pad up to TrampolineSelectorPagePair header size
nop
nop
nop
.macro TrampolineEntry
// load address of trampoline data (one page before this instruction)
adr x17, -PAGE_MAX_SIZE
b L_a1a2_selectorTrampHead
.endmacro
.macro TrampolineEntryX16
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
.endmacro
.macro TrampolineEntryX256
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
.endmacro
.align 3
.private_extern __a1a2_firstSelectorTramp
__a1a2_firstSelectorTramp:
// 2048-4 trampolines to fill 16K page
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
// TrampolineEntry
// TrampolineEntry
// TrampolineEntry
// TrampolineEntry
.private_extern __a1a2_selectorTrampEnd
__a1a2_selectorTrampEnd:
#endif
@@ -0,0 +1,569 @@
/*
* a1a2-selectortramps-i386.s
* OCMethodTrace
*
* https://github.com/omxcodec/OCMethodTrace.git
*
* Copyright (C) 2018 Michael Chen <omxcodec@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef __i386__
#include <mach/mach.h>
#include "selectortramps.mac"
.text
.private_extern __a1a2_selectorTrampHead
.private_extern __a1a2_firstSelectorTramp
.private_extern __a1a2_nextSelectorTramp
.private_extern __a1a2_selectorTrampEnd
.align PAGE_SHIFT
__a1a2_selectorTrampHead:
// 1. selector
popl %eax
andl $0xFFFFFFF8, %eax
subl $ PAGE_SIZE, %eax
movl (%eax), %ecx // selectorPtr -> ecx
movl %ecx, 8(%esp) // ecx -> _cmd
// 2. msgSend
INIT_PIC(__a1a2_selectorTrampHead)
PRELOAD(__a1a2_selectorTrampHead, __a1a2_selectorTrampHead)
subl $ PAGE_SIZE, LABEL_ADDR(__a1a2_selectorTrampHead, __a1a2_selectorTrampHead)
END_PIC()
jmp *0(%eax) // tail call msgSend
.macro TrampolineEntry
call __a1a2_selectorTrampHead
nop
nop
nop
.endmacro
.align 5
__a1a2_firstSelectorTramp:
TrampolineEntry
__a1a2_nextSelectorTramp: // used to calculate size of each trampoline
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
// TrampolineEntry
// TrampolineEntry
// TrampolineEntry
// TrampolineEntry
__a1a2_selectorTrampEnd:
#endif
@@ -0,0 +1,568 @@
/*
* a1a2-selectortramps-x86_64.s
* OCMethodTrace
*
* https://github.com/omxcodec/OCMethodTrace.git
*
* Copyright (C) 2018 Michael Chen <omxcodec@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef __x86_64__
#include <mach/mach.h>
#include "selectortramps.mac"
.text
.private_extern __a1a2_selectorTrampHead
.private_extern __a1a2_firstSelectorTramp
.private_extern __a1a2_nextSelectorTramp
.private_extern __a1a2_selectorTrampEnd
.align PAGE_SHIFT
__a1a2_selectorTrampHead:
// 1. selector
popq %r10
andq $0xFFFFFFFFFFFFFFF8, %r10
subq $ PAGE_SIZE, %r10
movq (%r10), %rsi // selector -> _cmd
// 2. msgSend
INIT_PIC(__a1a2_selectorTrampHead)
PRELOAD(__a1a2_selectorTrampHead, __a1a2_selectorTrampHead)
subq $ PAGE_SIZE, LABEL_ADDR(__a1a2_selectorTrampHead, __a1a2_selectorTrampHead)
END_PIC()
jmp *0(%r10) // tail call msgSend
.macro TrampolineEntry
callq __a1a2_selectorTrampHead
nop
nop
nop
.endmacro
.align 5
__a1a2_firstSelectorTramp:
TrampolineEntry
__a1a2_nextSelectorTramp:
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
// TrampolineEntry
// TrampolineEntry
// TrampolineEntry
// TrampolineEntry
__a1a2_selectorTrampEnd:
#endif
@@ -0,0 +1,166 @@
/*
* a2a3-selectortramps-arm.s
* OCMethodTrace
*
* https://github.com/omxcodec/OCMethodTrace.git
*
* Copyright (C) 2018 Michael Chen <omxcodec@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if __arm__
#include <arm/arch.h>
#include <mach/vm_param.h>
.syntax unified
.text
.private_extern __a2a3_selectorTrampHead
.private_extern __a2a3_firstSelectorTramp
.private_extern __a2a3_selectorTrampEnd
// Trampoline machinery assumes the trampolines are Thumb function pointers
#if !__thumb2__
# error sorry
#endif
.thumb
.thumb_func __a2a3_selectorTrampHead
.thumb_func __a2a3_firstSelectorTramp
.thumb_func __a2a3_selectorTrampEnd
.align PAGE_MAX_SHIFT
__a2a3_selectorTrampHead:
// Trampoline's data is one page before the trampoline text.
// Also correct PC bias of 4 bytes.
// 1. selector
sub r12, #PAGE_MAX_SIZE
ldr r2, [r12, #-4] // _cmd = selector
// 2. msgSend. Can't "ldr r12, msgSend", error: out of range pc-relative fixup value
mov r12, pc
sub r12, #PAGE_MAX_SIZE
ldr pc, [r12, #-12]
// not reached
nop
// Align trampolines to 8 bytes
.align 3
.macro TrampolineEntry
mov r12, pc
b __a2a3_selectorTrampHead
.align 3
.endmacro
.macro TrampolineEntryX16
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
.endmacro
.macro TrampolineEntryX256
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
.endmacro
.private_extern __a2a3_firstSelectorTramp
__a2a3_firstSelectorTramp:
// 2048-2 trampolines to fill 16K page
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
// TrampolineEntry
// TrampolineEntry
// TrampolineEntry
.private_extern __a2a3_selectorTrampEnd
__a2a3_selectorTrampEnd:
#endif
@@ -0,0 +1,569 @@
/*
* a2a3-selectortramps-i386.s
* OCMethodTrace
*
* https://github.com/omxcodec/OCMethodTrace.git
*
* Copyright (C) 2018 Michael Chen <omxcodec@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef __i386__
#include <mach/mach.h>
#include "selectortramps.mac"
.text
.private_extern __a2a3_selectorTrampHead
.private_extern __a2a3_firstSelectorTramp
.private_extern __a2a3_nextSelectorTramp
.private_extern __a2a3_selectorTrampEnd
.align PAGE_SHIFT
__a2a3_selectorTrampHead:
// 1. selector
popl %eax
andl $0xFFFFFFF8, %eax
subl $ PAGE_SIZE, %eax
movl (%eax), %ecx // selectorPtr -> ecx
movl %ecx, 12(%esp) // ecx -> _cmd
// 2. msgSend
INIT_PIC(__a2a3_selectorTrampHead)
PRELOAD(__a2a3_selectorTrampHead, __a2a3_selectorTrampHead)
subl $ PAGE_SIZE, LABEL_ADDR(__a2a3_selectorTrampHead, __a2a3_selectorTrampHead)
END_PIC()
jmp *0(%eax) // tail call msgSend
.macro TrampolineEntry
call __a2a3_selectorTrampHead
nop
nop
nop
.endmacro
.align 5
__a2a3_firstSelectorTramp:
TrampolineEntry
__a2a3_nextSelectorTramp:
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
// TrampolineEntry
// TrampolineEntry
// TrampolineEntry
// TrampolineEntry
__a2a3_selectorTrampEnd:
#endif
@@ -0,0 +1,568 @@
/*
* a2a3-selectortramps-x86_64.s
* OCMethodTrace
*
* https://github.com/omxcodec/OCMethodTrace.git
*
* Copyright (C) 2018 Michael Chen <omxcodec@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef __x86_64__
#include <mach/mach.h>
#include "selectortramps.mac"
.text
.private_extern __a2a3_selectorTrampHead
.private_extern __a2a3_firstSelectorTramp
.private_extern __a2a3_nextSelectorTramp
.private_extern __a2a3_selectorTrampEnd
.align PAGE_SHIFT
__a2a3_selectorTrampHead:
// 1. selector
popq %r10
andq $0xFFFFFFFFFFFFFFF8, %r10
subq $ PAGE_SIZE, %r10
movq (%r10), %rdx // selector -> _cmd
// 2. msgSend
INIT_PIC(__a2a3_selectorTrampHead)
PRELOAD(__a2a3_selectorTrampHead, __a2a3_selectorTrampHead)
subq $ PAGE_SIZE, LABEL_ADDR(__a2a3_selectorTrampHead, __a2a3_selectorTrampHead)
END_PIC()
jmp *0(%r10) // tail call msgSend
.macro TrampolineEntry
callq __a2a3_selectorTrampHead
nop
nop
nop
.endmacro
.align 5
__a2a3_firstSelectorTramp:
TrampolineEntry
__a2a3_nextSelectorTramp:
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
// TrampolineEntry
// TrampolineEntry
// TrampolineEntry
// TrampolineEntry
__a2a3_selectorTrampEnd:
#endif
@@ -0,0 +1,38 @@
/*
* selectortramps.mac
* OCMethodTrace
*
* https://github.com/omxcodec/OCMethodTrace.git
*
* Copyright (C) 2018 Michael Chen <omxcodec@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef __x86_64__
#define PRELOAD(x,f) movq x@GOTPCREL(%rip), %r10;
#define LABEL_ADDR(x,f) %r10
#define LABEL_VALUE(x,f) (%r10)
#define INIT_PIC(f)
#define END_PIC(f)
#elif __i386__
#define PRELOAD(x,f) leal x-L0## f ##$pb(%ebx), %eax;
#define LABEL_ADDR(x,f) %eax
#define LABEL_VALUE(x,f) (%eax)
#define INIT_PIC(x) \
push %ebx; \
call L0## x ##$pb; \
L0## x ##$pb:; \
pop %ebx;
#define END_PIC(x) pop %ebx
#endif
@@ -0,0 +1,8 @@
//
// Prefix header for all source files of the 'dkhelperDylib' target in the 'dkhelperDylib' project
//
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#import "/opt/theos/Prefix.pch" //path/to/theos/Prefix.pch
#endif
+25
View File
@@ -0,0 +1,25 @@
// weibo: http://weibo.com/xiaoqing28
// blog: http://www.alonemonkey.com
//
// dkhelperDylib.h
// dkhelperDylib
//
// Created by 朱德坤 on 2019/1/23.
// Copyright (c) 2019 DKJone. All rights reserved.
//
#import <Foundation/Foundation.h>
#define INSERT_SUCCESS_WELCOME " 🎉!!congratulations!!!🎉\n👍----------------insert dylib success----------------👍\n"
@interface CustomViewController
@property (nonatomic, copy) NSString* newProperty;
+ (void)classMethod;
- (NSString*)getMyName;
- (void)newMethod:(NSString*) output;
@end
+91
View File
@@ -0,0 +1,91 @@
// weibo: http://weibo.com/xiaoqing28
// blog: http://www.alonemonkey.com
//
// dkhelperDylib.m
// dkhelperDylib
//
// Created by 朱德坤 on 2019/1/23.
// Copyright (c) 2019 DKJone. All rights reserved.
//
#import "dkhelperDylib.h"
#import <CaptainHook/CaptainHook.h>
#import <UIKit/UIKit.h>
#import <Cycript/Cycript.h>
#import <MDCycriptManager.h>
CHConstructor{
printf(INSERT_SUCCESS_WELCOME);
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidFinishLaunchingNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
#ifndef __OPTIMIZE__
CYListenServer(6666);
MDCycriptManager* manager = [MDCycriptManager sharedInstance];
[manager loadCycript:NO];
NSError* error;
NSString* result = [manager evaluateCycript:@"UIApp" error:&error];
NSLog(@"result: %@", result);
if(error.code != 0){
NSLog(@"error: %@", error.localizedDescription);
}
#endif
}];
}
CHDeclareClass(CustomViewController)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wstrict-prototypes"
//add new method
CHDeclareMethod1(void, CustomViewController, newMethod, NSString*, output){
NSLog(@"This is a new method : %@", output);
}
#pragma clang diagnostic pop
CHOptimizedClassMethod0(self, void, CustomViewController, classMethod){
NSLog(@"hook class method");
CHSuper0(CustomViewController, classMethod);
}
CHOptimizedMethod0(self, NSString*, CustomViewController, getMyName){
//get origin value
NSString* originName = CHSuper(0, CustomViewController, getMyName);
NSLog(@"origin name is:%@",originName);
//get property
NSString* password = CHIvar(self,_password,__strong NSString*);
NSLog(@"password is %@",password);
[self newMethod:@"output"];
//set new property
self.newProperty = @"newProperty";
NSLog(@"newProperty : %@", self.newProperty);
//change the value
return @"朱德坤";
}
//add new property
CHPropertyRetainNonatomic(CustomViewController, NSString*, newProperty, setNewProperty);
CHConstructor{
CHLoadLateClass(CustomViewController);
CHClassHook0(CustomViewController, getMyName);
CHClassHook0(CustomViewController, classMethod);
CHHook0(CustomViewController, newProperty);
CHHook1(CustomViewController, setNewProperty);
}
+210
View File
@@ -0,0 +1,210 @@
// Copyright (c) 2013, Facebook, Inc.
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name Facebook nor the names of its contributors may be used to
// endorse or promote products derived from this software without specific
// prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import "fishhook.h"
#import <dlfcn.h>
#import <stdlib.h>
#import <string.h>
#import <sys/types.h>
#import <mach-o/dyld.h>
#import <mach-o/loader.h>
#import <mach-o/nlist.h>
#ifdef __LP64__
typedef struct mach_header_64 mach_header_t;
typedef struct segment_command_64 segment_command_t;
typedef struct section_64 section_t;
typedef struct nlist_64 nlist_t;
#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64
#else
typedef struct mach_header mach_header_t;
typedef struct segment_command segment_command_t;
typedef struct section section_t;
typedef struct nlist nlist_t;
#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT
#endif
#ifndef SEG_DATA_CONST
#define SEG_DATA_CONST "__DATA_CONST"
#endif
struct rebindings_entry {
struct rebinding *rebindings;
size_t rebindings_nel;
struct rebindings_entry *next;
};
static struct rebindings_entry *_rebindings_head;
static int prepend_rebindings(struct rebindings_entry **rebindings_head,
struct rebinding rebindings[],
size_t nel) {
struct rebindings_entry *new_entry = (struct rebindings_entry *) malloc(sizeof(struct rebindings_entry));
if (!new_entry) {
return -1;
}
new_entry->rebindings = (struct rebinding *) malloc(sizeof(struct rebinding) * nel);
if (!new_entry->rebindings) {
free(new_entry);
return -1;
}
memcpy(new_entry->rebindings, rebindings, sizeof(struct rebinding) * nel);
new_entry->rebindings_nel = nel;
new_entry->next = *rebindings_head;
*rebindings_head = new_entry;
return 0;
}
static void perform_rebinding_with_section(struct rebindings_entry *rebindings,
section_t *section,
intptr_t slide,
nlist_t *symtab,
char *strtab,
uint32_t *indirect_symtab) {
uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1;
void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr);
for (uint i = 0; i < section->size / sizeof(void *); i++) {
uint32_t symtab_index = indirect_symbol_indices[i];
if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL ||
symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) {
continue;
}
uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx;
char *symbol_name = strtab + strtab_offset;
if (strnlen(symbol_name, 2) < 2) {
continue;
}
struct rebindings_entry *cur = rebindings;
while (cur) {
for (uint j = 0; j < cur->rebindings_nel; j++) {
if (strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) {
if (cur->rebindings[j].replaced != NULL &&
indirect_symbol_bindings[i] != cur->rebindings[j].replacement) {
*(cur->rebindings[j].replaced) = indirect_symbol_bindings[i];
}
indirect_symbol_bindings[i] = cur->rebindings[j].replacement;
goto symbol_loop;
}
}
cur = cur->next;
}
symbol_loop:;
}
}
static void rebind_symbols_for_image(struct rebindings_entry *rebindings,
const struct mach_header *header,
intptr_t slide) {
Dl_info info;
if (dladdr(header, &info) == 0) {
return;
}
segment_command_t *cur_seg_cmd;
segment_command_t *linkedit_segment = NULL;
struct symtab_command* symtab_cmd = NULL;
struct dysymtab_command* dysymtab_cmd = NULL;
uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t);
for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) {
cur_seg_cmd = (segment_command_t *)cur;
if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) {
if (strcmp(cur_seg_cmd->segname, SEG_LINKEDIT) == 0) {
linkedit_segment = cur_seg_cmd;
}
} else if (cur_seg_cmd->cmd == LC_SYMTAB) {
symtab_cmd = (struct symtab_command*)cur_seg_cmd;
} else if (cur_seg_cmd->cmd == LC_DYSYMTAB) {
dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd;
}
}
if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment ||
!dysymtab_cmd->nindirectsyms) {
return;
}
// Find base symbol/string table addresses
uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff;
nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff);
char *strtab = (char *)(linkedit_base + symtab_cmd->stroff);
// Get indirect symbol table (array of uint32_t indices into symbol table)
uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff);
cur = (uintptr_t)header + sizeof(mach_header_t);
for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) {
cur_seg_cmd = (segment_command_t *)cur;
if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) {
if (strcmp(cur_seg_cmd->segname, SEG_DATA) != 0 &&
strcmp(cur_seg_cmd->segname, SEG_DATA_CONST) != 0) {
continue;
}
for (uint j = 0; j < cur_seg_cmd->nsects; j++) {
section_t *sect =
(section_t *)(cur + sizeof(segment_command_t)) + j;
if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) {
perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab);
}
if ((sect->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS) {
perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab);
}
}
}
}
}
static void _rebind_symbols_for_image(const struct mach_header *header,
intptr_t slide) {
rebind_symbols_for_image(_rebindings_head, header, slide);
}
int rebind_symbols_image(void *header,
intptr_t slide,
struct rebinding rebindings[],
size_t rebindings_nel) {
struct rebindings_entry *rebindings_head = NULL;
int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel);
rebind_symbols_for_image(rebindings_head, (const struct mach_header *) header, slide);
free(rebindings_head);
return retval;
}
int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) {
int retval = prepend_rebindings(&_rebindings_head, rebindings, rebindings_nel);
if (retval < 0) {
return retval;
}
// If this was the first call, register callback for image additions (which is also invoked for
// existing images, otherwise, just run on existing images
if (!_rebindings_head->next) {
_dyld_register_func_for_add_image(_rebind_symbols_for_image);
} else {
uint32_t c = _dyld_image_count();
for (uint32_t i = 0; i < c; i++) {
_rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i));
}
}
return retval;
}
@@ -0,0 +1,76 @@
// Copyright (c) 2013, Facebook, Inc.
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name Facebook nor the names of its contributors may be used to
// endorse or promote products derived from this software without specific
// prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef fishhook_h
#define fishhook_h
#include <stddef.h>
#include <stdint.h>
#if !defined(FISHHOOK_EXPORT)
#define FISHHOOK_VISIBILITY __attribute__((visibility("hidden")))
#else
#define FISHHOOK_VISIBILITY __attribute__((visibility("default")))
#endif
#ifdef __cplusplus
extern "C" {
#endif //__cplusplus
/*
* A structure representing a particular intended rebinding from a symbol
* name to its replacement
*/
struct rebinding {
const char *name;
void *replacement;
void **replaced;
};
/*
* For each rebinding in rebindings, rebinds references to external, indirect
* symbols with the specified name to instead point at replacement for each
* image in the calling process as well as for all future images that are loaded
* by the process. If rebind_functions is called more than once, the symbols to
* rebind are added to the existing list of rebindings, and if a given symbol
* is rebound more than once, the later rebinding will take precedence.
*/
FISHHOOK_VISIBILITY
int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel);
/*
* Rebinds as above, but only in the specified image. The header should point
* to the mach-o header, the slide should be the slide offset. Others as above.
*/
FISHHOOK_VISIBILITY
int rebind_symbols_image(void *header,
intptr_t slide,
struct rebinding rebindings[],
size_t rebindings_nel);
#ifdef __cplusplus
}
#endif //__cplusplus
#endif //fishhook_h