LLDB

学习自 LLDB 知多少

LLDB是一个有着REPL的特性和C++、Python插件的开源调试器
LLDB是下一代高性能调试器。 它由一组可重用的组件构建,可以高度利用较大的LLVM项目中的现有库,例如Clang表达式解析器和LLVM反汇编程序。
LLDB是Mac OS X上Xcode的默认调试器,支持在桌面和iOS设备和模拟器上调试C,Objective-C和C ++。

LLDB命令结构

LLDB命令通用结构:

<command>[<subcommand> [<subcommand>...]] <action> [-options [option-value]] [argument [argument...]]
  • commond、subcommond:LLDB调试命令的名称。命令和子命令按照层级结构来排列:一个命令对象为跟随其的子命令对象创建一个上下文,子命令又为其子命令创建一个上下文,以此类推
  • action:命令操作,想在前面的命令序列的上下文中执行的一些操作
  • options:命令选项,行为修改器。通常带有一些值
  • argument:命令参数,根据使用的命令的上下文来表示不同的东西
  • []:表示命令可选

例如:
breakpoint set -n main
command为breakpoint、action为set、option即为-n表示根据方法name设置断点、argument:main表示方法名main

原始命令

LLDB支持不带命令选项的原始命令,原始命令会将命令后面的所有东西当做参数(arguement)处理。但很多原始命令也可以带命令选项,当你使用命令选项的时候,需要在命令选项后面--区分命令选项和参数。
例如: 
expression(就是p/print/call)、expression -o(就是 po),我们用这两个命令打印一下一个UIView的地址

//调用对象的description方法
(lldb) po 0x7fe8a201b400
<UITableView: 0x7fe8a201b400; frame = (0 0; 0 0); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x600001c072a0>; layer = <CALayer: 0x6000012029e0>; contentOffset: {0, 0}; contentSize: {0, 0}; adjustedContentInset: {0, 0, 0, 0}>

//计算地址的值
(lldb) expression 0x7fa3b981ee00
(long) $0 = 140341168696832

(lldb) p 0x7fa3b981ee00
(long) $1 = 140341168696832

//expression即为一个原始命令 为了告诉其 -o为命令选项而不是参数 需要加上 --
(lldb) expression -o -- 0x7fa3b981ee00
<UITableView: 0x7fa3b981ee00; frame = (0 0; 0 0); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x600001e19ce0>; layer = <CALayer: 0x600001001420>; contentOffset: {0, 0}; contentSize: {0, 0}; adjustedContentInset: {0, 0, 0, 0}>

(lldb) expression -object -- 0x7fa3b981ee00
<UITableView: 0x7fa3b981ee00; frame = (0 0; 0 0); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x600001e19ce0>; layer = <CALayer: 0x600001001420>; contentOffset: {0, 0}; contentSize: {0, 0}; adjustedContentInset: {0, 0, 0, 0}>

假如前n个字母已经能匹配到某个命令,则只写前n个命令等效于写下完整的命令。

LLDB常用命令

apropos 辅助记忆

当不能完全记得某个命令时,使用apropos通过命令中的关键字获取相关命令信息

断点设置

使用断点命令,实现图形化界面不好实现的功能

  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. target stop-hook add -o "frame variable": 添加每次程序stop时都希望执行的命令
  8. target stop-hook、watchpoint 的增删改查命令与 breakpoint 的基本相同
  9. 等等

流程控制

  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)类型的信息。

其它常用命令模板

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

插件

  1. 推荐插件一: facebook 开源的 LLDB 插件 chisel
  2. 推荐插件二:DerekSelander/LLDB