我在使用NDK的C++中有一些代码。当C++代码中发生崩溃(在设备上;而不是通过仿真器)时,我得到一个逻辑删除(崩溃转储),其中包含一个调用堆栈,该调用堆栈的深度始终为2级:

I/DEBUG   ( 5089): pid: 5048, tid: 5062  >>> com.example.site <<<
I/DEBUG   ( 5089):          #00  pc 0059e08c  /data/data/com.example.site/lib/libexample.so (_ZNK10MyNamespaceAPI11MyClass12GetDataEv)
I/DEBUG   ( 5089):          #01  lr 5bc9ef2c  /data/data/com.example.site/lib/libexample.so
I/DEBUG   ( 5089):     5cc6e764  5bce3070  /data/data/com.example.site/lib/libexample.so
I/DEBUG   ( 5089):     5cc6e774  5bce309c  /data/data/com.example.site/lib/libexample.so
I/DEBUG   ( 5089):     5cc6e784  5bce2af4  /data/data/com.example.site/lib/libexample.so
I/DEBUG   ( 5089):     5cc6e788  5c27ea9c  /data/data/com.example.site/lib/libexample.so

有没有一种方法可以配置我的应用程序或Android,以在打印到故障转储的调用堆栈中提供更多详细信息和深度?究竟是什么决定了这一点?我已经看到了一些示例,其中人们获得了多达15个级别的调用堆栈深度。

最佳答案

过去几年发展起来的回溯机制显示了能够找到的尽可能多的帧(IIRC的固定上限为32)。如果有什么阻止它进一步走到栈顶的地方,它将尽早停止。

ARM上的调用机制将返回地址放入链接寄存器(LR)中,但允许编译器将其溢出到堆栈中。对于“noreturn”功能,技术上根本不需要进行设置。有些汇编器伪操作会添加元数据,以帮助展开器弄清楚可以找到返回地址的位置,并且在较新的Android版本中应该都能正常工作。

当您获得两层深度的堆栈跟踪时,表示当前方法的展开失败,并且只能向您显示程序计数器(PC)的值以及恰好在LR中的值。

确保使用-g进行编译以启用调试。

失败的函数是否直接从JNI调用?在某些较旧的Android版本中,由于代码的结构方式,跟踪将在JNI调用桥处停止,尽管该问题已在Dalvik back in 2011中修复。不过,最近的设备使用Art,我希望它有不同的处理方式。

类似的问题here

07-24 09:46
查看更多