웹사이트 검색

gdb를 사용하여 Linux에서 C 프로그램을 디버깅하는 방법


이 페이지에서

  1. GDB 디버거 기본 사항\n
  2. GDB 사용 예
  3. 결론

코더의 경험과 관계없이 개발하는 모든 소프트웨어에 버그가 완전히 없을 수는 없습니다. 따라서 버그를 식별하고 수정하는 것은 소프트웨어 개발 주기에서 가장 중요한 작업 중 하나입니다. 버그를 식별하는 방법(테스트, 코드 자체 검토 등)에는 여러 가지 방법이 있지만 문제가 있는 위치를 정확히 이해하여 쉽게 수정할 수 있도록 도와주는 전용 소프트웨어(디버거라고 함)가 있습니다.

C/C++ 프로그래머이거나 Fortran 및 Modula-2 프로그래밍 언어를 사용하여 소프트웨어를 개발하는 경우 버그 및 기타 문제에 대해 코드를 쉽게 디버깅할 수 있는 GDB라는 훌륭한 디버거가 있다는 사실에 기뻐할 것입니다. 이 기사에서는 GDB가 제공하는 몇 가지 유용한 기능/옵션을 포함하여 GDB의 기본 사항에 대해 설명합니다.

하지만 계속 진행하기 전에 이 문서에 제시된 모든 지침과 예제는 Ubuntu 14.04LTS에서 테스트되었음을 언급할 가치가 있습니다. 튜토리얼에 사용된 예제 코드는 C 언어로 작성되었습니다. 우리가 사용한 명령줄 셸은 bash(버전 4.3.11)입니다. 우리가 사용한 GDB 버전은 7.7.1입니다.

GDB 디버거 기본 사항

일반 용어로 GDB를 사용하면 프로그램이 실행되는 동안 프로그램 내부를 엿볼 수 있으므로 문제가 정확히 어디에 있는지 식별하는 데 도움이 됩니다. 다음 섹션에서 작업 예제를 통해 GDB 디버거의 사용법에 대해 논의하지만 그 전에 나중에 도움이 될 몇 가지 기본 사항에 대해 논의하십시오.

첫째, GDB와 같은 디버거를 성공적으로 사용하려면 컴파일러가 디버거에 필요한 디버깅 정보도 생성하는 방식으로 프로그램을 컴파일해야 합니다. 예를 들어, 이 튜토리얼의 뒷부분에서 예제 C 프로그램을 컴파일하는 데 잘 사용되는 gcc 컴파일러의 경우 코드를 컴파일하는 동안 -g 명령줄 옵션을 사용해야 합니다.

gcc 컴파일러 매뉴얼 페이지에서 이 명령줄 옵션에 대해 설명하는 내용을 알아보려면 여기를 참조하세요.

다음 단계는 시스템에 GDB가 설치되어 있는지 확인하는 것입니다. 그렇지 않고 Ubuntu와 같은 Debian 기반 시스템을 사용하는 경우 다음 명령을 사용하여 도구를 쉽게 설치할 수 있습니다.

sudo apt-get install gdb

다른 배포판에 설치하려면 여기로 이동하세요.

이제 디버깅 준비가 된 방식으로 프로그램을 컴파일하고 GDB가 시스템에 있으면 다음 명령을 사용하여 디버깅 모드에서 프로그램을 실행할 수 있습니다.

gdb [prog-executable-name]

이렇게 하면 GDB 디버거가 시작되지만 프로그램 실행 파일은 이 시점에서 시작되지 않습니다. 디버깅 관련 설정을 정의할 수 있는 시간입니다. 예를 들어 특정 줄 번호 또는 함수에서 프로그램 실행을 일시중지하도록 GDB에 알리는 중단점을 정의할 수 있습니다.

계속해서 실제로 프로그램을 시작하려면 다음 gdb 명령을 실행해야 합니다.

run

프로그램에서 일부 명령줄 인수를 전달해야 하는 경우 여기에서 지정할 수 있다는 점을 여기서 언급할 가치가 있습니다. 예를 들어:

run [arguments]

GDB는 디버깅하는 동안 유용한 많은 유용한 명령을 제공합니다. 다음 섹션의 예에서 그 중 일부에 대해 논의하십시오.

GDB 사용 예

이제 우리는 GDB와 사용법에 대한 기본적인 아이디어를 갖게 되었습니다. 예를 들어 거기에 지식을 적용해 봅시다. 다음은 예제 코드입니다.

#include <stdio.h>

int main()
{
int out = 0, tot = 0, cnt = 0;
int val[] = {5, 54, 76, 91, 35, 27, 45, 15, 99, 0};

while(cnt < 10)
{
out = val[cnt];
tot = tot + 0xffffffff/out;
cnt++;
}

printf("\n Total = [%d]\n", tot);
return 0;
}

따라서 기본적으로 이 코드가 하는 일은 val 배열에 포함된 각 값을 선택하고 이를 정수에 할당한 다음 변수 이전 값과 0xffffffff/out의 결과를 합산하여 tot를 계산하는 것입니다.

여기서 문제는 코드가 실행될 때 다음 오류가 발생한다는 것입니다.

$ ./gdb-test 
Floating point exception (core dumped)

따라서 코드를 디버깅하기 위한 첫 번째 단계는 -g로 프로그램을 컴파일하는 것입니다. 명령은 다음과 같습니다.

gcc -g -Wall gdb-test.c -o gdb-test

다음으로, GDB를 실행하고 디버그하려는 실행 파일을 알려주십시오. 이에 대한 명령은 다음과 같습니다.

gdb ./gdb-test 

이제 내가 받고 있는 오류는 부동 소수점 예외이며 대부분의 사람들이 이미 알고 있듯이 x가 0일 때 n % x에 의해 발생합니다. 따라서 이를 염두에 두고 11번 줄에 중단점을 설정했습니다 분열이 일어나는 곳. 이는 다음과 같은 방식으로 수행되었습니다.

(gdb) break 11

(gdb)는 디버거 프롬프트이며 방금 break 명령을 작성했습니다.

이제 GDB에 프로그램 실행을 시작하도록 요청했습니다.

run

따라서 중단점에 처음 도달했을 때 GDB가 출력에 표시한 내용은 다음과 같습니다.

Breakpoint 1, main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;
(gdb)

위의 출력에서 볼 수 있듯이 디버거는 중단점이 있는 행을 표시했습니다. 이제 out의 현재 값을 인쇄해 보겠습니다. 이는 다음과 같은 방법으로 수행할 수 있습니다.

(gdb) print out
$1 = 5
(gdb)

값 5가 출력된 것을 볼 수 있습니다. 그래서 지금은 괜찮습니다. 디버거에게 다음 중단점까지 프로그램 실행을 계속하도록 요청했습니다. 이는 c 명령을 사용하여 수행할 수 있습니다.

c  

나는 out의 값이 0이라는 것을 알 때까지 이 작업을 계속했습니다.

...
...
...
Breakpoint 1, main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;
(gdb) print out
$2 = 99
(gdb) c
Continuing.

Breakpoint 1, main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;
(gdb) print out
$3 = 0
(gdb)

이제 이것이 정확한 문제인지 확인하기 위해 이번에는 c 대신 GDBs s(또는 단계) 명령을 사용했습니다. 이유는 프로그램 실행이 현재 일시 중지된 11행을 실행하고 이 지점에서 충돌이 발생하는지 확인하기를 원했기 때문입니다.

일어난 일은 다음과 같습니다.

(gdb) s

Program received signal SIGFPE, Arithmetic exception.
0x080484aa in main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;

예, 위의 강조 표시된 출력에서 확인할 수 있듯이 여기에서 예외가 발생했습니다. s 명령을 다시 한 번 실행하려고 시도했을 때 최종 확인이 이루어졌습니다.

(gdb) s 

Program terminated with signal SIGFPE, Arithmetic exception.
The program no longer exists.

따라서 이런 식으로 GDB를 사용하여 프로그램을 디버깅할 수 있습니다.

결론

GDB는 사용자가 탐색하고 사용할 수 있는 많은 기능을 제공하므로 여기에서 표면을 긁었습니다. 도구에 대해 자세히 알아보려면 GDB의 매뉴얼 페이지를 살펴보고 코드에서 무언가를 디버깅할 때마다 사용해 보십시오. 디버거에는 약간의 학습 곡선이 연결되어 있지만 노력할 가치가 있습니다.