Android studio中NDK开发(四)——使用addr2line分析Crash日志

一、前言

在NDK开发中经常会出现应用Crash的情况,而JNI层的报错信息,不像Java层报错信息那样可以直接在日志中看到错误的行数,JNI层中出现的错误直接看根本定位不到错误的位置。通常来说,JNI报的基本都是堆栈信息,需要NDK的一些工具进行地址转换,转换后即可看到错误的位置。这些地址转换的工具有addr2line、ndk-stack等,我比较喜欢addr2line,平时也用这个工具进行调试。

二、分析

错误信息如下:

  A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
  A/DEBUG: Build fingerprint: 'xiaomi/mido/mido:7.0/NRD90M/V10.1.1.0.NCFCNFI:user/release-keys'
  A/DEBUG: Revision: '0'
  A/DEBUG: ABI: 'arm'
  A/DEBUG: pid: 29290, tid: 29290, name: e.hasee.ndkdemo  >>> com.example.hasee.ndkdemo <<<
  A/DEBUG: signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
  A/DEBUG:     r0 00000000  r1 0000726a  r2 00000006  r3 00000008
  A/DEBUG:     r4 f6cbc590  r5 00000006  r6 f6cbc538  r7 0000010c
  A/DEBUG:     r8 12e45dc0  r9 f3f88000  sl ff90e8ec  fp f3f88000
  A/DEBUG:     ip 00000058  sp ff90e5f8  lr f5c3a2c7  pc f5c3cb48  cpsr 200f0010
  A/DEBUG: backtrace:												//堆栈信息,只需要关注这部分就好
  A/DEBUG:     #00 pc 00049b48  /system/lib/libc.so (tgkill+12)
  A/DEBUG:     #01 pc 000472c3  /system/lib/libc.so (pthread_kill+34)
  A/DEBUG:     #02 pc 0001d565  /system/lib/libc.so (raise+10)
  A/DEBUG:     #03 pc 000190b1  /system/lib/libc.so (__libc_android_abort+34)
  A/DEBUG:     #04 pc 00017114  /system/lib/libc.so (abort+4)
  A/DEBUG:     #05 pc 0009063f  /data/app/com.example.hasee.ndkdemo-2/lib/arm/libthird.so (_ZN7GSMutex4LockEv+90)
  A/DEBUG:     #06 pc 00090837  /data/app/com.example.hasee.ndkdemo-2/lib/arm/libthird.so (_ZN11GSAutoMutexC1ER7GSMutex+10)
  A/DEBUG:     #07 pc 0004b4d7  /data/app/com.example.hasee.ndkdemo-2/lib/arm/libthird.so (_ZN12GSGB28181SDK9CSipStack18GetHistoryRegisterEv+34)
  A/DEBUG:     #08 pc 0004b60b  /data/app/com.example.hasee.ndkdemo-2/lib/arm/libthird.so (_ZN12GSGB28181SDK9CSipStack13SendRegistMsgERK16_Stru_Regist_MsgjPc+58)
  A/DEBUG:     #09 pc 000033a3  /data/app/com.example.hasee.ndkdemo-2/lib/arm/libnative-lib.so (Java_com_example_hasee_ndkdemo_NDKUtil_agentRegister+686)

1、先提取backtrace部分

上面的这些报错信息里面,backtrace部分显示的是错误的堆栈信息,所以我们只需要关注 backtrace部分就可以了。
提取后如下所示:

  A/DEBUG: backtrace:
  A/DEBUG:     #00 pc 00049b48  /system/lib/libc.so (tgkill+12)
  A/DEBUG:     #01 pc 000472c3  /system/lib/libc.so (pthread_kill+34)
  A/DEBUG:     #02 pc 0001d565  /system/lib/libc.so (raise+10)
  A/DEBUG:     #03 pc 000190b1  /system/lib/libc.so (__libc_android_abort+34)
  A/DEBUG:     #04 pc 00017114  /system/lib/libc.so (abort+4)
  A/DEBUG:     #05 pc 0009063f  /data/app/com.example.hasee.ndkdemo-2/lib/arm/libthird.so (_ZN7GSMutex4LockEv+90)
  A/DEBUG:     #06 pc 00090837  /data/app/com.example.hasee.ndkdemo-2/lib/arm/libthird.so (_ZN11GSAutoMutexC1ER7GSMutex+10)
  A/DEBUG:     #07 pc 0004b4d7  /data/app/com.example.hasee.ndkdemo-2/lib/arm/libthird.so (_ZN12GSGB28181SDK9CSipStack18GetHistoryRegisterEv+34)
  A/DEBUG:     #08 pc 0004b60b  /data/app/com.example.hasee.ndkdemo-2/lib/arm/libthird.so (_ZN12GSGB28181SDK9CSipStack13SendRegistMsgERK16_Stru_Regist_MsgjPc+58)
  A/DEBUG:     #09 pc 000033a3  /data/app/com.example.hasee.ndkdemo-2/lib/arm/libnative-lib.so (Java_com_example_hasee_ndkdemo_NDKUtil_agentRegister+686)

2、提取对应so库的信息

可以看到每一行最后面都跟着“xxx.so”信息
“#00” 至 “#04” 部分后面的都是 “/system/lib/libc.so” ,这些都是系统的库,这个我们不需要管;
“#05” 至 “#09” 部分后面的so库都是我自己的,这些才是我们需要定位的部分。

  “/data/app/com.example.hasee.ndkdemo-2/lib/arm/libthird.so”		  	 	// 引入的第三方so库
  “/data/app/com.example.hasee.ndkdemo-2/lib/arm/libnative-lib.so ”		// 编译生成的so库

将“#05” 至 “#09” 部分提取出来,如下所示:

  A/DEBUG:     #05 pc 0009063f  /data/app/com.example.hasee.ndkdemo-2/lib/arm/libthird.so (_ZN7GSMutex4LockEv+90)
  A/DEBUG:     #06 pc 00090837  /data/app/com.example.hasee.ndkdemo-2/lib/arm/libthird.so (_ZN11GSAutoMutexC1ER7GSMutex+10)
  A/DEBUG:     #07 pc 0004b4d7  /data/app/com.example.hasee.ndkdemo-2/lib/arm/libthird.so (_ZN12GSGB28181SDK9CSipStack18GetHistoryRegisterEv+34)
  A/DEBUG:     #08 pc 0004b60b  /data/app/com.example.hasee.ndkdemo-2/lib/arm/libthird.so (_ZN12GSGB28181SDK9CSipStack13SendRegistMsgERK16_Stru_Regist_MsgjPc+58)
  A/DEBUG:     #09 pc 000033a3  /data/app/com.example.hasee.ndkdemo-2/lib/arm/libnative-lib.so (Java_com_example_hasee_ndkdemo_NDKUtil_agentRegister+686)

3、提取错误地址

剩下到的这几行中,重点看 “pc” 后面的十六进制数,这些是对应so库中的具体错误信息地址,这些地址才是我们最终需要转换的对象。为了更直观的展示,我把前面的“A/DEBUG” 和 “pc” 两个标签去掉,剩下行号还有地址以及so库部分提取出来。
提取如下所示:

  #05	0009063f  /data/app/com.example.hasee.ndkdemo-2/lib/arm/libthird.so
  #06	00090837  /data/app/com.example.hasee.ndkdemo-2/lib/arm/libthird.so 
  #07	0004b4d7  /data/app/com.example.hasee.ndkdemo-2/lib/arm/libthird.so
  #08	0004b60b  /data/app/com.example.hasee.ndkdemo-2/lib/arm/libthird.so 
  #09	000033a3  /data/app/com.example.hasee.ndkdemo-2/lib/arm/libnative-lib.so 

上面就是最终我们需要关注的部分,有了十六进制地址值以及后面的so库,下面我们就可以使用addr2line进行地址转换了。

三、使用addr2line对地址进行转换

1、addr2line工具的路径放在

" ${NDK} / toolchains / ${ABI} / prebuilt / windows-x86_64 / bin / "下

  ${NDK}     // 你的NDK解压包路径
  ${ABI}     // 你的调试设备的CPU架构,通常来说实体机一般都是对应 arm-linux-androideabi

2、Terminal中转换地址的命令

  arm-linux-androideabi-addr2line -C -f -e ${SOPATH} ${Address}
  -C -f  			//打印错误行数所在的函数名称
  -e    	   		//打印错误地址的对应路径及行数
  ${SOPATH}  		//so库路径 
  ${Address}		//需要转换的堆栈错误信息地址,可以添加多个,但是中间要用空格隔开

四、例子

对上面最终提取的错误信息(“#05 – #09”)中的堆栈地址进行转换

1、首先找到自己的so库路径

对于“#05” 至 “#08” 部分的地址,我对应的so库路径为

  F:/Android/workspace/NDKDemo/app/src/main/jniLibs/armeabi-v7a/libthird.so

对于“#09”行中的地址,我对应的so库为:

  F:/Android/workspace/NDKDemo/app/build/intermediates/cmake/debug/obj/armeabi-v7a/libnative-lib.so

2、在Terminal中输入命令

对于“#05” 至 “#08” 部分的地址,我输入的命令为:

  arm-linux-androideabi-addr2line -C -f -e F:/Android/workspace/NDKDemo/app/src/main/jniLibs/armeabi-v7a/libthird.so 	0009063f  00090837  0004b4d7  0004b60b  

对于“#09”行中的地址,我输入的命令为:

  arm-linux-androideabi-addr2line -C -f -e F:/Android/workspace/NDKDemo/app/build/intermediates/cmake/debug/obj/armeabi-v7a/libnative-lib.so 	 000033a3  

注意:
1)我这里已经将addr2line配置到环境变量中,所以可以直接使用arm-linux-androideabi-addr2line命令。如果没有配置的话,记得要加上自己的完整路径,否则会出现Terminal报错:

'arm-linux-androideabi-addrline2' 不是内部或外部命令,也不是可运行的程序或批处理文件。”

2)要看清楚后面的so库,我这里第三方的so库和我自己的编译打包的so库都有报错地址信息,所以转换地址的时候,要注意地址后面对应的是哪个so库,不然的话会转换失败,转换的地址显示为 " ? ? 0 “(一个so库的错误地址信息跑到另外一个so库去查,当然查不到,除非两个错误位置在两个so库中的堆栈地址相同,查不到的时候,就会输出” ? ? 0 ")这个问题也困扰了我一个上午,要特别注意。

3)libnative-lib.so是我自己打包编译的库,自己打包编译的so库可以在Project视图的
" ./app/build/intermediates/cmake/debug/obj/&{ABI}/ " 路径下找到

Android studio中NDK开发(四)——使用addr2line分析Crash日志_第1张图片

3、效果

第三方libthird.so库的显示信息
Android studio中NDK开发(四)——使用addr2line分析Crash日志_第2张图片
自己编译的libnatve-lib.so库的显示信息
在这里插入图片描述
点击一下转换后的地址就可以跳转到错误的位置了。


如有错误,欢迎指正,虚心学习!

你可能感兴趣的:(Android,NDK)