指令碼命令 如何寫gdb命令指令碼

2021-10-16 02:26:01 字數 4003 閱讀 2202

作者|nanxiao

編輯|包包   

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

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

define commandname      statement      ......  end
其中statement可以是任意gdb命令。此外自定義命令還支援最多10個輸入引數:$arg0,$arg1 …… $arg9,並且還用$argc來標明一共傳入了多少引數。

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

#include int global = 0;int fun_1(void)int fun_a(void)int main(void)
首先編譯成可執行檔案:

gcc -g -o test test.c
接著用gdb進行除錯:

可以看到使用bt(backtrace縮寫)命令可以列印當前執行緒的呼叫棧。我們的第乙個自定義命令就是也實現乙個backtrace功能:

define mybacktrace    btend
怎麼樣?簡單吧,純粹復用gdb提供的命令。下面來驗證一下:

(gdb) define mybacktracetype commands for definition of "mybacktrace".end with a line saying just "end".>bt>end(gdb) mybacktrace#0  fun_a () at test.c:12#1  0x0000000000400500 in main () at test.c:18
功能完全正確!

接下來定義乙個賦值命令,把第二個引數的值賦給第乙個引數:

define myassign    set var $arg0 = $arg1end
執行一下:

(gdb) define myassigntype commands for definition of "myassign".end with a line saying just "end".>set var $arg0 = $arg1>end(gdb) myassign global 3(gdb) p global$1 = 3
可以看到global變數的值變成了3。

對於自定義命令來說,傳進來的引數只是進行簡單的文字替換,所以你可以傳入賦值的表示式,甚至是函式呼叫:

(gdb) myassign global fun_1()(gdb) p global$2 = 1
可以看到global變數的值變成了1。

除此以外,還可以為自定義命令寫幫助文件,也就是執行help命令時列印出的資訊:

document myassign    assign the second parameter value to the first parameterend
執行help命令:

(gdb) document myassigntype documentation for "myassign".end with a line saying just "end".>assign the second parameter value to the first parameter>end(gdb) help myassignassign the second parameter value to the first parameter
可以看到列印出了myassign的幫助資訊。

(二) 命令指令碼

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

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

(1)條件命令:if...else...end。這個同其它語言中提供的if命令沒什麼區別,只是注意結尾的end。

(2)迴圈命令:while...end。gdb同樣提供了loop_break和loop_continue命令分別對應其它語言中的break和continue,另外同樣注意結尾的end。

另外gdb還提供了很多輸出命令。比方說echo命令,如果僅僅是輸出一段文字,echo命令特別方便。此外還有和c語言很相似的支援格式化輸出的printf命令,等等。

指令碼檔案的注釋也是以#開頭的,這個同很多其它指令碼語言都一樣。

最後指出的是在gdb中執行指令碼要使用source命令,例如:「source ***.gdb」。

(三) 乙個完整的例子

最後以乙個完整的gdb指令碼(search_byte.gdb)做例子,來總結一下本文提到的內容:

define search_byte    if $argc != 3        help search_byte    else        set $begin_addr = $arg0        set $end_addr = $arg1        while $begin_addr <= $end_addr            if *((unsigned char*)$begin_addr) == $arg2                printf "find it!the address is 0x%x\n", $begin_addr                loop_break            else                set $begin_addr = $begin_addr + 1            end        end        if $begin_addr > $end_addr            printf "can't find it!\n"        end    endenddocument search_byte    search a specified byte value(0 ~ 255) during a memory    usage: search_byte begin_addr end_addr byteend
這個指令碼定義了search_byte命令,目的是在一段指定記憶體查詢乙個值(unsigned char型別):需要輸入記憶體的起始位址,結束位址和要找的值。

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

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

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

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

另外這個指令碼還定義了search_byte的幫助資訊。

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

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

受篇幅所限,本文只是對gdb命令指令碼做了乙個粗淺的介紹,旨在起到拋磚引玉的效果。

如果大家想更深入地了解這部分知識,可以參考gdb手冊的相關章節:extending gdb (最後向大家推薦乙個github上的.gdbinit

參考文獻:

(1)extending gdb (

(2)捉蟲日記(

如何寫 如何寫好指令碼?

好的指令碼當然要有好的開場白 好的開題 破題 話題引入,好的敘述與分析 好的結束語。好的指令碼還應有好的輔助說明的素材,700 800字的指令碼,對應的素材數量如下 非真人出鏡者 素材數量需要翻倍,最好找到超過20個素材。寫好指令碼還應注意以幾點 一 開門見山 快速切入主題,這樣的話就更容易讓觀眾對...

架構指令碼如何寫

首先我們看看遊戲主要是由哪幾部分組成的,如下圖所示,任何平台下的任何遊戲核心都是由 資料 邏輯 渲染三大部分組成。當你寫過 2個平台下的遊戲時你會發現其實遊戲開發很 容易 為什麼 容易 呢?因為此時你會發現所有平台下開發遊戲的模式,如下圖中的 資料 與 邏輯 兩部分真的是完全一樣的,這兩部分是與遊戲...

shell指令碼 命令

命令連線符 表示不管前面是否執行成功都要執行 表示前面執行成功才執行後面 表示前面執行失敗才執行後面 read命令 read 選項 值 read p 提示語句 n 字元個數 t 時間秒 s 不顯示 運算子 expr 3 2 結果賦值 sum expr 3 2 或者 sum 3 2 乘法expr 3 ...