=============================

== gdb 7.11.1 명령어


** docker run 실행시 --security-opt seccomp=unconfined 옵션이 없으면 gdb에서 breakporint 를 못잡음

  (ex. docker run -it --name 컨테이너명 --security-opt seccomp=unconfined 이미지명)

 

gdb 잘 쓰기 : https://kldp.org/node/71806

gdb 잘 쓰기 user defined commands : https://kldp.org/node/87778 




** 실행

> gdb 프로그램명

> gdb 프로그램명 core파일명

> gdb 프로그램명 PID

(gdb) r 프로그램명

(gdb) r 프로그램명 인자1 인자2

(gdb) attach PID    # 실행중인 프로세스에 연결



** core 덤프 남기기 & 디버깅

// core file size 확인

> ulimit -a

    

// core file size 0인 경우 늘림

> ulimit -c unlimited

    

// core 파일 디버깅 (gdb 프로그램명 core 파일명)

> gdb ./app ./core




** 종료

(gdb) k   # 프로그램 수행 종료

(gdb) q   # gdb 종료

(gdb) $(ctrl+d)   # gdb 종료



** 소스보기

(gdb) l   # main 함수 부터 소스 출력(list)

(gdb) l 행번호   # 행 출력

(gdb) l 함수명   # 함수 출력

(gdb) l 파일명:함수명   # 파일의 함수 출력

(gdb) l 파일명:행번호   # 파일의 행 출력

(gdb) set listsize 행수   # 한번에 행 수 만큼 출력



** breakpoint 설정

(gdb) b 함수명

(gdb) b 행수

(gdb) b 파일명:함수명

(gdb) b +2    # 현재 행에서 2개 행 이후에 설정

(gdb) b -2     # 현재 행에서 2개 행 이전에 설정

(gdb) b *0x8000000  # 0x8000000 주소에 설정(어셈블리 디버깅시 사용)

(gdb) b 10 if var == 0  # 10행에 설정 및 var 변수가 0일때 동작

(gdb) condition 1 var == 0  # 1번 breakpoint 에 대해 var 변수가 0일때 동작



** breakpoint 삭제

(gdb) cl 함수명

(gdb) cl 행수

(gdb) cl 파일명:함수명

(gdb) cl 파일명:행수

(gdb) d   # 모든 breakpoint 삭제



** 디버깅

(gdb) s   # step : 현재 행 수행 후 중지. (함수의 경우 내부로 들어감)

(gdb) n   # next : 현재 행 수행 후 중지. (함수의 경우 내부로 들어가지 않음)

(gdb) c   # continue : 다음 breakpoint 까지 실행

(gdb) s 5  # step 명령어 5번 수행

(gdb) n 5  # next 명령어 5번 수행

(gdb) u   # 현재 루프 탈출

(gdb) finish  # 현재 함수 탈출

(gdb) return  # 함수 실행하지 않고 탈출

(gdb) return 123 # 함수 실행하지 않고 리턴값 123 으로 탈출

(gdb) si    # 현재 인스트럭션 수행(어셈블리 입장). 함수 호출 시 내부로 들어감

(gdb) ni    # 현재 인스트럭션 수행(어셈블리 입장). 함수 호출 시 내부로 들어가지 않음

(gdb) watch 변수명   # 변수값이 변경될때마다 breakpoint 걸림



** 디버깅 - 변수

(gdb) info locals   # 지역변수 출력

(gdb) info args   # 함수 인자 출력

(gdb) p 변수명   # 변수값 보기

(gdb) p *포인터변수명   # 포인터 변수값 보기

(gdb) p 함수명   # 함수 주소 보기

(gdb) p $eax    # 레지스트 값 출력 ($eax, $ebx, $ecx, $edx, $eip, ...)

(gdb) p *배열@4    # 배열 4개 출력

(gdb) p '파일명'::변수명    # 특정 변수 출력

(gdb) p '함수명'::변수명    # 특정 변수 출력

(gdb) p/x 변수명   # 변수를 16진수로 출력

  p/출력형식 변수명

  출력형식 : t(2진수), o(8진수), d(int형), u(uint형), x(16진수), c(최초1바이트 값을 문자형으로 출력), f(부동소수값), a(가장 가까운 심볼의 오프셋 출력)

(gdb) p (char*)변수명    # 타입 변환하여 출력

(gdb) p 포인터변수명 + 4    # 포인터변수에서 4바이트 떨어진 곳 부터 출력

(gdb) p var = 1000    # var 변수 값을 1000으로 설정

(gdb) display 변수명   # 디버깅 진행시 변수명 계속 출력

   display/출력형식 변수명   # 원하는 출력형식 지정(p 의 출력형식과 동일)

(gdb) undisplay 디스플레이번호  # 해당 번호의 display 설정을 해지

(gdb) disable display 디스플레이번호   # display 일시 중단

(gdb) enable display 디스플레이번호   # display 시작



** 스택

(gdb) bt   # backtrace : 스택 트레이스 출력

(gdb) i f   # info frame : 스택 상태 출력형식


  extended : 16 bit -> 32 bit 로 확장됨을 의미. 64bit는 r 이 붙음

  esp(extended stack pointer) : 현재 스택의 가장 위에 있는 데이터를 가리키는 포인터.

  ebp(extended base pointer) : 현재 스택의 바닥. 함수가 호출되거나 종료될때마다 달라짐.

  eip(extended instruction pointer) : 실행할 명령의 주소


(gdb)  frame [N]    # n번 스택 프레임으로 변경

(gdb) up    # 상위 스택 프레임으로 이동

(gdb) up [N]    # n번 상위 스택 프레임으로 이동

(gdb) down # 하위 스택 프레임으로 이동

(gdb) down [N]    # n번 하위 스택 프레임으로 이동



** 메모리

x/[범위][출력형식][범위단위]

  출력형식 : p 출력형식 포함, s(문자열), i(어셈블리)

  범위단위 : b(byte:1바이트), h(halfword:2바이트), w(word:4바이트), g(giant word:8바이트)

  

(gdb) x/10i main  # main 함수 시작부터 인스트럭션을 어셈블리로 변환하여 출력형식

(gdb) x/10b 0x8000000   # 0x8000000 번지부터 10바이트 출력



** 기타

(gdb) disas 함수명   # 함수를 어셈블리 코드로 출력

(gdb) disas 0x8000000 0x8000100    # 주소 범위의 서엠블리 코드 출력

(gdb) call 함수명(인자)    # 특정 함수 임의 호출

(gdb) jump *0x8000000   # 해당 주소로 무조건 점프

(gdb) signal SIGKILL    # 시그널 보내기(시그널 종류는 info signals 로 확인)

(gdb) set {int}0x8000000 = 100    # 해당 주소에 int 형으로 100 대입

  set {타입}주소 = 값

(gdb) set prompt ttt:   # 프롬프트를 ttt: 로 변경

(gdb) set print array on    # 배열 출력시 여러행 사용

(gdb) info functions    # 함수 리스트 출력

(gdb) info types    # 선언된 타입 출력



** 멀티스레드

(gdb) info threads    # 현재 동작중인 스레드 확인

(gdb) b [행번호] thread [스레드번호]    # 해당 스레드에 대해서만 동작

(gdb) thread [스레드번호]    # 현재 스레드를 변경될때마다



** 멀티프로세스

아래 명령어로 자식프로세스 디버깅

  > gdb 프로그램명 PID

혹은 (gdb) p pid = 0 으로 자식프로세스 제어흐름으로 가게끔 변경



** 소스 파일

> gdb -D=소스디렉토리 프로그램명   # 소스 디렉토리 지정하여 실행

(gdb) dir 디렉토리    # 소스 디렉토리 지정





=============================

== 기타 툴



** strace (systemcall tracer)

> apt-get install -y strace   # 설치

> strace -f 프로그램명   # -f : fork된 자식 프로세스 포함

> strace -fp PID    # 해당 PID 프로그램의 system call 확인



** ltrace (library call tracer)

공유 라이브러리만 가능. 정적 라이브러리(-static 컴파일) 는 아무런 정보도 못봄.

> apt-get install -y ltrace   # 설치

> ltrace -f 프로그램명   # -f : fork된 자식 프로세스 포함

> ltrace -fp PID    # 해당 PID 프로그램의 library call 확인



** splint (secure programmin lint)

c 소스 검사 유틸리티

> splint main.cpp



** valgrind (메모리 디버거)

> apt-get install -y valgrind   # 설치

> valgrind --leak-resolution=high --leak-check=yes -v ./프로그램파일명   # 메모리 관련 오류 분석









====================================

== 바이너리 유틸리티


** addr2line : 바이너리 파일에서 특정 주소가 어떤 파일/행인지 보여줌

  > addr2line -fe like 0x80484a0

  main

  /a/b/c/main.c:5


** ar : 정적 라이브러리 생성/수정

** as : GNU 어셈블러

** gprof : 프로파일 정보 출력

  > gcc -pg -o main main.c

    (-pg 로 프로파일 정보 생성하여 컴파일)

  > gprof -A ./main


** ld : GNU 링커(collect2 대신 사용 가능)

** nm : ELF 포멧 오브젝트 파일의 심볼 정보 출력

** objcopy : 오브젝트 파일 복사/변환

** objdump : 오브젝트 파일 덤프/역어셈

  > objdump -S main.o

    (-g 옵션으로 컴파일 필요)

  

** ranlib : 정적 라이브러리 내에 인덱스 생성

** size : 오브젝트 파일 사이즈 정보 출력

  > size main

    (text, data, bss, dec hex filename 출려)


** strip : 오브젝트 파일 사이즈 줄임

  > strip -R .note -R .comment -s main

  (-R 옵션으로 .note, .comment 영역 삭제)