커널 개발 도구
Linux 커널 개발 생산성을 좌우하는 도구 체인을 한 번에 연결해 설명합니다. 컴파일러/링커(Linker) 설정, sparse·smatch·Coccinelle 기반 결함 탐지, checkpatch와 코딩 스타일(Coding Style) 검증, pahole/BTF를 통한 타입 정보 확인, QEMU·virtme·kselftest·KUnit 기반 재현 가능한 테스트, Git 패치(Patch) 리뷰/전송 흐름까지 실제 서브시스템 개발 루틴에 맞춰 상세히 다룹니다.
핵심 요약
- 재현 우선 — 증상보다 재현 조건 고정이 먼저입니다.
- 도구 선택 — 로그, 트레이스, 코어덤프 용도를 분리합니다.
- 증거 보존 — 원인 추적 전 관측 데이터를 먼저 확보합니다.
- 오버헤드(Overhead) 관리 — 추적 범위를 최소화해 왜곡을 줄입니다.
- 사후 검증 — 수정 후 동일 조건에서 재발 여부를 확인합니다.
단계별 이해
- 재현 시나리오 정의
입력 조건과 타이밍을 고정합니다. - 관측 포인트 배치
핵심 함수/이벤트만 선별 추적합니다. - 원인 축소
가설을 하나씩 배제하며 범위를 줄입니다. - 수정 검증
회귀 테스트와 운영 지표를 함께 확인합니다.
개발 도구 선택 매트릭스
커널 개발 단계와 목적에 따라 필요한 도구가 다릅니다. 아래 매트릭스는 각 도구의 용도와 우선순위(Priority)를 정리합니다.
| 도구 | 주요 용도 | 필수 여부 | 사용 시점 | 대상 사용자 |
|---|---|---|---|---|
| GCC | 커널 컴파일 | ★★★ 필수 | 빌드 | 모든 개발자 |
| checkpatch.pl | 코딩 스타일 검사 | ★★★ 필수 | 커밋 전 | 패치 제출자 |
| sparse | 정적 분석 (NULL 체크, 락 검증) | ★★☆ 권장 | 빌드 시 | 모든 개발자 |
| coccinelle | 패턴 기반 코드 변환 | ★★☆ 권장 | 대규모 리팩토링 | 서브시스템 메인테이너 |
| git format-patch | 패치 생성 | ★★★ 필수 | 패치 제출 | 패치 제출자 |
| b4 | 패치 시리즈 다운로드/적용 | ★★☆ 권장 | 패치 리뷰 | 메인테이너 |
| QEMU | 가상머신 테스트 | ★★☆ 권장 | 테스트 | 모든 개발자 |
| Clang | 대체 컴파일러 | ★☆☆ 선택 | 빌드 검증 | 서브시스템 메인테이너 |
| pahole | 구조체(Struct) 레이아웃 분석 | ★☆☆ 선택 | 최적화 | 성능 튜닝 전문가 |
| KUnit/kselftest | 단위 테스트 | ★★☆ 권장 | 개발 중 | 새 기능 개발자 |
도구 우선순위 가이드:
- 첫 패치 제출자: GCC + checkpatch.pl + git format-patch (최소 필수)
- 정기 기여자: + sparse + QEMU + KUnit (품질 향상)
- 메인테이너: + coccinelle + b4 + Clang (대규모 관리)
- 성능 전문가: + pahole + perf + ftrace (상세 분석)
개발 환경 구축
커널 개발에 필요한 최소 패키지:
# Debian/Ubuntu
sudo apt install build-essential bc bison flex libelf-dev \
libssl-dev libncurses-dev dwarves python3 git
# Fedora/RHEL
sudo dnf install gcc make bc bison flex elfutils-libelf-devel \
openssl-devel ncurses-devel dwarves python3 git
# 커널 소스 가져오기
git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux
git checkout $(git tag -l 'v*' | sort -V | tail -n1) # 최신 릴리스 태그 체크아웃
GCC (GNU Compiler Collection)
커널은 릴리스마다 최소 GCC 버전 요구사항이 다릅니다. 빌드 전 scripts/min-tool-version.sh를 확인하고, 실무적으로는 GCC 8+를 권장합니다.
# 커널 빌드에서 사용되는 주요 GCC 옵션
-Wall -Wundef -Werror=strict-prototypes -Wno-trigraphs
-fno-strict-aliasing -fno-common
-fno-delete-null-pointer-checks
-O2 # 최적화 레벨
-fstack-protector-strong # 스택 보호
-mgeneral-regs-only # ARM64: FP/SIMD 레지스터 사용 금지
-mindirect-branch=thunk-extern # Spectre 완화
# GCC 플러그인 (CONFIG_GCC_PLUGINS=y)
-fplugin=randomize_layout # 구조체 랜덤화 (RANDSTRUCT)
-fplugin=stackleak_plugin # 스택 리크 방지
-fplugin=latent_entropy # 잠재적 엔트로피 수집
Clang/LLVM
ClangBuiltLinux 프로젝트 덕분에 Clang으로도 커널을 완전히 빌드할 수 있습니다:
# Clang으로 커널 빌드
make CC=clang LLVM=1 defconfig
make CC=clang LLVM=1 -j$(nproc)
# Clang 전용 기능
CONFIG_CC_IS_CLANG=y
CONFIG_CFI_CLANG=y # Control-Flow Integrity
CONFIG_LTO_CLANG_THIN=y # Link-Time Optimization (Thin LTO)
CONFIG_SHADOW_CALL_STACK=y # 섀도 콜 스택 (ARM64)
| 특성 | GCC | Clang |
|---|---|---|
| 빌드 속도 | 보통 | 약간 빠름 |
| 진단 메시지 | 보통 | 우수 (색상, 제안) |
| LTO | 제한적 | Thin LTO 지원 |
| CFI | 미지원 | 지원 |
| 플러그인 | GCC 플러그인 다수 | LLVM pass |
| 아키텍처 | 모든 아키텍처 | x86, ARM, ARM64 위주 |
코드 분석 도구
sparse
Linus Torvalds가 작성한 정적 분석 도구. 주소 공간(Address Space) 혼합(__user, __kernel), endian 오류, lock 문제를 검출합니다:
# sparse로 커널 빌드 검사
make C=1 # 변경된 파일만 검사
make C=2 # 모든 파일 검사
# 특정 파일만 검사
make C=1 drivers/net/ethernet/intel/e1000e/
/* sparse 어노테이션 */
void my_ioctl(void __user *ubuf, void __iomem *mmio)
{
/* sparse 경고: __user 포인터 역참조는 copy_from_user 사용 필요 */
/* sparse 경고: __iomem 포인터는 readl/writel 사용 필요 */
}
Coccinelle
시맨틱 패치(Semantic Patch) 도구. 코드 변환 패턴을 SmPL 언어로 정의합니다:
# Coccinelle 시맨틱 패치 실행
make coccicheck MODE=report # 보고만
make coccicheck MODE=patch # 패치 적용
# 특정 스크립트만 실행
make coccicheck COCCI=scripts/coccinelle/api/kfree.cocci
checkpatch.pl
커널 코딩 스타일 검사 도구. 패치 제출 전 반드시 실행해야 합니다:
# 패치 파일 검사
scripts/checkpatch.pl 0001-my-patch.patch
# 파일 직접 검사
scripts/checkpatch.pl --file drivers/mydriver/myfile.c
# 엄격 모드
scripts/checkpatch.pl --strict 0001-my-patch.patch
# 주요 경고 유형
# WARNING: line length exceeds 100 columns
# WARNING: Missing a blank line after declarations
# ERROR: trailing whitespace
# ERROR: code indent should use tabs where possible
# CHECK: Alignment should match open parenthesis
checkpatch.pl의 경고/오류 유형별 대응법과 코딩 스타일 검증 워크플로는 커널 코딩 스타일 문서에서 상세히 다룹니다.
커널 코딩 스타일 (Kernel Coding Style)
리눅스 커널은 Documentation/process/coding-style.rst에 정의된 고유한 코딩 스타일을 따릅니다. 이 스타일은 Linus Torvalds가 제정하였으며, 모든 패치 제출 시 반드시 준수해야 합니다. 핵심 규칙을 아래에 요약하며, 각 규칙의 상세 설명과 실전 예제는 커널 코딩 스타일 전용 문서를 참고하세요.
코딩 스타일 빠른 참조
| 항목 | 규칙 | 예시 |
|---|---|---|
| 들여쓰기 | 탭 8칸 (스페이스 금지) | if (x) {⟨TAB⟩statement; |
| 줄 길이 | 80열 권장, 100열 최대 | 긴 줄은 여는 괄호 뒤에서 나눔 |
| 중괄호 | K&R 스타일 (함수만 다음 줄) | if (x) { vs int f()\n{ |
| 함수명 | 소문자_언더스코어 | my_function() |
| 변수명 | 짧고 명확 (단일 문자도 OK) | i, tmp, ret (지역 변수) |
| 매크로(Macro) | 대문자_언더스코어 | #define MAX_SIZE 100 |
| 주석 | /* C89 스타일 */ |
// C99 한 줄 주석은 일부 허용 |
| goto | 에러 처리에 적극 사용 | goto err_free; (정리 레이블) |
| 함수 인자 | 출력 매개변수는 포인터로 | int get_value(int *out) |
| 반환 값 | 성공 0, 실패 -errno | return -EINVAL; |
들여쓰기, 중괄호, 네이밍, typedef, 함수 규칙, goto 패턴, 매크로, 반환값, 공백, kernel-doc 주석, 메모리 할당, printk 로깅, 조건부 컴파일, 에디터 설정 등 각 규칙의 상세 설명과 코드 예제는 커널 코딩 스타일 전용 문서를 참고하세요.
pahole과 BTF
pahole은 구조체의 메모리 레이아웃을 분석합니다. hole(패딩(Padding))을 찾아 구조체를 최적화할 수 있습니다:
# 구조체 레이아웃 분석
pahole -C task_struct vmlinux | head -50
# struct task_struct {
# struct thread_info thread_info; /* 0 24 */
# unsigned int __state; /* 24 4 */
# /* ... */
# /* size: 9792, cachelines: 153, members: 259 */
# /* sum members: 9600, holes: 14, sum holes: 192 */
# BTF 생성 (BPF Type Format)
CONFIG_DEBUG_INFO_BTF=y
# pahole --btf_encode_detached btf_vmlinux vmlinux
Git 워크플로
# 커널 패치 생성
git format-patch -1 HEAD # 마지막 커밋을 패치로
git format-patch -3 --cover-letter # 3개 커밋 + 커버 레터
# 패치 전송
git send-email --to=subsystem@vger.kernel.org \
--cc=maintainer@kernel.org \
0001-my-patch.patch
# 메인테이너 찾기
scripts/get_maintainer.pl 0001-my-patch.patch
# git bisect로 버그 커밋 찾기
git bisect start
git bisect bad # 현재 커밋은 버그 있음
git bisect good v6.5 # v6.5는 정상
# ... 커널 빌드 & 테스트 반복 ...
git bisect good # 또는 git bisect bad
git bisect reset # 완료 후 리셋
# b4 도구 (메일링 리스트 패치 관리)
b4 am 20231115120000.12345-1-developer@kernel.org # 패치 시리즈 적용
b4 shazam # 현재 lore URL의 패치 적용
패치 제출 체크리스트
커널 패치를 메인라인에 제출하기 전 반드시 확인해야 할 필수 항목입니다. 이 체크리스트를 따르지 않으면 메인테이너에게 거부되거나 무시됩니다.
| 단계 | 체크 항목 | 명령어/도구 | 통과 기준 |
|---|---|---|---|
| 1. 코드 품질 | ☐ checkpatch.pl 실행 | scripts/checkpatch.pl --strict *.patch |
ERROR 0개, WARNING 최소화 |
| ☐ sparse 검사 | make C=2 |
경고 없음 (수정 분야만) | |
| ☐ 컴파일 성공 | make allmodconfig && make -j$(nproc) |
빌드 에러 0개 | |
| 2. 테스트 | ☐ 기능 테스트 | QEMU 또는 실제 하드웨어 | 변경 사항 정상 동작 |
| ☐ 회귀 테스트 | KUnit, kselftest | 기존 테스트 모두 통과 | |
| ☐ GCC/Clang 모두 빌드 | make CC=clang LLVM=1 |
양쪽 컴파일러 성공 | |
| 3. 커밋 메시지 | ☐ 서브시스템 접두사 | git log --oneline 참조 | subsys: Description 형식 |
| ☐ 본문 작성 (why) | 72열 줄바꿈 | 변경 이유 명확 설명 | |
| ☐ Signed-off-by | git commit -s |
본인 실명 + 이메일 | |
| ☐ Fixes/Cc 태그 (버그 수정 시) | Fixes: 12-char-SHA |
stable 백포트 대상 명시 | |
| 4. 대상 확인 | ☐ 메인테이너 확인 | scripts/get_maintainer.pl *.patch |
To/Cc 리스트 확보 |
| ☐ 메일링리스트 구독 | linux-kernel@vger.kernel.org | 서브시스템 리스트 포함 | |
| ☐ lore 검색 (중복 확인) | lore.kernel.org 검색 | 동일 패치 없음 확인 | |
| 5. 포맷 검증 | ☐ 패치 시리즈 번호 | git format-patch -3 -v2 |
[PATCH v2 1/3] 형식 |
| ☐ 커버 레터 (3개+ 패치) | --cover-letter |
시리즈 전체 설명 | |
| ☐ In-Reply-To 설정 (v2+) | --in-reply-to=<msg-id> |
이전 버전 쓰레드 연결 | |
| 6. 제출 | ☐ git send-email 설정 | ~/.gitconfig sendmail 설정 |
SMTP 정상 동작 |
| ☐ 자기 앞 테스트 발송 | 본인 이메일로 먼저 발송 | 포맷 확인 후 본 발송 |
자주 거부되는 이유:
- checkpatch.pl ERROR 미수정
- Signed-off-by 누락 (DCO 위반)
- 커밋 메시지에 "why" 설명 없음
- 잘못된 메인테이너에게 발송
- HTML 메일 발송 (plain text 필수)
- 첨부 파일로 패치 발송 (인라인 필수)
- 여러 무관한 변경을 한 패치로 뭉침
첫 패치 제출 팁:
- 작게 시작: 오타 수정, checkpatch 정리 등 간단한 패치로 프로세스(Process) 익히기
- Documentation/ 먼저: 문서 개선은 리뷰 부담이 적고 승인율 높음
- staging/ 드라이버: drivers/staging은 품질 기준이 낮아 입문용으로 적합
- 리뷰 반영: 메인테이너 피드백은 24시간 내 응답, 수정 후 v2 발송
- patience: 답변까지 1~2주 소요 가능, 2주 후 polite ping 허용
QEMU 테스트 환경
# 최소 커널 + initramfs로 QEMU 부팅
make x86_64_defconfig
make -j$(nproc)
# 최소 initramfs 생성
mkdir -p rootfs/bin
cp /path/to/busybox rootfs/bin/busybox
cd rootfs/bin && ln -s busybox sh && cd ../..
cat > rootfs/init << 'EOF'
#!/bin/sh
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t debugfs debugfs /sys/kernel/debug
echo "Boot OK"
exec /bin/sh
EOF
chmod +x rootfs/init
cd rootfs && find . | cpio -o -H newc | gzip > ../initramfs.gz && cd ..
# QEMU 실행
qemu-system-x86_64 \
-kernel arch/x86/boot/bzImage \
-initrd initramfs.gz \
-append "console=ttyS0 nokaslr" \
-nographic -m 1G -smp 4 \
-enable-kvm
# 9p 파일시스템 공유 (호스트 디렉토리를 게스트에 마운트)
qemu-system-x86_64 ... \
-fsdev local,id=shared,path=/path/to/share,security_model=none \
-device virtio-9p-pci,fsdev=shared,mount_tag=hostshare
# 게스트에서: mount -t 9p hostshare /mnt
크로스 컴파일(Cross Compilation)
# ARM64 크로스 컴파일
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
make defconfig
make -j$(nproc)
# RISC-V 크로스 컴파일
export ARCH=riscv
export CROSS_COMPILE=riscv64-linux-gnu-
make defconfig
make -j$(nproc)
# 크로스 컴파일 툴체인 설치
# Debian/Ubuntu:
sudo apt install gcc-aarch64-linux-gnu gcc-riscv64-linux-gnu
# Fedora:
sudo dnf install gcc-aarch64-linux-gnu gcc-riscv64-linux-gnu
IDE/에디터 설정
# compile_commands.json 생성 (clangd/ccls용)
scripts/clang-tools/gen_compile_commands.py
# 또는 bear 사용
bear -- make -j$(nproc)
# cscope/ctags 생성
make cscope tags
# VS Code 설정: .vscode/c_cpp_properties.json
# "compileCommands": "${workspaceFolder}/compile_commands.json"
# Vim + cscope
# :cscope add cscope.out
# :cs find g function_name (정의 찾기)
# :cs find c function_name (호출처 찾기)
# :cs find s symbol_name (심볼 참조 찾기)
KUnit과 kselftest
# KUnit: 커널 단위 테스트 프레임워크
./tools/testing/kunit/kunit.py run --arch=x86_64
# 특정 테스트만 실행
./tools/testing/kunit/kunit.py run --kunitconfig=lib/kunit/.kunitconfig
# kselftest: 커널 셀프 테스트
make -C tools/testing/selftests run_tests
make -C tools/testing/selftests TARGETS=net run_tests # 네트워크 테스트만
커널 문서화
# kernel-doc 형식의 함수 주석
# HTML 문서 빌드
make htmldocs
# 결과: Documentation/output/
# 특정 서브시스템 문서만
make SPHINXDIRS=driver-api htmldocs
/**
* kmalloc - allocate kernel memory
* @size: how many bytes of memory are required
* @flags: GFP allocation flags
*
* kmalloc is the normal method of allocating memory
* for objects smaller than page size in the kernel.
*
* Return: pointer to allocated memory, or NULL on failure
*/
void *kmalloc(size_t size, gfp_t flags);
개발 워크플로 다이어그램
참고 자료: 커널 패치 제출 가이드, ClangBuiltLinux, Documentation/dev-tools/
커널 개발 도구 상세 실행 가이드
GCC 커널 빌드 주요 옵션
# 커널이 기본 사용하는 GCC 플래그 (top-level Makefile)
-Wall -Wundef -Werror=strict-prototypes -Werror=implicit-function-declaration
-Wno-trigraphs -fno-strict-aliasing -fno-common
-fno-delete-null-pointer-checks -fno-stack-protector
-Wdeclaration-after-statement -Wno-pointer-sign
# 아키텍처 의존 플래그 (x86_64)
-mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx
# ↑ 커널 코드에서 SIMD 레지스터 사용 금지 (kernel_fpu_begin 없이)
-mno-red-zone # Red Zone 비활성화 (인터럽트 핸들러 안전성)
-mcmodel=kernel # 커널 주소 공간 (상위 2GB) 코드 모델
-fno-pie # PIE 비활성화 (KASLR은 별도 메커니즘)
-mstack-protector-guard=global # Stack Canary
# 디버그 빌드
make KCFLAGS="-g -O0" menuconfig # 최적화 제거 (디버깅 시)
make KCFLAGS="-fsanitize=undefined" # UBSAN (Undefined Behavior)
# 빌드 시간 최적화
make -j$(nproc) # 병렬 빌드 (CPU 코어 수)
make CC="ccache gcc" -j$(nproc) # ccache로 재빌드 가속
GDB 커널 디버깅 상세
QEMU의 -s -S 옵션으로 GDB 디버그 포트를 열고, vmlinux 심볼 파일을 로드하여 커널을 소스 수준에서 디버깅할 수 있습니다. scripts/gdb/의 lx-dmesg, lx-ps 등 커널 전용 GDB 확장 명령을 활용하면 커널 내부 상태를 효과적으로 분석할 수 있습니다.
ftrace 상세 사용법
# ftrace 기본 설정 경로
FTRACE=/sys/kernel/debug/tracing
# 사용 가능한 트레이서 목록
cat $FTRACE/available_tracers
# nop function function_graph irqsoff preemptoff preemptirqsoff wakeup
# function 트레이서: 함수 호출 추적
echo function > $FTRACE/current_tracer
echo tcp_sendmsg > $FTRACE/set_ftrace_filter # 특정 함수만
echo 1 > $FTRACE/tracing_on
cat $FTRACE/trace_pipe # 실시간 출력
# function_graph 트레이서: 함수 호출 트리
echo function_graph > $FTRACE/current_tracer
echo vfs_write > $FTRACE/set_graph_function # 진입점
echo 5 > $FTRACE/max_graph_depth # 최대 깊이
cat $FTRACE/trace
# 이벤트 기반 트레이싱
echo 1 > $FTRACE/events/sched/sched_switch/enable # 스케줄러 이벤트
echo 1 > $FTRACE/events/irq/irq_handler_entry/enable # IRQ 이벤트
echo 1 > $FTRACE/events/kmem/kmalloc/enable # 메모리 할당
# 트리거: 특정 함수 호출 시 스택 트레이스
echo 'stacktrace' > $FTRACE/set_ftrace_filter
echo '__alloc_pages:stacktrace' >> $FTRACE/set_ftrace_filter
# 히스토그램 (5.x+)
echo 'hist:keys=common_pid:vals=hitcount' > \
$FTRACE/events/sched/sched_switch/trigger
perf 상세 사용법
perf는 Linux 커널의 성능 카운터 서브시스템(perf_events)을 활용하는 프로파일링(Profiling) 도구입니다. CPU 사이클, 캐시(Cache) 미스, 브랜치 예측 실패 등의 하드웨어 카운터와 tracepoint 기반 소프트웨어 이벤트를 통합적으로 분석할 수 있으며, Flame Graph 생성, 스케줄러(Scheduler) 지연(Latency) 분석, 동적 프로브(Probe) 등 다양한 기능을 제공합니다.
bpftrace 상세 사용법
# bpftrace: eBPF 기반 동적 트레이싱 (awk-like 문법)
# 시스템 콜 빈도 (5초간)
bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }' -d 5
# 프로세스별 read 크기 히스토그램
bpftrace -e 'tracepoint:syscalls:sys_exit_read /args->ret > 0/ {
@bytes[comm] = hist(args->ret);
}'
# 디스크 I/O 지연 분석
bpftrace -e 'tracepoint:block:block_rq_issue {
@start[args->dev, args->sector] = nsecs;
}
tracepoint:block:block_rq_complete /@start[args->dev, args->sector]/ {
@usecs = hist((nsecs - @start[args->dev, args->sector]) / 1000);
delete(@start[args->dev, args->sector]);
}'
# TCP retransmit 추적
bpftrace -e 'kprobe:tcp_retransmit_skb {
@[kstack] = count();
}'
# 커널 함수 인자 접근
bpftrace -e 'kprobe:vfs_read {
@bytes[comm] = hist(arg2); /* arg2 = count */
}'
KASAN / KMSAN / UBSAN 상세
커널 새니타이저는 런타임 메모리 오류를 감지하는 강력한 디버깅 도구입니다. KASAN은 use-after-free, out-of-bounds 등을 감지하고(Generic/SW_TAGS/HW_TAGS 모드), KMSAN은 초기화되지 않은 메모리 사용을(Clang 전용), UBSAN은 정수 오버플로(Integer Overflow) 등 미정의 동작을 감지합니다. 프로덕션 환경에서는 KFENCE로 낮은 오버헤드의 확률적 감지가 가능합니다.
커널 빌드 도구
리눅스 커널의 빌드 시스템(Build System)은 GNU Make를 기반으로 하며, Kconfig로 설정을 관리하고 Kbuild로 실제 컴파일 규칙을 정의합니다. 이 세 가지 구성 요소가 유기적으로 결합하여 수천 개의 소스 파일을 효율적으로 관리합니다.
make 주요 타겟
커널 빌드에서 자주 사용하는 make 타겟을 목적별로 분류합니다.
| 카테고리 | 타겟 | 설명 | 사용 예시 |
|---|---|---|---|
| 설정 | menuconfig | ncurses 기반 TUI 설정 메뉴 | make menuconfig |
nconfig | 향상된 ncurses 설정 메뉴 | make nconfig | |
xconfig | Qt 기반 GUI 설정 메뉴 | make xconfig | |
olddefconfig | 기존 .config 유지, 새 옵션은 기본값 | make olddefconfig | |
| 빌드 | all | vmlinux + 모듈 + dtbs 전체 빌드 | make -j$(nproc) |
bzImage | 압축된 커널 이미지 (x86) | make bzImage | |
modules | 모듈만 빌드 | make modules | |
modules_install | 모듈 설치 | make modules_install | |
| 설정 생성 | defconfig | 아키텍처 기본 설정 | make defconfig |
allmodconfig | 가능한 모든 옵션을 모듈로 | make allmodconfig | |
tinyconfig | 최소 설정 (빠른 빌드 테스트) | make tinyconfig | |
| 정리 | clean | 빌드 결과물 제거 | make clean |
mrproper | clean + .config 제거 | make mrproper | |
distclean | mrproper + 에디터 백업 제거 | make distclean | |
| 분석 | cscope | cscope 인덱스 생성 | make cscope |
tags | ctags 인덱스 생성 | make tags | |
htmldocs | HTML 문서 빌드 | make htmldocs |
Kconfig 시스템
Kconfig는 커널 설정 옵션을 선언적으로 정의하는 언어입니다. 각 서브시스템의 Kconfig 파일에 설정 항목, 의존성, 도움말이 정의됩니다.
# drivers/net/ethernet/intel/Kconfig 예시
config E1000E
tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet"
depends on PCI
select CRC32
select PTP_1588_CLOCK
help
This driver supports Intel PRO/1000 PCI-Express ethernet adapters.
To compile this driver as a module, choose M here.
The module will be called e1000e.
# Kconfig 주요 키워드
# config : 새 설정 항목 정의
# bool : y/n 선택
# tristate : y/m/n 선택 (모듈 가능)
# int : 정수 값
# string : 문자열 값
# depends on: 의존성 (조건 미충족 시 숨김)
# select : 강제 활성화 (역방향 의존성)
# imply : 약한 select (사용자 비활성화 가능)
# default : 기본값
# menuconfig: 하위 메뉴를 포함하는 설정 항목
# choice : 상호 배타적 선택 그룹
# .config 파일 조작 유틸리티
scripts/config --enable CONFIG_E1000E
scripts/config --disable CONFIG_E1000E
scripts/config --module CONFIG_E1000E
scripts/config --set-val CONFIG_LOG_BUF_SHIFT 18
scripts/config --set-str CONFIG_LOCALVERSION "-custom"
# 두 .config 파일 비교
scripts/diffconfig .config.old .config
# 설정 의존성 분석
make listnewconfig # 새 .config에만 있는 옵션
make oldconfig # 새 옵션마다 대화형 질문
make syncconfig # 내부적으로 헤더 파일 동기화
Kbuild 시스템
Kbuild는 각 디렉토리의 Makefile에서 오브젝트 파일을 선언하는 방식으로 동작합니다. obj-y는 내장(Built-in), obj-m은 모듈로 빌드됩니다.
# drivers/net/ethernet/intel/e1000e/Makefile
obj-$(CONFIG_E1000E) += e1000e.o
e1000e-objs := netdev.o ethtool.o ich8lan.o 82571.o mac.o \
nvm.o phy.o manage.o ptp.o
# Kbuild 변수 종류
obj-y += foo.o # 내장 컴파일
obj-m += bar.o # 모듈 컴파일
obj-$(CONFIG_X) += baz.o # 설정에 따라 결정
# 추가 컴파일 플래그
ccflags-y += -DDEBUG # 디렉토리 전체에 적용
CFLAGS_foo.o += -O0 # 특정 파일에만 적용
# 하위 디렉토리
obj-y += subdirectory/
# Kbuild 빌드 과정 상세 보기
make V=1 drivers/net/ethernet/intel/e1000e/ # 실행 명령 표시
make V=2 drivers/net/ethernet/intel/e1000e/ # 왜 재빌드하는지 표시
# 특정 파일만 빌드
make drivers/net/ethernet/intel/e1000e/netdev.o
# 전처리(Preprocessing) 결과 확인
make drivers/net/ethernet/intel/e1000e/netdev.i
# 어셈블리 출력
make drivers/net/ethernet/intel/e1000e/netdev.s
# 빌드 시간 프로파일링
make -j$(nproc) 2>&1 | ts '[%H:%M:%.S]' # moreutils의 ts 사용
빌드 가속: ccache와 distcc
# ccache: 컴파일 결과 캐싱으로 재빌드 속도 향상
sudo apt install ccache
make CC="ccache gcc" -j$(nproc)
# ccache 통계 확인
ccache -s
# Hits: 12345
# Misses: 678
# Hit ratio: 94.80%
# ccache 크기 설정 (기본 5GB)
ccache -M 20G
# distcc: 분산 컴파일 (네트워크의 여러 머신 활용)
sudo apt install distcc
export DISTCC_HOSTS="localhost worker1 worker2 worker3"
make CC="distcc gcc" -j$(($(nproc) * 4))
# ccache + distcc 결합
export CCACHE_PREFIX=distcc
make CC="ccache gcc" -j$(($(nproc) * 4))
소스 탐색 도구
수만 개의 파일로 구성된 리눅스 커널 소스를 효과적으로 탐색하려면 전용 인덱싱 도구가 필수입니다. 함수 정의(Definition), 호출 관계(Call Graph), 심볼 참조(Symbol Reference) 등을 빠르게 검색할 수 있습니다.
cscope
cscope는 대규모 C 코드베이스를 위한 대화형 소스 탐색 도구입니다. 커널은 make cscope 타겟을 내장하고 있어 인덱스 생성이 간편합니다.
# cscope 인덱스 생성 (커널 내장 타겟)
make cscope
# 수동 인덱스 생성 (세밀한 제어)
find . -name '*.c' -o -name '*.h' -o -name '*.S' > cscope.files
cscope -b -q -k # -b: 빌드만, -q: 역방향 인덱스, -k: 커널 모드
# cscope 대화형 검색 (터미널)
cscope -d # 인덱스 로드 후 검색 모드
# 0: 이 C 심볼을 찾습니다
# 1: 이 전역 정의를 찾습니다
# 2: 이 함수에 의해 호출되는 함수를 찾습니다
# 3: 이 함수를 호출하는 함수를 찾습니다
# 4: 이 텍스트 문자열을 찾습니다
# 6: 이 egrep 패턴을 찾습니다
# 7: 이 파일을 찾습니다
# 8: 이 파일을 #include 하는 파일을 찾습니다
# Vim에서 cscope 사용
# :cscope add cscope.out
# :cs find g schedule → 함수 정의
# :cs find c schedule → 호출하는 곳
# :cs find s task_struct → 심볼 참조
# :cs find d sys_read → 이 함수가 호출하는 함수
# :cs find t "EXPORT_SYMBOL" → 텍스트 검색
ctags (Universal Ctags)
# ctags 인덱스 생성 (커널 내장 타겟)
make tags # ctags 기반
make TAGS # etags 기반 (Emacs용)
# Universal Ctags 수동 생성 (더 많은 옵션)
ctags -R --languages=C,C++ --exclude=.git \
--fields=+lS --extras=+q \
arch/x86 drivers/ fs/ include/ kernel/ mm/ net/
# Vim에서 ctags 사용
# :tag function_name → 정의로 이동
# Ctrl-] → 커서 위치 태그로 이동
# Ctrl-t → 이전 위치로 복귀
# :tselect function_name → 중복 태그 선택
GNU Global (gtags)
GNU Global은 cscope와 ctags의 기능을 결합한 소스 코드 태그 시스템입니다. 정의, 참조, 심볼을 모두 인덱싱하며 증분 업데이트(Incremental Update)를 지원합니다.
# GNU Global 설치 및 인덱스 생성
sudo apt install global
cd /path/to/linux
gtags # GPATH, GRTAGS, GTAGS 생성
# 증분 업데이트 (변경된 파일만 재인덱싱)
global -u
# 검색 명령
global -d schedule # 정의 (definition)
global -r schedule # 참조 (reference)
global -s EXPORT_SYMBOL # 심볼 (symbol, grep)
global -g "spin_lock_irq" # 패턴 검색 (grep)
global -x schedule # 상세 정보 (정의 + 파일 + 줄번호)
global -P '*.c' # 파일 경로 검색
# htags: HTML 크로스 레퍼런스 생성
htags -Ffnsa # HTML/ 디렉토리에 결과 생성
Elixir Cross-Referencer
Bootlin에서 운영하는 Elixir Cross-Referencer는 웹 브라우저에서 커널 소스를 탐색할 수 있는 온라인 도구입니다. 설치 없이 사용할 수 있으며, 여러 커널 버전 간 코드 비교가 가능합니다.
| 도구 | 유형 | 장점 | 단점 | 추천 용도 |
|---|---|---|---|---|
| cscope | 로컬 CLI/TUI | 호출 관계 추적, 커널 내장 지원 | 증분 업데이트 없음, C 전용 | 함수 호출 그래프 분석 |
| ctags | 로컬 CLI | 빠른 태그 점프, 에디터 통합 | 참조 검색 미지원 | 빠른 정의 이동 |
| GNU Global | 로컬 CLI | 증분 업데이트, 정의+참조 통합 | 초기 인덱싱 느림 | 대규모 분석 프로젝트 |
| Elixir | 웹 기반 | 설치 불필요, 버전 비교 | 오프라인 불가, 커스텀 코드 불가 | 빠른 참조, 코드 리뷰 |
| clangd/ccls | LSP 서버 | IDE 통합, 의미 분석 | compile_commands.json 필요 | IDE 기반 개발 |
정적 분석 도구 상세
정적 분석(Static Analysis)은 코드를 실행하지 않고 소스 수준에서 결함을 탐지하는 기법입니다. 커널 개발에서는 주소 공간 혼동, 잠금 규약(Locking Protocol) 위반, API 오용 등을 컴파일 시점에 발견할 수 있습니다.
smatch
smatch는 커널 코드에 특화된 정적 분석 도구로, sparse보다 더 정교한 데이터 흐름(Data Flow) 분석을 수행합니다. 널 포인터 역참조(NULL Pointer Dereference), 범위 초과(Out-of-bounds), 잠금 불일치 등을 감지합니다.
# smatch 설치 (소스 빌드)
git clone https://repo.or.cz/smatch.git
cd smatch
make -j$(nproc)
sudo make install PREFIX=/usr/local
# smatch로 커널 검사
make CHECK="smatch -p=kernel" C=1
make CHECK="smatch -p=kernel" C=2 # 모든 파일
# 특정 검사만 실행
make CHECK="smatch -p=kernel --enable=check_locking" C=1
# smatch 주요 검사 항목
# - NULL 포인터 역참조 (check_deref, check_dereferences_param)
# - 범위 검사 (check_overflow, check_user_data)
# - 잠금 불일치 (check_locking)
# - use-after-free (check_free)
# - 초기화 안 된 변수 (check_uninitialized)
# - 에러 코드 반환 (check_return_efault, check_err_ptr)
Coccinelle
Coccinelle은 시맨틱 패치(Semantic Patch) 도구로, SmPL(Semantic Patch Language)을 사용하여 코드 변환 패턴을 정의합니다. 단순 정규식으로는 불가능한 구문 인식(Syntax-aware) 변환이 가능합니다.
// SmPL 예제: kzalloc 변환 (kmalloc + memset → kzalloc)
@@
expression x, size, flags;
statement S;
@@
- x = kmalloc(size, flags);
+ x = kzalloc(size, flags);
if (x == NULL) S
- memset(x, 0, size);
// SmPL 예제: of_node_put() 누락 감지
@@
expression node;
@@
node = of_find_compatible_node(...);
... when != of_node_put(node)
when != return ...;
+ of_node_put(node);
// SmPL 예제: sizeof 타입 불일치 감지
@@
type T;
T *p;
@@
p = kmalloc(
- sizeof(T *)
+ sizeof(*p)
, ...)
# Coccinelle 실행 방법
# 1) 커널 내장 coccicheck 타겟
make coccicheck MODE=report # 전체 검사 (보고만)
make coccicheck MODE=patch # 패치 자동 적용
make coccicheck MODE=context # 문맥 출력
make coccicheck MODE=org # org-mode 형식
# 2) 특정 스크립트만
make coccicheck COCCI=scripts/coccinelle/api/kfree.cocci MODE=report
# 3) 특정 디렉토리만
make coccicheck M=drivers/net/ MODE=report
# 4) 직접 실행
spatch --sp-file my_rule.cocci --dir drivers/net/ --include-headers
# 커널에 내장된 주요 Coccinelle 스크립트
ls scripts/coccinelle/
# api/ → API 변환 (kfree, alloc, ...)
# free/ → 해제 관련 (double free, use-after-free)
# misc/ → 기타 패턴
# null/ → NULL 검사
# locks/ → 잠금 관련
Clang Static Analyzer
Clang 정적 분석기(Static Analyzer)는 경로 민감(Path-sensitive) 분석을 수행하여 데드 코드(Dead Code), 메모리 누수(Memory Leak), 초기화되지 않은 변수 사용 등을 탐지합니다.
# scan-build를 사용한 커널 분석
scan-build make CC=clang -j$(nproc)
# HTML 보고서 생성
scan-build -o /tmp/scan-report make CC=clang -j$(nproc)
# 결과: /tmp/scan-report/YYYY-MM-DD-HHMMSS/
# 특정 체커만 활성화
scan-build -enable-checker core.NullDereference \
-enable-checker unix.Malloc \
make CC=clang -j$(nproc)
# 주요 체커 목록
# core.NullDereference : NULL 포인터 역참조
# core.DivideZero : 0으로 나누기
# core.UndefinedBinaryOp : 미정의 연산
# unix.Malloc : 메모리 할당/해제 오류
# unix.MallocSizeof : sizeof 불일치
# deadcode.DeadStores : 사용되지 않는 대입
| 도구 | 분석 유형 | 커널 특화 | 속도 | 거짓 양성 | 주요 검출 항목 |
|---|---|---|---|---|---|
| sparse | 타입 기반 | 매우 높음 | 빠름 | 낮음 | __user/__iomem 혼동, endian, bitwise |
| smatch | 데이터 흐름 | 높음 | 중간 | 중간 | NULL 역참조, 범위 초과, 잠금 불일치 |
| Coccinelle | 패턴 매칭 | 높음 | 중간 | 낮음 | API 오용, 코드 변환, 일관성 |
| Clang Analyzer | 경로 민감 | 낮음 | 느림 | 높음 | 메모리 누수, 데드 코드, use-after-free |
동적 분석 도구
동적 분석(Dynamic Analysis)은 커널을 실행하면서 런타임(Runtime) 오류를 감지합니다. 새니타이저(Sanitizer)는 커널에 계측 코드(Instrumentation Code)를 삽입하여 메모리 접근, 동시성(Concurrency), 미정의 동작 등을 실시간으로 감시합니다.
KASAN (Kernel Address Sanitizer)
KASAN은 메모리 접근 오류를 런타임에 감지하는 가장 강력한 커널 도구입니다. 세 가지 모드를 지원합니다.
| 모드 | CONFIG 옵션 | 컴파일러 | 오버헤드 | 사용 환경 |
|---|---|---|---|---|
| Generic KASAN | CONFIG_KASAN_GENERIC=y |
GCC/Clang | 메모리 ~3x, CPU ~2x | 개발/테스트 |
| SW_TAGS KASAN | CONFIG_KASAN_SW_TAGS=y |
Clang (ARM64) | 메모리 ~1.5x, CPU ~1.2x | ARM64 테스트 |
| HW_TAGS KASAN | CONFIG_KASAN_HW_TAGS=y |
GCC/Clang (ARM64 MTE) | 메모리 ~1.05x, CPU ~1.05x | 프로덕션 가능 |
# KASAN 활성화 커널 설정
scripts/config --enable CONFIG_KASAN
scripts/config --enable CONFIG_KASAN_GENERIC
scripts/config --enable CONFIG_KASAN_INLINE # 더 빠른 검사 (바이너리 커짐)
scripts/config --enable CONFIG_KASAN_STACK # 스택 변수 검사
make olddefconfig
make -j$(nproc)
# KASAN 보고 예시 (dmesg 출력)
# ==================================================================
# BUG: KASAN: slab-use-after-free in my_function+0x42/0x100
# Read of size 8 at addr ffff888012345678 by task test/1234
#
# Call Trace:
# dump_stack_lvl+0x44/0x5c
# print_report+0x17e/0x4b0
# kasan_report+0xb4/0xf0
# my_function+0x42/0x100
#
# Allocated by task 1234:
# kmalloc_trace+0x26/0x60
# my_alloc+0x20/0x50
#
# Freed by task 1234:
# kfree+0x8e/0xb0
# my_free+0x18/0x30
# ==================================================================
KMSAN (Kernel Memory Sanitizer)
# KMSAN: 초기화되지 않은 메모리 사용 감지 (Clang 전용)
scripts/config --enable CONFIG_KMSAN
make CC=clang LLVM=1 -j$(nproc)
# KMSAN 검출 예시
# ==================================================================
# BUG: KMSAN: uninit-value in my_function+0x42/0x100
# Uninit was created at:
# kmalloc_trace+0x26/0x60
# my_init+0x20/0x50
# ==================================================================
# 주의: KMSAN은 KASAN과 동시 사용 불가
# KMSAN은 현재 x86_64에서만 지원
KCSAN (Kernel Concurrency Sanitizer)
KCSAN은 데이터 경합(Data Race)을 감지하는 동시성 새니타이저입니다. 잠금 없이 공유 변수에 접근하는 코드를 찾아냅니다.
# KCSAN 활성화
scripts/config --enable CONFIG_KCSAN
scripts/config --enable CONFIG_KCSAN_REPORT_ONCE_IN_MS=0 # 모든 경합 보고
make -j$(nproc)
# KCSAN 보고 예시
# ==================================================================
# BUG: KCSAN: data-race in my_reader / my_writer
#
# write to 0xffff888012345678 of 4 bytes by task 5678:
# my_writer+0x42/0x100
#
# read to 0xffff888012345678 of 4 bytes by task 1234:
# my_reader+0x30/0x80
#
# value changed: 0x00000001 -> 0x00000002
# ==================================================================
# 의도적인 데이터 경합 표시 (false positive 방지)
# READ_ONCE(x), WRITE_ONCE(x, val) 사용
# data_race(expr) 래퍼 사용
UBSAN (Undefined Behavior Sanitizer)
# UBSAN 활성화 (GCC/Clang 모두 지원)
scripts/config --enable CONFIG_UBSAN
scripts/config --enable CONFIG_UBSAN_BOUNDS # 배열 범위 검사
scripts/config --enable CONFIG_UBSAN_SHIFT # 잘못된 시프트 감지
scripts/config --enable CONFIG_UBSAN_DIV_ZERO # 0으로 나누기
scripts/config --enable CONFIG_UBSAN_UNREACHABLE # 도달 불가 코드
scripts/config --enable CONFIG_UBSAN_BOOL # 잘못된 bool 값
scripts/config --enable CONFIG_UBSAN_ENUM # 잘못된 enum 값
scripts/config --enable CONFIG_UBSAN_TRAP # 위반 시 즉시 트랩 (디버깅용)
make -j$(nproc)
# UBSAN 검출 예시
# UBSAN: shift-out-of-bounds in drivers/foo/bar.c:123:4
# shift exponent 64 is too large for 32-bit type 'unsigned int'
lockdep (Lock Dependency Validator)
lockdep은 잠금 순서 위반과 잠재적 교착 상태(Deadlock)를 런타임에 감지하는 커널 내장 검증기입니다. 실제 교착이 발생하기 전에 잘못된 잠금 순서를 경고합니다.
# lockdep 활성화
scripts/config --enable CONFIG_LOCKDEP
scripts/config --enable CONFIG_PROVE_LOCKING # 잠금 순서 증명
scripts/config --enable CONFIG_LOCK_STAT # 잠금 경합 통계
scripts/config --enable CONFIG_DEBUG_LOCK_ALLOC # 잠금 할당 추적
make -j$(nproc)
# lockdep 보고 예시
# ============================================
# WARNING: possible circular locking dependency detected
# 6.x.0 #1 Not tainted
# -----------------------------------------------
# test/1234 is trying to acquire lock:
# ffff888012345678 (&lock_A){+.+.}-{3:3}, at: func_b+0x20/0x50
#
# but task is already holding lock:
# ffff888087654321 (&lock_B){+.+.}-{3:3}, at: func_a+0x18/0x40
#
# which lock already depends on the new lock.
# Possible unsafe locking scenario:
# CPU0 CPU1
# ---- ----
# lock(&lock_A);
# lock(&lock_B);
# lock(&lock_A); ← 교착
# lock(&lock_B); ← 교착
# ============================================
# 잠금 통계 확인
cat /proc/lock_stat | head -50
| 새니타이저 | 검출 대상 | 메모리 오버헤드 | CPU 오버헤드 | 컴파일러 | KASAN 동시 사용 |
|---|---|---|---|---|---|
| KASAN (Generic) | use-after-free, OOB, double-free | ~3x | ~2x | GCC/Clang | - |
| KMSAN | 초기화 안 된 메모리 | ~3x | ~3x | Clang only | 불가 |
| KCSAN | 데이터 경합 | 낮음 | 낮음 | GCC/Clang | 가능 |
| UBSAN | 미정의 동작 (시프트, 오버플로) | 낮음 | 낮음 | GCC/Clang | 가능 |
| lockdep | 교착, 잠금 순서 위반 | ~1.5x | 낮음 | GCC/Clang | 가능 |
| KFENCE | use-after-free, OOB (확률적) | 매우 낮음 | 매우 낮음 | GCC/Clang | 불가 |
디버깅 도구
커널 디버깅은 사용자 공간 프로그램과 달리 특수한 환경이 필요합니다. GDB를 직접 연결하려면 QEMU나 KGDB를 사용해야 하고, 크래시(Crash) 후 분석은 kdump로 수집한 vmcore를 crash 유틸리티로 분석합니다.
GDB/KGDB 설정
# 1) QEMU + GDB (가장 일반적인 커널 디버깅 방법)
# 커널 빌드 (디버그 정보 포함)
scripts/config --enable CONFIG_DEBUG_INFO
scripts/config --enable CONFIG_DEBUG_INFO_DWARF5
scripts/config --enable CONFIG_GDB_SCRIPTS
scripts/config --disable CONFIG_RANDOMIZE_BASE # KASLR 비활성화
make -j$(nproc)
# QEMU 실행 (GDB 대기 모드)
qemu-system-x86_64 \
-kernel arch/x86/boot/bzImage \
-initrd initramfs.gz \
-append "console=ttyS0 nokaslr" \
-nographic -m 2G -smp 2 \
-s -S # -s: GDB 포트 1234, -S: 시작 시 정지
# 다른 터미널에서 GDB 연결
gdb vmlinux
(gdb) target remote :1234
(gdb) lx-symbols # 모듈 심볼 로드
(gdb) break start_kernel
(gdb) continue
(gdb) lx-dmesg # dmesg 출력
(gdb) lx-ps # 프로세스 목록
(gdb) lx-lsmod # 모듈 목록
(gdb) lx-mounts # 마운트 목록
(gdb) p init_task.comm # 구조체 필드 접근
(gdb) p/x init_task.mm->pgd # 페이지 테이블
# 2) KGDB (실제 하드웨어에서 시리얼/네트워크 디버깅)
# 부트 파라미터:
# kgdboc=ttyS0,115200 kgdbwait
# 3) 커널 모듈 디버깅
# 모듈 로드 주소 확인 후 GDB에 추가
cat /sys/module/my_module/sections/.text
(gdb) add-symbol-file my_module.ko 0xffffffffc0000000
crash 유틸리티
crash는 실행 중인 커널이나 크래시 덤프(Crash Dump)를 분석하는 도구입니다. kdump/kexec으로 수집한 vmcore 파일을 사후에 분석할 수 있습니다.
# crash 설치
sudo apt install crash
# vmcore 분석
crash vmlinux /var/crash/vmcore
# crash 주요 명령
crash> bt # 백트레이스 (현재 또는 크래시 태스크)
crash> bt -a # 모든 CPU의 백트레이스
crash> bt 1234 # PID 1234의 백트레이스
crash> ps # 프로세스 목록
crash> ps -m # 메모리 사용량 포함
crash> task # 현재 task_struct 출력
crash> struct task_struct ffff888012345678 # 특정 주소의 구조체
crash> kmem -s # SLAB 캐시 정보
crash> kmem -i # 메모리 사용 요약
crash> files 1234 # PID 1234의 열린 파일
crash> vm 1234 # PID 1234의 가상 메모리 영역
crash> log # 커널 로그 (dmesg)
crash> dev # 디바이스 목록
crash> net # 네트워크 인터페이스
crash> mount # 마운트 포인트
crash> mod # 로드된 모듈
crash> rd -S ffff888012345678 32 # 메모리 읽기 (심볼 포함)
crash> dis -l func_name # 함수 디스어셈블 (소스 줄 포함)
kdump/kexec
# kdump: 커널 패닉(Kernel Panic) 시 메모리 덤프 수집
# 1) kdump 설치 및 설정
sudo apt install kdump-tools kexec-tools
# 2) 크래시 커널용 메모리 예약 (GRUB)
# /etc/default/grub:
# GRUB_CMDLINE_LINUX="crashkernel=256M"
sudo update-grub
# 3) 커널 설정
scripts/config --enable CONFIG_KEXEC
scripts/config --enable CONFIG_CRASH_DUMP
scripts/config --enable CONFIG_PROC_VMCORE
# 4) 크래시 커널 로드 확인
cat /sys/kernel/kexec_crash_loaded # 1이면 준비 완료
# 5) 수동 테스트 (주의: 시스템 크래시 유발)
echo c > /proc/sysrq-trigger # 강제 크래시
# 6) 재부팅 후 vmcore 분석
ls /var/crash/ # vmcore 파일 위치
crash vmlinux /var/crash/*/vmcore
dmesg와 printk
# dmesg: 커널 링 버퍼(Ring Buffer) 출력
dmesg # 전체 출력
dmesg -T # 사람 읽기 가능한 타임스탬프
dmesg -w # 실시간 모니터링 (follow)
dmesg -l err,warn # 특정 레벨만
dmesg -k # 커널 메시지만
dmesg --clear # 버퍼 지우기
# printk 로그 레벨
# 0 = KERN_EMERG (시스템 사용 불가)
# 1 = KERN_ALERT (즉시 조치 필요)
# 2 = KERN_CRIT (치명적 상태)
# 3 = KERN_ERR (오류)
# 4 = KERN_WARNING (경고)
# 5 = KERN_NOTICE (정상이지만 중요)
# 6 = KERN_INFO (정보)
# 7 = KERN_DEBUG (디버그)
# 콘솔 로그 레벨 변경
echo 7 > /proc/sys/kernel/printk # 디버그 메시지까지 출력
# 동적 디버그 (pr_debug/dev_dbg 활성화)
echo 'file drivers/net/*.c +p' > /sys/kernel/debug/dynamic_debug/control
echo 'module e1000e +p' > /sys/kernel/debug/dynamic_debug/control
echo 'func my_function +p' > /sys/kernel/debug/dynamic_debug/control
/* printk 사용 패턴 */
pr_info("device %s initialized\n", dev_name); /* KERN_INFO */
pr_err("failed to allocate: %d\n", err); /* KERN_ERR */
pr_warn("deprecated API used by %s\n", current->comm); /* KERN_WARNING */
pr_debug("entering %s\n", __func__); /* KERN_DEBUG (동적 디버그) */
/* 디바이스 드라이버용 (dev_info 등) */
dev_info(dev, "probe successful\n");
dev_err(dev, "firmware load failed: %d\n", ret);
dev_dbg(dev, "register 0x%04x = 0x%08x\n", reg, val);
/* 네트워크 드라이버용 */
netdev_info(netdev, "link up at %d Mbps\n", speed);
netdev_err(netdev, "TX timeout\n");
프로파일링 도구
커널 성능 분석에는 perf, ftrace, BPF 세 가지 주요 프레임워크가 사용됩니다. 각 도구는 서로 다른 관점에서 커널 동작을 분석하며, 상호 보완적으로 활용합니다.
perf
# perf stat: 하드웨어 카운터 기반 통계
perf stat -e cycles,instructions,cache-misses,branches,branch-misses \
make -j$(nproc)
# perf record + report: 샘플링 기반 프로파일링
perf record -g -a -- sleep 10 # 10초 시스템 전체 샘플링
perf report --stdio # 텍스트 보고서
perf report # TUI 보고서
# 커널 함수 프로파일링 (root 필요)
perf record -g -a -e cycles:k -- sleep 10 # 커널 모드만
# Flame Graph 생성
perf record -g -a -- sleep 30
perf script | stackcollapse-perf.pl | flamegraph.pl > flame.svg
# perf probe: 동적 트레이스포인트
perf probe -a 'vfs_read file->f_path.dentry->d_name.name:string'
perf record -e probe:vfs_read -a -- sleep 5
perf probe -d vfs_read # 삭제
# perf sched: 스케줄러 분석
perf sched record -- sleep 10
perf sched latency # 스케줄링 지연
perf sched map # CPU별 실행 맵
# perf c2c: 캐시 라인 경합 분석
perf c2c record -a -- sleep 10
perf c2c report --stdio
ftrace
# trace-cmd: ftrace의 사용자 친화적 프론트엔드
sudo apt install trace-cmd
# 기록 + 보고
trace-cmd record -p function_graph -g vfs_write sleep 5
trace-cmd report | head -100
# 특정 이벤트만 기록
trace-cmd record -e sched:sched_switch -e irq:irq_handler_entry sleep 10
# KernelShark: ftrace GUI 분석 도구
sudo apt install kernelshark
kernelshark trace.dat
# ftrace 인스턴스 (독립적 트레이싱 세션)
mkdir /sys/kernel/debug/tracing/instances/my_trace
echo function > /sys/kernel/debug/tracing/instances/my_trace/current_tracer
echo vfs_read > /sys/kernel/debug/tracing/instances/my_trace/set_ftrace_filter
echo 1 > /sys/kernel/debug/tracing/instances/my_trace/tracing_on
# 스냅샷 (현재 트레이스 버퍼 복사)
echo 1 > /sys/kernel/debug/tracing/snapshot
cat /sys/kernel/debug/tracing/snapshot
BPF/bpftool
BPF(Berkeley Packet Filter)는 커널 내에서 안전하게 실행되는 프로그램을 통해 관측성(Observability)을 제공합니다. perf나 ftrace보다 유연한 데이터 수집과 집계가 가능합니다. 상세한 내용은 BPF/XDP 전용 페이지를 참고하세요.
# bpftool: BPF 프로그램 및 맵 관리
bpftool prog list # 로드된 BPF 프로그램 목록
bpftool map list # BPF 맵 목록
bpftool prog show id 123 # 특정 프로그램 상세 정보
bpftool map dump id 456 # 맵 내용 출력
bpftool btf dump file vmlinux # BTF 타입 정보 출력
# BCC tools: 사전 빌드된 BPF 도구 모음
sudo apt install bpfcc-tools
execsnoop-bpfcc # 프로세스 실행 추적
opensnoop-bpfcc # 파일 오픈 추적
biolatency-bpfcc # 블록 I/O 지연 히스토그램
tcplife-bpfcc # TCP 연결 수명
runqlat-bpfcc # 스케줄러 런큐 지연
funccount-bpfcc 'vfs_*' # VFS 함수 호출 횟수
코드 포맷팅 및 검사
커널 코드의 일관성을 유지하기 위해 자동화된 검사 도구들을 활용합니다. 패치 제출 전 반드시 이 도구들을 실행하여 코딩 스타일 위반을 사전에 수정해야 합니다.
checkpatch.pl
# checkpatch.pl 기본 사용법
scripts/checkpatch.pl 0001-my-patch.patch # 패치 파일 검사
scripts/checkpatch.pl --file drivers/mydriver/myfile.c # 파일 직접 검사
scripts/checkpatch.pl --strict 0001-my-patch.patch # 엄격 모드
scripts/checkpatch.pl --terse 0001-my-patch.patch # 간결 출력
# git hook으로 자동 검사
cat > .git/hooks/pre-commit << 'HOOK'
#!/bin/bash
git diff --cached --diff-filter=ACM | scripts/checkpatch.pl --no-signoff -
HOOK
chmod +x .git/hooks/pre-commit
# 특정 검사 무시
scripts/checkpatch.pl --ignore LONG_LINE,SPLIT_STRING 0001-my-patch.patch
# checkpatch 주요 메시지 유형
# ERROR: 반드시 수정 (패치 거부 사유)
# WARNING: 수정 권장 (리뷰어가 지적할 수 있음)
# CHECK: 선택적 (--strict 모드에서만 표시)
# 자주 발생하는 ERROR
# ERROR: trailing whitespace → 줄 끝 공백 제거
# ERROR: code indent should use tabs → 스페이스 → 탭 변환
# ERROR: switch and case at same indent → case 들여쓰기
# ERROR: do not use C99 // comments → /* */ 사용
# 자주 발생하는 WARNING
# WARNING: line length exceeds 80 columns → 줄 길이 조절
# WARNING: Missing blank line after declaration → 빈 줄 추가
# WARNING: braces {} are not necessary for single statement → 불필요한 중괄호
clang-format
# 커널은 .clang-format 파일을 포함하고 있음
# 주의: clang-format은 보조 도구이며, checkpatch.pl이 최종 기준
# 파일 포맷팅 (변경 사항 출력만)
clang-format --style=file -n drivers/mydriver/myfile.c
# 파일 포맷팅 (직접 수정)
clang-format --style=file -i drivers/mydriver/myfile.c
# git diff와 결합 (변경된 줄만 포맷)
git diff -U0 HEAD~1 | clang-format-diff -p1 -style=file
# VS Code에서 설정
# settings.json:
# "C_Cpp.clang_format_style": "file"
# "editor.formatOnSave": true
테스트 프레임워크
커널 코드의 품질을 보장하기 위해 다양한 수준의 테스트 프레임워크가 존재합니다. 단위 테스트(Unit Test)부터 시스템 수준 퍼징(Fuzzing)까지, 각 프레임워크는 서로 다른 결함 유형을 대상으로 합니다.
KUnit 상세
KUnit은 커널 내장 단위 테스트 프레임워크입니다. 커널 함수를 격리된 환경에서 빠르게 테스트할 수 있으며, UML(User Mode Linux) 기반으로 실행하면 수 초 만에 결과를 확인할 수 있습니다.
# KUnit 기본 실행 (UML 기반 — 가장 빠름)
./tools/testing/kunit/kunit.py run
# 특정 테스트 스위트만 실행
./tools/testing/kunit/kunit.py run --filter "kunit_test*"
# 특정 .kunitconfig로 실행
./tools/testing/kunit/kunit.py run \
--kunitconfig=drivers/base/.kunitconfig
# QEMU 기반 실행 (실제 아키텍처 테스트)
./tools/testing/kunit/kunit.py run --arch=x86_64 --qemu_config=...
# 결과 형식 지정
./tools/testing/kunit/kunit.py run --json # JSON 출력
./tools/testing/kunit/kunit.py run --raw_output # KTAP 원본 출력
# KUnit 디버깅
./tools/testing/kunit/kunit.py run --make_options=LLVM=1 # Clang으로 빌드
./tools/testing/kunit/kunit.py run --alltests # 모든 테스트
/* KUnit 테스트 작성 예시 */
#include <kunit/test.h>
static void example_add_test(struct kunit *test)
{
/* 단언(Assertion) */
KUNIT_EXPECT_EQ(test, 1 + 1, 2);
KUNIT_EXPECT_NE(test, 1 + 1, 3);
KUNIT_EXPECT_TRUE(test, 1 < 2);
KUNIT_EXPECT_NOT_NULL(test, kmalloc(64, GFP_KERNEL));
}
static void example_alloc_test(struct kunit *test)
{
struct my_struct *obj;
/* KUnit 관리 리소스 (테스트 종료 시 자동 해제) */
obj = kunit_kzalloc(test, sizeof(*obj), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, obj); /* ASSERT: 실패 시 테스트 중단 */
obj->value = 42;
KUNIT_EXPECT_EQ(test, obj->value, 42);
/* kfree 불필요 — kunit이 자동 정리 */
}
static struct kunit_case example_test_cases[] = {
KUNIT_CASE(example_add_test),
KUNIT_CASE(example_alloc_test),
{}
};
static struct kunit_suite example_test_suite = {
.name = "example",
.test_cases = example_test_cases,
};
kunit_test_suite(example_test_suite);
kselftest 상세
# kselftest: 커널 기능 회귀 테스트 (사용자 공간에서 실행)
# 전체 테스트 실행
make -C tools/testing/selftests run_tests
# 특정 서브시스템만
make -C tools/testing/selftests TARGETS=net run_tests
make -C tools/testing/selftests TARGETS="mm bpf" run_tests
# 빌드만 (설치 후 실행)
make -C tools/testing/selftests INSTALL_PATH=/tmp/kselftest install
/tmp/kselftest/run_kselftest.sh
# 개별 테스트 실행
cd tools/testing/selftests/net
make
./reuseport_bpf
# 주요 테스트 카테고리
# bpf/ : eBPF 프로그램 테스트
# mm/ : 메모리 관리 (mmap, hugepage, ...)
# net/ : 네트워크 스택
# ftrace/ : 트레이싱 기능
# cgroup/ : 제어 그룹
# filesystems/ : 파일시스템
# seccomp/ : 시스템 콜 필터링
# kvm/ : 가상화
LTP (Linux Test Project)
# LTP: 포괄적인 리눅스 커널 테스트 스위트
git clone https://github.com/linux-test-project/ltp.git
cd ltp
make autotools
./configure
make -j$(nproc)
sudo make install
# 전체 테스트 실행 (시간 오래 걸림)
cd /opt/ltp
sudo ./runltp
# 특정 테스트 그룹만
sudo ./runltp -f syscalls # 시스템 콜 테스트
sudo ./runltp -f mm # 메모리 관리 테스트
sudo ./runltp -f io # I/O 테스트
sudo ./runltp -f net.tcp_cmds # 네트워크 TCP 테스트
# 개별 테스트 실행
sudo ./testcases/bin/mmap01
sudo ./testcases/bin/fork01
syzkaller (커널 퍼저)
syzkaller는 Google이 개발한 커널 퍼징(Fuzzing) 도구로, 시스템 콜을 무작위 조합하여 커널 버그를 자동으로 발견합니다. syzbot은 syzkaller의 자동화된 CI 시스템으로, 매일 수천 개의 크래시를 자동 보고합니다.
# syzkaller 설치 (Go 필요)
git clone https://github.com/google/syzkaller.git
cd syzkaller
make
# 커널 설정 (syzkaller용)
# KASAN, KCSAN, lockdep 등 새니타이저 활성화 권장
scripts/config --enable CONFIG_KASAN
scripts/config --enable CONFIG_KCSAN
scripts/config --enable CONFIG_LOCKDEP
scripts/config --enable CONFIG_KCOV # 커버리지 수집 (syzkaller 필수)
scripts/config --enable CONFIG_DEBUG_INFO
scripts/config --enable CONFIG_CONFIGFS_FS
scripts/config --enable CONFIG_SECURITYFS
# syzkaller 설정 (my.cfg)
# {
# "target": "linux/amd64",
# "http": "127.0.0.1:56741",
# "workdir": "/tmp/syzkaller",
# "kernel_obj": "/path/to/linux",
# "image": "/path/to/bullseye.img",
# "syzkaller": "/path/to/syzkaller",
# "procs": 8,
# "type": "qemu",
# "vm": {
# "count": 4,
# "kernel": "/path/to/bzImage",
# "cpu": 2,
# "mem": 2048
# }
# }
# 실행
./bin/syz-manager -config my.cfg
# 웹 대시보드: http://127.0.0.1:56741
# syzbot 자동 보고: https://syzkaller.appspot.com
| 프레임워크 | 테스트 유형 | 실행 환경 | 속도 | 주요 대상 |
|---|---|---|---|---|
| KUnit | 단위 테스트 | UML / QEMU | 매우 빠름 (수 초) | 내부 API, 자료구조 |
| kselftest | 기능 테스트 | 실제 커널 (사용자 공간) | 보통 (수 분) | syscall, ABI 호환성 |
| LTP | 적합성 테스트 | 실제 커널 | 느림 (수 시간) | POSIX 호환, 스트레스 |
| syzkaller | 퍼징 | QEMU VM (다수) | 연속 실행 | 미지의 버그 자동 발견 |
| xfstests | 파일시스템 테스트 | 실제 커널 | 느림 | ext4, xfs, btrfs 등 |
버전 관리: Git 워크플로 상세
리눅스 커널은 세계 최대 규모의 Git 저장소 중 하나이며, 고유한 패치 기반 워크플로를 사용합니다. Pull Request 대신 메일링 리스트를 통한 패치 교환이 표준이며, 이를 위한 전용 도구들이 존재합니다.
git-send-email 설정
# git send-email 설치
sudo apt install git-email
# ~/.gitconfig 설정 예시 (Gmail SMTP)
git config --global sendemail.smtpserver smtp.gmail.com
git config --global sendemail.smtpserverport 587
git config --global sendemail.smtpencryption tls
git config --global sendemail.smtpuser your-email@gmail.com
# 앱 비밀번호 사용 (2FA 활성화 시):
git config --global sendemail.smtppass "xxxx-xxxx-xxxx-xxxx"
# 패치 생성 및 전송 전체 흐름
# 1) 작업 브랜치 생성
git checkout -b fix-null-deref origin/master
# 2) 코드 수정 및 커밋
git add -p # 변경 내용 검토 후 스테이징
git commit -s # -s: Signed-off-by 자동 추가
# 3) 커밋 메시지 형식
# subsystem: fix null pointer dereference in foo()
#
# When bar() returns NULL, we must check the return value
# before dereferencing. Otherwise, a null pointer exception
# can occur during probe.
#
# Fixes: a1b2c3d4e5f6 ("subsystem: add bar() support")
# Cc: stable@vger.kernel.org
# Signed-off-by: Your Name <your@email.com>
# 4) 패치 파일 생성
git format-patch -1 -v1 --subject-prefix="PATCH" HEAD
# 5) checkpatch 검사
scripts/checkpatch.pl v1-0001-*.patch
# 6) 메인테이너 확인
scripts/get_maintainer.pl v1-0001-*.patch
# 7) 자기 앞 테스트 발송
git send-email --to=your@email.com v1-0001-*.patch
# 8) 본 발송
git send-email \
--to=subsystem@vger.kernel.org \
--cc=maintainer1@kernel.org \
--cc=maintainer2@kernel.org \
--cc=linux-kernel@vger.kernel.org \
v1-0001-*.patch
b4 도구
b4은 kernel.org에서 개발한 패치 시리즈 관리 도구입니다. lore.kernel.org에서 패치를 가져오고, 리뷰 태그를 수집하며, 패치를 재전송하는 작업을 자동화합니다.
# b4 설치
pip install b4
# 패치 시리즈 가져와 적용 (Message-ID 사용)
b4 am 20231115120000.12345-1-developer@kernel.org
# lore URL에서 패치 적용
b4 shazam https://lore.kernel.org/linux-kernel/20231115120000.12345-1-developer@kernel.org
# 패치 시리즈 정보 확인
b4 mbox 20231115120000.12345-1-developer@kernel.org
# b4 기반 패치 워크플로 (최신 방법)
# 1) 작업 준비
b4 prep --fork-point origin/master --set-prefix "PATCH"
# 2) 커밋 작성 (일반 git 작업)
git add -p && git commit -s
# 3) 커버 레터 편집
b4 prep --edit-cover
# 4) 패치 전송
b4 send
# 5) v2 전송 (리뷰 반영 후)
b4 prep --set-prefix "PATCH v2"
b4 send
git bisect 상세
# git bisect: 이진 검색(Binary Search)으로 버그 도입 커밋 찾기
# 수동 bisect
git bisect start
git bisect bad HEAD # 현재 = 버그 있음
git bisect good v6.5 # v6.5 = 정상
# → git이 중간 커밋을 체크아웃
# → 빌드 & 테스트 후:
git bisect good # 또는 git bisect bad
# → 반복... (O(log n) 커밋)
git bisect reset # 완료 후 원래 브랜치로
# 자동 bisect (스크립트로 자동 판별)
git bisect start HEAD v6.5
git bisect run ./test-script.sh
# test-script.sh: 종료 코드 0 = good, 1-124 = bad, 125 = skip
# 자동 bisect 예시 스크립트
cat > test-bug.sh << 'EOF'
#!/bin/bash
make -j$(nproc) 2>/dev/null || exit 125 # 빌드 실패 = skip
# QEMU로 부팅 테스트
timeout 60 qemu-system-x86_64 \
-kernel arch/x86/boot/bzImage \
-initrd initramfs.gz \
-append "console=ttyS0" \
-nographic -m 1G 2>&1 | grep -q "BUG:" && exit 1
exit 0
EOF
chmod +x test-bug.sh
git bisect run ./test-bug.sh
IDE/에디터 설정 상세
커널 개발을 위한 에디터 설정은 코드 탐색, 자동 완성(Autocomplete), 정적 분석 통합이 핵심입니다. compile_commands.json을 생성하면 LSP(Language Server Protocol) 기반 도구가 정확한 의미 분석을 수행합니다.
VS Code 설정
# 1) compile_commands.json 생성 (필수)
scripts/clang-tools/gen_compile_commands.py
# 또는 bear 사용 (어떤 빌드 시스템이든 지원)
bear -- make -j$(nproc)
# 2) VS Code 확장 설치
# - clangd (C/C++ IntelliSense, 코드 완성, 네비게이션)
# - C/C++ (Microsoft, 대안)
# - Vim (Vim 키 바인딩)
# - GitLens (Git 통합)
# 3) .vscode/settings.json
{
"clangd.path": "/usr/bin/clangd",
"clangd.arguments": [
"--background-index",
"--compile-commands-dir=${workspaceFolder}",
"--header-insertion=never",
"--completion-style=detailed",
"-j=4"
],
"files.associations": {
"*.h": "c"
},
"editor.tabSize": 8,
"editor.insertSpaces": false,
"editor.rulers": [80, 100],
"files.trimTrailingWhitespace": true,
"C_Cpp.intelliSenseEngine": "disabled"
}
Vim/Neovim 설정
" ~/.vimrc 또는 ~/.config/nvim/init.vim (커널 개발용)
" 커널 코딩 스타일
set tabstop=8
set shiftwidth=8
set noexpandtab
set textwidth=80
set colorcolumn=80,100
filetype plugin indent on
syntax on
" cscope 설정
if has("cscope")
set csprg=/usr/bin/cscope
set csto=0
set cst
set nocsverb
if filereadable("cscope.out")
cs add cscope.out
endif
set csverb
" 키 매핑
nmap <C-\>s :cs find s <C-R>=expand("<cword>")<CR><CR>
nmap <C-\>g :cs find g <C-R>=expand("<cword>")<CR><CR>
nmap <C-\>c :cs find c <C-R>=expand("<cword>")<CR><CR>
nmap <C-\>d :cs find d <C-R>=expand("<cword>")<CR><CR>
endif
" ctags 설정
set tags=./tags;/
" Neovim LSP (clangd) — init.lua
" require('lspconfig').clangd.setup{
" cmd = { "clangd", "--background-index",
" "--compile-commands-dir=." },
" }
Emacs 설정
;; ~/.emacs.d/init.el (커널 개발용)
;; 커널 코딩 스타일
(defun linux-kernel-coding-style ()
"Setup C coding style for Linux kernel."
(setq indent-tabs-mode t)
(setq tab-width 8)
(setq c-basic-offset 8)
(c-set-style "linux"))
(add-hook 'c-mode-hook 'linux-kernel-coding-style)
;; TAGS 사용 (etags)
;; M-. : 정의로 이동
;; M-* : 이전 위치로 복귀
;; make TAGS 로 인덱스 생성
;; eglot (내장 LSP 클라이언트, Emacs 29+)
(add-hook 'c-mode-hook 'eglot-ensure)
(setq eglot-server-programs
'((c-mode . ("clangd" "--background-index"))))
가상화 기반 개발 환경
커널 개발에서 가상화(Virtualization)는 안전한 테스트 환경을 제공합니다. 버그가 있는 커널을 부팅해도 호스트 시스템에 영향이 없으며, 디버거 연결도 용이합니다.
QEMU
# QEMU 기본 실행 옵션 상세
qemu-system-x86_64 \
-kernel arch/x86/boot/bzImage \ # 커널 이미지
-initrd initramfs.gz \ # 초기 RAM 디스크
-append "console=ttyS0 nokaslr root=/dev/sda rw" \ # 커널 파라미터
-nographic \ # 그래픽 없이 시리얼 콘솔만
-m 2G \ # 메모리 2GB
-smp 4 \ # CPU 4코어
-enable-kvm \ # KVM 가속 (호스트 = Linux)
-cpu host \ # 호스트 CPU 기능 전달
-s -S \ # GDB 대기 (포트 1234)
-drive file=rootfs.img,format=qcow2 \ # 디스크 이미지
-netdev user,id=net0,hostfwd=tcp::2222-:22 \ # 포트 포워딩
-device virtio-net-pci,netdev=net0
# QEMU 디스크 이미지 생성
qemu-img create -f qcow2 rootfs.img 10G
# debootstrap으로 루트 파일시스템 설치
sudo debootstrap --arch=amd64 bookworm /mnt/rootfs
# 또는 Syzkaller의 create-image.sh 사용
# ARM64 에뮬레이션
qemu-system-aarch64 \
-M virt -cpu cortex-a57 \
-kernel Image \
-append "console=ttyAMA0" \
-nographic -m 2G -smp 2
# RISC-V 에뮬레이션
qemu-system-riscv64 \
-M virt -cpu rv64 \
-kernel Image \
-append "console=ttyS0" \
-nographic -m 2G
virtme / virtme-ng
virtme는 현재 호스트의 루트 파일시스템을 그대로 사용하여 커널을 빠르게 부팅하는 도구입니다. 별도 디스크 이미지가 필요 없어 개발 사이클(Cycle)이 매우 빠릅니다.
# virtme-ng 설치
pip install virtme-ng
# 빠른 커널 부팅 (현재 호스트 파일시스템 사용)
vng --build --run
# 또는
virtme-run --kdir . --mods=auto
# 특정 커널 파라미터와 함께
virtme-run --kdir . --mods=auto \
--append "nokaslr" \
--memory 2G --cpus 4
# 스크립트 실행 후 종료
virtme-run --kdir . --mods=auto \
--script-sh "dmesg | grep -i error; poweroff"
# KUnit 빠른 실행
./tools/testing/kunit/kunit.py run --arch=x86_64
UML (User Mode Linux)
# UML: 커널을 사용자 프로세스로 실행 (가장 빠른 커널 테스트 방법)
# UML 커널 빌드
make ARCH=um defconfig
make ARCH=um -j$(nproc)
# UML 실행
./linux rootfstype=hostfs rw init=/bin/bash
# UML + 네트워크
./linux rootfstype=hostfs rw \
eth0=slirp,,/usr/bin/slirp-fullbolt
# KUnit에서 UML 사용 (기본값)
./tools/testing/kunit/kunit.py run # 자동으로 ARCH=um 사용
# UML 장점
# - 가상화 불필요 (일반 프로세스)
# - GDB로 직접 디버깅 (gdb ./linux)
# - 빌드/실행 매우 빠름
# - KUnit 기본 백엔드
# UML 단점
# - 하드웨어 접근 불가
# - x86/x86_64만 지원
# - 일부 커널 기능 미지원 (KVM, 인터럽트 등)
CI/CD 시스템
커널 개발에서 지속적 통합(Continuous Integration)은 다양한 아키텍처와 설정 조합에서 빌드와 테스트를 자동화합니다. 주요 CI 시스템은 패치가 메인라인에 병합되기 전에 문제를 조기에 발견합니다.
KernelCI
KernelCI는 리눅스 재단이 후원하는 커널 CI 프로젝트입니다. 200개 이상의 보드에서 커널을 빌드하고 부팅 테스트를 수행합니다.
| CI 시스템 | 운영 주체 | 주요 기능 | 결과 접근 |
|---|---|---|---|
| KernelCI | Linux Foundation | 빌드 + 부팅 테스트, 200+ 보드 | kernelci.org |
| 0-Day (Intel) | Intel | 빌드 오류, 성능 회귀, 정적 분석 | 메일링 리스트 자동 보고 |
| LKFT (Linaro) | Linaro | ARM/ARM64 kselftest, LTP | lkft.linaro.org |
| syzbot | syzkaller 기반 자동 퍼징 | syzkaller.appspot.com | |
| CKI (Red Hat) | Red Hat | 빌드 + 기능 테스트 | 메일링 리스트 보고 |
0-Day CI (Intel)
0-Day는 Intel이 운영하는 빌드 봇(Build Bot)으로, 메인라인 커밋과 메일링 리스트 패치를 자동으로 빌드하여 컴파일 오류, 경고, 성능 회귀(Performance Regression)를 메일로 보고합니다.
# 0-Day 보고 예시 (메일 수신)
# Subject: [PATCH v2] driver: fix null deref
# From: kernel test robot <lkp@intel.com>
#
# Hi,
# Thank you for the patch!
#
# >> drivers/foo/bar.c:123:4: error: implicit function declaration
#
# All errors (new ones prefixed by >>):
# ...
# 로컬에서 0-Day와 유사한 검증 수행
# 여러 설정으로 빌드 테스트
for config in defconfig allmodconfig allyesconfig; do
make mrproper
make $config
make -j$(nproc) 2>&1 | tee build_${config}.log
done
# 크로스 컴파일 테스트
for arch_cross in "arm64 aarch64-linux-gnu-" "riscv riscv64-linux-gnu-"; do
set -- $arch_cross
make mrproper
ARCH=$1 CROSS_COMPILE=$2 make defconfig
ARCH=$1 CROSS_COMPILE=$2 make -j$(nproc) 2>&1 | tee build_${1}.log
done
실전 워크플로 가이드
각 개발 시나리오에 따라 도구를 효율적으로 조합하는 방법을 안내합니다.
시나리오 1: 첫 커널 패치 제출
# ① 개발 환경 준비
sudo apt install build-essential bc bison flex libelf-dev \
libssl-dev libncurses-dev dwarves python3 git git-email
git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux
# ② 빌드 검증
make defconfig
make -j$(nproc)
# ③ 수정 (예: 오타 수정)
git checkout -b fix-typo origin/master
# ... 코드 수정 ...
# ④ 빌드 & 검사
make -j$(nproc)
scripts/checkpatch.pl --file modified_file.c
# ⑤ 커밋 & 패치 생성
git add -p
git commit -s # Signed-off-by 포함
git format-patch -1 HEAD
# ⑥ 검사 & 전송
scripts/checkpatch.pl 0001-*.patch
scripts/get_maintainer.pl 0001-*.patch
git send-email --to=your@email.com 0001-*.patch # 테스트 발송
git send-email --to=... --cc=... 0001-*.patch # 본 발송
시나리오 2: 커널 버그 추적
# ① 증상 기록
dmesg -T | tail -50 > bug_report.log
# ② 재현 환경 구축 (QEMU)
scripts/config --enable CONFIG_KASAN
scripts/config --enable CONFIG_DEBUG_INFO
scripts/config --disable CONFIG_RANDOMIZE_BASE
make -j$(nproc)
qemu-system-x86_64 -kernel arch/x86/boot/bzImage \
-initrd initramfs.gz -append "console=ttyS0 nokaslr" \
-nographic -m 2G -s
# ③ GDB로 디버깅
gdb vmlinux -ex "target remote :1234" -ex "lx-symbols"
# ④ git bisect로 원인 커밋 특정
git bisect start HEAD v6.5
git bisect run ./test-bug.sh
# ⑤ 수정 & 검증
# ... 코드 수정 ...
make C=1 -j$(nproc) # sparse 검사
./tools/testing/kunit/kunit.py run # 단위 테스트
# ⑥ 패치 전송
git commit -s
git format-patch -1 HEAD
scripts/checkpatch.pl --strict 0001-*.patch
시나리오 3: 성능 분석 및 최적화
# ① 기준선(Baseline) 측정
perf stat -r 5 -- my_benchmark
# ② 핫스팟 식별
perf record -g -a -- my_benchmark
perf report
perf script | stackcollapse-perf.pl | flamegraph.pl > baseline.svg
# ③ 상세 분석
# 캐시 미스
perf stat -e L1-dcache-load-misses,LLC-load-misses -- my_benchmark
# 캐시 라인 경합
perf c2c record -- my_benchmark
# 구조체 패딩 분석
pahole -C hot_struct vmlinux
# ④ ftrace로 지연 측정
echo function_graph > /sys/kernel/debug/tracing/current_tracer
echo hot_function > /sys/kernel/debug/tracing/set_graph_function
echo 1 > /sys/kernel/debug/tracing/tracing_on
# ... 워크로드 실행 ...
cat /sys/kernel/debug/tracing/trace
# ⑤ 최적화 후 비교
perf stat -r 5 -- my_benchmark # 최적화 후 측정
# Flame Graph 비교
도구 생태계 요약
| 개발 단계 | 필수 도구 | 권장 도구 | 고급 도구 |
|---|---|---|---|
| 코드 작성 | 에디터 + ctags | clangd + LSP | GNU Global, cscope |
| 빌드 | GCC, make | ccache, Clang | distcc, Thin LTO |
| 정적 검사 | checkpatch.pl | sparse, smatch | Coccinelle, Clang Analyzer |
| 동적 검사 | KASAN | UBSAN, lockdep | KMSAN, KCSAN, KFENCE |
| 테스트 | QEMU 부팅 | KUnit, kselftest | LTP, syzkaller, xfstests |
| 디버깅 | dmesg, printk | GDB + QEMU | crash, kdump, KGDB |
| 프로파일링 | perf stat | perf record, ftrace | bpftrace, BCC, Flame Graph |
| 패치 제출 | git format-patch, git send-email | b4, get_maintainer.pl | lore.kernel.org, patchwork |
커널 개발 도구 종합 요약
| 도구 | 분류 | 주요 용도 | 핵심 명령/옵션 |
|---|---|---|---|
| GCC/Clang | 빌드 | 커널 컴파일 | make CC=clang LLVM=1 |
| GDB | 디버깅 | 커널/모듈 디버깅 | target remote :1234, lx-dmesg |
| QEMU | 가상화(Virtualization) | 빌드 커널 테스트 | -kernel -initrd -s -S |
| ftrace | 트레이싱 | 함수/이벤트 추적 | /sys/kernel/debug/tracing/ |
| perf | 프로파일링 | 성능 분석, 카운터 | perf record -g, perf report |
| bpftrace | 트레이싱 | 동적 eBPF 트레이싱 | bpftrace -e '...' |
| sparse | 정적 분석 | 타입/잠금(Lock) 검사 | make C=1 또는 C=2 |
| Coccinelle | 리팩터링 | 패턴 기반 코드 변환 | make coccicheck |
| checkpatch.pl | 스타일 | 코딩 스타일 검사 | ./scripts/checkpatch.pl -f file.c |
| pahole/BTF | 분석 | 구조체 레이아웃, BPF | pahole -C task_struct vmlinux |
| KASAN | 런타임 검사 | 메모리 오류 감지 | CONFIG_KASAN=y |
| lockdep | 런타임 검사 | 데드락 감지 | CONFIG_LOCKDEP=y |
| KUnit | 테스트 | 커널 단위 테스트 | make KUNIT=y, kunit.py run |
| kselftest | 테스트 | 기능 회귀 테스트 | make -C tools/testing/selftests run_tests |
| crash | 사후 분석 | vmcore 분석 | crash vmlinux vmcore |
| Bootlin Elixir | 브라우저 | 소스 크로스 레퍼런스 | elixir.bootlin.com |
커널 모듈 개발 도구
커널 모듈(Kernel Module)은 커널을 재컴파일하지 않고 기능을 추가/제거할 수 있는 동적 로드(Dynamic Loading) 메커니즘입니다. 모듈 개발에 특화된 도구와 기법을 설명합니다.
외부 모듈 빌드
# 외부 모듈 Makefile 예시
obj-m += my_module.o
my_module-objs := main.o helper.o
# 다중 소스 파일 모듈
KDIR ?= /lib/modules/$(shell uname -r)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
# 추가 플래그
ccflags-y += -DDEBUG -Werror
# 외부 모듈 빌드 및 로드
make -C /lib/modules/$(uname -r)/build M=$PWD modules
sudo insmod my_module.ko param1=value1
lsmod | grep my_module
sudo rmmod my_module
# 모듈 정보 확인
modinfo my_module.ko
# filename: /path/to/my_module.ko
# description: My test module
# author: Developer Name
# license: GPL
# depends:
# vermagic: 6.x.0 SMP preempt mod_unload
# 모듈 의존성 확인
modprobe --show-depends my_module
# 모듈 심볼 확인
nm my_module.ko | grep ' T ' # 내보낸(exported) 심볼
/* 커널 모듈 기본 템플릿 */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
static int param_value = 42;
module_param(param_value, int, 0644);
MODULE_PARM_DESC(param_value, "An integer parameter");
static int __init my_module_init(void)
{
pr_info("my_module loaded, param=%d\n", param_value);
return 0;
}
static void __exit my_module_exit(void)
{
pr_info("my_module unloaded\n");
}
module_init(my_module_init);
module_exit(my_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Developer Name");
MODULE_DESCRIPTION("Example kernel module");
MODULE_VERSION("1.0");
모듈 디버깅
# 모듈 디버깅 단계
# 1) 동적 디버그 활성화
echo 'module my_module +p' > /sys/kernel/debug/dynamic_debug/control
# 2) QEMU에서 모듈 디버깅
# 모듈 로드 주소 확인
cat /sys/module/my_module/sections/.text
# 0xffffffffc0123000
# GDB에서 심볼 로드
(gdb) add-symbol-file my_module.ko 0xffffffffc0123000
(gdb) break my_function
(gdb) continue
# 3) ftrace로 모듈 함수 추적
echo ':mod:my_module' > /sys/kernel/debug/tracing/set_ftrace_filter
echo function > /sys/kernel/debug/tracing/current_tracer
echo 1 > /sys/kernel/debug/tracing/tracing_on
# 4) 모듈 로드/언로드 이벤트 추적
echo 1 > /sys/kernel/debug/tracing/events/module/module_load/enable
echo 1 > /sys/kernel/debug/tracing/events/module/module_free/enable
문서화 도구
커널 코드의 문서화는 유지보수성과 코드 리뷰 효율성에 직접적인 영향을 미칩니다. kernel-doc 형식의 주석(Comment)은 자동으로 API 문서를 생성하며, Sphinx를 통해 HTML/PDF로 변환됩니다.
kernel-doc 형식
/**
* struct my_device - device information structure
* @name: device name string
* @id: unique device identifier
* @flags: device state flags (see &my_device_flags)
* @lock: protects concurrent access to @flags
* @list: linked list node for device registry
*
* This structure holds all information for a single
* managed device. Allocate with my_device_create()
* and free with my_device_destroy().
*
* Context: Process context only. @lock must not be
* held when calling any function that may sleep.
*/
struct my_device {
const char *name;
u32 id;
unsigned long flags;
spinlock_t lock;
struct list_head list;
};
/**
* my_device_create - allocate and initialize a device
* @name: device name (copied internally)
* @parent: parent device, or NULL for top-level
*
* Allocates a new &struct my_device and registers it
* with the device subsystem. The caller must call
* my_device_destroy() when done.
*
* Context: Process context. May sleep (GFP_KERNEL allocation).
*
* Return:
* * pointer to new device - success
* * ERR_PTR(-ENOMEM) - allocation failure
* * ERR_PTR(-EEXIST) - name already registered
*/
struct my_device *my_device_create(const char *name,
struct device *parent);
# kernel-doc 검증
scripts/kernel-doc -none drivers/mydriver/myfile.c # 형식 오류만 검사
scripts/kernel-doc -rst drivers/mydriver/myfile.c # RST 출력
scripts/kernel-doc -man drivers/mydriver/myfile.c # man 페이지 출력
# Sphinx로 HTML 문서 빌드
make htmldocs
# 결과: Documentation/output/index.html
# 특정 서브시스템만
make SPHINXDIRS="driver-api" htmldocs
make SPHINXDIRS="core-api" htmldocs
make SPHINXDIRS="networking" htmldocs
# kernel-doc 경고를 ERROR로 변환
make SPHINXOPTS="-W" htmldocs # 경고가 있으면 빌드 실패
# PDF 문서 빌드 (LaTeX 필요)
make pdfdocs
RST 문서 작성
.. SPDX-License-Identifier: GPL-2.0
==========================
My Subsystem Documentation
==========================
Overview
========
This subsystem provides ...
API Reference
=============
.. kernel-doc:: drivers/mydriver/myfile.c
:export:
.. kernel-doc:: include/linux/mydriver.h
:internal:
Configuration
=============
.. kernel-doc:: drivers/mydriver/Kconfig
Tables
------
.. flat-table:: Device States
:header-rows: 1
* - State
- Description
* - IDLE
- Device is not processing
* - ACTIVE
- Device is processing data
보안 감사 도구
커널 코드의 보안 취약점을 사전에 발견하기 위한 전용 도구들입니다.
KASAN + Stack Depot
# Stack Depot: 메모리 할당/해제 시 스택 트레이스 저장
scripts/config --enable CONFIG_KASAN
scripts/config --enable CONFIG_STACKDEPOT
scripts/config --enable CONFIG_PAGE_OWNER # 페이지 소유자 추적
# 메모리 누수 감지
scripts/config --enable CONFIG_DEBUG_KMEMLEAK
make -j$(nproc)
# 부팅 후 메모리 누수 확인
echo scan > /sys/kernel/debug/kmemleak
cat /sys/kernel/debug/kmemleak
# 페이지 소유자 분석
echo 1 > /sys/kernel/debug/page_owner
cat /sys/kernel/debug/page_owner | head -100
보안 강화 설정 검증
# 커널 보안 설정 확인 스크립트
# https://github.com/a13xp0p0v/kernel-hardening-checker
pip install kernel-hardening-checker
kernel-hardening-checker -c /boot/config-$(uname -r)
# 주요 보안 CONFIG 옵션
scripts/config --enable CONFIG_STACKPROTECTOR_STRONG
scripts/config --enable CONFIG_FORTIFY_SOURCE
scripts/config --enable CONFIG_STRICT_KERNEL_RWX
scripts/config --enable CONFIG_RANDOMIZE_BASE # KASLR
scripts/config --enable CONFIG_INIT_ON_ALLOC_DEFAULT_ON
scripts/config --enable CONFIG_INIT_ON_FREE_DEFAULT_ON
scripts/config --enable CONFIG_HARDENED_USERCOPY
scripts/config --enable CONFIG_SLAB_FREELIST_HARDENED
# 보안 관련 부팅 파라미터
# lockdown=confidentiality — 커널 잠금 모드
# init_on_alloc=1 — 할당 시 0 초기화
# page_poison=1 — 해제 페이지 독소 주입
# slab_nomerge — SLAB 캐시 병합 금지
커널 크기 분석 도구
임베디드(Embedded) 시스템이나 최적화가 필요한 환경에서는 커널 바이너리 크기를 분석하고 줄이는 것이 중요합니다.
# 커널 바이너리 크기 분석
size vmlinux
# text data bss dec hex filename
# 12345678 2345678 567890 15259246 e8f4ee vmlinux
# 심볼별 크기 정렬 (상위 20개)
nm --size-sort -r vmlinux | head -20
# 섹션별 크기
readelf -S vmlinux | grep -E 'Size|\.text|\.data|\.rodata|\.bss'
# bloat-o-meter: 두 빌드 간 크기 변화 비교
scripts/bloat-o-meter vmlinux.old vmlinux
# add/remove: 5/3 grow/shrink: 12/8 up/down: 1234/-567 (667)
# Function old new delta
# my_new_function - 234 +234
# my_changed_function 100 150 +50
# my_optimized_function 200 150 -50
# 모듈별 크기
find /lib/modules/$(uname -r)/ -name '*.ko' -exec du -sh {} \; | sort -rh | head -20
# CONFIG_CC_OPTIMIZE_FOR_SIZE: 크기 최적화 (-Os)
scripts/config --enable CONFIG_CC_OPTIMIZE_FOR_SIZE
자주 발생하는 문제와 해결
| 문제 | 증상 | 원인 | 해결 |
|---|---|---|---|
| 빌드 실패 | fatal error: openssl/opensslv.h |
개발 헤더 미설치 | apt install libssl-dev |
| 빌드 실패 | BTF: .tmp_vmlinux.btf: pahole not found |
pahole(dwarves) 미설치 | apt install dwarves |
| 빌드 실패 | No rule to make target 'debian/...' |
소스 트리 오염 | make mrproper |
| QEMU 부팅 실패 | Kernel panic - not syncing: No init found |
initramfs 또는 rootfs 없음 | initramfs 생성 또는 -initrd 지정 |
| GDB 연결 실패 | Remote connection closed |
QEMU에 -s 옵션 누락 |
qemu-system-x86_64 -s -S ... |
| GDB 심볼 없음 | No debugging symbols found |
CONFIG_DEBUG_INFO 비활성 | scripts/config --enable CONFIG_DEBUG_INFO |
| 모듈 로드 실패 | version magic mismatch |
모듈과 커널 버전 불일치 | 동일 소스/설정으로 모듈 재빌드 |
| sparse 경고 | incorrect type in argument |
__user/__kernel 포인터 혼동 | copy_from_user()/copy_to_user() 사용 |
| perf 권한 | Error: Access to performance monitoring |
권한 부족 | sysctl kernel.perf_event_paranoid=-1 |
| ftrace 미동작 | tracefs 빈 출력 | debugfs 미마운트 | mount -t debugfs none /sys/kernel/debug |
| checkpatch HTML | non-ASCII characters |
유니코드(Unicode) 문자 포함 | ASCII 문자만 사용 (주석에서 제거) |
| send-email 실패 | 530 Authentication required |
SMTP 인증 설정 오류 | 앱 비밀번호 생성, .gitconfig 확인 |
빌드 환경 진단 한 줄 명령:
# 빌드 도구 버전 일괄 확인
echo "GCC: $(gcc --version | head -1)" && \
echo "Make: $(make --version | head -1)" && \
echo "Binutils: $(ld --version | head -1)" && \
echo "Perl: $(perl --version | head -2 | tail -1)" && \
echo "Python: $(python3 --version)" && \
echo "pahole: $(pahole --version 2>/dev/null || echo 'not installed')"
도구 설치 빠른 참조
| 도구 | Debian/Ubuntu | Fedora/RHEL | 소스 빌드 |
|---|---|---|---|
| GCC | apt install gcc |
dnf install gcc |
- |
| Clang/LLVM | apt install clang lld llvm |
dnf install clang lld llvm |
apt.llvm.org |
| sparse | apt install sparse |
dnf install sparse |
git.kernel.org |
| smatch | - | - | repo.or.cz/smatch.git |
| Coccinelle | apt install coccinelle |
dnf install coccinelle |
coccinelle.lip6.fr |
| pahole | apt install dwarves |
dnf install dwarves |
github.com/acmel/dwarves |
| ccache | apt install ccache |
dnf install ccache |
ccache.dev |
| cscope | apt install cscope |
dnf install cscope |
- |
| GNU Global | apt install global |
dnf install global |
gnu.org/software/global |
| crash | apt install crash |
dnf install crash |
github.com/crash-utility |
| trace-cmd | apt install trace-cmd |
dnf install trace-cmd |
git.kernel.org |
| perf | apt install linux-perf |
dnf install perf |
tools/perf/ (커널 소스) |
| bpftrace | apt install bpftrace |
dnf install bpftrace |
github.com/bpftrace |
| BCC | apt install bpfcc-tools |
dnf install bcc-tools |
github.com/iovisor/bcc |
| b4 | pip install b4 |
pip install b4 |
git.kernel.org/pub/scm/utils/b4 |
| QEMU | apt install qemu-system-x86 |
dnf install qemu-system-x86 |
qemu.org |
| virtme-ng | pip install virtme-ng |
pip install virtme-ng |
github.com/arighi/virtme-ng |
| kdump | apt install kdump-tools |
dnf install kexec-tools |
- |
| KernelShark | apt install kernelshark |
dnf install kernelshark |
git.kernel.org |
참고 자료
- Kernel Development Tools — 커널 개발 도구 공식 문서 (kernel.org)
- Debugging kernel and modules via gdb (kernel.org)
- KGDB/KDB — 커널 내장 디버거 (kernel.org)
- KASAN — Kernel Address Sanitizer 가이드 (kernel.org)
- UBSAN — Undefined Behavior Sanitizer (kernel.org)
- KCOV — 코드 커버리지 도구 (kernel.org)
- KCSAN — Concurrency Sanitizer (kernel.org)
- Sparse — 정적 분석 도구 (kernel.org)
- Coccinelle — 시맨틱 패치 엔진 (kernel.org)
- KUnit — 커널 단위 테스트 프레임워크 (kernel.org)
- checkpatch.pl — 코딩 스타일 검사기 (kernel.org)
- ftrace — Function Tracer 문서 (kernel.org)
- kdump — 커널 크래시 덤프 가이드 (kernel.org)
- perf wiki — 성능 분석 도구 (kernel.org)
- Submitting Patches — 패치 제출 가이드 (kernel.org)
- Linux Kernel Coding Style 공식 규칙 (kernel.org)
- GCC Online Documentation — 컴파일러 레퍼런스 (gcc.gnu.org)
- Clang Documentation — LLVM 기반 컴파일러 (llvm.org)
- ClangBuiltLinux — Clang으로 커널 빌드하기 (clangbuiltlinux.github.io)
- strace(1) — 시스템 콜 추적 매뉴얼 (man7.org)
- ltrace(1) — 라이브러리 호출 추적 매뉴얼 (man7.org)
- Valgrind User Manual — 메모리 오류 검출 (valgrind.org)
- GDB User Manual — GNU 디버거 레퍼런스 (sourceware.org)
- crash utility — 커널 크래시 덤프 분석기 (crash-utility.github.io)
- Smatch — 커널 소스 정적 분석 도구 (sourceforge.net)
- Cppcheck Manual — C/C++ 정적 분석 도구 (sourceforge.io)
- SystemTap Documentation — 동적 트레이싱 (sourceware.org)
- perf Examples — 실전 성능 분석 예제 모음 (brendangregg.com)
관련 문서
개발 도구와 관련된 다른 주제를 더 깊이 이해하고 싶다면 다음 문서를 참고하세요.