Android使用addr2line分析Native Crash

NDK提供的工具将函数地址解析为具体的函数名和行数才能进一步分析问题。

常用的地址转换工具有addr2line、ndk-stack等,个人比较喜欢addr2line,所以接下来介绍下该工具的基本使用方式

日常使用过程中,只需要关注-C -f -e三个参数即可

// -C: Demangle函数名
// -f: 显示函数名
// -e: 带符号表的so路径

这里展开说说-C这个参数,我们知道C/C++语言在编译以后,函数的名字会被编译器修改为编译器内部识别的名字,该名字在链接的时候被用到。将C++源代码转换为C++ ABI标识符的过程称为mangle,相反的过程称为demangle

以Linux下的g++为例,每个方法都以_Z开头,比如_Z3foov就是函数foo(),v表示参数类型为void。从foo()转换为_Z3foov的过程被称为mangle,_Z3foov转换为foo()的过程被称为demangle。

其中NDK中的aarch64-linux-android-c++fil(和addr2line同一个目录)是专门用来支持Demangle的

新建一个带C++的Android Studio工程,主动创造一个native crash

启动app后如预期崩溃

抓到崩溃信息后,根据ABI找到相对应的addr2line工具和带符号表的so文件。

我们主要关注backtrace后面的信息,同时带"pc"和"/data"的行基本就是app相关的崩溃行了

除了最后一个是被strip了符号的so,前三个so文件都是可以的

终端中使用addr2line转换地址

aarch64-linux-android-addr2lin -C -f -e ${SO_PATH} ${Address} ${Address} ...

 

解析结果

定位到具体的函数名和行数后就可以进一步排查问题了

Crash堆栈解析脚本

日常工作或者学习中还是使用一个python脚本来解析带crash堆栈的文件比较方便

#!/usr/bin/python
import sys
import re
import os

ADDR2LINE_PATH ='your tool abs path'

if len(sys.argv) >= 3:
    SO_PATH = sys.argv[1]
    FILE_PATH = sys.argv[2]

CMD_BASE = ADDR2LINE_PATH + ' -C -f -e ' + SO_PATH + ' '
with open(FILE_PATH, 'r') as f:
    for line in f:
        crash = re.search('#[0-9]+ +pc +([0-9A-Fa-f]+) +/data', line)
        if crash is not None:
            addr = crash.groups(1)[0]
            cmd = CMD_BASE + addr
            res = os.popen(cmd).read()
            print(res)

使用效果

 

### App 运行时 Native Crash 的原因分析 Native Crash 是指应用程序在执行本地代码(通常是 C/C++ 编写的库)时发生的崩溃。这种类型的崩溃通常由内存访问违规或其他低级错误引起。以下是常见的 Native Crash 原因及其解决方案: #### 1. **内存管理问题** - **常见原因**: 内存泄漏、野指针访问、未初始化的指针操作或越界数组访问可能导致程序崩溃[^1]。 - **解决方案**: 使用调试工具如 AddressSanitizer 或 Valgrind 来检测内存问题并修复相关代码逻辑。 #### 2. **函数调用异常** - **常见原因**: 调用了不兼容的 API 函数或者传递了非法参数给本地方法[^3]。 - **解决方案**: 确保所有传入本地层的数据都经过严格验证,并遵循 ABI 和 API 文档中的规定。 #### 3. **动态链接库加载失败** - **常见原因**: .so 文件缺失、版本冲突或路径配置不当可能引发崩溃。 - **解决方案**: 验证 APK 中包含所需的共享对象文件 (.so),并通过日志确认它们被成功加载。 #### 4. **线程同步问题** - **常见原因**: 多线程环境下缺乏必要的锁机制,造成数据竞争条件 (data race)[^2]。 - **解决方案**: 应用互斥量 (mutex) 或其他并发控制技术来保护共享资源。 #### 5. **堆栈溢出** - **常见原因**: 局部变量占用过多空间或将大结构体作为函数返回值处理可能会耗尽栈容量。 - **解决方案**: 将大型数据分配至堆区而非栈区;优化递归算法以减少帧消耗。 --- ### 解决方案的具体实施步骤 为了更高效地定位和解决问题,建议按照以下方式操作: #### 工具辅助诊断 - 利用 `minidump_stackwalk` 提取 minidump 文件中的堆栈信息以便进一步排查。 ```bash /Applications/Android\ Studio.app/Contents/bin/lldb/bin/minidump_stackwalk dump_file.dmp symbols_dir/ ``` - 结合 `addr2line` 定位具体崩溃位置[^2]: ```bash arm-linux-androideabi-addr2line -C -f -s -e libyourlibrary.so 0x161a0 ``` 此命令会输出对应的源码文件名及行号,从而帮助开发者快速锁定问题区域。 #### 日志记录增强 增加详细的 logging 输出,在关键流程处打印状态消息,便于后续回溯事件链条。 --- ### 示例代码片段展示如何安全释放资源 下面是一个简单的例子演示如何避免由于忘记释放资源而导致的 crash: ```cpp #include <jni.h> #include <cstdlib> extern "C" JNIEXPORT void JNICALL Java_com_example_NativeLib_releaseResource(JNIEnv *env, jobject thiz){ static int* ptr = new int(42); // Simulate resource allocation delete ptr; // Ensure proper deallocation to prevent memory corruption } ``` 通过上述措施可有效降低 native crashes 发生概率。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薛文旺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值