一、概述
开发调试中,常常使用LLDB加快调试,更快速简单的定位到问题点。
下面是之前收集并且整理的常用命令 、插件和 使用技巧。
二、命令
关于命令的详细用法,使用help <command> <subcommand>
进行查看
2.0、关于~/.lldbinit
LLDB有了一个启动时加载的文件~/.lldbinit
,每次启动都会加载。
可以添加一些自定义命令,加载插件等等。
cat ~/.lldbinit
查看文件内容,包含以下信息:
command script import /path/to/fblldb.py
一般系统,在~/.lldbinit
默认导入facebook的fblldb.py
里面命令。
当然也可以自行安装相关插件。@import 导入第三方框架
,可以把基础框架放入到~/.lldbinit
文件中
例如@import Foundation/UIKit/CoreGraphics
等系统框架,否则lldb调试相关框架会报错,
2.1、打印命令
p
打印基础数据类型;打印对象时会返回对象指针地址。
p/x 变量名
打印变量的16进制(x 代表十六进制格式、t 代表二进制格式)
p/t
:二进制输出
p/c
:字符编码
p/x
:16进制输出查看对象内存分配
x
对象:对象内存情况
x/4gx
对象:按照四段16字节输出对象内存情况
x/8gx
对象:按照八段16字节po
打印对象的desc信息frame variable
打印exp
命令作用同p
命令
2.2、堆栈
bt
打印当前线程堆栈(backtrace的缩写)
bt all
打印所有线程的堆栈frame select 层数
跳转到某一层的堆栈
frame variable
查看当前堆栈的变量up
向上查看堆栈down
向下查看堆栈
2.3、线程
-
thread list
列出所有的线程 -
thread select 线程编号
切换线程 thread backtrace
-
thread backtrace all
打印所有线程的堆栈 -
thread return
各种原因,不想让代码执行某个方法,或者要直接返回一个想要的值。
2.4、表达式
-
e、expr、expression
执行表达式,常用的做法是,在不重新编译的情况下,给变量赋值。
如self.view.backgroundColor = [UIColor redColor];
2.5、关于image
(image
是LLDB给 target modules
取的别名 )
image list
列出当前执行的和依赖第三方的所有镜像image lookup -n 名字
查找项目中某个变量名、函数名等,包括第三方SDK或者静态库。
例如,用来查找同名的Category方法。image lookup --address 地址+偏移量
等价于image lookup -a 地址+偏移量
image lookup -v -a 地址+偏移量
查找完整的源代码行信息image lookup -type 类名
查看类的成员
2.6、断点
调试技巧:断点编辑,xcode中可以右键某个断点,可以进行断点编辑,可以设置某种条件下触发断点,实际开发中蛮实用。
2.6.1、breakpoint set
断点设置,其中breakpoint
可以缩写为b
-n 方法名
根据方法名给当前类设置断点。
也可以根据方法名给指定类多个方法设置断点,如下
breakpoint set -n "-[ViewController save:]" -n "-[ViewController continueGame:]" -n "-[ViewController pauseGame:]"
breakpoint set --selector 方法名
给整个项目某个指定方法设置断点-f
指定文件设定
breakpoint set -f ViewController.m -n viewDidAppear:
-l
指定某一行设置断点
breakpoint set -f ViewController.m -l 33
-a
给某个内存地址设置断点-c
设置条件断点
breadpoint set -n helloworld: -c flag==NO
-r
遍历整个项目中的所有方法,设置断点
例如breakpoint set -r Game:
为项目所有包含Game:
这个字符的所有方法,设置断点
2.6.2、breakpoint command 给断点设置一些命令
breakpoint command add
添加命令
例如,breakpoint command add -o "po self.view" 3
其中,-o
完整写法是–one-liner
,表示增加一条命令。3表示对id为3的breakpoint增加命令。breakpoint command list num
查看某个断点的所有命令breakpoint command delete num
删除某个断点的所有命令
2.6.3、其他
-
breakpoint list
查看断点列表 -
breakpoint disable/enable num
开启和禁止断点 -
breakpoint delete num
删除某个断点,没有入参则删除所有断点
2.7、watchpoint 内存断点
如果说breakpoint是对方法生效的断点,watchpoint就是对地址生效的断点。
想要知道某个属性什么时候被篡改了,我们该怎么办呢?就可以使用watchpoint。
2.7.1、设置
watchpoint set variable
设置变量
例如,watchpoint set variable self->name
不接受方法,因此以下命令无效watchpoint set variable self.name
,因为OC中点操作符调用setter和getter方法。watchpoint set expression address
观察某个地址
2.7.2、命令
-
watchpoint command add\delete\list
同breakpoint,断点设置命令
2.7.3、其他
-
watchpoint list
查看当前所有 -
watchpoint enable/disable num
开启和禁止断点 watchpoint delete num
2.8、流程控制语句
-
c
继续,continue -
n
next -
s
进入step in -
finish
完成
2.9、targets
2.9.1、modules
-
target modules lookup
访问一个或多个目标模块的信息
由于LLDB给target modules
取了个别名image
,所以这个命令我们又可以写成image lookup
。 如下
详见上面的image
命令
2.9.2、stop-hook
在breadpoint
和 watchpoint
断点停止的时候,去执行一些命令。
target stop-hook list
查看所有的hooktarget stop-hook add
添加的hook
使用-o
表示添加一条命令。target stop-hook delete num
删除指定编号的hook,没有入参num则表达式全部target stop-hook disable/enable num
开启和禁用hook,没有入参num则代表全部
2.9.3、target symbols add(add-dsym)
当我们对接framework的时候,如果只有framework代码,没有工程代码,能不能debug呢?其实我们只需要拿到工程的ipa和dSYM文件,就可以debug了,通过Attach to Process,使用命令add-dsym将dSYM文件加入target,即可只debug framework,不需要工程的代码
2.10、其他
call
调用方法,不打印值;p、po
也有该功能,并且会打印返回值disassemble
,缩写为dis
打印当前目标的汇编代码
使用例子demo
1、image list
读取app的image进程内存首地址
[ 0] 67EC1881-E7CC-38BC-A49E-D6FE5E755FB0 0x000000010ebe1000
2、memory read addr
addr-符号表的符号地址,可以通过mach-o查看。
addr = 第一步首地址 + mach-o的offset地址
0x10EBE9050 = 0x000000010ebe1000 + 0x00008048
- 相关内存命令:find、history、read、region、writer
3、dis -s addr
这一步的addr是上一步红框的倒叙(由于iOS是小端模式,内存地址8位倒着读)。
输出:HelloWorld/fxNSlog:
,其中 fxNSlog:
是用fishhook NSLog
的替换函数。
4、操作寄存器
register read/write
三、LLDB 和 Python
3.1、插件的原理
LLDB 有内建的,完整的 Python 支持。在LLDB中输入 script,会打开一个 Python REPL。
3.2、Chisel插件(facebook开源调试利器,原理同时)
常用的命令:
pviews self.view
递归打印所有的view,并能标示层级pvc
递归打印当前ViewController的层级visualize img_obj
使用Mac的预览打开一个 UIImage, CGImageRef, UIView, 或 CALayer。fv & fvc var
通过类名搜索当前内存中存在的view和viewController实例的命令,支持正则搜索。show/hide
无需重新编译,直接显示和隐藏view或者layercaflush
重新渲染绘制界面,相当于执行了[CATransaction flush]
方法
注意如果在动画过程中执行这个命令,就直接渲染出动画结束的效果。
在调试界面颜色、坐标之类的时候,可以直接在控制台修改属性,然后caflush就可以看到效果啦。mask/umask 和 border/unborder
这两组命令用来标识一个view或layer的位置时用。
mask用来在view上覆盖一个半透明的矩形, border可以给view添加边框。presponder self.view
打印响应者链
** 更多好用的用法,请参考help命令,值得你深入研究。 **
四、XCode调试
- 显示汇编相关,
Debug -> Debug Wokflow -> Always Show Disassembly
则会显示汇编信息。
例子:在NSLog
打断点,如下
NSString *str = @"helloworld";
id __weak objc = str;
NSLog(@"%@", objc);
参考
LLDB调试小节
objc.io#19#与调试器共舞 - LLDB 的华尔兹
iOS中教你快速掌握LLDB调试技巧
Chisel-LLDB命令插件,让调试更Easy