네이티브 크래시 읽는 법 — Fatal signal 한 줄과 tombstone 백트레이스
셋톱박스에서 "재생 중 화면이 검게 변했다", "앱이 소리 없이 꺼졌다"는 증상은 자바 크래시가 아니라 코덱·드라이버·네이티브 라이브러리의 크래시인 경우가 많습니다.
이때 logcat에는 자바 스택트레이스 대신 Fatal signal 한 줄과 암호 같은 주소 목록이 남습니다. 이 글은 그 한 줄을 해석하는 법,
그리고 tombstone 파일의 백트레이스를 읽고 소스 위치로 바꾸는 법을 정리합니다. 형식과 예시는 source.android.com의 Diagnose native crashes 문서를 기준으로 했습니다.
1. Fatal signal 한 줄 분해하기
F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 2250 (CodecLooper), pid 2201 (com.example.player)
| 부분 | 뜻 |
|---|---|
Fatal signal 11 (SIGSEGV) | 프로세스가 받은 시그널. 종류는 아래 2장 |
code 1 (SEGV_MAPERR) | 시그널의 세부 이유. SEGV_MAPERR는 매핑되지 않은 주소, SEGV_ACCERR는 권한이 없는 주소(예: 읽기 전용 영역에 쓰기) |
fault addr 0x0 | 접근하려던 주소. 0이나 0에 가까운 작은 값이면 널 포인터(널 구조체의 필드 접근이면 0xc처럼 작은 수) |
in tid 2250 (CodecLooper) | 죽은 스레드와 그 이름. 이름만으로 어느 계층인지 짐작할 수 있는 경우가 많음 |
pid 2201 (com.example.player) | 죽은 프로세스. 옛 버전에는 이 부분이 없을 수 있음 |
2. 시그널 종류별 의미
| 시그널 | 흔한 원인 | 로그에서 볼 것 |
|---|---|---|
SIGSEGV (11) | 잘못된 메모리 접근: 널 포인터, 해제된 메모리 사용, 범위 밖 접근 | fault addr의 값 |
SIGABRT (6) | 의도적 중단: abort(), assert 실패, 치명 로그 호출 | Abort message: 줄 — 원인이 문장으로 적혀 있는 경우가 많음 |
SIGBUS (7) | 정렬되지 않은 접근, 매핑된 파일이 잘린 경우 등 | 메모리 맵(파일 매핑) 정보 |
SIGILL (4) | 잘못된 명령어 실행(손상된 코드, 다른 CPU용 바이너리) | 라이브러리 버전·아키텍처 |
SIGFPE (8) | 정수 0으로 나누기 등 | 백트레이스 맨 위 함수 |
SIGSYS (31) | 보안 정책(seccomp)이 금지한 시스템 호출 | SYS_SECCOMP 코드 |
SIGABRT의 Abort message 예
FORTIFY: ... prevented ...-byte write into ...-byte buffer— 버퍼 넘침을 컴파일러 보호 기능이 잡아 중단시킴.stack corruption detected— 스택이 덮어써짐(백트레이스에__stack_chk_fail).파일명:줄: 함수명: assertion "..." failed— 개발자가 넣은 assert가 실패. 메시지에 위치가 그대로 있음.
3. tombstone의 구조
네이티브 크래시가 나면 시스템은 상세 덤프를 /data/tombstones/tombstone_NN에 저장하고, 같은 내용의 앞부분을 DEBUG(버전에 따라 crash_dump) 태그로 logcat에도 남깁니다.
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'vendor/model/device:12/.../user/release-keys'
pid: 2201, tid: 2250, name: CodecLooper >>> com.example.player <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
(레지스터 값들)
backtrace:
#00 pc 0004a1c8 /vendor/lib/libexample_codec.so (ExampleDecoder::flush()+24)
#01 pc 00039f10 /vendor/lib/libexample_codec.so
#02 pc 0001d2a4 /system/lib/libstagefright.so (...)
...
- Build fingerprint — 정확히 어떤 펌웨어였는지. 같은 크래시가 특정 펌웨어에서만 나는지 비교할 때 씁니다.
- pid / tid / name —
>>> <<<사이가 프로세스 이름입니다. - signal — logcat의 Fatal signal 줄과 같은 정보.
- backtrace — 맨 위(
#00)가 크래시가 난 지점, 아래로 갈수록 그 함수를 부른 쪽입니다.
백트레이스 한 줄은 #번호 pc 라이브러리-안-오프셋 라이브러리-경로 (함수명+오프셋)입니다. 괄호 안 함수명이 있으면 그것만으로도 큰 단서이고,
없다면 라이브러리에 심볼이 제거된(stripped) 상태입니다.
먼저 볼 줄 고르기
#00이libc.so의abort·memcpy·strlen같은 표준 함수라면, 그건 피해자입니다. 아래로 내려가 처음 나오는 앱·제조사 라이브러리가 실제로 잘못된 값을 넘긴 쪽입니다.- 경로가
/vendor/로 시작하면 칩 제조사·기기 제조사가 제공한 라이브러리입니다. 셋톱박스의 코덱·디스플레이 크래시는 대부분 여기서 나고, 수정도 제조사 몫입니다. - 경로가 앱의 설치 폴더(
/data/app/...)면 앱이 포함한 네이티브 라이브러리입니다.
4. 주소를 소스 위치로 바꾸기 (심볼화)
라이브러리를 직접 빌드했고 심볼이 남은 원본 파일(.so)을 가지고 있다면 백트레이스의 오프셋을 소스 파일과 줄 번호로 바꿀 수 있습니다.
# NDK의 ndk-stack: tombstone 전체를 한 번에 변환
ndk-stack -sym 앱/obj/local/arm64-v8a -dump tombstone_02
# 한 줄만 볼 때: llvm-addr2line (NDK에 포함)
llvm-addr2line -C -f -e libexample_codec.so 0x4a1c8
- 오프셋은 반드시 크래시가 난 펌웨어·빌드와 똑같은 라이브러리 파일로 변환해야 합니다. 빌드가 하나라도 다르면 엉뚱한 줄이 나옵니다.
- 제조사 라이브러리처럼 원본이 없다면 심볼화는 할 수 없습니다. 이때는 tombstone 원본, Build fingerprint, 재현 절차를 묶어 제조사에 전달하는 것이 최선입니다.
5. tombstone 파일 받기
adb bugreport bugreport.zip # 일반 사용자 빌드에서 가장 확실한 방법 (압축 안에 tombstone 포함)
adb shell ls /data/tombstones # 개발용 빌드라면 직접 목록 확인·pull 가능
tombstone 파일은 번호를 돌려 쓰므로, 크래시가 반복되는 기기에서는 오래된 것이 금방 덮어써집니다. 재현 직후에 받으세요. logcat의 Tombstone written to: 줄이 어느 번호에 저장됐는지 알려 줍니다(대시보드의 크래시 덤프 저장 패턴).
6. 반복되는 네이티브 크래시를 묶어 보는 요령
- fault addr가 매번 0x0이고 #00 함수가 같다 — 같은 버그일 가능성이 높습니다(특정 조건에서 널 포인터).
- fault addr와 #00 위치가 매번 다르다 — 메모리가 다른 곳에서 먼저 망가졌고(해제 후 사용, 버퍼 넘침) 크래시는 그 결과일 뿐일 수 있습니다. 가장 어려운 유형입니다.
- 특정 콘텐츠·코덱에서만 난다 — 재생하던 영상의 코덱·해상도·DRM 여부를 함께 기록해 두면 재현이 쉬워집니다.
대시보드의 반복 오류 묶음은 주소와 숫자를 지운 서명으로 묶기 때문에, Fatal signal 줄의 시그널·코드·스레드 이름이 같은 크래시를 한 줄로 모아 보여 줍니다.
정리
- Fatal signal 한 줄에서 시그널, fault addr, 스레드 이름 세 가지만 읽어도 방향이 잡힙니다.
- SIGABRT라면
Abort message부터. 원인이 문장으로 적혀 있는 경우가 많습니다. - 백트레이스는 표준 라이브러리를 건너뛰고 처음 나오는 앱·제조사 라이브러리 줄을 봅니다.
- 심볼화는 똑같은 빌드의 라이브러리로만 합니다. 없으면 tombstone 원본을 그대로 전달하세요.
참고 자료: Android Open Source Project, "Diagnose native crashes" (source.android.com/docs/core/tests/debug/native-crash). 예시의 라이브러리 이름과 주소는 설명용으로 만든 것입니다.
· 실습: 셋톱박스 2대의 로그를 대시보드로 읽어 보기
· ANR 로그 분석하기
· 앱이 크래시 없이 사라질 때
· 아티클 목록 · 패턴 사전 · 서비스 소개
문의: dkdnj123@gmail.com