aESOP S3C6410 보드에는 Native GDB가 기본으로 포함되어 제공 됩니다.
따라서, 일반 리눅스 PC에서 GDB를 사용하는 것과 동일하게 타깃 보드에서 GDB를 이용하여
응용프로그램 디버깅을 수행할 수 있습니다.
다음은 http://dualpage.muz.ro/ 에서 발췌해 온 GDB의 간단한 사용 방법 입니다.
대상 프로그램 지정
먼저 디버깅을 할 대상 프로그램을 지정하는 방법에는
두가지 방법이 있습니다.
1. open - 새로 프로그램을 지정한다.
2. attch - 이미 실행중인 프로그램을 지정한다.
먼저 open은 다음과 같이 하면 됩니다.
gdb 대상프로그램
dual5651@dualpage:~$ gdb ./exam1
GNU gdb 6.3-debian
Copyright 2004 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-linux"...Using host libthread_db library "/lib/libthread_db.so.1".
(gdb)
위는 성공적으로 대상 프로그램을 open하였을때의 모습입니다.
만약 존재하지 않는 프로그램을 open하고자 한다면 마지막 줄에
다음과 같은 메시지가 뜹니다.
This GDB was configured as "i386-linux"..../exam2:
그런 파일이나 디렉토리가 없음.
attch는 이미 실행중인 process를 디버깅하고자 할때 사용하는
것으로, 다음과 같이 사용하실 수 있습니다.
dual5651@dualpage:~$ ps -aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1085 0.0 0.8 7176 2160 ? Ss 20:50 0:00 sshd:
root 1087 0.0 0.8 7176 2160 ? S 20:50 0:00 sshd:
root 1141 0.0 0.1 1344 312 tty1 S+ 21:17 0:00 /root/exam
dual5651 1132 0.0 0.3 2480 856 pts/0 R+ 21:14 0:00 ps -aux
먼저 ps -aux 명령을 이용하여 현재 실행중인 프로세스들의
목록을 출력하여 보았더니, root님이 /root/exam 이라는
프로그램을 실행중이신 것을 볼 수 있습니다. PID가 1141이라는
것을 잘 봐두어야 합니다. :)
이 프로세스를 attch하려면 다음과 같이 하면 됩니다.
gdb 대상프로그램 PID
dual5651@dualpage:~$ gdb /root/exam 1141
GNU gdb 6.3-debian
Copyright 2004 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-linux"...Using host libthread_db library "/lib/libthread_db.so.1".
Attaching to program: /root/exam, process 1141
프로세스 실행상태 관리
디버깅을 하려면 먼저 대상 프로그램을 켜야 할 것이고,
끝난후에는 디버깅 되는 대상을 죽여줘야 할 것입니다.
다음과 같은 명령어가 존재합니다.
run - 대상 프로그램을 시작 시킨다.
ex)run : 대상 프로그램을 시작 시킨다.
run 인자 - 대상 프로그램의 인자값을 준 상태로 시작 시킨다.
ex)run 1234 : 인자로써 1234를 주고 시작 시킨다.
kill - 대상 프로그램을 종료 시킨다.
ex)kill : 대상 프로그램을 종료 시킨다.
Break Point(중단점) 관리
Break Point는 디버깅을 하는데 있어서 아주 중요한
기능이라고 할 수 있겠습니다. (BP 없는 디버거는 꿈꿀수도 없죠 lol)
다음과 같은 BreakPoint관리 명령어가 존재합니다.
1. Break - Break Point 설치
2. clear,delete - Break Point 제거
3. disable - Break Point 비활성화
4. enable - Break Point 활성화
5. condition - Break Point에 조건 부여
Break
지정한 주소에 Break Point를 걸 수 있는 명령입니다.
다음과 같이 사용할 수 있습니다.
break 함수 - 지정한 함수에 BP를 설치 합니다.
ex)break main : main()함수에 BP를 설치한다.
break 주소 - 지정한 주소에 BP를 설치 합니다.
ex)break 0x08048454 - 0x08048454에 BP를 설치한다.
break - 인자 없는 break는 실행중인 현재 주소에 BP를 설치합니다.
ex)break - 현재 실행중인 주소에 BP를 설치한다.
실제로 BP를 설치하면 어떻게 되는지 알아 보도록 하겠습니다.
dual5651@dualpage:~$ gdb ./exam1
GNU gdb 6.3-debian
Copyright 2004 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-linux"...Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) break main
Breakpoint 1 at 0x804845a
(gdb) run
Starting program: /home/dual5651/exam1
Breakpoint 1, 0x0804845a in main ()
(gdb)
main에 Break Point를 설치한 상태에서 프로그램을 실행 시키니,
바로 main에 설치한 BP에 걸린 것을 볼 수 있습니다. :)
break 명령을 사용할 때에, Breakpoint 다음에 보여주는 숫자는
현재 설치한 BP의 번호입니다. 이 번호를 사용하여 해당 BP를
제거/비활성화/활성화 등의 관리를 합니다.
Clear, Delete
지정한 BP를 제거하거나, 모든 BP를 제거 할때 사용합니다.
두 명령어의 사용방법은 전혀 다른데,
다음과 같이 사용할 수 있습니다.
clear 함수 - 지정한 함수에 설치되어 있는 BP 제거
ex)clear main : main()함수에 설치된 BP 제거
delete BP번호 - 지정한 BP번호의 BP를 제거
ex)delete 1 : 1번 BP에 대한 BP제거
delete - 모든 BP를 제거
ex)delete - 모든 BP제거
실제로 BP를 설치 후, 제거해 보도록 하겠습니다.
(gdb) break main
Breakpoint 1 at 0x804845a
(gdb) clear main
Deleted breakpoint 1
(gdb) break main
Breakpoint 2 at 0x804845a
(gdb) delete 2
(gdb) break 0x80484e0
Function "0x80484e0" not defined.
Make breakpoint pending on future shared library load?
(y or [n]) y
Breakpoint 3 (0x80484e0) pending.
(gdb) delete
Delete all breakpoints? (y or n) y
(gdb)
clear는 친절하게 BP가 제거되면 알려주는데, delete는 안 그렇군요.:(
Disable
특정 BP를 비활성화 시키거나 모든 BP를 비활성화 시킵니다.
다음과 같이 사용할 수 있습니다.
disable 번호 - 지정한 번호에 대한 BP를 비활성화 시킵니다.
ex) disable 1 - 1번 BP를 비활성화 시킵니다.
disable - 모든 BP를 비활성화 시킵니다.
ex) disable - 모든 BP를 비활성화 시킵니다.
Enable
특정 BP를 활성화 시키거나 모든 BP를 활성화 시킵니다.
다음과 같이 사용할 수 있습니다.
enable 번호 - 지정한 번호에 대한 BP를 활성화 시킵니다.
ex) enable 1 - 1번 BP를 활성화 시킵니다.
enable - 모든 BP를 활성화 시킵니다.
ex) enable - 모든 BP를 활성화 시킵니다.
Condition
특정 BP에 조건을 부여할 수 있습니다.
다음과 같이 사용할 수 있습니다.
condition 번호 조건 - 지정한 번호에 대한 BP에 조건을 부여합니다.
ex) condition 1 $eax==5 : 1번 BP는 eax의 값이 5일때만 멈춘다.
ex) condition 1 $eax < 3 : 1번 BP는 eax의 값이 3미만일때만 멈춘다
ex) condition 1 ($eax < 3) && ($ecx > 5) : eax의 값이 3미만이고,
ecx의 값이 5 초과 일때만 멈춘다.
ex) condition 1 ($eax < 3) || ($ecx > 5) : eax의 값이 3미만이거나,
ecx의 값이 5촉
ex) condition 1 $eax=5 : 1번 BP가 작동할떄 eax의 값을 5로 만든다.
위의 예 말고도 원하는 특정한 조건일 때 멈추게 할수도 있거니와,
해당 BreakPoint에 걸렸을때 원하는 값으로 Set 시키는 용도로
사용할 수 있는 것입니다. :)
Debugging중 상태 보기
Info
gdb로 디버깅 중, 현재 Register들의 상태라던지,
설치되어 있는 BreakPoint들의 상태가 궁금할 수 있습니다.
이럴떄 사용하는 명령어가 바로 info 입니다.
다음과 같이 사용할 수 있습니다.
info reg - 모든 레지스터들의 정보 출력
ex) info reg : 모든 레지스터들의 정보 출력
info reg 특정레지스터 - 특정레지스터의 정보 출력
ex) info reg eax - eax의 정보 출력
ex) info reg eax ebx - eax,ebx의 정보 출력
info breakpoints - 모든 BreakPoint들의 정보 출력
ex) info breakpoints - 모든 BreakPoint들의 정보 출력
info breakpoints BP번호 - 특정한 BP번호에 대한 정보 출력
ex) info breakpoints 1 - 1번 BP에 대한 정보 출력
info args - 프로세스가 시작될때 주어진 인자값 출력
ex) info args
info func - 프로세스가 사용하는 함수들에 대한 출력
ex) info func
info frame - 프로세스 프레임에 대한 정보 출력
ex)info frame
info display - 중단될 떄 마다 출력될 display들에 대한 출력
ex) info display
실제로 디버깅 도 중 info 명령을 이용해 정보를 표시해 보겠습니다.
(gdb) break main
Breakpoint 1 at 0x804845a
(gdb) run
Starting program: /home/dual5651/exam1
Breakpoint 1, 0x0804845a in main ()
(gdb) info reg
eax 0x1 1
ecx 0x1 1
edx 0x40156db4 1075146164
ebx 0x401558c0 1075140800
esp 0xbffffad0 0xbffffad0
ebp 0xbffffaf8 0xbffffaf8
esi 0x40016540 1073833280
edi 0xbffffb54 -1073743020
eip 0x804845a 0x804845a
eflags 0x10282 66178
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x0 0
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x0804845a <main+6>
breakpoint already hit 1 time
(gdb)
Display
중단될 떄 마다 특정한 값을 출력하고 싶다면,
display 명령을 사용하면 됩니다.
다음과 같이 사용할 수 있습니다.
display $레지스터 - 특정 레지스터 값을 중단될 떄 마다 출력
ex)display $eax : eax의 값을 중단될 떄 마다 출력
실제로 어떻게 표시되는지 해보겠습니다.
(gdb) watch $eax
1 : $eax = 0
(gdb) nexti
0x080484a2 in main ()
1: $eax = 0
(gdb) info display
Auto-display expressions now in effect:
Num Enb Expression
1: y $eax
Watch
info와 특정한 레지스터의 값이 변경되었을 떄나,
변수의 값이 변경되었을 떄에 그 변경됨을 알고 싶다면,
watch 명령어를 사용할 수 있습니다.
다음과 같이 사용할 수 있습니다.
watch $레지스터 - 특정 레지스터의 값이 변경될 떄.
ex)watch $eax : $eax의 값이 변경될 떄 마다 알림
watch $주소 - 특정 주소의 값이 변경될 떄
ex)watch $804981c : 0x804981c의 값이 변경될때 알림
*watch는 BP와 마찬가지로 info watchpoints를 통해서
목록을 볼 수 있고, break관리에 쓰던 명령들을 쓸 수 있음.
실제로 진행 시켜 보면서 eax의 값이 변경되었을 떄
어떻게 gdb가 표시해주는지 보겠습니다.
(gdb) watch $eax
Watchpoint 2: $eax
(gdb) cont
Continuing.
Watchpoint 2: $eax
Old value = 1
New value = 0
0x08048462 in main ()
(gdb) info watchpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x0804845a <main+6>
breakpoint already hit 1 time
2 watchpoint keep y $eax
breakpoint already hit 1 time
(gdb)
Printf
printf는 c언어를 해보신 분이라면 다 아는 함수죠.
지정한 형식에 따라 값을 출력해 줍니다.
다음과 같이 사용할 수 있습니다.
printf [“포맷스트링”, 인자1, 인자2, 인자3, ..., 인자n]
ex) printf "%x",$eax :eax 레지스터의 값을 16진수로 표시
x/포맷문자
메모리에 있는 값을 출력해야 할 떄가 있습니다.
그떄 사용하는 것이, x/ 입니다.
다음과 같이 사용할 수 있습니다.
x/x 주소 - 특정한 주소의 값을 16진수로 출력
ex) x/x 0x8048454 : 0x8048454의 값을 16진수로 출력
x/s 주소 - 특정한 주소의 값을 문자열로 출력
ex) x/s 0x8048454 : 0x8048454의 값을 문자열로 출력
x/50x 주소 - 특정한 주소부터 50개 만큼 16진수로 출력
ex) x/50x 0x8048454 : 0x8048454부터 50개만큼 출력
x/c 주소 - 특정한 주소의 값을 문자값으로 출력
ex) x/c 0x8048454 : 0x8048454에 있는 값을 문자로 출력
다 예를 들 수 없어서 이만 생략합니다. :)
실제로 사용하면 어떻게 출력되는지 해보겠습니다.
(gdb) x/s 0x8048680
0x8048680 <_IO_stdin_used+28>: "Name : "
(gdb) x/10c 0x8048680
0x8048680 <_IO_stdin_used+28>: 78 'N' 97 'a' 109 'm' 101 'e' 32 ' ' 58 ':' 32 ' ' 0 ' '
0x8048688 <_IO_stdin_used+36>: 83 'S' 101 'e'
(gdb) x/5x 0x8048680
0x8048680 <_IO_stdin_used+28>: 0x4e 0x61 0x6d 0x65 0x20
(gdb)
Disas
특정한 주소의 코드가 보고 싶을 떄 사용하는 명령어 입니다.
다음과 같이 사용할 수 있습니다.
disas - 가장 처음 부터 Disassemble한다.
ex) disas
disas 함수 - 특정한 함수만 Disassemble 한다.
ex) disas main
disas 시작주소 끝주소 - 시작주소 부터 끝주소 까지 Disassemble
ex) disas 0x804845c 0x804849d
ex) disas main main+5
Debugging 진행
Nexti
Debugging을 할떄에 step by step을 하며 한줄씩 실행 시켜야
할떄가 있습니다. 그럴 떄 사용하는 명령어가 nexti입니다.
다음과 같이 사용할 수 있습니다.
nexti - 다음 명령어 까지 실행
ex)nexti : 다음 명령어 까지 실행
nexti 갯수 - 갯수 만큼의 명령어 실행
ex)nexti 5 : 5개의 명령어 실행
실제 사용해 보면 다음과 같습니다.
(gdb) nexti
0x0804845d in main ()
(gdb) nexti 5
0x08048477 in main ()
(gdb)
Cont
Debugging을 할때에 다음 BP까지의 명령들은 step by step을
건너 뛰고 싶을때 사용하는 명령어 입니다.
다음과 같이 사용할 수 있습니다.
cont - 다음 BP를 만날떄까지 실행
ex)cont - 다음 BP를 만날떄까지 실행
그 외의 명령어들
set - 특정한 값으로 변경 시킬때 사용합니다.
ex) set $eax=3 : eax의 값을 3으로 만듭니다.
quit - gdb를 종료합니다.
bt - 콜 스택을 보여줍니다.
cd - 작업 폴더 변경
pwd - 현재 폴더 출력
help - 도움말 정보를 출력합니다.