LLDB进阶:使用命令行进行检查
LLDB 是一个命令行调试环境,功能类似于 GDB。LLDB 为 Xcode 提供了底层调试环境,在调试区域内设有控制台窗格,方便直接访问 Xcode IDE 环境中的 LLDB 命令
这篇简要介绍 LLDB 的语法和命令特性,介绍命令别名功能的使用,并介绍 LLDB 的帮助系统
关于基础部分可以阅读我之前的博客:《运行,暂停,检查:探索如何使用LLDB进行有效调试》
LLDB命令结构
所有刚开始使用LLDB的用户都应该了解LLDB的命令结构和语法,以便挖掘LLDB的潜力,并了解如何最大化发挥其作用
在许多情况下,LLDB提供的命令与GDB命令类似,这样可以使得有经验的GDB玩家更容易上手LLDB
你知道吗?
GDB (GNU Debugger) 是 Linux 和 Unix 系统下最常用、最强大的程序调试工具。它主要用于调试 C、C++、Go、Rust 等语言编写的程序简单来说,GDB 就像是给你的程序拍了一张"X光片",允许你在程序运行时查看其内部状态,或者在程序崩溃时"时光倒流"去查看原因
理解LLDB命令语法
LLDB 命令语法始终结构化且规则。LLDB 命令的格式如下:
<command> [<subcommand> [<subcommand>...]] <action> [-options [option-value]] [argument [argument...]]
command 和subcommand 是LLDB调试命令,其按照层级结构排列:command 命令为其后subcommand 创建上下文,后者再次为下一层级subcommand创建上下文,依此类推
动作,即action 为你想在这个上下文中执行的操作
选项(options)是动作的修改器,一般是一个值
参数(argument)会根据上下文表示多种不同的内容
这里的上下文可能有些难以理解,实际上把他当作链式调用即可
例如我们要把一个View添加到ViewController 里,我们不能直接add,而是需要一个可以执行该方法的对象即self.view
这里的上下文就是这个意思,实际上这里的意思是想告诉你
LLDB 的命令是不能乱序的,前面的词(Command)决定了后面的词(Subcommand/Action)的具体含义和有效性。 前面的词就是后面的词赖以生存的"环境"
这样写还是有点乱,我们来看一个例子
swift
po self.view
还记得这个指令吗?我在第一篇关于LLDB的博客中介绍过,在终端打出这个指令之后,LLDB会以一种相对友好的方式来告诉你这个对象的各种信息
对于这行命令,它实际上是简写形式,我们把他展开来看
swift
expression --object-description -- self.view
比较复杂是吧,接下来我们拿着这行命令来对它进行解刨
-
Command & Subcommand (对象/上下文):
expression即为对应部分,这是动作的发起者,你可以把他想象成一个类,它的上下文含义即为:我要开始在这里运行一段代码了这样调试器就知道了你后面输入的是代码而不是什么奇奇怪怪的东西
-
Action (动作):
这里并没有action的部分,这是因为expression本身只有一个核心功能,在这种情况下,action会被自动并入
-
Options (选项/修饰符):
--object-description这是一个动作修饰符,平常我们缩写为-o这行是在配置
expression的行为,即打印出人能读懂的东西而不是内存地址,它类似于description方法 -
Arguments (参数):
self.view这是参数内容expression需要一段有效的代码作为参数,所以这里必须是代码
在这里,参数是一个OC的属性访问语法
LLDB 命令行解析会在命令执行之前完成。命令(command)、子命令(subcommand)、选项(options)、选项值(option-value)、参数(argument)都是用空格分隔的
双引号(" ")用于保护选项值(option-value)和参数(argument)中的空格
如果需要将反斜杠(\)或者双引号(")放入参数(argument)中,则需要在参数中该字符前加上反斜杠(\)。LLDB 等效地使用单引号(')和双引号("),以允许轻松编写命令行中的双引号部分
使用命令选项
像我们刚刚的例子中一样,LLDB 中的命令选项有规范形式和缩写形式。例如,以下是断点集合命令的部分命令选项列表,括号内列出了规范形式:
swift
breakpoint set
-M <method> ( --method <method> )
-S <selector> ( --selector <selector> )
-b <function-name> ( --basename <function-name> )
-f <filename> ( --file <filename> )
-l <linenum> ( --line <linenum> )
-n <function-name> ( --name <function-name> )
...
在LLDB中使用命令补全
如果你有在我的第一篇博客中动手实践过,那你应该发现LLDB 支持源文件名、符号名、文件名等的命令补全
在终端窗口中,通过在命令行输入制表符字符来启动完成
Xcode 控制台中的补全功能与源代码编辑器中的补全相同:
完成补全在输入第三个字符后自动弹出,补全弹窗可通过 Esc(Esc)键手动调用。此外,Xcode 控制台中的补全遵循编辑面板中指定的 Xcode 文本编辑偏好设置
命令别名与帮助
现在我们已经了解了LLDB的命名别名机制来构造常用的命令的别名,例如你的代码全是bug,网络请求一运行就报错,所以反复输入
swift
(lldb) breakpoint set --file foo.c --line 12
你可以构造一个别名
swift
(lldb) command alias bfl breakpoint set -f %1 -l %2
这样你就可以输入命令
swift
(lldb) bfl foo.c 12
由于命令别名在各种情况下都很有用,我们应该熟悉它们的结构
你知道吗?
LLDB已经添加了一些alias(例如,step、next、continue),但并未为所有命令添加alias,因为每个命令可以使用一个或两个单独字母表示更为方便,即命令的简写形式更为方便
然而,用户可以根据个人偏好设置LLDB别名。用户配置的别名会保存在
~/.lldbinit文件,LLDB启动时会读取该文件。help命令会索引别名以方便查看已设置的别名要查看所有当前定义的别名及其定义,请使用
help -a命令,并在帮助输出末尾找到当前定义的别名,从以下开始:
The following is a list of your current command abbreviations (see 'help command alias' for more info):
对于已经命名别名的命令,你可以使用(lldb) command unalias bfl来移除他们
使用快捷键来调试
Debug时,使用快捷键可以提高调试效率,下面是一些常用快捷键:
| 功能 | 快捷键 | 命令 |
|---|---|---|
| 显示、隐藏控制台 | Cmd + Shift + Y | |
| 启用、禁用所有断点 | Cmd + Y | breakpoint enable、breakpoint disable |
| 光标移动到控制台 | Cmd + Shift + C | |
| 清空控制台 | Cmd + K | |
| 暂停、继续 | Cmd + Ctrl + Y | continue |
| step over | F6 | next |
| step into | F7 | step |
| step out | F8 | finish |
参考资料: