JNI SO库崩溃异常与库信息

1.前言

为了编译根据so库崩溃指令地址,能快速定位到导致崩溃函数。

2.工具介绍

1.1addr2line:

可以通过指令地址映射出成JNI对应的文件名,函数名,行数的工具。
工具位置:/Users/zhouwen/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-addr2line
工具使用: arm-linux-androideabi-addr2line -C -f -e<参数> libnative-lib2.so<动态库> 崩溃地址

1.2.objdump:

Display information from object ----根据objdump --help里描述
用于反汇编查看目标文件或者可执行文件的信息。
工具位置:/Users/zhouwen/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-objdump

3.工具使用:

异常分析

3.1.addr2line
抛出致命异常
JNIEXPORT void JNICALL Java_jni_chowen_com_nativeapp_MainActivity_throwException
        (JNIEnv *env, jobject jobject1, jstring jstring1) {
    jclass  jclass1 = env->FindClass("java/io/IOException");
    const char* c = env->GetStringUTFChars(jstring1, 0);

    env->FatalError(c); // 抛出一个致命异常

    jthrowable jthrowable1 = env->ExceptionOccurred();

    if (env->ThrowNew(jclass1, c) == JNI_OK){
        if(jthrowable1){
            LOGE("JNI throw suc ExceptionOccurred");
        }
        env->ExceptionDescribe();

        LOGE("JNI throw suc");
    } else {
        LOGE("JNI throw failed");
    }
}
backtrace信息:
backtrace:
2019-07-05 14:18:22.078 8767-8767/? A/DEBUG:     #00 pc 00000ac4  [vdso:b660f000] (__kernel_vsyscall+16)
2019-07-05 14:18:22.078 8767-8767/? A/DEBUG:     #01 pc 0001edf8  /system/lib/libc.so (syscall+40)
2019-07-05 14:18:22.078 8767-8767/? A/DEBUG:     #02 pc 0001f073  /system/lib/libc.so (abort+115)
2019-07-05 14:18:22.078 8767-8767/? A/DEBUG:     #03 pc 0054d4fb  /system/lib/libart.so (art::Runtime::Abort(char const*)+603)
2019-07-05 14:18:22.078 8767-8767/? A/DEBUG:     #04 pc 0011fb23  /system/lib/libart.so (_ZNSt3__110__function6__funcIPFvPKcENS_9allocatorIS5_EES4_EclEOS3_+35)
2019-07-05 14:18:22.078 8767-8767/? A/DEBUG:     #05 pc 0065f2eb  /system/lib/libart.so (android::base::LogMessage::~LogMessage()+1051)
2019-07-05 14:18:22.078 8767-8767/? A/DEBUG:     #06 pc 003e25a4  /system/lib/libart.so (art::JNI::FatalError(_JNIEnv*, char const*)+180)
2019-07-05 14:18:22.078 8767-8767/? A/DEBUG:     #07 pc 0013818c  /system/lib/libart.so (art::CheckJNI::FatalError(_JNIEnv*, char const*)+924)
2019-07-05 14:18:22.078 8767-8767/? A/DEBUG:     #08 pc 0003754b  /data/app/jni.chowen.com.nativeapp-v1AIqpkS5gwn6UB76ahh8A==/lib/x86/libnative-lib2.so (_JNIEnv::FatalError(char const*)+59)
2019-07-05 14:18:22.078 8767-8767/? A/DEBUG:     #09 pc 0003736a  /data/app/jni.chowen.com.nativeapp-v1AIqpkS5gwn6UB76ahh8A==/lib/x86/libnative-lib2.so 
执行命令arm-linux-androideabi-addr2line
/Users/zhouwen/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-addr2line -C -f -e /Users/zhouwen/work/NativeApp/app/build/intermediates/cmake/debug/obj/x86/libnative-lib2.so 0003736a
Java_jni_chowen_com_nativeapp_MainActivity_throwException
/Users/zhouwen/work/NativeApp/app/src/main/cpp/native-lib.cpp:52
addr2line参数:

libnative-lib2.so为崩溃的SO动态库
0003736a:指令地址
Java_jni_chowen_com_nativeapp_MainActivity_throwException:解析出JNI里对应的函数名称
/Users/zhouwen/work/NativeApp/app/src/main/cpp/native-lib.cpp:52:对应的指令地址解析出来对应的文件及函数对应的行数为第52行。

➜  ~ /Users/zhouwen/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-addr2line --help
Usage: /Users/zhouwen/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-addr2line [option(s)] [addr(s)]
 Convert addresses into line number/file name pairs.
 If no addresses are specified on the command line, they will be read from stdin
 The options are:
  @                Read options from 
  -a --addresses         Show addresses
  -b --target=  Set the binary file format
  -e --exe=  Set the input file name (default is a.out)
  -i --inlines           Unwind inlined functions
  -j --section=    Read section-relative offsets instead of addresses
  -p --pretty-print      Make the output easier to read for humans
  -s --basenames         Strip directory names
  -f --functions         Show function names
  -C --demangle[=style]  Demangle function names
  -h --help              Display this information
  -v --version           Display the program's version

3.2.objdump

查看.o文件信息
 /Users/zhouwen/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-objdump -S /Users/zhouwen/Desktop/ffmpeg/ffmpeg-4.1.3/libavcodec/yuv4dec.o
/Users/zhouwen/Desktop/ffmpeg/ffmpeg-4.1.3/libavcodec/yuv4dec.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 :
    AVFrame *pic = data;
    const uint8_t *src = avpkt->data;
    uint8_t *y, *u, *v;
    int i, j, ret;

    if (avpkt->size < 6 * (avctx->width + 1 >> 1) * (avctx->height + 1 >> 1)) {
   0:   e590c05c    ldr ip, [r0, #92]   ; 0x5c
{
   4:   e92d4ff0    push    {r4, r5, r6, r7, r8, r9, sl, fp, lr}
    if (avpkt->size < 6 * (avctx->width + 1 >> 1) * (avctx->height + 1 >> 1)) {
   8:   e28cc001    add ip, ip, #1
   c:   e590e060    ldr lr, [r0, #96]   ; 0x60
  10:   e1a0c0cc    asr ip, ip, #1
  14:   e08cc08c    add ip, ip, ip, lsl #1
  18:   e28ee001    add lr, lr, #1
  1c:   e1a0e0ce    asr lr, lr, #1
  20:   e1a0c08c    lsl ip, ip, #1
{
  24:   e24dd00c    sub sp, sp, #12
    if (avpkt->size < 6 * (avctx->width + 1 >> 1) * (avctx->height + 1 >> 1)) {
  28:   e00c0c9e    mul ip, lr, ip
{
  2c:   e58d3004    str r3, [sp, #4]
    if (avpkt->size < 6 * (avctx->width + 1 >> 1) * (avctx->height + 1 >> 1)) {
  30:   e1a0e003    mov lr, r3
  34:   e593301c    ldr r3, [r3, #28]
{
  38:   e1a07000    mov r7, r0
    if (avpkt->size < 6 * (avctx->width + 1 >> 1) * (avctx->height + 1 >> 1)) {
  3c:   e153000c    cmp r3, ip
{
  40:   e58d2000    str r2, [sp]
    const uint8_t *src = avpkt->data;
  44:   e59e5018    ldr r5, [lr, #24]
    if (avpkt->size < 6 * (avctx->width + 1 >> 1) * (avctx->height + 1 >> 1)) {
  48:   ba000044    blt 160 
        av_log(avctx, AV_LOG_ERROR, "Insufficient input data.\n");
        return AVERROR(EINVAL);
    }

    if ((ret = ff_get_buffer(avctx, pic, 0)) < 0)
  4c:   e3a02000    mov r2, #0
  50:   e1a06001    mov r6, r1
  54:   ebfffffe    bl  0 
  58:   e3500000    cmp r0, #0
  5c:   ba00003d    blt 158 

    y = pic->data[0];
    u = pic->data[1];
    v = pic->data[2];

    for (i = 0; i < (avctx->height + 1) >> 1; i++) {
  60:   e5973060    ldr r3, [r7, #96]   ; 0x60
    pic->key_frame = 1;
  64:   e3a02001    mov r2, #1
    for (i = 0; i < (avctx->height + 1) >> 1; i++) {
  68:   e0833002    add r3, r3, r2
  6c:   e1530002    cmp r3, r2
    pic->key_frame = 1;
  70:   e5862054    str r2, [r6, #84]   ; 0x54
    pic->pict_type = AV_PICTURE_TYPE_I;
  74:   e5862058    str r2, [r6, #88]   ; 0x58
    v = pic->data[2];
  78:   e8960610    ldm r6, {r4, r9, sl}
    for (i = 0; i < (avctx->height + 1) >> 1; i++) {
  7c:   da000030    ble 144 
  80:   e597c05c    ldr ip, [r7, #92]   ; 0x5c
  84:   e3a08000    mov r8, #0
  88:   e08cc002    add ip, ip, r2
        for (j = 0; j < (avctx->width + 1) >> 1; j++) {
  8c:   e35c0001    cmp ip, #1
  90:   da000023    ble 124 
  94:   e2853006    add r3, r5, #6
  98:   e249b001    sub fp, r9, #1
  9c:   e24ae001    sub lr, sl, #1
  a0:   e1a00004    mov r0, r4
  a4:   e3a02000    mov r2, #0
            u[j] = *src++ ^ 0x80;
  a8:   e5531006    ldrb    r1, [r3, #-6]
            v[j] = *src++ ^ 0x80;
            y[                   2 * j    ] = *src++;
            y[                   2 * j + 1] = *src++;
            y[pic->linesize[0] + 2 * j    ] = *src++;
            y[pic->linesize[0] + 2 * j + 1] = *src++;
  ac:   e084c082    add ip, r4, r2, lsl #1
            u[j] = *src++ ^ 0x80;
  b0:   e221107f    eor r1, r1, #127    ; 0x7f
  b4:   e1e01001    mvn r1, r1
  b8:   e5eb1001    strb    r1, [fp, #1]!
            v[j] = *src++ ^ 0x80;
  bc:   e5531005    ldrb    r1, [r3, #-5]
  c0:   e2800002    add r0, r0, #2
  c4:   e221107f    eor r1, r1, #127    ; 0x7f
  c8:   e1e01001    mvn r1, r1
  cc:   e5ee1001    strb    r1, [lr, #1]!
            y[                   2 * j    ] = *src++;
  d0:   e5531004    ldrb    r1, [r3, #-4]
  d4:   e7c41082    strb    r1, [r4, r2, lsl #1]
            y[                   2 * j + 1] = *src++;
  d8:   e5531003    ldrb    r1, [r3, #-3]
  dc:   e5401001    strb    r1, [r0, #-1]
            y[pic->linesize[0] + 2 * j    ] = *src++;
  e0:   e5961020    ldr r1, [r6, #32]
  e4:   e5535002    ldrb    r5, [r3, #-2]
  e8:   e0841001    add r1, r4, r1
  ec:   e7c15082    strb    r5, [r1, r2, lsl #1]
            y[pic->linesize[0] + 2 * j + 1] = *src++;
  f0:   e5965020    ldr r5, [r6, #32]
  f4:   e5531001    ldrb    r1, [r3, #-1]
  f8:   e08cc005    add ip, ip, r5
  fc:   e5cc1001    strb    r1, [ip, #1]
        for (j = 0; j < (avctx->width + 1) >> 1; j++) {
 100:   e597c05c    ldr ip, [r7, #92]   ; 0x5c
 104:   e2822001    add r2, r2, #1
 108:   e28cc001    add ip, ip, #1
 10c:   e15200cc    cmp r2, ip, asr #1
 110:   e1a05003    mov r5, r3
 114:   e2833006    add r3, r3, #6
 118:   baffffe2    blt a8 
 11c:   e5973060    ldr r3, [r7, #96]   ; 0x60
 120:   e2833001    add r3, r3, #1
        }

        y += 2 * pic->linesize[0];
        u +=     pic->linesize[1];
        v +=     pic->linesize[2];
 124:   e2860020    add r0, r6, #32
 128:   e8900007    ldm r0, {r0, r1, r2}
    for (i = 0; i < (avctx->height + 1) >> 1; i++) {
 12c:   e2888001    add r8, r8, #1
 130:   e15800c3    cmp r8, r3, asr #1
        y += 2 * pic->linesize[0];
 134:   e0844080    add r4, r4, r0, lsl #1
        u +=     pic->linesize[1];
 138:   e0899001    add r9, r9, r1
        v +=     pic->linesize[2];
 13c:   e08aa002    add sl, sl, r2
    for (i = 0; i < (avctx->height + 1) >> 1; i++) {
 140:   baffffd1    blt 8c 
    }

    *got_frame = 1;
 144:   e59d2000    ldr r2, [sp]
 148:   e3a03001    mov r3, #1
 14c:   e5823000    str r3, [r2]

    return avpkt->size;
 150:   e59d3004    ldr r3, [sp, #4]
 154:   e593001c    ldr r0, [r3, #28]
}
 158:   e28dd00c    add sp, sp, #12
 15c:   e8bd8ff0    pop {r4, r5, r6, r7, r8, r9, sl, fp, pc}
        av_log(avctx, AV_LOG_ERROR, "Insufficient input data.\n");
 160:   e59f2010    ldr r2, [pc, #16]   ; 178 
 164:   e3a01010    mov r1, #16
 168:   e08f2002    add r2, pc, r2
 16c:   ebfffffe    bl  0 
        return AVERROR(EINVAL);
 170:   e3e00015    mvn r0, #21
 174:   eafffff7    b   158 
 178:   00000008    .word   0x00000008

Disassembly of section .text.unlikely:

00000000 :
    if (avpkt->size < 6 * (avctx->width + 1 >> 1) * (avctx->height + 1 >> 1)) {
   0:   e3a03000    mov r3, #0
{
   4:   e5803070    str r3, [r0, #112]  ; 0x70
    if (avpkt->size < 6 * (avctx->width + 1 >> 1) * (avctx->height + 1 >> 1)) {
   8:   e1a00003    mov r0, r3
   c:   e12fff1e    bx  lr
查看.a静态库中.o文件信息
➜  ~ /Users/zhouwen/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-objdump -a /Users/zhouwen/Desktop/ffmpeg/ffmpeg-4.1.3/android/armv7-a/lib/libswscale.a
In archive /Users/zhouwen/Desktop/ffmpeg/ffmpeg-4.1.3/android/armv7-a/lib/libswscale.a:

alphablend.o:     file format elf32-littlearm
rw-r--r-- 0/0   4244 Jan  1 08:00 1970 alphablend.o


gamma.o:     file format elf32-littlearm
rw-r--r-- 0/0   1224 Jan  1 08:00 1970 gamma.o


hscale.o:     file format elf32-littlearm
rw-r--r-- 0/0   4320 Jan  1 08:00 1970 hscale.o


hscale_fast_bilinear.o:     file format elf32-littlearm
rw-r--r-- 0/0   1204 Jan  1 08:00 1970 hscale_fast_bilinear.o


input.o:     file format elf32-littlearm
rw-r--r-- 0/0  46804 Jan  1 08:00 1970 input.o


options.o:     file format elf32-littlearm
rw-r--r-- 0/0   5660 Jan  1 08:00 1970 options.o


output.o:     file format elf32-littlearm
rw-r--r-- 0/0 162388 Jan  1 08:00 1970 output.o


rgb2rgb.o:     file format elf32-littlearm
rw-r--r-- 0/0  11336 Jan  1 08:00 1970 rgb2rgb.o


slice.o:     file format elf32-littlearm
rw-r--r-- 0/0   5480 Jan  1 08:00 1970 slice.o


swscale.o:     file format elf32-littlearm
rw-r--r-- 0/0  15288 Jan  1 08:00 1970 swscale.o


swscale_unscaled.o:     file format elf32-littlearm
rw-r--r-- 0/0  66444 Jan  1 08:00 1970 swscale_unscaled.o


utils.o:     file format elf32-littlearm
rw-r--r-- 0/0  39388 Jan  1 08:00 1970 utils.o


vscale.o:     file format elf32-littlearm
rw-r--r-- 0/0   5372 Jan  1 08:00 1970 vscale.o


yuv2rgb.o:     file format elf32-littlearm
rw-r--r-- 0/0  35260 Jan  1 08:00 1970 yuv2rgb.o
objdump参数:

../Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-objdump --help

Display information from object .
 At least one of the following switches must be given:
  -a, --archive-headers    Display archive header information
  -f, --file-headers       Display the contents of the overall file header
  -p, --private-headers    Display object format specific file header contents
  -P, --private=OPT,OPT... Display object format specific contents
  -h, --[section-]headers  Display the contents of the section headers
  -x, --all-headers        Display the contents of all headers
  -d, --disassemble        Display assembler contents of executable sections
  -D, --disassemble-all    Display assembler contents of all sections
  -S, --source             Intermix source code with disassembly
  -s, --full-contents      Display the full contents of all sections requested
  -g, --debugging          Display debug information in object file
  -e, --debugging-tags     Display debug information using ctags style
  -G, --stabs              Display (in raw form) any STABS info in the file
  -W[lLiaprmfFsoRt] or
  --dwarf[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,
          =frames-interp,=str,=loc,=Ranges,=pubtypes,
          =gdb_index,=trace_info,=trace_abbrev,=trace_aranges,
          =addr,=cu_index]
                           Display DWARF info in the file
  -t, --syms               Display the contents of the symbol table(s)
  -T, --dynamic-syms       Display the contents of the dynamic symbol table
  -r, --reloc              Display the relocation entries in the file
  -R, --dynamic-reloc      Display the dynamic relocation entries in the file
  @                  Read options from 
  -v, --version            Display this program's version number
  -i, --info               List object formats and architectures supported
  -H, --help               Display this information

 The following switches are optional:
  -b, --target=BFDNAME           Specify the target object format as BFDNAME
  -m, --architecture=MACHINE     Specify the target architecture as MACHINE
  -j, --section=NAME             Only display information for section NAME
  -M, --disassembler-options=OPT Pass text OPT on to the disassembler
  -EB --endian=big               Assume big endian format when disassembling
  -EL --endian=little            Assume little endian format when disassembling
      --file-start-context       Include context from start of file (with -S)
  -I, --include=DIR              Add DIR to search list for source files
  -l, --line-numbers             Include line numbers and filenames in output
  -F, --file-offsets             Include file offsets when displaying information
  -C, --demangle[=STYLE]         Decode mangled/processed symbol names
                                  The STYLE, if specified, can be `auto', `gnu',
                                  `lucid', `arm', `hp', `edg', `gnu-v3', `java'
                                  or `gnat'
  -w, --wide                     Format output for more than 80 columns
  -z, --disassemble-zeroes       Do not skip blocks of zeroes when disassembling
      --start-address=ADDR       Only process data whose address is >= ADDR
      --stop-address=ADDR        Only process data whose address is <= ADDR
      --prefix-addresses         Print complete address alongside disassembly
      --[no-]show-raw-insn       Display hex alongside symbolic disassembly
      --insn-width=WIDTH         Display WIDTH bytes on a single line for -d
      --adjust-vma=OFFSET        Add OFFSET to all displayed section addresses
      --special-syms             Include special symbols in symbol dumps
      --prefix=PREFIX            Add PREFIX to absolute paths for -S
      --prefix-strip=LEVEL       Strip initial directory names for -S
      --dwarf-depth=N        Do not display DIEs at depth N or greater
      --dwarf-start=N        Display DIEs starting with N, at the same depth
                             or deeper
      --dwarf-check          Make additional dwarf internal consistency checks.  

4.That's All

addr2line和objdump这两个工具参数就不展开介绍了,网上资料很多。

你可能感兴趣的:(JNI SO库崩溃异常与库信息)