
lldb的Xcode默认的调试器,它与LLVM编译器一起,带给我们更丰富的流程控制和数据检测的调试功能。平时用Xcode运行程序,实际走的都是lldb。熟练使用lldb,可以让你debug事半功倍
-
lldb 用法
首先在应用程序内打断点。
接下来一个一个的去介绍和使用。 -
apropos :调试器命令列表相关的词或主题
语法:apropos <search-word>
作用:输出你想要搜索的关键词的相关内容。
例子:apropos log
结果:apropos.png
-
breakpoint :命令操作断点
语法:breakpoint <subcommand> [<command-options>]
作用:可以通过命令来对断点进行增加、删除等操作。
一些子命令如下:
1、clear:删除或禁用断点匹配指定的源文件和行。
2、command:命令添加,删除和清单LLDB命令在遇到断点时执行。
3、delete:删除指定的断点(s)。如果没有断点指定,删除它们。
4、disable:禁用指定断点(s),而不删除它们。如果没有指定,禁用所有断点。
5、enable:使指定的禁用断点(s)。如果没有断点指定,使所有的人。
6、list:列举一些或所有断点配置的详细级别。
7、modify:修改选项断点或设置的断点可执行文件。如果没有指定断点,作用于最后创建断点。
8、name:命令来管理断点的名字标签
9、set:设置一个断点或设置断点的可执行文件。
例子:通过 breakpoint 来添加、删除以及查找断点。
查看当前断点列表

红色框框里面表示断点的行数。可以看出来现在也就只有2个断点,一个在73行,一个在80行。
- 添加一个95行的断点
breakpoint set -f ViewController.m -l 95
-f 后面的是文件名 -l 后面是行数
- 再次查看当前断点列表

- 删除 80 行的断点
breakpoint clear -f ViewController.m -l 80
- 结果列表中就没有 80 行的断点信息了。

-
bugreport :命令来创建特定于域的bug报告
语法:bugreport <subcommand> [<subcommand-options>]
作用:创建一份 bug 报告
例子:
bug report unwind XXX(XXX 是你想看的方法名)
结果会输出一堆东西。you can try! -
command :管理自定义命令LLDB命令(创建别名)
语法:command <subcommand> [<subcommand-options>]
一些子命令:
1、alias:定义一个自定义命令
2、delete:删除一个或多个自定义命令的命令
3、history:当前执行的历史命令
4、regex:定义一个现有命令的自定义命令
5、script:来管理自定义命令实现的脚本解释器
6、source:从文件读取和执行命令LLDB
7、unalias:删除一个或多个自定义命令定义为“命令别名”
例子:
想知道你执行 LLDB 几条命令,输入
command history
还有个实用的例子:
比如上面的添加断点命令过长,那么我们可以这样做。
command alias bkt breakpoint set -f %1 -l %2
然后再添加断点。
bkt ViewController.m 90
你看结果会发现已经添加上了,是不是很方便?
别名添加断点.png
如果不想要这个别名了就可以执行下列命令把它给删除。
command unaries but -
disassemble :拆卸指定的指令
语法:disassemble [<cmd-options>]
例子:
disassemble -b
这样会显示你当前断点所在的方法内所有的操作码字节。
效果:
操作码字节.png
红色框内的信息能更好的帮助你调试程序。
如果你想拆卸某一行可以用下面的命令:
disassemble -c 84(这个数字就是你想要拆卸的行数,当然了他会联系上下文给你拆卸这个对象的信息) -
expression (我用到的: 修改程序中的代码)
场景:假设你程序运行后发现有个视图的背景颜色不好看,需要改,好吧,在代码中改一下,再运行。发现不好看,再改。这样太过麻烦,但是我们可以用 expression 来实现,代码:
expression imageView.backgroundColor = [UIColor redColor]
然后再运行你就会发现这个视图的颜色变成红色了。不止颜色,一些数值也是可以改的。 -
frame 命令选择与当前线程的堆栈帧
子命令:
1、info:列表当前堆栈帧在当前的信息线程
2、select:选择当前堆栈框架内通过索引当前线程
3、variable:显示变量当前堆栈帧。默认为所有参数和局部变量的范围
效果:
frame效果图.png
1中,箭头表示的是你断点所在的位置
后面的就是你所写的代码
2中,有你当前所在的类的名字,所在方法的方法名以及一些创建的对象
3中,就是列举方法名,行数,类名等信息。
根据自己的喜好选择相应的命令。 -
quit 退出当前的LLDB。
-
register 访问当前线程的寄存器和堆栈帧
子命令:
1、read:读取当前的寄存器值当前帧
2、write:修改一个寄存器值 -
settings 管理 LLDB 的设置
子命令:
1、append:将值附加到调试器里面。数组、字典或者字符串设置。
2、clear:清除调试器
3、insert-after:在指定的元素的索引,将一个或多个值插入一系列调试器设置
4、insert-before:在指定的元素的索引,立刻将一个或多个值插入一系列调试器设置
5、list:调试器列表
6、remove:移除设置
7、replace:替换设置中的值
8、set:设置指定的调试器的设置值
9、show:显示调试器设置和他们目前的值。 -
source 检查源代码所描述的调试信息当前目标的过程
子命令:
1、info:显示一行信息来源为当前目标的过程。默认为当前堆栈帧中指令指针
2、list:显示指定的当前目标过程的源代码 -
thread 操作在一个或多个线程在当前过程
子命令:
1、backtrace:显示线程调用堆栈。默认为当前可以指定线程,线程索引作为参数。使用thread-index看到所有线程。
2、continue:继续执行当前目标的过程。
3、info:显示一个扩展的总结一个或多个线程。
4、jump:将程序计数器设置为一个新的地址。
5、list:显示每个线程在当前目标的总结的过程。
6、plan:管理线程控制计划执行。
7、return:返回从堆栈帧,短路执行更新的框架和选择屈服指定的值。
8、select:更改当前选中的线程。
9、step-in:进入调用
10、step-init:单步调用
11、step-ints-over:单步,跨过调用。
12、step-out:执行完当前堆栈帧并停止之后返回。
13、step-over:单步,跨过调用。
14、step-scripted:C中选择的脚本类。
15、until:到达到行号或地址当前或指定的线程,停止时返回从当前函数作为一种安全措施。
例子:
thread info
当前线程的信息.png
-
type 命令操作的类型系统
子命令:- 1️⃣、category:操作类型分类
- define:定义一个新的类别
- delete:删除一个类别
- disable:禁用一个类别
- enable:启用一个类别
- list:现有的类别的列表
- 2️⃣、filter:操作类型过滤器
- add:添加一个新的过滤器的类型
- clear:删除所有现有的过滤器
- delete:删除现有的滤波器类型
- list:显示当前过滤器的列表
- 3️⃣、format:自定义值显示格式
- add:添加一个新的格式类型
- clear:删除所有现有的格式样式
- delete:删除现有的格式风格类型
- info:评估提供的表达式和显示格式应用于结果值
- list:显示当前的列表格式
- 4️⃣、lookup:当前查找类型和声明
- 5️⃣、summary:编辑变量汇总
- add:添加一个新的汇总的风格类型
- clear:删除所有现有的总结
- delete:删除现有的一种总结类型
- info:评估提供的表达式和显示总结应用结果值
- list:显示当前的列表格式
- 6️⃣、synthetic:操作合成类型
- add:添加一个新类型合成提供者
- clear:删除所有的类型
- delete:删除现有的一种合成类型
- info:评估提供的表达式和显示总结应用结果值
- list:显示当前的列表格式
- 1️⃣、category:操作类型分类
-
version 显示调试器LLDB版本
-
watchpoint 操作检查点,检查内存的读写。
- 1️⃣、command:添加,删除和检查LLDB命令当监视点
- add:添加一组命令LLDB监视点
- delete:删除监视点
- list:监视点成功的列表
- 2️⃣、delete:删除指定的监视点
- 3️⃣、disable:禁用指定的监视点,而不删除它
- 4️⃣、enable:使指定的禁用的监视点
- 5️⃣、ignore:设置忽略依靠指定的监视点
- 6️⃣、list:列出所有监测点配置的表
- 7️⃣、modify:在监视点或者设置监测点上修改可执行文件,如果没有指定监视点,就传递一个空参数做修改。
- 8️⃣、set:设置监视点
例子:
创建一个监视点
watchpoint set expression -- a(这个a 在代码中是 int a = 0;)
会输出这样的信息
Watchpoint created: Watchpoint 1: addr = 0x00000000 size = 8 state = enabled type = w
分别为:监视点的代号,内存地址,大小,状态和类型。
再添加个对这个 a 的读写检测
watchpoint set variable -w read_write a
则会输出
- 1️⃣、command:添加,删除和检查LLDB命令当监视点
Watchpoint created: Watchpoint 3: addr = 0x7fff54ed67c4 size = 4 state = enabled type = rw
declare @ '/Users/XXX/Desktop/Demozz/Demozz/ViewController.m:89'
watchpoint spec = 'a'
new value: 0
比上面的输出相比,多了以下几点改变
1、监视点的代号、内存地址、大小、类型都变了。
2、增加了declare(状态声明)
3、增加了监视点的规范
4、增加了输出这个检查的变量的值。
那我们打印一些监视点的列表
watchpoint list
则输出
Number of supported hardware watchpoints: 4
Current watchpoints:
Watchpoint 1: addr = 0x00000000 size = 8 state = enabled type = w
Watchpoint 3: addr = 0x7fff54ed67c4 size = 4 state = enabled type = rw
declare @ '/Users/miya-shaocong/Desktop/Demozz/Demozz/ViewController.m:89'
watchpoint spec = 'a'
new value: 0
如果我们想删除一个监视点,只需要把代号给提交过去就好了。
watchpoint delete 1
想删除全部的话,就这样
watchpoint delete
它会让你确认
About to delete all watchpoints, do you want to do that?: [Y/n]
然后你输入 Y 确定就好了。
- po 显示任何返回值与控制的格式类型
- 变量
比如你想看某个变量的值,不需要在代码中添加log,直接断点到那个地方,然后 po 变量名,就会输出你想要看到值
- 变量
(lldb) po b
100
- 坐标
比如你想看到某个视图的坐标以及大小信息,那就直接 po 这个视图的frame。
(lldb) po self.view.frame
(origin = (x = 0, y = 0), size = (width = 375, height = 667))
你还可以尝试输出其他(你想要看的东西)。
- print 更详细的输出,(包括类型)
(lldb) print a
(int) $5 = 0
(lldb) print b
(int) $6 = 100
(lldb) print self.view
(UIView *) $7 = 0x00007fd183d04cf0
(lldb) print self.view.frame
(CGRect) $8 = (origin = (x = 0, y = 0), size = (width = 375, height = 667))
$X 这种是命令结果的引用名,我们可以用于任何其他表达式或者接收参数的命令。
比如:
(lldb) print $5 + 109
(int) $9 = 109
// ---
(lldb) po $8
(origin = (x = 0, y = 0), size = (width = 375, height = 667))
- next 直接跨过当前的断点,跳到下一个断点位置,并输出断点所在的行数。
- run 重新启动程序。
- kill 终止当前的程序
-
可视化工具操作
第一步:右键断点,然后选择Edit Breakponit
第二步:
Xcode可视化工具.png
第三步:运行到断点看结果
结果.png
网友评论