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
通过命令中的关键字获取相关命令信息
断点设置
使用断点命令,实现图形化界面不好实现的功能
- breakpoint list: 查看所有断点列表
- breakpoint delete: 删除所有断点(可以跟上组号,表示删除指定组)
- breakpoint disable/enable: 禁用 启用指定断点
- breakpoint set -r some:遍历项目中包含some这个字符所有方法并设置断点
- breakpoint 支持按文件名、函数名、行数、正则等各种条件筛选设置断点
- watchpoint set expression 0x10cc64d50: 在内存中为地址为0x10cc64d50的对象设置内存断点
- target stop-hook add -o "frame variable": 添加每次程序stop时都希望执行的命令
- target stop-hook、watchpoint 的增删改查命令与 breakpoint 的基本相同
- 等等
流程控制
图一
图二
- 第一个按钮: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 的引用计数造成一些问题,或者会使函数内的清理部分失效。但是在函数的开头执行这个命令,是个非常好的隔离次函数、伪造返回值的方式。
可执行文件&共享库查询命令
这些命令常用于逆向和定位错误时
- image list: 列出主要的可执行文件和所有依赖的共享库。
image lookup --address 0x1ec4:在可执行文件或者任何共享库中查找原始地址信息
image lookup -v --address 0x1ec4:查找完整的源代码行信息。
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值。
插件
- 推荐插件一: facebook 开源的 LLDB 插件 chisel
- 推荐插件二:DerekSelander/LLDB