Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

omxcodec/OCMethodTrace

Open more actions menu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

49 Commits
49 Commits
 
 
 
 
 
 
 
 

Repository files navigation

OCMethodTrace - Trace Any Objective-C Method Calls

跟踪打印Objective-C任何实例(类)方法

功能:

  1. 支持任意OC实例(类)方法的跟踪打印
  2. 支持多架构(arm32,arm64,i386,x86_64)
  3. 支持跟踪父类和子类相同的方法
  4. 支持各种灵活配置,包括方法黑白名单等

配置说明:

全局配置:

LogLevel:Trace日志级别,对应MDTraceLogLevel,必须定义,默认值:0

0:MDTraceLogLeveError,错误级别
1:MDTraceLogLeveDebug,调试级别

LogWhen:Trace日志输出时机,对应MDTraceLogWhen,必须定义,默认值:0

0:MDTraceLogWhenStartup ,启动即输出日志
1:MDTraceLogWhenVolume ,根据音量键控制输出日志(增加音量:输出日志;降低音量:关闭日志;默认时关闭日志)
2:MDTraceLogWhenRegexString ,输出日志包含匹配字符串才输出日志

LogRegexString:日志正则匹配字符串,仅当logWhen=MDTraceLogWhenRegexString有效。日志包含指定正则字符串才输出日志

TraceFlag:Trace控制位(尽量在该处扩展),对应MDTraceFlag,全局必须定义,默认值:0x02,指定类可选定义,默认值:0x00

0x01:MDTraceFlagDoesNotUseDescription,跳过调用对象description方法,避免不正规的description实现导致递归
0x02:MDTraceFlagDumpClassListInfo,打印类列表信息,便于调试
0x04:MDTraceFlagDumpClassMethod,打印某个类的方法(不包括父类方法),便于调试
0x08:MDTraceFlagDumpSuperClassMethod,打印某个类的父类方法(包括递归父类的方法),便于调试

TraceObject:Trace对象,对应TraceObject,必须定义,默认值:1

0:MDTraceObjectNone,屏蔽trace所有类
1:MDTraceObjectCoreClass,trace引擎指定类的方法(仅测试验证使用),仅需要考虑CORE_CLASS_LIST
2:MDTraceObjectUserClass,trace用户指定类的方法,需要考虑USER_CLASS_LIST + "USER_CLASS_LIST和CORE_CLASS_LIST交集"
3:MDTraceObjectRegexClass,trace用户指定类 + 正则匹配类的方法,需要考虑USER_CLASS_LIST + "USER_CLASS_LIST和CORE_CLASS_LIST交集" + "匹配ClassRegexString的CLASS_LIST和CORE_CLASS_LIST交集"

MDTraceObjectUserClass和MDTraceObjectRegexClass的区别:
* MDTraceObjectUserClass:在考虑USER_CLASS_LIST指定的类的时候,如果USER_CLASS_LIST和CORE_CLASS_LIST存在部分交集,交集对应的类需要合并,合并算法详见:+[MDTraceClassInfo mergeInfoWithCoreInfo:userInfo:userInfo:]
* MDTraceObjectRegexClass:在考虑MDTraceObjectUserClass的基础上,再考虑ClassRegexString正则匹配的类。

处理TraceObject的详细算法见:-[ MDMethodTrace parseClassListInfo],算法内部注意优先级顺序:core > user > regex

指定类配置:

USER_CLASS_LIST:用户指定类列表,必须定义

TraceMode: Trace模式,对应MDTraceMode,可选定义,默认值:1
    0:MDTraceModeOff,屏蔽trace方法
    1:MDTraceModeAll,trace所有方法
    2:MDTraceModeIncludeWhiteList,trace包含"白名单方法列表"的方法
    3:MDTraceModeExcludeBlackList,trace排除"黑名单方法列表"的方法
TraceFlag:定义同全局配置,但是粒度更小,属于某个类范围内,可选定义,默认值:0x00
MethodWhiteList:白名单方法列表,可选定义,但MDTraceModeIncludeWhiteList时必须定义
MethodBlackList:黑名单方法列表,可选定义,但MDTraceModeExcludeBlackList时必须定义

跟踪某些类的时候,该类的某些方法有可能会导致app崩溃。这时候,你可以通过多次的试验,找出导致崩溃的方法,使用黑名单模式,然后把这些异常方法放在黑名单方法列表中。当然,如果你并不需要跟踪该类全部的方法的话,也可以使用白名单模式。

CORE_CLASS_LIST:引擎指定类列表,必须定义

TraceMode:定义同USER_CLASS_LIST的TraceMode,但是仅支持MDTraceModeOff和MDTraceModeExcludeBlackList
TraceFlag:定义同全局配置,但是粒度更小,属于某个类范围内,可选定义,默认值:0x00
MethodBlackList:黑名单方法列表,可选定义,但MDTraceModeExcludeBlackList时必须定义

ClassRegexString:类正则匹配字符串,仅TraceObject=MDTraceObjectRegexClass有效

每个匹配的类使用默认类配置(可以理解成一个默认的User类)。使用场景:在不确定trace哪些类的情况下,批量trace一些有规律命名方式的类,匹配字符串如:“Notification|^CM|(F|f)igCaptureSource”

USER_CLASS_LIST和CORE_CLASS_LIST的关系:

* CORE_CLASS_LIST:存在的意义在于,OCMethodTrace框架(引擎)内部也需要调用一些OC类方法,为了保证整个框架可以跑起来,避免trace到框架内部使用到的类导致的打印递归循环,所以,需排除这些指定类的全部方法或者部分方法。
* USER_CLASS_LIST:用户自己指定的类,可以任意发挥。但是如果CORE_CLASS_LIST有相同的类,会优先CORE_CLASS_LIST中的配置。合并算法详见"+[MDTraceClassInfo mergeInfoWithCoreInfo:userInfo:userInfo:]"

技术要点:

支持跟踪父类和子类相同的方法

SatanWoo提出了一个方法(见感谢2),使用“runtime的消息转发机制+跳板原理(桥)”实现,流程:
每个方法置换到不同的IMP桥上 -> 从桥上反推出当前的调用关系(class和selector)-> 构造一个中间态新名字 -> forwardingTargetForSelector(self, 中间态新名字) 。
但是SatanWoo的demo(见感谢3)有两个比较大的缺陷:
* 仅支持arm64平台,不支持多架构;
* 仅支持实例方法,不支持类方法。
为此我做了一些改进,如下:
* 支持多架构:参考objc4(见感谢4)的objc-block-trampolines.m,编写了一个通用的跳板实现,其中通过汇编支持多架构。
* 支持类方法:NSObject (OCMethodTrace)需hook类方法"+[NSObject forwardingTargetForSelector:]"

Trace输出无限循环递归的特殊处理

递归调用都发生在"-[OCMethodTrace omt_forwardInvocation:]"函数内部,有两个地方:
* 对象调用自身的description导致的无限递归:为了打印对象的描述,需要调用对象的description方法,而该方法内部很可能会调用对象的其它内部方法,继而递归又调用"-[OCMethodTrace omt_forwardInvocation:]",于是无限循环。当前解决的方法是:在"-[OCMethodTrace omt_forwardInvocation:]"开始处通过遍历函数堆栈链查找"OMTBlockRunBeforeSelector","OMTBlockRunAfterSelector"和"OMTDescriptionWithTargetSelector"这几个方法,可以知道是否存在递归,发现递归就不要再调用runBefore和runAfter回调即可。缺点:遍历函数堆栈链的方法实在不优雅,而且性能也受影响,需要优化!
* OCMethodTrace框架使用到的基础类导致的无限递归:比如"-[OCMethodTrace omt_forwardInvocation:]"函数范围内用到一些类:如NSDate,NSString或者runBefore或runAfter回调用到的方法等,一旦他们也被trace,也会导致循环递归。解决的思路是:把这些类放在黑名单里,不再trace。当然还有降低循环递归的方式是,内部实现尽量使用C或者C++实现。

TODO:

  1. 通过遍历堆栈链,判断是否存在循环递归调用的算法性能太差,需优化。
  2. 开启全局dump类方法(MDTraceFlagDumpClassMethod)容易导致异常,不建议开启。

感谢:

  1. https://github.com/qhd/ANYMethodLog
  2. https://satanwoo.github.io/2017/09/24/mainthreadchecker1
  3. https://github.com/SatanWoo/MainThreadChecker.git
  4. https://opensource.apple.com/tarballs/objc4/objc4-723.tar.gz

欢迎提Issues和Pull requests,如有问题,可以联系 Michael Chen (omxcodec@gmail.com)

Releases

No releases published

Packages

 
 
 

Contributors

Morty Proxy This is a proxified and sanitized view of the page, visit original site.