Gnu Debugger는 다음과 같은 구성으로 동작한다. 아래 그림 참고

    1. Target : 실제 debug 정보를 포함한 compile된 elf 정보(line number등을 포함)를 가지고 구동되는 device
    2. Host PC : 해당 device와 연결되어 있는 PC이며, terminal로 device를 제어하는 한다.
    3. GDB PC : GDB program이 구동되는 PC로 target에 탑재된 source를 가지고 있다.

따라서 2,3은 하나의 PC에서 처리가 가능하나, cross compile 환경에서 tool chain의 한계처럼 각기 다른 PC에서 처리되는 경우도 많다.
 
 

2번과 3번이 같으면 local debugging
2번과 3번이 다른 pc면 remote debugging
target remote IP:PORT 형식으로 연결되는데, remote debugging시 이부분에 port forwording을 한번더 적용된다.
 
 
로컬 디버깅시
가. gdbserver로 android process debug 시작

    1. 먼저 build된 full source를 준비한다.
    2. build한 source로 emul 혹은 target을 실행시킨다.
    3. local pc와 연결을 위해 adb 5039 port를 local 5039 port로 그대로 forwarding시킨다.

adb forward tcp:5039 tcp:5039

    1. debugging할 process를 선택(PID)한다. 이때 thread라면 PPID 까지 확인하여 어느 process인지 확인한다.

adb shell ps
adb shell ps -t [PID]  
USER PID PPID VSIZE RSS WCHAN PC NAME
system 60 33 190676 34764 ffffffff afd0db4c S system_server
 

    1. target내부에 존재하는 gdb server로 하여금 해당 process attach 시킨 후, 그 정보를 5039 port로 통신하도록 설정한다.

system server를 디버깅, background로 실행하면 좋다
adb shell gdbserver :5039 --attach 60 &

  • gdb server가 직접 프로그램을 실행하면서 디버깅을 시작할 수도 있다.
    adb shell gdbserver :5039 out/target/product/generic/system/bin/app_process [arguments]
  • 만약 zygote을 처음부터 디버깅 하려면
    service zygote /system/bin/gdbserver :5039 /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
     
    정리: 이제 target 설정은 마무리가 되었다. 위의 전 과정을 setup_gdb 로 가능(bashrc에 script추가한 경우)> setup_gdb
     
     
    나. GDB debugger(client)와 gdbserver와 연결
    1. full src에 이미 ndk dir에 같은 gdb version이 존재하나, window경우 같은 version의 ndk(gdb)를 설치해야 알맞은 정보를 얻어올 수 있다.

이때, windows경우 arm을 지원하는 windows용 tool chain을 골라야 한다. file 명령으로 format 확인
file arm-linux-androideabi-gdb.exe --> PE32 executable (console) Intel 80386 (stripped to external PDB), for MS Windows 라고 나오면 됨
/cygdrive/d/SDK/Android/android-ndk-r8b/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/arm-linux-androideabi-gdb.exe 가 존재
linux 경우 lunch를 실행하면 자동으로 ANDROID_TOOLCHAIN 환경변수에 gdb가 위치하는 dir가 잡힘
 

    1. source가 존재하는 서버에서 해당하는 gdb client로 원하는 process symbol을 debugging 시도

win> arm-linux-androideabi-gdb.exe out/target/product/generic/symbols/system/bin/app_process
linux> arm-linux-androideabi-gdb out/target/product/generic/symbols/system/bin/app_process
cgdb로 시작하려면 > cgdb -d + "위의 명령" 으로 하면 된다.

    1. 이제 gdb가 실행되었으므로 gdb에서 symbol 위치를 설정해놓는다.

set solib-absolute-prefix out/target/product/generic/symbols/

    1. 실제 so가 들어있는 lib위치를 설정한다

여기 여러 개의 so가 dir로 나눠져 있으므로 필요한 것은 반드시 추가한다. 이때 debug symbol이 있어야 하므로 symbols아래에 있는 것을 추가한다.
*set solib-search-path out/target/product/generic/symbols/system/lib:*
*out/target/product/generic/symbols/system/lib/hw:*
out/target/product/generic/symbols/system/lib/ssl/engines

    1. gdb client에서 위에서 설정된 환경을 가지고 이제 5039 port로 gdbserver와 실제로 통신하라고 말해준다.

target remote :5039
 
정리: 위의 전 과정을 gdbclient surfaceflinger로 가능, android root에서 lunch를 실행한 경우> gdbclient surfaceflingerbash script에 넣어놓은 것을 이용하는 경우> start_gdb out/target/product/generic/symbols/system/bin/surfaceflinger
 
다. GDB frontend로 디버깅 시작        

    1. 이제 gdb 연결이 된 상태로 gdb를 실행하면 되나, 여기서 gdb frontend를 붙이면 훨씬 디버깅이 쉽다

gdb frontend로는 DDD, insight, T32, windbg, emacs-gdb, gdbtui(emacs), cgdb(vi)등이 존재하며, 여기서는 가장 가벼운 cgdb를 추천한다.

    1. 이제 gdb 명령을 넣어 실행하면 된다.  

      명령

      설명

      b 'android::SurfaceFlinger::postFramebuffer()'

      break, namespace가 존재할때

      b SurfaceFlinger.cpp:519

      break, source 위치를 정확히 알때

      info b

      break를 num 순서대로 표시한다

      disable b 1

      num 1 break를 제거한다

      break InterpAsm-armv5te.S:10143

      assem break 걸기

      c //continue

      go

       
      example) DDD Debugger 사용시                
      앞의 단계) '나'에서 일반 gdb대신 DDD를 frontend로 설정한 경우
      > ddd -debugger arm-none-linux-gnueabi-gdb.exe out/target/product/generic/symbols/system/bin/app_process        
      이제 ddd가 실행되었으므로 gdb consol창에서 symbol 위치를 설정해놓는다.        
      set solib-absolute-prefix out/target/product/generic/symbols/
      실제 so가 들어있는 lib위치를 설정한다        
      set solib-search-path out/target/product/generic/symbols/system/lib
      set solib-search-path out/target/product/generic/symbols/system/bin
      gdb에게 설정된 환경을 loading하게 하고 5050 port와 통신하라고 말해준다.        
      target remote :5050
      break를 걸어 멈추게 한다        
      b 'android::SurfaceFlinger::postFramebuffer()'
       
      라. remote debugging                

    2. 위에서 remote debugging이 필요한 경우(target이 연결된 PC와 source가 존재하는 PC가 다른 경우) port forwarding을 이용하여 마치 같은 machine에 있는 것 처럼(local debugging 처럼) 동작시킬 수 있다.        

port forwarding
terminal에서 제공하는 것을 이용하는 경우 putty의 port forwarding이나 teraterm의 port forwarding을 이용가능, 여기서는 teraterm 이용
sshd/ssh-client가 설치된경우 "ssh -L 5039:localhost:5039 계정@서버주소" 로도 가능

    1. port forwarding 설정하기로, 위의 "나. GDB debugger(client)와 gdbserver와 연결" 단계 바로 전에 실행하면 된다.        

      putty를 사용한 경우

      teraterm을 사용한 경우


      R5039는 remote를 선택한 후 add해야함


       

    2. port forwarding 설정 확인하기

아래 처럼 gdb debugger가 깔린 pc(보통 서버)에서 실행하면 된다.
$ netstat -an |grep 503
tcp 0 0 127.0.0.1:5039 0.0.0.0:* LISTEN
tcp6 0 0 ::1:5039 :::* LISTEN
 
위와 같이 5039 port를 listen하고 있어야 한다. 참고로, target과 연결된 PC에서 위와 같은 terminal설정으로 연결하면, server는 자동으로 target과 연결된 pc의 port와 연결되게 된다.