在大型專案中,如果程式突然奔潰會是一件很頭疼的事,程式設計師很難去尋找導致奔潰的**,只能通過不斷的設定斷點或者列印訊息來慢慢的找到出錯位置,這會消耗程式設計師很大的精力和時間。所以很多公司都會有一套程式奔潰定位機制來找到奔潰函式和行數。目前常用的方法是生成core檔案,然後再通過gdb除錯得到奔潰定位和函式的呼叫歷史,可以看文章《 linux 利用gdb進行程式奔潰定位 》。但如果環境中沒有gdb,那就抓瞎了。所以我們需要自己寫**來獲得和bt類似的功能。
linux中有幾個介面類似於gdb中的bt命令,可以獲取核心堆疊訊息:
int backtrace(void **buffer,int size)
char** backtrace_symbols (void *const *buffer, int size)
void backtrace_symbols_fd (void *const *buffer, int size, int fd)
具體可見:《linux下利用backtrace追蹤函式呼叫堆疊以及定位段錯誤》
但通過backtrace捕獲的堆疊訊息沒有具體的行號,其書寫形式也晦澀難懂,需要我們自己去解析。
源**見《 linux 利用gdb進行程式奔潰定位 》,通過backtrace獲得的原始資料為:
./kasen(_z12hpr_errtracei+0x5a)[0x402213]
/lib64/libc.so
.6(+0x35650)[0x7fec9e8e0650]
./libhello.so(_zn6chello4funcev+0x0)[0x7fec9f48b830]
./kasen(main+0x21)[0x401f1c]
/lib64/libc.so
.6(__libc_start_main+0xf5)[0x7fec9e8ccaf5]
./kasen[0x401df9]
資訊有:動態庫、執行檔案、函式、位址
通過上述資訊我們就可得到具體的奔潰的行號。
函式的呼叫關係其實就是乙個壓棧和出棧的順序,先壓進的後出,所以可以看到前面兩行和最後兩行是對稱的,其實這四行是比較固定的,我們可以忽略。我們主要解析中間的幾行:
./libhello.so(_zn6chello4funcev+0x0)[0x7fec9f48b830]
./kasen(main+0x21)[0x401f1c]
addr2line -e 可執行檔名(或者動態庫) 偏移位址
以上的命令對於執行檔案和動態庫的情況是不一樣的,如果是可執行檔案,其偏移位址就是上述[0x7fec9f48b830 ]中的位址,如果是動態庫的話,偏移位址還需要減去動態庫載入時的基位址。基位址的求解**為:
char* getbaseaddress(const
char* psoname)
\'", psoname, szfilename);
file* pfile = popen(szcmd, "r");
int n = fread(baseaddr, 1, 20,pfile);
baseaddr[n-1] = '\0';
return baseaddr;
}
int noffsetaddress = strtol(szstack, null, 16) - strtol(pbaseaddress, null, 16);
int noffsetaddress = strtol(szstack, null, 16);
char szcmd[128];
sprintf(szcmd, "addr2line -e %s 0x%x", psoname, noffsetaddress);
執行後,得到:
/mnt/shared/tmp/main/hello/hello.cpp:13
./libhello.so(_zn6chello4funcev+0x0)[0x7fec9f48b830]
./kasen(main+0x21)[0x401f1c]
括號中的即為函式名,只是這個函式名是c++風格的經過名稱修飾後的,我們可以根據這種風格進行解析得到函式名,如_zn6chello4funcev解析後得到chello::func(void);其他的一些例子如下:
int
func(int) ---------> _z4funci
float func(float) ---------> _z4funcf
int c::func(int) ---------> _zn1c4funcei
int c::c2::func(int) ---------> _zn1c2c24funcei
int n::func(int) ---------> _zn1n4funcei
程式奔潰的原因
常出現程式崩潰的幾種狀況1 記憶體越界 具體的 形式可為陣列下標越界和指標移動越界,在操作乙個陣列或是指標之前,要明確其邊界範圍,不應訪問不屬於系統分配的記憶體區域。2 指標為空 即此時通過指標訪問的記憶體位址為0,這個位址系統是不允許訪問的,系統也不會分配位址為0的記憶體給程式,這屬於一種特殊的記...
C 之程式奔潰建立DUMP檔案(VS2015)
注意一下自己vs的版本!以及編譯平台!本程式是基於 vs2015 版本,x86 建立標頭檔案dumpfile.h,將下列 放進檔案中 pragma once include include include include include using namespace std pragma comm...
C 中大量字串拼接導致程式執行過慢奔潰等問題
剛剛入職,需要根據給定的二進位制檔案翻譯成大白話文,涉及到了很多優先順序 幀號等等,前期程式設計過程中沒有過多的注意加上沒有拿實際資料測試,大量使用了拼接字串 在文字量or資料量很小的情況下執行很完美,幾乎沒什麼卡頓,最後拿採集到的實際資料 50m左右二進位制檔案 進行測試時,程式執行奇慢無比,甚至...