Post

gdb로 C 메모리 구조 파악 및 core dump 분석하기

gdb로 C 메모리 구조 파악 및 core dump 분석하기

gdb로 C 메모리 구조 분석하기 — 실습 중심 튜토리얼

C 언어를 사용하다 보면 어느 순간 마주하게 되는 Segmentation Fault, 버퍼 오버플로우, 메모리 누수.
이럴 때 진짜 무기를 꺼내야죠 — 바로 gdb입니다.

이 글에서는 gdb로 Stack / Heap / 전역 변수 등을 직접 추적하며 시각적으로 메모리를 분석하는 방법을 단계별로 정리합니다.


🧪 분석 대상 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
#include <stdlib.h>

int global_var = 100;

void print_addrs() {
    int local_var = 42;
    int* heap_var = malloc(sizeof(int));
    *heap_var = 777;

    printf("[main] global_var addr : %p\n", (void*)&global_var);
    printf("[main] local_var addr  : %p\n", (void*)&local_var);
    printf("[main] heap_var addr   : %p\n", (void*)heap_var);

    free(heap_var);
}

int main() {
    print_addrs();
    return 0;
}

⚙️ 컴파일

1
gcc -g memtest.c -o memtest

-g 옵션은 디버깅 심볼 정보를 포함시켜 gdb에서 소스 코드 수준 분석이 가능하게 해줍니다.


🧩 gdb로 분석 시작

1
gdb ./memtest

1. 브레이크포인트 설정

(gdb) break print_addrs

2. 실행

(gdb) run

3. 변수 주소 보기

(gdb) print &global_var
(gdb) print &local_var
(gdb) print heap_var

🔍 메모리 위치로 영역 구분하기

변수예상 영역
global_varData 또는 BSS (전역)
local_varStack
heap_varHeap

예시 출력:

1
2
3
$1 = (int *) 0x404024        ← global_var
$2 = (int *) 0x7fffffffe53c  ← local_var
$3 = (int *) 0x555555757260  ← heap_var

🧠 주소 비교로 이해하기

  • global_var고정된 낮은 주소 (0x400000번대) → 실행 파일 내부 (data 영역)
  • local_var높은 주소 (0x7ffffff…) → 스택
  • heap_var는 중간 주소 (보통 0x55… 또는 0x60…대) → 힙

💡 메모리 안의 값도 확인 가능

(gdb) x/4x &global_var     # 4개 정수(hex)로 보기
(gdb) x/4d &global_var     # 4개 정수(decimal)

또는

(gdb) x/1i main            # main 함수의 첫 어셈블리 명령

⚠️ 실수 예제: 스택 변수 포인터 리턴

1
2
3
4
int* bad_func() {
    int x = 999;
    return &x;  // 위험!
}
(gdb) break bad_func
(gdb) run
(gdb) next
(gdb) print &x

→ 함수 종료 후 포인터를 쓰면, 이미 해제된 stack 주소 접근이기 때문에 segfault 발생!


✅ 정리

gdb 명령설명
break func함수에 브레이크포인트 설정
run프로그램 실행
next or step다음 줄 실행
print var변수 값 출력
x/4x addr메모리 주소 직접 확인
bt백트레이스(호출 스택 출력)

gdb에서 core dump 분석하기 — 크래시 원인 추적 실습

프로그램이 갑자기 종료되고 “Segmentation fault (core dumped)”라는 메시지를 본 적 있으신가요?
이때 생성된 core dump 파일은 프로그램이 죽던 그 순간의 메모리 상태를 저장한 스냅샷입니다.

이 글에서는 gdb를 사용하여 core dump를 분석하고 버그 원인을 추적하는 방법을 알려드립니다.


🔧 core dump 생성 설정

리눅스에서는 기본적으로 core dump 생성을 제한하고 있습니다.
아래 명령으로 core 파일이 생성되도록 설정하세요.

1
2
ulimit -c unlimited          # 현재 쉘에서 core dump 크기 제한 해제
echo "/tmp/core.%e.%p" | sudo tee /proc/sys/kernel/core_pattern
  • %e: 실행 파일 이름
  • %p: 프로세스 ID

core 파일은 보통 /tmp/ 또는 현재 디렉토리에 저장됩니다.


🧪 실습용 크래시 코드

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>

void crash() {
    int *p = NULL;
    *p = 42;  // Null pointer dereference
}

int main() {
    crash();
    return 0;
}

⚙️ 컴파일

1
gcc -g crash.c -o crash

-g 옵션은 디버깅 정보를 포함시켜 gdb에서 분석 가능하게 해줍니다.


💥 실행 후 core 생성 확인

1
2
3
4
5
./crash
# Segmentation fault (core dumped)

ls /tmp/core.*
# → core.crash.12345

🔍 gdb로 core 파일 열기

1
gdb ./crash /tmp/core.crash.12345

이제 gdb가 프로그램이 죽은 지점의 메모리 상태를 불러와 분석할 수 있습니다.


🔎 주요 gdb 명령

(gdb) bt              # 백트레이스 (호출 스택)
(gdb) info locals     # 지역 변수 상태 확인
(gdb) frame 0         # 현재 프레임으로 이동
(gdb) list            # 죽은 줄 근처 소스 보기
(gdb) print *p        # 원인 변수 출력

✅ 분석 예시 결과

1
2
3
4
5
6
Program terminated with signal SIGSEGV, Segmentation fault.
#0  crash () at crash.c:5
5       *p = 42;
(gdb) bt
#0  crash () at crash.c:5
#1  0x0000000000401136 in main () at crash.c:9

💡 핵심 요약

  • core 파일은 죽던 그 순간의 메모리와 레지스터 정보를 저장한 디버깅 자료입니다.
  • 반드시 -g 옵션을 주고 컴파일해야 gdb에서 분석 가능합니다.
  • bt, info locals, print 등을 통해 문제 코드 위치 및 상태를 파악할 수 있습니다.

This post is licensed under CC BY 4.0 by the author.

© standspring. Some rights reserved.

Using the Chirpy theme for Jekyll.