본문 바로가기

Programming/Linux Tip

GDB 명령어

아래 사이트에서 조금 도움을 받았다.

하지만, 잘못된 정보나 보충할 부분도 있어서 추가해 본다.

http://hoyeden.blog.me/20206894205

http://kthan.tistory.com/entry/Linux%EB%A6%AC%EB%88%85%EC%8A%A4-%EB%94%94%EB%B2%84%EA%B9%85%EC%9D%84-%EC%9C%84%ED%95%9C-gdb-%EC%82%AC%EC%9A%A9%EB%B2%95-%EB%B0%8F-%EB%AA%85%EB%A0%B9%EC%96%B4-%EC%A4%91%EA%B8%89


사용을 하려면 먼저 대상이 되는 process 를 

-g 옵션으로 컴파일 해야 한다.


대상 process 가 다수의 parameter(argument) 으로 실행된다면, 아래와 같이 --args 키워드를 입력하면 된다.

gdb --args gcc -02 -c foo.c



[root@DD root]# gdb -q file

(gdb)

 

* -q 쓰는 이유 : 안쓰면 지저분한 설명들이 주루룩 나온다.




disassemble 하기.

(gdb) disassemble main


아래와 같이 asm 으로 풀어서 나온다.

Breakpoint 2, android::vold::Disk::readPartitions (this=0xb46e9200) at system/vold/Disk.cpp:248

warning: Source file is more recent than executable.

248         LOG(WARNING) << "readPartitions()++";

(gdb) disassemble android::vold::Disk::readPartitions

Dump of assembler code for function android::vold::Disk::readPartitions():

   0xb6eeee48 <+0>:     stmdb   sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}

   0xb6eeee4c <+4>:     sub     sp, #4

   0xb6eeee4e <+6>:     vpush   {d8}

   0xb6eeee52 <+10>:    sub     sp, #232        ; 0xe8

   0xb6eeee54 <+12>:    ldr.w   r6, [pc, #1848] ; 0xb6eef590

...



종료

(gdb) quit 


모든 함수 리스트 출력하기 & 함수의 주소값

info functions





브레이크 걸기

break *main+0

 : 상대주소(offset)앞에 별을 붙이면 된다.


break : 특정 위치에 브레이크 포인트 설정


예) break func : func 함수의 시작위치에 설정
     break 123   : 123번째 줄에 설정
     break main.c:func  : main.c 파일의 func 함수의 시작 위치에 설정
     break 123 if i == 1  : i값이 1 일때 123번째 줄에 설정


1.2 rbreak :정규표현식(regular expression)을 사용해 여러 심볼에 브레이크포인트 설정


예) rbreak ^func : fun로 시작하는 모든 심볼에 설정
     rbreak func : func를 포함하는 모든 심볼에 설정 





브레이크 상태 확인. 

info breakpoints

info b 





 

브레이크 포인트 지우기 / 비활성화

del (브레이크 포인터 번호)

 : 앞에 붙은 넘버를 통해서 삭제.

ex) del 2

 : 그냥 del 하면 한번에 다 지움.


clear :특정 브레이크포인트 지우기 

     예) clear func : func 함수에 설정한 브레이크포인트 지움
          clear 123  : 123번째 줄에 설정한 브레이크포인트 지움


enable/disable breakpoints :특정 브레이크 포인트 활성화/비활성화 


예) disable breakpoints : 모든  브레이크포인트 비활성화

     disable breakpoints 1,2,5 : 1,2,5번 브레이크 포인트 비활성화 (info b로 조회한 브레이크포인트 숫자)

     enable breakpoints : 모든  브레이크포인트 활성화

     enable breakpoints 1,2,5 : 1,2,5번 브레이크 포인트 활성화 


delete :설정한 모든 브레이크포인트를 지움



프로세스 시작하면서 디버깅 시작

run






다음 라인으로 이동

next





다음 브레이크 포인터 까지 실행

countinue


동작중인 프로세스에 attach 하면 block 상태가 된다.

디버깅을 시작할때 c 를 입력한다.





info 명령어

info <출력할 타입>: 특정 타입의 info 정보를 출력.
(gdb에서 info를 입력하고 Tab키를 누르면 조회 가능한 모든 값들을 볼 수 있음. )


예) info locals : 지역 변수와 값 출력 
     info variables : 전역 변수와 값 출력 
     info registers : 레지스터의 값 출력
     info frame: 스택 프레임 정보 출력
     info thread: 스레드별 정보 출력

      info stack: call stack 출력 == bt



print 명령어


print/[출력 형식] (형 변환)[변수] : 특정 변수 값을 원하는 포맷으로 출력 

  • 출력 형식:
    t: 2진수
    o: 8진수
    d: int형 10진수
    u: unsigned int형 10진수
    x: 16진수
    c: 1 바이트를 char형 
    f: float형 

예) print/x lval : lval를 16진수로 출력 
     print (char *) str : str변수를 "char *" 타입으로 변환 후 출력           

  • 다양한 값 지정 

예) print array@12   : 크기가 12인 array라는 배열을 출력           
    print func::value  : func라는 함수에 있는 value라는 변수 출력 

 




display 명령어


display <lvalue> : s(step)명령 수행시 매번 lvalue값을 출력

enable/disable display <display번호> : 설정한 번호의 display를 활성화/비활성화 


display 변수를 해제하기 위해서는 undisplay 명령어를 이용한다.

    (gdb) undisplay [N]

display 역시 x,c,o 등등을 이용해 다양한 형태로 출력 가능하다.



watch 명령어


와치포인트는 변수값의 변화와 코드의 변화를 확인할때 편리하게 이용가능하다.

    (gdb) watch [변수명]   //변수에 값이 써질 때 브레이크
    (gdb) rwatch [변수명]  //변수의 값이 읽혀질 때 브레이크

    (gdb) awatch [변수명]  //변수에 읽기, 쓰기 경우에 브레이크


단, optimized out 된 변수들은 사용할 수 없다.


(gdb) i locals

cmd = <optimized out>

output = <optimized out>

res = <optimized out>

foundParts = <optimized out>

table = <optimized out>


만약 optimize 를 하기 싫다면, makefile 에 -O0 옵션을 추가 하거나 아래와 같이 함수를 컴파일 명령어로 감싸준다.


If you can't or don't want to disable optimization, then you can try declaring the variable as volatile. This is usually enough to make your compiler preserve the variable in the final code.

Alternatively, in recent GCC versions you can disable optimization for just a function, like this:

void my_function() __attribute__((optimize(0)))
{
  int x = floor(sqrt(3));
}

list 명령어


list  : 소스 리스트 출력  


예) list    : 현재 실행중인 위치 주변의 소스 출력 
     list func : func 함수의 주변의 소스 출력  
     list 199 : 199 라인 주변의 소스 출력  
     list main.c:main  :  main.c 함수의 main함수 주변의 소스 출력  
     list main.c:199    : main.c 함수의 199 라인 주변의 소스 출력   

  • 보여지는 라인 수 설정 
  예) (gdb) set listsize 20 : list 명령어로 보여지는 라인수를 20줄로 변경


전체 레지스터의 값 보기

info register 

 : BUT !! 반드시 특정 위치에 브레이크가 걸려있어야 한다.

 

 

x/x (주소값)

 : ("16진수의주소값" / "원하는주소값")

 : 주소값에 들어있는 내용을 16진수로 보기.

 

 

x/s (주소값)

 : 주소값의 내용을 string형태로 보기

 ex) x/10s 0x00844001

 

 

x/d (주소값) 

 : 10진수로 보기

 

 

x/x $esp

 : esp에 들어있는 값 보기.

 : $eax하면 eax값도 볼수있고.

 : x/x $ebp-20 ⇒ 이렇게 상대값으로도 볼수있다.




스택프레임간 이동


frame [n] : n번째 스택 프레임으로 이동
up [n] : n번째 상위 스택으로 이동
down [n] : n번째 하위 스택으로 이동



원문 : http://kwanseob.blogspot.kr/2012/03/gdb.html




GDB 사용법


*참조도서: "유닉스 리눅스 프로그래밍 필수 유틸리티"

GDB 사용 방법

<<실행>>
GDB를 이용하기 위해서는 컴파일 과정에서 디버깅 정보를 삽입해야 한다.

    컴파일 시 옵션 'g' 이용
    $ gcc -g -o main main.c

컴파일이 정상 종료 되면 GDB를 실행한다.

    gdb [프로그램명]
    $ gdb main
    gdb [프로그램명] [프로세스PID]
    $ gdb main 1928

GDB가 정상 실행되면 터미널의 프롬프트가 (gdb)로 바뀌게 된다.

<<종료>>
종료방법에는 크게 두가지가 있다.

    ctrl + d
    (gdb) q
    (gdb) quit

<<소스보기>>
옵션에 따라 실행중인 프로그램의 소스를 다양한 방법으로 볼 수 있다.

    l(list)
    list 10
    list [함수명]
    list -  //이전 10라인을 출력한다.
    list [파일명]:[함수명]
    list [파일명]:10

list 명령어를 사용하면 소스코드가 10줄 단위로 출력된다.
다음의 명령을 통해 출력단위를 변경할 수 있다.

    set listsize 20

<<세그멘테이션 폴트가 발생했을대>>
컴파일한 프로그램을 실행했을때 segmentation fault 가 발생하여
비정상 종료되었다면 다음의 명령어를 통해 오류 지점을 확인할 수 있다.

    (gdb) r(run)

run 명령어는 GDB가 프로그램을 실행시켜 이상이 발생했을때의 파일과 지점을 출력해준다.
또한 관련 함수 또는 변수에 담긴 값을 출력하여 오류수정에 많은 도움을 준다.

오류 지점에 도달하기 전 과정을 확인하기 위해서는 다음 명령어를 이용하면 된다.

    (gdb) bt

bt명령어는 백트레이스로 프로그램 스택을 역으로 탐색한다.

<<브레이크포인트>>
브레이크포인트는 다음의 방법들을 통해 설정 가능하다.

    (GDB) b(break) [함수명]
    (GDB) break 10
    (GDB) break [파일명]:[함수명]
    (GDB) break [파일명]:10
    (GDB) break +2  //현재 행에서 2개 행 이후 브레이크포인트 설정
    (GDB) break -2  //현재 행에서 2개 행 이전 브레이크포인트 설정
    (GDB) break *0x8049000  //메모리주소에 설정(어셈블리로 디버깅시 이용)
    (GDB) break 10 if var == 0  //var 변수의 값이 0일때 10번 행에 설정

브레이크포인트의 발동 조건은 다양하게 변경 가능하다.

    (GDB) condition [N] var == 0   //var변수가 0일때 N번 브레이크포인트 동작
    (GDB) condition [N] func(i) > 5

현재 설정된 브레이크포인트의 목록은 다음의 명령으로 확인 가능하다.

    (GDB) info break

브레이크포인트는 GDB가 종료될때까지 유효하다.
따라서 필요없을때는 다음의 방법들을 통해 설정을 지운다.

    (GDB) cl(clear) [함수명]
    (GDB) clear 10
    (GDB) clear [파일명]:[함수명]
    (GDB) clear [파일명]:10
    (GDB) d   //모든 브레이크포인트 지움
    (GDB) disable br  //모든 브레이크포인트 비활성화
    (GDB) disable br 1 3  //1번, 3번 브레이크포인트 비활성화
    (GDB) ensable br  //모든 브레이크포인트 활성화
    (GDB) ensable br 1 3  //1번, 3번 브레이크포인트 활성화

<<프로그램 실행>>
프로그램의 실행은 run 명령어를 이용한다.
만일 이미 실행중일때는 재실행한다.

    (gdb) r(run)

프로그램 실행시 인자를 지정하기 위해서는 다음과 같이 이용한다.

    (gdb) run arg1 arg2

실행중인 프로그램을 종료할 때는 kill 명령어를 이용한다.

    (gdb) k(kill)

현재 실행중인 행의 수행을 멈추기 위해서는 step 명령어를 이용한다.
step 명령어는 한행씩 동작하도록 한다. next 명령어와는 함수 호출시 다른 결과를 보인다.

    (gdb) s(step)
    (gdb) step 6   //step을 6번 수행

현재 행의 실행이 멈춘상태에서 다음 행을 실행하기 위해서는

    (gdb) n(next)
    (gdb) next 6   //next를 6번 수행

만일 step명령을 이용중 루프에 빠져 나오지 못할경우에는 until 명령어를 이용한다.

    (gdb) u(until)

한행씩이 아닌 다시 연달아서 실행하기 위해서는

    (gdb) c(continue)

함수가 매우 길어 끝나는 지점으로 이동하기 위해서는 finish 명령어를 사용한다.

    (gdb) finish

함수의 남은 부부을 수행하지 않고 빠져나오기 위해서는 return 명령어를 사용한다.

    (gdb) return

return 명령어를 사용시 return 값을 임의로 지정하기 위해서는 다음과 같이 이용한다.

    (gdb) return 1234



<<변수와 레지스터 값 검사>>
현재 위치한 행에서 접근 가능한 지역변수들 목록 확인

    (gdb) info locals

현재 위치한 행에서 접근 가능한 전역변수들 목록 확인

    (gdb) info variables

확인하고싶은 변수의 값을 출력하기 위해서는 print 명령어를 사용한다.

    (gdb) p(print) [변수명]  //변수의 값
    (gdb) print [함수명]   //함수의 주소 값

포인터 변수의 경우 위의 방법으로 하면 주소값만이 출력된다.
포인터 변수의 값 또는 포인터 구조체 등의 값을 보기 위해서는 * 를 붙여준다.

    (gdb) print *[변수명]

이중 포인터라면 ** 를 붙여준다.

GDB는 변수 뿐만 아니라 레지스터의 값도 확인할 수 있다.

    (gdb) print $[레지스터명]

print 명령어는 지역변수를 우선하여 보여주기 때문에
지역변수와 전역변수에서 동일한 이름을 사용할때 전역변수를 확인하기 위해서는 :: 을 이용한다.

    (gdb) print 'main.c'::[변수명]

파일명은 '따옴표' 으로 감싸야한다.

특정 함수에 있는 변수를 확인하기 위해서는

    (gdb) print [함수명]::[변수명]

print 명령어로 변수 또는 레지스터를 확인할 때는 기본적으로 10진수로 출력한다.
이를 다른 형식으로 보고싶을 때는 다음과 같은 방법을 이용한다.

    (gdb) print/t [변수명]    //2진수로
    (gdb) print/o [변수명]    //8진수로
    (gdb) print/d [변수명]    //10진수로 (int)
    (gdb) print/u [변수명]    //부호없는 10진수로 (unsigned int)
    (gdb) print/x [변수명]    //16진수로
    (gdb) print/c [변수명]    //최초 1바이트 값을 문자형으로
    (gdb) print/f [변수명]    //부동소수점값
    (gdb) print/a [변수명]    //가장 가까운 심볼의 오프셋

print 명령어는 값을 보여줄뿐 아니라 값을 설정하는 것도 가능하다.

    (gdb) print [변수명] = [값]