signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xc

最近一直研究JNI和NDK方面与Java的对接,今天遇到一个这样的错,就是打开App,然后通过JNI调用C++代码,然后就闪退, 日志如下所示:

09-05 10:07:59.626 10962-10962/com.daniulive.smartpublisher A/libc: Fatal signal 11 (SIGSEGV), code 1, fault addr 0xc in tid 10962 (.smartpublisher)
                                                                    
                                                                    [ 09-05 10:07:59.626   458:  458 W/         ]
                                                                    debuggerd: handling request: pid=10962 uid=10062 gid=10062 tid=10962
09-05 10:07:59.693 10984-10984/? A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
09-05 10:07:59.693 10984-10984/? A/DEBUG: Build fingerprint: 'Hisense/Z1/HS8953QC:7.1.1/NMF26F/L1370.6.01.01:user/release-keys'
09-05 10:07:59.694 10984-10984/? A/DEBUG: Revision: '0'
09-05 10:07:59.694 10984-10984/? A/DEBUG: ABI: 'arm64'
09-05 10:07:59.694 10984-10984/? A/DEBUG: pid: 10962, tid: 10962, name: .smartpublisher  >>> com.daniulive.smartpublisher <<<
09-05 10:07:59.694 10984-10984/? A/DEBUG: signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xc
09-05 10:07:59.694 10984-10984/? A/DEBUG:     x0   0000000000000000  x1   0000000000000001  x2   0000000000000004  x3   0000000000000003
09-05 10:07:59.694 10984-10984/? A/DEBUG:     x4   656d616e5f726669  x5   0000808080808080  x6   0000007fa116e000  x7   0000000000000000
09-05 10:07:59.694 10984-10984/? A/DEBUG:     x8   0000000000000000  x9   0000000000000000  x10  0000000000000000  x11  000000000000001e
09-05 10:07:59.695 10984-10984/? A/DEBUG:     x12  0000000000000018  x13  0000000000000000  x14  0000000000000000  x15  00253207056c0de8
09-05 10:07:59.695 10984-10984/? A/DEBUG:     x16  0000007f94fea328  x17  0000007f94f1bc84  x18  00000000ffffffff  x19  0000007f9d296a00
09-05 10:07:59.695 10984-10984/? A/DEBUG:     x20  0000007f9ccaea50  x21  0000007f9d296a00  x22  0000007fd09aaaac  x23  0000007f9bb3b83a
09-05 10:07:59.695 10984-10984/? A/DEBUG:     x24  000000000000000c  x25  a5dd763335e33087  x26  0000007f9d296a98  x27  0000007f9d296a00
09-05 10:07:59.695 10984-10984/? A/DEBUG:     x28  0000000000000012  x29  0000007fd09aa2e0  x30  0000007f94f1b48c
09-05 10:07:59.695 10984-10984/? A/DEBUG:     sp   0000007fd09aa2d0  pc   0000007f94f1bc90  pstate 0000000020000000
09-05 10:07:59.700 10984-10984/? A/DEBUG: backtrace:
09-05 10:07:59.701 10984-10984/? A/DEBUG:     #00 pc 000000000001bc90  /data/app/com.daniulive.smartpublisher-1/lib/arm64/libnative-lib.so (_ZN10CDeviceLib12LaunchDeviceEv+12)
09-05 10:07:59.701 10984-10984/? A/DEBUG:     #01 pc 000000000001b488  /data/app/com.daniulive.smartpublisher-1/lib/arm64/libnative-lib.so (_Z12LaunchDevicem+80)
09-05 10:07:59.701 10984-10984/? A/DEBUG:     #02 pc 000000000001ae68  /data/app/com.daniulive.smartpublisher-1/lib/arm64/libnative-lib.so (startStream+804)
09-05 10:07:59.701 10984-10984/? A/DEBUG:     #03 pc 000000000001a3c4  /data/app/com.daniulive.smartpublisher-1/lib/arm64/libnative-lib.so (Java_com_daniulive_smartpublisher_jbjniapis_jnistartStream+220)
09-05 10:07:59.701 10984-10984/? A/DEBUG:     #04 pc 000000000024831c  /data/app/com.daniulive.smartpublisher-1/oat/arm64/base.odex (offset 0x242000)

这个日志重要的开始标志是在这句下面:signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xc 

直接找最有用的backtrace信息。 backtrace描述了crash发生时函数的调用关系及其它地址信息等,可谓是真实地还原了crash的现场。接下来就看下现场的具体情况是怎么样的。 

backtrace中,从#00到#04 共五行信息代表是crash时函数调用关系,从下往上倒着看,#04行的方法调用了#03行的方法;#03行的方法调用了#02行的方法;向上类推,最后就是#01行的方法调用了#00行的方法。而最终出现的crash就是在#00行中。

#** pc 后面跟着就是异常时PC寄存器值,后面需要用到。

现在,我们用一个工具:addr2line,这个工具可以查看到出错的文件名、哪行代码出错了。这个工具已经包含在NDK里面了,目录如下:你的NDK路径\toolchains\aarch64-linux-android-4.9\prebuilt\windows-x86_64\bin,如下图所示:

接着需要拿到当前调试出错时的那个so库,路径在:你的项目路径app\build\intermediates\cmake\debug\obj\arm64-v8a。(因为日志有提示说arm64,所以选择这个arm64-v8a),另外,一定是要在obj目录下的,因为每调试一次,生成的So信息都不一样,如果对不上的话就查不到信息了。。。

将so库复制到一个新的文件里(路径随意,不过最好不好带中文),然后再新建一个Bat脚本,脚本信息如下:

@echo off
rem current direction
set cur_dir=%cd%
 
rem addr2line tool path
set add2line_path=E:\android-ndk-r16b-windows-x86_64\android-ndk-r16b\toolchains\aarch64-linux-android-4.9\prebuilt\windows-x86_64\bin\aarch64-linux-android-addr2line.exe
 
rem debug file
set /p debug_file=请输入当前目录下debug文件名:
 
rem debug_file_path
set debug_file_path=%cur_dir%\%debug_file%
 
rem debug address
set /p debug_addr=请输入异常时PC寄存器值:
 
echo ----------------------- addr2line ------------------------
echo debug文件路径: %debug_file_path%  PC=%debug_addr%
 
if exist %debug_file_path% (
%add2line_path% -e %debug_file_path% -f %debug_addr% 
) else (
echo debug file is no exist. 
)
 
echo ---------------------------------------------------------
pause

上面代码的set add2line_path=后面跟的就是那个addr2line工具路径。

所以此新建的文件夹里有so库和上面那个脚本:

双击此脚本,然后输入库名和寄存器地址,然后就可以查到出错的行号了,效果如下所示:

注:上面演示的是最最最幸运的效果,但实际中,第三方的so库一般都是不提供源码,又或者已加密了,所以此时得出的是行号为??:?或??:0

如果遇到addr2line得到??:?或??:0的情况,原因就是编译得到的so文件没有附加上符号表(symbolic)信息。

贴上两个类似??:?或??:0情况的链接吧:https://blog.csdn.net/u010477502/article/details/50626263

http://jileniao.net/post-201.html

猜你喜欢

转载自blog.csdn.net/toyauko/article/details/82416429