Linux C 跟蹤程式奔潰及函式呼叫關係

2021-07-10 06:40:50 字數 2479 閱讀 2047

在大型專案中,如果程式突然奔潰會是一件很頭疼的事,程式設計師很難去尋找導致奔潰的**,只能通過不斷的設定斷點或者列印訊息來慢慢的找到出錯位置,這會消耗程式設計師很大的精力和時間。所以很多公司都會有一套程式奔潰定位機制來找到奔潰函式和行數。目前常用的方法是生成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左右二進位制檔案 進行測試時,程式執行奇慢無比,甚至...