LLDB 知多少

重识 LLDB

LLDB 是什么?

 “若是调试是删除 bug 的过程,那么编程就是引入 bug 的过程。”(Edsger W. Dijkstra)html

 对于苹果开发者而言,LLDB 是无人不知的调试工具,然而此知非彼知,相信有至关规模的开发者对 LLDB 的了解仍然停留于几个基础命令的使用,今天让咱们来从新认识一下既熟悉又陌生的 LLDB,看看它那些你未曾用过的强大功能,以及如何提升咱们的开发效率。git

 开始把玩其功能以前,先搞清楚 LLDB 是什么,简言之,LLDB 是一个有着 REPL 的特性和 C++ 、Python 插件的开源调试器。github

 LLDB is a next generation, high-performance debugger. It is built as a set of reusable components which highly leverage existing libraries in the larger LLVM Project, such as the Clang expression parser and LLVM disassembler.
 LLDB is the default debugger in Xcode on Mac OS X and supports debugging C, Objective-C and C++ on the desktop and iOS devices and simulator.express

 以上摘自官方文档中的一段简短的介绍,更多相关信息请参阅 LLDB 官方文档编程

LLDB 命令结构

 知道了 LLDB 是什么,还要了解其命令结构及语法,这样才能告别死记命令,开启压榨 LLDB 之路了。LLDB 通用结构的形式以下:sass

<command> [<subcommand> [<subcommand>...]] <action> [-options [option-value]] [argument [argument...]]函数

其中:工具

  • command、subcommand:LLDB调试命令的名称。命令和子命令按层级结构来排列:一个命令对象为跟随其的子命令对象建立一个上下文,子命令又为其子命令建立一个上下文,依此类推。
  • action:命令操做,想在前面的命令序列的上下文中执行的一些操做。
  • options:命令选项,行为修改器(action modifiers)。一般带有一些值。
  • argument:命令参数,根据使用的命令的上下文来表示各类不一样的东西。
  • []:表示命令是可选的,能够有也能够没有。

举个例子:学习

命令:breakpoint set -n main 对应到上面的语法就是:ui

  • command:breakpoint 断点命令
  • action:set 设置断点
  • option:-n 表根据方法 name 设置断点
  • arguement:mian 表示方法名为 mian

关于原始命令

 LLDB支持不带命令选项的原始命令,原始命令会将命令后面的全部东西当作参数(arguement)处理。但不少原始命令也能够带命令选项,当你使用命令选项的时候,须要在命令选项后面加 -- 区分命令选项和参数。
 如:expression (就是 p/print/call)、expression -o(就是 po),打印一个UIView对象地址:

 前者是计算其地址的值,后者调用了对象的 description 方法,其中体现了惟一匹配原则:假如根据前n个字母已经能惟一匹配到某个命令,则只写前n个字母等效于写下完整的命令。再用设置断点的命令举例,下面两条命令等效:
 更多命令结构的介绍及用法,请参考 LLDB 入门。接下来介绍点 LLDB 最实用又最容易被忽略的用法。


LLDB 经常使用命令总结

辅助记忆:apropos

 当咱们并不能彻底记得某个命令的时候,使用 apropos 经过命令中的某个关键字就能够找到全部相关的命令信息。 好比: 咱们想使用stop-hook的命令,可是已经不记得stop-hook命令是啥样了:

实在记不起来也不要慌,这里有 命令list

一.断点设置

 关于断点设置,多数人都习惯用图形界面去作,但在调试中有些场景仅仅靠图形界面仍是不够的,好比:如何经过断点实现相似 KVO 那样对成员变量变化的监听呢?(别跟我说你要加代码重写set方法...即便这样也不靠谱)。下面一一罗列那些好用的断点命令:

  1. breakpoint list:查看全部断点列表
  2. breakpoint delete:删除全部断点(可跟组号删除指定组)
  3. breakpoint disable/enable:禁用 启用指定断点
  4. breakpoint set -r some:遍历整个项目中包含 some 这个字符的全部方法并设置断点
  5. breakpoint 支持按文件名、函数名、行数、正则等各类条件筛选设置断点,请结合语法并参考官方文档
  6. watchpoint set expression 0x10cc64d50:在内存中为地址为0x10cc64d50的对象设置内存断点
  7. watchpoint set variable xxoo:为当前对象的变量 xxoo 设置内存断点
  8. target stop-hook add -o "frame variable":添加每次程序 stop 时都但愿执行的命令:frame variable(打印当前栈内的全部变量)
  9. target stop-hook、watchpoint 的增删改查命令与 breakpoint 的基本相同
  10. 更多变态断点玩法需自定义插件支持,火烧眉毛的你请快进此文 》》》

二.流程控制

这两幅图你必定不陌生:

  1. 图一
  2. 图二
  • 第一个按钮:continue/c 继续执行
  • 第二个按钮:
    • 图一: thread step-over/next/n 当前线程下一步(以一个完整子函数为一步)
    • 图二: thread step-inst-over/ni 当前线程下一步(以一个汇编函数为一步)
  • 第三个按钮:
    • 图一: thread step-in/step/s 当前线程下一步(遇到子函数就进入而且继续单步执行)
    • 图二: thread step-inst-over/si 当前线程下一步(遇到汇编函数就进入而且继续单步执行汇编指令)
  • 第四个按钮:thread step-out/finish 退出当前帧栈

其余命令:

  • thread return:它有一个可选参数,在执行时它会把可选参数加载进返回寄存器里,而后马上执行返回命令,跳出当前栈帧。这意味这函数剩余的部分不会被执行。这会给 ARC 的引用计数形成一些问题,或者会使函数内的清理部分失效。可是在函数的开头执行这个命令,是个很是好的隔离次函数、伪造返回值的方式。

三.可执行文件&共享库查询命令

这些命令在逆向及定位错误时使用频率很是高。

  1. image list:列出主要的可执行文件和全部依赖的共享库。
  2. image lookup --address 0x1ec4:在可执行文件或任何共享库中查找原始地址信息。
  3. image lookup -v --address 0x1ec4:查找完整的源代码行信息。
  4. image lookup --type NSString:根据名称查找对应(NSString)类型的信息。

四.其余经常使用命令模板

  1. register read:显示当前线程的通用寄存器。
  2. register write rax 123:将一个新的十进制值“123”写入当前线程寄存器“rax”。
  3. memory read --size 4 --format x --count 4 0xbffff3c0:从地址0xbffff3c0读取内存,并显示4个十六进制uint32_t值。

增强版 LLDB —— 修改 .lldbinit 文件 & 插件安装

 前面所列的命令在 这里 都能找到官方说明,更多命令用法有兴趣的建议本身去细细探索,接下来咱们将站在巨人的肩膀上,用高手们专门为 LLDB 写的插件去深刻挖掘它的潜力。

  1. 推荐插件一: facebook 开源的 LLDB 插件 chisel

    brew install chisel 的安装过程这里就不赘述了,安装成功后,在~/目录下的 .lldbinit 文件中引入对应文件路径,增长一行:command script import /usr/local/opt/chisel/libexec/fblldb.py 后保存, 重启 Xcode便可使用。它提供的快捷 命令清单及说明 这里也不赘述了。截个图感觉下它的强大吧:

  2. 推荐插件二DerekSelander/LLDB

    该插件与 chisel 都是用 Python 写的,其安装须要手动下载仓库,而后将仓库中 dslldb.py 文件的路径用与上述一样的方式添加到 .lldbinit 中,具体用法也很简单粗暴,就不在这粘贴了,请至 README 领略。

总结:

 看到这,你收获的只有暂时记忆,其实等于毫无所获...并且还浪费了宝贵的几分钟,这也是我极不但愿看到的,而避免其成为事实的惟一方式就是,请你打开 Xcode,运行一个项目,参照着文中涉及到的说明文档,试着敲一敲每一个命令,体会一下它们的用法与区别。最后,为你的 LLDB 配好插件,去感觉它的蜕变,相信我,你的开发效率提高的可不止一点点。学习是一种能力,拒绝操做手册式灌输,分享者多半是在总结学习收获时为读者提供一些思路或方向,这也是我为你保留一丝探索余地的初衷,愿你有所收获。

 水平有限,请大神多多指正。下篇再会~

相关文章
相关标签/搜索