블로그 이미지
하루, 글. 그림. 영상매체. 표현을 도와주는 기기들. 도전 중. 동화다아아

카테고리

분류 전체보기 (176)
잡담 (1)
IT 기기-리뷰&뉴스 (7)
리뷰 - 도서 (1)
리뷰 - 영상 (0)
리뷰 - 그림/음악 (1)
내장형 하드웨어 (163)
Total635,306
Today53
Yesterday129
 

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)


Posted by 동화다아아

댓글을 달아 주세요

최근에 달린 댓글

최근에 받은 트랙백

글 보관함