포스트모템 자동화 — debuginfod·Minidump 파이프라인
대규모 운영 환경에선 core dump 분석을 수동으로 할 수 없습니다. 사고가 하루에 수십. 이 시리즈의 마지막 장은 자동화 — build-id로 debuginfo 자동 다운로드, Breakpad/crashpad minidump 워크플로, Sentry 같은 SaaS, 그리고 CI에서 자동 사후 분석.
#Build-ID — 정체성
ELF 빌드 시 링커가 해시로 만든 32바이트 (SHA-1 기본). 같은 바이트별로 같은 빌드면 같은 ID.
$ readelf -n /usr/bin/myapp | grep "Build ID" Build ID: 8d3a91f0e5a3b2c1d4e6...# 명시 설정$ ld --build-id=sha1 ... # SHA-1 (기본)$ ld --build-id=md5 ...$ ld --build-id=uuid ... # 무작위 UUID$ ld --build-id=0xdeadbeef # 명시 값대부분의 빌드 시스템(CMake, Meson, autotools)이 자동으로 --build-id 켭니다.
core 안에도 프로세스 실행 파일의 build-id가 저장 — 디버거가 맞는 debuginfo를 찾는 핵심.
#별도 debuginfo
배포 빌드는 보통 stripped + 별도 debuginfo.
$ objcopy --only-keep-debug myapp myapp.debug$ strip --strip-debug myapp$ objcopy --add-gnu-debuglink=myapp.debug myappGDB가 myapp를 열 때 myapp.debug를 함께 찾음. 세 가지 검색 경로.
myapp와 같은 디렉터리.- 글로벌 debug 디렉터리:
/usr/lib/debug/<path>. - build-id 디렉터리:
/usr/lib/debug/.build-id/<XX>/<YY...>.debug.
(gdb) show debug-file-directoryThe directory where separate debug symbols are searched for is "/usr/lib/debug".
(gdb) set debug-file-directory /opt/symbols:/usr/lib/debug여러 경로를 콜론으로.
#Build-ID 디렉터리 구조
/usr/lib/debug/.build-id/├── 8d/│ ├── 3a91f0e5a3b2c1d4e6.....debug # myapp│ └── ce8b7f2a4d3e1c9b0f.....debug # libfoo.so├── 4f/│ └── 5a2b...debug└── ...첫 2글자가 디렉터리, 나머지가 파일명. 효율적인 lookup.
$ build_id=$(readelf -n /usr/bin/myapp | awk '/Build ID/ {print $3}')$ ls /usr/lib/debug/.build-id/${build_id:0:2}/${build_id:2}.debug배포판은 <package>-debuginfo 또는 <package>-dbgsym 패키지로 이 구조를 제공.
# Fedora$ sudo dnf install glibc-debuginfo libstdc++-debuginfo
# Ubuntu$ sudo apt install glibc-dbgsym libstdc++6-dbgsym
# 또는 debuginfod로 자동 (아래)#debuginfod — 네트워크 자동 다운로드
build-id로 HTTP로 debuginfo 가져오는 표준 서비스.
$ export DEBUGINFOD_URLS="https://debuginfod.fedoraproject.org/"
# 자동 동작$ gdb /usr/bin/foo /var/crash/core.foo.123Downloading separate debug info for /usr/bin/foo... done[...심볼 자동 로드 + 정상 디버깅...]내부 동작 — HTTP GET https://server/buildid/<id>/debuginfo. 부분 다운로드 (Range)로 매우 큰 debuginfo도 효율적.
#캐시
$ ls ~/.cache/debuginfod_client/$ du -sh ~/.cache/debuginfod_client/기본 1 GB 한도. 자주 쓰는 debuginfo는 캐싱.
$ export DEBUGINFOD_CACHE_PATH=/big/path/cache$ export DEBUGINFOD_MAXSIZE=10G#알려진 서버
| 서버 | URL | 커버 |
|---|---|---|
| Fedora | https://debuginfod.fedoraproject.org/ | Fedora, RHEL, CentOS |
| Ubuntu | https://debuginfod.ubuntu.com/ | Ubuntu |
| Debian | https://debuginfod.debian.net/ | Debian |
| Arch | https://debuginfod.archlinux.org/ | Arch |
| elfutils | https://debuginfod.elfutils.org/ | 모음 |
여러 URL을 동시 (공백 구분).
$ export DEBUGINFOD_URLS="https://debuginfod.fedoraproject.org/ https://debuginfod.elfutils.org/"#사내 debuginfod
자체 CI 빌드를 사내 서버에 인덱싱.
$ debuginfod -F /opt/builds -d /var/cache/debuginfod -p 8002 /opt/builds-F— 인덱싱할 디렉터리.-d— 캐시 DB.-p— 리슨 포트.
운영 머신에서.
$ export DEBUGINFOD_URLS="http://debuginfod.internal.example.com:8002/"모든 사고에 자동 debuginfo 매칭. 대규모 운영의 game changer.
#debuginfod-find 직접
$ debuginfod-find debuginfo /usr/bin/foo/home/me/.cache/debuginfod_client/<build-id>/debuginfo
$ debuginfod-find executable BUILDID$ debuginfod-find source BUILDID /path/to/file.cGDB 외 다른 도구(systemtap, perf, pprof)도 같은 라이브러리(libdebuginfod) 사용.
#자동 사후 분석 — 한 스크립트
#!/usr/bin/env bash# postmortem.sh — core dump 자동 분석
set -e
CORE=$1EXE=$(file "$CORE" | awk -F"'" '{print $2}')
# build-id 추출BUILD_ID=$(readelf -n "$CORE" 2>/dev/null | awk '/Build ID/ {print $3}' | head -1)echo "Executable: $EXE"echo "Build ID: $BUILD_ID"
# debuginfo 자동 다운로드 + GDB 분석export DEBUGINFOD_URLS="http://debuginfod.internal:8002/ https://debuginfod.elfutils.org/"
gdb -batch \ -ex 'set pagination off' \ -ex 'set print pretty on' \ -ex 'set print elements 100' \ -ex 'echo \n=== Death info ===\n' \ -ex 'print $_siginfo' \ -ex 'echo \n=== Backtrace ===\n' \ -ex 'bt full' \ -ex 'echo \n=== All threads ===\n' \ -ex 'thread apply all bt' \ -ex 'echo \n=== Loaded libs ===\n' \ -ex 'info shared' \ -ex 'echo \n=== Registers ===\n' \ -ex 'info registers' \ "$EXE" "$CORE" 2>&1$ ./postmortem.sh /var/crash/core.myapp.1234 > /tmp/report.txtCI에서 PR에 segfault 자동 검출 시 이 스크립트 실행 → 코멘트로 콜스택 첨부.
#minidump — 클라이언트 분포
Chrome·Firefox·Steam 게임·VLC가 수억 사용자에게 배포. 사용자 머신에서 전체 core dump (수 GB)는 비현실적. minidump는 축약된 형태.
#Breakpad / crashpad
Google Breakpad와 후속 crashpad. 크로스 플랫폼 (Win/Mac/Linux).
// 앱 진입에 한 줄#include "client/linux/handler/exception_handler.h"google_breakpad::ExceptionHandler eh(...);// 이후 크래시 시 minidump 자동 생성minidump 파일 (.dmp) 구조:
- Header + 다수 Streams.
- Streams: ThreadList, ModuleList, MemoryList, SystemInfo, ExceptionInfo, …
- 콜스택의 주변 메모리만 (스택 + 일부 힙).
- 모듈 목록 (어떤 .so/.dll이 로드됐는지).
크기: 보통 수 MB. core의 1/1000.
#symbol server
minidump 분석은 symbol 서버가 필요. 빌드 시 dump_syms로 .sym 파일 생성:
$ dump_syms ./myapp > myapp.sym$ head -3 myapp.symMODULE Linux x86_64 8D3A91F0E5A3B2C1D4E6... myappFILE 0 /home/me/main.cppFUNC 1234 50 0 main이 .sym을 symbol 서버에 모듈 ID별로 저장.
#Stack walking
$ minidump_stackwalk crash.dmp ./symbols/Module 0: /home/me/myapp + 0x1234 [myapp + 0x1234] main + 0x10 [main.cpp:42] ...
Thread 0 (crashed): 0x... [myapp + 0x1234]: process_request ...stackwalker가 minidump + symbol로 콜스택 재구성. 일반 GDB 대신 전용 도구.
#Sentry / Crashlytics
상용 SaaS — minidump + symbol 서버 + dashboard.
기능:
- 동일 콜스택 그룹화.
- 사용자 영향 통계.
- regression 검출 (새 버전에서 증가).
- 정확한 빌드와 디버그 정보 매칭.
- Slack/email 알림.
비용 — 트래픽 기준. 큰 게임은 월 수천 달러.
#Sentry 자체 호스팅
상용이지만 self-hosted 무료 옵션. Docker compose로 배포.
$ git clone https://github.com/getsentry/self-hosted$ cd self-hosted && ./install.sh운영 환경 자체 사용에 좋음.
#자체 Sentry 비슷한 도구 — Backtrace, Bugsnag
다양한 상용. minidump 외에도 언어 native (Python tracebacks, JavaScript stacks).
#ASan / TSan과 core
Sanitizer는 검출 시 진단 + abort(). SIGABRT가 core 생성.
$ ASAN_OPTIONS="abort_on_error=1:disable_coredump=0" ./progabort_on_error=1—_exit대신abort().disable_coredump=0— ASan이RLIMIT_CORE=0안 함.
core 안에 ASan shadow 메모리도 포함하려면.
$ ASAN_OPTIONS="abort_on_error=1:disable_coredump=0:coredump_dump_full_shadow=1" ./progshadow가 원본 1/8이라 큰 프로세스면 core가 매우 큼.
ASan 진단은 보통 abort 직전 stderr에 출력. core에선 추가 메모리 정보만.
#gcore — 살아 있는 프로세스
운영 서비스가 느려졌지만 안 죽었을 때. gcore로 snapshot.
$ sudo gcore -o /tmp/core <pid>[프로세스 일시 정지, core dump, 재개]$ ls /tmp/core.<pid>이 core는 진짜 사망 core와 같은 포맷. 일반 GDB로 분석.
gcore가 내부적으로 GDB attach + memory dump + detach. 큰 프로세스면 수초 정지.
대안: BPF로 동적 stack trace, 또는 eu-stack.
$ eu-stack -p <pid>[모든 스레드 콜스택, 매우 가벼움]#자동화 — CI / Production
#CI
- name: Run tests run: | ulimit -c unlimited ./test_runner || true # 항상 통과 (다음 step에서 분석)
- name: Analyze cores if: failure() run: | for core in core.*; do echo "=== $core ===" gdb -batch -ex 'bt' -ex 'thread apply all bt' \ ./test_runner "$core" done테스트가 죽으면 자동으로 콜스택 분석 → PR 코멘트.
#Production
[Unit]Description=Postmortem analyzer
[Service]Type=oneshotExecStart=/usr/local/bin/analyze-cores.sh
# /etc/systemd/system/postmortem.path[Path]PathChanged=/var/lib/systemd/coredumpUnit=postmortem.service
[Install]WantedBy=multi-user.target새 core 떨어질 때마다 자동 분석 + 결과 Slack/이메일 전송.
#자체 알람
import gdb, subprocess, json, requests
def analyze_core(core_path, exe_path): gdb.execute(f"file {exe_path}", to_string=True) gdb.execute(f"core-file {core_path}", to_string=True)
# 콜스택 bt = gdb.execute("bt", to_string=True)
# 시그널 siginfo = gdb.execute("print $_siginfo", to_string=True)
# 콜스택 해시로 그룹화 sig = "|".join(frame.split()[1:3] for frame in bt.split("\n") if frame.strip())
# Slack 전송 requests.post("https://hooks.slack.com/...", json={ "text": f"Core dump:\n```\n{bt}\n```\nSignal:\n{siginfo}", "thread_ts": signature_to_ts.get(sig) # 같은 콜스택은 같은 thread })
analyze_core(...)#자체 분석 — pyelftools
GDB 없이도 Python으로 core 분석.
from elftools.elf.elffile import ELFFile
with open('core', 'rb') as f: elf = ELFFile(f) for seg in elf.iter_segments(): if seg.header.p_type == 'PT_NOTE': for note in seg.iter_notes(): if note.n_type == 'NT_PRSTATUS': # 레지스터 추출 pr = note.n_desc pid = struct.unpack_from('i', pr, ...)[0] ... elif note.n_type == 'NT_FILE': # 매핑된 파일 목록 ... elif seg.header.p_type == 'PT_LOAD': # 메모리 영역 data = seg.data() ...대규모 분석 (수천 core)에서 GDB 띄우기보다 빠름.
#시리즈 정리
4장으로 core dump의 전체 생명주기를 다뤘습니다.
- Ch 1 Core 생성 메커니즘 — ulimit, core_pattern, systemd-coredump.
- Ch 2 ELF core 포맷 — PT_NOTE, NT_PRSTATUS, NT_FILE.
- Ch 3 GDB로 core 분석 — 8가지 패턴, siginfo, 변수 검사.
- Ch 4 (이 장) 자동화 — debuginfod, minidump, Sentry.
사고 분석의 표준 운영:
LimitCORE=infinity+core_pattern.- CI에서 stripped 빌드 + 별도 debuginfo.
- 사내 debuginfod 서버에 인덱싱.
- 사고 시
coredumpctl debug또는 자동 스크립트. - 콜스택 해시로 동일 사고 그룹화.
- 대규모 클라이언트는 minidump + Sentry.
#관련 항목 (시리즈 전체)
#외부 자료
Postmortem Debugging · 4 of 6
관련 글
CXL Fabric Postmortem — 분산 디바이스·Multi-Host Pool 장애 추적
CXL 2.0/3.x fabric에서 multi-host pooled 디바이스 fail 분석 — Fabric Manager log·LD 상태·cross-host correlation.
CXL 디바이스 Core Dump 분석 — Device State·Mailbox Log·NUMA 토폴로지
CXL 디바이스가 fail한 후 core dump에서 device state·mailbox 명령 이력·NUMA 토폴로지를 복원하는 분석 흐름.
GDB로 Core 분석 — backtrace·info threads·py 활용
core 열기, siginfo 해독, 콜스택 분석, 변수 검사, 자주 만나는 패턴.