[GDB] 사용법

GDB?

gdb는 디버깅과 프로그램 실행을 위한 유틸리티

왜 printf()가 아닌 gdb를 사용해서 디버깅하나요?

printf 디버깅은 프로그램의 실행 흐름을 살피고 따라가는 데 많은 도움을 준다. Debug() 함수를 사용해서 코딩하는 것보다 많이 사용되기도 한다. 하지만, 좀더 세밀한 프로그램 분석과 변수 변화를 보는 데에는 적합하지 않다.

전문적인 개발자들은 디버거를 이용한다. 흐름을 추적하고, 변수를 검사하고, 실행시점의 실패 지점을 정확하게 분석할 수 있기 때문이다.

시나리오

Segmentation Fault

가장 많이 발생하는 오류이다. 이 오류는 프로그램을 종료시킨다. 할당된 주소 공간 외부의 주소에 액세스할 때 발생한다. 그러나 실질적으로 말하면, 널포인터가 있는 메모리 참조에 의해 발생한다. 이러한 에러는 printf 디버깅으로는 감지하기 어렵다.

Bus error

일반적인 런타임 오류 중 하나이며, 프로세스의 종료를 야기한다. CPU의 주소가 잘못 정렬된 포인터를 사용할 때 발생한다.

Silent Bug(묵시적 버그)

프로그램이 손상되거나 유용한 정보를 인쇄하지 않고 잘못된 방향으로 이동하는 버그가 있을 수 있다. 그런 단서가 없으면 원인을 추적할 수 없다. 코드에 여러 개의 printfs를 포함했을 수 있지만, 분명히 비효율적이다.
만약 gdb에서 프로그램을 실행한다면, 언제든지 브레이크 신호만 보내면 정지하고 실행 지점을 찾을 수 있다. 그러면 추적하거나 검사할 수 있다.

사용법

gdb를 사용하기 위해서 C 나 C++로 작성되어 컴파일 되는 경우 -g 옵션이 필요하다. -01이나 -02 같은 최적화 옵션을 사용해서는 안된다.

%cc -g -o filename filename.c ...
%gcc -g filename.c

gdb를 시작하려면 명령줄에 gdb filename을 입력한다. (gdb) 프롬프트가 표시된다.

%gdb filename
%gdb
GNU gdb 4.18
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-unknown-freebsd".
(gdb) _

명령어

자주 사용하는 명령어는 극히 일부이며, 몇몇개의 프로그램을 디버깅하면 금방 손에 익는다.

Execution control

  • break line
  • break file_name:line
  • break function_name
  • bUsed to set a breakpoint at the line or function. In the case of the line, execution is stopped before any code on the line is executed. In the case of function_name, execution stops when the function is called.
  • run
  • run args
  • rStart execution of the program. If breakpoints are set, execution stops when the breakpoint is reached. Otherwise, the program runs to completion. gdb prints a message stating the status of the program on termination.
  • continue
  • cContinue execution from where it stopped.
  • step
  • step [n]Execute the next or next n source line(s). This command steps into functions. Argument N means do this N times.
  • next
  • next [n]Same as step, but the command passes functions, treating them as if they were single statements. Argument N means do this N times.
  • untilExecute until the program reaches a source line greater than the current. If your program enters a for loop and you grow weary of typing next, you can use the command to exit the loop.
  • finishExecute until current function return.

Breakpoint management

  • deleteDeletes all breakpoints.
  • clear function
  • clear lineDeletes any breakpoints set on the line or at the entry of function.

Listing of program

  • list sourceline
  • list function
  • list [+|-]
  • list
  • lPrint 10 lines centered at sourceline, or starting from the beginning of function. list print 10 more lines, whereas list - prints 10 lines before the last printing.

Examination of data

  • print expressionPrint the value of expression. The contents of variables in the program can be viewed through this command.
    • print iPrint the value of variable i.
    • print *pPrint the contents of memory pointed by p, where p is a pointer variable.
    • print xCheck all the members of a structure, assuming x is a structure.
    • print x.fieldCheck the members of a structure.
    • print p->fieldCheck a member of a structure, assuming p is a pointer to a structure.
    • print array[i]Print the i'th element of array.
    • print arrayPrint all the element of array, assuming array is an array.
  • display expressionPrint value of expression each time the program stops.
  • delete displayCancel some expressions to be displayed when program stops.

Examination of Stack

  • bt
  • wherePrint a backtrace of all the active functions on the execution stack. This is very useful in determining the location of execution, and order in which functions call each other.
  • frame numberSelect and print a stack frame.
  • upSelect and print a stack frame (function) that called this one.
  • downSelect and print a stack frame called by this one.

Others

  • help
  • help category
  • help commandDisplay the set of commands available in gdb. The last two display the usage, and information about command categories, and commands.
  • kill
  • kKill execution of the program being run. Typically used to prepare to re-start the program from the beginning.
  • quiteExit gdb.
  • returnTyping of return will repeat the previous command. You can use this method to quickly step through the program with next or step. Or, you may want to use this to quickly browse your program with list command.

디버깅 과정(Sequence)

디버깅 과정을 간략하게 정리해보았다.

Segmentation fault 발생

%example ...
segmentation fault
%

gdb는 에러가 발생한 위치를 보여주고, 에러 메시지를 발생한다.

gdb에서 실행

(gdb) list
19 {
20 int sum = 0;
21 int i;
22
23 for(i = 0;;i++)
24 sum += *ptrs[i];
25 }
26
27
28 void PrintArray()
(gdb) print i
$1 = 23424592334

list 명령을 사용하여 에러 발생 지점의 주변을 확인하고, print 명령을 사용하여 변수의 값을 확인할 수 있다.

원인을 찾으면 수정 후 소스 코드를 다시 컴파일할 수 있다.

코드 세그먼트의 시작 부분에 중단점(Break Point) 설정

분석해야할 코드의 시작 부분에 중단점을 설정할 수 있다. 프로그램을 실행하고 변수를 확인하면서 다음 명령으로 한줄 씩(Line by Line)추적할 수 있다. 원하는 부분이 나올 때까지 이 절차를 반복한다.

반응형