directory

  1. What are the types of Native crashes
  2. How to catch and collect Native crashes
  3. How to analyze and locate Native crashes
  4. data
  5. harvest

We know that a Java crash occurs when an uncaught exception occurs in Java code, causing the program to exit abnormally. Common exceptions include: NPE, OOM, ArrayIndexOutOfBoundsException, an IllegalStateException, ConcurrentModificationException and so on. There is another class of crashes that we have to focus on, and that is Native layer crashes, where stack information and specific crashes are not as clear as Java layer crashes. Whenever we meet, we need to find and analyze. The purpose of writing this article is to help ourselves make a record, and ALSO hope to help you with similar troubles. Let’s start to learn and practice together. This study practice demo to Zhang Shaowen “Android development master class” in the example.

What are the types of Native crashes

Let’s first build a Native crash and look at the crash information of Native

Signal xx: indicates the error type. We can first determine which type of crash is based on the error type. Common Android Native crashes are as follows: SIGSEGV has the highest probability.

Next is the register snapshot, which is not directly visible, and the fault ADDR is a key information, which will be used in the subsequent analysis of location.

The next step is to call the stack, which is also very important, and can directly help us see the stack information of Crash, but it needs the symbol table so to convert the corresponding function name and line number, otherwise it is also difficult to understand.

How to catch and collect Native crashes

Common Native crash capture tools: Chromium BreakPad, Tencent Bugly Let’s learn and practice BreakPad to collect Natvie crash. Breakpad is a cross-platform open source project. In this section, we will learn how to compile and use it in practice.

2.1 Let’s take a look at how Breakpad works

Image from: learn this trick to make C++ crash no escape!

2.2 The installation process is as follows

  1. Download [Breakpad] source (chromium.googlesource.com/breakpad/br…).
  2. Download dePOT_tools
  3. Breakpad relies on LSS, download it (github.com/adelshokhy1…) Save the linux_SYscall_support. h file in LSS to breakpad/ SRC /third_party/ LSS /.
  4. Breakpad./configure && make && sudo make install

The /usr/local/bin/minidump_dump and /usr/local/bin/minidump_stackwalk command tools will be used later in the analysis

2.3 Integrate Breakpad into the Android project

Copy the SRC folder from the Google-Breakpad source code to the project’s SRC /main/ CPP directory. Configure cmake or makefile. Here we use cmake cmake_minimum_required(VERSION 3.4.1)

Set (BREAKPAD_ROOT ${CMAKE_CURRENT_SOURCE_DIR} ${BREAKPAD_ROOT} / SRC/common/android/include) # classified files to compile the CPP code file (GLOB BREAKPAD_SOURCES_COMMON ${BREAKPAD_ROOT}/src/client/linux/crash_generation/crash_generation_client.cc ${BREAKPAD_ROOT}/src/client/linux/dump_writer_common/thread_info.cc ${BREAKPAD_ROOT}/src/client/linux/dump_writer_common/ucontext_reader.cc ${BREAKPAD_ROOT}/src/client/linux/handler/exception_handler.cc ${BREAKPAD_ROOT}/src/client/linux/handler/minidump_descriptor.cc ${BREAKPAD_ROOT}/src/client/linux/log/log.cc ${BREAKPAD_ROOT}/src/client/linux/microdump_writer/microdump_writer.cc ${BREAKPAD_ROOT}/src/client/linux/minidump_writer/linux_dumper.cc ${BREAKPAD_ROOT}/src/client/linux/minidump_writer/linux_ptrace_dumper.cc ${BREAKPAD_ROOT}/src/client/linux/minidump_writer/minidump_writer.cc ${BREAKPAD_ROOT}/src/client/minidump_file_writer.cc  ${BREAKPAD_ROOT}/src/common/convert_UTF.c ${BREAKPAD_ROOT}/src/common/md5.cc ${BREAKPAD_ROOT}/src/common/string_conversion.cc ${BREAKPAD_ROOT}/src/common/linux/elfutils.cc ${BREAKPAD_ROOT}/src/common/linux/file_id.cc ${BREAKPAD_ROOT}/src/common/linux/guid_creator.cc ${BREAKPAD_ROOT}/src/common/linux/linux_libc_support.cc ${BREAKPAD_ROOT}/src/common/linux/memory_mapped_file.cc ${BREAKPAD_ROOT}/ SRC /common/ Linux /safe_readlink.cc ${BREAKPAD_ROOT}/src/common/android/breakpad_getcontext.S ) set_source_files_properties(${BREAKPAD_ASM_SOURCE} Add_library (breakpad STATIC ${BREAKPAD_SOURCES_COMMON} ${BREAKPAD_ASM_SOURCE}) # link target_link_libraries(breakpad log)Copy the code

2.4 Add breakpad callback

Uncaught exceptions in the Java layer can be handled by UncaughtExceptionHandler.

 google_breakpad::MinidumpDescriptor descriptor(path);
    static google_breakpad::ExceptionHandler eh(descriptor, NULL, DumpCallback, NULL, true, -1);
Copy the code

Details are as follows:

#include <stdio.h> #include <jni.h> #include "client/linux/handler/exception_handler.h" #include "client/linux/handler/minidump_descriptor.h" void onNativeCrash(const char* info) { JNIEnv *env = 0; jclass crashPinClass = env->FindClass( "com/test/crash/TestCrash"); if (crashPinClass == NULL){ return; } jmethodID crashReportMethod = env->GetStaticMethodID(crashPinClass, "onNativeCrash", "(Ljava/lang/String;) V"); if (crashReportMethod == NULL) { return; } jstring crashInfo = env->NewStringUTF(info); env->CallStaticVoidMethod(crashPinClass, crashReportMethod, crashInfo); } / / collapse callback bool DumpCallback (const google_breakpad: : MinidumpDescriptor & descriptor, void * context, Bool Succeeded) {onNativeCrash(""); return succeeded; } extern "C" JNIEXPORT void JNICALL Java_com_sample_breakpad_BreakpadInit_initBreakpadNative(JNIEnv *env, jclass type, jstring path_) { const char *path = env->GetStringUTFChars(path_, 0); google_breakpad::MinidumpDescriptor descriptor(path); static google_breakpad::ExceptionHandler eh(descriptor, NULL, DumpCallback, NULL, true, -1); env->ReleaseStringUTFChars(path_, path); }Copy the code

Then load so to set the storage path of the DMP file generated after the crash. How do we analyze crashes collected? In the following section we continue to learn about practice.

Iii. How to analyze and locate Native crash

Before looking at several common analysis tools, let’s look at the difference between compiling and producing so with and without a sign table.

We can use the file command to see the difference between them

file cmake/debug/obj/arm64-v8a/libcrash-lib.so ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, BuildID[sha1]=c776759b526457b5777fc8833f7fc0fcc46055cc, with debug_info, For time to view view Namely take the symbol table file transforms/stripDebugSymbol/debug / 0 / lib/arm64 v8a/libcrash - lib. So the ELF 64 - bit LSB Shared object, ARM aarch64, Version 1 (SYSV), dynamically linked, BuildID [sha1] = c776759b526457b5777fc8833f7fc0fcc46055cc, stripped - > stripped the debug information, There's no sign tableCopy the code

If it is so developed and compiled by ourselves, the SO with symbol table should be backed up or uploaded when it is released, so as to facilitate analysis and location of native crash. Special attention should be paid to that: the MD5 of SO printed by different machines is different, so the corresponding so with symbol table should be saved after the release (SO of different architectures in the OBj directory).

So let’s take a look at some of the tools that we use

3.1 minidumP_stackWalk Export crash stack information

This is the command tool we compiled in the previous section. Usage:

minidump_stackwalk fd311404-a968-4ce0-17d5fa8a-61a8fdf1.dmp libcrash-lib.so >crash.log
Copy the code

The generated crash.log file is as follows

CPU: arm64 8 CPUs GPU: UNKNOWN Crash reason: SIGSEGV /SEGV_MAPERR Crash address: 0x0 Process uptime: Not available Thread 0 (crashed) 0 libcrash-lib.so + 0x5e0 --> Error address x0 = 0x0000007b14AC4e00 x1 = 0x0000007fedDE9894 x2 =  0x0000000000000000 x3 = 0x0000007b14a56c00 x4 = 0x0000007feddeaa00 x5 = 0x0000007a7e1a7965 @ "crash.log" 2226L, 114492BCopy the code

Addr2line can convert the address to the corresponding function name and line number.

3.2 the addr2line

The basic usage is as follows

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: -e --exe=<executable> Set the input file name (default is A. out) -f --functions Show function namesCopy the code

The path of the addr2line command is as follows. You can select the addr2line based on the CPU architecture of the device in the crash information.

Arm: $NDK_PATH toolchains/arm - Linux - androideabi - 4.9 / prebuilt/Darwin - x86_64 / bin arm64: $NDK_PATH/toolchains/aarch64 - Linux - android 4.9 / prebuilt/Darwin - x86_64 / binCopy the code

Dump (arm64, 0x5e0); add2line (arm64)

/ Users/yangbin/Library/Android/Android - the NDK - r16b toolchains/aarch64 - Linux - Android - 4.9 / prebuilt/Darwin - x86_64 / bin/aarch64 - linux-android-addr2line -f -e /Users/yangbin/work/avwork/thirdparty/nativecrash/Chapter01/sample/build/intermediates/cmake/debug/obj/arm64-v8a/libcras h-lib.so 0x5e0 _Z5Crashv /Users/yangbin/work/avwork/thirdparty/nativecrash/Chapter01/sample/.externalNativeBuild/cmake/debug/arm64-v8a/.. /.. /.. /.. /src/main/cpp/crash.cpp:10Copy the code

It can be seen that the output of the corresponding error class and the number of lines, combined with the error cause SIGSEGV can quickly analyze the specific cause.

3.3 Script the preceding procedure

Sh./test/TMP/fd311404-a968-4ce0-17d5FA8a-61a8fdf1.dmp crash.log The script comes from: Learn this trick, let C++ crash nowhere to escape!

#! /bin/bash if [ $# != 3 ] ; then echo "USAGE: $0 TARGET_NAME DMP_NAME OUTPUT_NAME" echo " e.g.: $0 test fd311404-a968-4ce0-17d5fa8a-61a8fdf1.dmp crash.log" exit 1; GetStackTrace () {echo "@getStackTrace ": {echo "@getStackTrace" : {echo "@getstackTrace" : Sym_file_name =$target_file_name'. Sym '# $sym_file_name =' head -n1 OIFS=$IFS; IFS=" "; set -- $line1; aa=$1; bb=$2; cc=$3; dd=$4; IFS=$OIFS version_number=$dd Mkdir -p./symbols/$target_file_name/$version_number mv $sym_file_name /symbols/$target_file_name/$version_number # redirects stack trace information to file minidump_stackwalk $dmp_file_name./symbols > $output_file_name } main() { getSymbol if [ $? == 0 ] then getStackTrace fi }Copy the code

3.4 the NDK – stack

The NDK-Stack is also a very useful tool that needs to be analyzed in conjunction with a Tombstone file at crash time.

The ndK-stack is used as follows

usage: ndk-stack.py [-h] -sym SYMBOL_DIR [-i INPUT]

Symbolizes Android crashes.

optional arguments:
  -h, --help            show this help message and exit
  -sym SYMBOL_DIR, --sym SYMBOL_DIR
                        directory containing unstripped .so files
  -i INPUT, -dump INPUT, --dump INPUT
                        input filename

ndk-stack -sym $PROJECT_PATH/obj/local/armeabi-v7a -dump tombstone.txt
Copy the code

Tombstone files can be obtained via adb Bugreport. Let’s take a look at the process of taking down the tombstone file by using the adb bugreport command and combining it with the NDK-Stack analysis

Adb bugreport.unzip bugreport-oneplus5t-qkq1.191014.012-2021-11-28-14-49-22. zip CD FS/data/tombstones We take the most recent one to analyze the NDK-stack-SYM /Users/yangbin/work/avwork/thirdparty/nativecrash/Chapter01/sample/build/intermediates/cmake/debug/obj/arm64-v8a -dump tombstone_09Copy the code

3.5 IDA Pro

If there is no symbol table so, we can use IDA so reverse analysis tool to analyze location analysis. For example, we can use IDA to open libcrash-lib.so without symbol table and query the problem by error address

Open libcrash-lib.so with IDA and skip to address 0x5e0

Let’s use libcrash-lib.so without the symbol table

You can see that you can also locate the corresponding class. But are some assembly language, need to understand. Objdump, another tool, can also be used to find the corresponding assembly information, and further analysis.

This article basically here, more for two months, familiar with this face two months post changes, more important is the target realized suddenly relaxed, actually this is the starting point, through this two months of work to understand familiar, audio and video has a very wide range of knowledge and application really involved, decoding, rendering, transmission, agreement, player, graphics, AI, etc. Come on, the next article begins our entry into the FFMPEG source code parsing series. Try to write at least one essay a week and study together

Four, data

  1. Crash Optimization (PART 1) : All that “crash” stuff
  2. Crash capture mechanism and implementation of Android Native code
  3. Learn this trick, let C++ crash nowhere to escape!
  4. Android uses Google Breakpad for crash log management
  5. Native crash log analysis method developed by Android NDK&JNI
  6. Crash capture mechanism and implementation of exception handling – Native layer
  7. Android NDK Tombstone/Crash Analysis
  8. Android Native crash location
  9. Android NDK tombstone/crash analysis
  10. How to analyze and locate Android Native Crash
  11. Dry goods | android APP crash – xCrash capture scheme
The corresponding open source project - "\ [[https://github.com/iqiyi/xCrash\]] (HTTP: / / https://links.jianshu.com/go?to=https%3A%2F%2Fgithub.com%2Fiqiyi%2FxCrash %255D)Copy the code
  1. Bugly-android Native code crash capture mechanism and implementation
  2. Blade Rider: Common Crashes and errors in Android Native

Five, the harvest

Through this study, we are familiar with how to capture and analyze native crashes. The summary is as follows:

  1. The learning practice is to capture and collect native crashes through breakpad
  2. Minidump_stackwalk is used to convert dump files generated by Breakpad into native crash information files, and then use add2line and the corresponding so with symbol table to resolve the crashed classes and the corresponding line number
  3. It is practical to obtain tombstone file and analyze natvie crash stack with NDK_stack
  4. So analysis of unsigned tables by IDA Pro is practiced

Thank you for reading

In the next article, we will enter the FFMPEG series again and study the source code level. Welcome to pay attention to the public account “audio and video development journey”, learn and grow together.

Welcome to communicate