Android NDK开发Crash问题分析

目前市场上越来越多的 Android App采用 C/C++ 来实现其关键逻辑,尤其是很多第三方的SDK,出于效率、安全,复用的考虑,比如人脸识别,语音识别等等。所以能分析 C/C++ 崩溃日志并能从日志中分析出原因,成为 Android 开发人员一项必备技能。本文将通过一个简单的Demo分析 Native 崩溃日志来定位出错的 C/C++ 代码及出错原因。

1、问题现场

为了方便,直接使用Android Studio中Sample:hello-jni,修改app/src/main/cpp/hello-jni.c文件内容如下,手动造一个Native Crash问题,这样在App启动后,就会出现闪退,抓取logcat日志。

因为使用的user版本的手机,所有没有权限读取到/data/tombstones日志,不过logcat日志对于分析本文的问题已经足够;

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
#include <string.h>
#include <jni.h>

/* This is a trivial JNI example where we use a native method
 * to return a new VM String. See the corresponding Java source
 * file located at:
 *
 *   hello-jni/app/src/main/java/com/example/hellojni/HelloJni.java
 */

void willCrash() {
    int *p = NULL;
    *p = 123;
}

JNIEXPORT jstring JNICALL
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
                                                  jobject thiz )
{
    willCrash();
    return (*env)->NewStringUTF(env, "Hello from JNI !  Compiled with ABI");
}

2、分析流程

2.1、关于日志

11-10 22:08:45.968  4449  4449 I crash_dump64: performing dump of process 4418 (target tid = 4418)
11-10 22:08:45.976  4449  4449 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
11-10 22:08:45.976  4449  4449 F DEBUG   : Build fingerprint: 'Xiaomi/sagit/sagit:9/PKQ1.190118.001/V10.4.2.0.PCACNXM:user/release-keys'
11-10 22:08:45.976  4449  4449 F DEBUG   : Revision: '0'
11-10 22:08:45.976  4449  4449 F DEBUG   : ABI: 'arm64'
11-10 22:08:45.976  4449  4449 F DEBUG   : pid: 4418, tid: 4418, name: xample.hellojni  >>> com.example.hellojni <<<
11-10 22:08:45.976  4449  4449 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
11-10 22:08:45.976  4449  4449 F DEBUG   : Cause: null pointer dereference
11-10 22:08:45.977  4449  4449 F DEBUG   :     x0  0000006f510e8460  x1  0000007ff2acb514  x2  0000000000000000  x3  0000006f51014c00
11-10 22:08:45.977  4449  4449 F DEBUG   :     x4  0000007ff2acb980  x5  0000006f38f34471  x6  766468752e63686e  x7  0000000000000000
11-10 22:08:45.977  4449  4449 F DEBUG   :     x8  000000000000007b  x9  0000000000000000  x10 0000000000430000  x11 0000006f50936688
11-10 22:08:45.977  4449  4449 F DEBUG   :     x12 000000000000018c  x13 0000006fd3eb1018  x14 0000006fd3e7e000  x15 ffffffffffffffff
11-10 22:08:45.977  4449  4449 F DEBUG   :     x16 0000006f38bd8fe0  x17 0000006f38bc8648  x18 0000000000000000  x19 0000006f51014c00
11-10 22:08:45.977  4449  4449 F DEBUG   :     x20 0000006f50850880  x21 0000006f51014c00  x22 0000007ff2acb7b0  x23 0000006f38f34471
11-10 22:08:45.977  4449  4449 F DEBUG   :     x24 0000000000000004  x25 0000006fd6f7a5e0  x26 0000006f51014ca0  x27 0000000000000001
11-10 22:08:45.977  4449  4449 F DEBUG   :     x28 0000000000000002  x29 0000007ff2acb4f0
11-10 22:08:45.977  4449  4449 F DEBUG   :     sp  0000007ff2acb4c0  lr  0000006f38bc8680  pc  0000006f38bc865c
11-10 22:08:46.305  4449  4449 F DEBUG   : 
11-10 22:08:46.305  4449  4449 F DEBUG   : backtrace:
11-10 22:08:46.305  4449  4449 F DEBUG   :     #00 pc 000000000000065c  /data/app/com.example.hellojni-Sytg7I9fr97KTcTz7Rrsjg==/lib/arm64/libhello-jni.so (willCrash+20)
11-10 22:08:46.305  4449  4449 F DEBUG   :     #01 pc 000000000000067c  /data/app/com.example.hellojni-Sytg7I9fr97KTcTz7Rrsjg==/lib/arm64/libhello-jni.so (Java_com_example_hellojni_HelloJni_stringFromJNI+20)
11-10 22:08:46.305  4449  4449 F DEBUG   :     #02 pc 000000000000909c  /data/app/com.example.hellojni-Sytg7I9fr97KTcTz7Rrsjg==/oat/arm64/base.odex (offset 0x9000) (com.example.hellojni.HelloJni.stringFromJNI+124)
11-10 22:08:46.305  4449  4449 F DEBUG   :     #03 pc 000000000055d788  /system/lib64/libart.so (art_quick_invoke_stub+584)
11-10 22:08:46.305  4449  4449 F DEBUG   :     #04 pc 00000000000d074c  /system/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+200)
11-10 22:08:46.305  4449  4449 F DEBUG   :     #05 pc 0000000000280dbc  /system/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+344)
11-10 22:08:46.305  4449  4449 F DEBUG   :     #06 pc 000000000027add0  /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+968)
---------------------------------省略部分-----------------------------------

可以看到,日志内容主要由下面几部分组成:(我们最主要的就是分析崩溃的过程和PID,终止的信号和故障地址和调用堆栈部分)

  • 构建指纹
  • 崩溃的过程和PID
  • 终止信号和故障地址
  • CPU寄存器
  • 调用堆栈

2.1.1、崩溃过程和PID信息

从上面日志中的第6行中我们可以看到崩溃进程的基本信息,如下所示:

pid: 8902, tid: 8902, name: xample.hellojni  >>> com.example.hellojni <<<

如果pid等于tid,那么就说明这个程序是在主线程中Crash掉的,名称的属性则表示Crash进程的名称以及在文件系统中位置。

2.1.2、终止信号和故障地址信息

从上面日志中的第7、8行中我们可以看到程序是因为什么信号导致了Crash以及出现错误的地址,如下所示:

11-10 19:53:21.890  8926  8926 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
11-10 19:53:21.890  8926  8926 F DEBUG   : Cause: null pointer dereference

第7行的信息说明出现进程Crash的原因是因为程序产生了段错误的信号,访问了非法的内存空间,而访问的非法地址是0x0。另外这个例子中直接给出来问题原因是因为空指针,其他问题并不一定会给出此信息。

2.1.3、调用堆栈信息

调用栈信息是分析程序崩溃的非常重要的一个信息,它主要记录了程序在Crash前的函数调用关系以及当前正在执行函数的信息,上面例中的backtrace的信息如下所示:

11-10 22:08:46.305  4449  4449 F DEBUG   : backtrace:
11-10 22:08:46.305  4449  4449 F DEBUG   :     #00 pc 000000000000065c  /data/app/com.example.hellojni-Sytg7I9fr97KTcTz7Rrsjg==/lib/arm64/libhello-jni.so (willCrash+20)
11-10 22:08:46.305  4449  4449 F DEBUG   :     #01 pc 000000000000067c  /data/app/com.example.hellojni-Sytg7I9fr97KTcTz7Rrsjg==/lib/arm64/libhello-jni.so (Java_com_example_hellojni_HelloJni_stringFromJNI+20)
11-10 22:08:46.305  4449  4449 F DEBUG   :     #02 pc 000000000000909c  /data/app/com.example.hellojni-Sytg7I9fr97KTcTz7Rrsjg==/oat/arm64/base.odex (offset 0x9000) (com.example.hellojni.HelloJni.stringFromJNI+124)
11-10 22:08:46.305  4449  4449 F DEBUG   :     #03 pc 000000000055d788  /system/lib64/libart.so (art_quick_invoke_stub+584)
11-10 22:08:46.305  4449  4449 F DEBUG   :     #04 pc 00000000000d074c  /system/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+200)
11-10 22:08:46.305  4449  4449 F DEBUG   :     #05 pc 0000000000280dbc  /system/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+344)
11-10 22:08:46.305  4449  4449 F DEBUG   :     #06 pc 000000000027add0  /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+968)

在上面的输出信息中,## 00,#01,#02 ......等表示的都是函数调用栈中栈帧的编号,其中编号越小的栈帧表示着当前最近调用的函数信息,所以栈帧标号#00表示的就是当前正在执行并导致程序崩溃函数的信息。

在栈帧的每一行中,pc后面的16进制数值表示的是当前函数正在执行语句的在共享链接库或者可执行文件中的位置,然后/lib/arm/libhello-jni.so则表示的是当前执行指令是在哪个文件当中,后面的小括号则是注明对应的是哪个函数。

例如,在上面的例子中,我们就可以定位到是程序是在willCrash中出现了错误,但是具体在那一行呢,我们还不是特别清楚,所以就需要我们进一步地使用更加高级的工具来帮助我们解析日志中有关调用栈的信息。

2.2、addr2line

addr2line是NDK中用来获得指定动态链接库文件或者可执行文件中指定地址对应的源代码信息,它们位于NDK包中的如下位置中,以arm64架构为例:

$$NDK_HOME/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-addr2line  

其中NDK_HOME表示你的NDK的安装路径,另外具体架构和目录的对应关系如下:

工具链 位置
arm $TOOLCHAIN/arm-linux-androideabi/lib/
arm64 $TOOLCHAIN/aarch64-linux-android/lib/
x86 $TOOLCHAIN/i686-linux-android/lib/
x86_64 $TOOLCHAIN/x86_64-linux-android/lib/

addr2line的使用说明如下所示:

Usage: ./aarch64-linux-android-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:
  @<file>                Read options from <file>
  -a --addresses         Show addresses
  -b --target=<bfdname>  Set the binary file format
  -e --exe=<executable>  Set the input file name (default is a.out)
  -i --inlines           Unwind inlined functions
  -j --section=<name>    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

./aarch64-linux-android-addr2line: supported targets: elf64-littleaarch64 elf64-bigaarch64 elf32-littleaarch64 elf32-bigaarch64 elf32-littlearm elf32-bigarm elf64-little elf64-big elf32-little elf32-big plugin srec symbolsrec verilog tekhex binary ihex
Report bugs to <http://source.android.com/source/report-bugs.html>

addr2line的基本用法如下所示:

./aarch64-linux-android-addr2line -f -e ~/Desktop/workspace/android/min/Demo/HelloJNI/app/build/intermediates/cmake/arm8Debug/obj/arm64-v8a/libhello-jni.so 000000000000065c
willCrash
/Users/min/Desktop/workspace/android/min/Demo/HelloJNI/app/src/main/cpp/hello-jni.c:29

如上所示,通过addr2line工具,我们可以看到libhello-jni.so文件中地址000000000000065c对应的源码是什么了,它对应的是源码中app/src/main/cpp/hello-jni.c:29处代码,查看上下文后,确定为空指针问题。

2.3、ndk-stack

Android NDK自从版本r6开始,提供了一个工具ndk-stack。这个工具能自动分析tombstone文件,能将崩溃时的调用内存地址和c ++代码一行一行对应起来。

ndk-stack工具同样也位于NDK包中,它的路径如下所示:

$NDK_HOME/ndk-stack

ndk-stack的使用说明如下所示:

Usage: ndk-stack -sym PATH [-dump PATH]
Symbolizes the stack trace from an Android native crash.

  -sym PATH   sets the root directory for symbols
  -dump PATH  sets the file containing the crash dump (default stdin)

See <https://developer.android.com/ndk/guides/ndk-stack.html>.

其中,

  • dump参数很容易理解,即dump下来的log文本文件,可以是logcat日志或者tombstones日志;
  • sym参数就是你的android项目下,编译成功之后,obj目录下的文件。

ndk-stack的基本用法如下所示:

ndk-stack -sym ~/Desktop/workspace/android/min/Demo/HelloJNI/app/build/intermediates/cmake/arm8Debug/obj/arm64-v8a/ -dump ~/Desktop/min.log |tee ~/Desktop/ndk-stack.txt

最后产生的结果文件如下,可以看到,堆栈信息的最后对应的是源码中app/src/main/cpp/hello-jni.c:29处代码,查看上下文后,确定为空指针问题。

********** Crash dump: **********
Build fingerprint: 'Xiaomi/sagit/sagit:9/PKQ1.190118.001/V10.4.2.0.PCACNXM:user/release-keys'
pid: 4418, tid: 4418, name: xample.hellojni  >>> com.example.hellojni <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
Stack frame #00 pc 000000000000065c  /data/app/com.example.hellojni-Sytg7I9fr97KTcTz7Rrsjg==/lib/arm64/libhello-jni.so (willCrash+20): Routine willCrash at /Users/min/Desktop/workspace/android/min/Demo/HelloJNI/app/src/main/cpp/hello-jni.c:29
Stack frame #01 pc 000000000000067c  /data/app/com.example.hellojni-Sytg7I9fr97KTcTz7Rrsjg==/lib/arm64/libhello-jni.so (Java_com_example_hellojni_HelloJni_stringFromJNI+20): Routine Java_com_example_hellojni_HelloJni_stringFromJNI at /Users/min/Desktop/workspace/android/min/Demo/HelloJNI/app/src/main/cpp/hello-jni.c:36
Stack frame #02 pc 000000000000909c  /data/app/com.example.hellojni-Sytg7I9fr97KTcTz7Rrsjg==/oat/arm64/base.odex (offset 0x9000) (com.example.hellojni.HelloJni.stringFromJNI+124)
Stack frame #03 pc 000000000055d788  /system/lib64/libart.so (art_quick_invoke_stub+584)
Stack frame #04 pc 00000000000d074c  /system/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+200)
Stack frame #05 pc 0000000000280dbc  /system/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+344)
Stack frame #06 pc 000000000027add0  /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+968)
Stack frame #07 pc 000000000052c8d8  /system/lib64/libart.so (MterpInvokeVirtual+588)
Stack frame #08 pc 000000000054fd14  /system/lib64/libart.so (ExecuteMterpImpl+14228)
Stack frame #09 pc 00000000001de676  /data/app/com.example.hellojni-Sytg7I9fr97KTcTz7Rrsjg==/oat/arm64/base.vdex (com.example.hellojni.HelloJni.onCreate+36)
Stack frame #10 pc 0000000000254ad4  /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.1893940555+488)
Stack frame #11 pc 000000000025a5c8  /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
---------------------------------省略部分-----------------------------------

2.4、ndk-stack

上面两种工具都是将崩溃点对应到源码再进行分析,objdump 则是可以在汇编层对崩溃原因进行分析。所以这要求我们必须了解一些 arm/x86 汇编知识。

objdump也是ndk自带的一个工具,通常与addr2line在同一目录:

$$NDK_HOME/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-objdump  

objdump的使用说明如下所示:

Usage: ./aarch64-linux-android-objdump <option(s)> <file(s)>
 Display information from object <file(s)>.
 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
  @<file>                  Read options from <file>
  -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.

./aarch64-linux-android-objdump: supported targets: elf64-littleaarch64 elf64-bigaarch64 elf32-littleaarch64 elf32-bigaarch64 elf32-littlearm elf32-bigarm elf64-little elf64-big elf32-little elf32-big plugin srec symbolsrec verilog tekhex binary ihex
./aarch64-linux-android-objdump: supported architectures: aarch64 aarch64:ilp32 arm armv2 armv2a armv3 armv3m armv4 armv4t armv5 armv5t armv5te xscale ep9312 iwmmxt iwmmxt2 arm_any plugin

The following AARCH64 specific disassembler options are supported for use
with the -M switch (multiple options should be separated by commas):

  no-aliases         Don't print instruction aliases.

  aliases            Do print instruction aliases.


The following ARM specific disassembler options are supported for use with
the -M switch:
  reg-names-special-atpcs  Select special register names used in the ATPCS
  reg-names-atpcs          Select register names used in the ATPCS
  reg-names-apcs           Select register names used in the APCS
  reg-names-std            Select register names used in ARM's ISA documentation
  reg-names-gcc            Select register names used by GCC
  reg-names-raw            Select raw register names
  force-thumb              Assume all insns are Thumb insns
  no-force-thumb           Examine preceding label to determine an insn's type

Report bugs to <http://source.android.com/source/report-bugs.html>.

objdump的基本用法如下所示:

objdump  ~/Desktop/workspace/android/min/Demo/HelloJNI/app/build/intermediates/cmake/arm8Debug/obj/arm64-v8a/ -dump ~/Desktop/min.log |tee ~/Desktop/ndk-stack.txt

最后产生的结果文件如下:

0000000000000648 <willCrash>:
willCrash():
/Users/min/Desktop/workspace/android/min/Demo/HelloJNI/app/src/main/cpp/hello-jni.c:27
 648:   d10043ff    sub sp, sp, #0x10
 64c:   52800f68    mov w8, #0x7b                   // #123
 650:   aa1f03e9    mov x9, xzr
/Users/min/Desktop/workspace/android/min/Demo/HelloJNI/app/src/main/cpp/hello-jni.c:28
 654:   f90007e9    str x9, [sp,#8]
/Users/min/Desktop/workspace/android/min/Demo/HelloJNI/app/src/main/cpp/hello-jni.c:29
 658:   f94007e9    ldr x9, [sp,#8]
 65c:   b9000128    str w8, [x9]
/Users/min/Desktop/workspace/android/min/Demo/HelloJNI/app/src/main/cpp/hello-jni.c:30
 660:   910043ff    add sp, sp, #0x10
 664:   d65f03c0    ret

0000000000000668 <Java_com_example_hellojni_HelloJni_stringFromJNI>:
Java_com_example_hellojni_HelloJni_stringFromJNI():
/Users/min/Desktop/workspace/android/min/Demo/HelloJNI/app/src/main/cpp/hello-jni.c:35
 668:   d100c3ff    sub sp, sp, #0x30
 66c:   a9027bfd    stp x29, x30, [sp,#32]
 670:   910083fd    add x29, sp, #0x20
 674:   f81f83a0    stur    x0, [x29,#-8]
 678:   f9000be1    str x1, [sp,#16]
/Users/min/Desktop/workspace/android/min/Demo/HelloJNI/app/src/main/cpp/hello-jni.c:36
 67c:   97ffffd5    bl  5d0 <willCrash@plt>
 680:   90000000    adrp    x0, 0 <__cxa_finalize@plt-0x5c0>
 684:   911ad001    add x1, x0, #0x6b4
/Users/min/Desktop/workspace/android/min/Demo/HelloJNI/app/src/main/cpp/hello-jni.c:37
 688:   f85f83a0    ldur    x0, [x29,#-8]
 68c:   f9400000    ldr x0, [x0]
 690:   f9429c00    ldr x0, [x0,#1336]
 694:   f85f83be    ldur    x30, [x29,#-8]
 698:   f90007e0    str x0, [sp,#8]
 69c:   aa1e03e0    mov x0, x30
 6a0:   f94007fe    ldr x30, [sp,#8]
 6a4:   d63f03c0    blr x30
 6a8:   a9427bfd    ldp x29, x30, [sp,#32]
 6ac:   9100c3ff    add sp, sp, #0x30
 6b0:   d65f03c0    ret

可以看到,000000000000065c这个地址的相关两个汇编指令如下:

 658:   f94007e9    ldr x9, [sp,#8]
 65c:   b9000128    str w8, [x9]

1、LDR R0, [R1]
LDR是把R1中的值取出放到寄存器R0中LDR:load R0 from register R1

2、STR R0, [R1]
STR是把R0中的值存入寄存器R1中,STR:store R0 to register R1

结合signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0信息,配合崩溃信号列表:

信号 描述
SIGSEGV 内存引用无效。
SIGBUS 访问内存对象的未定义部分。
SIGFPE 算术运算错误,除以零。
SIGILL 非法指令,如执行垃圾或特权指令
SIGSYS 糟糕的系统调用
SIGXCPU 超过CPU时间限制。
SIGXFSZ 文件大小限制。

我们大体可以猜出来这一个空指针的问题。

3、参考

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容