天天看點

如何寫gdb指令腳本

作為unix/linux下使用廣泛的調試器,gdb不僅提供了豐富的指令,還引入了對腳本的支援:一種是對已存在的腳本語言支援,比如python,使用者可以直接書寫python腳本,由gdb調用python解釋器執行;另一種是指令腳本(command file),使用者可以在腳本中書寫gdb已經提供的或者自定義的gdb指令,再由gdb執行。在這篇文章裡,我會介紹一下如何寫gdb的指令腳本。

(一) 自定義指令

gdb支援使用者自定義指令,格式是:

其中<code>statement</code>可以是任意gdb指令。此外自定義指令還支援最多10個輸入參數:<code>$arg0</code>,<code>$arg1</code> …… <code>$arg9</code>,并且還用<code>$argc</code>來标明一共傳入了多少參數。

下面結合一個簡單的c程式(test.c),來介紹如何寫自定義指令:

首先編譯成可執行檔案:

接着用gdb進行調試:

可以看到使用<code>bt</code>(<code>backtrace</code>縮寫)指令可以列印目前線程的調用棧。我們的第一個自定義指令就是也實作一個<code>backtrace</code>功能:

怎麼樣?簡單吧,純粹複用gdb提供的指令。下面來驗證一下:

功能完全正确!

接下來定義一個指派指令,把第二個參數的值賦給第一個參數:

執行一下:

可以看到<code>global</code>變量的值變成了<code>3</code>。

對于自定義指令來說,傳進來的參數隻是進行簡單的文本替換,是以你可以傳入指派的表達式,甚至是函數調用:

可以看到<code>global</code>變量的值變成了<code>1</code>。

除此以外,還可以為自定義指令寫幫助文檔,也就是執行<code>help</code>指令時列印出的資訊:

執行<code>help</code>指令:

可以看到列印出了<code>myassign</code>的幫助資訊。

(二) 指令腳本

首先對于指令腳本的命名,其實gdb沒有什麼特殊要求,隻要檔案名不是gdb支援的其它腳本語言的檔案名就可以了(比如.py)。因為這樣做會使gdb按照相應的腳本語言去解析指令腳本,結果自然是不對的。

其次為了幫助使用者寫出功能強大的腳本,gdb提供了如下的流程控制指令:

(1)條件指令:<code>if...else...end</code>。這個同其它語言中提供的<code>if</code>指令沒什麼差別,隻是注意結尾的<code>end</code>。

(2)循環指令:<code>while...end</code>。gdb同樣提供了<code>loop_break</code>和<code>loop_continue</code>指令分别對應其它語言中的<code>break</code>和<code>continue</code>,另外同樣注意結尾的<code>end</code>。

另外gdb還提供了很多輸出指令。比方說<code>echo</code>指令,如果僅僅是輸出一段文本,<code>echo</code>指令特别友善。此外還有和c語言很相似的支援格式化輸出的<code>printf</code>指令,等等。

腳本檔案的注釋也是以<code>#</code>開頭的,這個同很多其它腳本語言都一樣。

最後指出的是在gdb中執行腳本要使用source指令,例如:“source xxx.gdb”。

(三) 一個完整的例子

最後以一個完整的gdb腳本(search_byte.gdb)做例子,來總結一下本文提到的内容:

這個腳本定義了<code>search_byte</code>指令,目的是在一段指定記憶體查找一個值(<code>unsigned char</code>類型):需要輸入記憶體的起始位址,結束位址和要找的值。

指令邏輯可以分成3個部分:

(a) 首先判斷輸入參數是不是3個,如果不是,就輸出幫助資訊;

(b) 從起始位址開始查找指定的值,如果找到,列印位址值并退出循環,否則把位址加1,繼續查找;

(c) 如果在指定記憶體區域沒有找到,列印提示資訊。

另外這個腳本還定義了<code>search_byte</code>的幫助資訊。

仍然以上面的c程式為例,來看一下如何使用這個gdb腳本:

可以看到<code>global</code>的值是<code>0</code>,起始位址是<code>0x600900</code>,結束位址是<code>0x600903</code>。在<code>global</code>的記憶體區域查找<code>0</code>成功,查找<code>1</code>失敗。

受篇幅所限,本文隻是對gdb指令腳本做了一個粗淺的介紹,旨在起到抛磚引玉的效果。如果大家想更深入地了解這部分知識,可以參考gdb手冊的相關章節:extending gdb (https://sourceware.org/gdb/onlinedocs/gdb/extending-gdb.html)。最後向大家推薦一個github上的.gdbinit檔案:https://github.com/gdbinit/gdbinit/blob/master/gdbinit,把這個弄懂,相信gdb腳本檔案就不在話下了。