지난 포스팅에서는 JNI 단에서 발생하는 Crash 를 수집하는 방법을 설명해드렸습니다.
지난 포스팅 링크 : 링크
이번 포스팅에서는 JNI 관련 Crash 발생시 원인이 되는 곳을 찾는법에 대해서 포스팅을 작성하겠습니다.
주 개발을 Windows 에서 하므로, 몇몇 과정이 다를 수 있습니다.
arm-linux-androideabi-addr2line.exe
minidump_stackwalk.exe
INSTALL
파일 확인minidump_stackwalk
#include <jni.h>
#include <android/log.h>
#include <stdio.h>
#include "google_breakpad/src/client/linux/handler/exception_handler.h"
#include "google_breakpad/src/client/linux/handler/minidump_descriptor.h"
JNIEnv * jEnv = 0;
static google_breakpad::ExceptionHandler* exceptionHandler;
bool DumpCallback(const google_breakpad::MinidumpDescriptor& descriptor,
void* context,
bool succeeded) {
__android_log_print(ANDROID_LOG_DEBUG, "PluuSystem", "Dump path: %s\n", descriptor.path());
jclass cls = jEnv->FindClass("com/pluusystem/breakpadjavacall/NativeController");
if(cls == NULL) {
return false;
}
jmethodID mhthod = jEnv->GetStaticMethodID(cls, "NativeCrashCallback", "(Ljava/lang/String;)I");
if(mhthod == NULL) {
return false;
}
const char* path = descriptor.path();
jstring jstr = jEnv->NewStringUTF(path);
if (jstr == NULL) {
return false;
}
jint i = jEnv->CallStaticIntMethod(cls, mhthod, jstr);
return succeeded;
}
void Crash() {
// volatile int* a = reinterpret_cast<volatile int*>(NULL);
// *a = 1;
int i = 10 / 0;
}
extern "C" {
void Java_com_pluusystem_breakpadjavacall_MainActivity_initNative(JNIEnv* env, jobject obj, jstring filepath)
{
jEnv = env;
if (false) {
const char *path = env->GetStringUTFChars(filepath, 0);
google_breakpad::MinidumpDescriptor descriptor(path);
exceptionHandler = new google_breakpad::ExceptionHandler(descriptor, NULL, DumpCallback, NULL, true, -1);
}
__android_log_print(ANDROID_LOG_DEBUG, "PluuSystem", "initNative cal");
}
void Java_com_pluusystem_breakpadjavacall_MainActivity_crashService(JNIEnv* env, jobject obj)
{
__android_log_print(ANDROID_LOG_DEBUG, "PluuSystem", "crashService call");
Crash();
}
}
사전 작업 : 51번째 줄을 false 처리하여 Logcat 에 Crash Log 가 나오도록 수정
I/DEBUG﹕ *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/DEBUG﹕ Build fingerprint: 'generic/vbox86p/vbox86p:4.3/JLS36G/eng.buildbot.20150609.213200:userdebug/test-keys'
I/DEBUG﹕ Revision: '0'
I/DEBUG﹕ pid: 24903, tid: 24903, name: reakpadjavacall >>> com.pluusystem.breakpadjavacall <<<
I/DEBUG﹕ signal 8 (SIGFPE), code -6 (SI_TKILL), fault addr 00006147
I/DEBUG﹕ eax 0000000a ebx 97efffe4 ecx 00000000 edx 00000000
I/DEBUG﹕ esi 9ec38d9c edi bfb358ac
I/DEBUG﹕ xcs 00000073 xds 0000007b xes 0000007b xfs 00000000 xss 0000007b
I/DEBUG﹕ eip 97efe861 ebp bfb35878 esp bfb35868 flags 00210246
I/DEBUG﹕ backtrace:
I/DEBUG﹕ #00 pc 00000861 /data/app-lib/com.pluusystem.breakpadjavacall-2/libtest_google_breakpad.so (Crash()+22)
I/DEBUG﹕ #01 pc 00000915 /data/app-lib/com.pluusystem.breakpadjavacall-2/libtest_google_breakpad.so (Java_com_pluusystem_breakpadjavacall_MainActivity_crashService+55)
I/DEBUG﹕ #02 pc 0002a05b /system/lib/libdvm.so (dvmPlatformInvoke+79)
I/DEBUG﹕ #03 pc 0000653f [heap]
I/DEBUG﹕ #04 pc 00085b32 /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+434)
I/DEBUG﹕ #05 pc 0008a0b6 /system/lib/libdvm.so (dvmResolveNativeMethod(unsigned int const*, JValue*, Method const*, Thread*)+326)
I/DEBUG﹕ #06 pc 00173058 /system/lib/libdvm.so
I/DEBUG﹕ #07 pc 00005d93 <unknown>
I/DEBUG﹕ #08 pc 0003b322 /system/lib/libdvm.so (dvmMterpStd(Thread*)+66)
I/DEBUG﹕ #09 pc 000369e9 /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+217)
I/DEBUG﹕ #10 pc 000b9f62 /system/lib/libdvm.so (dvmInvokeMethod(Object*, Method const*, ArrayObject*, ArrayObject*, ClassObject*, bool)+1634)
I/DEBUG﹕ #11 pc 000ce9e0 /system/lib/libdvm.so (Dalvik_java_lang_reflect_Method_invokeNative(unsigned int const*, JValue*)+288)
I/DEBUG﹕ #12 pc 00173058 /system/lib/libdvm.so
I/DEBUG﹕ #13 pc 00005eff <unknown>
I/DEBUG﹕ #14 pc 0003b322 /system/lib/libdvm.so (dvmMterpStd(Thread*)+66)
I/DEBUG﹕ #15 pc 000369e9 /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+217)
I/DEBUG﹕ #16 pc 000bacf7 /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, char*)+759)
I/DEBUG﹕ #17 pc 0007774d /system/lib/libdvm.so (CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, char*)+109)
I/DEBUG﹕ #18 pc 0005d3ea /system/lib/libandroid_runtime.so (_JNIEnv::CallStaticVoidMethod(_jclass*, _jmethodID*, ...)+42)
I/DEBUG﹕ #19 pc 0005eaac /system/lib/libandroid_runtime.so (android::AndroidRuntime::start(char const*, char const*)+924)
I/DEBUG﹕ #20 pc 00001017 /system/bin/app_process (main+567)
I/DEBUG﹕ #21 pc 0000cedc /system/lib/libc.so (__libc_init+108)
I/DEBUG﹕ #22 pc 00000a91 /system/bin/app_process (_start+97)
I/DEBUG﹕ stack:
I/DEBUG﹕ bfb35828 00000000
I/DEBUG﹕ bfb3582c 00000000
I/DEBUG﹕ bfb35830 00000000
I/DEBUG﹕ bfb35834 00000000
I/DEBUG﹕ bfb35838 00000000
I/DEBUG﹕ bfb3583c 00000000
I/DEBUG﹕ bfb35840 00000000
I/DEBUG﹕ bfb35844 00000000
I/DEBUG﹕ bfb35848 00000000
I/DEBUG﹕ bfb3584c 00000000
I/DEBUG﹕ bfb35850 00000000
I/DEBUG﹕ bfb35854 00000000
I/DEBUG﹕ bfb35858 00000000
I/DEBUG﹕ bfb3585c 00000000
I/DEBUG﹕ bfb35860 00000000
I/DEBUG﹕ bfb35864 00000000
I/DEBUG﹕ #00 bfb35868 b71397a9 /system/lib/liblog.so (__android_log_print+9)
I/DEBUG﹕ bfb3586c 97efffe4 /data/app-lib/com.pluusystem.breakpadjavacall-2/libtest_google_breakpad.so
I/DEBUG﹕ bfb35870 9ec38d9c
I/DEBUG﹕ bfb35874 bfb358ac [stack]
I/DEBUG﹕ bfb35878 bfb35898 [stack]
I/DEBUG﹕ bfb3587c 97efe916 /data/app-lib/com.pluusystem.breakpadjavacall-2/libtest_google_breakpad.so (Java_com_pluusystem_breakpadjavacall_MainActivity_crashService+56)
I/DEBUG﹕ #01 bfb35880 00000003
I/DEBUG﹕ bfb35884 97efe92f /data/app-lib/com.pluusystem.breakpadjavacall-2/libtest_google_breakpad.so
I/DEBUG﹕ bfb35888 97efe9a6 /data/app-lib/com.pluusystem.breakpadjavacall-2/libtest_google_breakpad.so
I/DEBUG﹕ bfb3588c b61a3ccc /system/lib/libdvm.so
I/DEBUG﹕ bfb35890 a544bbc8 /dev/ashmem/dalvik-heap (deleted)
I/DEBUG﹕ bfb35894 00000001
I/DEBUG﹕ bfb35898 bfb358c8 [stack]
I/DEBUG﹕ bfb3589c b600c05c /system/lib/libdvm.so (dvmPlatformInvoke+80)
I/DEBUG﹕ #02 bfb358a0 b8e8f540 [heap]
I/DEBUG﹕ ........ ........
I/DEBUG﹕ memory map around fault addr 00006147:
I/DEBUG﹕ (no map below)
I/DEBUG﹕ (no map for address)
I/DEBUG﹕ 96e9e000-97223000 rw- /dev/ashmem/gralloc-buffer (deleted)
Logcat 에서 확인 할 사항은 JNI Module 명과 관련된 11, 12번째 줄에 내용입니다.
JNI 디버그 옵션으로 생성된 so 파일
과 arm-linux-androideabi-addr2line
를 이용해서 결과를 확인합니다.
arm-linux-androideabi-addr2line 를 사용하는 옵션은 아래와 같습니다.
arm-linux-androideabi-addr2line.exe [option(s)] [addr(s)]
관련 추천 옵션은 아래를 추천합니다.
// 11줄, 00000861 /data/app-lib/com.pluusystem.breakpadjavacall-2/libtest_google_breakpad.so (Crash()+22)
arm-linux-androideabi-addr2line -C -fe x86\libtest_google_breakpad.so 00000861
Crash()
D:\GitHub\BreakpadJavaCall\app\src\main/jni/test_breakpad.cpp:43
// 12줄, 00000915 /data/app-lib/com.pluusystem.breakpadjavacall-2/libtest_google_breakpad.so
arm-linux-androideabi-addr2line -C -fe x86\libtest_google_breakpad.so 00000915
Java_com_pluusystem_breakpadjavacall_MainActivity_crashService
D:\GitHub\BreakpadJavaCall\app\src\main/jni/test_breakpad.cpp:64
실제로 Crash 가 발생한 Stack 을 체크할수 있습니다.
사전 작업 : 51번째 줄을 true 처리하여 Google Breakpad 처리하도록 수정
Crash로 생성된 dump 파일 (예, 53cf87db-0429-1cbf-3cd576a2-2b42c50d.dmp) 을 minidump_stackwalk
를 이용해서 Dump 파일에서부터 Stack 정보를 취득합니다.
minidump_stackwalk <minidumo-file> [symbol-path ...]
minidump_stackwalk 53cf87db-0429-1cbf-3cd576a2-2b42c50d.dmp > 53cf87db-0429-1cbf-3cd576a2-2b42c50d.dmp.txt
해당 파일을 내용을 간략하게 표시하면 아래와 같습니다.
Operating system: Android
0.0.0 Linux 3.4.67-qemu+ #13 SMP PREEMPT Thu Mar 19 15:12:39 CET 2015 i686
CPU: x86
GenuineIntel family 6 model 60 stepping 3
1 CPU
Crash reason: SIGFPE
Crash address: 0x97ece827
Process uptime: not available
Thread 0 (crashed)
0 libtest_google_breakpad.so + 0x1a827
eip = 0x97ece827 esp = 0xbfb35868 ebp = 0xbfb35878 ebx = 0x97f01f0c
esi = 0x9ec38d9c edi = 0xbfb358ac eax = 0x0000000a ecx = 0x00000000
edx = 0x00000000 efl = 0x00210246
Found by: given as instruction pointer in context
1 libtest_google_breakpad.so + 0x1a9e1
eip = 0x97ece9e1 esp = 0xbfb35880 ebp = 0xbfb35898
Found by: previous frame's frame pointer
2 libdvm.so + 0x2a05c
eip = 0xb600c05c esp = 0xbfb358a0 ebp = 0xbfb358c8
Found by: previous frame's frame pointer
3 libdvm.so + 0x85b33
eip = 0xb6067b33 esp = 0xbfb358d0 ebp = 0x9df30af0
Found by: previous frame's frame pointer
4 data@app@com.pluusystem.breakpadjavacall-1.apk@classes.dex + 0x124f1c
eip = 0x9804df1c esp = 0xbfb358e8 ebp = 0x9df30af0
Found by: stack scanning
5 libtest_google_breakpad.so + 0x1a9a9
eip = 0x97ece9a9 esp = 0xbfb358ec ebp = 0x9df30af0
Found by: stack scanning
6 data@app@com.pluusystem.breakpadjavacall-1.apk@classes.dex + 0x119a50
eip = 0x98042a50 esp = 0xbfb358f4 ebp = 0x9df30af0
Found by: stack scanning
...생략...
관련 .so 파일에 해당하는 라인을 검색해서 해당내용을 추적할 수 있습니다.
추적방법은 위의 Logcat 에 적혀있는 방법과 동일합니다.
// 12줄, libtest_google_breakpad.so + 0x1a827
arm-linux-androideabi-addr2line -C -fe x86\libtest_google_breakpad.so 0x1a827
Crash()
D:\GitHub\BreakpadJavaCall\app\src\main/jni/test_breakpad.cpp:43
// 17줄, libtest_google_breakpad.so + 0x1a9e1
arm-linux-androideabi-addr2line -C -fe x86\libtest_google_breakpad.so 0x1a9e1
Java_com_pluusystem_breakpadjavacall_MainActivity_crashService
D:\GitHub\BreakpadJavaCall\app\src\main/jni/test_breakpad.cpp:65
// 29줄, libtest_google_breakpad.so + 0x1a9a9
arm-linux-androideabi-addr2line -C -fe x86\libtest_google_breakpad.so 0x1a9a9
Java_com_pluusystem_breakpadjavacall_MainActivity_crashService
D:\GitHub\BreakpadJavaCall\app\src\main/jni/test_breakpad.cpp:61
Google Breakpad 를 이용해서 덤프를 취득하여 디버그해본 결과, 기존 breakpad 의 샘플로는 올바른 덤프 취득을 할 수 없었습니다.
그래도, 테스트 도중 JNI 레벨에서 Crash 가 일어난 경우에 대해서 Stack 추적에 도움이 될듯합니다.
좀 더 정확한 디버그를 아시는분은 알려주시면 추가 포스팅을 하겠습니다.
comments powered by Disqus
Android NDK Google Breakpad Crash JNI Debug addr2line minidump_stackwalk
Subscribe to this blog via RSS.
LazyColumn/Row에서 동일한 Key를 사용하면 크래시가 발생하는 이유
Posted on 30 Nov 2024