[Linux] GDB 소개
GDB는 GNU Debugger의 약자로, Rechard Stallman이 개발했다. 많은 UNIX system에서 사용되는 free software다.
사용법
GDB는 gcc build 할 때 -g
option을 주고 나온 executable을 가지고 사용 할 수 있다.
$ gdb -g a.c -o a.out
그리고 gdb 수행 할 때 gcc 결과물을 넣어주면 된다. 만약 argument가 있다면 argument를 주고 실행하면 된다. 그 후 run (r)
을 치면 수행된다.
# gdb [executable] [arg0] [arg1] ... $ gdb a.out hello world ... (gdb) run
Function
GDB를 사용하는데 많은 기능들이 존재한다. 각 기능에 대해서 간략하게 아래 표로 설명할 수 있다.
Command (short key) | Description |
---|---|
file | 파일의 심볼을 읽음 |
run (r) | 파일 실행 |
break (b) | Break point 생성 |
info (i) | 각종 정보 표시 |
continue (c) | 계속 파일 실행 |
next (n) | 다음 라인 수행 |
step (s) | 함수 안으로 진입 |
print (p) | 변수를 출력 |
set | 변수 값 변경 가능 |
examine (x) | 메모리 내용 확인 |
list (l) | Source code를 출력 |
kill (k) | 프로그램 종료 |
watch (wa) | 특정 변수를 지속적으로 출력 |
delete (d) | Break point와 watch point 제거 |
backtrace (bt) | 프로그램이 중단되었을 때 stack frame 출력 |
display | 특정 변수를 매번 출력 |
u | 현재 loop을 빠져나감 |
finish | 현재 함수를 수행하고 빠져나감 |
return | 현재 함수를 수행하지 않고 빠져나감 |
step instruction (si) | 현재 instruction 수행하면서 함수로 진입 |
next instruction (ni) | 현재 instruction 수행 |
advance | 특정 포인트까지 진행 |
frame (f) | Backtrace 후 특정 frame으로 포커스 변경 |
thread | Thread switching |
attach | 현재 실행중인 프로그램을 디버깅 할 때 사용 |
disas | 특정 주소에 대해 disassembly 할 때 사용 |
layout | 각종 정보들 (register, assembly)를 한눈에 볼 수 있게 도움 |
Run
프로그램을 수행하는 명령어로, argument를 넣어서 수행 할 때도 사용된다.
# 1 $ gdb --args [executable] [arg0] [arg1] ... # 2 (gdb) r [arg0] [arg1]
Break Point
GDB 수행 중 특정 부분에서 멈추고자 할 때 사용된다. 아래의 코드를 예시를 들어본다.
#include <stdio.h> #include <stdlib.h> int sum(int, int); int main(int argc, char **argv) { int i; int j; int r; i = atoi(argv[1]); j = atoi(argv[2]); printf("Add from %d to %d\n", i, j); r = sum(i, j); printf("Sum = %d\n", r); return 0; } int sum(int from, int to) { int i; int total = 0; for (i=from; i<to; i++) { total += i; } return total; }
(gdb) r 2 3 (gdb) l 1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int sum(int, int); 5 6 int main(int argc, char **argv) 7 { 8 int i; 9 int j; 10 int r; (gdb) l 11 12 i = atoi(argv[1]); 13 j = atoi(argv[2]); 14 printf("Add from %d to %d\n", i, j); 15 r = sum(i, j); 16 printf("Sum = %d\n", r); 17 18 return 0; 19 } 20 (gdb) b 15 Breakpoint 1 at 0x5555555546de: file test.c, line 15. (gdb) i b Num Type Disp Enb Address What 1 breakpoint keep y 0x00005555555546de in main at test.c:15
위 코드에서 15번째 라인에 break point를 넣고 break point를 info (i)
command로 확인하는 모습이다. 그리고 수행하면 break point에서 멈추는 것을 확인 할 수 있고, continue (c)
command로 끝까지 수행 할 수 있다.
(gdb) r 2 3 Starting program: /home/shumin/workspace/03_System_Programming/00/a.out 2 3 Add from 2 to 3 Breakpoint 1, main (argc=3, argv=0x7fffffffe598) at test.c:15 15 r = sum(i, j);
Command | Description |
---|---|
b func | func 심볼의 시작 부분에 BreakPoint 설정 |
b 10 | 10행에 BreakPoint 설정 |
b file.c:func | file.c 파일의 func Symbol에 BreakPoint 설정 |
b file.c:10 | file.c 파일의 10행에 BreakPoint 설정 |
b +2 | 현재 행에서 2개 행 이후 지점에 BreakPoint 설정 |
b -2 | 현재 행에서 2개 행 이전 지점에 BreakPoint 설정 |
b *0x8049000 | 0x8049000 주소에 BreakPoint 설정(Assembly로 디버깅시 사용) |
b 10 if var == 0 | 10행에 BreakPoint를 설정하는데, var 변수의 값이 0일 때 작동 |
rb fun* | *fun*에 해당하는 모든 Symbol에 BreakPoint 설정 |
rb ^fun | fun으로 시작하는 모든 Symbol에 BreakPoint 설정 |
rb TestClass:: | TestClass에 해당하는 모든 Symbol에 BreakPoint 설정 |
Step
함수의 안으로 진입하고 싶을 때 사용하는 명령어다. 위 예시 코드를 계속 수행하면 아래와 같다.
(gdb) s sum (from=2, to=3) at test.c:24 24 int total = 0;
특정 변수 또는 함수의 결과를 출력하고 싶을 때 사용한다.
Command | Description |
---|---|
p var | var 변수의 값을 출력 |
p sum(1, 10) | sum(1, 10) 함수의 결과를 출력 |
p struct->var | 구조체 struct의 var 변수 출력 |
p (*pointer).var | 포인터에 접근해서 var 변수 출력 |
p (*pointer) | 구조체 전체를 출력 |
p $rip | 특정 register의 값 확인 |
실제로 함수 내부로 진입 후 함수의 argument의 값과, 함수를 호출한 결과를 출력할 수 있는 것을 볼 수 있다.
Next
Line by line으로 수행하고 싶을 때 사용한다. 뒤에 숫자를 넣어 여러 라인을 수행시킬 수 있다.
(gdb) n [number]
Set
특정 변수 또는 메모리의 값을 새로 변경할 때 사용한다.
set count = 10 | count 변수에 10을 저장 |
set {int}0x84aa_fa00 = 10 | 0x84aa_fa00 주소에 10을 저장 |
Examine
특정 주소의 메모리 값을 확인하는데 사용하는 명령어다.
x/[repeat count][format][unit size] [address]
Option | Description |
---|---|
Repeat count | 입력된 주소를 기준으로 연속된 address에 대해 repeat count만큼 데이터를 출력한다. Default value는 1이다. |
Format | x (hexa), d (decimal), u (unsigned decimal), o (octal), t , a , c , f , s (string), i (for machine instructions), m (for displaying memory tags) 다양한 포멧을 제공한다. Default는 h 다. |
Unit size | b : Bytes.h : Halfwords (two bytes).w : Words (four bytes). This is the initial default.g : Giant words (eight bytes). |
Command | Description |
---|---|
x 0x555555554717 | 0x555555554717 주소의 data 출력 |
x/i 0x555555554717 | 0x555555554717 주소의 data를 instruction으로 출력 |
x/4x 0x555555554717 | 0x555555554717 주소에 있는 data를 4 bytes씩 출력 |
x $rip | $rip에 저장된 주소가 가리키는 내부 값을 출력 |
아래 코드는 Program Counter (PC)가 가지고 있는 주소를 x
command를 통해 알아내는 방법이다.
(gdb) x $pc 0x555555554717 <sum+10>: 0x00fc45c7
참고로 출력하는 형식을 바꿀 수 있는데 다음과 같이 구성된다.
List
Source code를 출력하는데 사용한다.
Command | Description |
---|---|
l | main 함수를 기점으로 소스 출력 |
l 10 | 10 행을 기준으로 출력 |
l func | func 함수의 소스를 출력 |
l – | 출력된 행의 이전 행을 출력 |
l file.c:func | file.c 파일의 func 함수 부분을 출력 |
l file.c:10 | file.c 파일의 10행을 기준으로 출력 |
set listsize 20 | 출력 행이 10행에서 20행으로 증가 |
Info
각종 정보들을 출력한다.
Command | Description |
---|---|
i b | 등록된 BreakPoints와 watchpoints를 출력 |
i line | 현재 디버깅하과 있는 위치 정보를 출력 |
i program | 현재 프로그램의 process 정보를 출력 |
i args | 현재 함수로 넘어온 인자의 정보를 출력 |
i locals | 현재 함수의 지역 변수를 출력 |
i r | 레지스터 값 확인 |
i var | 모든 변수들 출력 |
i thread | 현재 동작하는 thread들의 정보를 출력 |
(gdb) i r rax 0xe 14 rbx 0x0 0 rcx 0x5555555546a0 93824992233120 rdx 0x7fffffffe518 140737488348440 rsi 0x7fffffffe508 140737488348424 rdi 0x1 1 rbp 0x7fffffffe420 0x7fffffffe420 rsp 0x7fffffffe400 0x7fffffffe400 r8 0x7ffff7dced80 140737351839104 r9 0x7ffff7dced80 140737351839104 r10 0x2 2 r11 0xffffffff 4294967295 r12 0x555555554540 93824992232768 r13 0x7fffffffe500 140737488348416 r14 0x0 0 r15 0x0 0 rip 0x555555554682 0x555555554682 <main+56> eflags 0x202 [ IF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0
Watch
Watch point를 정해 특정 변수가 바뀔 때 마다 break가 걸린다. 이때 해당 변수의 scope에서만 설정이 가능하다.
Command | Description |
---|---|
watch var | var 변수가 써질 때 실행을 중단 |
rwatch var | var 변수가 읽힐 때 실행을 중단 |
awatch var | var 변수가 읽고 써질 때 실행을 중단 |
Delete
Break point와 watch point 제거에 사용된다.
d 1 | 1번째 point 삭제 |
d 2 3 | 2, 3번째 point 삭제 |
(gdb) i b Num Type Disp Enb Address What 1 breakpoint keep y 0x00005555555546de in main at test.c:15 breakpoint already hit 1 time 2 breakpoint keep y 0x000055555555471e in sum at test.c:26 3 hw watchpoint keep y i (gdb) d 3 (gdb) i b Num Type Disp Enb Address What 1 breakpoint keep y 0x00005555555546de in main at test.c:15 breakpoint already hit 1 time 2 breakpoint keep y 0x000055555555471e in sum at test.c:26
Backtrace
어떤 과정을 거쳐 현재의 위치로 와 있는지 확인할 수 있으며, segment fault가 발생 했을 때 유용하다.
Display
특정 변수를 매번 출력할 때 사용한다.
Command | Description |
---|---|
display var | var 변수 값을 매번 화면에 출력 |
display /x var | var 변수 값을 16진수로 출력 |
undisplay 1 | 1번 display point를 제거 |
disable display 1 | 1번 display point를 비활성화 |
enable display 1 | 1번 display point를 활성화 |
Frame
backtrace를 보게되면 function call의 순서가 나열되며 여러 frame이 나오게 된다. 이 때 내가 특정 frame으로 이동해서 해당 frame의 변수를 frame 기능을 통해서 수행 가능하다.
Command | Description |
---|---|
f | 현재 frame 정보 출력 |
f 8 | backtrace 출력한 frame number 중 8번 frame으로 이동 |
Thread
Multi-thread 프로그램을 디버깅 할 때 사용되는 명령어다.
Command | Description |
---|---|
thread 2 | 2번 thread로 switching (Thread 정보를 알기 위해서 i thread 를 통해 알 수 있음) |
Attach
현재 실행중인 프로그램을 디버깅 할 때 사용하는 명령어다.
Command | Description |
---|---|
attach 2323 | PID 2323의 process를 gdb에 물림, 그러나 debug symbol이 없어서 사람 눈으로 보기 해석하기 어려움 (PID 정보를 알기 위해서 ps 명령어를 통해 알 수 있음) |
Layout
Command | Description |
---|---|
layout reg | 현재 시점에서 register 정보들을 한눈에 보여줌 |
layout asm | 현재 시점에서 assembly code를 한눈에 보여줌 |
참고로 끄는 방법은 Ctrl+x
+ a
다.
Core File
프로세스가 수행 중에 치명적인 예외가 발생해 더 이상 수행이 불가능할 때 생성된다. 예를 들면 0으로 나눈다던지, 잘못된 메모리 참조와 같은 상황에 발생한다.
예외 상황에 처하면 OS는 signal을 해당 프로세스에 보내고 시그널을 받은 프로세스는 kernel에 있는 기본 시그널 핸들러를 수행하는데, 기본 시그널 핸들러에서 core file로 저장하는 부분이 있다면 현재 수행 중인 프로세스의 이미지를 core file로 저장한다. 즉 Core file이란 문제가 발생해 프로세스가 종료되는 순간의 프로세스 이미지 파일로, 여기에는 종료 순간의 CPU context와 프로세스의 code 및 data, stack 등의 정보가 들어있어 debugging 하는데 유용하게 사용할 수 있다.
# gdb [executable file] [core dump] $ gdb a.out core
Reference
- https://en.m.wikipedia.org/wiki/GNU_Debugger