안드로이드의 native stack trace의 활용
밥벌이2011. 8. 30. 17:52
순수 자바 어플리케이션이라면 디버그가 꽤나 쉽지만 JNI를 쓴 앱에서 native쪽에서 죽는 문제를 디버그하려면 일단 눈물 부터 닦고 시작해야 하는 게 안드로이드다. 물론 이전에 쓴 안드로이드 Native단에서 GDB로 디버그하기의 방법으로 gdb로 편하게 디버그 할 수도 있지만, 세상일이 언제나 호락호락하게 이쪽 형편에 맞춰 주는 게 아니라서, 가령 특정 단말에서만 Native에서 죽는데 단말 바이너리가 개발용이 아니라서 gdbserver가 탑재 되어 있지도 않고 탑재 시킬수도 없는 상황이라든가 디버그하다가 오히려 gdbserver가 미쳐서 세그멘테이션 폴트로 계속 죽는다든가 뭐 그런 상황이 언제든지 찾아 올 수 있다.
안드로이드 앱이 native 레이어에서 죽으면 보통 다음과 같은 로그를 뿌리게 된다.
방법은 간단하다. 안드로이드 소스나 NDK에 포함된 objdump를 사용하는 것으로, objdump 파일은 (리눅스의 경우) prebuilt/linux-x86/arm-eabi-[버전]/bin/ 내에 있다.
위와 같이 실행하면 libwacrt.asm 파일이 만들어지게 되며 asm 파일을 열어서 스택 트레이스에 찍힌 주소를 검색해 보면 손쉽게 어디서 죽었는지 확인할 수 있다.
이와 같은 방법으로 유추한 콜 스택은:
이 되겠다.
%%P.S. 페북에서 누가 댓글 달아서 알게 됐는데 objdump 대신 addr2line을 써도 된다. 오히려 더 편한가??
안드로이드 앱이 native 레이어에서 죽으면 보통 다음과 같은 로그를 뿌리게 된다.
위의 콜 스택을 보면 JNI로 호출 된 libwacrt 라이브러리 내에서 뭔가 열심히 일하다 죽었다는 것을 알 수 있지만 심볼 테이블이 나오지 않기 때문에 실제 어떤 함수를 호출하다가 죽었는지는 표시되지 않는다. 그러나 strip 되지 않은 라이브러리를 objdump 시킨 후 스택 트레이스에 찍힌 PC 값을 기반으로 뭘 하다 죽었는지를 알아 낼 수 있다는 게 이 글의 핵심이다.D/dalvikvm( 3130): GC_CONCURRENT freed 461K, 53% free 2874K/6087K, external 452K/1028K, paused 2ms+1msI/DEBUG ( 2573): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***I/DEBUG ( 2573): Build fingerprint: 'samsung/SHW-M250K/SHW-M250K:2.3.3/GINGERBREAD/ED12:eng/test-keys'I/DEBUG ( 2573): pid: 16568, tid: 16577 >>> com.kwac.widgetmanager <<<I/DEBUG ( 2573): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000I/DEBUG ( 2573): r0 00000000 r1 00000001 r2 002191b8 r3 00000000I/DEBUG ( 2573): r4 81da96bc r5 81da0ae4 r6 00000000 r7 00000000I/DEBUG ( 2573): r8 00000001 r9 81da0ae4 10 46927e54 fp 000fc788I/DEBUG ( 2573): ip 81da0b34 sp 46b3a7b0 lr fffff5a4 pc 81bbbfa0 cpsr 00000030I/DEBUG ( 2573): d0 3f80000041800000 d1 0000000041800000I/DEBUG ( 2573): d2 0000000000000000 d3 0000000000000000I/DEBUG ( 2573): d4 0000000500000000 d5 41d397c7f2000000I/DEBUG ( 2573): d6 408f400000000000 d7 42732239425fd0e1I/DEBUG ( 2573): d8 0000000000000000 d9 0000000000000000I/DEBUG ( 2573): d10 0000000000000000 d11 0000000000000000I/DEBUG ( 2573): d12 0000000000000000 d13 0000000000000000I/DEBUG ( 2573): d14 0000000000000000 d15 0000000000000000I/DEBUG ( 2573): d16 0000000000000001 d17 3ff0000000000000I/DEBUG ( 2573): d18 3ff0000000000000 d19 0000000000000000I/DEBUG ( 2573): d20 0000000000000000 d21 0000000000000000I/DEBUG ( 2573): d22 3ff0000000000000 d23 0000000000000000I/DEBUG ( 2573): d24 3ff0000000000000 d25 0000000000000000I/DEBUG ( 2573): d26 0000000000000000 d27 0000000000000000I/DEBUG ( 2573): d28 0002aaa80002aaa8 d29 0002aaa80002aaa8I/DEBUG ( 2573): d30 0001000000010000 d31 0001000000010000I/DEBUG ( 2573): scr 60000010I/DEBUG ( 2573):I/DEBUG ( 2573): #00 pc 003bbfa0 /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #01 pc 002358f2 /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #02 pc 0023596a /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #03 pc 0029ae72 /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #04 pc 002ac342 /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #05 pc 0016a0c4 /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #06 pc 0016db78 /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #07 pc 00250044 /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #08 pc 0025045a /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #09 pc 002508fc /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #10 pc 00250bfe /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #11 pc 00242808 /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #12 pc 00157b8a /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #13 pc 00157bc4 /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #14 pc 0014fada /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #15 pc 00151a48 /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #16 pc 00151c32 /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #17 pc 00151c56 /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #18 pc 00151fde /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #19 pc 002edda8 /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #20 pc 0015159e /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #21 pc 002ef050 /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #22 pc 00158c54 /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #23 pc 001589ac /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #24 pc 002ede0c /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #25 pc 0014fb4a /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #26 pc 00151864 /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #27 pc 00249380 /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #28 pc 00017eb4 /system/lib/libdvm.soI/DEBUG ( 2573): #29 pc 00049ae4 /system/lib/libdvm.soI/DEBUG ( 2573): #30 pc 0001d0c8 /system/lib/libdvm.soI/DEBUG ( 2573): #31 pc 00022398 /system/lib/libdvm.soI/DEBUG ( 2573):I/DEBUG ( 2573): code around pc:I/DEBUG ( 2573): 81bbbf80 62637022 1c58e00a 0063eb00 ff9cf7ffI/DEBUG ( 2573): 81bbbf90 69e26a63 f8421c59 62617023 e018f8dfI/DEBUG ( 2573): 81bbbfa0 f8556831 6019300e 81f0e8bd 0014a6a7I/DEBUG ( 2573): 81bbbfb0 001e4bb4 001ed780 fffff5a4 001ed748I/DEBUG ( 2573): 81bbbfc0 bf004770 4b0bb510 46047a02 b10a447bI/DEBUG ( 2573):I/DEBUG ( 2573): code around lr:I/DEBUG ( 2573): fffff584 ffffffff ffffffff ffffffff ffffffffI/DEBUG ( 2573): fffff594 ffffffff ffffffff ffffffff ffffffffI/DEBUG ( 2573): fffff5a4 ffffffff ffffffff ffffffff ffffffffI/DEBUG ( 2573): fffff5b4 ffffffff ffffffff ffffffff ffffffffI/DEBUG ( 2573): fffff5c4 ffffffff ffffffff ffffffff ffffffffI/DEBUG ( 2573):I/DEBUG ( 2573): stack:I/DEBUG ( 2573): 46b3a770 46927e54I/DEBUG ( 2573): 46b3a774 afd14173 /system/lib/libc.soI/DEBUG ( 2573): 46b3a778 81da96bcI/DEBUG ( 2573): 46b3a77c 00000001I/DEBUG ( 2573): 46b3a780 002191b8I/DEBUG ( 2573): 46b3a784 00000000I/DEBUG ( 2573): 46b3a788 00000001I/DEBUG ( 2573): 46b3a78c afd14789 /system/lib/libc.soI/DEBUG ( 2573): 46b3a790 81da96bcI/DEBUG ( 2573): 46b3a794 81c3f393 /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): 46b3a798 81da96bcI/DEBUG ( 2573): 46b3a79c 81bbbee9 /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): 46b3a7a0 81da96bcI/DEBUG ( 2573): 46b3a7a4 81da0ae4I/DEBUG ( 2573): 46b3a7a8 df002777I/DEBUG ( 2573): 46b3a7ac e3a070adI/DEBUG ( 2573): #00 46b3a7b0 46b3a7e0I/DEBUG ( 2573): 46b3a7b4 00000000I/DEBUG ( 2573): 46b3a7b8 001b07f8I/DEBUG ( 2573): 46b3a7bc 00000000I/DEBUG ( 2573): 46b3a7c0 00000001I/DEBUG ( 2573): 46b3a7c4 81a358f7 /data/data/com.kwac.widgetmanager/lib/libwacrt.soI/DEBUG ( 2573): #01 46b3a7c8 46b3a7e0I/DEBUG ( 2573): 46b3a7cc 0019ff68I/DEBUG ( 2573): 46b3a7d0 001b07f8I/DEBUG ( 2573): 46b3a7d4 00000000I/DEBUG ( 2573): 46b3a7d8 00000001I/DEBUG ( 2573): 46b3a7dc 81a3596f /data/data/com.kwac.widgetmanager/lib/libwacrt.so
방법은 간단하다. 안드로이드 소스나 NDK에 포함된 objdump를 사용하는 것으로, objdump 파일은 (리눅스의 경우) prebuilt/linux-x86/arm-eabi-[버전]/bin/ 내에 있다.
$ arm-eabi-objdump -dR libwacrt.so > libwacrt.asm
위와 같이 실행하면 libwacrt.asm 파일이 만들어지게 되며 asm 파일을 열어서 스택 트레이스에 찍힌 주소를 검색해 보면 손쉽게 어디서 죽었는지 확인할 수 있다.
00249348 <_ZN7androidL12DestroyFrameEP7_JNIEnvP8_jobject>:249348: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr}24934c: 4c19 ldr r4, [pc, #100] (2493b4 <_ZN7androidL12DestroyFrameEP7_JNIEnvP8_jobject+0x6c>)24934e: 460e mov r6, r1249350: 4605 mov r5, r0249352: 447c add r4, pc249354: 68e2 ldr r2, [r4, #12]249356: f7ff f895 bl 248484 <_ZN7_JNIEnv11GetIntFieldEP8_jobjectP9_jfieldID>24935a: 4607 mov r7, r024935c: f71f fb34 bl 1689c8 <_ZNK7WebCore5Frame4viewEv>249360: 4604 mov r4, r0249362: 6840 ldr r0, [r0, #4]249364: 1c43 adds r3, r0, #1249366: 4638 mov r0, r7249368: 6063 str r3, [r4, #4]24936a: f71f fb27 bl 1689bc <_ZNK7WebCore5Frame6loaderEv>24936e: 4680 mov r8, r0249370: 4638 mov r0, r7249372: f71f fbe3 bl 168b3c <_ZNK7WebCore5Frame4pageEv>249376: 4607 mov r7, r0249378: f1b8 0f00 cmp.w r8, #0 ; 0x024937c: d002 beq.n 249384 <_ZN7androidL12DestroyFrameEP7_JNIEnvP8_jobject+0x3c>24937e: 4640 mov r0, r8249380: f708 fa64 bl 15184c <_ZN7WebCore11FrameLoader16detachFromParentEv>249384: b12f cbz r7, 249392 <_ZN7androidL12DestroyFrameEP7_JNIEnvP8_jobject+0x4a>249386: 4638 mov r0, r7249388: f727 f80c bl 1703a4 <_ZN7WebCore4PageD1Ev>24938c: 4638 mov r0, r724938e: f6c5 ffcf bl 10f330 <_ZN3WTF8fastFreeEPv>249392: 1d20 adds r0, r4, #4249394: f705 f876 bl 14e484 <_ZN3WTF10RefCountedIN7WebCore6WidgetEE5derefEv>249398: f8df c01c ldr.w ip, [pc, #28] ; 2493b8 <_ZN7androidL12DestroyFrameEP7_JNIEnvP8_jobject+0x70>24939c: 682a ldr r2, [r5, #0]24939e: 4628 mov r0, r52493a0: 44fc add ip, pc2493a2: 4631 mov r1, r62493a4: 2300 movs r3, #02493a6: f8d2 41b4 ldr.w r4, [r2, #436]2493aa: f8dc 200c ldr.w r2, [ip, #12]2493ae: 47a0 blx r42493b0: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc}2493b4: 0035d40e .word 0x0035d40e2493b8: 0035d3c0 .word 0x0035d3c0
이와 같은 방법으로 유추한 콜 스택은:
....귀찮다 위쪽은 생략...WebCore::ResourceLoader::cancel()WebCore::DocumentLoader::stopLoading(DatabasePolicy)WebCore::FrameLoader::stopAllLoaders(DatabasePolicy)WebCore::FrameLoader::detachFromParent()android::DestroyFrame(JNIEnv*)
%%P.S. 페북에서 누가 댓글 달아서 알게 됐는데 objdump 대신 addr2line을 써도 된다. 오히려 더 편한가??
$ arm-eabi-addr2line -e libwacrt.so 00249380
[소스 위치 어딘가...]/WebCoreFrameBridge.cpp:1044
'밥벌이' 카테고리의 다른 글
MSSQL에서 LIMIT 구문 흉내내기 (0) | 2012.06.20 |
---|---|
안드로이드 GDB 디버깅 ver 2 (2) | 2012.02.22 |
안드로이드 Asset 사용에 있어 몇가지... (0) | 2011.08.05 |
안드로이드 캘린더 연동 앱 만들기 Part 2 (0) | 2011.06.02 |
안드로이드 캘린더 연동 앱 만들기 Part 1 (12) | 2011.03.24 |