Core Dump 확인 방법 — 활성화·수집·gdb 분석
NOTE
Core dump는 크래시 “순간의 메모리 스냅샷”이다. 어떤 함수의 몇 번째 줄에서, 어떤 변수 값으로, 어떤 호출 경로를 타고 죽었는지 — 로그로는 못 얻는 정보를 사후에 그대로 재현해서 볼 수 있다.
0. 사전 조건 — core dump가 왜 안 남는가
기본값이 꺼져 있는 배포판이 많다. 순서대로 확인한다.
(1) 현재 셸의 core 크기 제한
ulimit -c # 0이면 비활성. unlimited면 무제한
ulimit -c unlimited # 현재 셸 및 이 셸에서 뜬 자식 프로세스에 한해 활성화이 설정은 셸 세션에만 적용된다. 데몬/서비스로 띄운 프로세스는 아래 systemd 방법을 쓴다.
(2) 코드 내부에서 직접 설정 (셸 설정에 의존하고 싶지 않을 때)
#include <sys/resource.h>
struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
setrlimit(RLIMIT_CORE, &rl);(3) systemd 서비스라면
/etc/systemd/system/foo.service의 [Service] 섹션에 추가한다.
LimitCORE=infinitysystemd 단위는 셸의 ulimit을 상속받지 않으므로 별도 설정이 필수다.
(4) core 파일이 어디에 쌓이는지 — core_pattern
cat /proc/sys/kernel/core_patterncore또는core.%p— 크래시한 프로세스의 현재 작업 디렉터리에 생성 (%p=PID)|/usr/lib/systemd/systemd-coredump ...— 파이프로 시작하면 systemd-coredump가 가로채서 저널에 저장한다(요즘 배포판 기본값). 이 경우 작업 디렉터리에 파일이 안 보이는 게 정상이며, 아래coredumpctl로 조회해야 한다.
1. systemd-coredump 환경 — coredumpctl
coredumpctl list # 최근 크래시 목록 (PID, 시각, 실행파일, 시그널)
coredumpctl info <PID 또는 실행파일명> # 상세 정보(시그널, 커맨드라인, 메모리맵)
coredumpctl gdb <PID 또는 실행파일명> # 해당 core를 gdb로 바로 열기
coredumpctl dump <PID> -o /tmp/my.core # core 파일로 따로 저장2. 전통적인 core 파일 — gdb로 직접 분석
gdb ./myprog core # 또는 coredumpctl dump로 뽑아낸 파일gdb 안에서 자주 쓰는 명령은 다음과 같다.
| 명령 | 용도 |
|---|---|
bt (backtrace) | 크래시 시점의 호출 스택 — 가장 먼저 확인할 것 |
bt full | 각 프레임의 지역 변수 값까지 같이 출력 |
frame N | N번 프레임으로 이동해서 그 시점 상태 확인 |
info locals | 현재 프레임의 지역 변수 전체 |
print 변수명 / p *포인터 | 특정 값 확인 (NULL인지, 이상한 값인지) |
info registers | 크래시 시점 레지스터 (SIGSEGV의 faulting address 등) |
list | 크래시 라인 주변 소스 코드 |
thread apply all bt | 멀티스레드 프로그램에서 모든 스레드의 스택을 한 번에 |
x/20xw $sp | 크래시 시점 스택 메모리를 16진수로 덤프 |
최소 예시
(gdb) bt
#0 strcpy_internal () from /lib/x86_64-linux-gnu/libc.so.6
#1 0x0000555555555169 in copy_name (dst=0x0, src=0x7fffffffe420 "hello") at main.c:12
#2 0x0000555555555195 in main () at main.c:20
(gdb) frame 1
#1 0x0000555555555169 in copy_name (dst=0x0, src=...) at main.c:12
12 strcpy(dst, src);
(gdb) print dst
$1 = 0x0
dst가 0x0(NULL)인 걸 확인 — NULL 포인터 역참조로 바로 원인이 확정된다.
3. gdb가 쓸모없어지는 흔한 실수들
WARNING
아래 조건 중 하나라도 어기면
bt가?? in ?? ()만 찍거나 라인 정보가 아예 안 나온다.
-g없이 컴파일 — 디버그 심볼이 없으면 함수명/라인 정보 자체가 바이너리에 없다. 최소-g -O0(최적화까지 끄면 변수 값도 정확)로 다시 빌드해서 재현해야 한다.strip된 바이너리 — 배포 시 심볼 테이블을 제거한 경우. 심볼 있는 빌드로 재현하거나.debug심볼 파일을 별도 보관해뒀다가 매칭한다.- core를 만들 때와 다른 버전의 바이너리/라이브러리로 열기 — 특히 공유 라이브러리 버전이 다르면 백트레이스가 엉뚱하게 나온다. 크래시 당시와 동일한 빌드/배포 아티팩트를 보관해두는 게 중요하다.
- 최적화 빌드(
-O2등) — 인라이닝/변수 최적화로bt full의 지역 변수가<optimized out>으로 나오는 경우가 흔하다. 재현 가능하면-O0디버그 빌드로 다시 크래시를 낸다.
4. 실행 중인(아직 안 죽은) 프로세스에 붙어서 보기 — gdb -p
크래시가 아니라 “행(hang)“이나 데드락 의심 상황이면 core 없이도 확인할 수 있다.
gdb -p <PID>
(gdb) bt # 또는 (gdb) thread apply all bt관련 문서
- 1. 비정상 종료 시그널 종류
- 2. 시그널별 원인 분석
- 4. 추가로 알아야 할 것들 — dmesg·siginfo_t·ASan·예방 도구 — core dump 자체가 안 남는 컨테이너 환경, dmesg 병행 확인