崩溃日志的栈帧缺失
[toc]
问题背景
有位网友反馈自己负责的一款多种语言(objective-c/Swift/kotlin)混编的 APP 深受崩溃日志栈帧丢失的困扰。
如下所示:
-
第一张图是通过 Xcode 看到的相对”真实“的 Backtrace(函数调用栈)
-
第二张图是通过崩溃捕获工具获得的 Backtrace(函数调用栈)
通过对比两张截图,我们很容易发现,第二份崩溃日志的 Backtrace(函数调用栈) 缺失了 KaMPKitiOS -[TestOCInvokeKotlin testFun:]
本系列文章将会比较两种获取 Backtrace(函数调用栈) 的原理,并提供一种捕获完整崩溃日志的方案。
崩溃捕获 Backtrace(函数调用栈) 的原理
大部分的崩溃捕获工具的核心代码都是依赖 Fast unwind
捕获 **Backtrace(函数调用栈)**的。
什么是 Fast unwind?
Fast unwind
是指只依赖有限的寄存器获取 Backtrace(函数调用栈) 的方案。
如下面的演示代码所示,Fast unwind 只需要简单的几行代码获取 Backtrace(函数调用栈)。
注意:以下方法只进行展示;线上产品应该充分考虑各种异常情况,避免因为栈帧异常,触发二次崩溃
void fastUnwind() {
void **fp = __builtin_frame_address(0);
for (;;) {
void **next_fp = *fp;
if (next_fp <= fp) break;
printf("%p\n", *(fp+1));
fp = next_fp;
}
}
什么是 Backtrace(函数调用栈)
根据官方文档,**Backtrace(函数调用栈)**就是 “APP 崩溃时,每个线程运行的代码”。
通常情况下,它会按照以下方式展示:
0 TouchCanvas 0x0000000102afb3d0 CanvasView.updateEstimatedPropertiesForTouches(_:) + 62416 (CanvasView.swift:231)
1 TouchCanvas 0x0000000102afb3d0 CanvasView.updateEstimatedPropertiesForTouches(_:) + 62416 (CanvasView.swift:231)
2 TouchCanvas 0x0000000102af7d10 ViewController.touchesMoved(_:with:) + 48400 (<compiler-generated>:0)
3 TouchCanvas 0x0000000102af80b8 @objc ViewController.touchesMoved(_:with:) + 49336 (<compiler-generated>:0)
4 UIKitCore 0x00000001ba9d8da4 forwardTouchMethod + 328
5 UIKitCore 0x00000001ba9d8e40 -[UIResponder touchesMoved:withEvent:] + 60
6 UIKitCore 0x00000001ba9d8da4 forwardTouchMethod + 328
7 UIKitCore 0x00000001ba9d8e40 -[UIResponder touchesMoved:withEvent:] + 60
8 UIKitCore 0x00000001ba9e6ea4 -[UIWindow _sendTouchesForEvent:] + 1896
9 UIKitCore 0x00000001ba9e8390 -[UIWindow sendEvent:] + 3352
10 UIKitCore 0x00000001ba9c4a9c -[UIApplication sendEvent:] + 344
11 UIKitCore 0x00000001baa3cc20 __dispatchPreprocessedEventFromEventQueue + 5880
12 UIKitCore 0x00000001baa3f17c __handleEventQueueInternal + 4924
13 UIKitCore 0x00000001baa37ff0 __handleHIDEventFetcherDrain + 108
14 CoreFoundation 0x00000001b68a4a00 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24
15 CoreFoundation 0x00000001b68a4958 __CFRunLoopDoSource0 + 80
16 CoreFoundation 0x00000001b68a40f0 __CFRunLoopDoSources0 + 180
17 CoreFoundation 0x00000001b689f23c __CFRunLoopRun + 1080
18 CoreFoundation 0x00000001b689eadc CFRunLoopRunSpecific + 464
19 GraphicsServices 0x00000001c083f328 GSEventRunModal + 104
20 UIKitCore 0x00000001ba9ac63c UIApplicationMain + 1936
21 TouchCanvas 0x0000000102af16dc main + 22236 (AppDelegate.swift:12)
22 libdyld.dylib 0x00000001b6728360 start + 4
其中,崩溃的每一行代表 Backtrace(函数调用栈) 中的一个 栈帧。
21 TouchCanvas 0x0000000102af16dc main + 22236 (AppDelegate.swift:12)
栈帧 的每一列都包含有关崩溃时执行的代码的信息。
每一列代表的含义如下所示:
-
21
:栈帧帧号。栈帧按调用顺序排列,其中帧0是暂停执行时正在执行的函数。帧1是调用 帧0 的函数。后续的依此类推。
-
TouchCanvas
:包含正在执行的函数的二进制文件的名称。通常情况下,我们只会见到三种名称:1、系统库 2、可执行文件 3、动态库
-
0x0000000102af16dc
:正在执行的机器指令的地址。对于帧0,这是 APP 暂停或终止时在线程上执行的机器指令的地址。对于其他栈帧,这是在控制权返回到该栈帧之后执行的第一条机器指令的地址。
-
main
:在完全符号化的崩溃报告中,正在执行的函数的名称。出于隐私原因,苹果提供的函数名会限制到前 100 个字符。 -
22236
:+
后面的数字是从函数入口到函数当前指令的字节偏移量。 -
AppDelegate.swift:12
:代码的文件名和行号在某些情况下,文件名或行号信息与原始源代码不对应:
-
如果源文件名为
<compiler-generated>
,则代表该函数是编译器为框架创建的源码 -
如果源文件的行号为
0
,则表示该 栈帧 不会映射到原始代码中的特定代码行。无法映射的原因有很多,比如编译器对函数进行了内联
-
Fast unwind
测试
在讲解 Fast unwind
的原理前,我们先看看上面代码的实际效果
完整测试代码:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSLog(@"开始打印:[NSThread callStackSymbols]");
NSLog(@"%@", [NSThread callStackSymbols]);
NSLog(@"===== 分隔符 =====");
fastUnwind();
}
static long idx = 0;
// 为了直观对比效果,将 函数名 和 指令的字节偏移量 进行打印
void dumpAddress(const void *p) {
char *(*demangle)(char const *) = dlsym(RTLD_DEFAULT, "demangle");
Dl_info info;
if (dladdr(p, &info)) {
char *demangleName = demangle(info.dli_sname);
if (demangleName && strlen(demangleName) > 0) {
printf("%ld 0x%016lx %s + %ld \n", idx, (unsigned long)p, demangleName, p - info.dli_saddr);
} else {
printf("%ld 0x%016lx %s + %ld \n", idx, (unsigned long)p, info.dli_sname , p - info.dli_saddr);
}
} else {
printf("非法地址");
}
++idx;
}
void fastUnwind() {
void **fp = __builtin_frame_address(0);
for (;;) {
void **next_fp = *fp;
if (next_fp <= fp) break;
dumpAddress(*(fp + 1));
// printf("%p\n", *(fp+1));
fp = next_fp;
}
}
两种获取 Backtrace(函数调用栈) 方式的日志对比:
0 Demo 0x0000000101383d32 -[ViewController viewDidAppear:] + 114
1 UIKitCore 0x00007fff23f4730c -[UIViewController _setViewAppearState:isAnimating:] + 920
2 UIKitCore 0x00007fff23f47ce3 -[UIViewController __viewDidAppear:] + 146
3 UIKitCore 0x00007fff23f47fbc -[UIViewController _endAppearanceTransition:] + 232
4 UIKitCore 0x00007fff23e18dda __48-[UIPresentationController transitionDidFinish:]_block_invoke + 138
5 UIKitCore 0x00007fff24b700ce -[_UIAfterCACommitBlock run] + 54
6 UIKitCore 0x00007fff24683de4 _runAfterCACommitDeferredBlocks + 333
7 UIKitCore 0x00007fff24673e8c _cleanUpAfterCAFlushAndRunDeferredBlocks + 221
8 UIKitCore 0x00007fff246a5700 _afterCACommitHandler + 85
9 CoreFoundation 0x00007fff2038b1e8 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
10 CoreFoundation 0x00007fff20385a67 __CFRunLoopDoObservers + 547
11 CoreFoundation 0x00007fff2038600a __CFRunLoopRun + 1113
12 CoreFoundation 0x00007fff203856c6 CFRunLoopRunSpecific + 567
13 GraphicsServices 0x00007fff2b76adb3 GSEventRunModal + 139
14 UIKitCore 0x00007fff24675187 -[UIApplication _run] + 912
15 UIKitCore 0x00007fff2467a038 UIApplicationMain + 101
16 Demo 0x0000000101384052 main + 114
17 libdyld.dylib 0x00007fff20256409 start + 1
===== 分隔符 =====
0 0x0000000101383d75 -[ViewController viewDidAppear:] + 181
1 0x00007fff23f4730c -[UIViewController _setViewAppearState:isAnimating:] + 920
2 0x00007fff23f47ce3 -[UIViewController __viewDidAppear:] + 146
3 0x00007fff23f47fbc -[UIViewController _endAppearanceTransition:] + 232
4 0x00007fff23e18dda __48-[UIPresentationController transitionDidFinish:]_block_invoke + 138
5 0x00007fff24b700ce -[_UIAfterCACommitBlock run] + 54
6 0x00007fff24683de4 _runAfterCACommitDeferredBlocks + 333
7 0x00007fff24673e8c _cleanUpAfterCAFlushAndRunDeferredBlocks + 221
8 0x00007fff246a5700 _afterCACommitHandler + 85
9 0x00007fff2038b1e8 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
10 0x00007fff20385a67 __CFRunLoopDoObservers + 547
11 0x00007fff2038600a __CFRunLoopRun + 1113
12 0x00007fff203856c6 CFRunLoopRunSpecific + 567
13 0x00007fff2b76adb3 GSEventRunModal + 139
14 0x00007fff24675187 -[UIApplication _run] + 912
15 0x00007fff2467a038 UIApplicationMain + 101
16 0x0000000101384052 main + 114
17 0x00007fff20256409 start + 1
通过对照两份日志,我们可以看到可以发现 fastUnwind
和 [NSThread callStackSymbols]
的打印内容是一致的。
实际上,本文的
fastUnwind
函数就是通过将[NSThread callStackSymbols]
的源码精简后得到的。
Fast unwind
实现原理
Fast unwind
实现原理依赖以下两个机制:
- 编译器或者开发者在 prolog 阶段按照规则保证相关的
lr
信息 - 带链接的跳转指令(比如 arm64 的 bl 指令会更新
lr
)
Fast unwind
机制演示
相信很多朋友会和我一样,看到上面的描述会一头雾水。
不要着急,我们用一个实际的例子感受一下。
- 第一步:我们需要先准备几个函数方便并添加断点
测试代码:
- 第二步,执行程序,并在
testB
处命中断点,打印寄存器和堆栈信息
(lldb) x/2a $fp
0x16bba0f70: 0x000000016bba0f80
0x16bba0f78: 0x0000000104262b74 KaMPKitiOS`testA + 12 at TestOCInvokeKotlin.m:66:1
(lldb) x/2a $sp
0x16bba0f70: 0x000000016bba0f80
0x16bba0f78: 0x0000000104262b74 KaMPKitiOS`testA + 12 at TestOCInvokeKotlin.m:66:1
(lldb) p/a $lr
(unsigned long) $5 = 0x0000000104262b74 KaMPKitiOS`testA + 12 at TestOCInvokeKotlin.m:66:1
(lldb)
本文主要使用 arm64 架构为例进行讲解:
x29/fp 是 帧指针,用于存储栈帧相关的信息
x30/lr 是 链接寄存器,该寄存器存储的内容是某个函数的的地址。
sp 是 堆栈寄存器
整理后的栈内存如下:
// +=============================+
// 0x16fb7c750 | |
// +-----------------------------+
// 0x16fb7c758 | |
// +=============================+
// 0x16fb7c760 | |
// +-----------------------------+
// 0x16fb7c768 | |
// +=============================+
// 0x16fb7c770 | fp (0x000000016bba0f80) | <- fp,sp
// +-----------------------------+
// 0x16fb7c778 | testA + 12 |
// +=============================+
- 第三步:继续执行程序,并在
testC
处命中断点,打印寄存器和堆栈信息
(lldb) p/a $lr
(unsigned long) $6 = 0x0000000104262b88 KaMPKitiOS`testB + 12 at TestOCInvokeKotlin.m:70:1
(lldb) x/2a $sp
0x16bba0f50: 0x000000016bba0f80
0x16bba0f58: 0x00000001a3bc0d9c libobjc.A.dylib`objc_storeStrong + 44
(lldb) x/2a $fp
0x16bba0f60: 0x000000016bba0f70
0x16bba0f68: 0x0000000104262b88 KaMPKitiOS`testB + 12 at TestOCInvokeKotlin.m:70:1
(lldb)
整理后的栈内存如下:
// +=============================+
// 0x16fb7c750 | | <- sp
// +-----------------------------+
// 0x16fb7c758 | |
// +=============================+
// 0x16fb7c760 | fp (0x000000016bba0f70) | <- fp
// +-----------------------------+
// 0x16fb7c768 | testB + 12 |
// +=============================+
// 0x16fb7c770 | fp (0x000000016bba0f80) |
// +-----------------------------+
// 0x16fb7c778 | testA + 12 |
// +=============================+
现在,我们总结一下 fp
寄存器的规律:fp
存储的值是内存地址 0x16bba0f60
,0x16bba0f60
存储了上一帧的地址 0x000000016bba0f70
。
根据上面的规律,我们可以发现,寄存器 fp
就像一个链表的起始地址,通过它可以将整个 Backtrace(函数调用栈) 进行串联。
为了节省篇幅,我们不会将整个 Backtrace(函数调用栈) 讲解一遍,而是只提供下面的几个 栈帧,希望读者能够结合本文的第一份代码相互印证。
(lldb) x/2a $fp
0x16b904700: 0x000000016b904710
0x16b904708: 0x00000001044feb88 KaMPKitiOS`testB + 12 at TestOCInvokeKotlin.m:70:1
(lldb) x/2a 0x000000016b904710
0x16b904710: 0x000000016b904720
0x16b904718: 0x00000001044feb74 KaMPKitiOS`testA + 12 at TestOCInvokeKotlin.m:66:1
(lldb) x/2a 0x000000016b904720
0x16b904720: 0x000000016b904760
0x16b904728: 0x00000001044fec2c KaMPKitiOS`-[TestOCInvokeKotlin testOc:] + 56 at TestOCInvokeKotlin.m:78:6
(lldb) x/2a 0x000000016b904760
0x16b904760: 0x000000016b9047c0
0x16b904768: 0x00000001045050f8 KaMPKitiOS`KaMPKitiOS.BreedsViewController.(testOcInvokeKotlinLostFrameStack in _A334B59FD68BA9444D870B4E917DE9AA)() -> () + 252 at ViewController.swift:88:19
(lldb) x/2a 0x000000016b9047c0
0x16b9047c0: 0x000000016b9047e0
0x16b9047c8: 0x0000000104504ff0 KaMPKitiOS`KaMPKitiOS.BreedsViewController.toggleFavorite(__C.SharedBreed) -> () + 32 at ViewController.swift:83:5
(lldb)
小结 1:寄存器 fp
就像一个链表,可以将整个 Backtrace(函数调用栈) 进行串联
栈帧 lowering
通常情况下,我们的的代码会经过 llvm 的 栈帧 lowering 过程生成函数的 prolog(序章) 和 epilog (尾声) 。
以 llvm
对 arm64
架构的处理为例, AArch64FrameLowering.cpp
文件的 llvm::AArch64FrameLowering::emitPrologue
方法负责生成函数的 prologue
prolog(序章)
prolog(序言) 是函数起始部分的指令。
函数的初始化代码。分配堆栈空间、调用其他函数、保存非易失性寄存器或使用异常处理的每个函数都必须具有 prolog
epilog(尾声)
epilog (尾声) 是函数结束部分的指令。
每个函数在每次退出时会有一个 epilog ,每个函数通常只有一个 prolog,而可以有多个 epilog
。 Epilog
代码将堆栈剪裁为固定分配大小(如有必要),解除分配固定堆栈分配,通过从堆栈中弹出其保存的值来还原非易失性寄存器,然后返回。
注意:函数结束部分的指令不一定是 epilog
下面以 testA
和 testB
两个函数为例介绍 epilog (尾声)
KaMPKitiOS`testA:
0x1042ea288 <+0>: stp x29, x30, [sp, #-0x10]!
0x1042ea28c <+4>: mov x29, sp
-> 0x1042ea290 <+8>: bl 0x1042ea29c ; testB at TestOCInvokeKotlin.m:113
0x1042ea294 <+12>: ldp x29, x30, [sp], #0x10
0x1042ea298 <+16>: ret
KaMPKitiOS`testB:
0x1042ea29c <+0>: stp x29, x30, [sp, #-0x10]!
0x1042ea2a0 <+4>: mov x29, sp
-> 0x1042ea2a4 <+8>: bl 0x1042ea2b0 ; testC at TestOCInvokeKotlin.m:117
0x1042ea2a8 <+12>: ldp x29, x30, [sp], #0x10
0x1042ea2ac <+16>: ret
两个函数的前两行是 prolog
,会保存寄存器 x29/fp
、x30/lr
并更新 sp
和 x29/fp
寄存器的内容:
-
stp x29, x30, [sp, #-0x10]!
会先将sp
减去0x10
;随后,会将寄存器x29
和x30
存储到sp
指向的位置 -
mov x29, sp
等价于$x29 = $sp
这里留一个小作业,有兴趣的读者可以结合前面的两个栈内存 分析一下
testC
的 prolog。
两个函数的后两行是 epilog
:
-
ldp x29, x30, [sp], #0x10
会恢复寄存器x29/fp
、x30/lr
并更新sp
寄存器 -
ret
表示返回,该指令执行后lr
寄存器保存的位置开始执行
小结 2 : prolog
会保存寄存器 x29/fp
、x30/lr
并更新 sp
和 x29/fp
寄存器的内容
bl 指令 与 编译器优化
本节会先简单介绍 bl
指令的用法,并介绍编译器优化对 Backtrace(函数调用栈) 的影响。
bl 指令
bl
会在更新 lr
寄存器的同时进行跳转。
该指令会执行两个任务:
- 将返回地址存放到链接寄存器中
- 将 pc 设置为子例程的地址
以 testB
为例:
寄存器 lr
的值会更新为 0x1042ea2a8
(bl 的下一个指令),然后从 0x1042ea2b0
开始执行
-> 0x1042ea2a4 <+8>: bl 0x1042ea2b0 ; testC at TestOCInvokeKotlin.m:117
0x1042ea2a8 <+12>: ldp x29, x30, [sp], #0x10
0x1042ea2ac <+16>: ret
除了 bl
指令外,还有很多用于调整的指令,比如 b
指令。
编译器优化
可能读者有些奇怪为什么前文会多次强调 带链接的跳转
指令。
现在,我们用具体的例子看看编译器优化对 Backtrace(函数调用栈) 的影响
指令精简
-
首先,需要在
Build Settings
开启Os
级别的编译优化 -
强制关闭编译器对
testA
和testB
的内联优化
__attribute__((__noinline__))
void testA() {
testB();
}
__attribute__((__noinline__))
void testB() {
testC();
}
- 重新运行 APP,我们可以看到两个函数的指令都被缩减到一个
b
指令
KaMPKitiOS`testA:
0x100792608 <+0>: b 0x10079260c ; testB at TestOCInvokeKotlin.m:114:5
KaMPKitiOS`testB:
-> 0x10079260c <+0>: b 0x100792610 ; testC at TestOCInvokeKotlin.m:117
通过打印 lr
寄存器的内容,我们可以注意到执行命令 b
以后, lr
寄存器不会被更新
通过 FastUnwind
获取的函数调用栈也会缺失 testA
和 testB
函数内联
现在,我们把 testA
和 testB
的 __attribute__((__noinline__))
修饰符移除并重新运行:
因为 testA
和 testB
的内容比较简单,编译器会直接在 dumpUnwind
调用 testC
函数。
经过函数内联优化后,通过 FastUnwind
获取的函数调用栈同样会缺失 testA
和 testB
小结 3:开启编译器优化后,会影响 Backtrace(函数调用栈) 的回溯
FastUnwind 机制原理小结
现在,我们再强调一下本节的内容:
FastUnwind 实现原理依赖以下两个机制:
- 编译器或者开发者在 prolog 阶段按照规则保证相关的
lr
信息 - 带链接的跳转指令(比如 arm64 的 bl 指令会更新
lr
)
Xcode 的 unwind 机制
前面通过介绍 FastUnwind 的实现原理,并介绍了两种可能导致栈帧缺失的原因:指令精简和函数内联。
现在,我们看看为什么 Xcode 可以展示缺失的堆栈。
Xcode 与 lldb
因为从 Xcode 5 1 开始,Xcode 不再支持 LLVM-GCC 编译器和 GDB 调试器。所以,我们本文只介绍 lldb 调试器。
lldb
是一款
Call Frame Information (CFI)
CFA - Canonical Frame Address, is the address of the stack pointer just before a call instruction is executed.
FDE - Frame Descriptor Entries are unique to each section and holds the CFI information in eh_frame section
CIE - Common Information Entries that hold information that is common to multiple FDEs in eh_frame section.
https://reviews.llvm.org/D79978
我们重点看一下前面的几行代码:
classDiagram
class frame_data{
frame_data frame_addr_next
frame_data_addr_t ret_addr
}
lldb
因为 Xcode
Got compact unwind encoding 0x52160000 for function objc2kotlin.138
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 73.1 74.1
* frame #0: 0x00000001006d2b55 LLDB`lldb_private::CompactUnwindInfo::GetUnwindPlan(this=0x0000000117cd60e0, target=0x0000000118875a00, addr=Address @ 0x00007ffeefbfd8f8, unwind_plan=0x000000011bca0510) at CompactUnwindInfo.cpp:195:7 [opt]
frame #1: 0x00000001006dfbc7 LLDB`lldb_private::FuncUnwinders::GetCompactUnwindUnwindPlan(this=0x0000000117a9ec40, target=0x0000000118875a00) at FuncUnwinders.cpp:94:27 [opt]
frame #2: 0x00000001006df1ed LLDB`lldb_private::FuncUnwinders::GetUnwindPlanAtCallSite(this=0x0000000117a9ec40, target=0x0000000118875a00, thread=0x0000000117e3d528) at FuncUnwinders.cpp:72:30 [opt]
frame #3: 0x000000010074230f LLDB`lldb_private::RegisterContextUnwind::GetFullUnwindPlanForFrame(this=0x0000000117e74430) at RegisterContextUnwind.cpp:906:41 [opt]
frame #4: 0x00000001007401aa LLDB`lldb_private::RegisterContextUnwind::InitializeNonZerothFrame(this=0x0000000117e74430) at RegisterContextUnwind.cpp:548:29 [opt]
frame #5: 0x000000010073e8fe LLDB`lldb_private::RegisterContextUnwind::RegisterContextUnwind(this=0x0000000117e74430, thread=0x0000000117e3d528, next_frame=std::__1::shared_ptr<lldb_private::RegisterContextUnwind>::element_type @ 0x00000001179a22a0 strong=1 weak=2, sym_ctx=0x0000000117e74920, frame_number=6, unwind_lldb=0x0000000117c38350) at RegisterContextUnwind.cpp:70:5 [opt]
frame #6: 0x00000001007dac8e LLDB`lldb_private::UnwindLLDB::GetOneMoreFrame(this=0x0000000117c38350, abi=0x0000000117c383f0) at UnwindLLDB.cpp:128:40 [opt]
frame #7: 0x00000001007da4eb LLDB`lldb_private::UnwindLLDB::AddOneMoreFrame(this=0x0000000117c38350, abi=0x0000000117c383f0) at UnwindLLDB.cpp:345:23 [opt]
frame #8: 0x00000001007db1ff LLDB`lldb_private::UnwindLLDB::DoGetFrameInfoAtIndex(this=0x0000000117c38350, idx=5, cfa=0x00007ffeefbfe078, pc=0x00007ffeefbfe070, behaves_like_zeroth_frame=0x00007ffeefbfe097) at UnwindLLDB.cpp:402:36 [opt]
frame #9: 0x0000000100753763 LLDB`lldb_private::StackFrameList::GetFramesUpTo(unsigned int) [inlined] lldb_private::Unwind::GetFrameInfoAtIndex(this=0x0000000117c38350, frame_idx=<unavailable>, cfa=0x00007ffeefbfe078, pc=0x00007ffeefbfe070, behaves_like_zeroth_frame=0x00007ffeefbfe097) at Unwind.h:53:12 [opt]
frame #10: 0x0000000100753742 LLDB`lldb_private::StackFrameList::GetFramesUpTo(this=0x0000000117c402d8, end_idx=<unavailable>) at StackFrameList.cpp:502 [opt]
frame #11: 0x0000000100755467 LLDB`lldb_private::StackFrameList::GetFrameAtIndex(this=0x0000000117c402d8, idx=<unavailable>) at StackFrameList.cpp:678:3 [opt]
frame #12: 0x0000000100755f8a LLDB`lldb_private::StackFrameList::GetStatus(this=<unavailable>, strm=0x00007ffeefbfe978, first_frame=<unavailable>, num_frames=<unavailable>, show_frame_info=true, num_frames_with_source=0, show_unique=<unavailable>, selected_frame_marker="* ") at StackFrameList.cpp:989:16 [opt]
frame #13: 0x00000001007bb8be LLDB`lldb_private::Thread::GetStatus(this=0x0000000117e3d528, strm=0x00007ffeefbfe978, start_frame=0, num_frames=4294967295, num_frames_with_source=0, stop_format=<unavailable>, only_stacks=<unavailable>) at Thread.cpp:1814:45 [opt]
frame #14: 0x0000000100c75b06 LLDB`CommandObjectThreadBacktrace::HandleOneThread(this=0x0000000117927e60, tid=271703, result=0x00007ffeefbfe978) at CommandObjectThread.cpp:361:18 [opt]
frame #15: 0x0000000100c756e8 LLDB`CommandObjectIterateOverThreads::DoExecute(this=0x0000000117927e60, command=0x00007ffeefbfe498, result=0x00007ffeefbfe978) at CommandObjectThread.cpp:85:23 [opt]
frame #16: 0x00000001006a90ea LLDB`lldb_private::CommandObjectParsed::Execute(this=<unavailable>, args_string=<unavailable>, result=0x00007ffeefbfe978) at CommandObject.cpp:993:19 [opt]
frame #17: 0x00000001006a0678 LLDB`lldb_private::CommandInterpreter::HandleCommand(this=0x00000001179098b0, command_line=<unavailable>, lazy_add_to_history=eLazyBoolNo, result=0x00007ffeefbfe978, override_context=0x0000000117909a90, repeat_on_empty_command=<unavailable>, no_context_switching=<unavailable>) at CommandInterpreter.cpp:1812:14 [opt]
frame #18: 0x00000001006aa905 LLDB`lldb_private::CommandObjectRegexCommand::DoExecute(this=<unavailable>, command=(Data = <no value available>, Length = 0), result=0x00007ffeefbfe978) at CommandObjectRegexCommand.cpp:57:28 [opt]
frame #19: 0x00000001006a92d2 LLDB`lldb_private::CommandObjectRaw::Execute(this=0x0000000117947460, args_string="", result=0x00007ffeefbfe978) at CommandObject.cpp:1015:17 [opt]
frame #20: 0x00000001006a0678 LLDB`lldb_private::CommandInterpreter::HandleCommand(this=0x00000001179098b0, command_line=<unavailable>, lazy_add_to_history=eLazyBoolNo, result=0x00007ffeefbfe978, override_context=0x0000000117909a90, repeat_on_empty_command=<unavailable>, no_context_switching=<unavailable>) at CommandInterpreter.cpp:1812:14 [opt]
frame #21: 0x00000001006a3a42 LLDB`lldb_private::CommandInterpreter::IOHandlerInputComplete(this=0x00000001179098b0, io_handler=0x0000000117c39058, line=<unavailable>) at CommandInterpreter.cpp:2850:3 [opt]
frame #22: 0x00000001005e2a32 LLDB`lldb_private::IOHandlerEditline::Run(this=0x0000000117c39058) at IOHandler.cpp:562:22 [opt]
frame #23: 0x00000001005c85af LLDB`lldb_private::Debugger::RunIOHandlers(this=0x0000000117908fc0) at Debugger.cpp:866:16 [opt]
frame #24: 0x00000001006a4cde LLDB`lldb_private::CommandInterpreter::RunCommandInterpreter(this=0x00000001179098b0, options=0x00007ffeefbfecb0) at CommandInterpreter.cpp:3089:16 [opt]
frame #25: 0x00000001003984d9 LLDB`lldb::SBDebugger::RunCommandInterpreter(this=0x00007ffeefbff178, auto_handle_events=<unavailable>, spawn_thread=<unavailable>) at SBDebugger.cpp:1178:42 [opt]
frame #26: 0x000000010000568e lldb`Driver::MainLoop(this=<unavailable>) at Driver.cpp:675:18 [opt]
frame #27: 0x0000000100006fb0 lldb`main(argc=<unavailable>, argv=<unavailable>) at Driver.cpp:932:26 [opt]
frame #28: 0x00007fff68079cc9 libdyld.dylib`start + 1
frame #29: 0x00007fff68079cc9 libdyld.dylib`start + 1
(lldb)
lldb) p this->m_section_sp.__ptr_->m_parent_wp.__ptr_->m_name.m_string
(const char *) $8 = 0x000000011901ef38 "__TEXT"
(lldb) p this->m_section_sp.__ptr_->m_name.m_string
(const char *) $9 = 0x00000001190fb530 "__eh_frame"
(lldb) p this->m_objfile.m_module_wp.__ptr_->m_file.m_filename
(lldb_private::ConstString) $10 = (m_string = "shared")
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 70.1
* frame #0: 0x00000001006dcef4 LLDB`lldb_private::DWARFCallFrameInfo::GetCFIData(this=0x000000011bb348c0) at DWARFCallFrameInfo.cpp:399:14 [opt]
frame #1: 0x00000001006dc3f4 LLDB`lldb_private::DWARFCallFrameInfo::GetFDEIndex(this=0x000000011bb348c0) at DWARFCallFrameInfo.cpp:435:5 [opt]
frame #2: 0x00000001006dae45 LLDB`lldb_private::DWARFCallFrameInfo::GetFirstFDEEntryInRange(this=0x000000011bb348c0, range=0x0000000117837398) at DWARFCallFrameInfo.cpp:199:3 [opt]
frame #3: 0x00000001006dadb1 LLDB`lldb_private::DWARFCallFrameInfo::GetUnwindPlan(this=0x000000011bb348c0, range=0x0000000117837398, unwind_plan=0x000000011783a2b8) at DWARFCallFrameInfo.cpp:167:50 [opt]
frame #4: 0x00000001006df9b9 LLDB`lldb_private::FuncUnwinders::GetEHFrameUnwindPlan(this=0x0000000117837390, target=<unavailable>) at FuncUnwinders.cpp:136:22 [opt]
frame #5: 0x00000001006df1a8 LLDB`lldb_private::FuncUnwinders::GetUnwindPlanAtCallSite(this=0x0000000117837390, target=0x0000000119128200, thread=0x0000000117b61178) at FuncUnwinders.cpp:70:30 [opt]
frame #6: 0x000000010074230f LLDB`lldb_private::RegisterContextUnwind::GetFullUnwindPlanForFrame(this=0x0000000117a5ce50) at RegisterContextUnwind.cpp:906:41 [opt]
frame #7: 0x00000001007401aa LLDB`lldb_private::RegisterContextUnwind::InitializeNonZerothFrame(this=0x0000000117a5ce50) at RegisterContextUnwind.cpp:548:29 [opt]
frame #8: 0x000000010073e8fe LLDB`lldb_private::RegisterContextUnwind::RegisterContextUnwind(this=0x0000000117a5ce50, thread=0x0000000117b61178, next_frame=std::__1::shared_ptr<lldb_private::RegisterContextUnwind>::element_type @ 0x000000011bb2c2e0 strong=1 weak=2, sym_ctx=0x0000000117a5cd90, frame_number=6, unwind_lldb=0x0000000119c211f0) at RegisterContextUnwind.cpp:70:5 [opt]
frame #9: 0x00000001007dac8e LLDB`lldb_private::UnwindLLDB::GetOneMoreFrame(this=0x0000000119c211f0, abi=0x0000000119c21150) at UnwindLLDB.cpp:128:40 [opt]
frame #10: 0x00000001007da4eb LLDB`lldb_private::UnwindLLDB::AddOneMoreFrame(this=0x0000000119c211f0, abi=0x0000000119c21150) at UnwindLLDB.cpp:345:23 [opt]
frame #11: 0x00000001007db1ff LLDB`lldb_private::UnwindLLDB::DoGetFrameInfoAtIndex(this=0x0000000119c211f0, idx=5, cfa=0x00007ffeefbfe078, pc=0x00007ffeefbfe070, behaves_like_zeroth_frame=0x00007ffeefbfe097) at UnwindLLDB.cpp:402:36 [opt]
frame #12: 0x0000000100753763 LLDB`lldb_private::StackFrameList::GetFramesUpTo(unsigned int) [inlined] lldb_private::Unwind::GetFrameInfoAtIndex(this=0x0000000119c211f0, frame_idx=<unavailable>, cfa=0x00007ffeefbfe078, pc=0x00007ffeefbfe070, behaves_like_zeroth_frame=0x00007ffeefbfe097) at Unwind.h:53:12 [opt]
frame #13: 0x0000000100753742 LLDB`lldb_private::StackFrameList::GetFramesUpTo(this=0x0000000117e148d8, end_idx=<unavailable>) at StackFrameList.cpp:502 [opt]
frame #14: 0x0000000100755467 LLDB`lldb_private::StackFrameList::GetFrameAtIndex(this=0x0000000117e148d8, idx=<unavailable>) at StackFrameList.cpp:678:3 [opt]
frame #15: 0x0000000100755f8a LLDB`lldb_private::StackFrameList::GetStatus(this=<unavailable>, strm=0x00007ffeefbfe978, first_frame=<unavailable>, num_frames=<unavailable>, show_frame_info=true, num_frames_with_source=0, show_unique=<unavailable>, selected_frame_marker="* ") at StackFrameList.cpp:989:16 [opt]
frame #16: 0x00000001007bb8be LLDB`lldb_private::Thread::GetStatus(this=0x0000000117b61178, strm=0x00007ffeefbfe978, start_frame=0, num_frames=4294967295, num_frames_with_source=0, stop_format=<unavailable>, only_stacks=<unavailable>) at Thread.cpp:1814:45 [opt]
frame #17: 0x0000000100c75b06 LLDB`CommandObjectThreadBacktrace::HandleOneThread(this=0x0000000117c9ab60, tid=134225, result=0x00007ffeefbfe978) at CommandObjectThread.cpp:361:18 [opt]
frame #18: 0x0000000100c756e8 LLDB`CommandObjectIterateOverThreads::DoExecute(this=0x0000000117c9ab60, command=0x00007ffeefbfe498, result=0x00007ffeefbfe978) at CommandObjectThread.cpp:85:23 [opt]
frame #19: 0x00000001006a90ea LLDB`lldb_private::CommandObjectParsed::Execute(this=<unavailable>, args_string=<unavailable>, result=0x00007ffeefbfe978) at CommandObject.cpp:993:19 [opt]
frame #20: 0x00000001006a0678 LLDB`lldb_private::CommandInterpreter::HandleCommand(this=0x0000000117c7c1f0, command_line=<unavailable>, lazy_add_to_history=eLazyBoolNo, result=0x00007ffeefbfe978, override_context=0x0000000117c7c3d0, repeat_on_empty_command=<unavailable>, no_context_switching=<unavailable>) at CommandInterpreter.cpp:1812:14 [opt]
frame #21: 0x00000001006aa905 LLDB`lldb_private::CommandObjectRegexCommand::DoExecute(this=<unavailable>, command=(Data = <no value available>, Length = 0), result=0x00007ffeefbfe978) at CommandObjectRegexCommand.cpp:57:28 [opt]
frame #22: 0x00000001006a92d2 LLDB`lldb_private::CommandObjectRaw::Execute(this=0x0000000117cba160, args_string="", result=0x00007ffeefbfe978) at CommandObject.cpp:1015:17 [opt]
frame #23: 0x00000001006a0678 LLDB`lldb_private::CommandInterpreter::HandleCommand(this=0x0000000117c7c1f0, command_line=<unavailable>, lazy_add_to_history=eLazyBoolNo, result=0x00007ffeefbfe978, override_context=0x0000000117c7c3d0, repeat_on_empty_command=<unavailable>, no_context_switching=<unavailable>) at CommandInterpreter.cpp:1812:14 [opt]
frame #24: 0x00000001006a3a42 LLDB`lldb_private::CommandInterpreter::IOHandlerInputComplete(this=0x0000000117c7c1f0, io_handler=0x0000000117e8a908, line=<unavailable>) at CommandInterpreter.cpp:2850:3 [opt]
frame #25: 0x00000001005e2a32 LLDB`lldb_private::IOHandlerEditline::Run(this=0x0000000117e8a908) at IOHandler.cpp:562:22 [opt]
frame #26: 0x00000001005c85af LLDB`lldb_private::Debugger::RunIOHandlers(this=0x0000000117c7b800) at Debugger.cpp:866:16 [opt]
frame #27: 0x00000001006a4cde LLDB`lldb_private::CommandInterpreter::RunCommandInterpreter(this=0x0000000117c7c1f0, options=0x00007ffeefbfecb0) at CommandInterpreter.cpp:3089:16 [opt]
frame #28: 0x00000001003984d9 LLDB`lldb::SBDebugger::RunCommandInterpreter(this=0x00007ffeefbff178, auto_handle_events=<unavailable>, spawn_thread=<unavailable>) at SBDebugger.cpp:1178:42 [opt]
frame #29: 0x000000010000568e lldb`Driver::MainLoop(this=<unavailable>) at Driver.cpp:675:18 [opt]
frame #30: 0x0000000100006fb0 lldb`main(argc=<unavailable>, argv=<unavailable>) at Driver.cpp:932:26 [opt]
frame #31: 0x00007fff68079cc9 libdyld.dylib`start + 1
frame #32: 0x00007fff68079cc9 libdyld.dylib`start + 1
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 22.1
* frame #0: 0x00000001005664c6 clang`llvm::AArch64FrameLowering::emitPrologue(this=<unavailable>, MF=<unavailable>, MBB=<unavailable>) const at AArch64FrameLowering.cpp:1505:9 [opt]
frame #1: 0x0000000100e6cc81 clang`(anonymous namespace)::PEI::runOnMachineFunction(llvm::MachineFunction&) at PrologEpilogInserter.cpp:1097:9 [opt]
frame #2: 0x0000000100e6cc36 clang`(anonymous namespace)::PEI::runOnMachineFunction(this=0x0000000110d04ec0, MF=<unavailable>) at PrologEpilogInserter.cpp:256 [opt]
frame #3: 0x0000000100d8c14d clang`llvm::MachineFunctionPass::runOnFunction(this=0x0000000110d04ec0, F=0x0000000110b196b8) at MachineFunctionPass.cpp:73:13 [opt]
frame #4: 0x00000001010a7cc1 clang`llvm::FPPassManager::runOnFunction(this=<unavailable>, F=0x0000000110b196b8) at LegacyPassManager.cpp:1516:27 [opt]
frame #5: 0x00000001010ad948 clang`llvm::FPPassManager::runOnModule(this=0x0000000110e44a30, M=<unavailable>) at LegacyPassManager.cpp:1552:16 [opt]
frame #6: 0x00000001010a831f clang`llvm::legacy::PassManagerImpl::run(llvm::Module&) at LegacyPassManager.cpp:1617:27 [opt]
frame #7: 0x00000001010a8079 clang`llvm::legacy::PassManagerImpl::run(this=<unavailable>, M=0x0000000110b13510) at LegacyPassManager.cpp:614 [opt]
frame #8: 0x0000000101a6e59f clang`clang::EmitBackendOutput(clang::DiagnosticsEngine&, clang::HeaderSearchOptions const&, clang::CodeGenOptions const&, clang::TargetOptions const&, clang::LangOptions const&, llvm::DataLayout const&, llvm::Module*, clang::BackendAction, std::__1::unique_ptr<llvm::raw_pwrite_stream, std::__1::default_delete<llvm::raw_pwrite_stream> >) at BackendUtil.cpp:979:19 [opt]
frame #9: 0x0000000101a6ce7e clang`clang::EmitBackendOutput(Diags=<unavailable>, HeaderOpts=0x0000000110e2e700, CGOpts=<unavailable>, TOpts=0x0000000000000000, LOpts=0x0000000000000000, TDesc=0x0000000110e336c0, M=0x0000000110b13510, Action=Backend_EmitAssembly, OS=llvm::raw_pwrite_stream @ 0x00007ffeefbfc730) at BackendUtil.cpp:1692 [opt]
frame #10: 0x0000000101d22c73 clang`clang::CodeGenAction::ExecuteAction(this=0x0000000110e316a0) at CodeGenAction.cpp:1173:5 [opt]
frame #11: 0x0000000101fe6764 clang`clang::FrontendAction::Execute(this=0x0000000110e2f530) at FrontendAction.cpp:956:8 [opt]
frame #12: 0x0000000101f8e193 clang`clang::CompilerInstance::ExecuteAction(this=0x0000000110e2d120, Act=0x0000000110e2f530) at CompilerInstance.cpp:1007:33 [opt]
frame #13: 0x000000010205a41a clang`clang::ExecuteCompilerInvocation(Clang=<unavailable>) at ExecuteCompilerInvocation.cpp:284:25 [opt]
frame #14: 0x000000010000420b clang`cc1_main(Argv=ArrayRef<const char *> @ 0x00007fd1d5bd6bd0, Argv0=<unavailable>, MainAddr=0x000000010000df20) at cc1_main.cpp:240:15 [opt]
frame #15: 0x0000000100010f16 clang`ExecuteCC1Tool(ArgV=<unavailable>) at driver.cpp:330:12 [opt]
frame #16: 0x0000000100010b53 clang`main(argc_=<unavailable>, argv_=<unavailable>) at driver.cpp:407:12 [opt]
frame #17: 0x00007fff6ee27cc9 libdyld.dylib`start + 1
(lldb)
参考文章
Canonical Frame Address
* thread #1, queue = ‘com.apple.main-thread’, stop reason = breakpoint 79.1
* frame #0: 0x00000001006e0a88 LLDB`lldb_private::CompactUnwindInfo::ScanIndex(this=0x0000000120c1f270, process_sp=std::__1::shared_ptr<lldb_private::Process>::element_type @ 0x0000000119879c18 strong=6 weak=22) at CompactUnwindInfo.cpp:256:5
frame #1: 0x00000001006dd285 LLDB`lldb_private::CompactUnwindInfo::IsValid(this=0x0000000120c1f270, process_sp=std::__1::shared_ptr<lldb_private::Process>::element_type @ 0x0000000119879c18 strong=6 weak=22) at CompactUnwindInfo.cpp:239:3
frame #2: 0x00000001006dcca1 LLDB`lldb_private::CompactUnwindInfo::GetUnwindPlan(this=0x0000000120c1f270, target=0x0000000119873000, addr=Address @ 0x00007ffeefbfd8e8, unwind_plan=0x000000011813eae0) at CompactUnwindInfo.cpp:174:8
frame #3: 0x00000001007061d4 LLDB`lldb_private::FuncUnwinders::GetCompactUnwindUnwindPlan(this=0x000000011a5b7d60, target=0x0000000119873000) at FuncUnwinders.cpp:94:27
frame #4: 0x0000000100705790 LLDB`lldb_private::FuncUnwinders::GetUnwindPlanAtCallSite(this=0x000000011a5b7d60, target=0x0000000119873000, thread=0x000000011a525358) at FuncUnwinders.cpp:72:30
frame #5: 0x00000001007dcb0f LLDB`lldb_private::RegisterContextUnwind::GetFullUnwindPlanForFrame(this=0x0000000120c23350) at RegisterContextUnwind.cpp:906:41 [opt]
frame #6: 0x00000001007da9aa LLDB`lldb_private::RegisterContextUnwind::InitializeNonZerothFrame(this=0x0000000120c23350) at RegisterContextUnwind.cpp:548:29 [opt]
frame #7: 0x00000001007d90fe LLDB`lldb_private::RegisterContextUnwind::RegisterContextUnwind(this=0x0000000120c23350, thread=0x000000011a525358, next_frame=std::__1::shared_ptr<lldb_private::RegisterContextUnwind>::element_type @ 0x0000000120c225e0 strong=1 weak=2, sym_ctx=0x0000000120c21d00, frame_number=6, unwind_lldb=0x000000011861ab00) at RegisterContextUnwind.cpp:70:5 [opt]
frame #8: 0x000000010087548e LLDB`lldb_private::UnwindLLDB::GetOneMoreFrame(this=0x000000011861ab00, abi=0x000000011863cc10) at UnwindLLDB.cpp:128:40 [opt]
frame #9: 0x0000000100874ceb LLDB`lldb_private::UnwindLLDB::AddOneMoreFrame(this=0x000000011861ab00, abi=0x000000011863cc10) at UnwindLLDB.cpp:345:23 [opt]
frame #10: 0x00000001008759ff LLDB`lldb_private::UnwindLLDB::DoGetFrameInfoAtIndex(this=0x000000011861ab00, idx=5, cfa=0x00007ffeefbfe088, pc=0x00007ffeefbfe080, behaves_like_zeroth_frame=0x00007ffeefbfe0a7) at UnwindLLDB.cpp:402:36 [opt]
frame #11: 0x00000001007edf63 LLDB`lldb_private::StackFrameList::GetFramesUpTo(unsigned int) [inlined] lldb_private::Unwind::GetFrameInfoAtIndex(this=0x000000011861ab00, frame_idx=, cfa=0x00007ffeefbfe088, pc=0x00007ffeefbfe080, behaves_like_zeroth_frame=0x00007ffeefbfe0a7) at Unwind.h:53:12 [opt]
frame #12: 0x00000001007edf42 LLDB`lldb_private::StackFrameList::GetFramesUpTo(this=0x0000000120c06df8, end_idx=) at StackFrameList.cpp:502 [opt]
frame #13: 0x00000001007efc67 LLDB`lldb_private::StackFrameList::GetFrameAtIndex(this=0x0000000120c06df8, idx=) at StackFrameList.cpp:678:3 [opt]
frame #14: 0x00000001007f078a LLDB`lldb_private::StackFrameList::GetStatus(this=, strm=0x00007ffeefbfe988, first_frame=, num_frames=, show_frame_info=true, num_frames_with_source=0, show_unique=, selected_frame_marker="* “) at StackFrameList.cpp:989:16 [opt]
frame #15: 0x00000001008560be LLDB`lldb_private::Thread::GetStatus(this=0x000000011a525358, strm=0x00007ffeefbfe988, start_frame=0, num_frames=4294967295, num_frames_with_source=0, stop_format=, only_stacks=) at Thread.cpp:1814:45 [opt]
frame #16: 0x0000000100d0f8d6 LLDB`CommandObjectThreadBacktrace::HandleOneThread(this=0x0000000118234800, tid=1645774, result=0x00007ffeefbfe988) at CommandObjectThread.cpp:361:18 [opt]
frame #17: 0x0000000100d0f4b8 LLDB`CommandObjectIterateOverThreads::DoExecute(this=0x0000000118234800, command=0x00007ffeefbfe4a8, result=0x00007ffeefbfe988) at CommandObjectThread.cpp:85:23 [opt]
frame #18: 0x00000001006a98fa LLDB`lldb_private::CommandObjectParsed::Execute(this=, args_string=, result=0x00007ffeefbfe988) at CommandObject.cpp:993:19 [opt]
frame #19: 0x00000001006a0e88 LLDB`lldb_private::CommandInterpreter::HandleCommand(this=0x000000011860fa10, command_line=, lazy_add_to_history=eLazyBoolNo, result=0x00007ffeefbfe988, override_context=0x000000011860fbf0, repeat_on_empty_command=, no_context_switching=) at CommandInterpreter.cpp:1812:14 [opt]
frame #20: 0x00000001006ab115 LLDB`lldb_private::CommandObjectRegexCommand::DoExecute(this=, command=(Data = , Length = 0), result=0x00007ffeefbfe988) at CommandObjectRegexCommand.cpp:57:28 [opt]
frame #21: 0x00000001006a9ae2 LLDB`lldb_private::CommandObjectRaw::Execute(this=0x0000000118253e00, args_string="”, result=0x00007ffeefbfe988) at CommandObject.cpp:1015:17 [opt]
frame #22: 0x00000001006a0e88 LLDB`lldb_private::CommandInterpreter::HandleCommand(this=0x000000011860fa10, command_line=, lazy_add_to_history=eLazyBoolNo, result=0x00007ffeefbfe988, override_context=0x000000011860fbf0, repeat_on_empty_command=, no_context_switching=) at CommandInterpreter.cpp:1812:14 [opt]
frame #23: 0x00000001006a4252 LLDB`lldb_private::CommandInterpreter::IOHandlerInputComplete(this=0x000000011860fa10, io_handler=0x000000011a526cf8, line=) at CommandInterpreter.cpp:2850:3 [opt]
frame #24: 0x00000001005e2a92 LLDB`lldb_private::IOHandlerEditline::Run(this=0x000000011a526cf8) at IOHandler.cpp:562:22 [opt]
frame #25: 0x00000001005c860f LLDB`lldb_private::Debugger::RunIOHandlers(this=0x000000011860eec0) at Debugger.cpp:866:16 [opt]
frame #26: 0x00000001006a54ee LLDB`lldb_private::CommandInterpreter::RunCommandInterpreter(this=0x000000011860fa10, options=0x00007ffeefbfecc0) at CommandInterpreter.cpp:3089:16 [opt]
frame #27: 0x0000000100398c79 LLDB`lldb::SBDebugger::RunCommandInterpreter(this=0x00007ffeefbff188, auto_handle_events=, spawn_thread=) at SBDebugger.cpp:1178:42 [opt]
frame #28: 0x000000010000568e lldb`Driver::MainLoop(this=) at Driver.cpp:675:18 [opt]
frame #29: 0x0000000100006fb0 lldb`main(argc=, argv=) at Driver.cpp:932:26 [opt]
frame #30: 0x00007fff7066bcc9 libdyld.dylib`start + 1
frame #31: 0x00007fff7066bcc9 libdyld.dylib`start + 1
graph TD
main
subgraph Driver
MainLoop
end
subgraph LLDB
subgraph lldb::SBDebugger
RunCommandInterpreter
end
subgraph CommandObjectIterateOverThreads
DoExecute2["DoExecute"]
end
subgraph lldb_private
subgraph CommandInterpreter
RunCommandInterpreter2["RunCommandInterpreter"]
IOHandlerInputComplete
HandleCommand
end
subgraph Debugger
RunIOHandlers
end
subgraph IOHandlerEditline::Run
Run
end
subgraph CommandObjectRaw
Execute
end
subgraph CommandObjectRegexCommand
DoExecute
end
subgraph CommandObjectParsed
Execute2["Execute"]
end
subgraph Thread
GetStatus
end
subgraph StackFrameList
GetStatus2[GetStatus]-->
GetFrameAtIndex-->
GetFramesUpTo
end
subgraph unwind
GetFrameInfoAtIndex
end
subgraph UnwindLLDB
DoGetFrameInfoAtIndex-->
AddOneMoreFrame-->
GetOneMoreFrame
end
subgraph RegisterContextUnwind
RegisterContextUnwind1[RegisterContextUnwind]-->
InitializeNonZerothFrame-->
GetFullUnwindPlanForFrame
end
subgraph FuncUnwinders
GetUnwindPlanAtCallSite-->GetEHFrameUnwindPlan
GetUnwindPlanAtCallSite-->GetCompactUnwindUnwindPlan
end
subgraph CompactUnwindInfo
GetUnwindPlan-->
IsValid-->
ScanIndex
end
subgraph DWARFCallFrameInfo
GetUnwindPlan-->GetFirstFDEEntryInRange-->GetFDEIndex-->GetCFIData
end
end
subgraph CommandObjectThreadBacktrace
HandleOneThread
end
DoExecute2-->HandleOneThread-->GetStatus-->GetStatus2
GetFramesUpTo--2.开始解析帧信息-->GetFrameInfoAtIndex-->DoGetFrameInfoAtIndex
GetOneMoreFrame-->RegisterContextUnwind1
GetFullUnwindPlanForFrame-->GetUnwindPlanAtCallSite
GetEHFrameUnwindPlan-->GetUnwindPlan
GetCompactUnwindUnwindPlan-->GetUnwindPlan
end
main-->MainLoop--开始处理交互式命令-->RunCommandInterpreter-->RunCommandInterpreter2
-->RunIOHandlers-->Run-->IOHandlerInputComplete-->HandleCommand
-->Execute-->DoExecute["DoExecute(bt 会被转为 thread backtrace)"]-->HandleCommand-->Execute2-->DoExecute2
Debugger
Provides a global root objects for the debugger core.
https://lldb.llvm.org/cpp_reference/classlldb__private_1_1IOHandlerEditline.html https://lldb.llvm.org/cpp_reference/classlldb__private_1_1CommandInterpreter.html