ndk 异常日志
模拟一个空指针的场景
arduino
void crash() {
int *p = nullptr;
*p = 1;
printf("p:%d \n", p);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_example_ndktest_JNIDynamicLoad_sayHello(JNIEnv *env, jobject thiz) {
crash();
}
我们在android studio 里看到的崩溃日志是
这里其实有一个技巧,java引发的crash 通常 会有dialog提示,而ne 引发的崩溃 则不会dialog提示,通常表现就是 直接进程退出了
碰到这种情况 我们第一时间应该用命令去查看对应的崩溃信息,as 这个ide里其实过滤掉了很多信息,对ne的查看其实不太方便
adb logcat以后 可以看出来 ne的崩溃信息 主要是三块
信号处理, 寄存器信息,以及 调用堆栈
符号表
ndk 其实本身build 是自带版本号的,多数情况下,我们不会修改这个版本号,下面的链接 可以查看你agp版本中自带的ndk版本号
developer.android.com/studio/proj...
像我这个demo工程就是agp8.1的版本
Library/Android/sdk/ndk/25.1.8937393
这个就是我们的ndk目录了
我们可以 找到我们的addr2line工具
Library/Android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/darwin-x86_64/bin
找到这个目录以后 我们就可以根据崩溃堆栈来定位到到底是哪行代码出的错了
./llvm-addr2line -e /app/build/intermediates/merged_native_libs/debug/out/lib/arm64-v8a/libdynamic-lib.so 00000000000189e0
最后一个参数 就是我们刚才崩溃堆栈中最顶部的那行
执行结果如下:
再看一下 果然是我们代码出错的地方
这里要注意了 strip过的so文件是没有符号表的
可以对比一下下面有没有符号表的体积差别
ndk-stack 命令
前面一小节的addr2line 在使用起来稍微有点麻烦
developer.android.com/ndk/guides/...
更推荐用ndk-stack 来解决
这个命令其实就在 Library/Android/sdk/ndk/25.1.8937393 下,其实内置的就是addr2line ,只不过用起来更方便了
./ndk-stack -sym /app/build/intermediates/merged_native_libs/debug/out/lib/arm64-v8a -dump /Users/11097719/Downloads/ne.txt
大家可以自行试一下 命令的执行结果
其他常用命令
readelf可以获取到 更多符号表的信息
./llvm-readelf -sW NdkTest/app/build/intermediates/merged_native_libs/debug/out/lib/arm64-v8a/libdynamic-lib.so > elfinfo.txt
objdump 也是常用命令之一,可以方便的查看 动态库依赖的信息
./llvm-objdump -p /app/build/intermediates/merged_native_libs/debug/out/lib/arm64-v8a/libdynamic-lib.so
如何搜索代码所在的so文件
比如你怎么知道要引用哪个so文件呢?例如我想调用某个系统的c代码,我搜索到以后 mk文件中怎么知道要链接哪个动态库?
最重要的就是查看Android.bp文件 这里面有重要的信息
我们可以去 cs.android.com/ 查看源码
比如你知道你要使用bitmap.h中的代码
那就直接查找bitmap.cpp的实现 都有哪里在用