학습 자료 글/컴퓨터시스템

컴퓨터시스템 기초 4. 디버거는 실행을 보는 창이다

cedis 2026. 3. 31. 16:21

[컴퓨터 시스템] 4. 디버거는 실행을 보는 창이다

디버깅을 막연히 '에러를 잡는 감'으로 배우면 시간이 오래 걸립니다. 시스템 공부에서는 특히 프로그램이 지금 어느 상태에 있는지 직접 보는 태도가 중요하고, 그래서 디버거는 선택 도구가 아니라 학습 도구에 가깝습니다.

이번 글에서는 GDB와 Valgrind를 기능 목록으로 소개하기보다, 어떤 질문에 답하게 해주는지 중심으로 정리합니다. 포인터와 메모리 감각이 아직 약하다면 3편을 먼저 보고 오는 편이 좋습니다.

먼저 짚고 갈 용어
breakpoint: 프로그램 실행을 특정 지점에서 멈추게 하는 표시
backtrace: 현재 함수 호출이 어떤 경로로 쌓였는지 보여주는 정보
segmentation fault: 허용되지 않은 메모리에 접근할 때 나는 대표적 오류
이번 글에서 다루는 것
  • 디버깅을 감이 아니라 상태 관찰로 보는 관점
  • GDB가 특히 강한 질문 세 가지
  • 작은 버그 예제로 breakpoint, step, print, backtrace 읽기
  • Valgrind가 메모리 문제에서 왜 강한지
  • 실전에서 GDB와 Valgrind를 어떤 순서로 쓰면 좋은지
한눈에 보는 흐름
1
디버깅을 감이 아니라 상태 관찰로 보는 관점
2
GDB가 특히 강한 질문 세 가지
3
작은 버그 예제로 breakpoint, step, print, backtrace 읽기
4
Valgrind가 메모리 문제에서 왜 강한지

1. 디버깅은 정답 찍기가 아니라 상태를 좁혀 가는 과정이다

오류가 났을 때 코드를 한참 바라보다가 감으로 수정하는 습관은 초반엔 자주 생깁니다. 하지만 시스템 수준 문제는 메모리 상태, 함수 호출 순서, 실제 값이 어떻게 변했는지까지 봐야 하므로 눈으로 관찰하는 도구가 훨씬 중요합니다.

그래서 디버깅의 첫 전환점은 '왜 틀렸지?'보다 '지금 상태가 내가 예상한 상태와 어디서 어긋났지?'로 질문을 바꾸는 데 있습니다.

디버깅할 때 먼저 던질 질문
어디서 멈췄는가, 지금 값은 무엇인가, 이 지점까지 어떤 호출 흐름으로 왔는가. 이 세 질문이 기본 뼈대입니다.

2. GDB는 세 가지 질문에 특히 강하다

GDB의 명령은 많지만, 초반에는 세 가지 질문으로 묶어 이해하면 훨씬 쉽습니다. 지금 어디까지 왔는지, 지금 값이 무엇인지, 여기까지 어떤 흐름으로 왔는지를 묻는 도구라고 생각하면 됩니다.

그림으로 먼저 보기
지금 어디에 있는가
대표 명령 감각: break, run, next, step
왜 중요한가: 문제가 처음 드러나는 지점을 찾는다
지금 값이 무엇인가
대표 명령 감각: print, display
왜 중요한가: 예상과 실제 값 차이를 확인한다
어떤 호출 흐름으로 왔는가
대표 명령 감각: backtrace
왜 중요한가: 잘못된 경로를 타고 온 지점을 좁힌다
질문대표 명령 감각왜 중요한가
지금 어디에 있는가break, run, next, step문제가 처음 드러나는 지점을 찾는다
지금 값이 무엇인가print, display예상과 실제 값 차이를 확인한다
어떤 호출 흐름으로 왔는가backtrace잘못된 경로를 타고 온 지점을 좁힌다

3. 아주 작은 버그 예제로 흐름을 따라가 보자

실전 디버깅은 커다란 프로그램에서도 결국 작은 관찰의 반복입니다. 짧은 예제로 먼저 감각을 잡아두면 이후 복잡한 코드에서도 같은 질문을 반복할 수 있습니다.

과정 그림
1
반복문 시작 줄에 breakpoint를 건다.
2
i와 sum 값을 보며 한 단계씩 진행한다.
3
i가 3이 되는 순간에도 루프가 한 번 더 돈다는 사실을 확인한다.
4
arr[3] 접근이 범위를 넘는다는 점을 눈으로 확인한다.
C
#include <stdio.h>

int main(void) {
    int arr[3] = {1, 2, 3};
    int i;
    int sum = 0;

    for (i = 0; i <= 3; i++) {
        sum += arr[i];
    }

    printf("%d\n", sum);
    return 0;
}
이 예제의 핵심
코드를 한눈에 이해하는 것보다, 실제 실행 중 변수 값과 반복 조건이 어떻게 어긋나는지 확인하는 태도가 더 중요합니다.

4. Valgrind는 메모리 문제를 다른 방식으로 드러낸다

GDB가 현재 상태를 직접 들여다보는 창이라면, Valgrind는 메모리 사용 패턴을 감시하는 검사기처럼 볼 수 있습니다. 특히 해제 후 접근, 초기화되지 않은 값 사용, 누수 같은 문제에서 강합니다.

그림으로 먼저 보기
GDB
강한 질문: 지금 어디서 어떤 값으로 실행 중인가
대표 상황: 크래시 지점 좁히기, 호출 흐름 추적
Valgrind
강한 질문: 메모리를 잘못 쓰고 있지 않은가
대표 상황: 누수, 해제 후 접근, 초기화 안 된 값 추적
도구강한 질문대표 상황
GDB지금 어디서 어떤 값으로 실행 중인가크래시 지점 좁히기, 호출 흐름 추적
Valgrind메모리를 잘못 쓰고 있지 않은가누수, 해제 후 접근, 초기화 안 된 값 추적

5. 실제로는 두 도구를 같이 쓰는 편이 자연스럽다

세그폴트가 났다면 먼저 GDB로 어디서 멈췄는지 봅니다. 그런데 그 원인이 이미 사라진 메모리를 가리킨 포인터라면, Valgrind가 더 먼저 힌트를 줄 수도 있습니다. 도구를 경쟁 관계로 보기보다 질문 종류에 따라 나눠 쓰는 편이 좋습니다.

과정 그림
1
프로그램이 어디서 죽는지 GDB로 확인한다.
2
메모리 사용이 의심되면 Valgrind로 잘못된 접근이나 누수를 확인한다.
3
원인을 찾으면 다시 GDB로 돌아가 값 흐름과 호출 경로를 좁힌다.

6. 디버깅을 공부 습관으로 만들려면

디버깅은 에러가 났을 때만 하는 특별 행사처럼 느껴지기 쉽습니다. 하지만 작은 예제라도 breakpoint를 걸어 보고, 값이 바뀌는 순간을 직접 확인하는 습관을 들이면 뒤의 시스템 주제도 훨씬 잘 보입니다.

특히 포인터, 배열, 스택 프레임처럼 눈에 안 보이는 개념은 디버거를 켜야 비로소 공부거리가 됩니다.

지금 남겨둘 실전 원칙
추측보다 관찰을 먼저 두고, 코드 읽기와 실행 상태 읽기를 번갈아 하는 습관을 만드는 것이 디버깅 실력을 가장 빨리 올립니다.

7. 직접 해볼 문제: 어떤 도구부터 켤지 정해 보자

이 문제는 도구 이름 암기보다 질문 종류를 분류하는 연습입니다.

미니 문제
프로그램이 갑자기 종료되는 경우와 메모리 누수가 의심되는 경우를 나눠, GDB와 Valgrind 중 무엇부터 켜는 편이 더 자연스러운지 이유와 함께 적어 보세요.

이번 글에서 기억할 것

디버깅은 감으로 고치는 일이 아니라 상태와 흐름을 좁혀 가는 과정이다.
GDB는 위치, 값, 호출 흐름이라는 세 질문에 특히 강하다.
Valgrind는 메모리 문제를 다른 각도에서 잡아내므로 GDB와 경쟁 관계가 아니라 보완 관계다.

스스로 점검

디버깅할 때 먼저 볼 세 질문을 말할 수 있는가
GDB와 Valgrind가 각각 어떤 종류의 문제에 더 강한지 구분할 수 있는가
배열 범위 초과나 포인터 문제를 코드 읽기만이 아니라 실행 상태 읽기로 좁혀 갈 수 있는가

다음 글 예고

다음 글에서는 데이터가 결국 비트로 저장된다는 사실을 바탕으로, 정수와 signed/unsigned, overflow가 왜 헷갈리는지 정리합니다.

한 줄 정리
디버거는 버그를 잡는 비밀 무기가 아니라, 실행 중인 프로그램 상태를 눈으로 보게 해 주는 학습 창에 가깝습니다.