gdb (GNU Debugger - 사용옵션)
gdb (GNU Debugger)
gdb는 C, C++, Modula-2로 구현된 프로그램을 디버그할 수 있는 도구이다. 버그를 잡는 걸 돕기 위해 gdb는 다음과 같은 작업들을 가능하게 한다.
- 프로그램의 행동에 영향을 줄 수 있는 각종 조건을 설정한 후, 프로그램을 시작한다.
- 특정 조건을 만나면 프로그램을 정지시킨다.
- 프로그램이 정지됐을 때 무슨 일이 일어났는지 검사한다.
- 프로그램 내부 설정을 바꾸어서 버그를 수정함으로써 다른 버그를 계속 찾아나간다.
gdb 실행
$ gdb [prog [core|procID]]
- prog: 디버깅할 프로그램
- core: 프로그램 실행 중에 “segmentation fault” 등의 오류에 의해 비정상적으로 종료할 때 생성되는 파일로, 그때의 시스템의 내부 상태를 그대로 저장해 놓은 것이다. 이 파일을 인자로 주면 실행파일이 비정상적으로 종료된 곳이 소스코드의 어느 부분인지를 표시해 준다.
- procID: 이미 실행중인 프로그램을 debugging하려면 해당 process의 id (PID)를 주면 되는데, 이 때 주의 할 것은 PID와 같은 이름의 파일이 있을 경우 gdb가 core파일로 여기게 되는 점이다.
주의: Debugging하고자 하는 실행파일은 gcc에서 –g 옵션을 주어 compile함으로써 gdb가 필요로 하는 부가 정보들이 추가된 것을 사용해야 제대로 debugging을 수행할 수 있다.
gdb 명령어
gdb를 실행하여 gdb prompt ‘(gdb) ’가 표시된 상태에서 gdb 명령어를 사용하여 디버깅을 진행한다.
참고: class와 command의 축약형도 지원된다. (예, ‘run’명령어를 축약형 ‘r’로 대신할 수 있다.)
⇒ 도움말 (help)
help [class|command] → 도움말, 명령어 분류 목록 출력, 해당 class에 속한 명령어 목록 표시, 해당 command에 대한 도움말 표시
⇒ 프로그램 수행 (running)
k(kill) → 디버깅 중인 프로그램의 실행을 강제로 종료시킨다.
r(run) [args] → 디버깅할 프로그램의 수행을 시작한다. 프로그램 실행에 필요한 argument (args)를 지정할 수 있다. args를 지정하지 않으면 바로 이전의 run실행이나 “set args”명령에 의해 미리 주어진 argument를 사용한다. 입출력 방향 재지정 (“>”, “<”, “>>”)을 사용할 수 있다.
set args [args] → 프로그램이 시작될 때, 디버깅할 프로그램에 전달할 argument를 설정한다.
n(next) [n] → 멈춰진 프로그램에서 프로그램의 다음 n(default=1)개의 문장을 수행한 후 멈춘다. 함수일 경우, 함수 전체를 수행한다.
s(step) [n] → 멈춰진 프로그램에서 프로그램의 다음 n(default=1)개의 문장을 수행한 후 멈춘다. 함수일 경우, 함수 내부로 들어가 한 문장씩 수행한다.(visual studio의 F10키의 기능과 같다.)
continue [n] → 시그널(Ctrl-C)이나 breakpoint 등에 의해 멈춰진 프로그램의 수행을 계속한다. n이 지정될 경우, 이후 n-1번의 breakpoint는 무시하고, n번째 breakpoint에서 수행을 멈춘다.(visual studio의 F11키의 기능과 같다.)
until [[file:]n|function] → 프로그램이 현재 라인보다 큰 라인이나 또는 지정된 라인이나 어드레스 또는 함수에 도달할 때까지 수행한다(break 명령과 동일한 argument). 또한, 현재 stack frame을 빠져나올 때도 멈춘다. loop를 지날 때, 첫번째 loop수행에서는 next명령과 동일하지만 두번째 loop수행부터는 그 loop를 벗어날 때까지 멈추지 않는다.
disassemble main → main함수를 쪼갠다.
bt(backtrace) → 오류가 발생한 함수를 역으로 찾아간다.
c → 다음 breakpoint를 만날 때 까지 계속 수행한다.
u → for문에서 빠져나와서 다음 breakpoint까지 수행한다.
⇒ 옵션
→ set listsize (숫자) 를 입력한다면 list 출력 범위를 조절할 수 있다.)
→ Enter 를 입력하면 마지막으로 수행했던 명령을 다시 수행한다.
⇒ 감시점 설정(watch)
→ watch (변수명) 입력하면 해당 변수에 watchpoint를 설정하고 해당 변수가 바뀔때마다 브레이크가 걸리면서 이전값과 현재값을 출력한다.
⇒ 변수 정보 보기
→ info locals : 현재 상태에서 어떤 지역변수들이 있으며, 값은 어떠한지를 알 수 있다.
→ info variables : 현재 상태에서의 전역변수 리스트를 확인할 수 있다.
→ p lval : lval 값을 확인한다.
→ p func : func 함수의 주소값을 확인한다.
→ p pt : pt가 구조체라면 구조체의 주소를 확인한다
→ p *pt : pt가 구조체라면 구조체의 값을 확인한다.
→ p **pt : *pt가 구조체라면 구조체의 값을 확인한다.
→ info registers : 레지스트 값 전체를 한번에 확인한다.
⇒ 레지스트 값 및 포인터가 가리키는 구조체의 배열을 출력 (info, print)
→ info all-registers : MMX 레지스트를포함하여 거의 대부분의 레지스트 값을 확인한다.
→ p $eax : eax 레지스트의 값을 확인한다. ( ex_ eax, ebx, ecx, edx, eip )
→ p *pt@4 : 4크기의 배열로 gdb가 알 수 있으므로 4개의 크기만큼 가져와서 확인할 수 있다.
⇒ 중복된 변수명이 있는 경우 특정 변수를 지정해서 출력 (print)
→ p 'main.c'::var : main.c 파일에 있는 전역변수인 var 변수의 값을 출력
→ p hello::var : hello 함수에 포함된 static 변수인 var 변수의 값을 출력
⇒ 출력 형식의 지정
→ p/t var : var 변수를 2진수로 출력
→ p/o var : var 변수를 8진수로 출력
→ p/d var : var 변수를 부호가 있는 10진수로 출력 (int)
→ p/u var : var 변수를 부호가 없는 10진수로 출력 (unsigned int)
→ p/x var : var 변수를 16진수로 출력
→ p/c var : var 변수를 최초 1바이트 값을 문자형으로 출력
→ p/f var : var 변수를 부동 소수점 값 형식으로 출력
→ p/a addr : addr주소와 가장 가까운 심볼의 오프셋을 출력 ( ex_ main + 15 )
⇒ 출력명령 요약 (print)
→ p [변수명] : 변수 값을 출력
→ p [함수명] : 함수의 주소를 출력
→ p/[출력형식] [변수명] : 변수 값을 출력 형식으로 출력
→ p '[파일명]'::[변수명] : 파일명에 있는 전역변수 값을 출력
→ p [함수명]::[변수명] : 함수에 있는 변수 값을 출력
→ p [변수명]@[배열크기] : 변수의 내용을 변수 배열의 크기 형태로 출력
⇒ 디스플레이 명령 (display, undisplay)
→ display [변수명] : 변수 값을 매번 화면에 디스플레이
→ display/[출력형식] [변수명] : 변수 값을 출력 형식으로 디스플레이
→ undisplay [디스플레이번호] : 디스플레이 설정을 없앤다
→ disable display [디스플레이번호] : 디스플레이를 일시 중단한다.
→ enable display [디스플레이번호] : 디스플레이를 다시 활성화한다.
⇒ 스택이란
→ 스택의 경우는 상위 1기가는 커널에서 사용하며, 그 바로 아래 공간인 상위 0xBFFFFFFF 부터 하위로 늘어나게된다.
→ 상세한 디버깅을 위해서는 -g 옵션으로 디버깅 정보와 --save-temps 옵션을 통해 어셈블리 코드를 얻어낼 수 있다.
→ 상위 프레임으로 갈 수록 메인 함수에 가까워 지는 것이다.
⇒ 스택 프레임 관련 명령 (frame, up, down, info)
→ frame [N] : n번 스택 프레임으로 변경
→ up : 상위 프레임으로 이동
→ up [N] : n번 상위 스택 프레임으로 이동
→ down : 하위 프레임으로 이동
→ down [N] : n번 하위 스택 프레임으로 이동
→ info frame : 현재 스택 프레임 정보를 출력
→ info args : 현재 스택 프레임의 함수가 호출될 때 인자를 출력
→ info locals : 현재 스택 프레임의 함수내의 지역변수를 출력
→ info catch : 현재 스택 프레임의 함수내의 예외 핸들러를 출력
⇒ 스택 트레이스 하는법
→ b main 또는 원하는 곳에 브레이크 포인트를 잡고 오류가 발생할 때 까지 c를 통해 진행하면, 세그먼트 폴트 등의 오류가 발생하고 디버그가 멈추는데 여기서 bt 를 통해서 전체 스택 프레임을 확인하고 어떤 함수에서 호출시에 문제가 발생하였는지 확인단, 일반적인 라이브러리에서는 오류발생 확률이 없다고 보고, 그 함수를 호출시에 문제를 의심한다. 다시 프레임을 이동하면서, 로컬변수와 전역변수 등을 확인하면서 디버깅이 가능하다.
⇒ 메모리 상태 검사 (x)
→ x/[범위][출력 형식][범위의 단위] : 메모리의 특정 범위의 값들을 확인할 수 있다.
→ 이렇게 메모리를 직접 읽어보는 일은 -g 옵션을 가지고 컴파일 되지 않은 실행파일을 디버깅 할때에 자주 사용된다.
→ 즉, x/10i main 과 같이 역 어셈블하여 해당 코드를 추측하는 것이다.
기본적인 컴파일 과정 정리
⇒ 첫 번째로 컴파일 시에 디버깅 정보를 담아야만 한다.
→ gcc -g -o (프로그램명) (소스파일명).c 로 컴파일하면 gdb로 컴파일 단계 분석이 가능해 진다.
⇒ gdb (프로그램명)을 입력하면 gdb모드로 들어간다.
→ l(list)를 입력하면 소스가 출력된다.
(l 10을 입력한다면 10행을 중심으로 위아래 +-5줄이 표시된다.)
→ b(break) n(라인 수) 를 입력하면 입력한 n 번째 라인에 breakpoint가 지정된다.
→ info b 를 입력하면 breakpoint 정보 표시.
→ r(run)을 입력하면 디버깅할 프로그램이 실행된다.
k(kill)을 입력하면 프로그램이 종료된다.
→ 변수가 i로 선언되어 있다면, display i 혹은 print i를 입력하면 i값의 변화를 추적한다.
→ s(step)를 입력하면 멈춰진 프로그램에서 다음(s 다음에 숫자를 입력하면 그 숫자만큼)의 문장을 실행하고 멈춘다. 함수일 경우 함수 내부로 들어가 한 문장씩 실행한다.(visual studio의 F10키와 같은 기능)
→ n(next)을 입력하면 멈춰진 프로그램에서 다음(n 다음에 숫자를 입력하면 그 숫자만큼)의 문장을 실행하고 멈춘다. 함수일 경우 함수 전체를 실행한다.(visual studio의 F11키와 같은 기능)
→ quit 을 입력하면 gdb를 빠져 나간다.
참조
gdb 사용법 (http://blog.naver.com/semigifn?Redirect=Log&logNo=9043533)
'내장형 하드웨어 > 참고자료' 카테고리의 다른 글
AVR(ATmega128)의 내부적 특징 (0) | 2011.04.18 |
---|---|
폰 노이만 구조 / 하버드 구조 (Von Neumann architecture / Havard architecture) (0) | 2011.04.18 |
vi (visual editor - 커맨드 모드, 에디트 모드, 확장명령) (0) | 2011.04.11 |
형식 지정자 (%c, %d, %i, %e, %f, %lf, %s, %o, %n ...) (0) | 2011.03.30 |
ASCII code (아스키 코드) (0) | 2011.03.30 |