我在项目中使用breakpad来处理崩溃并生成堆栈跟踪。 在堆栈跟踪中,stackwalker发现函数调用信息的方式有很多种。此处描述的流程Finding_the_caller_frame:
他们之间的区别是什么?更重要的是他们如何帮助调试?
Thread 0 (crashed)
0 test_google_breakpad!crash [test_breakpad.cpp : 17 + 0x4]
r4 = 0x00015530 r5 = 0xbea2cbe4 r6 = 0xffffff38 r7 = 0xbea2cb5c
r8 = 0x00000000 r9 = 0x00000000 r10 = 0x00000000 fp = 0x00000000
sp = 0xbea2cb50 lr = 0x00009025 pc = 0x00008f84
Found by: given as instruction pointer in context
1 test_google_breakpad!main [test_breakpad.cpp : 25 + 0x3]
r4 = 0x00015530 r5 = 0xbea2cbe4 r6 = 0xffffff38 r7 = 0xbea2cb5c
r8 = 0x00000000 r9 = 0x00000000 r10 = 0x00000000 fp = 0x00000000
sp = 0xbea2cb50 pc = 0x00009025
Found by: call frame info
2 libc.so + 0x164e5
r4 = 0x00008f64 r5 = 0xbea2cc34 r6 = 0x00000001 r7 = 0xbea2cc3c
r8 = 0x00000000 r9 = 0x00000000 r10 = 0x00000000 fp = 0x00000000
sp = 0xbea2cc18 pc = 0x400c34e7
Found by: call frame info
答案 0 :(得分:4)
指令指针方法意味着CPU寄存器已经指向函数的存储器位置,因此不需要搜索该函数。这是查找当前堆栈帧的最简单,最可靠的方法。
接下来使用调用帧技术,您可以通过查看存储返回地址的堆栈存储器中的位置来查找当前函数的调用者。这是"返回"的确切技术。会用来找到它的回归目的地。可以链接此技术,因为每个先前的调用也将其返回值放在堆栈上。这是非常可靠的,但如果某些堆栈内存损坏(可能是堆栈溢出,可能是错误的指针写入)并且一个或多个返回地址被删除,则可能会失败。
最后,最不可靠的技术是在堆栈内存中搜索看起来像函数地址的任何内容。这可以帮助您从损坏的堆栈中恢复,但是除了函数地址之外很难分辨数据(包括函数指针!),所以它的猜测。但是,如果找到一个,那么如果你发现一些没有被删除的堆栈,你通常可以链回到调用框架技术。