天天看點

用GDB調試程式(五)

檢視運作時資料

———————

    在你調試程式時,當程式被停住時,你可以使用print指令(簡寫指令為p),或是同義指令inspect來檢視目前程式的運作資料。print指令的格式是:

    print <expr>

    print /<f> <expr>

        <expr>是表達式,是你所調試的程式的語言的表達式(GDB可以調試多種程式設計語言),<f>是輸出的格式,比如,如果要把表達式按16進制的格式輸出,那麼就是/x。

一、表達式

    print和許多GDB的指令一樣,可以接受一個表達式,GDB會根據目前的程式運作的資料來計算這個表達式,既然是表達式,那麼就可以是目前程式運作中的const常量、變量、函數等内容。可惜的是GDB不能使用你在程式中所定義的宏。

    表達式的文法應該是目前所調試的語言的文法,由于C/C++是一種大衆型的語言,是以,本文中的例子都是關于C/C++的。(而關于用GDB調試其它語言的章節,我将在後面介紹)

    在表達式中,有幾種GDB所支援的操作符,它們可以用在任何一種語言中。

    @

        是一個和數組有關的操作符,在後面會有更詳細的說明。

    ::

        指定一個在檔案或是一個函數中的變量。

    {<type>} <addr>

        表示一個指向記憶體位址<addr>的類型為type的一個對象。

二、程式變量

    在GDB中,你可以随時檢視以下三種變量的值:

        1、全局變量(所有檔案可見的)

        2、靜态全局變量(目前檔案可見的)

        3、局部變量(目前Scope可見的)

    如果你的局部變量和全局變量發生沖突(也就是重名),一般情況下是局部變量會隐藏全局變量,也就是說,如果一個全局變量和一個函數中的局部變量同名時,如果目前停止點在函數中,用print顯示出的變量的值會是函數中的局部變量的值。如果此時你想檢視全局變量的值時,你可以使用“::”操作符:

        file::variable

    function::variable

    可以通過這種形式指定你所想檢視的變量,是哪個檔案中的或是哪個函數中的。例如,檢視檔案f2.c中的全局變量x的值:

    gdb) p 'f2.c'::x

    當然,“::”操作符會和C++中的發生沖突,GDB能自動識别“::” 是否C++的操作符,是以你不必擔心在調試C++程式時會出現異常。

    另外,需要注意的是,如果你的程式編譯時開啟了優化選項,那麼在用GDB調試被優化過的程式時,可能會發生某些變量不能通路,或是取值錯誤碼的情況。這個是很正常的,因為優化程式會删改你的程式,整理你程式的語句順序,剔除一些無意義的變量等,是以在GDB調試這種程式時,運作時的指令和你所編寫指令就有不一樣,也就會出現你所想象不到的結果。對付這種情況時,需要在編譯程式時關閉編譯優化。一般來說,幾乎所有的編譯器都支援編譯優化的開關,例如,GNU的C/C++編譯器GCC,你可以使用“-gstabs”選項來解決這個問題。關于編譯器的參數,還請檢視編譯器的使用說明文檔。

三、數組

    有時候,你需要檢視一段連續的記憶體空間的值。比如數組的一段,或是動态配置設定的資料的大小。你可以使用GDB的“@”操作符,“@”的左邊是第一個記憶體的位址的值,“@”的右邊則你你想檢視記憶體的長度。例如,你的程式中有這樣的語句:

        int *array = (int *) malloc (len * sizeof (int));

    于是,在GDB調試過程中,你可以以如下指令顯示出這個動态數組的取值:

        p

*array@len

    @的左邊是數組的首位址的值,也就是變量array所指向的内容,右邊則是資料的長度,其儲存在變量len中,其輸出結果,大約是下面這個樣子的:

        (gdb) p

        $1 = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40}

    如果是靜态數組的話,可以直接用print數組名,就可以顯示數組中所有資料的内容了。

四、輸出格式

    一般來說,GDB會根據變量的類型輸出變量的值。但你也可以自定義GDB的輸出的格式。例如,你想輸出一個整數的十六進制,或是二進制來檢視這個整型變量的中的位的情況。要做到這樣,你可以使用GDB的資料顯示格式:

    x  按十六進制格式顯示變量。

    d  按十進制格式顯示變量。

    u  按十六進制格式顯示無符号整型。

    o  按八進制格式顯示變量。

    t  按二進制格式顯示變量。

    a  按十六進制格式顯示變量。

    c  按字元格式顯示變量。

    f  按浮點數格式顯示變量。

        (gdb) p i

        $21 = 101   

        (gdb) p/a i

        $22 = 0x65

        (gdb) p/c i

        $23 = 101 'e'

        (gdb) p/f i

        $24 = 1.41531145e-43

        (gdb) p/x i

        $25 = 0x65

        (gdb) p/t i

        $26 = 1100101

五、檢視記憶體

    你可以使用examine指令(簡寫是x)來檢視記憶體位址中的值。x指令的文法如下所示:

    x/<n/f/u> <addr>

    n、f、u是可選的參數。

    n 是一個正整數,表示顯示記憶體的長度,也就是說從目前位址向後顯示幾個位址的内容。

    f 表示顯示的格式,參見上面。如果位址所指的是字元串,那麼格式可以是s,如果地十是指令位址,那麼格式可以是i。

    u 表示從目前位址往後請求的位元組數,如果不指定的話,GDB預設是4個bytes。u參數可以用下面的字元來代替,b表示單位元組,h表示雙位元組,w表示四位元組,g表示八位元組。當我們指定了位元組長度後,GDB會從指記憶體定的記憶體位址開始,讀寫指定位元組,并把其當作一個值取出來。

    <addr>表示一個記憶體位址。

    n/f/u三個參數可以一起使用。例如:

    指令:x/3uh 0x54320 表示,從記憶體位址0x54320讀取内容,h表示以雙位元組為一個機關,3表示三個機關,u表示按十六進制顯示。

六、自動顯示

    你可以設定一些自動顯示的變量,當程式停住時,或是在你單步跟蹤時,這些變量會自動顯示。相關的GDB指令是display。

    display <expr>

    display/<fmt> <expr>

    display/<fmt> <addr>

    expr是一個表達式,fmt表示顯示的格式,addr表示記憶體位址,當你用display設定好了一個或多個表達式後,隻要你的程式被停下來,GDB會自動顯示你所設定的這些表達式的值。

    格式i和s同樣被display支援,一個非常有用的指令是:

        display/i $pc

    $pc是GDB的環境變量,表示着指令的位址,/i則表示輸出格式為機器指令碼,也就是彙編。于是當程式停下後,就會出現源代碼和機器指令碼相對應的情形,這是一個很有意思的功能。

    下面是一些和display相關的GDB指令:

    undisplay <dnums...>

    delete display <dnums...>

    删除自動顯示,dnums意為所設定好了的自動顯式的編号。如果要同時删除幾個,編号可以用空格分隔,如果要删除一個範圍内的編号,可以用減号表示(如:2-5)

    disable display <dnums...>

    enable display <dnums...>

    disable和enalbe不删除自動顯示的設定,而隻是讓其失效和恢複。

    info display

    檢視display設定的自動顯示的資訊。GDB會打出一張表格,向你報告當然調試中設定了多少個自動顯示設定,其中包括,設定的編号,表達式,是否enable.

本文來自CSDN部落格,轉載請标明出處:

http://blog.csdn.net/haoel/archive/2003/07/09/2883.aspx

繼續閱讀