這篇文章主要列舉了解決幾種斷點失效的經驗和方法,對於那些苦苦掙扎在莫名其妙的問題中的開發者也許有較大的幫助。 概述首先,讓我們看一下一個典型的包括本地代碼的Android應用的結構: 應用代碼被打包存放在一個.apk文件中,實際上,.apk文件就是一個ZIP格式壓縮包,壓縮包中包括一個classes.dex文件(所有的Java代碼都包含其中)和一個或更多存放在lib\<EABI名稱>目錄下的本地代碼庫文件。正常情況下,包含本地代碼的應用的工作步驟如下所述: 每個本地代碼庫都有兩個版本:
設置斷點 當你在源代碼文件中的某一行設置斷點時,GDB需要先進行一些操作才能真正的創建該斷點並且讓這個斷點可以背觸發。
這3步操作任意一步失敗,斷點就不會被創建,或者創建錯誤從而導致永遠都不會被觸發。我們在下一小節介紹這種問題的診斷方法以及如何修復它。 診斷問題本小節將詳細描述如何檢查由於不規範配置或文件缺失導致斷點失效的方法。 A. 確保庫文件已被加載 第一件要做的事情是確定本地代碼庫是不是已經被加載了,並且GDB是不是已經知道這件事情。我們可以在GDB中輸入“info shared”命令來查看。 info shared命令結果包含三個重要信息: From To Syms Read Shared Object Library 如果有些庫文件沒在這顯示出來,那麼可以通過”sharedlibrary”手動強制GDB重新加載一次符號表。 可以看到你項目的obj/local/armeabi目錄路徑被打印出來,該目錄下應該包含了帶有調試信息的.so文件,如果在該目錄下沒有.so文件的,那麼將正確的.so文件複製到該目錄下並重新運行”sharedlibrary”命令。 還有一個比較常見的導致斷點失效的原因是你再生成和調試項目時使用不同的目錄。舉個例子,如果你編譯庫文件時項目源代碼位於c:\projects,然後你又將源代碼移到d:\projects目錄下,這時在d:\projects\main.cpp文件中設置一個斷點就會失敗,GDB並不會使用d: \projects\main.cpp這個源文件替代原來目錄下的文件。像這一類問題都可以通過檢查源文件並且和設置斷點時的源文件做比較來解決,你可以先移除所有斷點,然後重新設置這些斷點,再看看你的IDE中顯示的GDB命令,看看到底是在哪個源文件中設置的斷點,是不是和生成庫文件時的源文件一致。 從上圖可以看到用來設置斷點的-break-insert命令可以顯示出你使用的源文件路徑,再使用”info sources”命令可以看看GDB真正發現的是哪些源文件。 將這條命令的輸出結果復製到一個文本編輯器中,然後再去查找你想調試的源文件(比如說說MyAndroidApp.c): 如果在輸出結果裡沒有你想要調試的源文件,那麼說明你家在的.so文件版本錯了(關於.so文件的版本問題見上一小節)。如果數據結果有你想要調試的文件,但是路徑和你使用-break-insert命令時顯示的源文件路徑不一致,這是你就需要再找找什麼原因了。這種情況下,在新路徑下重新編譯生成你的項目,或者將源文件放回到老的路徑下,這樣就可以保證你設置斷點的源文件和”info sources”命令輸出的源文件路徑保持一致了。 如果你設置了斷點,但是從來沒有生效,也有一種可能是你的Android應用加載的.so文件和你的GDB用來計算地址的.so文件版本不一致造成的。導致這種情況的最常見原因是Android加載時有bug,它沒有去加載armeabi-v7a目錄下的文件,而是加載了armeabi目錄下的庫文件。如果你覺得有可能是這個問題,試試修改編譯生成的配置,要么在armeabi平台編譯,要么在armeabi-v7a平台編譯,千萬不要同時再者兩個平台下編譯。(【譯者註】原作者前面沒有提到armeabi-v7a,現在突然冒出來了,armeabi和armeabi-v7a是不同的CPU類型,後者帶有包括浮點運算等其他功能,通過Android.mk文件中的target_cpu_api來指定,如果選擇了armeabi-v7a的話,前面提到的xxx\armeabi目錄都會變成xxx\armeabi-v7a,一個帶有NDK開發的Android項目中可能有多個Android.mk,原作者的意思就是所有的Android.mk文件的target_cpu_api設置都要一樣) |