본문 바로가기
컴퓨터 관련/Linux || Unix

리눅스(Linux) gdb로 디버깅해보자 [2] - 브레이크 포인트(break point), 디버깅 시작

by _BlankSpace 2019. 7. 14.

지난 포스팅에 이어서, 리눅스에서 gdb로 디버깅을 해보는 두 번째 포스팅입니다.

이전 글에서는 gdb를 시작하고, 종료하는 방법과 소스를 출력하는 방법을 정리하였습니다. 관련 내용이 궁금하신 분은 아래 글을 참고해주세요.

[프로그래밍/Linux || Unix] - 리눅스(Linux) gdb로 디버깅해보자 [1] (시작 및 종료, 소스 출력)

 

이번 포스팅에서는 gdb를 이용할 때, 브레이크 포인트를 잡는 법과 디버깅을 시작하는 방법을 설명하려고 합니다. 사실, 디버깅에서는 브레이크 포인트를 제대로 잡아야 디버깅도 쉽다고 할 수 있습니다.

 

그러므로, gdb로 디버깅하는 것에 있어서 가장 중요한 부분이 아닐까라는 생각이 듭니다.

 

 

그럼, 바로 설명으로 넘어가도록 하겠습니다.

 

포스팅에 사용할 예제

이번 포스팅에서는 코드의 내용을 보면서 진행해야 하는 부분이 많기 때문에 간단한 프로그램을 예제로 준비하였습니다. 아래 예제로 gdb 디버깅을 할 것이므로 참고해주세요.

 

#include <stdio.h>
#define MAX_STUDENTS 4

typedef struct Student Student;

struct Student {
    char name[20];
    int age;
    int score;
};

int printStudant(Student* s) {
    printf("----- Student Status -----\n");
    printf("Name = %s\n", s->name);
    printf("Age = %d\n", s->age);
    printf("score = %d\n", s->score);
}

char getStudentGrade(int score) {
    if (score >= 90) return 'A';
    else if (score >= 80) return 'B';
    else if (score >= 70) return 'C';
    else if (score >= 60) return 'D';
    else return 'F';
}

int main(void) {
    Student s[3] = {{"John", 15, 80}, {"Eric", 15, 65}, {"Chris", 15, 50}};

    for (int i = 0; i < MAX_STUDENTS; i++) {
        printStudant(&s[i]);
        
        char grade = getStudentGrade(s[i].score);
        if (grade == 'A' || grade == 'B') {
            printf("Good Grade\n");
        }
        else {
            printf("Bad Grade\n");
        }
    }
    return 0;
}

 

간단하게 학생의 정보를 구조체로 받고, 내용을 출력하는 프로그램입니다. 브레이크 포인트로 잡는 연습에 사용할 수 있을만한 예제라 생각하므로 참고 부탁 드립니다.

 

 

브레이크 포인트(Break Point)를 설정해보자.

일단, 브레이크 포인트가 무엇인 지에 대해서 먼저 정리해봐야 할 것 같습니다.

 

브레이크 포인트(Break Point)는 말 그대로, 멈추려는 지점을 설정하는 것입니다. 우리가 프로그램에 이상이 있다고 가정헤 보겠습니다. 그럼, 의심이 되는 부분을 보기 위해서는 그 전 단계에서 멈춘 후에 한 단계식 살펴봐야할 것입니다.

 

이럴 경우에 전 단계에 브레이크 포인트를 지정하여, 프로그램을 멈춘 후에 하나 하나 살펴보는 것입니다. 물론 이것이 디버깅이라고도 부를 수 있습니다.

 

위의 프로그램 예제를 돌려보면, 문제가 발생하는 것을 보실 수 있습니다. 마지막 Student의 내용이 제대로 들어가 있지 않죠? 값을 할당하지 않았는데, 해당 부분에 접근하여 그렇습니다.

 

 

사실, 프로그램을 실행할 때, 잘못된 메모리에 접근하면 세그멘테이션 오류(Segmentation fault)가 발생할 것입니다. 저의 경우는 vmware로 실행하다 보니, 할당되지 않은 메모리에 접근해도 따로 오류 메시지는 안나오는 것 같습니다.

 

하지만, 프로그램의 Student는 3개를 생성하였는데, 4번째 학생의 정보를 접근하고 있습니다. 이러면, 보통 세그멘테이션 오류가 발생하게 됩니다.

 

사실, 이처럼 눈에 보이게 오류가 발생한다면, 디버깅이 굉장히 쉽습니다. 하지만, 프로그램이 방대하여 어디서부터 잘못된 것인지 모를 경우에는 상위 클래스까지 계속해서 올라가며 디버깅을 해야 한다는 것입니다.

이럴 경우에도 printf로 일일히 찍는다면, 퇴근은 절대 못할 것입니다. 그러므로, 우리는 break point로 의심스러운 부분을 잡아내야 할 것입니다.

 

먼저, 브레이크 포인트는 아래 표와 같이 사용할 수 있습니다.

명령어

실행 내용

b func

func 함수 시작 부분에서 브레이크 포인트를 설정함.

b 20

20 번 줄에 브레이크 포인트를 설정함.

b test.c:func

test.c 파일의 func 함수에 브레이크 포인트를 설정함. (오버라이딩 함수면 둘다 설정됨)

b test.c:20

test.c 파일의 20 번 줄에 브레이크 포인트를 설정함. (오버라이딩 함수면 둘다 설정됨)

b +5

현재 줄에서 2줄 아래에 브레이크 포인트를 설정함.

b -5

현재 줄에서 2줄 위에 브레이크 포인트를 설정함.

 

그럼, 예제에 브레이크 포인트를 사용해보도록 하겠습니다. 각 줄마다 주석을 달았으니, 궁금하신 부분이 있으시면 댓글 남겨주세요.

 

(gdb) b printStudant // printStutant 함수에 브레이크 포인트 지정.
Breakpoint 1 at 0x4005e2: file GDBTest1.c, line 13.
(gdb) b getStudentGrade // getStudentGrade 함수에 브레이크 포인트 지정.
Breakpoint 2 at 0x40063c: file GDBTest1.c, line 20.
(gdb) r // 디버깅 시작.
Starting program: /home/bs/WorkSpace/practice/CPP/test 

Breakpoint 1, printStudant (s=0x7fffffffde30) at GDBTest1.c:13
13	    printf("----- Student Status -----\n");
(gdb) b +5 // 현재 줄에서 5줄 아래에 브레이크 포인트 지정.
Note: breakpoint 2 also set at pc 0x40063c.
Breakpoint 3 at 0x40063c: file GDBTest1.c, line 18.
(gdb) c // 다음 브레이크 포인트까지 프로그램 진행.
Continuing.
----- Student Status -----
Name = John
Age = 15
score = 80

Breakpoint 2, getStudentGrade (score=80) at GDBTest1.c:20
20	    if (score >= 90) return 'A';
(gdb) b -5 // 현재 줄에서 5줄 위에 브레이크 포인트 지정.
Breakpoint 4 at 0x400602: file GDBTest1.c, line 15.
(gdb) c // 다음 브레이크 포인트까지 프로그램 진행.
Continuing.
Good Grade

Breakpoint 1, printStudant (s=0x7fffffffde4c) at GDBTest1.c:13
13	    printf("----- Student Status -----\n");

 

위의 예제를 바탕으로, 직접 gdb를 실행하셔서 브레이크 포인트 명령어를 입력해보시면 이해가 더욱 빠르실 것입니다.

한 가지 팁으로, 지금까지 설정한 브레이크 포인트가 궁금하시면 info b 명령어를 입력해주세요.

 

(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000004005e2 in printStudant at GDBTest1.c:13
	breakpoint already hit 2 times
2       breakpoint     keep y   0x000000000040063c in getStudentGrade at GDBTest1.c:20
	breakpoint already hit 1 time
3       breakpoint     keep y   0x000000000040063c in getStudentGrade at GDBTest1.c:18
	breakpoint already hit 1 time
4       breakpoint     keep y   0x0000000000400602 in printStudant at GDBTest1.c:15

 

 

설정한 브레이크 포인트(Break Point)를 제거해보자.

이제, 브레이크 포인트를 설정해봤으니, 제거하는 방법도 알아야겠죠.

 

먼저, 브레이크 포인트를 제거하는 명령어는 아래 표와 같습니다.

명령어

실행 내용

cl func

func 함수의 시작 부분에 브레이크 포인트를 제거함.

cl 20

20번 줄의 브레이크 포인트를 제거함.

cl test.c:func

test.c func 함수에 지정한 브레이크 포인트를 제거함.

cl test.c:20

test.c 20번 줄에 지정한 브레이크 포인트를 제거함.

d

모든 브레이크 포인트를 제거함.

d 1

브레이크 포인트 1번을 제거함.

 

아래 처럼 브레이크 포인트를 제거할 수 있습니다.

 

(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000004005e2 in printStudant at GDBTest1.c:13
	breakpoint already hit 2 times
2       breakpoint     keep y   0x000000000040063c in getStudentGrade at GDBTest1.c:20
	breakpoint already hit 1 time
3       breakpoint     keep y   0x000000000040063c in getStudentGrade at GDBTest1.c:18
	breakpoint already hit 1 time
4       breakpoint     keep y   0x0000000000400602 in printStudant at GDBTest1.c:15
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000004005e2 in printStudant at GDBTest1.c:13
	breakpoint already hit 2 times
2       breakpoint     keep y   0x000000000040063c in getStudentGrade at GDBTest1.c:20
	breakpoint already hit 1 time
3       breakpoint     keep y   0x000000000040063c in getStudentGrade at GDBTest1.c:18
	breakpoint already hit 1 time
4       breakpoint     keep y   0x0000000000400602 in printStudant at GDBTest1.c:15
(gdb) cl printStudant
Deleted breakpoint 1 
(gdb) info b
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x000000000040063c in getStudentGrade at GDBTest1.c:20
	breakpoint already hit 1 time
3       breakpoint     keep y   0x000000000040063c in getStudentGrade at GDBTest1.c:18
	breakpoint already hit 1 time
4       breakpoint     keep y   0x0000000000400602 in printStudant at GDBTest1.c:15
(gdb) cl 15
Deleted breakpoint 4 
(gdb) info b
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x000000000040063c in getStudentGrade at GDBTest1.c:20
	breakpoint already hit 1 time
3       breakpoint     keep y   0x000000000040063c in getStudentGrade at GDBTest1.c:18
	breakpoint already hit 1 time
(gdb) d 3
(gdb) info b
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x000000000040063c in getStudentGrade at GDBTest1.c:20
	breakpoint already hit 1 time
(gdb) d
Delete all breakpoints? (y or n) y
(gdb) 

 

이상으로 이번 포스팅에서 브레이크 포인트에 대한 설명을 마치겠습니다. 브레이크 포인트는 디버깅의 꽃이라고도 할 수 있기 때문에 꼭 숙지하셨으면 좋겠습니다.

 

잘못된 내용이 있다면 댓글 남겨주세요.

 

저의 글이 도움이 되었다면 공감 버튼 한번 씩 눌러주세요 :)

 

댓글