[2026] Core Dump 완벽 가이드 | 생성·분석·디버깅 실전 총정리

[2026] Core Dump 완벽 가이드 | 생성·분석·디버깅 실전 총정리

이 글의 핵심

Core Dump 생성 방법, GDB로 분석하는 법, Segmentation Fault 디버깅, 실무 사례까지. ulimit 설정, 심볼 파일, 백트레이스 분석으로 프로덕션 크래시 문제를 해결하는 완벽 가이드.

들어가며: Core Dump가 필요한 이유

프로덕션 환경에서 프로그램이 갑자기 크래시하면 어떻게 디버깅할까요? 재현이 어려운 버그, 간헐적인 Segmentation Fault, 메모리 손상 문제를 해결하려면 Core Dump가 필수입니다. Core Dump의 가치:

  • 크래시 시점의 완전한 메모리 스냅샷
  • 모든 변수 값과 스택 트레이스
  • 재현 없이 사후 분석 가능
  • 프로덕션 환경의 실제 데이터 이 글에서 다룰 내용:
  • Core Dump 생성 설정
  • GDB로 Core Dump 분석
  • 실전 디버깅 시나리오
  • 자동화 및 모니터링

실무에서 마주한 현실

개발을 배울 때는 모든 게 깔끔하고 이론적입니다. 하지만 실무는 다릅니다. 레거시 코드와 씨름하고, 급한 일정에 쫓기고, 예상치 못한 버그와 마주합니다. 이 글에서 다루는 내용도 처음엔 이론으로 배웠지만, 실제 프로젝트에 적용하면서 “아, 이래서 이렇게 설계하는구나” 하고 깨달은 것들입니다. 특히 기억에 남는 건 첫 프로젝트에서 겪은 시행착오입니다. 책에서 배운 대로 했는데 왜 안 되는지 몰라 며칠을 헤맸죠. 결국 선배 개발자의 코드 리뷰를 통해 문제를 발견했고, 그 과정에서 많은 걸 배웠습니다. 이 글에서는 이론뿐 아니라 실전에서 마주칠 수 있는 함정들과 해결 방법을 함께 다루겠습니다.

목차

  1. Core Dump 기본 개념
  2. Core Dump 생성 설정
  3. GDB로 Core Dump 분석
  4. 실전 디버깅 시나리오
  5. 자동화 및 수집
  6. 프로덕션 환경 설정
  7. 고급 분석 기법
  8. 문제 해결

1. Core Dump 기본 개념

Core Dump란?

Core Dump는 프로그램이 비정상 종료(크래시)될 때 메모리의 내용을 파일로 저장한 것입니다. 아래 코드는 mermaid를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

flowchart TB
    Program[프로그램 실행] --> Crash["크래시 발생\nSIGSEGV, SIGABRT 등"]
    
    Crash --> Kernel[커널이 신호 수신]
    
    Kernel --> Check{Core Dump\n활성화?}
    
    Check -->|Yes| Dump["메모리 덤프 생성\ncore.12345"]
    Check -->|No| Exit[프로그램 종료]
    
    Dump --> File["Core Dump 파일\n- 스택\n- 힙\n- 레지스터\n- 변수 값"]
    
    File --> Debug[GDB로 분석]

Core Dump에 포함된 정보

다음은 code를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

1. 스택 메모리 (Stack)
   - 함수 호출 스택
   - 지역 변수
   - 함수 인자
2. 힙 메모리 (Heap)
   - 동적 할당된 메모리
   - malloc/new로 생성된 객체
3. 레지스터 상태
   - PC (Program Counter)
   - SP (Stack Pointer)
   - 범용 레지스터
4. 전역 변수
   - 정적 변수
   - 전역 객체
5. 공유 라이브러리 매핑
   - 로드된 .so 파일 목록
   - 메모리 주소 매핑

크래시를 일으키는 신호

아래 코드는 c를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// Core Dump를 생성하는 신호들
SIGQUIT    // Quit (Ctrl+\)
SIGILL     // Illegal Instruction
SIGABRT    // Abort (assert 실패)
SIGFPE     // Floating Point Exception (0으로 나누기)
SIGSEGV    // Segmentation Fault (잘못된 메모리 접근)
SIGBUS     // Bus Error (정렬 오류)
SIGTRAP    // Trace/Breakpoint Trap
SIGSYS     // Bad System Call

2. Core Dump 생성 설정

ulimit 설정

다음은 bash를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 현재 Core Dump 크기 제한 확인
ulimit -c
# 0 → Core Dump 비활성화
# unlimited → 제한 없음
# Core Dump 활성화 (현재 세션)
ulimit -c unlimited
# 영구 설정 (모든 사용자)
echo "* soft core unlimited" | sudo tee -a /etc/security/limits.conf
echo "* hard core unlimited" | sudo tee -a /etc/security/limits.conf
# 특정 사용자만
echo "myuser soft core unlimited" | sudo tee -a /etc/security/limits.conf
# systemd 서비스의 경우
# /etc/systemd/system/myapp.service
[Service]
LimitCORE=infinity

Core Dump 저장 위치 설정

다음은 bash를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 현재 설정 확인
cat /proc/sys/kernel/core_pattern
# 기본값: core (현재 디렉토리에 'core' 파일 생성)
# 커스텀 패턴 설정
sudo sysctl -w kernel.core_pattern=/var/crash/core.%e.%p.%t
# 영구 설정
echo "kernel.core_pattern=/var/crash/core.%e.%p.%t" | sudo tee -a /etc/sysctl.conf
# 패턴 변수:
# %e - 실행 파일 이름
# %p - PID
# %t - 타임스탬프 (Unix time)
# %s - 신호 번호
# %u - UID
# %g - GID
# %h - 호스트명
# 예시: core.myapp.12345.1234567890

systemd-coredump 사용 (권장)

다음은 bash를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# systemd-coredump 설치 (Ubuntu)
sudo apt install systemd-coredump
# 설정
sudo nano /etc/systemd/coredump.conf
[Coredump]
Storage=external
Compress=yes
ProcessSizeMax=2G
ExternalSizeMax=2G
MaxUse=10G
# Core Dump 저장 위치
# /var/lib/systemd/coredump/
# Core Dump 목록 확인
coredumpctl list
# 특정 Core Dump 정보
coredumpctl info <PID>
# Core Dump 추출
coredumpctl dump <PID> -o core.dump
# GDB로 바로 분석
coredumpctl debug <PID>

3. GDB로 Core Dump 분석

기본 분석 흐름

다음은 bash를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 1. 디버그 심볼과 함께 컴파일
g++ -g -O0 myapp.cpp -o myapp
# 2. Core Dump 생성되도록 설정
ulimit -c unlimited
# 3. 프로그램 실행 (크래시 발생)
./myapp
# Segmentation fault (core dumped)
# 4. GDB로 Core Dump 열기
gdb ./myapp core.12345
# 또는 systemd-coredump 사용
coredumpctl debug 12345

GDB 기본 명령어

다음은 gdb를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# Core Dump 로드 후
# 1. 백트레이스 (스택 트레이스)
(gdb) bt
#0  0x00005555555551a9 in crash_function () at myapp.cpp:10
#1  0x00005555555551c8 in main () at myapp.cpp:15
# 상세 백트레이스
(gdb) bt full
#0  0x00005555555551a9 in crash_function () at myapp.cpp:10
        ptr = 0x0
        value = 42
#1  0x00005555555551c8 in main () at myapp.cpp:15
        argc = 1
        argv = 0x7fffffffe0a8
# 2. 특정 프레임으로 이동
(gdb) frame 0
(gdb) frame 1
# 3. 소스 코드 확인
(gdb) list
5       void crash_function() {
6           int* ptr = nullptr;
7           int value = 42;
8           
9           // Segmentation Fault!
10          *ptr = value;
11      }
# 4. 변수 값 확인
(gdb) print ptr
$1 = (int *) 0x0
(gdb) print value
$2 = 42
# 5. 모든 지역 변수
(gdb) info locals
ptr = 0x0
value = 42
# 6. 레지스터 상태
(gdb) info registers
rax            0x0                 0
rbx            0x555555557d60      93824992247136
rsp            0x7fffffffddd0      0x7fffffffddd0
rip            0x5555555551a9      0x5555555551a9 <crash_function()+15>
# 7. 메모리 내용 확인
(gdb) x/10x $rsp
0x7fffffffddd0: 0xffffddf0      0x00007fff      0x555551c8      0x00005555
# 8. 스레드 정보
(gdb) info threads
  Id   Target Id         Frame
* 1    Thread 0x7ffff7fc1740 (LWP 12345) crash_function () at myapp.cpp:10
  2    Thread 0x7ffff77c0700 (LWP 12346) 0x00007ffff7bc8e2d in poll ()
# 9. 특정 스레드로 전환
(gdb) thread 2
(gdb) bt

실전 예제 1: Null Pointer Dereference

아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// crash_null.cpp
#include <iostream>
void process_data(int* data) {
    std::cout << "Processing: " << *data << std::endl;  // 크래시!
}
int main() {
    int* ptr = nullptr;
    process_data(ptr);
    return 0;
}

다음은 bash를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 컴파일 (디버그 심볼 포함)
g++ -g -O0 crash_null.cpp -o crash_null
# 실행
./crash_null
# Segmentation fault (core dumped)
# GDB 분석
gdb ./crash_null core
(gdb) bt
#0  0x00005555555551b2 in process_data (data=0x0) at crash_null.cpp:4
#1  0x00005555555551e1 in main () at crash_null.cpp:9
(gdb) frame 0
(gdb) print data
$1 = (int *) 0x0
(gdb) list
1       #include <iostream>
2
3       void process_data(int* data) {
4           std::cout << "Processing: " << *data << std::endl;  // 여기서 크래시!
5       }
# 원인: data가 nullptr
# 해결: nullptr 체크 추가

실전 예제 2: Buffer Overflow

아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// crash_overflow.cpp
#include <cstring>
void copy_string(const char* src) {
    char buffer[10];
    strcpy(buffer, src);  // 버퍼 오버플로우!
    
    printf("Copied: %s\n", buffer);
}
int main() {
    copy_string("This is a very long string that will overflow");
    return 0;
}

다음은 bash를 활용한 상세한 구현 코드입니다. 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 컴파일
g++ -g -O0 -fno-stack-protector crash_overflow.cpp -o crash_overflow
# 실행
./crash_overflow
# *** stack smashing detected ***: terminated
# Aborted (core dumped)
# GDB 분석
gdb ./crash_overflow core
(gdb) bt
#0  0x00007ffff7a42387 in raise () from /lib/x86_64-linux-gnu/libc.so.6
#1  0x00007ffff7a43a78 in abort () from /lib/x86_64-linux-gnu/libc.so.6
#2  0x00007ffff7a851a6 in __libc_message () from /lib/x86_64-linux-gnu/libc.so.6
#3  0x00007ffff7b27d5c in __fortify_fail () from /lib/x86_64-linux-gnu/libc.so.6
#4  0x00007ffff7b27d20 in __stack_chk_fail () from /lib/x86_64-linux-gnu/libc.so.6
#5  0x000055555555521e in copy_string (src=0x555555556004 "This is a very long string...") at crash_overflow.cpp:8
#6  0x0000555555555239 in main () at crash_overflow.cpp:12
(gdb) frame 5
(gdb) print buffer
$1 = "This is a \000ery long string that will overflow"
# 버퍼 크기 10바이트를 초과함
(gdb) print src
$2 = 0x555555556004 "This is a very long string that will overflow"
# 해결: strncpy 사용 또는 std::string 사용

4. 실전 디버깅 시나리오

시나리오 1: Double Free

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// crash_double_free.cpp
#include <cstdlib>
#include <iostream>
int main() {
    int* ptr = new int(42);
    
    std::cout << "Value: " << *ptr << std::endl;
    
    delete ptr;
    
    // Double free!
    delete ptr;
    
    return 0;
}

다음은 bash를 활용한 상세한 구현 코드입니다. 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 컴파일
g++ -g -O0 crash_double_free.cpp -o crash_double_free
# 실행
./crash_double_free
# Value: 42
# free(): double free detected in tcache 2
# Aborted (core dumped)
# GDB 분석
gdb ./crash_double_free core
(gdb) bt
#0  0x00007ffff7a42387 in raise () from /lib/x86_64-linux-gnu/libc.so.6
#1  0x00007ffff7a43a78 in abort () from /lib/x86_64-linux-gnu/libc.so.6
#2  0x00007ffff7a8524a in __libc_message () from /lib/x86_64-linux-gnu/libc.so.6
#3  0x00007ffff7a8c89c in malloc_printerr () from /lib/x86_64-linux-gnu/libc.so.6
#4  0x00007ffff7a8e5fc in _int_free () from /lib/x86_64-linux-gnu/libc.so.6
#5  0x0000555555555234 in main () at crash_double_free.cpp:12
(gdb) frame 5
(gdb) list
7       int* ptr = new int(42);
8       
9       std::cout << "Value: " << *ptr << std::endl;
10      
11      delete ptr;
12      
13      // Double free!
14      delete ptr;  // 여기서 크래시!
(gdb) print ptr
$1 = (int *) 0x555555559eb0  # 이미 해제된 주소
# 해결: delete 후 ptr = nullptr 설정

시나리오 2: Use After Free

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// crash_use_after_free.cpp
#include <iostream>
#include <vector>
class MyClass {
public:
    int value;
    MyClass(int v) : value(v) {}
    void print() { std::cout << "Value: " << value << std::endl; }
};
int main() {
    MyClass* obj = new MyClass(42);
    
    obj->print();
    
    delete obj;
    
    // Use after free!
    obj->print();  // 크래시 또는 이상한 값
    
    return 0;
}

다음은 bash를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# AddressSanitizer로 컴파일 (권장)
g++ -g -O0 -fsanitize=address crash_use_after_free.cpp -o crash_use_after_free
# 실행
./crash_use_after_free
# Value: 42
# =================================================================
# ==12345==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000010
# READ of size 4 at 0x602000000010 thread T0
#     #0 0x555555555289 in MyClass::print() crash_use_after_free.cpp:9
#     #1 0x5555555552f8 in main crash_use_after_free.cpp:18
# Core Dump 분석 (ASan 없이 컴파일한 경우)
gdb ./crash_use_after_free core
(gdb) bt
#0  0x0000555555555289 in MyClass::print (this=0x555555559eb0) at crash_use_after_free.cpp:9
#1  0x00005555555552f8 in main () at crash_use_after_free.cpp:18
(gdb) frame 0
(gdb) print this
$1 = (MyClass * const) 0x555555559eb0
(gdb) print *this
$2 = {value = 0}  # 또는 쓰레기 값
(gdb) print this->value
$3 = 0  # 메모리가 이미 해제됨
# 해결: delete 후 obj = nullptr 설정

시나리오 3: Stack Overflow

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// crash_stack_overflow.cpp
#include <iostream>
void recursive_function(int depth) {
    char buffer[10000];  // 큰 지역 변수
    
    std::cout << "Depth: " << depth << std::endl;
    
    // 무한 재귀
    recursive_function(depth + 1);
}
int main() {
    recursive_function(0);
    return 0;
}

다음은 bash를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 컴파일
g++ -g -O0 crash_stack_overflow.cpp -o crash_stack_overflow
# 실행
./crash_stack_overflow
# Depth: 0
# Depth: 1
# ...
# Depth: 850
# Segmentation fault (core dumped)
# GDB 분석
gdb ./crash_stack_overflow core
(gdb) bt
#0  0x0000555555555189 in recursive_function (depth=851) at crash_stack_overflow.cpp:4
#1  0x00005555555551c4 in recursive_function (depth=850) at crash_stack_overflow.cpp:9
#2  0x00005555555551c4 in recursive_function (depth=849) at crash_stack_overflow.cpp:9
...
#850 0x00005555555551c4 in recursive_function (depth=1) at crash_stack_overflow.cpp:9
#851 0x00005555555551c4 in recursive_function (depth=0) at crash_stack_overflow.cpp:9
#852 0x00005555555551d9 in main () at crash_stack_overflow.cpp:13
# 스택 프레임 개수 확인
(gdb) bt | wc -l
853
# 각 프레임의 buffer 크기
(gdb) print sizeof(buffer)
$1 = 10000
# 총 스택 사용량: 853 × 10,000 ≈ 8.5MB
# 스택 크기 제한 초과
# 스택 크기 확인
ulimit -s
# 8192 (8MB)
# 해결: 재귀 깊이 제한 또는 힙 사용

시나리오 4: 멀티스레드 크래시

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// crash_thread.cpp
#include <iostream>
#include <thread>
#include <vector>
int shared_counter = 0;
void increment() {
    for (int i = 0; i < 100000; i++) {
        shared_counter++;  // Race condition!
    }
}
int main() {
    std::vector<std::thread> threads;
    
    for (int i = 0; i < 10; i++) {
        threads.emplace_back(increment);
    }
    
    for (auto& t : threads) {
        t.join();
    }
    
    std::cout << "Counter: " << shared_counter << std::endl;
    
    // 메모리 손상으로 인한 크래시 가능
    return 0;
}

다음은 bash를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# ThreadSanitizer로 컴파일
g++ -g -O0 -fsanitize=thread crash_thread.cpp -o crash_thread -pthread
# 실행
./crash_thread
# ==================
# WARNING: ThreadSanitizer: data race (pid=12345)
#   Write of size 4 at 0x555555558010 by thread T2:
#     #0 increment() crash_thread.cpp:8
#   Previous write of size 4 at 0x555555558010 by thread T1:
#     #0 increment() crash_thread.cpp:8
# Core Dump 분석 (TSan 없이)
gdb ./crash_thread core
(gdb) info threads
  Id   Target Id         Frame
* 1    Thread 0x7ffff7fc1740 (LWP 12345) 0x00007ffff7bc8e2d in poll ()
  2    Thread 0x7ffff77c0700 (LWP 12346) increment () at crash_thread.cpp:8
  3    Thread 0x7ffff6fbf700 (LWP 12347) increment () at crash_thread.cpp:8
# 각 스레드의 백트레이스 확인
(gdb) thread apply all bt
Thread 1 (Thread 0x7ffff7fc1740 (LWP 12345)):
#0  0x00007ffff7bc8e2d in poll () from /lib/x86_64-linux-gnu/libc.so.6
#1  0x0000555555555456 in main () at crash_thread.cpp:22
Thread 2 (Thread 0x7ffff77c0700 (LWP 12346)):
#0  increment () at crash_thread.cpp:8
#1  0x00007ffff7e8e6df in execute_native_thread_routine ()
# 해결: std::mutex 사용

5. 자동화 및 수집

Core Dump 자동 수집 스크립트

다음은 bash를 활용한 상세한 구현 코드입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#!/bin/bash
# /usr/local/bin/core-collector.sh
CORE_DIR="/var/crash"
MAX_CORES=50
NOTIFY_EMAIL="admin@example.com"
# Core Dump 정보 추출
EXECUTABLE="$1"
PID="$2"
TIMESTAMP="$3"
SIGNAL="$4"
CORE_FILE="$CORE_DIR/core.$EXECUTABLE.$PID.$TIMESTAMP"
# 디렉토리 생성
mkdir -p "$CORE_DIR"
# Core Dump 저장 (stdin으로 전달됨)
cat > "$CORE_FILE"
# 압축
gzip "$CORE_FILE"
CORE_FILE="$CORE_FILE.gz"
# 메타데이터 저장
cat > "$CORE_FILE.info" <<EOF
Executable: $EXECUTABLE
PID: $PID
Timestamp: $(date -d @$TIMESTAMP)
Signal: $SIGNAL
Hostname: $(hostname)
User: $(id -un)
Kernel: $(uname -r)
EOF
# 백트레이스 추출 (디버그 심볼 있는 경우)
if [ -f "/usr/bin/$EXECUTABLE" ]; then
    gdb -batch -ex "bt" -ex "quit" "/usr/bin/$EXECUTABLE" <(gunzip -c "$CORE_FILE") \
        > "$CORE_FILE.backtrace" 2>&1
fi
# 오래된 Core Dump 정리
find "$CORE_DIR" -name "core.*" -mtime +7 -delete
# 개수 제한
CORE_COUNT=$(find "$CORE_DIR" -name "core.*.gz" | wc -l)
if [ $CORE_COUNT -gt $MAX_CORES ]; then
    find "$CORE_DIR" -name "core.*.gz" -type f -printf '%T+ %p\n' | \
        sort | head -n $(($CORE_COUNT - $MAX_CORES)) | \
        cut -d' ' -f2- | xargs rm -f
fi
# 알림 전송
echo "Core dump collected: $CORE_FILE" | \
    mail -s "Core Dump Alert: $EXECUTABLE" "$NOTIFY_EMAIL"
# 로그
logger -t core-collector "Core dump: $EXECUTABLE (PID: $PID, Signal: $SIGNAL)"

아래 코드는 bash를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

# 스크립트 등록
sudo chmod +x /usr/local/bin/core-collector.sh
# core_pattern 설정
sudo sysctl -w kernel.core_pattern="|/usr/local/bin/core-collector.sh %e %p %t %s"

자동 분석 스크립트

다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#!/usr/bin/env python3
"""
Core Dump 자동 분석 도구
"""
import subprocess
import sys
import re
import json
from pathlib import Path
class CoreDumpAnalyzer:
    def __init__(self, executable, core_file):
        self.executable = executable
        self.core_file = core_file
        self.analysis = {}
    
    def analyze(self):
        """Core Dump 분석"""
        print(f"🔍 Analyzing {self.core_file}...")
        
        # 1. 백트레이스
        self.analysis['backtrace'] = self.get_backtrace()
        
        # 2. 크래시 위치
        self.analysis['crash_location'] = self.get_crash_location()
        
        # 3. 스레드 정보
        self.analysis['threads'] = self.get_threads()
        
        # 4. 레지스터 상태
        self.analysis['registers'] = self.get_registers()
        
        # 5. 메모리 맵
        self.analysis['memory_map'] = self.get_memory_map()
        
        return self.analysis
    
    def get_backtrace(self):
        """백트레이스 추출"""
        cmd = [
            'gdb', '-batch',
            '-ex', 'bt',
            '-ex', 'quit',
            self.executable,
            self.core_file
        ]
        
        result = subprocess.run(cmd, capture_output=True, text=True)
        return result.stdout
    
    def get_crash_location(self):
        """크래시 위치 파싱"""
        bt = self.get_backtrace()
        
        # #0 프레임 추출
        match = re.search(r'#0\s+(.+?) at (.+?):(\d+)', bt)
        if match:
            return {
                'function': match.group(1),
                'file': match.group(2),
                'line': int(match.group(3))
            }
        
        return None
    
    def get_threads(self):
        """스레드 정보"""
        cmd = [
            'gdb', '-batch',
            '-ex', 'info threads',
            '-ex', 'quit',
            self.executable,
            self.core_file
        ]
        
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        threads = []
        for line in result.stdout.split('\n'):
            if 'Thread' in line:
                threads.append(line.strip())
        
        return threads
    
    def get_registers(self):
        """레지스터 상태"""
        cmd = [
            'gdb', '-batch',
            '-ex', 'info registers',
            '-ex', 'quit',
            self.executable,
            self.core_file
        ]
        
        result = subprocess.run(cmd, capture_output=True, text=True)
        return result.stdout
    
    def get_memory_map(self):
        """메모리 맵"""
        cmd = [
            'gdb', '-batch',
            '-ex', 'info proc mappings',
            '-ex', 'quit',
            self.executable,
            self.core_file
        ]
        
        result = subprocess.run(cmd, capture_output=True, text=True)
        return result.stdout
    
    def generate_report(self):
        """분석 리포트 생성"""
        report = []
        report.append("=" * 70)
        report.append("CORE DUMP ANALYSIS REPORT")
        report.append("=" * 70)
        
        # 크래시 위치
        if self.analysis.get('crash_location'):
            loc = self.analysis['crash_location']
            report.append(f"\n🔴 CRASH LOCATION:")
            report.append(f"   Function: {loc['function']}")
            report.append(f"   File: {loc['file']}:{loc['line']}")
        
        # 백트레이스
        report.append(f"\n📚 BACKTRACE:")
        report.append(self.analysis['backtrace'])
        
        # 스레드
        if self.analysis.get('threads'):
            report.append(f"\n🧵 THREADS ({len(self.analysis['threads'])}):")
            for thread in self.analysis['threads']:
                report.append(f"   {thread}")
        
        return '\n'.join(report)
# 사용
if __name__ == '__main__':
    if len(sys.argv) < 3:
        print("Usage: analyze_core.py <executable> <core_file>")
        sys.exit(1)
    
    analyzer = CoreDumpAnalyzer(sys.argv[1], sys.argv[2])
    analyzer.analyze()
    
    report = analyzer.generate_report()
    print(report)
    
    # JSON으로 저장
    with open('analysis.json', 'w') as f:
        json.dump(analyzer.analysis, f, indent=2)
    
    print("\n✅ Analysis saved to analysis.json")

6. 프로덕션 환경 설정

systemd 서비스 설정

다음은 ini를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# /etc/systemd/system/myapp.service
[Unit]
Description=My Application
After=network.target
[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
# Core Dump 설정
LimitCORE=infinity
LimitNOFILE=65536
# 환경 변수
Environment="NODE_ENV=production"
# 실행
ExecStart=/opt/myapp/bin/myapp
# 재시작 정책
Restart=on-failure
RestartSec=5s
# 로깅
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target

Docker 컨테이너에서 Core Dump

다음은 dockerfile를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# Dockerfile
FROM ubuntu:22.04
# Core Dump 활성화
RUN echo "* soft core unlimited" >> /etc/security/limits.conf && \
    echo "* hard core unlimited" >> /etc/security/limits.conf
# 디버그 도구 설치
RUN apt-get update && apt-get install -y gdb
# 애플리케이션
COPY myapp /usr/local/bin/
RUN chmod +x /usr/local/bin/myapp
CMD [myapp]

다음은 bash를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# Docker 실행 (Core Dump 활성화)
docker run -d \
  --name myapp \
  --ulimit core=-1 \
  -v /var/crash:/var/crash \
  myapp:latest
# Core Dump 확인
docker exec myapp ls -lh /var/crash/
# Core Dump 추출
docker cp myapp:/var/crash/core.12345 ./
# 컨테이너 내에서 GDB 실행
docker exec -it myapp gdb /usr/local/bin/myapp /var/crash/core.12345

Kubernetes에서 Core Dump

다음은 yaml를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: myapp
spec:
  containers:
  - name: myapp
    image: myapp:latest
    
    # Core Dump 설정
    securityContext:
      capabilities:
        add:
        - SYS_PTRACE
    
    # 볼륨 마운트
    volumeMounts:
    - name: core-dumps
      mountPath: /var/crash
    
    # 리소스 제한
    resources:
      limits:
        memory: "2Gi"
        cpu: "1"
  
  # 호스트 경로 마운트
  volumes:
  - name: core-dumps
    hostPath:
      path: /var/crash
      type: DirectoryOrCreate
  
  # Init 컨테이너로 ulimit 설정
  initContainers:
  - name: setup-core
    image: busybox
    command: ['sh', '-c', 'ulimit -c unlimited']
    securityContext:
      privileged: true

7. 고급 분석 기법

메모리 덤프 분석

다음은 gdb를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# GDB에서 메모리 내용 확인
# 1. 특정 주소의 메모리 (16진수)
(gdb) x/10x 0x7fffffffddd0
0x7fffffffddd0: 0xffffddf0  0x00007fff  0x555551c8  0x00005555
0x7fffffffdde0: 0x00000000  0x00000001  0xffffe0a8  0x00007fff
# 2. 문자열로 해석
(gdb) x/s 0x555555556004
0x555555556004: "Hello, World!"
# 3. 명령어 (어셈블리)
(gdb) x/10i $rip
=> 0x5555555551a9 <crash_function+15>:  mov    %eax,(%rdx)
   0x5555555551ab <crash_function+17>:  nop
   0x5555555551ac <crash_function+18>:  pop    %rbp
# 4. 배열 내용
(gdb) print array[0]@10
$1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
# 5. 구조체 멤버
(gdb) print *my_struct
$2 = {
  id = 42,
  name = 0x555555559eb0 "Test",
  value = 3.14
}
# 6. 포인터 체인 따라가기
(gdb) print *node
$3 = {data = 10, next = 0x555555559ec0}
(gdb) print *node->next
$4 = {data = 20, next = 0x555555559ed0}
(gdb) print *node->next->next
$5 = {data = 30, next = 0x0}

조건부 분석

다음은 gdb를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 특정 조건의 스택 프레임만 출력
(gdb) bt full
# 출력이 너무 많으면
# Python 스크립트로 필터링
(gdb) python
import gdb
frame = gdb.newest_frame()
while frame:
    func = frame.name()
    if func and 'process' in func:
        print(f"Frame: {func}")
        # 지역 변수 출력
        block = frame.block()
        for symbol in block:
            if symbol.is_variable:
                print(f"  {symbol.name} = {symbol.value(frame)}")
    frame = frame.older()
end

Core Dump 비교

다음은 bash를 활용한 상세한 구현 코드입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 두 개의 Core Dump 비교 (재현 가능한 크래시)
#!/bin/bash
CORE1="core.12345"
CORE2="core.12346"
EXECUTABLE="./myapp"
# 백트레이스 추출
gdb -batch -ex "bt" -ex "quit" "$EXECUTABLE" "$CORE1" > bt1.txt
gdb -batch -ex "bt" -ex "quit" "$EXECUTABLE" "$CORE2" > bt2.txt
# 차이점 확인
diff -u bt1.txt bt2.txt
# 같은 위치에서 크래시하는지 확인
if diff -q bt1.txt bt2.txt > /dev/null; then
    echo "✅ Same crash location (reproducible)"
else
    echo "⚠️  Different crash locations"
fi

8. 문제 해결

Core Dump가 생성되지 않을 때

다음은 bash를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 1. ulimit 확인
ulimit -c
# 0이면 비활성화됨
# 활성화
ulimit -c unlimited
# 2. core_pattern 확인
cat /proc/sys/kernel/core_pattern
# |/usr/share/apport/apport %p %s %c %d %P (Ubuntu)
# core (기본값)
# 3. 디스크 공간 확인
df -h /var/crash
# 4. 권한 확인
ls -ld /var/crash
# drwxrwxrwt 2 root root 4096 ...
# 5. suid 프로그램 (보안상 Core Dump 안 됨)
ls -l myapp
# -rwsr-xr-x (s 플래그 있으면 suid)
# suid 제거
sudo chmod u-s myapp
# 6. 프로세스가 chroot 환경인 경우
# Core Dump가 chroot 내부에 생성됨
# 7. SELinux/AppArmor 확인
sudo getenforce  # SELinux
sudo aa-status   # AppArmor

Core Dump가 너무 클 때

다음은 bash를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# Core Dump 크기 제한
ulimit -c 1048576  # 1GB
# 또는 /etc/security/limits.conf
* soft core 1048576
* hard core 1048576
# 특정 메모리 영역만 덤프 (Linux)
# /proc/PID/coredump_filter
# 비트 플래그:
# bit 0: anonymous private memory
# bit 1: anonymous shared memory
# bit 2: file-backed private memory
# bit 3: file-backed shared memory
# bit 4: ELF header pages
# bit 5: private huge pages
# bit 6: shared huge pages
# 예: 스택과 힙만 덤프
echo 0x33 > /proc/self/coredump_filter

심볼 파일 없을 때

다음은 bash를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 디버그 심볼 분리 (배포 시)
# 1. 디버그 심볼과 함께 컴파일
g++ -g myapp.cpp -o myapp
# 2. 심볼 분리
objcopy --only-keep-debug myapp myapp.debug
strip --strip-debug --strip-unneeded myapp
# 3. 디버그 링크 추가
objcopy --add-gnu-debuglink=myapp.debug myapp
# 배포: myapp (작은 크기)
# 보관: myapp.debug (디버그 심볼)
# GDB 사용 시 자동으로 myapp.debug 로드
gdb ./myapp core
# 또는 수동 로드
(gdb) symbol-file myapp.debug

실전 도구

coredumpctl (systemd)

다음은 bash를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# Core Dump 목록
coredumpctl list
# 최근 Core Dump
coredumpctl list --since today
# 특정 프로그램
coredumpctl list myapp
# 상세 정보
coredumpctl info 12345
# Core Dump 추출
coredumpctl dump 12345 -o core.dump
# GDB로 바로 분석
coredumpctl debug 12345
# 삭제
coredumpctl remove 12345

crash (커널 크래시 분석)

아래 코드는 bash를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 커널 크래시 덤프 분석 (kdump)
sudo apt install crash kexec-tools
# vmcore 분석
crash /usr/lib/debug/boot/vmlinux-$(uname -r) /var/crash/vmcore
# crash 명령어
crash> bt              # 백트레이스
crash> ps              # 프로세스 목록
crash> log             # 커널 로그
crash> files          # 열린 파일
crash> vm             # 가상 메모리

gcore (실행 중인 프로세스 덤프)

다음은 bash를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 실행 중인 프로세스의 Core Dump 생성
# (프로세스 중단 없이)
# PID 확인
ps aux | grep myapp
# Core Dump 생성
gcore 12345
# Saved corefile core.12345
# 또는 GDB로
gdb -p 12345
(gdb) generate-core-file
(gdb) detach
(gdb) quit
# 프로세스는 계속 실행됨

고급 GDB 기법

GDB 스크립트

다음은 gdb를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# analyze.gdb
set pagination off
set logging file analysis.txt
set logging on
echo \n=== BACKTRACE ===\n
bt full
echo \n=== THREADS ===\n
info threads
thread apply all bt
echo \n=== REGISTERS ===\n
info registers
echo \n=== LOCALS ===\n
info locals
echo \n=== SHARED LIBRARIES ===\n
info sharedlibrary
set logging off
quit

아래 코드는 bash를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

# 스크립트 실행
gdb -batch -x analyze.gdb ./myapp core.12345
# 결과 확인
cat analysis.txt

GDB Python API

다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며, 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# gdb_script.py
import gdb
class AnalyzeCommand(gdb.Command):
    """Analyze core dump"""
    
    def __init__(self):
        super(AnalyzeCommand, self).__init__("analyze", gdb.COMMAND_USER)
    
    def invoke(self, arg, from_tty):
        # 현재 프레임
        frame = gdb.selected_frame()
        
        print(f"Function: {frame.name()}")
        print(f"PC: 0x{frame.pc():x}")
        
        # 지역 변수
        block = frame.block()
        print("\nLocal variables:")
        for symbol in block:
            if symbol.is_variable:
                try:
                    value = symbol.value(frame)
                    print(f"  {symbol.name} = {value}")
                except:
                    pass
        
        # 백트레이스
        print("\nBacktrace:")
        i = 0
        f = gdb.newest_frame()
        while f:
            print(f"  #{i} {f.name()} at {f.find_sal().symtab}:{f.find_sal().line}")
            f = f.older()
            i += 1
AnalyzeCommand()

다음은 간단한 bash 코드 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

# GDB에서 Python 스크립트 로드
gdb ./myapp core.12345
(gdb) source gdb_script.py
(gdb) analyze

메모리 손상 디버깅

Heap Corruption 분석

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// crash_heap_corruption.cpp
#include <iostream>
#include <cstring>
struct Node {
    int data;
    Node* next;
};
int main() {
    Node* head = new Node{10, nullptr};
    Node* second = new Node{20, nullptr};
    head->next = second;
    
    // 버퍼 오버플로우로 메모리 손상
    char* buffer = new char[10];
    strcpy(buffer, "This is a very long string");  // 오버플로우!
    
    // 나중에 크래시 (손상된 메모리 접근)
    std::cout << head->next->data << std::endl;
    
    delete[] buffer;
    delete second;
    delete head;
    
    return 0;
}

다음은 bash를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# Valgrind로 메모리 오류 감지
valgrind --leak-check=full --track-origins=yes ./crash_heap_corruption
# ==12345== Invalid write of size 1
# ==12345==    at 0x4C2FB7F: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
# ==12345==    by 0x108A2B: main (crash_heap_corruption.cpp:16)
# AddressSanitizer로 컴파일
g++ -g -O0 -fsanitize=address crash_heap_corruption.cpp -o crash_heap_corruption
./crash_heap_corruption
# =================================================================
# ==12345==ERROR: AddressSanitizer: heap-buffer-overflow
# WRITE of size 28 at 0x602000000010 thread T0
#     #0 0x7ffff7b3a1b0 in strcpy
#     #1 0x555555555289 in main crash_heap_corruption.cpp:16

GDB로 힙 상태 확인

아래 코드는 gdb를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# malloc 디버깅 (glibc)
(gdb) set environment MALLOC_CHECK_ 2
# 힙 청크 확인
(gdb) print *(mchunkptr)0x555555559eb0
# 힙 통계
(gdb) call malloc_stats()
# 메모리 맵 확인
(gdb) info proc mappings

일상 비유로 이해하기: 메모리를 아파트 건물로 생각해보세요. 스택은 엘리베이터 같아서 빠르지만 공간이 제한적입니다. 힙은 창고처럼 넓지만 물건을 찾는 데 시간이 걸립니다. 포인터는 “3층 302호”처럼 주소를 가리키는 메모지라고 보면 됩니다.

자동화된 크래시 리포팅

Sentry 통합

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// sentry_example.cpp
#include <sentry.h>
#include <signal.h>
void signal_handler(int sig) {
    // Sentry에 크래시 리포트
    sentry_capture_event(sentry_value_new_message_event(
        SENTRY_LEVEL_FATAL,
        "crash",
        "Application crashed"
    ));
    
    // Core Dump 생성
    signal(sig, SIG_DFL);
    raise(sig);
}
int main() {
    // Sentry 초기화
    sentry_options_t* options = sentry_options_new();
    sentry_options_set_dsn(options, "https://your-dsn@sentry.io/project");
    sentry_options_set_release(options, "myapp@1.0.0");
    sentry_init(options);
    
    // 신호 핸들러 등록
    signal(SIGSEGV, signal_handler);
    signal(SIGABRT, signal_handler);
    
    // 애플리케이션 로직
    // ...
    
    sentry_close();
    return 0;
}

Breakpad (Google)

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// breakpad_example.cpp
#include "client/linux/handler/exception_handler.h"
static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor,
                         void* context,
                         bool succeeded) {
    printf("✅ Minidump created: %s\n", descriptor.path());
    
    // 크래시 정보를 서버로 전송
    // upload_crash_report(descriptor.path());
    
    return succeeded;
}
int main() {
    google_breakpad::MinidumpDescriptor descriptor("/tmp/crashes");
    google_breakpad::ExceptionHandler eh(
        descriptor,
        nullptr,
        dumpCallback,
        nullptr,
        true,
        -1
    );
    
    // 애플리케이션 로직
    int* ptr = nullptr;
    *ptr = 42;  // 크래시
    
    return 0;
}

프로덕션 베스트 프랙티스

Core Dump 수집 파이프라인

아래 코드는 mermaid를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

flowchart TB
    Crash[애플리케이션 크래시] --> Generate[Core Dump 생성]
    
    Generate --> Collect["수집 스크립트\n- 압축\n- 메타데이터"]
    
    Collect --> Upload["중앙 저장소 업로드\nS3, NFS 등"]
    
    Upload --> Notify["알림 전송\nSlack, Email"]
    
    Upload --> Analyze["자동 분석\n- 백트레이스\n- 크래시 위치"]
    
    Analyze --> Report["리포트 생성\nJira, GitHub Issue"]
    
    Analyze --> Dedupe["중복 제거\n같은 크래시 그룹화"]

설정 템플릿

다음은 bash를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# /etc/sysctl.d/50-coredump.conf
kernel.core_pattern=|/usr/local/bin/core-handler %e %p %t %s
kernel.core_pipe_limit=0
fs.suid_dumpable=2
# /etc/security/limits.d/core.conf
* soft core unlimited
* hard core unlimited
# /usr/local/bin/core-handler
#!/bin/bash
EXECUTABLE="$1"
PID="$2"
TIMESTAMP="$3"
SIGNAL="$4"
CORE_DIR="/var/crash"
CORE_FILE="$CORE_DIR/core.$EXECUTABLE.$PID.$TIMESTAMP.gz"
mkdir -p "$CORE_DIR"
gzip > "$CORE_FILE"
# S3 업로드
aws s3 cp "$CORE_FILE" "s3://my-crashes/$EXECUTABLE/"
# Slack 알림
curl -X POST https://hooks.slack.com/services/YOUR/WEBHOOK/URL \
  -H 'Content-Type: application/json' \
  -d "{\"text\":\"🔴 Crash: $EXECUTABLE (PID: $PID)\"}"

모니터링 대시보드

다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#!/usr/bin/env python3
"""
Core Dump 모니터링 대시보드
"""
import os
import time
from pathlib import Path
from collections import defaultdict
import json
class CoreDumpMonitor:
    def __init__(self, crash_dir='/var/crash'):
        self.crash_dir = Path(crash_dir)
        self.stats = defaultdict(int)
    
    def scan(self):
        """Core Dump 파일 스캔"""
        cores = list(self.crash_dir.glob('core.*'))
        
        for core in cores:
            parts = core.name.split('.')
            if len(parts) >= 2:
                executable = parts[1]
                self.stats[executable] += 1
        
        return self.stats
    
    def generate_report(self):
        """리포트 생성"""
        stats = self.scan()
        
        print("=" * 60)
        print("CORE DUMP STATISTICS")
        print("=" * 60)
        
        total = sum(stats.values())
        print(f"\nTotal crashes: {total}")
        
        print("\nBy application:")
        for app, count in sorted(stats.items(), key=lambda x: x[1], reverse=True):
            bar = '█' * min(count, 50)
            print(f"  {app:20s} {count:5d} {bar}")
        
        # JSON 저장
        with open('/var/www/html/crash-stats.json', 'w') as f:
            json.dump({
                'total': total,
                'by_app': dict(stats),
                'timestamp': time.time()
            }, f)
    
    def cleanup_old(self, days=7):
        """오래된 Core Dump 삭제"""
        cutoff = time.time() - (days * 86400)
        
        for core in self.crash_dir.glob('core.*'):
            if core.stat().st_mtime < cutoff:
                print(f"🗑️  Deleting old core: {core.name}")
                core.unlink()
# Cron으로 주기적 실행
# 0 * * * * /usr/local/bin/monitor-cores.py

언어별 Core Dump 생성

C/C++

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 에러 처리를 통해 안정성을 확보합니다, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <signal.h>
#include <unistd.h>
// 강제로 Core Dump 생성
void force_core_dump() {
    abort();  // SIGABRT 발생
    // 또는
    raise(SIGSEGV);
    // 또는
    kill(getpid(), SIGQUIT);
}
// 신호 핸들러로 정보 추가
void signal_handler(int sig) {
    fprintf(stderr, "Caught signal %d\n", sig);
    
    // 백트레이스 출력
    void* callstack[128];
    int frames = backtrace(callstack, 128);
    char** symbols = backtrace_symbols(callstack, frames);
    
    for (int i = 0; i < frames; i++) {
        fprintf(stderr, "%s\n", symbols[i]);
    }
    
    free(symbols);
    
    // Core Dump 생성
    signal(sig, SIG_DFL);
    raise(sig);
}
int main() {
    signal(SIGSEGV, signal_handler);
    signal(SIGABRT, signal_handler);
    
    // 애플리케이션 로직
    
    return 0;
}

Python

다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다, 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

import faulthandler
import sys
# Core Dump 활성화
faulthandler.enable()
# 파일로 출력
with open('crash.log', 'w') as f:
    faulthandler.enable(file=f)
# 강제 크래시 (테스트용)
def crash():
    import ctypes
    ctypes.string_at(0)  # Segmentation Fault
try:
    crash()
except:
    pass
# 또는 신호 등록
import signal
faulthandler.register(signal.SIGUSR1)
# SIGUSR1 전송 시 백트레이스 출력
# kill -USR1 <PID>

Go

다음은 go를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

package main
import (
    "os"
    "os/signal"
    "runtime/pprof"
    "syscall"
)
func main() {
    // SIGQUIT 시 고루틴 덤프
    sigChan := make(chan os.Signal, 1)
    signal.Notify(sigChan, syscall.SIGQUIT)
    
    go func() {
        <-sigChan
        
        // 고루틴 스택 덤프
        pprof.Lookup("goroutine").WriteTo(os.Stderr, 1)
        
        // 힙 프로파일
        f, _ := os.Create("heap.prof")
        pprof.WriteHeapProfile(f)
        f.Close()
        
        os.Exit(1)
    }()
    
    // 애플리케이션 로직
    select {}
}
// SIGQUIT 전송
// kill -QUIT <PID>

성능 영향 최소화

Core Dump 생성 시 성능

아래 코드는 code를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

Core Dump 생성 시간:
- 1GB 메모리: 약 1-2초
- 10GB 메모리: 약 10-20초
프로세스는 생성 중 중단됨 (응답 불가)

선택적 Core Dump

다음은 c를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <sys/prctl.h>
// Core Dump 비활성화
prctl(PR_SET_DUMPABLE, 0);
// 특정 조건에서만 활성화
if (is_debug_mode) {
    prctl(PR_SET_DUMPABLE, 1);
}
// 민감한 정보 처리 전 비활성화
void process_sensitive_data() {
    prctl(PR_SET_DUMPABLE, 0);
    
    // 민감한 작업
    
    prctl(PR_SET_DUMPABLE, 1);
}

압축 및 필터링

다음은 bash를 활용한 상세한 구현 코드입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# Core Dump 즉시 압축
kernel.core_pattern=|gzip > /var/crash/core.%e.%p.%t.gz
# 특정 프로그램만 수집
kernel.core_pattern=|/usr/local/bin/selective-core-handler %e %p
# selective-core-handler
#!/bin/bash
EXECUTABLE="$1"
PID="$2"
# 특정 프로그램만 저장
if [[ "$EXECUTABLE" == "myapp" || "$EXECUTABLE" == "critical-service" ]]; then
    cat > "/var/crash/core.$EXECUTABLE.$PID"
else
    # 무시
    cat > /dev/null
fi

정리

Core Dump 체크리스트

개발 환경

  • ulimit -c unlimited 설정
  • -g 플래그로 컴파일
  • 최적화 비활성화 (-O0)
  • AddressSanitizer 사용 (-fsanitize=address)
  • Valgrind로 메모리 검사

프로덕션 환경

  • /etc/security/limits.conf에 core 제한 설정
  • kernel.core_pattern 설정
  • systemd-coredump 설치 및 설정
  • 디스크 공간 모니터링
  • 자동 수집 스크립트 구성
  • 알림 시스템 연동

분석

  • GDB 설치 및 사용법 숙지
  • 디버그 심볼 보관
  • 백트레이스 자동 추출
  • 크래시 패턴 분석
  • 중복 제거 및 그룹화

GDB 명령어 치트시트

다음은 bash를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 기본
gdb <executable> <core>     # Core Dump 로드
bt                          # 백트레이스
bt full                     # 상세 백트레이스
frame <N>                   # N번 프레임으로 이동
list                        # 소스 코드
# 변수
print <var>                 # 변수 값
print *<ptr>                # 포인터가 가리키는 값
print <array>[0]@10         # 배열 10개 요소
info locals                 # 모든 지역 변수
info args                   # 함수 인자
# 메모리
x/10x <addr>                # 메모리 (16진수)
x/10s <addr>                # 문자열
x/10i <addr>                # 명령어 (어셈블리)
# 스레드
info threads                # 스레드 목록
thread <N>                  # N번 스레드로 전환
thread apply all bt         # 모든 스레드 백트레이스
# 레지스터
info registers              # 모든 레지스터
print $rip                  # 특정 레지스터
# 기타
info sharedlibrary          # 로드된 라이브러리
info proc mappings          # 메모리 맵

일반적인 크래시 원인

다음은 mermaid를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

flowchart TB
    Crash[프로그램 크래시]
    
    Null["Null Pointer\nDereference"]
    Overflow[Buffer Overflow]
    UseAfter[Use After Free]
    DoubleFree[Double Free]
    StackOver[Stack Overflow]
    Race[Race Condition]
    Assert[Assert Failure]
    
    Crash --> Null
    Crash --> Overflow
    Crash --> UseAfter
    Crash --> DoubleFree
    Crash --> StackOver
    Crash --> Race
    Crash --> Assert
    
    Null --> Fix1[nullptr 체크]
    Overflow --> Fix2[경계 검사]
    UseAfter --> Fix3[스마트 포인터]
    DoubleFree --> Fix4[delete 후 nullptr]
    StackOver --> Fix5[재귀 제한]
    Race --> Fix6[뮤텍스]
    Assert --> Fix7[조건 검증]

디버깅 전략

다음은 code를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

1. 재현 가능한 크래시
   → GDB로 직접 디버깅
   → 중단점 설정
   → 단계별 실행
2. 재현 불가능한 크래시
   → Core Dump 분석
   → 로그 확인
   → 패턴 찾기
3. 간헐적 크래시
   → AddressSanitizer
   → Valgrind
   → 스트레스 테스트
4. 멀티스레드 크래시
   → ThreadSanitizer
   → 모든 스레드 백트레이스
   → Race condition 확인
5. 메모리 손상
   → Valgrind
   → AddressSanitizer
   → 힙 프로파일링

참고 자료

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3