Oc Method Trace
Oc Method Trace
* OCMethodTrace.m
* OCMethodTrace
*
* https://github.com/omxcodec/OCMethodTrace.git
*
* Copyright (C) 2018 Michael Chen <[email protected]>
*
* 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 "OCMethodTrace.h"
#import <UIKit/UIKit.h>
#import <objc/runtime.h>
#import <objc/message.h>
#import <execinfo.h>
#import <dlfcn.h>
#import <pthread.h>
#import "OCSelectorTrampolines.h"
// trace 位置
typedef NS_ENUM(NSUInteger, OMTTracePosition) {
OMTTracePositionBefore = 1 << 0, // before
OMTTracePositionAfter = 1 << 1, // after
};
// 错误码,对内使用,便于调试
typedef NS_ENUM(NSUInteger, OMTErrorCode) {
OMTErrorNoError, // NERR 没有错误
OMTErrorSelectorPassThrough, // SPTH 透传不处理
OMTErrorSelectorAlreadyHooked, // SAHK 已经 hook 过
OMTErrorSelectorInUserBlacklist, // SIUB 在用户的黑名单里
OMTErrorClassInSelfBlacklist, // CISB 在内部的类黑名单里
OMTErrorSelectorInSelfBlacklist, // SISB 在内部的 sel 黑名单里
OMTErrorSelectorUnsuppotedMethodSignature, // SUMS 无法支持的方法签名(导致 crash 的异常签名)
OMTErrorSelectorUnsuppotedEncodeType, // SUEY 无法支持的编码类型(局部无法识别的签名)
OMTErrorDoesNotRespondToMethod, // NMTD 无此 method
OMTErrorDoesNotRespondToSelector, // NSEL 无此 sel
OMTErrorDoesNotRespondToIMP, // NIMP 无此 IMP
OMTErrorSwizzleMethodFailed, // SMDF 替换方法失败
};
////////////////////////////////////////////////////////////////////////////////
#pragma mark - C Helper Define
// 替换实例方法
static void swizzle_instance_method(Class cls, SEL originSel, SEL newSel);
// 替换类方法
static void swizzle_class_method(Class cls, SEL originSel, SEL newSel);
// 是否支持某类型限定符
static BOOL omt_isTypeQualifier(const char argumentType);
// 是否是 struct 类型
static BOOL omt_isStructType(const char *argumentType);
// 获取 struct 类型名
static NSString *omt_structName(const char *argumentType);
// 是否是 union 类型
static BOOL omt_isUnionType(const char *argumentType);
// 获取 union 类型名
static NSString *omt_unionName(const char *argumentType);
static BOOL isCGRect (const char *type);
static BOOL isCGPoint (const char *type);
static BOOL isCGSize (const char *type);
static BOOL isCGVector (const char *type);
static BOOL isUIOffset (const char *type);
static BOOL isUIEdgeInsets (const char *type);
static BOOL isCGAffineTransform(const char *type);
////////////////////////////////////////////////////////////////////////////////
#pragma mark - Class Define
- (BOOL)runCondition:(SEL)sel;
- (void)runBefore:(id)target class:(Class)cls sel:(SEL)sel args:(NSArray *)args
deep:(int)deep;
- (void)runAfter:(id)target class:(Class)cls sel:(SEL)sel ret:(id)ret deep:
(int)deep interval:(NSTimeInterval)interval;
@end
- (instancetype)initWithTarget:(id)target selector:(SEL)aSelector;
@end
// 类转发方法
+ (id)omt_forwardingTargetForSelector:(SEL)aSelector;
// 实例转发方法
- (id)omt_forwardingTargetForSelector:(SEL)aSelector;
@end
// 获取原始的类名
- (Class)omt_originClass;
// 获取原始的方法名
- (SEL)omt_originSelector;
// 获取方法返回值
- (id)omt_getReturnValue;
// 获取方法参数
- (NSArray *)omt_getArguments;
@end
@interface OCMethodTrace() {
pthread_mutex_t _blockMutex;
pthread_mutex_t _deepMutex;
}
// 初始化内部默认黑名单
- (void)initDefaultClassBlackList;
- (void)initDefaultMethodBlackList;
// 初始化所支持类型编码的字典
- (void)initSupportedTypeDict;
// 初始化 trace 位置字典
- (void)initTracePositionDict;
// 根据错误码返回错误描述
+ (NSString *)errorString:(OMTErrorCode)errorCode;
// 判断函数数组里任意函数是否存在递归循环调用
+ (BOOL)detectInfiniteLoopAtSelectorArray:(NSArray *)selectorArray;
// 获取 target 的 description
- (NSString *)descriptionWithTarget:(id)target class:(Class)cls selector:(SEL)sel
targetPosition:(OMTTargetPosition)targetPosition;
// 判断类是否在内部默认黑名单中
- (BOOL)isClassInBlackList:(NSString *)className;
// 判断方法是否在内部默认黑名单中
- (BOOL)isSelectorInBlackList:(NSString *)methodName;
// 判断类型编码是否可以处理
- (BOOL)isSupportedType:(NSString *)typeEncode;
// 获取方法名对应的 trace 位置
- (OMTTracePosition)tracePosition:(NSString *)methodName;
// block 相关
- (void)setBlock:(OMTBlock *)block forKey:(NSString *)key;
- (OMTBlock *)blockforKey:(NSString *)key;
- (OMTBlock *)blockWithTarget:(id)target;
// 原子操作 deep++,返回原值
- (int)atomicAddDeep;
// 原子操作 deep--
- (void)atomicIncDeep;
// 根据条件跟踪目标类的方法
- (void)traceMethodWithClass:(Class)cls condition:(OMTConditionBlock)condition;
// 判断方法是否支持跟踪
- (OMTErrorCode)isTraceSupportedWithClass:(Class)cls method:(Method)method;
// 替换方法
- (OMTErrorCode)swizzleMethodWithClass:(Class)cls selector:(SEL)selector;
// 转发实现
- (void)omt_forwardInvocation:(NSInvocation *)invocation;
@end
////////////////////////////////////////////////////////////////////////////////
size_t i;
for (i = 0; i < kNumSupportedTypeQualifier; i++) {
if (argumentType == supportedTypeQualifierList[i]) {
return YES;
}
}
return NO;
}
////////////////////////////////////////////////////////////////////////////////
#pragma mark - OCMethodTrace
@implementation OCMethodTrace
////////////////////////////////////////////////////////////////////////////////
+ (OCMethodTrace *)sharedInstance
{
static OCMethodTrace *instance = nil;
static dispatch_once_t pred;
dispatch_once(&pred, ^{
instance = [[OCMethodTrace alloc] init];
});
return instance;
}
- (void)traceMethodWithClass:(Class)cls
condition:(OMTConditionBlock)condition
before:(OMTBeforeBlock)before
after:(OMTAfterBlock)after
{
#ifndef DEBUG
return;
#endif
// 黑名单的类不跟踪
if ([self isClassInBlackList:NSStringFromClass(cls)]) {
OMT_LOG(OMTLogLevelDebug, @"[%@] trace class: %@",
[self.class errorString:OMTErrorClassInSelfBlacklist],
NSStringFromClass(cls));
return;
}
// 处理实例方法
[self traceMethodWithClass:cls condition:condition];
// 处理类方法
Class metaCls = object_getClass(cls);
if (class_isMetaClass(metaCls)) {
[self traceMethodWithClass:metaCls condition:condition];
}
}
////////////////////////////////////////////////////////////////////////////////
#pragma mark - Private OCMethodTrace API
- (instancetype)init
{
self = [super init];
if (self) {
// 参考 ANYMethodLog 的处理
[self initDefaultClassBlackList];
[self initDefaultMethodBlackList];
[self initSupportedTypeDict];
[self initTracePositionDict];
self.disableTrace = NO;
self.logLevel = OMTLogLevelDebug;
self.blockCache = [NSMutableDictionary dictionary];
self.deep = 0;
pthread_mutex_init(&_blockMutex, NULL);
pthread_mutex_init(&_deepMutex, NULL);
}
return self;
}
- (void)dealloc
{
pthread_mutex_destroy(&_blockMutex);
pthread_mutex_destroy(&_deepMutex);
}
- (void)initDefaultClassBlackList
{
self.defaultClassBlackList = @[@"OCMethodTrace",
@"OMTBlock",
@"OMTMessageStub",
@"NSMethodSignature",
@"NSInvocation",
];
}
- (void)initDefaultMethodBlackList
{
self.defaultMethodBlackList = @[@".cxx_destruct",
@"_isDeallocating",
@"release",
@"autorelease",
@"recycle",
@"retain",
@"Retain",
@"_tryRetain",
@"copy",
@"copyWithZone:",
@"mutableCopyWithZone:",
@"nsis_descriptionOfVariable:",
@"respondsToSelector:",
@"class",
@"methodSignatureForSelector:",
@"allowsWeakReference",
@"retainWeakReference",
@"forwardInvocation:",
@"description",
@"sharedInstance",
@"SharedInstance",
@"getInstance",
@"GetInstance",
];
}
- (void)initSupportedTypeDict
{
// https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/
ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-
CH100-SW1
- (void)initTracePositionDict
{
// @interface NSObject
self.tracePositionDict = @{@"initialize" : @(OMTTracePositionBefore |
OMTTracePositionAfter),
@"init" : @(OMTTracePositionBefore |
OMTTracePositionAfter),
@"new" : @(OMTTracePositionBefore |
OMTTracePositionAfter),
@"allocWithZone:" : @(OMTTracePositionBefore |
OMTTracePositionAfter),
@"alloc" : @(OMTTracePositionBefore |
OMTTracePositionAfter),
@"dealloc" : @(OMTTracePositionBefore),
@"finalize" : @(OMTTracePositionBefore),
}; // 添加更多类型
}
+ (NSString *)errorString:(OMTErrorCode)errorCode
{
struct CodeToString {
OMTErrorCode errorCode;
const char *errorString;
};
static const struct CodeToString kCodeToString[] = {
{ OMTErrorNoError, "NERR" },
{ OMTErrorSelectorPassThrough, "SPTH" },
{ OMTErrorSelectorAlreadyHooked, "SAHK" },
{ OMTErrorSelectorInUserBlacklist, "SIUB" },
{ OMTErrorClassInSelfBlacklist, "CISB" },
{ OMTErrorSelectorInSelfBlacklist, "SISB" },
{ OMTErrorSelectorUnsuppotedMethodSignature,"SUMS" },
{ OMTErrorSelectorUnsuppotedEncodeType, "SUEY" },
{ OMTErrorDoesNotRespondToMethod, "NMTD" },
{ OMTErrorDoesNotRespondToSelector, "NSEL" },
{ OMTErrorDoesNotRespondToIMP, "NIMP" },
{ OMTErrorSwizzleMethodFailed, "SMDF" },
};
size_t i;
for (i = 0; i < kNumCodeToString; i++) {
if (errorCode == kCodeToString[i].errorCode) {
break;
}
}
NSAssert(i != kNumCodeToString, @"Unknown errorCode???");
+ (BOOL)detectInfiniteLoopAtSelectorArray:(NSArray *)selectorArray
{
void *callstack[128];
int frames = backtrace(callstack, 128);
char **strs = backtrace_symbols(callstack, frames);
- (BOOL)isClassInBlackList:(NSString *)className
{
return [self.defaultClassBlackList containsObject:className];
}
- (BOOL)isSelectorInBlackList:(NSString *)methodName
{
return [self.defaultMethodBlackList containsObject:methodName];
}
- (BOOL)isSupportedType:(NSString *)typeEncode
{
return [self.supportedTypeDict.allKeys containsObject:typeEncode];
}
- (OMTTracePosition)tracePosition:(NSString *)methodName
{
OMTTracePosition defaultPostion = OMTTracePositionBefore |
OMTTracePositionAfter;
return [self.tracePositionDict.allKeys containsObject:methodName] ?
[self.tracePositionDict[methodName] intValue]: defaultPostion;
}
- (OMTBlock *)blockWithTarget:(id)target
{
pthread_mutex_lock(&_blockMutex);
Class cls = [target class];
OMTBlock *block = [self.blockCache objectForKey:NSStringFromClass(cls)];
while (nil == block) {
cls = [cls superclass];
if (nil == cls) {
break;
}
block = [self.blockCache objectForKey:NSStringFromClass(cls)];
}
pthread_mutex_unlock(&_blockMutex);
return block;
}
- (int)atomicAddDeep
{
pthread_mutex_lock(&_deepMutex);
int deep = _deep++;
pthread_mutex_unlock(&_deepMutex);
return deep;
}
- (void)atomicIncDeep
{
pthread_mutex_lock(&_deepMutex);
_deep--;
pthread_mutex_unlock(&_deepMutex);
}
- (void)traceMethodWithClass:(Class)cls condition:(OMTConditionBlock)condition
{
unsigned int outCount;
Method *methods = class_copyMethodList(cls, &outCount);
for (unsigned int i = 0; i < outCount; i++) {
Method method = *(methods + i);
SEL selector = method_getName(method);
if (errorCode == OMTErrorNoError) {
errorCode = [self swizzleMethodWithClass:cls selector:selector];
}
- (OMTErrorCode)isTraceSupportedWithClass:(Class)cls method:(Method)method
{
char returnTypeCString[1024];
memset(returnTypeCString, 0, sizeof(returnTypeCString));
method_getReturnType(method, returnTypeCString, sizeof(returnTypeCString));
const char *returnType = returnTypeCString;
// 3 内部黑名单中的方法不处理
if ([self isSelectorInBlackList:selectorName]) {
return OMTErrorSelectorInSelfBlacklist;
}
// 4 签名异常的方法不处理。模拟器下有一些奇葩的方法(系统方法居多)签名异常,会导致[NSMethodSignature
signatureWithObjCTypes:] crash,所以需捕捉异常
BOOL hasSignatureException = NO;
@try {
__unused NSMethodSignature *methodSignature = [NSMethodSignature
signatureWithObjCTypes:method_getTypeEncoding(method)];
} @catch (__unused NSException *e) {
hasSignatureException = YES;
}
if (hasSignatureException) {
return OMTErrorSelectorUnsuppotedMethodSignature;
}
// 5 处理返回值类型
// 跳过类型限定符
if (omt_isTypeQualifier(returnType[0])) {
returnType++;
}
// 支持指针类型
if (returnType[0] != _C_PTR) {
// struct 和 union 有可能无法解析,但是也通过,解释不出的用 NSValue 输出,便于打印函数调用链
if (!(omt_isStructType(returnType) || omt_isUnionType(returnType))) {
if (![self isSupportedType:[NSString stringWithUTF8String:returnType]])
{
return OMTErrorSelectorUnsuppotedEncodeType;
}
}
}
// 跳过类型限定符
if (omt_isTypeQualifier(argumentType[0])) {
argumentType++;
}
// 支持指针类型
if (argumentType[0] == _C_PTR) {
continue;
}
return OMTErrorNoError;
}
- (OMTErrorCode)swizzleMethodWithClass:(Class)cls selector:(SEL)selector
{
// 1 检查该 selector 是否已经 hook 过
SEL newSelector = NSSelectorFromString([NSString stringWithFormat:@"%@%@->%@",
OMTMessageFinalPrefix,
NSStringFromClass(cls),
NSStringFromSelector(selector)]);
if (class_respondsToSelector(cls, newSelector)) {
return OMTErrorSelectorAlreadyHooked;
}
// 2 原方法相关校验
Method originMethod = class_getInstanceMethod(cls, selector);
if (!originMethod) {
return OMTErrorDoesNotRespondToMethod;
}
IMP originIMP = method_getImplementation(originMethod);
if (!originIMP) {
return OMTErrorDoesNotRespondToIMP;
}
const char *originTypes = method_getTypeEncoding(originMethod);
// 3 转发:旧方法跳转到转发 IMP
// 使用比较另类的"类与方法间隔符",如"->"。如果使用"_",有可能会导致冲突,如系统内部类"__CFNotification"就会异常
SEL forwardingSEL = NSSelectorFromString([NSString stringWithFormat:@"%@%@->
%@",
OMTMessageTempPrefix,
NSStringFromClass(cls),
NSStringFromSelector(selector)]);
IMP forwardingIMP = imp_implementationWithSelector(forwardingSEL, originTypes);
NSAssert(originIMP != forwardingIMP, @"originIMP != forwardingIMP");
method_setImplementation(originMethod, forwardingIMP);
return OMTErrorNoError;
}
- (void)omt_forwardInvocation:(NSInvocation *)invocation
{
if (self.disableTrace) {
[invocation invoke];
return;
}
OMTBlockRunAfterSelector,
OMTDescriptionWithTargetSelector]];
if ([originClass isSubclassOfClass:NSBundle.class] &&
[NSStringFromSelector(originSelector) isEqualToString:@"dealloc"]) {
disableTrace = YES;
}
int deep = [self atomicAddDeep];
if (!disableTrace) {
if ([originClass isSubclassOfClass:NSBundle.class] &&
[NSStringFromSelector(originSelector) isEqualToString:@"dealloc"]) {
return;
}
OMTBlock *block = [self blockWithTarget:invocation.target];
OMTTracePosition postion = [self
tracePosition:NSStringFromSelector(originSelector)];
NSDate *start;
// 2 调用原方法
[invocation invoke];
// 3 原方法调用后回调
if (postion & OMTTracePositionAfter) {
NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:start];
if (target) {
[block runAfter:target class:originClass sel:originSelector ret:
[invocation omt_getReturnValue] deep:deep interval:interval];
}
}
} else {
// 直接调用原方法
[invocation invoke];
}
[self atomicIncDeep];
}
@end
////////////////////////////////////////////////////////////////////////////////
#pragma mark - OMTBlock
@implementation OMTBlock
- (BOOL)runCondition:(SEL)sel
{
if (self.condition) {
return self.condition(sel);
} else {
return YES;
}
}
@end
////////////////////////////////////////////////////////////////////////////////
#pragma mark - OMTMessageStub
@implementation OMTMessageStub
- (instancetype)initWithTarget:(id)target selector:(SEL)aSelector
{
self = [super init];
if (self) {
self.target = target;
NSString *finalSelectorName = [NSStringFromSelector(aSelector)
stringByReplacingOccurrencesOfString:OMTMessageTempPrefix
withString:OMTMessageFinalPrefix];
self.selector = NSSelectorFromString(finalSelectorName);
}
return self;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
Method method = class_getInstanceMethod(object_getClass(self.target),
self.selector);
if (NULL == method) {
OMT_LOGE(@"No Method, target: %@ selector: %@", self.target,
NSStringFromSelector(self.selector));
assert(NULL != method);
}
// 勿删,调试观察类名和方法名
__unused const char *className = [NSStringFromClass([self.target class])
UTF8String];
__unused const char *selectorName = [NSStringFromSelector(self.selector)
UTF8String];
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p target: %p selector: %@>",
NSStringFromClass([self class]), self, self.target,
NSStringFromSelector(self.selector)];
}
@end
////////////////////////////////////////////////////////////////////////////////
#pragma mark - NSObject (OCMethodTrace)
+ (void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
swizzle_class_method([self class], @selector(forwardingTargetForSelector:),
@selector(omt_forwardingTargetForSelector:));
swizzle_instance_method([self class],
@selector(forwardingTargetForSelector:),
@selector(omt_forwardingTargetForSelector:));
});
}
+ (id)omt_forwardingTargetForSelector:(SEL)aSelector
{
if ([NSStringFromSelector(aSelector) hasPrefix:OMTMessageTempPrefix] && ![self
isKindOfClass:[OMTMessageStub class]]) {
return [[OMTMessageStub alloc] initWithTarget:self selector:aSelector];
}
return [self omt_forwardingTargetForSelector:aSelector];
}
- (id)omt_forwardingTargetForSelector:(SEL)aSelector
{
if ([NSStringFromSelector(aSelector) hasPrefix:OMTMessageTempPrefix] && ![self
isKindOfClass:[OMTMessageStub class]]) {
return [[OMTMessageStub alloc] initWithTarget:self selector:aSelector];
}
return [self omt_forwardingTargetForSelector:aSelector];
}
@end
////////////////////////////////////////////////////////////////////////////////
#pragma mark - NSInvocation (OCMethodTrace)
- (Class)omt_originClass
{
NSString *finalSelectorName = [NSStringFromSelector(self.selector)
stringByReplacingOccurrencesOfString:OMTMessageFinalPrefix withString:@""];
NSUInteger location = [finalSelectorName rangeOfString:@"->"].location;
NSString *originClassName = [finalSelectorName
substringWithRange:NSMakeRange(0, location)];
return NSClassFromString(originClassName);
}
- (SEL)omt_originSelector
{
NSString *finalSelectorName = [NSStringFromSelector(self.selector)
stringByReplacingOccurrencesOfString:OMTMessageFinalPrefix withString:@""];
NSUInteger location = [finalSelectorName rangeOfString:@"->"].location;
NSString *originSelectorName = [finalSelectorName
substringWithRange:NSMakeRange(location + 2, finalSelectorName.length - location -
2)];
return NSSelectorFromString(originSelectorName);
}
- (id)omt_getReturnValue
{
const char *returnType = self.methodSignature.methodReturnType;
id ret = nil;
// 跳过类型限定符
if (omt_isTypeQualifier(returnType[0])) {
returnType++;
}
// 基本类型
#define GET_RETURN_VALUE(_type) \
if (0 == strcmp(returnType, @encode(_type))) { \
_type ret_temp; \
[self getReturnValue:&ret_temp]; \
ret = @(ret_temp); \
}
// 结构体类型
#define GET_STRUCT_RETURN_VALUE(_type) \
if (is##_type(returnType)) { \
_type ret_temp; \
[self getReturnValue:&ret_temp]; \
ret = NSStringFrom##_type(ret_temp); \
}
if (omt_isStructType(returnType)) {
GET_STRUCT_RETURN_VALUE(CGRect)
else GET_STRUCT_RETURN_VALUE(CGPoint)
else GET_STRUCT_RETURN_VALUE(CGSize)
else GET_STRUCT_RETURN_VALUE(CGVector)
else GET_STRUCT_RETURN_VALUE(UIOffset)
else GET_STRUCT_RETURN_VALUE(UIEdgeInsets)
else GET_STRUCT_RETURN_VALUE(CGAffineTransform)
}
else if (omt_isUnionType(returnType)) {
// do nothing
}
else GET_RETURN_VALUE(char)
else GET_RETURN_VALUE(int)
else GET_RETURN_VALUE(short)
else GET_RETURN_VALUE(long)
else GET_RETURN_VALUE(long long)
else GET_RETURN_VALUE(unsigned char)
else GET_RETURN_VALUE(unsigned int)
else GET_RETURN_VALUE(unsigned short)
else GET_RETURN_VALUE(unsigned long)
else GET_RETURN_VALUE(unsigned long long)
else GET_RETURN_VALUE(float)
else GET_RETURN_VALUE(double)
else GET_RETURN_VALUE(BOOL)
else if (strcmp(returnType, @encode(void)) == 0) {
ret = @"void";
}
else if (0 == strcmp(returnType, @encode(char *))) {
char *ret_temp;
[self getReturnValue:&ret_temp];
ret = [NSString stringWithUTF8String:ret_temp ? ret_temp : "NULL"];
}
else if (0 == strcmp(returnType, @encode(id))) {
__unsafe_unretained id ret_temp;
[self getReturnValue:&ret_temp];
ret = [[OCMethodTrace sharedInstance] descriptionWithTarget:ret_temp class:
[self omt_originClass] selector:[self omt_originSelector]
targetPosition:OMTTargetPositionAfterReturnValue];
}
else if (0 == strcmp(returnType, @encode(Class))) {
Class ret_temp;
[self getReturnValue:&ret_temp];
ret = NSStringFromClass(ret_temp);
}
else if (0 == strcmp(returnType, @encode(SEL))) {
SEL ret_temp;
[self getReturnValue:&ret_temp];
ret = NSStringFromSelector(ret_temp);
}
else if (0 == strcmp(returnType, "@?")) { // block
// 则模仿 lldb bt 堆栈打印形式,直接打印地址
void *ret_temp;
[self getReturnValue:&ret_temp];
ret = [NSString stringWithFormat:@"%p", ret_temp];
}
else if (returnType[0] == _C_PTR) {
void *ret_temp;
[self getReturnValue:&ret_temp];
if (0 == strcmp(returnType, @encode(CFStringRef))) {
ret = [NSString stringWithString:ret_temp ? (__bridge NSString
*)ret_temp : @"NULL"]; // 深拷贝
}
if (nil == ret) {
// 模仿 lldb bt 堆栈打印形式,直接打印地址
ret = [NSString stringWithFormat:@"%p", ret_temp];
}
}
if (nil == ret) {
NSUInteger valueSize = 0;
NSGetSizeAndAlignment(returnType, &valueSize, NULL);
unsigned char valueBytes[valueSize];
[self getReturnValue:valueBytes];
ret = [NSValue valueWithBytes:valueBytes objCType:returnType];
}
return ret;
}
- (NSArray *)omt_getArguments
{
NSMethodSignature *methodSignature = [self methodSignature];
NSMutableArray *argList = (methodSignature.numberOfArguments > 2 ?
[NSMutableArray array] : nil);
for (NSUInteger i = 2; i < methodSignature.numberOfArguments; i++) {
const char *argumentType = [methodSignature getArgumentTypeAtIndex:i];
id arg = nil;
// 跳过类型限定符
if (omt_isTypeQualifier(argumentType[0])) {
argumentType++;
}
// 基本类型
#define GET_ARGUMENT(_type) \
if (0 == strcmp(argumentType, @encode(_type))) { \
_type arg_temp; \
[self getArgument:&arg_temp atIndex:i]; \
arg = @(arg_temp); \
}
// 结构体类型
#define GET_STRUCT_ARGUMENT(_type) \
if (is##_type(argumentType)) { \
_type arg_temp; \
[self getArgument:&arg_temp atIndex:i]; \
arg = NSStringFrom##_type(arg_temp); \
}
if (omt_isStructType(argumentType)) {
GET_STRUCT_ARGUMENT(CGRect)
else GET_STRUCT_ARGUMENT(CGPoint)
else GET_STRUCT_ARGUMENT(CGSize)
else GET_STRUCT_ARGUMENT(CGVector)
else GET_STRUCT_ARGUMENT(UIOffset)
else GET_STRUCT_ARGUMENT(UIEdgeInsets)
else GET_STRUCT_ARGUMENT(CGAffineTransform)
}
else if (omt_isUnionType(argumentType)) {
// do nothing
}
else GET_ARGUMENT(char)
else GET_ARGUMENT(int)
else GET_ARGUMENT(short)
else GET_ARGUMENT(long)
else GET_ARGUMENT(long long)
else GET_ARGUMENT(unsigned char)
else GET_ARGUMENT(unsigned int)
else GET_ARGUMENT(unsigned short)
else GET_ARGUMENT(unsigned long)
else GET_ARGUMENT(unsigned long long)
else GET_ARGUMENT(float)
else GET_ARGUMENT(double)
else GET_ARGUMENT(BOOL)
else if (0 == strcmp(argumentType, @encode(char *))) {
char *arg_temp;
[self getArgument:&arg_temp atIndex:i];
arg = [NSString stringWithUTF8String:arg_temp ? arg_temp : "NULL"];
}
else if (0 == strcmp(argumentType, @encode(id))) {
__unsafe_unretained id arg_temp;
[self getArgument:&arg_temp atIndex:i];
arg = [[OCMethodTrace sharedInstance] descriptionWithTarget:arg_temp
class:[arg_temp class] selector:[self omt_originSelector]
targetPosition:OMTTargetPositionBeforeArgument];
}
else if (0 == strcmp(argumentType, @encode(Class))) {
Class arg_temp;
[self getArgument:&arg_temp atIndex:i];
arg = NSStringFromClass(arg_temp);
}
else if (0 == strcmp(argumentType, @encode(SEL))) {
SEL arg_temp;
[self getArgument:&arg_temp atIndex:i];
arg = NSStringFromSelector(arg_temp);
}
else if (0 == strcmp(argumentType, "@?")) { // block
// 则模仿 lldb bt 堆栈打印形式,直接打印地址
void *arg_temp;
[self getArgument:&arg_temp atIndex:i];
arg = [NSString stringWithFormat:@"%p", arg_temp];
}
else if (argumentType[0] == _C_PTR) {
void *arg_temp;
[self getArgument:&arg_temp atIndex:i];
if (0 == strcmp(argumentType, @encode(CFStringRef))) {
arg = [NSString stringWithString:arg_temp ? (__bridge NSString
*)arg_temp : @"NULL"]; // 深拷贝
}
if (nil == arg) {
// 则模仿 lldb bt 堆栈打印形式,直接打印地址
arg = [NSString stringWithFormat:@"%p", arg_temp];
}
}
if (nil == arg) {
NSUInteger valueSize = 0;
NSGetSizeAndAlignment(argumentType, &valueSize, NULL);
unsigned char valueBytes[valueSize];
[self getArgument:valueBytes atIndex:i];
arg = [NSValue valueWithBytes:valueBytes objCType:argumentType];
}
[argList addObject:arg];
}
return argList;
}
@end