1. 程式人生 > >GDB遠端除錯(二)之用gdb解決segmentation-fault段錯誤,看gdb的使用(嵌入式)

GDB遠端除錯(二)之用gdb解決segmentation-fault段錯誤,看gdb的使用(嵌入式)

最近在除錯程式碼的時候鬧人的segmentation-fault段錯誤,又來煩人了抓狂,不過程式碼都是自己寫的 ,有事也是作繭自縛,自作自受,先自責下敲打

來看看在串列埠段錯誤給了我們什麼資訊:


可以看出 Fault addr=0x328,出錯的地址在 0x328,這個哪 啊?可惜backtrace沒有給出execution path,哎,也不知道出在哪行程式碼了。得,自己發掘吧。

這裡我們可以先用addr2line工具看看能否找出出錯行,


只給出幾個問號,雞毛都沒有,這可能有兩種情況,一是編譯的時候沒加-g選項,另一個原因是0x328可能是系統函式的呼叫地址?反正就是沒有什麼資訊。

那麼還是編譯的時候先把-g加上吧,然後把gdb請出來。我們使用的是嵌入式環境,需要使用交叉編譯的gdb工具,這個過程就不說了,可以看另外一篇文章。

http://blog.csdn.net/mantis_1984/article/details/27494579

在target端用gdbserver 把應用程式掛起,監控:

./arm-arago-linux-gnueabi-gdbserver 192.168.1.100:2000 ./my_app &

然後在server端啟動gdb:


然後重複剛才出錯的時的操作,看看GDB會抓到什麼錯誤資訊:


好,gdb捕捉到了這個段錯誤資訊,接下來看看棧回溯資訊:


frame 0貌似沒有什麼資訊展示出來,那麼看看frame 1


可以看到frame 1呼叫棧在程式碼memcpy處進入的下一級 frame 0, 然後出錯,那基本上可以鎖定就是“

memcpy();這一行程式碼出現的問題,分別把變數dst和pst 打印出來,此時發現pst是不能訪問的記憶體,且此地址正是0x328,也就是前面所說串列埠包段錯誤的地址。

這句程式碼貌似沒什麼問題,此時分析問題就要結合程式碼的上下文以及其呼叫關係了。我們通過棧回溯可以追查到到底哪裡呼叫的這段程式碼。


程式碼太長,擷取一段說明問題出在哪裡,呼叫log_list_get_one_log後,獲取一條日誌在oneNode裡,但是連結串列中的oneNode->next也被獲取出來了,

下面在建立本地連結串列時給pst->next=NULL本沒有問題,可以後面的memcpy後把oneNode->next也賦值給了pst->next,這是我們不願意看到的,因為當本地釋放

pst後,會將glb_h_alarm_log中的那個next指標所指向的記憶體也釋放掉了,所以再次用獲取glb_h_alarm_log時會出現記憶體不可訪問的段錯誤(上面的0x328)不能

訪問,因為在外面已經被釋放。

所以說在使用連結串列,尤其是複製別的連結串列時,一定要小心處理這個next指標,很危險的。所以上面程式碼應該改成 memcpy這一行與pst->next=NULL交換,就沒有問題了。

問題比較隱蔽,沒有gdb,這個問題估計很難發現。