Andorid Studio NDK開發-LLDB除錯

姜家志發表於2017-03-28

LLDB是一個高效的c/c++的偵錯程式,是與LLVM編譯器一起使用,提供了豐富的流程控制和資料檢測,有效的幫忙我們除錯程式。LLDB也已經取代GDB成為XCode的預設偵錯程式,Android Studio中也可以使用LLDB除錯NDK程式,在Android Studio也中可以LLDB,從SDK Tools中下載LLDB最新版本,配合Android Studiogradle-experimental一起除錯NDK專案,會更加的方便。

LLDB安裝

Androis StudioToolbar中可以找到Android的更新圖示,開啟可以看到Android SDK的升級配置,在SDK Tools中可以找到LLDB的安裝選項。

Andorid Studio NDK開發-LLDB除錯
安裝LLDB

究竟如何使用LLDB除錯NDK程式呢?在上一篇的Andorid Studio NDK 開發 - NDK 開發利器 gradle-experimental中介紹了使用gradle-experimental可以簡化NDK的開發配置,其中提到了在執行選項中有兩個執行的配置選項appapp-native,其中的app-native就是用來執行和除錯JNI開發的。app-native不僅僅可以直接執行,也可以進行Debug,選中aap-native之後,直接選擇debug按鈕就可以進入NDK的Debug模式

Debug JNI

選擇app-native,點選debug按鈕可以直接進入Debug狀態,在一段程式碼處設定一個斷點,如圖所示:

Andorid Studio NDK開發-LLDB除錯
斷點

可以看到程式執行到斷點出,就進入了Debug狀態,在左側的狀態裡面可以看到變數的值和指標地址:

Andorid Studio NDK開發-LLDB除錯
變數資訊

程式進入了Debugz狀態,但是並沒有使用到LLDB,下面就使用下LLDB強大的功能。

使用LLDB

從上面的圖中可以看到除了Variables的Tab頁以外,還有一個Tab頁就是LLDB,點選進入可以看到(lldb)的命令列,在命令列裡面可以輸入LLDB的命令,LLDB命令有很多強大的能力,比如,列印,定址,呼叫堆疊等,通過這些命令可以有效的幫助除錯NDK程式。

Andorid Studio NDK開發-LLDB除錯
lldb

上圖中使用p(print)列印命令列印出了chars變數的內容,列印的內容包括變數的型別:char[10],變數的值:"i am test"。

LLDB常用命令

  • print (p)列印命令,列印變數以及其值:

    p chars
    (char [10]) $0 = "i am test"

  • po 僅列印變數的值:

    po chars
    "i am test"

  • call 就是呼叫的意思,上述po和p也有呼叫的功能。一般只在不需要顯示輸出,或是方法無返回值時使用。例如定義一個變數int p=0,使用call命令:

    call p++
    (int) $0 = 1

  • expr 可以在除錯時動態執行指定表示式,並列印結果,用於在除錯過程中修改變數的值
    比如我們在程式裡面定義int b=1;可以在斷點的時候使用expr更改其值。

    expr b=10
    (int) $0 = 10

  • bt 命令用來堆疊資訊,加all可列印所有thread的堆疊,比如我們增加一段導致崩潰的程式碼

    JNIEXPORT jstring JNICALL
    Java_com_jjz_NativeUtil_firstNative(JNIEnv *env, jclass type) {
      char chars[] = "i am test";
      int p=0;
      p=1/0;
      return (*env)->NewStringUTF(env, chars);
    }複製程式碼

    執行的時候出現了崩潰,這個時候執行bt命令,得到堆疊資訊:

    *thread #1, name = 'com.jjz', stop reason = signal SIGFPE
    * frame #0: 0xf6ff35e8 libc.so`tgkill + 12
      frame #1: 0xf6ff11ec libc.so`pthread_kill + 36
      frame #2: 0xf6fcd846 libc.so`raise + 14
      frame #3: libexperiment.so`__aeabi_idiv0 at lib1funcs.S:1337
      frame #4: libexperiment.so`Java_com_jjz_NativeUtil_firstNative(env=0xf4218ea0, type=0xff8b732c) at experiment.c:16
      frame #5: base.odex`java.lang.String com.jjz.NativeUtil.firstNative() at NativeUtil.java:0
      frame #6: base.odex`void com.jjz.MainActivity.onCreate(android.os.Bundle) at MainActivity.java:15
      frame #7: 0x729d58bf複製程式碼
  • image用於定址,可以用來查詢棧地址對應的程式碼位置,image命令有很多的引數,可以幫助我們更加清晰的定位問題,其中比較常用的是image lookup:

    image lookup --address 0xfxxxxx
    0xfxxxxx表示對應的棧地址,有了地址可以通過image lookup命令來檢視該棧地址上面對應的程式碼。

相關文章