如何輕鬆搞定 Segmentation fault ,看這篇就夠了!

我相信每個程序員年輕的時候,在運行某程序,當屏幕彈出“Segmentation fault”時,你會變得非常焦慮,因爲你不知道代碼哪裏跑掛了,初級程序員常常使用printf函數在懷疑點一個個的加打印去定位問題出在哪裏了。

 

如果你熟悉gdb,你可能會使用gdb去運行這個程序,然後異常後執行backtrace(簡寫bt)命令打印異常調用棧。

 

但是gdb並不是萬能的,例如程序運行一段時間概率出現“Segmentation fault”的問題,gdb就派不上用場了,我們期望故障復現後,立馬能把異常調用棧打印出來。

 

我們可以利用linux消息機制,例如給0地址賦值會觸發段錯誤,系統會收到SIGSEGV消息,我們給消息註冊回調函數,如下部分代碼實現這一需求。

 

下面我們可以在回調函數backtrace_handler中實現異常調用棧的打印。

 

常規的實現方式是利用backtrace和backtrace_symbols函數就可以實現異常調用棧的打印了,如下部分代碼實現這一需求。

 

爲了看到驗證結果,我們編寫測試代碼example.c,初始化時候調用backtrace_reg註冊函數,如下部分代碼實現這一需求。

 

我們使用gcc example.c  -g -o example編譯後運行,可以得到如下異常調用棧,

 

上面的地址看不懂怎麼辦?

 

可以藉助addr2line命令進行轉換,能夠轉換成功的前提是編譯的時候需要帶-g。這樣我們可以看到異常行號是63行,與實際代碼一致。

 

好了,這樣一個用戶態最基本的異常調用棧功能就實現了,但是這種方法也有缺陷,在你執行addr2line的時候,需要出錯的那個版本的可執行文件,有些情況下很可能出錯的版本和addr2line的版本不一致,翻譯不出正確的錯誤行號。

 

如何解決這個問題呢?把addr2line命令直接放到代碼中system執行?

 

這也太山寨了吧。

 

我們可以看看gdb源碼怎麼實現bt的,看看能不能對上面代碼做點優化?

 

預知詳情,請聽下回分解。

 

歡迎掃碼關注公衆號“嵌入式Linux技術分享”,一起學習Linux吧

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章