动态调试LLDB - wanshanhu79/Study GitHub Wiki
将程序运行起来,通过下断点、打印等方式,查看参数、返回值、函数调用流程等。
Xcode里包含有调试器LLDB,debugserver一开始存放在Mac的Xcode里,路径为/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/9.1/DeveloperDiskImage.dmg/usr/bin/debugserver
。当Xcode识别到手机设备时,Xcode会自动将debugserver安装到iPhone上。
一般情况下,只能调试通过Xcode安装的APP
默认情况下,/Develop/usr/bin/debugserver
缺少一定的权限,只能调试通过Xcode安装的APP
,无法调试其他APP。如果希望调试其他APP,需要对debugserver重新签名,签上2个调试相关的权限。
- get-task-allow
- task_for_pid_allow
-
iPhone上的
/Developer
目录是只读的,无法直接对它签名,需要先把debugserver复制到Mac -
通过ldid命令导出文件以前的签名权限
ldid -e debugserver > debugserver.entitlements
给debugserver.plist文件加上get-task-allow 和 task_for_pid_allow 权限
-
通过ldid命令重新签名
ldid -S debugserver.entitlements debugserver
-
将已经签好权限的debugserver放到
/usr/bin
目录,便于找到debugserver指令 -
关于权限的签名,也可以使用codesign
# 查看权限信息 codesign -d --entitlements - debugserver # 签名权限 codesign -f -s --entitlements debugserver.entitlements debugserver #或者简写为 codesign -fs --entitlements debugserver.entitlements debugserver
debugserver *:端口号 -a 进程
- *: 端口号 :使用iPhone的某个端口启动debugserver服务(只要不是保留端口号就行)
- -a 进程 :输入APP的进程信息(进程ID或者进程名称)
-
启动lldb
lldb
-
连接debugserver服务
(lldb) process connect connect://手机IP地址:debugserver服务端口号
-
使用LLDB的c命令让程序先继续运行
(lldb) c
-
接下来就可以使用lldb指令调试APP
debugserver -x auto *:端口号 APP的可执行文件路径
-
指令的格式是
<command> [<subcommand> [<subcommand...>]] <action> [-options [option-value]] [argument [argument...]]
- : 命令
- : 子命令
- : 命令操作
- : 命令选项
- : 命令参数
- [] : 表示可以没有
breakpoint set -n test
- 给test函数设置断点
-
breakpoint 是
* set是
* -n是
- test是
-
breakpoint 是
* set是
* -n是
-
help
- 查看指令的用法
- 比如help breakpoint、help breakpoint set
-
expression --
-
执行一个表达式
* <cmd-options> : 命令选项 * -\- : 命令选项结束符,表示所有的命令选项已经设置完毕,如果没有命令选项,-\-可以省略 * <expr> : 需要执行的表达式
expression self.view.backgroundColor = [UIColor redColor]
-
expression、expression -- 和指令print、p、call的效果一样
-
expression -O -- 和指令po的效果一样
-
使用 OC 的代码在Swift 的框架中:
expression -l objc -O -- <expr>
-expression -l objc -O -- [self.view recursiveDescription]
打印 self.view 的子视图 - Swift中修改值unsafeBitCast(point, to: type)
expression unsafeBitCast(0x7fa94cb015c0, to: UIButton.self).frame.origin.x = 100
- 刷新视图暂存区:expression CATransaction.flush()
-
-
thread
- thread backtrace
- 打印线程的堆栈信息
- 和指令bt的效果一样
- thread return []
- 让函数直接返回某个值,不会执行断点后面的代码
- hread continue、continue、c : 程序继续运行
- thread step-over、next、n : 单步运行,把子函数当做整体一步执行
- thread step-in、step、s : 单步运行,遇到子函数会进入子函数
- thread step-out、finsh : 直接执行完当前函数的所有代码,返回到上一个函数
- si、ni和s、n类似 * s、n是源码级别 * si(thread step-inst 、stepi)、ni(thread step-inst-over、nexti)是汇编指令级别
- thread backtrace
-
frame variable []
- 打印当前栈帧的变量
-
breakpoint set
-
设置断点
-
breakpoint set -a 函数地址
-
breakpoint set -n 函数名
-
breakpoint set -n test
: C语言函数-
breakpoint set -n touchesBegan:withEvent:
: OC方法名,没有指定类,是所有的
-
breakpoint set -n "-[ViewController touchesBegan:withEvent:"
-
-
breakpoint set -r 正则表达式 : 会对所有符合这个条件的地方设置断点
-
breakpoint set -s 动态库 -n 函数名
-
breakpoint list : 列出所有的断点(每个断点都有自己的编号) * breakpoint disable 断点编号 :禁用断点 * breakpoint enable 断点编号 : 启用断点 * breakpoint delete 断点编号 : 删除断点
-
-
image lookup
- image lookup -t 类型 : 查找某个类型的信息
- image lookup -a 地址 : 根据内存地址查找在模块中的位置
- image lookup -n 符号或者函数名 : 查找某个符号或者函数的位置
-
image list
- 列出所加载的模块信息
- image list -o -f : 打印出模块的偏移地址(ASLR)、全路径
-
小技巧
-
敲Enter,会自动执行上次的命令
-
绝大部分指令都可以使用缩写
-
-
设置别名
command alias poc expression -l objc -O --
command alias flush expression -l objc -- (void)[CATransaction flush]
po
Enter expressions, then terminate with an empty line to evaluate:
1 class $BreakpointUtils {
2 static var $counter = 0
3 }
4 func $increaseCounter() {
5 $BreakpointUtils.$counter += 1
6 print("Times I've hit this breakpoint: \($BreakpointUtils.$counter)")
7 }
使用美元符号表示这些属性和方法属于lldb,而不是实际代码。
lldb插件chisel
v myProperty
(Int) myProperty = 1