【注意】最后更新于 November 9, 2018,文中内容可能已过时,请谨慎使用。
{% github it-boyer chisel f331dc6 width = 30% %}
这个pull请求添加findinstances命令,该命令完成Add findinstances, and new support framework in Chisel.xcodeproj 和Add Makefile for installing framework的工作。
用户可以运行help findinstances获取findinstances的详细信息。简要总结一下,findinstances可以找到给定class类或protocol协议的所有实例,并使用谓词表达式过滤这些结果。
如果您有一个名为XXSocialUser的类,那么您可以通过运行findinstances XXSocialUser == 'curry'来找到一个特定的用户。
Chisel.xcodeproj为新建findinstance提供了凿子框架支持。
使用Chisel.xcodeproj支持新建chisel Framework通过本地代码实现command,findinstances等功能。也可以通过这种方式来实现更多chisel命令。
findinstance命令通过扫描iOS/macOSmalloc API。对于每个allocation分配,都会使用heuristics来识别可能的Objective-C实例。heuristics不调用对象上的method,而是依赖objc runtime运行时函数,基于class metadata类元数据来匹配到oc实例。这避免了在objc运行时机制下分配和有状态副作用。
在第一次传递之后,候选对象将通过第二次传递,检查它们是否与可选的NSPredicate匹配。如果没有谓词,则输出对象的信息最少。如果有谓词,并且对象传递谓词,那么对象将输出更多细节,特别是谓词中查询的细节。
| 1
2
3
4
5
6
7
 | findinstances UIView
findinstances *UIView
findinstances UIScrollViewDelegate
findinstances UIView window == nil || hidden == true || alpha == 0 || layer.bounds.#size.width == 0 ||  layer.bounds.#size.height == 0 
findinstances UIView subviews.@count == 0
findinstances NSDictionary any @allKeys beginswith 'perf_'
findinstances NSArray @count > 100
 | 
开发使用
构建Xcode项目,并获得到Chisel Framework的路径。:
| 1
 | /Users/<me>/Library/Developer/Xcode/DerivedData/Chisel-<stuff>/Build/Products/Debug-iphonesimulator/Chisel.framework/Chisel
 | 
在lldb环境下执行:
| 1
2
3
 | $ lldb
>>> expr -l objc -- (void*)dlopen("/path/to/Chisel.framework/Chisel", 2)
script o=lldb.SBExpressionOptions(); o.SetLanguage(lldb.eLanguageTypeObjC); o.SetTrapExceptions(False); o.SetTryAllThreads(False); o.SetTimeoutInMicroSeconds(10*1000000); lldb.frame.EvaluateExpression('(void)PrintInstances("<classname>", "<predicate>")', o)
 | 
<classname>:可以是class类名或protocol协议名
<predicate>:是一个可由NSPredicate解析的字符串
可以使用regex command 命令:
(注意,findinstance后面必须换行)
| 1
2
 | command regex findinstances
s/(\S+) *(.*)/script o=lldb.SBExpressionOptions(); o.SetLanguage(lldb.eLanguageTypeObjC); o.SetTrapExceptions(False); o.SetTryAllThreads(False); o.SetTimeoutInMicroSeconds(10*1000000); lldb.frame.EvaluateExpression('(void)PrintInstances("%1", "%2")', o)/
 | 
或者,作为python命令,存储在path/to/findinstances.py中:
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
 | import lldb
def findinstances(debugger, command, exe_ctx, result, _):
options = lldb.SBExpressionOptions()
options.SetTrapExceptions(False)
options.SetTryAllThreads(False)
options.SetTimeoutInMicroSeconds(10*1000000)
options.SetLanguage(lldb.eLanguageTypeObjC)
frame = exe_ctx.frame
if not exe_ctx.target.module['Chisel']:
frame.EvaluateExpression('(void*)dlopen("/path/to/Chisel.framework/Chisel", 2)', options)
args = command.split(' ', 1)
typeName = args[0]
predicate = args[1] if len(args) > 1 else ''
frame.EvaluateExpression('(void)PrintInstances("{}", "{}")'.format(typeName, predicate), options)
def __lldb_init_module(debugger, _):
debugger.HandleCommand('command script add -f findinstances.findinstances findinstances')
 | 
安装
Add Makefile for installing framework
This allows you to run make install with optional environment variables
in order to build and install Chisel.framework.
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
 | PREFIX ?= /usr/local/lib
export INSTALL_NAME =
ifneq ($(LD_DYLIB_INSTALL_NAME),)
    INSTALL_NAME = "LD_DYLIB_INSTALL_NAME=$(LD_DYLIB_INSTALL_NAME)"
endif
install:
    xcodebuild \
        -scheme Chisel \
        -configuration Release \
        -sdk iphonesimulator \
        install \
        $(INSTALL_NAME) \
        DSTROOT=/ \
        INSTALL_PATH="$(PREFIX)"
 |