LLDB 检查调用堆栈
当程序运行时, 程序会存储它的运行信息在调用栈中. 每当方法被调用, 程序就会在调用栈顶添加新的栈帧, 每个栈帧都包含着传递给方法的参数, 方法的局部变量信息, 方法返回后要跳转到的地址信息.
当程序在断点处停止时, 可以通过调试器检查当前栈帧的状态. 通过帧栈状态可以很好地分析方法的行为以及方法是如何和程序的其它部分交互的.
获取当前栈帧的信息
frame info
通过frame info
指令, 可以获取到当前帧栈对应代码的位置, 包括源文件信息以及行号信息.
(lldb) frame info
frame #0: 0x00000001000034cf Greeter`Greeter.greet(name="Mei", self=0x0000000100205bf0) at Greeter.swift:9:12
检查变量信息
frame variable(f v)
通过frame variable
指令. 可以获取当前帧栈上的所有变量信息.
(lldb) frame variable
(String) name = "Anton"
(Greeter.Greeter) self = 0x0000000100502920 {
acquaintances = ([0] = "Anton")
}
执行表达式
expression
执行表达式是LLDB的一个强大的功能. 通过这个表达式, 可以改变存储的变量信息, 从而改变程序的运行结果.
(lldb) expression -- acquaintances.insert("Mei")
(lldb) expression -- acquaintances.remove("Anton")
(String?) $R1 = "Anton"
frame variable(f v)
与 expression
的比较
frame variable (f v )
|
expression -- (p)
|
expression -O -- (po )
|
---|---|---|
不会实际运行代码 | 实际运行了代码 | 实际运行了代码 |
使用LLDB的格式输出 | 使用LLDB的格式输出 | 使用自定义的格式(如Swift的 debugDescription )输出, 如果没有自定义格式, 会使用LLDB的格式输出 |
expression
由于会运行表达式, 可能会给程序带来影响, 如果想要安全快速的调试, 可以使用frame variable
获取线程调用栈(Backtrace)
调用栈展示了当前的方法调用结构. 通过thread backtrace(bt)
, 可以沿着调用栈观察到程序是怎样通过调用方法一步一步变为当前状态的.
(lldb) thread backtrace
* thread #1: tid = 0x1288be3, 0x0000000100001a98 Greeter`Greeter.hasMet(name="Anton", self=0x0000000101200190) -> Bool + 24 at Greeter.swift:5, queue = 'com.apple.main-thread', stop reason = step in
frame #0: 0x0000000100001a98 Greeter`Greeter.hasMet(name="Anton", self=0x0000000101200190) -> Bool + 24 at Greeter.swift:5
* frame #1: 0x0000000100001be4 Greeter`Greeter.greet(name="Anton", self=0x0000000101200190) -> () + 84 at Greeter.swift:9
frame #2: 0x00000001000019eb Greeter`main + 155 at Greeter.swift:20
frame #3: 0x00007fff949d05ad libdyld.dylib`start + 1
frame #4: 0x00007fff949d05ad libdyld.dylib`start + 1
可以传入整型参数控制展示的帧栈个数
通过 thread backtrace all
可以获取所有线程的调用栈
获取线程列表
thread list
(lldb) thread list
Process 96461 stopped
* thread #1: tid = 0x1384af1, 0x000000010000111f main`sayHello() -> () + 15 at main.swift:2, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
参考资料: Examining the Call Stack
上一篇: LLDB 命令入门(第 6 章:线程、分帧和步进)
下一篇: 青少年 CTF--见微知著 [WP]
推荐阅读
-
2440 堆栈实现类型、b 系列指令、汇编丢弃 c、c 调用汇编、切换操作模式、初始化异常向量表、中断处理、
-
LLDB 检查调用堆栈
-
(1)创建并展示模拟数据实例 我们有两组各包含5个样本的30个基因表达数据(其中15个基因上调,15个基因下调)。以下是如何生成及显示这些数据: ```r set.seed(123) # 保证可复现结果 exp = matrix(rnorm(300), nrow = 30, ncol = 10) exp[1:15, 1:5] = exp[1:15, 1:5] + matrix(rnorm(75, mean = 4), nrow = 15, ncol = 5) exp[16:30, 6:10] = exp[16:30, 6:10] + matrix(rnorm(75, mean = 3), nrow = 15, ncol = 5) exp = round(exp, 2) # 四舍五入到小数点后两位 colnames(exp) = paste("样本", 1:10, sep = "") # 改为中文列名 rownames(exp) = paste("基因", 1:30, sep = "") # 改为中文行名 head(exp) ``` (2)在R中安装和加载pheatmap包 首先确保已安装pheatmap包,如果没有,请运行: ```r if (!requireNamespace("BiocManager", quietly = TRUE)) install.packages("BiocManager") BiocManager::install("pheatmap") # 安装pheatmap包 library(pheatmap) # 加载pheatmap包 packageVersion("pheatmap") # 检查版本号 ``` (3)基本的热力图绘制 使用上述示例数据 `exp`,我们可以直接调用 `pheatmap()` 函数进行基本的热力图绘制: ```r pheatmap(exp, cluster_rows = TRUE, cluster_cols = TRUE) # 对行和列进行聚类 ```