一、打印输出、变量修改
1. print:简化命令:p
1.1 如果打印的是简单类型,则会列出简单类型的类型和值。如果是对象,还会打印出对象指针地址。
1.2 如果我们只想查看对象的值的信息,则可以使用po(print object的缩写)命令。
1.3 我们还可以为其指定不同的打印格式,其命令格式是print/格式。p/x代表16进制;p/t代表2进制等等。
两个指令实际都是expression指令的缩写。p打印的是当前对象的地址而po则会调用对象的description方法
2. expression:简化命令:exp、e
2.1 expression 命令不仅能输出某个变量的值(对象的类型和地址),还能改变程序中的实际值。比如:
(lldb) exp var (结果能输出var这个变量的值)
(lldb) exp self.view.backgroundColor = UIColor.red (将背景变成红色)
2.2 下面三行命令是创建一个Controller并present
(lldb) exp let $newController = UIViewController()
(lldb) exp $newController.view.backgroundColor = UIColor.green.withAlphaComponent(0.4)
(lldb) exp self.present($newController, animated: true, completion: nil)
2.3 控制台临时增加的变量,需要在变量前面增加符号:$。如下:
(lldb) exp $var = 10
(lldb) exp $var (也可以用print查看:p $var)
二、获取状态
1. frame:
1.1 frame info:获取当前断点地址、代码行数以及函数的相关参数
(lldb) frame info (touchesBegan内设置的断点)
frame #0: 0x000000010392ca34 LLDBTestDemo`ViewController.touchesBegan(touches=Swift.Set<UIKit.UITouch> @ 0x00007ffeec2d12e8, event=0x000060000010ea90, self=0x00007fc217d0cc70) at ViewController.swift:27
1.2 frame variable:展示当前作用域下的参数和局部变量
(lldb) frame variable 等价于 (lldb)fr v
效果和打断点在’控制台’开启Variables view(控制台区域左侧区域)看到的一样
(lldb) frame variable --no-args 等价于 (lldb) fr v -a
1.3 frame variable 变量:展示指定变量var的具体内容
(lldb) frame variable 变量
2. bug日志保存
(lldb) bugreport unwind --outfile Users/ming/Desktop/bugreport/日志文件名称
3. refcount 能获得指定对象的引用数量(调试某些内存泄露问题时)
(lldb) language swift refcount 对象a
三、应用的执行流程
1. 获取当前断点的状态:打印断点所在的地址、代码块以及停在哪一行
(lldb) process status
2. process 其它命令:attach、connect、kill、load、lanuch、continue
3. 断点
3.1 输出所有断点
(lldb) breakpoint list
3.2 设置新断点
(lldb) breakpoint set -f ViewController.swift -l 17 (等价于下面的简写)(-f 是你想要放置断点处的文件名,-l 是新断点的行数。)
(lldb) b ViewController.swift 17
3.3 根据地址设置断点
(lldb) br set -a 0x00000001039edf2d 等价于:
(lldb) b -a 0x00000001039edf2d
3.4 使用正则来设置断点
(lldb) breakpoint set --func-regex 函数名
(lldb) b -r 函数名
3.5 为断点增加命令:
第一步设置一个断点如下:
(lldb) breakpoint set -f ViewController.swift -l 27
设置后控制台会输出:Breakpoint 3: where = …… (其中3 是这个断点的’序号index’)
第二步准备断点命令:
(lldb) breakpoint command add 3 (其中3 是这个断点的’序号index’)
然后控制台会进入命令输入模式,最终以输入DONE作为结束标识。
第三步查看刚刚输入的命令:
(lldb) breakpoint command list 3
第四步,使得程序进入这个断点,查看是否执行’断点命令’
尝试:在刚刚输入DONE前一行输入continue
4. 线程操作
4.1 控制台断点流程执行
(lldb) process continue 继续 等价于 continue 等价于 c
(lldb) thread step-over 单步 等价于 next 等价于 n
(lldb) thread step-in 进入 等价于 step 等价于 s
(lldb) thread step-out 跳出 等价于 finish 等价于 f
4.2 获取当前线程函数的调用栈:
命令:frame info、frame variable、target variable等命令,这些操作都有一个局限:我们查看的各个变量都是当前作用域的。这意味着程序遇到断点的时候暂停,所有的操作都是局限于当前函数以及当前函数所在线程的内部。
命令:thread backtrace可以获取当前线程函数的调用栈
(lldb) thread backtrace (输出一系列带序号的frame)
输入frame select指令,我们可以任意的去选择一个作用域去查看
(lldb) frame select 2 (2:前一步输出的序号)
通过上面的指令,我们可以在断点发生的时候跳转到当前存在的任一线程里的任一作用域去进行操作。
4.3 image指令:是target module指令的缩写,借助它我们能够查看当前的Binary Images相关的信息。
在日常开发的过程中,我们会收集到用户各式各样的crash log。log中会为我们提供崩溃前函数栈的运行情况,每一个函数都会对应一个函数地址。
要解决问题首先我们需要确定的是程序最后调用了什么函数。由于ALSR的原因crash log中的函数地址我们不能够直接的去使用,我们需要在测试的机器上自己去计算出对应的函数地址。一般情况下crash log中会附带一个Binary Images。我们要利用这个来计算出每一个函数地址相对于所在框架的偏移量。
首先:利用 image list 指令来查看本机的Binary Images
(lldb) image list
有了本机的Binary Images我们就可以通过之前计算出的偏移量来获取本机对应函数的地址。
然后:通过image lookup指令查找对应地址的函数就可以确定崩溃前究竟执行了哪些函数
(lldb) image lookup -a 0x1025dd00a
tip:可以通过frame info来获取一个地址,使用image lookup来试一试
5. watchpoint:监视某个变量或某一块内存的读写情况
(lldb) watchpoint set variable 变量名称 (功能:监控变量)
(lldb) watchpoint set expression 0x地址 (功能:监控内存块。操作未成功,参考target stop-hook add的格式)
6. register :指令能够获取和修改各个寄存器的信息
一个典型的CPU是由运算器、控制器、寄存器等器件构成的,而寄存器进行的就是信息存储。
(lldb) register read (功能:查看命令)
(lldb) register write x2 0x地址 (还没实践)
四、脚本
推荐使用Facebook开源的脚本:https://github.com/facebook/chisel
自己写的脚本可以用下面的命令导入:
(lldb) command script import /Users/XXX/Desktop/脚本.py
还可以加入到lldbinit中,让Xcode启动就调用。
在终端(terminal)中输入下面的两条命令:
touch .lldbinit
open .lldbinit
然后在弹出的界面加入下面的代码:
command script import ‘Python文件的实际目录地址’
六 异常情况处理
error: no known method '-func:'; cast the message send to the method's return type
解决方法:在前面添加返回类型,如下
po (BOOL)[NSDecimalNumber isAGreaterThanB:@323.434432432 valueB:@323.4340000005]