[C/C++] GDB 사용법

Eugene CHOI·2022년 2월 11일
0

C/C++

목록 보기
8/9
  • 이 포스트는 Kali-Linux 환경에서 수행한 결과입니다.
  • 명령어 앞에 (gdb)가 붙은 것은 gdb 명령어임을 의미합니다. 실제로 명령어를 칠 때는 (gdb)를 빼고 입력합니다.
  • 명령어 앞에 $가 붙은 것은 shell 명령어임을 의미합니다.실제로 명령어를 칠 때는 $를 빼고 입력합니다.
  • 앞에 아무 표시 없이 적힌 블럭은 입력한 명령어의 출력 문구입니다.

What is GDB


GDB란 GNU DeBugger의 약자로 GNU 소프트웨어를 위한 기본 디버거라는 의미입니다.

GDB가 지원하는 언어는 다양합니다.
Ada, Assembly, C, C++, D, Fortran, Go, Objective-C, OpenCL, Modula-2, Pascal, Rust

Installation

한 줄이면 쉽게 설치할 수 있습니다.

sudo apt install gdb

Command

gdb는 기본적으로 AT&T문법을 따릅니다. 하지만 intel 문법이 보기 좋기 때문에 intel 문법으로 변경하고 시작합니다.

(gdb) set disassembly-flavor intel

.gitconfig나 .bashrc처럼 gdb쉘이 시작할 때 자동으로 실행되는 initial script 파일이 있습니다. 경로는 ~/.gdbinit입니다.
따라서 위 명령어를 매번 입력하기 싫다면 다음 명령어를 입력하여 스크립트를 추가해줍니다.

$ echo set disassembly-flavor intel >> ~/.gdbinit

잘 적용되었는지 확인하려면 다음 명령어를 입력하면 됩니다.

(gdb) show disassembly-flavor

제 터미널 출력은 다음과 같습니다.

The disassembly flavor is "intel".

gdb

GDB를 시작하려면 바이너리명을 인수로 주면 됩니다.

$ gdb "binary_name"

GDB를 종료하려면 q를 입력하면 됩니다.

(gdb) q

현재 터미널에서 실행하고 있는 프로그램이 있을 때 Ctrl+Z를 누르면 suspend가 되고 bg명령어를 치면 background에서 실행시킬 수 있습니다.

ps를 입력하면 현재 실행 중인 process를 볼 수 있습니다.

break

break point를 주려면 break 명령을 사용하면 됩니다. b라고만 해도 동작합니다.

(gdb) b "function_name"

Example

(gdb) b *main
Breakpoint 1 at 0x4005bd

특정 지점에 break point를 주려면 +"line_number"를 이어적으면 됩니다.

(gdb) b "function_name"+"line_number"

Example

(gdb) b *main+8
Breakpoint 2 at 0x4005c5

b *main에 비해 8증가 된 주소값을 볼 수 있습니다.

또한 특정 주소를 이용하여 break point를 걸 수도 있습니다.

(gdb) b "address"

Example

(gdb) b *0x00000000004005bd
Breakpoint 3 at 0x4005bd

EIP, RIP를 알고 있다면 현재 주소에 상대적인 주소값을 이용하여 break point를 지정할 수도 있습니다.

(gdb) b -10

run

GDB에서 바이너리를 실행하려면 run을 입력하면 됩니다. 인수를 줄 수도 있습니다.

(gdb) run "arguments"

break point가 걸려 있는 상태에서 run을 하면 break point에서 일시정지가 됩니다.
계속 진행을 하려면 continue의 약자 cont를 입력하면 됩니다.

(gdb) cont

break point가 걸려 있는 상태에서 계속 진행하지 않고 한 step만 진행하려면 ni명령어를 사용합니다.

(gdb) ni

info

어떤 break point가 있는지 확인하려면 info b 명령을 사용하면 됩니다.

(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000004005bd <main>
2       breakpoint     keep y   0x00000000004005c5 <main+8>

바이너리를 실행 중에 레지스터를 보려면 info reg 명령어를 사용합니다.

(gdb) info reg

바이너리를 실행 중에 특정 레지스터를 확인하려면 다음 명령어를 사용합니다.
레지스터는 항상 $기호를 붙입니다. 레스터 이름 대신 메모리 주소를 입력해도 됩니다.

(gdb) info reg "register_name"
commandmeanresult
(gdb) x/t $rsp2진법0x7fffffffdea0: 11111111111111111101111110100000
(gdb) x/o $rsp8진법0x7fffffffdea0: 037777757640
(gdb) x/d $rsp10진법0x7fffffffdea0: -8288
(gdb) x/u $rsp16진법0x7fffffffdea0: 4294959008
(gdb) x/x $rspchar0x7fffffffdea0: 0xffffdfa0
(gdb) x/c $rspfloat0x7fffffffdea0: -96 '\240'
(gdb) x/f $rspfloat0x7fffffffdea0: 6.9533558074255227e-310
(gdb) x/s $rspstring0x7fffffffdea0: "\240\337\377\377\377\177
(gdb) x/bx $rsp1바이트0x7fffffffdea0: 0xa0
(gdb) x/bx $rsp2바이트0x7fffffffdea0: 0xa0
(gdb) x/wx $rsp4바이트0x7fffffffdea0: 0xffffdfa0
(gdb) x/gx $rsp8바이트0x7fffffffdea0: 0x00007fffffffdfa0

예를 들어 x/bx에서 x/bx 사이에 숫자 N을 넣으면 N만큼 연속으로 읽으라는 의미입니다.

(gdb) x/10bx $rsp
0x7fffffffdea0: 0xa0    0xdf    0xff    0xff    0xff    0x7f    0x00    0x00
0x7fffffffdea8: 0x00    0x00

delete

특정 break point를 삭제하려면 delete 명령어와 함께 info에서 확인한 break point의 번호를 적으면 됩니다.

(gdb) delete 2

그냥 delete라고만 치면 모든 break point를 삭제할 수 있습니다.

(gdb) delete
Delete all breakpoints? (y or n)

Register

namemeans
ripinstruction pointer
esp
profile
Hi, my name is Eugene CHOI the Automotive MCU FW developer.

0개의 댓글