본문 바로가기

Academy I/Tech Academy

Linux gdb 사용법 [II]

1.1. gdb로 디버깅하기


1.1.1. gdb 시작하기

gdb <filename>으로 gdb를 시작할 수 있다. 프롬프트가 뜨고 여기에 커맨드를 입력해 디버거의 동작을 지시할 수 있다.


1.1.2. 프로그램 실행하기

run 명령으로 프로그램을 시작할 수 있다. run 뒤에 인자를 지정하면 프로그램의 인자로 전달된다. 프로그램 실행 중 에러가 발생하면 gdb는 에러의 이유와 위치를 보여준다.


1.1.3. 스택 추적

에러가 발생해 프로그램의 실행이 중단된 경우 backtrace 또는 bt명령을 이용해 중단된 위치에 어떻게 도달했는지 추적할 수 있다.


1.1.4. 변수 살펴보기

print <변수명> 명령을 이용해 변수가 값을 볼 수 있다. 이때 출력의 형식은 $1 = value와 같은데 gdb가 나중을 위해 임시로 변수의 값을 $1에 저장했다는 의미이다. print 명령을 이용해 배열이나 구조체의 멤버 변수 값도 볼 수 있다. @<숫자> 구조를 사용해 배열의 여러 요소를 동시에 볼 수도 있다.


1.1.5. 프로그램의 소스 코드 보기

list를 입력하면 현재 실행이 중단된 지점 부근의 코드를 보여준다. 인자로 줄 번호 혹은 함수 이름을 입력하면 그 위치의 코드를 볼 수 있다.


1.1.6. Breakpoint 지정

중단점을 지정하면, 프로그램이 실행되다 중단점을 만났을 때 정지하고 제어를 디버거로 반환한다. break <줄번호>를 입력해 중단점을 설정할 수 있다. cont를 입력하면 다시 실행을 재개한다. display 명령을 사용하면 프로그램이 중단점에서 정지할 때마다 배열을 자동으로 표시할 수 있다. commands 명령을 이용해 중단점을 만났을 경우 수행할 작업을 지정할 수 있다.


1.1.7. 디버거에서 패치하기

set명령을 이용해 재컴파일 없이 코드를 수정할 수 있다. set variable n=n+1과 같은 방법으로 강제로 변수값을 바꿀 수 있다.


커맨드

기 능

help <command>

도움말을 출력한다

run

프로그램을 실행한다

backtrace(=bt)

스택을 추적한다

print <variable>

변수를 출력한다

list <line> or <func>

소스를 출력한다

break <line>

중단점을 설정한다

cont

중단된 실행을 재개한다

display <variable>

중단점을 만날 때마다 변수값을 출력한다

commands

중단점을 만났을 때 수행할 동작을 지정한다

info <command>

display, break등과 같은 명령에 의해 설정된 내용을 출력한다

disable <command> <num>

display, break등과 같은 명령에 의한 설정을 비활성화 한다

enable <command> <num>

비활성화 된 설정을 활성화 한다

set variable <expression>

변수의 값을 패치한다

<gdb 주요 커맨드>


매크로

기 능

@<숫자>

배열에서 숫자 만큼의 항목을 지정한다

$<숫자>

print에 의해 출력된 변수들의 값

$

마지막으로 출력된 변수 값

$$

마지막 한단계 앞에서 출력된 변수 값

<gdb에서 사용할 수 있는 매크로>


[출처] 디버깅 - gdb (1/2)|작성자 화무




1. gdb로 디버깅하기


1.1. gdb 주요 커맨드 & 매크로 요약


매크로

기 능

@<숫자>

배열에서 숫자 만큼의 항목을 지정한다

$<숫자>

print에 의해 출력된 변수들의 값

$

마지막으로 출력된 변수 값

$$

마지막 한 단계 앞에서 출력된 변수 값

<gdb에서 사용할 수 있는 매크로>


커맨드

기 능

help <command>

도움말을 출력한다

run

프로그램을 실행한다

backtrace(=bt)

스택을 추적한다

print <variable>

변수를 출력한다

list <line> or <func>

소스를 출력한다

break <line>

중단점을 설정한다

cont

중단된 실행을 재개한다

display <variable>

중단점을 만날 때마다 변수 값을 출력한다

commands

중단점을 만났을 때 수행할 동작을 지정한다

info <command>

display, break등과 같은 명령에 의해 설정된 내용을 출력한다

disable <command> <num>

display, break등과 같은 명령에 의한 설정을 비활성화 한다

enable <command> <num>

비활성화 된 설정을 활성화 한다

set variable <expression>

변수의 값을 패치한다

<gdb 주요 커맨드>


1.2. 실습


1.2.1. 실습용 프로그램


디버깅 할 프로그램의 소스 코드는 다음과 같다.



이 프로그램은 버블소팅 함수인 sort를 호출해, array를 key 순서로 오름차순 정렬한 후 출력한다. 그러나 현재 버그가 실행하면 세그멘테이션 에러가 발생한다.


1.2.2. gdb 시작

아래와 같이 프로그램을 컴파일 한 후 gdb에 물린다. 컴파일 시 -g 옵션을 주는 것은 gdb용 디버깅 정보를 포함하기 위함이다.



1.2.3. 프로그램 실행

run 명령을 이용해 프로그램을 실행한다. 에러가 발생하면 gdb는 그 이유와 위치를 보여주고, 프로그램 실행이 정지된다. 아래 결과를 보면 배열을 비교하는 과정에서 에러가 발생함을 알 수 있다.



1.2.4. 스택 추적

backtrace 명령을 이용해 함수 호출 스택을 볼 수 있다. 즉, 어떤 과정(함수)을 거쳐 현재 위치에 도달 했는지 알 수 있다. 다음은 현재 위치가 main에서 호출한 sort함수 임을 나타낸다.



1.2.5. 변수 살펴보기

3번 과정으로부터 배열의 범위를 벗어난 참조 때문에 에러가 발생했음을 짐작할 수 있다. 따라서 배열 인덱스로 사용되는 j의 값을 확인할 필요가 있다. 아래와 같이 print 명령을 사용해 j 값을 확인할 수 있다.



현재 j는 4임을 볼 수 있다. j+1은 5가 되는데 배열의 인덱스는 0~4 이므로 에러가 발생했다.


print 명령을 이용해 배열 요소의 값을 볼 수도 있다. 또한 한번 출력된 값은 “$번호”의 형식으로 순서대로 자동 기억된다. 이를 이용해 이전 결과를 참조할 수 있다.



1.2.6. 프로그램의 소스 코드 보기

list 명령을 사용하면 현재 위치 주변의 소스 코드를 출력한다. 교재에서는 list를 사용하면 sort함수 안쪽의 내용이 출력되었는데, 학교 서버에 접속해서 실습을 해 보니 main함수에서 sort를 호출하는 부분이 표시되었다.


즉, 호출 스택에서 가장 바깥쪽 부분 소스를 보여준다. run 과정에서 에러가 발생한 부분이 26번째 줄임을 알았으므로, list 26을 통해 근처 소스를 볼 수 있다.



일단 24번째 줄에서 실행 조건을 j < n에서 j < n-1로 수정한 후, 다시 컴파일 한 뒤 출력하면 세그멘테이션 에러는 발생하지 않는다. 그러나 정상적으로 정렬은 되지 않는다.



1.2.7. 중단점 지정하기

일단 break 명령을 이용해 sort함수의 바깥쪽 루프를 중단점으로 설정한다. 그 다음 display 명령을 이용해 중단될 때마자 array의 모든 내용을 출력 하도록 한다. 매번 cont를 호출해 실행을 재개하는 것은 번거로우므로 command를 이용해 중단되었을 때마다 호출할 명령으로 cont를 지정한다.




바깥쪽 루프의 반복 횟수가 모자람을 알 수 있다. 출력된 정보를 보면, 루프를 돌면서 n의 값이 줄어드는 것이 보인다. 소스 코드에서 이 부분을 찾아서 수정하면 정상적인 결과가 출력된다.


set 명령을 이용해 다음과 같이 바로 패치하여 생각한 해법이 올바른지 알아볼 수 있다.


 

n-- 부분에서 다시 n = n+1을 해 주어 n 값을 5로 유지해 주었더니 정상적인 실행 결과가 출력되었다.


[출처] 디버깅 - gdb (2/2)|작성자 화무




1. assert (Page 585)


1.1. assert 요약

<assert.h>에 정의되어 있는 void assert(int expression) 매크로 함수는 expression의 값이 0이면 에러 정보를 stderr에 출력하고 abort를 호출해 프로그램을 종료한다.


NDEBUG 매크로가 정의되어 있으면 assert는 아무 것도 수행하지 않는다.

 

1.2. 실 습

다음은 수학 라이브러리에 있는 sqrt 함수를 이용해 제곱근을 구하는 프로그램이다. assert를 통해 x가 음수가 아닐 경우에만 제곱근을 계산한다. -lm은 수학 라이브러리인 libm.a를 링크하기 위한 옵션이다.




my_sqrt의 인자로 -2가 들어가면 Assertion Error가 발생한다. 컴파일시 다음과 같이 NDEBEG 매크로를 정의하면 assert는 아무런 동작도 하지 않는다.



Gcc에서 math.h에 정의 되어있는 함수들 예를 들어
sqrt(), atan(), atan2(), pow() 등등의 여러 함수를 사용해서 코딩을 한뒤에
컴파일을 하게되면 다음과 같은 에러가 발생합니다.

 undefined reference to `sqrt'

이것은 Unix계열에서 math.h에 정의되어있는 함수를 사용할때는 추가적으로 옵션을 더 줘야 해결이 됩니다.

$gcc -o xxxx.c xxxx -lm

-lm 옵션을 컴파일시 적어주게 되면 math.h와 연결이 되어 컴파일이 문제없이 진행이 됩니다.

[출처] 디버깅 - assert|작성자 화무



'Academy I > Tech Academy' 카테고리의 다른 글

[Linux]Shell 활용 (01)  (0) 2014.12.31
[Linux]man 활용  (0) 2014.12.31
[Linux]설치된 Command의 경로, 정보를 얻는 명령들  (0) 2014.12.31
Linux Shell Programming  (0) 2014.12.22
Linux make 사용법 [II]  (0) 2014.12.22
VirtualBox의 Linux(CentOS)에서 공유폴더 설정  (0) 2014.12.22
Linux gdb 사용법 [I]  (0) 2014.12.19
Linux make 사용법 [I]  (0) 2014.12.18