crash와 drgn 분석 — vmcore에서 커널 상태 복원하기
커널 panic 후 시스템이 죽었습니다. 재현은 안 됩니다. kdump가 재부팅 직전 RAM을 vmcore 파일로 저장해 줬다면 — crash 또는 drgn으로 부검합니다. 이건 user-space의 core dump 분석(gdb exe core)에 해당하는 커널 버전.
#kdump 셋업
vmcore를 만드는 건 kdump. 커널 패닉 직전에 예약된 메모리에서 2차 커널을 부팅해 RAM을 디스크로 저장.
#활성화
# Fedora/RHEL$ sudo dnf install kexec-tools$ sudo systemctl enable --now kdump
# Ubuntu/Debian$ sudo apt install kdump-tools linux-crashdump$ sudo systemctl enable --now kdump-tools
# 부팅 옵션 — 예약 메모리# /etc/default/grubGRUB_CMDLINE_LINUX="... crashkernel=512M"$ sudo update-grub$ sudo rebootcrashkernel=512M이 재부팅 시 2차 커널용 메모리 예약. 너무 작으면 vmcore 못 만듦.
#상태 확인
$ sudo kdumpctl statuskdump: Kdump is operational
$ cat /proc/iomem | grep Crash 04000000-23ffffff : Crash kernel # 예약된 영역#강제 패닉으로 테스트
$ echo c | sudo tee /proc/sysrq-trigger[Sysrq: Trigger a crash][BUG: kernel NULL pointer dereference][panic +14s][kdump: kexec'ing into crash kernel][2차 커널 부팅, vmcore 저장][reboot]
# 재부팅 후$ ls /var/crash/127.0.0.1-2026-05-15-12:34:56/$ ls /var/crash/127.0.0.1-*/vmcore vmcore-dmesg.txt kexec-dmesg.logvmcore가 본체 (수 GB), vmcore-dmesg.txt는 panic 직전 dmesg.
#crash — 전통 도구
$ sudo dnf install crash kernel-debuginfo-$(uname -r)
$ sudo crash /usr/lib/debug/.../vmlinux /var/crash/.../vmcore
KERNEL: /usr/lib/debug/.../vmlinux DUMPFILE: /var/crash/.../vmcore [PARTIAL DUMP] CPUS: 4 DATE: Sun May 11 03:21:14 KST 2026 UPTIME: 23:45:12LOAD AVERAGE: 0.42, 0.30, 0.18 TASKS: 234 NODENAME: prod-01 RELEASE: 6.5.0-... VERSION: ... MACHINE: x86_64 MEMORY: 16 GB PANIC: "BUG: kernel NULL pointer dereference, address: 0000..." PID: 1234 COMMAND: "myprog" TASK: ffff... [...] CPU: 2 STATE: TASK_RUNNING (PANIC)
crash>자동으로 panic 원인·시간·메모리·CPU·죽은 task 표시.
#기본 명령
crash> bt # 현재 task의 콜스택crash> bt -a # 모든 CPUcrash> ps # 프로세스 목록crash> ps -k # 커널 스레드crash> log # dmesgcrash> log | tail # 마지막 로그crash> sys # 시스템 정보crash> mach # CPU 정보crash> mount # 마운트crash> net # 네트워크 디바이스crash> files # 열린 파일crash> vm <pid> # 그 task의 VM 정보crash> task <pid> # task_structcrash> kmem -s # slab 통계crash> kmem -i # 메모리 요약crash> p <var> # 전역 변수crash> rd <addr> # 메모리 읽기crash> dis <func> # 디스어셈블crash> struct task_struct <addr> # 구조체 출력crash> list <addr> # linked list 순회crash> tree <addr> # tree 순회 (rbtree)#한 예 — panic 원인 추적
crash> btPID: 1234 TASK: ffff... CPU: 2 COMMAND: "myprog" #0 [ffff...] machine_kexec at ffffffff8104a123 #1 [ffff...] __crash_kexec at ffffffff8108b456 #2 [ffff...] panic at ffffffff8108c789 #3 [ffff...] oops_end at ffffffff8102d012 #4 [ffff...] no_context at ffffffff8106f345 #5 [ffff...] __do_page_fault at ffffffff8106f678 #6 [ffff...] do_page_fault at ffffffff8106f9ab #7 [ffff...] page_fault at ffffffff819c5678 [exception RIP: my_driver_handler+0x42] RIP: ffffffffc0123456 RSP: ffff... RAX: 0000000000000000 ... #8 [ffff...] __handle_irq_event_percpu at ffffffff810abc01 ...
crash> dis my_driver_handler0xffffffffc0123410 <my_driver_handler>: push %rbp...0xffffffffc0123456 <my_driver_handler+0x42>: mov 0x10(%rax),%rcx ^^^ %rax = 0 → NULL deref
crash> sym ffffffffc0123456my_driver_handler+0x42 at drivers/my_module.c:42NULL 역참조 위치 + 소스 줄. my_module.c:42의 *(p + 0x10)에서 p == NULL.
#list 순회 — 자료구조
crash> p init_taskinit_task = $1 = { state = 0, ... tasks = { next = 0xffff..., prev = 0xffff... }, ...}
crash> list -H init_task.tasks task_struct.tasks -s task_struct.comm | headffff... comm = "init"ffff... comm = "kthreadd"...linked list 순회 + struct member 추출.
#drgn — Python 기반 모더 도구
drgn — Meta가 만든 Python interactive.
$ sudo dnf install drgn# 또는$ pip install drgn#진입
$ sudo drgn -k -c /var/crash/.../vmcore # vmcore$ sudo drgn # 라이브 커널 (/proc/kcore)
>>>Python REPL. 모든 커널 변수·구조체에 직접 접근.
>>> from drgn.helpers.linux import *
# 현재 init_task>>> init = prog['init_task']>>> init.comm(char [16])"swapper/0"
# 모든 task 순회>>> for task in for_each_task(prog):... print(task.pid.value_(), task.comm.string_().decode())0 swapper/01 init2 kthreadd3 rcu_gp...#Helper 함수
drgn에 수많은 helper. drgn.helpers.linux.*:
from drgn.helpers.linux import ( for_each_task, for_each_online_cpu, list_for_each_entry, find_task, pid_for_each_thread, find_inode_by_path, block_device_name, ...)
# 특정 PIDtask = find_task(prog, 1234)print(task.comm.string_())
# 그 task의 fdfrom drgn.helpers.linux.fs import fgetfile = fget(task, 3) # fd 3print(file.f_path.dentry.d_name.name.string_())#콜스택
>>> task = find_task(prog, 1234)>>> for frame in task.stack_trace():... print(frame)#0 page_fault+0x... at arch/x86/kernel/...#1 do_page_fault+0x... at arch/x86/mm/...#2 my_function+0x42 at drivers/foo.c:42...#vs crash
| crash | drgn | |
|---|---|---|
| 언어 | 자체 DSL | Python |
| 표현력 | 제한적 | 무제한 |
| 학습 곡선 | 중 | 낮음 (Python 알면) |
| 자료구조 | bt/list/tree 등 | for, dict, list comprehension |
| 자체 도구 | bash + crash 스크립트 | Python 함수 |
| 속도 | 빠름 | 비슷 |
| 커뮤니티 | 옛, 안정 | 활발 (Meta·Red Hat) |
drgn이 작성하기 쉽고 Python 생태계와 자연스럽게 통합. crash는 전통 사용자가 익숙.
#자체 분석 스크립트
#!/usr/bin/env drgn# crash-info.py — vmcore 진단 자동화
from drgn.helpers.linux import for_each_task
print(f"Kernel: {prog['linux_banner'].string_().decode().strip()}")print(f"Uptime: ...")print()
# CPU별 콜스택print("=== Per-CPU active task ===")for cpu in for_each_online_cpu(prog): task = per_cpu(prog['current_task'], cpu) print(f"CPU {cpu}: {task.comm.string_().decode()} pid={task.pid.value_()}")
# blocked task (D state)print("\n=== Tasks in D state (uninterruptible) ===")for task in for_each_task(prog): if task.__state.value_() == 0x2: # TASK_UNINTERRUPTIBLE print(f" {task.comm.string_().decode()} pid={task.pid.value_()}")$ sudo drgn -k -c vmcore -s crash-info.py운영 환경에서 모든 panic에 같은 분석을 자동 실행.
#라이브 디버깅 — drgn on /proc/kcore
$ sudo drgn
# 라이브 커널의 task list (운영 서비스 분석에 유용)>>> for t in for_each_task(prog):... if t.__state.value_() == 0x2:... print(t.comm.string_(), t.pid.value_())vmcore 없이 동작 중 시스템 분석. 커널 패닉 안 일으키므로 안전.
#자주 만나는 사고 유형
#NULL 역참조
PANIC: "BUG: kernel NULL pointer dereference, address: 0000000000000010"→ bt로 콜스택, dis로 명령, RAX/RDI 등으로 어떤 포인터가 NULL인지.
#Soft lockup
PANIC: "Kernel panic - not syncing: softlockup: hung tasks"→ bt -a로 모든 CPU. 한 CPU가 한 함수에서 영원히 무한 루프.
#Hung task
PANIC: "Kernel panic - not syncing: hung_task: blocked tasks"→ D state task 추적 (drgn 스크립트 위 참고).
#Use-after-free
PANIC: "BUG: KASAN: use-after-free in ..."→ KASAN 빌드여야. shadow memory에 alloc/free 사이트.
#Out of memory
PANIC: "Out of memory: Killed process N (myprog) ..."→ kmem -i로 메모리 요약. vm <pid>로 oom-killed task의 메모리.
#kdump-anon — clouddump
운영 환경에서 vmcore를 디스크 대신 네트워크로.
nfs <nfs-server>:/path/to/dumps# 또는ssh user@<remote-server>ssh_key /root/.ssh/kdump_rsapanic 시 2차 커널이 NFS 마운트 → vmcore 업로드. 자체 디스크가 없는 클라우드 VM에서.
#kpoke — debugfs 디버깅 헬퍼
debugfs 안에 커널 구조체를 보기 좋게 출력하는 인터페이스. drivers/는 이걸 활용해 자체 상태를 노출.
$ ls /sys/kernel/debug/$ cat /sys/kernel/debug/tracing/trace$ cat /sys/kernel/debug/btrfs/<uuid>/...$ cat /sys/kernel/debug/kprobes/list각 서브시스템이 자체적으로 출력. 자체 driver 작성 시 debugfs로 디버그 인터페이스 제공.
#자주 만나는 함정
| 증상 | 원인 |
|---|---|
crash: cannot read vmlinux | debuginfo 패키지 안 깔림 |
| vmcore 크기 0 | crashkernel= 옵션 안 켰음 |
| kdump 서비스 실패 | crashkernel 메모리 너무 작음 또는 부팅 옵션 누락 |
| crash가 wrong kernel 거부 | vmlinux build-id ≠ vmcore의 |
drgn: cannot determine kernel version | -k로 커널 모드 명시 |
| 모듈 심볼 없음 | 해당 모듈의 debuginfo 별도 |
| vmcore 매우 큼 (수십 GB) | makedumpfile -d 31로 user pages 제외 |
#정리
- kdump가 panic 직전 RAM을 vmcore로.
- crash (전통) 와 drgn (Python) 두 도구.
- crash는 자체 DSL, drgn은 Python — 표현력 ↑.
- helper 함수로 모든 task / cpu / fd / inode 순회.
- live 분석은
/proc/kcore+ drgn. - 사고 유형: NULL deref / softlockup / hung / use-after-free / OOM.
- 클라우드 환경은 NFS·SSH로 vmcore 업로드.
#다음 장 예고
Ch 7 (마지막) — Kernel panic / Oops 메시지 해석. crash 없이 dmesg만으로 분석.
#관련 항목
Kernel Debugging · 6 of 9
- 1리눅스 커널 디버깅 개론 — User/Kernel 경계와 도구 선택
- 2printk·dmesg·dynamic_debug 분석 — 커널 로그 추적
- 3ftrace와 tracepoints 활용 — 커널 함수 호출 트레이싱
- 4eBPF·bpftrace로 커널 디버깅 — 동적 관측의 신세대
- 5kdb·kgdb 인터랙티브 커널 디버깅 — Source-level Step·Breakpoint
- 6crash와 drgn 분석 — vmcore에서 커널 상태 복원하기
- 7Kernel Panic·Oops 메시지 해석 — Decoder Ring 만들기
- 8CXL 커널 드라이버 디버깅 — ftrace·bpftrace·drgn 활용
- 9drivers/cxl 코드 분석 — 진입점부터 sysfs까지
관련 글
CXL 커널 드라이버 디버깅 — ftrace·bpftrace·drgn 활용
Linux drivers/cxl/ 서브시스템 디버깅 — ftrace로 probe 흐름 추적, bpftrace로 mailbox 명령 캡처, drgn으로 커널 상태 검사.
Kernel Panic·Oops 메시지 해석 — Decoder Ring 만들기
dmesg 한 줄로 정확한 위치 찾기. RIP, Call Trace, BUG, Tainted 디코딩.
kdb·kgdb 인터랙티브 커널 디버깅 — Source-level Step·Breakpoint
별 머신 또는 시리얼로 커널을 step-debug. kgdb 셋업, gdb 연결, 실전 흐름.
이 글을 참조하는 글 (6)
- CXL Fabric Postmortem — 분산 디바이스·Multi-Host Pool 장애 추적— Postmortem Debugging
- CXL 디바이스 Core Dump 분석 — Device State·Mailbox Log·NUMA 토폴로지— Postmortem Debugging
- CXL 커널 드라이버 디버깅 — ftrace·bpftrace·drgn 활용— Kernel Debugging
- 리눅스 메모리 회계 — RSS·VSS·PSS·smaps 해석— Memory Diagnostics
- Kernel Panic·Oops 메시지 해석 — Decoder Ring 만들기— Kernel Debugging
- kdb·kgdb 인터랙티브 커널 디버깅 — Source-level Step·Breakpoint— Kernel Debugging