androidaddr2line
1. 如何定位Android NDK開發中遇到的錯誤
利用Android NDK開發本地應用時,幾乎所有的程序員都遇到過程序崩潰的問題,但它的崩潰會在logcat中列印一堆看起來類似天書的堆棧信息,讓人舉足無措。單靠添加一行行的列印信息來定位錯誤代碼做在的行數,無疑是一件令人崩潰的事情。在網上搜索「Android NDK崩潰」,可以搜索到很多文章來介紹如何通過Android提供的工具來查找和定位NDK的錯誤,但大都晦澀難懂。下面以一個實際的例子來說明,如何通過兩種不同的方法,來定位錯誤的函數名和代碼行。
首先,來看看我們在hello-jni程序的代碼中做了什麼(有關如何創建或導入工程,此處略),下面代碼中:在JNI_OnLoad()的函數中,即so載入時,調用willCrash()函數,而在willCrash()函數中, std::string的這種賦值方法會產生一個空指針錯誤。這樣,在hello-jni程序載入時就會閃退。我們記一下這兩個行數:在61行調用了willCrash()函數;在69行發生了崩潰。
下面我們來看看發生崩潰(閃退)時系統列印的logcat日誌:
如果你看過logcat列印的NDK錯誤的日誌就會知道,我省略了後面很多的內容,很多人看到這么多密密麻麻的日誌就已經頭暈腦脹了,即使是很多資深的Android開發者,在面對NDK日誌時也大都默默地選擇了無視。
其實,只要你細心的查看,再配合Google 提供的工具,完全可以快速地准確定位出錯的代碼位置,這個工作我們稱之為「符號化」。需要注意的是,如果要對NDK錯誤進行符號化的工作,需要保留編譯過程中產生的包含符號表的so文件,這些文件一般保存在$PROJECT_PATH/obj/local/目錄下。
第一種方法:ndk-stack
這個命令行工具包含在NDK工具的安裝目錄,和ndk-build及其他常用的一些NDK命令放在一起,比如在我的電腦上,其位置是/android-ndk-r9d/ndk-stack。根據Google官方文檔,NDK從r6版本開始提供ndk-stack命令,如果你用的之前的版本,建議還是盡快升級至最新的版本。使用ndk –stack命令也有兩種方式
實時分析日誌
在運行程序的同時,使用adb獲取logcat日誌,並通過管道符輸出給ndk-stack,同時需要指定包含符號表的so文件位置;如果你的程序包含了多種CPU架構,在這里需求根據錯誤發生時的手機CPU類型,選擇不同的CPU架構目錄,如:
當崩潰發生時,會得到如下的信息:
我們重點看一下#03和#04,這兩行都是在我們自己生成的libhello-jni.so中的報錯信息,因此會發現如下關鍵信息:
回想一下我們的代碼,在JNI_OnLoad()函數中(第61行),我們調用了willCrash()函數;在willCrash()函數中(第69行),我們製造了一個錯誤。這些信息都被准確無誤的提取了出來!是不是非常簡單?
先獲取日誌再分析
這種方法其實和上面的方法沒有什麼大的區別,僅僅是logcat日誌獲取的方式不同。可以在程序運行的過程中將logcat日誌保存到一個文件,甚至可以在崩潰發生時,快速的將logcat日誌保存起來,然後再進行分析,比上面的方法稍微靈活一點,而且日誌可以留待以後繼續分析。
第二種方法:使用addr2line和objmp命令
這個方法適用於那些不滿足於上述ndk-stack的簡單用法,而喜歡刨根問底的程序員們,這兩個方法可以揭示ndk-stack命令的工作原理是什麼,盡管用起來稍微麻煩一點,但可以稍稍滿足一下程序員的好奇心。
先簡單說一下這兩個命令,在絕大部分的linux發行版本中都能找到他們,如果你的操作系統是Linux,而你測試手機使用的是Intel x86系列,那麼你使用系統中自帶的命令就可以了。然而,如果僅僅是這樣,那麼絕大多數人要絕望了,因為恰恰大部分開發者使用的是Windows,而手機很有可能是armeabi系列。
在NDK中自帶了適用於各個操作系統和CPU架構的工具鏈,其中就包含了這兩個命令,只不過名字稍有變化,你可以在NDK目錄的toolchains目錄下找到他們。以我的Mac電腦為例,如果我要找的是適用於armeabi架構的工具,那麼他們分別為arm-linux-androideabi-addr2line和arm-linux-androideabi-objmp;位置在下面目錄中,後續介紹中將省略此位置:
假設你的電腦是Windows系統,CPU架構為mips,那麼你要的工具可能包含在一下目錄中:
接下來就讓我們來看看如何使用這兩個工具,下面具體介紹。
找到日誌中的關鍵函數指針
其實很簡單,就是找到backtrace信息中,屬於我們自己的so文件報錯的行。
首先要找到backtrace信息,有的手機會明確列印一行backtrace(比如我們這次使用的手機),那麼這一行下面的一系列以「#兩位數字 pc」開頭的行就是backtrace信息了。有時可能有的手機並不會列印一行backtrace,那麼只要找到一段以「#兩位數字 pc 」開頭的行,就可以了。
其次要找到屬於自己的so文件報錯的行,這就比較簡單了。找到這些行之後,記下這些行中的函數地址。
使用addr2line查找代碼位置
執行如下的命令,多個指針地址可以在一個命令中帶入,以空格隔開即可
結果如下:
從addr2line的結果就能看到,我們拿到了我們自己的錯誤代碼的調用關系和行數,在hello-jni.cpp的69行和61行(另外兩行因為使用的是標准函數,可以忽略掉),結果和ndk-stack是一致的,說明ndk-stack也是通過addr2line來獲取代碼位置的。
使用objmp獲取函數信息
通過addr2line命令,其實我們已經找到了我們代碼中出錯的位置,已經可以幫助程序員定位問題所在了。但是,這個方法只能獲取代碼行數,並沒有顯示函數信息,顯得不那麼「完美」,對於追求極致的程序員來說,這當然是不夠的。下面我們就演示一下怎麼來定位函數信息。
首先使用如下命令導出函數表:
在生成的asm文件中查找剛剛我們定位的兩個關鍵指針00004fb4和00004f58:
從這兩張圖可以清楚的看到(要注意的是,在不同的NDK版本和不同的操作系統中,asm文件的格式不是完全相同,但都大同小異,請大家仔細比對),這兩個指針分別屬於willCrash()和JNI_OnLoad()函數,再結合剛才addr2line的結果,那麼這兩個地址分別對應的信息就是:
相當完美,和ndk-stack得到的信息完全一致!
Testin崩潰分析如何幫開發者發現NDK錯誤
以上提到的方法,只適合在開發測試期間,如果你的應用或游戲已經上線,而用戶經常反饋說崩潰、閃退,指望用戶幫你收集信息定位問題幾乎是不可能的。這個時候,我們就需要用其他的手段來捕獲崩潰信息。
目前業界已經有一些公司推出了崩潰信息收集的服務,通過嵌入SDK,在程序發生崩潰時收集堆棧信息,發送到雲服務平台,從而幫助開發者定位錯誤信息。在這方面,國內的Testin和國外的crittercism都可以提供類似服務。
Testin從1.4版本開始支持NDK的崩潰分析,其最新版本已升級到1.7。當程序發生NDK錯誤時,其內嵌的SDK會收集程序在用戶手機上發生崩潰時的堆棧信息(主要就是上面我們通過logcat日誌獲取到的函數指針)、設備信息、線程信息等,SDK將這些信息上報至Testin雲服務平台,在平台進行唯一性的處理、並可以自定義時段進行詳盡的統計分析,從多維度展示程序崩潰的信息和嚴重程度;最新版本還支持用戶自定義場景,方便開發者定位問題所在。
從用戶手機上報的堆棧信息,Testin為NDK崩潰提供了符號化的功能,只要將我們編譯過程中產生的包含符號表的so文件上傳,就可以自動將函數指針地址定位到函數名稱和代碼行數。符號化之後,看起來就和我們前面在本地測試的結果是一樣的了,一目瞭然。而且使用這個功能還有一個好處:這些包含符號表的so文件,在每次開發者編譯之後都會改變,很有可能我們發布之後就已經變了,因為開發者會修改程序。在這樣的情況下,即使我們拿到了崩潰時的堆棧信息,那也無法再進行符號化了。我們可以將這些文件上傳到Testin進行符號化的工作,Testin會為我們保存和管理不同版本的so文件,確保信息不會丟失。
2. 有人知道怎麼把編譯路徑arm-linux-androideabi-4.6改成4.8的
1.將ndk中的arm-linux-androideabi-addr2line可執行文件的路徑加入配置文件~/.bashrc中,例如:exportPATH=$PATH:~/dlna/android-ndk-r6b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin2.使配置生效:source~/.bashrc3.使用工具。例如:arm-linux-androideabi-addr2line-C-f-e~/workspace/DLNA/libs/armeabi/libctrlpt.so0003deb4其中,0003deb4為堆棧信息中pc的值。android應用崩潰的調試方法有兩種方法可以分析crash的堆棧信息1google提供了一個python腳本,可以從/p/android-ndk-stacktrace-analyzer/下載這個python腳本,然後使用adblogcat-d>logfile導出crash的log,使用arm-eabi-objmp位於build/prebuilt/linux-x86/arm-eabi-4.2.1/bin下面把so或exe轉換成匯編代碼,如:arm-eabi-objmp-Smylib.so>mylib.asm,使用腳本pythonparse_stack.py2直接使用NDK下面的arm-linux-androideabi-addr2line(D:\android-ndk-r8\toolchains\arm-linux-androideabi-4.4.3\prebuilt\windows\bin\arm-linux-androideabi-addr2line.exe)例如:arm-linux-androideabi-addr2line-C-f-elibxxx.so0x#####(address)android調試工具addr2line使用補充使用addr2line追蹤自有動態庫(so文件)的bug,補充:解決出現??:0,沒法展示源代碼行數的問題在Android.mk文件中:Java代碼LOCAL_CFLAGS:=-D__STDC_CONSTANT_MACROS-Wl,-Map=test.map-g補充2個編譯參數-Wl,-Map=test.map-g.增加gcc警告和調試標志arm-linux-androideabi-addr2line-C-f-e/項目目錄/obj/local/armeabi/libfaa_jni.so0024362etip:1,注意調試文件的位置在obj目錄下,並非libs目錄下生成的so文件2,0024362e為出錯的機制位置還有:在jni/目錄下增加Application.mk文件,修改為debug模式,進行調試APP_OPTIM:=debug
3. addr2line,android,該怎麼解決
明顯:arm-linux-androideabi-g++找進入目錄:prebuilt/linux-x86/ccache/ccache prebuilt/linux-x86/toolchain/arm-linux-androideabi-4.4.x/bin/
看否文件或鏈接文件:
arm-linux-androideabi-addr2line arm-linux-androideabi-gprof
arm-linux-androideabi-ar arm-linux-androideabi-ld
arm-linux-androideabi-as arm-linux-androideabi-ld.bfd
arm-linux-androideabi-c++ arm-linux-androideabi-ld.gold
arm-linux-androideabi-c++filt arm-linux-androideabi-nm
arm-linux-androideabi-cpp arm-linux-androideabi-obj
arm-linux-androideabi-g++ arm-linux-androideabi-objmp
arm-linux-androideabi-gcc arm-linux-androideabi-ranlib
arm-linux-androideabi-gcc-4.4.3 arm-linux-androideabi-readelf
arm-linux-androideabi-gccbug arm-linux-androideabi-run
arm-linux-androideabi-gcov arm-linux-androideabi-size
arm-linux-androideabi-gdb arm-linux-androideabi-strings
arm-linux-androideabi-gdbtui arm-linux-androideabi-strip
特別看:arm-linux-androideabi-g++
若沒別(同事朋友邊拷份)份放若軟鏈接文件看看鏈接指向文件存存份放鏈接指向文件
4. 如何在Android studio下調試ndk
1.Library Symbols (共享庫的符號)
ndk提供了一些工具可以供程序員直接獲取到出錯的文件,函數以及行數。 但是這部分工具都需要沒有去符號的共享庫(通常是放在main/obj/local/armeabi-v7a)。而main/libs/armeabi-v7a中的共享庫是去掉了符號的,所以直接從設備上抓下來的lib是不能夠通過工具來找到對應的符號(而且沒有去symbol的庫比去掉的空間佔用會大許多)。所以如果想要分析一份native crash,那麼unstripped lib幾乎不可缺少,但是即使是strip過的庫也同樣會包含少量的symbol。
2.Analyze Tools
即常用的輔助工具
1、addr2line ((ANDROID_NDK)\toolchains\arm-Linux-androideabi-4.7\prebuilt\windows\bin)
#通過backtrace一欄提供的地址查詢對應的符號,可以定位到文件,函數,行數.
Usage: addr2line –aCfe libs(trace_address)
2、ndk-stack (android-ndk-r8d\ndk-stack)
#相當於執行多次addr2line, 可以直接針對一份crash log使用,會輸出所有backtrace里地址對應的symbol
Usage: ndk-stack –sym (libdirectory)–mp(crash_log_file)
5. 如何定位Android NDK開發中遇到的錯誤
如果你看過logcat列印的NDK錯誤的日誌就會知道,我省略了後面很多的內容,很多人看到這么多密密麻麻的日誌就已經頭暈腦脹了,即使是很多資深的Android開發者,在面對NDK日誌時也大都默默地選擇了無視。
其實,只要你細心的查看,再配合Google 提供的工具,完全可以快速地准確定位出錯的代碼位置,這個工作我們稱之為「符號化」。需要注意的是,如果要對NDK錯誤進行符號化的工作,需要保留編譯過程中產生的包含符號表的so文件,這些文件一般保存在$PROJECT_PATH/obj/local/目錄下。
第一種方法:ndk-stack
這個命令行工具包含在NDK工具的安裝目錄,和ndk-build及其他常用的一些NDK命令放在一起,比如在我的電腦上,其位置是/android-ndk-r9d/ndk-stack。根據Google官方文檔,NDK從r6版本開始提供ndk-stack命令,如果你用的之前的版本,建議還是盡快升級至最新的版本。使用ndk –stack命令也有兩種方式
實時分析日誌
在運行程序的同時,使用adb獲取logcat日誌,並通過管道符輸出給ndk-stack,同時需要指定包含符號表的so文件位置;如果你的程序包含了多種CPU架構,在這里需求根據錯誤發生時的手機CPU類型,選擇不同的CPU架構目錄,如:
當崩潰發生時,會得到如下的信息:
我們重點看一下#03和#04,這兩行都是在我們自己生成的libhello-jni.so中的報錯信息,因此會發現如下關鍵信息:
回想一下我們的代碼,在JNI_OnLoad()函數中(第61行),我們調用了willCrash()函數;在willCrash()函數中(第69行),我們製造了一個錯誤。這些信息都被准確無誤的提取了出來!是不是非常簡單?
先獲取日誌再分析
這種方法其實和上面的方法沒有什麼大的區別,僅僅是logcat日誌獲取的方式不同。可以在程序運行的過程中將logcat日誌保存到一個文件,甚至可以在崩潰發生時,快速的將logcat日誌保存起來,然後再進行分析,比上面的方法稍微靈活一點,而且日誌可以留待以後繼續分析。
第二種方法:使用addr2line和objmp命令
這個方法適用於那些不滿足於上述ndk-stack的簡單用法,而喜歡刨根問底的程序員們,這兩個方法可以揭示ndk-stack命令的工作原理是什麼,盡管用起來稍微麻煩一點,但可以稍稍滿足一下程序員的好奇心。
先簡單說一下這兩個命令,在絕大部分的Linux發行版本中都能找到他們,如果你的操作系統是Linux,而你測試手機使用的是Intel x86系列,那麼你使用系統中自帶的命令就可以了。然而,如果僅僅是這樣,那麼絕大多數人要絕望了,因為恰恰大部分開發者使用的是Windows,而手機很有可能是armeabi系列。
在NDK中自帶了適用於各個操作系統和CPU架構的工具鏈,其中就包含了這兩個命令,只不過名字稍有變化,你可以在NDK目錄的toolchains目錄下找到他們。以我的Mac電腦為例,如果我要找的是適用於armeabi架構的工具,那麼他們分別為arm-linux-androideabi-addr2line和arm-linux-androideabi-objmp;位置在下面目錄中,後續介紹中將省略此位置:
假設你的電腦是Windows系統,CPU架構為mips,那麼你要的工具可能包含在一下目錄中:
接下來就讓我們來看看如何使用這兩個工具,下面具體介紹。
找到日誌中的關鍵函數指針
其實很簡單,就是找到backtrace信息中,屬於我們自己的so文件報錯的行。
首先要找到backtrace信息,有的手機會明確列印一行backtrace(比如我們這次使用的手機),那麼這一行下面的一系列以「#兩位數字 pc」開頭的行就是backtrace信息了。有時可能有的手機並不會列印一行backtrace,那麼只要找到一段以「#兩位數字 pc 」開頭的行,就可以了。
其次要找到屬於自己的so文件報錯的行,這就比較簡單了。找到這些行之後,記下這些行中的函數地址。
使用addr2line查找代碼位置
執行如下的命令,多個指針地址可以在一個命令中帶入,以空格隔開即可
結果如下:
從addr2line的結果就能看到,我們拿到了我們自己的錯誤代碼的調用關系和行數,在hello-jni.cpp的69行和61行(另外兩行因為使用的是標准函數,可以忽略掉),結果和ndk-stack是一致的,說明ndk-stack也是通過addr2line來獲取代碼位置的。
6. 如何使用arm-linux-androideabi-addr2line
1.將ndk中的arm-linux-androideabi-addr2line可執行文件的路徑加入配置文件~/.bashrc中,例如:
export PATH=$PATH:~/dlna/android-ndk-r6b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin
2.使配置生效:source ~/.bashrc
3.使用工具。例如:arm-linux-androideabi-addr2line -C -f -e ~/workspace/DLNA/libs/armeabi/libctrlpt.so 0003deb4
其中,0003deb4為堆棧信息中pc的值。
android應用崩潰的調試方法
有兩種方法可以分析 crash 的堆棧信息
1 google提供了一個python腳本,可以從
http://code.google.com/p/android-ndk-stacktrace-analyzer/
下載這個python腳本,然後使用 adb logcat -d > logfile 導出 crash 的log,
使用 arm-eabi-objmp 位於build/prebuilt/linux-x86/arm-eabi-4.2.1/bin下面
把so或exe轉換成匯編代碼,如:arm-eabi-objmp -S mylib.so > mylib.asm,
使用腳本
python parse_stack.py <asm-file> <logcat-file>
2 直接使用NDK下面的arm-linux-androideabi-addr2line
(D:\android-ndk-r8\toolchains\arm-linux-
androideabi-4.4.3\prebuilt\windows\bin\arm-linux-androideabi-addr2line.exe)
例如:arm-linux-androideabi-addr2line -C -f -e libxxx.so 0x#####(address)
android調試工具addr2line使用補充
使用addr2line追蹤自有動態庫(so文件)的bug, 補充:
解決出現 ??:0 , 沒法展示源代碼行數的問題
在Android.mk 文件中:
Java代碼
LOCAL_CFLAGS
:=
-D__STDC_CONSTANT_MACROS
-Wl,-Map=test.map
-g
補充2個編譯參數 -Wl,-Map=test.map -g .
增加gcc警告和調試標志
arm-linux-androideabi-addr2line -C -f -e /項目目錄/obj/local/armeabi/libfaa_jni.so 0024362e
tip: 1,注意調試文件的位置在obj目錄下,並非libs目錄下生成的so文件
2,0024362e 為出錯的機制位置
還有:
在jni/目錄下增加Application.mk 文件, 修改為debug 模式,進行調試 APP_OPTIM := debug
7. 如何定位Android NDK開發中遇到的錯誤法
Android NDK定義:
Android NDK 是在SDK前面又加上了「原生」二字,即Native Development Kit,因此又被Google稱為「NDK」。眾所周知,Android程序運行在Dalvik虛擬機中,NDK允許用戶使用類似C / C++之類的原生代碼語言執行部分程序。
常見的NDK類型異常會導致程序錯誤:
NDK編譯生成的。so文件作為程序的一部分,在運行發生異常時同樣會造成程序崩潰。
不同於Java代碼異常造成的程序崩潰,在NDK的異常發生時,程序在Android設備上都會立即退出,即通常所說的閃退,而不會彈出「程序xxx無響應,是否立即關閉」之類的提示框。
NDK是使用C/C++來進行開發的,熟悉C/C++的程序員都知道,指針和內存管理是最重要也是最容易出問題的地方,稍有不慎就會遇到諸如內存無效訪問、無效對象、內存泄露、堆棧溢出等常見的問題。
在程序的某個位置釋放了某個內存空間,而後在程序的其他位置試圖訪問該內存地址,這就會產生無效地址錯誤。
發現並解決NDK錯誤:
ndk-stack。
這個命令行工具包含在NDK工具的安裝目錄,和ndk-build及其他常用的一些NDK命令放在一起。根據Google官方文檔,NDK從r6版本開始提供ndk-stack命令。
使用addr2line和objmp命令。
這個方法適用於那些不滿足於上述ndk-stack的簡單用法,在NDK中自帶了適用於各個操作系統和CPU架構的工具鏈,其中就包含了這兩個命令,只不過名字稍有變化,可以在NDK目錄的toolchains目錄下找到。
注意:以上提到的方法,只適合在開發測試期間,如果應用或游戲已經上線,而用戶經常反饋說崩潰、閃退,指望用戶收集信息定位問題幾乎是不可能的。這個時候,就需要用其他的手段來捕獲崩潰信息。
8. 如何使用arm-linux-androideabi-addr2line 查看函數名
1.將ndk中的arm-Linux-androideabi-addr2line可執行文件的路徑加入配置文件~/.bashrc中,例如:
export PATH=$PATH:~/dlna/Android-ndk-r6b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin
2.使配置生效:source ~/.bashrc
3.使用工具。例如:arm-linux-androideabi-addr2line -C -f -e ~/workspace/DLNA/libs/armeabi/libctrlpt.so 0003deb4
其中,0003deb4為堆棧信息中pc的值。
9. 關於Android JNI 編程如何定位段錯誤的問題(addr2line的使用)求答案
今天在此總結一下:
1.普通的應用程序或者靜動態庫,如果你想用addr2line
來定位段錯誤出在哪一行,請記住在編譯它們的時候一定加上編譯選項
-g
它會生成symbols信息
在你的exe
or
lib
裡面。
2.NDK編譯生成靜動態庫就沒有必要在Android.mk的編譯選項裡面加-g了,應為ndk默認就會生成symbols,這個是我做實驗得出來的結論。你可以在與jni平行的一層目錄中找到libs
和
objs文件夾
在這兩個文件夾裡面分別可以找到程序運行需要的動態庫和含symbols信息的動態庫。
至於addr2line的使用方法
,我在這里也啰嗦一句
addr2line
-e
xxxx.so
[報段錯誤的地址]
庫就是地址後面跟的庫
就說這么多唄!