Archive for the ‘stackframe’ Category

android: arm64: how to analyze the call stack after a process hit native crash

October 28, 2015

This post is to analyze the call stack after a process hits native crash in android.

testing environment
The infrastructure code base here is LA.BF64.1.1-06510-8×94.0 with Android 5.0.0_r2(LRX21M) and Linux kernel 3.10.49. The device CPU is architecture arm-v8 cortex-53.

use gdb to get call stack from core file
In android: coredump: analyze core file with gdb, we demonstrate how to use gdb to load core file and get call stack of coredumptest, which deferences a NULL pointer and hit native crash.

(gdb) bt
#0  strlen () at bionic/libc/arch-arm64/generic/bionic/strlen.S:71
#1  0x0000005595326f00 in strlen (s=0x0) at bionic/libc/include/string.h:239
#2  test4 () at frameworks/native/services/coredumptest/CoredumpTest.cpp:11
#3  0x0000005595326f88 in test3 () at frameworks/native/services/coredumptest/CoredumpTest.cpp:20
#4  0x0000005595327010 in test2 () at frameworks/native/services/coredumptest/CoredumpTest.cpp:29
#5  0x0000005595327098 in test1 () at frameworks/native/services/coredumptest/CoredumpTest.cpp:38
#6  0x0000005595326d7c in main () at frameworks/native/services/coredumptest/CoredumpTest.cpp:56

get call stack from tombstone
In addition to core file, we could also get call stacks from tombstone. While a 64-bit process hits native crash, debuggerd64 wlll attach the process and dump its register and call stacks in /data/tombstones/tombstone_0x, where 0 <= x <= 9.

ABI: 'arm64'
pid: 20948, tid: 20948, name: coredumptest  >>> /data/coredumptest <<< 
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 
    x0   0000000000000000  x1   0000000000000000  x2   0000007fcbe33358  x3   000000000000000a
    x4   0000000000000001  x5   0000000000000000  x6   000000000000000b  x7   0000000000000000
    x8   00000000000000a4  x9   0000000000000000  x10  0000007fcbe32f88  x11  0101010101010101
    x12  0000000000000001  x13  000000000000001e  x14  0000007faa6560f0  x15  0000007faa656100
    x16  0000005595338fb8  x17  0000007faa597424  x18  0000000000000000  x19  ffffffffffffffff
    x20  0000007fcbe33348  x21  0000000000000001  x22  0000005595326d50  x23  0000000000000000
    x24  0000000000000000  x25  0000000000000000  x26  0000000000000000  x27  0000000000000000
    x28  0000000000000000  x29  0000007fcbe33220  x30  0000005595326f00
    sp   0000007fcbe33220  pc   0000007faa597434  pstate 0000000040000000
    v0   2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e  v1   746165662e6d70642e74736973726570
    v2   6f63656e6362696c0000000000657275  v3   00000000000000000000000000000000
    v4   00000000000000008020080280000000  v5   00000000400000004000000000000000
    v6   00000000000000000000000000000000  v7   80200802802008028020080280200802
    v8   00000000000000000000000000000000  v9   00000000000000000000000000000000
    v10  00000000000000000000000000000000  v11  00000000000000000000000000000000
    v12  00000000000000000000000000000000  v13  00000000000000000000000000000000
    v14  00000000000000000000000000000000  v15  00000000000000000000000000000000
    v16  40100401401004014010040140100401  v17  00000000a00a80000000aa8000404000
    v18  00000000000000008020080280000000  v19  00000000000000000000000000000000
    v20  00000000000000000000000000000000  v21  00000000000000000000000000000000
    v22  00000000000000000000000000000000  v23  00000000000000000000000000000000
    v24  00000000000000000000000000000000  v25  00000000000000000000000000000000
    v26  00000000000000000000000000000000  v27  00000000000000000000000000000000
    v28  00000000000000000000000000000000  v29  00000000000000000000000000000000
    v30  00000000000000000000000000000000  v31  00000000000000000000000000000000
    fpsr 00000000  fpcr 00000000

backtrace:
    #00 pc 0000000000014434  /system/lib64/libc.so (strlen+16)
    #01 pc 0000000000000efc  /data/coredumptest
    #02 pc 0000000000000f84  /data/coredumptest
    #03 pc 000000000000100c  /data/coredumptest
    #04 pc 0000000000001094  /data/coredumptest
    #05 pc 0000000000000d78  /data/coredumptest (main+40)
    #06 pc 0000000000013474  /system/lib64/libc.so (__libc_init+100)
    #07 pc 0000000000000e8c  /data/coredumptest

use addr2line to analyze call stacks in tombstone
We could use addr2line to transform symbol address to source code function name and line number.

$ aarch64-linux-android-addr2line -e symbols/system/bin/coredumptest -a 0000000000000ef8
_Z5test4v
0x0000000000000ef8
frameworks/native/services/coredumptest/CoredumpTest.cpp:10
$ aarch64-linux-android-addr2line -e symbols/system/bin/coredumptest -a 0000000000000f84
0x0000000000000f84
_Z5test3v
frameworks/native/services/coredumptest/CoredumpTest.cpp:20
$ aarch64-linux-android-addr2line -e symbols/system/bin/coredumptest -a 000000000000100c
0x000000000000100c
_Z5test2v
frameworks/native/services/coredumptest/CoredumpTest.cpp:29
$ aarch64-linux-android-addr2line -f -e symbols/system/bin/coredumptest -a 0000000000001094
0x0000000000001094
_Z5test1v
frameworks/native/services/coredumptest/CoredumpTest.cpp:38
$ aarch64-linux-android-addr2line -f -e symbols/system/bin/coredumptest -a 0000000000000d78       
0x0000000000000d78
main
frameworks/native/services/coredumptest/CoredumpTest.cpp:56

review source code to see why the native crash happens
From source code, we could find that the native crash is due to dereferencing NULL pointer.

#define LOG_TAG "CoredumpTest"

#include <utils/Log.h>
#include <string.h>
#include <sys/resource.h>

using namespace android;

int test4()
{
    int ret = strlen(NULL);

    ALOGD("enter %s: %d", __func__,  ret);

    return ret;
}

int test3()
{
    int ret = test4() + 3;

    ALOGD("enter %s: %d", __func__, ret);

    return ret;
}

int test2()
{
    int ret = test3() + 2;

    ALOGD("enter %s: %d", __func__, ret);

    return ret;
}

int test1()
{
    int ret = test2() + 1;

    ALOGD("enter %s: %d", __func__, ret);

    return ret;
}

int main()
{
    struct rlimit core_limit;
    core_limit.rlim_cur = RLIM_INFINITY;
    core_limit.rlim_max = RLIM_INFINITY;

    if (setrlimit(RLIMIT_CORE, &core_limit) < 0) {
        ALOGD("Failed to setrlimit: %s", strerror(errno));
        return 1;
    }

    int n = test1();
    ALOGD("Ready to enter test");

    return 0;
}

conclusion
After a process hit native crash, we could analyze the call stack of the process from core file or tombstone. Then, review the source code to see why the crash happens.


%d bloggers like this: