译者注:原文利用的是xcode6.3.2,我翻译的时候,利用的是xcode7.2.1,经由验证,本部分中说的依然是有效的.在文中你可以学习到一系列的技能,非常值得一看.这些技能不单单只是用来创建插件,对你平时的调试等,也有非常大的帮助.
欢迎你来到创建xcode插件教程的第二部分.在第一部分中,你已经理解了怎么通过NSNotification来窥伺xcode的内部类,并且代码注入了其私有类DVTBezelAlertPanel,并且,你还添加了一个NSMenuItem菜单到xcode的菜单栏里,通过它来持久化是否开启我们自定义的插件Rayrolling的功能
在这个教程中,你会在第一部分中创建的Rayrolling的根本上连续向前,如果你并没有在这之前阅读第一部分或者你想从本处开始,你可以下载第一部分完成的demo.本章中,你将会通过深入理解一些可用的工具来进一步探索Xcode,利用你将会学到的新知识,来修正Xcode的标题栏,使标题栏改为展示Ray的某首歌的歌词。
开始啦
打开Xcode和Terminal(终端),并且将它俩都平铺在桌面上,这样你可以同时看到它们,方便后续的操作.(yohunl注:后文将会一壁在Xcode上点击,一壁不雅观察终端掌握台的输出,一旦创造我们须要的输出,就要立马停滞终端掌握台,以是,平铺在桌面上才便于你操作,否则,你就忙不过来啦)
由于从上一章,你已经学会了从xcode运行一个xcode实例来创建插件和调试插件,以是我们换一种新的办法:你将会直接通过终端命令来利用LLDB来探索Xcode,你不用再像第一部分那样从一个Xcode启动另一个调试用的Xcode实例来探索Xcode是若何事情的了.
LLDB的BFF和DTrace
DTrace是最好的探索Xcode的工具之一,它是一款相称精良的调试工具,它是Instruments的基石.只要你理解怎么利用它,你将会创造它是非常有用的工具.
首先,为了对其有个理解,我们须要一个利用DTrace的demo,就犹如我们学习一门新措辞时候,总是会通过一个Hello Worlddemo一样.那么开始吧… 创建一个脚本,它是用来保持所有以IDE开头的类的运行计数,并在每次你调用该特定类方法或者实例方法时,增加计数.在你退出脚本时候,DTrace将会转储这些数据.
运行Xcode,然后,在Terminal的一个新窗口中,输入如下的脚本:
sudodtrace-n'objc$target:IDE::entry{@[probemod]=count;}'-p`pgrep-xoXcode`
虽然你键入命令后并不会看到任何的输出,但是DTrace已经在后台默默的天生了所有方法调用的踪迹(trace).回到Xcode,随便考试测验一些操作.打开某些文件,随便做一些点击操作.回到Terminal,然后按Ctrl+C来结束脚本,脚本产生的内容将会输出到Terminal上 (只有在你Ctrl + C终止脚本后,才能在Terminal上看到脚本输出的内容)
相称酷吧:),实在利用Dtrace,你可以做到很多事,但是我们的教程不会覆盖你想理解的DTrace的全部,相反的,我们供应一个快速的Dtrace语法的概述,它将会帮助你开始:
1.Probe Description(探头解释,前序描述):由供应者(Provider),模块(Module),功能(Function),名字(Name)组成,它们由冒号分隔.省略它们中的任何一个,将会使Probe Description包含所有的匹配项.你可以利用 和 ? 操作符来做模式匹配.
Provider:这个包含了一系列的类和方法,例如profile,fbt,或者io.在我们的教程中,紧张利用objc来hookObjective-C的方法调用.
Module:在OC措辞中,这部分指示的是你希望不雅观察的指定的类名
Function:指示你希望不雅观察的特定方法名
Name:虽然根据你的Provider的不同,有不同的name值可选,但是你在此只须要利用entry或者retrun,来匹配函数的开始或者结束.
你要理解,你可以利用$target关键字来匹配进程ID,也可以利用p或者c标志来指定target.
2.Predicate(谓词部分): 可选的表达式,它是用来过滤哪些动作是知足条件的.你可以把它当做一个if语句的条件部分.
3.Action(动作): 将要实行的操作.它可以只是大略的输出一些内容到掌握台,也可以是实行一个高等功能.
就犹如LLDB的命令image lookup -rn {Regex Query}一样,你也可以利用l标志来转储(dump)特定进程中的类和方法.
为了演示这点,我们来看这样一个大略的例子,运行Safari,然后在终端输入以下脚本
sudodtrace-ln'objc$target::-ecret:entry'-p`pgrep-xnSafari`
上述的DTrace脚本会打印出所有的名字中包含ecret字符串的实例方法.由于Probe Description部分 供应了Name参数entry,所有的方法都有entry和return,以是基本上忽略了所有的重复查询要求.
把稳:如果你想节制更多的Dtarce知识,你可以参考Big Nerd的文章和 这本Dtrace书本.如果并没有理解所有的这篇快速先容中先容的内容,也不须要沮丧,由于Dtrace是一个相称繁芜的工具.
现在你理解到Dtace的最基本的内容,我们可以开始利用它来探求我们感兴趣的NSViews了.由于Xcode含有大量的Views,你会创造,利用LLDB来试图找出它们,让你不堪重负.纵然结合LLDB的条件断点,调试一些运用程序都包含的共同东西,也是一个丑陋的过程.
幸运的是,利用Dtrace,将能带给你对付此类问题的巨大的帮助.你将会利用DTrace来找出Xcode中组成标题栏的视图(NSViews).(⊙o⊙)…….那么该怎么做呢?
这是一种方法:当鼠标停滞在,或者点击一个NSView,hitTest:方法将会被触发,这个方法将会返回在这个鼠标点下最深的子视图.你可以利用DTrace来顺着hitTest:方法来确定视图,那个你该当进一步探索其其父视图和子视图的视图.
在终端中输入以下脚本:
sudodtrace-qn'objc$target:NSView:-hitTest?:return/arg1!=0/{printf(\"大众UIView:0x%x\n\"大众,arg1);}'-p`pgrep-xoXcode`
一旦这段脚本运行,请确定你的Xcode是第一相应者(通过在Xcode上任何地方点击一下即可成为第一相应者).在Xcode的窗口上移动你的鼠标指针,当你停滞移动鼠标指针的时候,Dtrace将会输出一个内存地址多次,这是由于 hitTest: 被在视图层次上的多个视图调用.
定位到Xcode的标题栏,点击标题栏.选择涌如今终端中最近的地址,拷贝到你的粘贴板中
打开一个新的终端窗口标签,运行LLDB,并将其附着到Xcode上,然后输出从DTrace中拷贝出的地址,像以下这样操作:
>lldb(lldb)proattach-nXcode...(lldb)po{上一步拷贝到粘贴板中的工具地址,例如是0x7fcc2687cd40,则该命令是po0x7fcc2687cd40}...
个中,pro 是 progress的缩写,LLDB利用的是前序匹配原则,在不引起歧义的情形下 process,proc,proce都是可以的.不才面你还会看到 pro at -n Xcode这种写法,都是由于这个原则,都是等效的. pro attach -n Xcode ,利用attach命令直接在LLDB中把一个正在运行的进程连接到LLDB中,以便于进行动态调试.也便是说这个命令直接可以将LLDB添加到任意的其它不是由它自己创建的进程中!!
你将会看到和以下相似的输出:
把稳:现在,Xcode被我们通过终端输入的LLDB命令所停息了.你可以在任何时候通过输入process interrupt或者其缩写pro i来停息Xcode,从而能够开始调试Xcode.其余,你也可以通过在任何时候输入continue或者缩写c来规复Xcode的运行.请确定你总是理解附着于Xcode上的LLDB的状态,你可以认为,当Xcode被你的调试LLDB所停息时候,它是不能够相应你的单击等操作的(犹如你在Xcode中打了断点,调试的时候进入到断点一样)
取决于你在Xcode中点击的地方,你可能会命中一系列的视图.探索这些内存地址的父视图(通过在lldb中 po [工具地址 supview])或者子视图(po [工具地址 subvies]),直到你得到了视图 IDEActivityView.
一旦你找到了IDEActivityView,若何确定这个视图便是你所希望找寻的视图呢?
通过在LLDB中输入以下命令:
(lldb)po[{找到的IDEActivityView实例的地址}setHidden:YES]在我的机子上是po[0x7fcc2686b3c0setHidden:YES]...这里的点表示我们省略了lldb的某些不主要的输出.(lldb)c...
如果是我们所期望的那个标题视图,那么现在Xcode的标题栏就被隐蔽了,这就能证明它的确是我们所期望的标题栏的视图啦.
通过如下命令来重新显示它:
(lldb)proi(lldb)po[{找到的IDEActivityView实例的地址}setHidden:NO]比如在我的机子上是po[0x7fcc2686b3c0setHidden:NO](lldb)c
以下这个图是上述在LLDB中输入命令的gif动画,供你参考:
按照以往的履历,你知道,当你Build或者Stop一个Xcode工程的时候,标题栏视图的内容将会变革.你可以用DTrace来不雅观察干系的函数.IDEActivity前缀是一个独特的命名约定,你可以不雅观察所有的以IDEActivity开头的类,以此来不雅观察在这幕后的所有相联系的事情.
回到终端,通过Control + C来停滞DTrace,然后输入以下命令到终端中:
sudodtrace-qn'objc$target:IDEActivity::entry{printf(\公众%c[%s%s]\n\"大众,probefunc[0],probemod,(string)&probefunc[1]);@num[probemod]=count;}'-p`pgrep-xnXcode`
这段脚本将会输出所有类名前缀是IDEActivity的所有方法调用.一旦你停滞这个脚本命令(Control+C),它还会输出指定类方法的被调用次数.
yohunl备注: 当你输入这个命令的时候,可能会碰着译者碰着的这种情形
yohunldeMacBook-Pro:~ yohunl$ sudo dtrace -qn 'objc$target:IDEActivity::entry { printf(\"大众%c[%s %s]\n\"大众, probefunc[0], probemod, (string)&probefunc[1]); @num[probemod] = count; }' -p `pgrep -xn Xcode`
dtrace: invalid probe specifier objc$target:IDEActivity::entry { printf(\"大众%c[%s %s]\n\"大众, probefunc[0], probemod, (string)&probefunc[1]); @num[probemod] = count; }: probe description objc50360:IDEActivity::entry does not match any probes
当碰着这种情形不要担心,不要茫然,你只要完备退出Xcode,再重新启动Xcode,再输入这个命令就好了.
开始这个DTrace命令,回到Xcode中,随便打开一个工程,编译并运行,然后再停滞.把稳不雅观察Xcode的标题栏的内容变革,然后停滞Dtrace命令,查当作果:
仔细剖析上面输出的信息.IDEActivityView和其它类之间是怎么运转的都在掌握台的输出信息中,但是也有大量的其它信息夹杂在个中(掌握台的输出信息中),不是么?
幸运的是,你可以有选择的限定展示给你的信息量.通过浏览干系的类,来确定是否有值得你进一步选择性探索的内容….,大概 IDEActivityReport 便是一个不错的候选类,由于以它开头的类看起来便是有联系的(在我们上述的操作中,末了在DTrace看到的很多都是它,以是我们有情由以为它便是有联系的).
修正Dtrace脚本,使他看起来如下:
sudodtrace-qn'objc$target:IDEActivityReport::entry{printf(\"大众%c[%s%s]\n\"大众,probefunc[0],probemod,(string)&probefunc[1]);@num[probemod]=count;}'-p`pgrep-xnXcode`
再运行,停滞Xcode的动作的同时,密切关注掌握台的输出信息.一旦停滞Xcode,立马Control+C停滞掉Dtrace的脚本,是否涌现了一些类,看起来是值得我们进一步去探索的呢?
IDEActivityReportStringSegment看起来比较值得探索.缩个人们的脚本的搜索范围,聚焦到这个类上来,把稳以下命令的变革,把稳Probe的Function部分的变革(我们上面剖析了Dtrace命令的组成,个中Probe部分有个Function组成部分)
sudodtrace-qn'objc$target:IDEActivityReportStringSegment::entry{printf(\"大众%c[%s%s]\n\"大众,probefunc[0],probemod,(string)&probefunc[1]);@num[probefunc]=count;}'-p`pgrep-xnXcode`
通过编译,运行,停滞Xcode工程;再一次停滞Dtrace命令,不雅观察IDEActivityReportStringSegment类的实例的方法各自被调用的次数(当Control+C停滞命令后,在掌握台会输出各个方法的调用次数).看起来,initWithString:priority:frontSeparator:backSeparator: 和 initWithString:priority:值得进一步剖析!
打开一个新的LLDB会话(打开一个终端标签页面,lldb进入LLDB),然后再运行如下命令:
(lldb)proattach-nXcode(lldb)rb'IDEActivityReportStringSegment\initWithString'Breakpoint9:2locations.(lldb)brcommandaddEnteryourdebuggercommand(s).Type'DONE'toend.>poNSLog(@\"大众customidentifier%s%@\"大众,$rsi,$rdx)>c>DONE(lldb)c
在上面这段命令中,你添加了自定义的命令,当任何属于IDEActivityReportStringSegment类的以initWithString方法开头的方法被调用时,就会实行添加的自定义命令.它输出IDEActivityReportStringSegment实例的方法的 Selector 和 self (还记得教程一中提到的各个寄存器中存放的内容了吧)到掌握台.
其余,利用了customidentifier 来标识 NSLog的输出信息,这样你可以更随意马虎的从掌握台的输出中随意马虎的定位到这些Log.
回到终端,新建一个终端tab(利用快捷键 command+ t ),建立一个customidentifier的grep尾搜索:
tail-f/var/log/system.log|grepcustomidentifier
译者注,这句话输入后,并没有输出,当你切换到Xcode中,编译,运行,就产生输出了
编译,运行Xcode,以便让Xcode产生IDEActivityReportStringSegment变革.下面的gif动画,显示了上面所说的所有你输入到LLDB中的命令,看起来如下:
比较掌握台的输出和Xcode的标题栏的输出,你可以明确的得到:它便是你要探求的内容!!
到利用Swizzle的时候了
创建一个Objective-C的类NSObject的category,命名为Rayrolling IDEActivityReportStringSegment
添加下面的代码到建立的文件 NSObject+Rayrolling_IDEActivityReportStringSegment.m:中:
#import\公众NSObject+Rayrolling_IDEActivityReportStringSegment.h\"大众#import\"大众NSObject+MethodSwizzler.h\公众#import\"大众Rayrolling.h\公众@interfaceNSObject//1-(id)initWithString:(id)arg1priority:(double)arg2frontSeparator:(id)arg3backSeparator:(id)arg4;@end@implementationNSObject(Rayrolling_IDEActivityReportStringSegment)//2+(void)load{staticdispatch_once_tonceToken;dispatch_once(&onceToken,^{[NSClassFromString(@\公众IDEActivityReportStringSegment\公众)swizzleWithOriginalSelector:@selector(initWithString:priority:frontSeparator:backSeparator:)swizzledSelector:@selector(Rayrolling_initWithString:priority:frontSeparator:backSeparator:)isClassMethod:NO];});}-(id)Rayrolling_initWithString:(NSString)stringpriority:(double)priorityfrontSeparator:(id)frontSeparatorbackSeparator:(id)backSeparator{//3staticNSArraylyrics;//4staticNSIntegerindex=0;staticdispatch_once_tonceToken;//5dispatch_once(&onceToken,^{lyrics=@[@\"大众Nevergonnaliveyouup.\"大众,@\"大众Nevergonnasetyoudown.\公众];});//6index=index>=lyrics.count-1?0:index+1;//7if([RayrollingisEnabled]){return[selfRayrolling_initWithString:lyrics[index]priority:priorityfrontSeparator:frontSeparatorbackSeparator:backSeparator];}return[selfRayrolling_initWithString:stringpriority:priorityfrontSeparator:frontSeparatorbackSeparator:backSeparator];}@end
下面是对上面代码的一些阐明:
你须要前向声明私有类的初始化方法initWithString:priority:frontSeparator:backSeparator:,否则编译器直接就让你通过不了.
load是常日被用来初始化添加swizzle代码的地方.
由于你利用一个category来交流方法,在category中建立实例变量是轻微有些繁芜的.你可以通过associated objects给一个已存在的类添加实例变量,但这个是你自己该当节制的内容.在这里,我们直策应用一个static NSArray来保持一个工具连续存在,纵然它所在的方法已经实行完毕了.
您可以利用相同的static伎俩,使得index也如此。
利用dispatch_once初始化歌词NSArray
递增index,如果越界了,就重置它
检测插件是否是可用状态,如果是,那就变动string参数,否则,利用默认的参数
正如你所看到的,利用精确的工具可以帮助你快速定位你想要的东西.然而,要达到这个目的,却有不止一种方法 - 你将会创造,通过堆(heap)剖析还是可以定位到你所感兴趣的内容
通过堆(heap)来重新探求IDEActivityView
在本节中,你将会重新征采Xcode的IDEActivityView和IDEActivityReportStringSegment,你将会利用一种略微不同的办法来达到这一目的.
到目前为止,你都是通过自上而下的办法来进行定位的:你先找到一个可能的class,然后以某种办法在内存中探求它的一个实例工具,再查找它的成员方法和属性.实在,以相反的方向来进行,彷佛也是可行的,便是沿着参考链从下而上去探求目标工具,直到找到它.
很幸运,Xcode中附带了一些Python脚本,让你能够做到这点!
结束掉终端中所有的已存在的LLDB和Dtrace的会话,然后重启Xcode.开始一个新的Xcode和LLDB会话,再一次实行LLDB附着到Xcode上的命令,然后,添加下面的命令脚本:
(lldb)proat-nXcode(lldb)commandscriptimportlldb.macosx.heap\公众malloc_info\"大众,\"大众ptr_refs\"大众,\公众cstr_refs\"大众,and\"大众objc_refs\"大众commandshavebeeninstalled,usethe\"大众--help\"大众optionsonthesecommandsfordetailedhelp.
这个脚本加载了一系列非常有用的方法到LLDB进程中.
malloc_info: 展示当前堆得工具的详细信息.尤其是结合MallocStackLogging环境变量的时候及其有用!
ptr_refs: 给它一个堆空间中的一个内存地址,它可以找到指向这个内存地址的其它工具.
cstr_refs: 参数类型是char ,查找它在内存中涌现的地方.
objc_refs: 找到内存中指定的类的实例
你可能想先理解理解最随意马虎的objc_refs.
在LLDB中,通过以下脚本来找寻所有的IDEActivityView类的实例变量:
(lldb)objc_refs-oIDEActivityViewSearchingforallinstancesofclassesorsubclassesof\"大众IDEActivityView\"大众(isa=0x10fffe650)0x00007faaee9cbf30:malloc(304)->0x7faaee9cbf30IDEActivityView.DVTLayerHostingView.NSView.NSResponder.NSObject.isa[IDEActivityView:0x7faaee9cbf30](因识别问题,这里将尖括号更换为方括号)
这个脚本输出了内存中所有的IDEActivityView类的实例.个中的 -o 参数表示输出工具,也便是会调用工具的 description 方法
通过这个大略地额脚本,你就可以在内存中找属于指定类的的实例工具.这招也适用于继续于该工具的子类.
yohunl备注:很遗憾,在我电脑上,这句怎么都查询不到
(lldb)objc_refs-oIDEActivityViewerror:libarclite_macosx.a(arclite.o)failedtoloadobjfilefor/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_macosx.aerror:libarclite_macosx.a(arclite.o)failedtoloadobjfilefor/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_macosx.aSearchingforallinstancesofclassesorsubclassesof\"大众IDEActivityView\"大众(isa=0x10ada9328)
试了很多次,都没能得到所期望的东西,但我相信这个方法是可以的
通过上一步 objc_refs创造的内存地址,你可以采取如下的脚本来展开一个IDEActivityView实例的成员变量:
(lldb)malloc_info-t0x7faaee9cbf300x00007faaee9cbf30:malloc(304)->0x7faaee9cbf30IDEActivityView.DVTLayerHostingView.NSView.NSResponder.NSObject.isa(IDEActivityView)addr={DVTLayerHostingView={NSView={NSResponder={...
这还不是它能做到的全部!你乃至可以用它,通过指定的内存地址来得到其它工具的引用:
(lldb)ptr_refs0x7faaee9cbf300x00007faaeed9a308:malloc(16)->0x7faaeed9a300+80x00007faaeedb4148:malloc(176)->0x7faaeedb4140+8IDEActivityViewBackgroundButton.NSButton.NSControl.NSView.NSResponder._nextResponder0x00007faaeedb4190:malloc(176)->0x7faaeedb4140+80IDEActivityViewBackgroundButton.NSButton.NSControl._aux.NSObject.isa0x00007faaeedb4928:malloc(160)->0x7faaeedb4920+8NSView.NSResponder._nextResponder...
把稳:这些命令,如果结合 im loo -rn {classmethod regex} 办法来查询,乃至可以帮助你快速的定位到,并且探查到在内存中存活的该类的所有实例.当然了,考试测验之前,请确定你的LLDB还是停息状态,否则的话,这些命令是不会起浸染的.
你设置可以更进一步,有一个环境变量MallocStackLogging,它可以在你初始化任何一个工具的时候用于栈(stack)回溯.虽然很多引用都可以指向同一个工具,但是它可以指出来,哪个才是这个工具的”终极拥有者”. 这段还要再剖析一下
由于上文的LLDB已经附着(attach)在xcode上,以是你要先杀掉Xcode进程,再通过带上MallocStackLogging环境参数的LLDB来重启它:
(lldb)prokillProcess65196exitedwithstatus=9(0x00000009)(lldb)prolaunch-vMallocStackLogging=1-nProcess67920launched:'/Applications/Xcode.app/Contents/MacOS/Xcode'(x86_64)
把稳:如果你比较
launchctlsetenvMallocStackLogging1
这个命令将通过launch创建的每一个进程的MallocStackLogging都设置成了true.以是你要记得,通过如下的命令来移除它们:
launchctlunsetenvMallocStackLogging
为了测试上面的内容,首先,确保你的Xcode的Edit菜单下的菜单项是 如下图所示的 Enable Rayrolling :
现在,打开任何一个Xcode工程,担保源码编辑窗口是打开的,编译,运行工程.伴随着工程的运行,你将会看到在编译完成和运行完成的时候,IDEActivityView(假装你不知道此时此刻,谁调用它)改变它的内容.
停息实行这个Xcode工程,如果须要,利用下面的命令来重新加载LLDB的heap(堆)方法集:
(lldb)proi(lldb)commandscriptimportlldb.macosx.heap\"大众malloc_info\"大众,\"大众ptr_refs\"大众,\"大众cstr_refs\"大众,and\"大众objc_refs\"大众commandshavebeeninstalled,usethe\"大众--help\"大众optionsonthesecommandsfordetailedhelp.
提醒:如果你对多次输入这个命令感到厌烦,你可以去网上理解下怎么在 ~/.lldbinit 方法中建立 command aliases (命令的别名,或者缩写).这个在 ~/.lldbinit 文件的内容,在每次创建一个LLDB的会话实例的时候,都会被加载.
现在,利用cstr_ref方法,给它通报Xcode标题栏的字符串内容.举个例子,如果这个工程的名字叫Rayrolling,那么你的Xcode的标题栏上显示的该当是诸如:”Running Rayrolling : Rayrolling:”此类的字符串:
(lldb)cstr_ref\"大众RunningRayrolling:Rayrolling\公众0x0000000118cb21d0:malloc(32)->0x118cb21d00x000000012079ae21:malloc(48)->0x12079ae10+17__NSCFString1bytesafter__NSCFString0x00000001207a3bb3:malloc(64)->0x1207a3b90+35__NSCFString19bytesafter__NSCFString0x00000001223834d1:malloc(48)->0x1223834c0+17__NSCFString1bytesafter__NSCFString0x000000011f9126a1:malloc(48)->0x11f912690+17__NSCFString1bytesafter__NSCFString
正如你所看到的那样,紧张的参考信息一样平常都是 NSString类型的参考,多数情形下,你并不能从字符串本身得到更多的信息.以是你可能想理解这样字符串是若何被创建的?由于有MallocStackLogging,做到这点,相称随意马虎!
(lldb)cstr_ref\公众RunningRayrolling:Rayrolling\"大众-s
这个脚本输出堆栈帧的信息,当这个char 被创建的时候.
通过所有的堆栈信息去跟踪实例变量,由于他们都是在内存中,内存地址的数量和其在内存中的相对位置都有可能不同,这些都取决于你和Xcode的互动办法的不同而不同.
通过阅读剖析堆栈的跟踪信息,你将会得到一组类,这些类便是卖力Xcode中这方面的.
举例来说,取决于你运行的这些LLDB查询命令,你可能会看到这些class,如: IDEActivityScrollingTextLayer , IDERunOperation , IDEActivityView 等等诸如此类的class.
你还可以利用 ptr_ref 来浸染于 cstr_ref 输出的信息,来看那些工具保留了这个string工具的引用.
繁杂的随机探索技巧
在Xcode中探求精确的api是很繁芜的,由于你是想在成千上万的类和方法中探求符合条件的几个类而已.
利用LLDB的正则表达式,可以帮助你更好的找到它们.某些时候,最好的获取信息的地方是代码中利用的单例(Singleton),查看Xcode中存在的单例,看看是否值得进一步深入的单例.
当LLDB附着到Xcode,并且处于停息状态时候,输入以下命令:
(lldb)iloo-rn\"大众\+\[IDE.\shared\公众
这条命令将会查找以IDE开头的类名,并且以”shared”开头的类方法.这条命令等价于 target modules lookup -rn \公众\+\[IDE.\ shared\公众,-r是指后面的是正则表达式
其余一个吸引力的替代方案是:
(lldb)iloo-rn\"大众\+\[[A-Za-z]\[A-Za-z]\]\"大众
它将会输出所有的没有参数的类方法.
正如你前面看到的,你可以很随意马虎的找出你刚兴趣的类,通过给一个名字给上面提到的Python脚本,就可以搜索到.其余还有一个盛行的工具,可以用来搜索类和类方法,这个工具的名字叫class-dump,它可以在 这里下载.它是LLDB命令im loo -rn {regex} 的另一种替代办法,由于它(Class-dump)可以输出更加整洁,清晰的头文件形式的输出.
当然了,class-dump也有小缺陷,它的缺陷便是你必须限定你的搜索在指定的framework或者plugin中,而LLDB的image lookup 命令搜索的是全体的Xcode进程中的framework和plugin!也便是image lookup的搜索范围更大,更广.
下一步该做什么?
这里是第二部分末了完成的domo工程.
在这个教程中,你学习到了最基本的DTrace技能,并且学习和利用了一些你可以得到的高等LLDB方法.
如果你想理解更多的关于DTrace的知识,你可以阅读另一篇obcj.io上的精良文章,还有便是官方的 DTrace文档
在本系列教程的第三部分,我们将再一次关注 汇编,你将会学到另一种机动的工具,它的名字叫 Cycript.