【问题标题】:incomplete backtrace in logcatlogcat 中不完整的回溯
【发布时间】:2013-07-13 20:17:38
【问题描述】:

当我的 Android 应用程序崩溃(或遇到断言)时,我得到的回溯行数永远不会超过四行。搜索类似问题时,我只发现一两个地方提到了这一点,并且库存响应是:“确保它是一个调试版本”和“你可能有堆栈损坏”。我已经看到许多地方发生了许多崩溃,框架看起来准确且没有损坏的证据。

这是在调试构建中断言失败后从“adb logcat”中摘录的典型摘录:

I/DEBUG   (  187):     d28 3f824fc6ced25306  d29 3fabdfebb8fe14dc
I/DEBUG   (  187):     d30 fff0000000000000  d31 fffffffeffffffd2
I/DEBUG   (  187):     scr 88000010
I/DEBUG   (  187): 
I/DEBUG   (  187): backtrace:
I/DEBUG   (  187):     #00  pc 00018516  /system/lib/libc.so
I/DEBUG   (  187):     #01  pc 0000dc44  /system/lib/libc.so (abort+4)
I/DEBUG   (  187):     #02  pc 0000168d  /system/lib/liblog.so (__android_log_assert+88)
I/DEBUG   (  187):     #03  pc 00170bcc  /data/data/com.jsam.crag/lib/libmain.so (sim::TouchObserverController::HandleEvent(SDL_Event const&)+340)
I/DEBUG   (  187): 
I/DEBUG   (  187): stack:
I/DEBUG   (  187):          6f4be770  6f4be76c  [stack:17025]
I/DEBUG   (  187):          6f4be774  00000000  
I/DEBUG   (  187):          6f4be778  00000000  

如您所见,大多数可用的回溯甚至不在我自己的代码中。我正在开发具有开箱即用操作系统的开发人员版 HTC One,使用 NDK 的 8e 版并针对 android-10 构建,尽管 android-15 也不例外。我正在使用工具链 v4.7,gnustl_static STL 和我的 C++ 标志是:

-std=c++11 -g -pthread -DPROFILE -D__STRICT_ANSI__ -DdSINGLE -Wall -Wextra -Wfatal-errors -fno-rtti -fno-exceptions

我将如何获得更长(最好是完整)的回溯?

【问题讨论】:

    标签: android c++ android-ndk


    【解决方案1】:

    您可以使用 gdb 在 android 上进行本机应用程序调试,请参阅 Generate core dump in android

    这可以为您提供更多信息,而不仅仅是堆栈跟踪。

    【讨论】:

    • 谢谢。这在调试应用程序时非常有用,但如果在我附加调试器之前它已经崩溃,我认为 logcat 是我唯一的信息来源。 (如果 Android 应用程序转储出核心文件,我会感到非常惊讶。)
    • 在另一个主题中(现在找不到链接)有说明,如果您使用 ulimit -c unlimited 的模拟,则在 root 设备上运行控制台应用程序核心转储有效。但是如果涉及到核心转储的java代码不起作用,这可能是因为java运行时在某处禁用它。
    • 谢谢。尽管我很确定我的两部手机都已解锁并且只有一部有此限制,但我会对此进行调查。
    • 谢谢,我会调查一下,虽然我很确定我的两部手机都已解锁,但只有一部手机在运行相同的二进制文件时有此限制。
    【解决方案2】:

    调试器堆栈跟踪机制使用异常展开机制来向上遍历树。这是通过 gcc -funwind-tables 参数启用的。

    gdb 忽略这些并使用自己的机制,该机制依赖于反汇编代码来确定返回值在堆栈中的位置。这通常适用于 gcc 生成的代码,但可能会让人感到困惑。有时 gdb 或 debuggerd 将能够解码另一个无法解码的堆栈跟踪。

    (编辑:更多注释)

    基本问题是编译器被配置为生成不使用帧指针的代码。调用者将返回地址放入 LR 寄存器,完成后被调用函数跳转到该地址。 LR 是一个通用寄存器,因此通常会将其溢出到堆栈并在返回之前将其恢复。遍历堆栈的代码需要判断它是否被溢出,如果是,在堆栈的哪个位置可以找到它。

    由于某种原因,debuggerd 似乎不认为它可以遍历堆栈更远。一个原因是缺少展开信息。

    【讨论】:

    • 感谢您的信息。我确实尝试添加 -funwind-tables ,但没有任何明显的区别。 debuggerd(或任何产生用 logcat 找到的信息的东西)似乎完全没有问题象征堆栈的前四行;它始终打印四行准确信息,仅此而已。它看起来像某个地方,信息被故意设置上限 - 可能是为了节省记录器的输出。
    • (我在答案中添加了更多细节。)调试器中有一个上限,但它设置为 32 帧。尝试删除-fno-exceptions,或者确保在-funwind-tables 之前指定它。我想知道无异常是否会禁用表生成。
    • 删除 -fno-exceptions 并添加 -funwind-table 似乎没有什么不同。我注意到从ndk-gdb 发出bt 现在会产生不好的结果,例如#3 0x400c3690 in ?? ()。此外,我在 Nexus One(使用 CyanogenMod)上创建了相同的崩溃,并获得了一个完整但混乱的堆栈,其函数名称为:_ZN3sim23TouchObserverController11HandleEventERK9SDL_Event。所以我现在想知道是操作系统还是设备有问题。
    • 如果您有c++filt 工具,您可以粘贴名称以获取sim::TouchObserverController::HandleEvent(SDL_Event const&)。我认为addr2line 工具会为您完成清理工作(请参阅stackoverflow.com/questions/2314273/…)。设备是否运行不同版本的 Android? debuggerd 的实现随着时间的推移发生了变化(例如,libcorkscrew 的引入有几转)。
    • 是的,One 在 4.1.2 上,而 Nexus One 在 2.3.7 上。当我有机会时,我一定会尝试获取更多数据点。
    【解决方案3】:

    答案似乎是升级到 Android 4.3。我的手机今天收到了更新(自定义 HTC 版本推出到开发者版设备),转储到系统日志的回溯现在显示完整堆栈。然而,正如@user1034749 所建议的那样,掌握 GDB 是一个不错的选择,它有许多额外的好处。

    【讨论】:

    • 更新到 4.3 似乎对我没有帮助:/
    • @kotlinski 您在运行相同/不同的设备等吗?您是否也只看到四行?
    猜你喜欢
    • 1970-01-01
    • 2012-10-24
    • 1970-01-01
    • 1970-01-01
    • 2010-09-27
    • 1970-01-01
    • 2011-10-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多