成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

用 Python 拓展 GDB(二)

AbnerMing / 835人閱讀

摘要:歡迎來到用拓展的第二篇。到目前為止,我們都是在用實現(xiàn)內(nèi)置領域特定語言也能實現(xiàn)的效果。這就是的全部要求了。構造函數(shù)接收一個表示被打印的的必選。在后被調(diào)用,可用于打印復雜的成員。能通過來自定義打印方式,無疑為的使用打開新的大門。

歡迎來到《用python拓展gdb》的第二篇。在上一篇,我們學習了gdb提供的常用python接口,并用python實現(xiàn)了自定義命令和調(diào)試腳本。

到目前為止,我們都是在用python實現(xiàn)內(nèi)置DSL(領域特定語言)也能實現(xiàn)的效果。從本篇開始,我們將繼續(xù)上路,去欣賞內(nèi)置DSL所缺乏的新風景。

下一站,Pretty-Printer。

什么是Pretty-Printer

當我們在gdb中打印一個類/結構體時,gdb會嘗試輸出該類型的所有成員和它們的值。對于指針,即是輸出指針所指向的地址。如果要想進一步查看指針指向的值,需要使用p *cls->x@range這樣的語法,來轉(zhuǎn)換出該地址上對應的值。畢竟,C/C++是一門接近硬件的語言,如果你不指明某個地址上的具體意義,在計算機看來,不過是些字節(jié)罷了。

如果你調(diào)試過C++的STL容器,就會(驚喜地)發(fā)現(xiàn):gdb并不會把容器里面各種亂七八糟的成員都打印一通,相反它僅僅輸出容器里面的數(shù)據(jù)(除非你使用的gdb版本感人)。這一特性的背后,離不開Pretty-Printer的功勞。Pretty-Printer允許用戶使用python給指定類編寫自定義的打印方式。事實上,gdb內(nèi)置了一個python腳本,正是這個腳本決定了STL容器的打印輸出。

項目中的某個類太過于復雜?
正在使用某個自定義的數(shù)據(jù)結構?
想要快速看出某個屬性的編碼代表什么?

Pretty-Printer可以幫你解決以上所有問題。

實現(xiàn)一個Pretty-Printer

跟自定義命令不同,Pretty-Printer不需要用戶去繼承某一類,用戶編寫的Pretty-Printer類僅需要實現(xiàn)指定的方法。你也可以視之為繼承接口。

順便一提,考慮到Pretty-Printer實在太長,請允許我為了偷懶,從下文開始用pprinter來簡寫之。

用戶實現(xiàn)的pprinter會收到一個表示被打印對象的gdb.Value作為構造參數(shù),另外還需要實現(xiàn)一個to_string方法,返回一個字符串作為該對象的打印結果。

這就是pprinter的全部要求了。此外你還可以實現(xiàn)children方法用于輸出該類里面復雜成員的值,display_hint方法用于定義輸出的樣式。

還是老樣子,邊上代碼邊解釋。

假設我們有如下一個Buffer結構體的定義:

struct Buffer {
    int used; /// 已使用的數(shù)目
    int free; /// 未使用的數(shù)目
    void *data;
    int8_t encoding; /// 當前存儲的數(shù)據(jù)類型
    /* data的類型取決于encoding的值。encoding和data類型的對應關系如下:
       0 -> int8_t
       1 -> int16_t
       2 -> int32_t
       3 -> int64_t
     */
};

現(xiàn)在我們需要編寫一個pprinter,它能夠輸出該Buffer里面的數(shù)據(jù),以及Buffer當前的使用程度。

# pprinter.py
class BufferPrinter:
    def __init__(self, val):
        "構造函數(shù)接收一個表示被打印的Buffer的gdb.Value"
        self.val = val

    def to_string(self):
        """必選。輸出打印的結果。
        由于gdb會在調(diào)用to_string后調(diào)用children,這里我們只輸出當前的使用程度。
        具體的數(shù)據(jù)留在children函數(shù)中輸出。
        """
        return "used: %d
free: %d
" % (self.val["used"], self.val["free"])

    def _iterate(self, pointer, size, encoding):
        # 根據(jù)encoding決定pointer的類型
        typestrs = ["int8_t", "int16_t", "int32_t", "int64_t"]
        pointer = pointer.cast(gdb.lookup_type(typestrs[encoding]).pointer())
        for i in range(size):
            elem = pointer.dereference()
            pointer = pointer + 1
            yield ("[%d]" % i, elem)

    def children(self):
        """可選。在to_string后被調(diào)用,可用于打印復雜的成員。
        要求返回一個迭代器,該迭代器每次迭代返回(名字,值)形式的元組。
        打印出來的效果類似于“名字 = 值”。
        """
        return self._iterate(self.val["data"],
                             int(self.val["used"]), int(self.val["encoding"]))

    def display_hint(self):
        """可選。影響輸出的樣式。
        可選值:array/map/string。
        返回array表示按類似于vector的方式打印。其它選項同理。
        """
        return "array"

事實上,我們完全可以把children方法打印的內(nèi)容放到to_string中。下面是等價的代碼:(打印的結果有所不同,不過差異不大)

    def _iterate(self, pointer, size, encoding):
        ...
            # 以上保持不變
            yield elem

    def to_string(self):
        status = "used: %d
free: %d
" % (self.val["used"], self.val["free"])
        data = "{" + " ".join(self._iterate(self.val["data"], int(self.val["used"]),
                              self.val["encoding"])) + "}"
        return status + data
注冊Pretty-Printer

接下來是向gdb注冊我們自定義的pprinter:

def lookup_buffer(val):
    """val是一個gdb.Value的實例,通過type屬性來獲取它的類型。
    如果類型為Buffer,那么就使用自定義的BufferPrinter。
    """
    if str(val.type) == "Buffer":
        return BufferPrinter(val)
    return None

gdb.pretty_printers.append(lookup_buffer)

使用效果如下:

(gdb) so pprinter.py
(gdb) info pretty-printer
global pretty-printers:
  .*
    bound
  BufferPrinter
(gdb) p buffer
$1 = used: 10
free: 0
data: {512 129 512 129 512 129 512 129 512 129 }
小結

從本篇開始,我們接觸了gdb更多的特性,登上了DSL所無法到達的高處。能通過python來自定義打印方式,無疑為gdb的使用打開新的大門?,F(xiàn)在,gdb工具箱里又多了項新工具。

項目中的某個類太過于復雜?在pprinter中僅顯示關鍵的成員屬性。

正在使用某個自定義的數(shù)據(jù)結構?通過編寫pprinter,我們也能像打印STL容器一樣打印出它們的數(shù)據(jù)。
想要快速看出某個屬性的編碼代表什么?可以在pprinter中實現(xiàn)編碼到可讀字符串的轉(zhuǎn)換,正如在示例中,我們從encoding中讀出data屬性的類型。

下一篇中,我們會談論另一個內(nèi)建DSL實現(xiàn)不了的功能——convenience function(可以理解為gdb會話中的內(nèi)置函數(shù))。敬請期待!

文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/37992.html

相關文章

  • Python 拓展 GDB(三)

    摘要:歡迎來到用拓展的第三篇。它們必須以開頭,以此區(qū)別于來自于上下文的函數(shù)。提供的基類名為。不過有一個區(qū)別是,的方法通常會返回一個對象,表示調(diào)用該函數(shù)后的返回值。它不能像通常意義上的函數(shù)獨立使用,只能跟某個命令搭配。具體實現(xiàn)參見用拓展第一篇。 歡迎來到《用python拓展gdb》的第三篇。上一篇我們談到了pretty printer,一個需要python支持的特性。這一篇我們談論另一個需要p...

    quietin 評論0 收藏0
  • Python 拓展 GDB(四)

    摘要:歡迎來到用拓展的最后一篇。對于通用語言來說,暴露的接口不過是又一個庫而已。這兩者間的通訊使用協(xié)議。該客戶端可以向外界暴露出調(diào)試時的信息。用拓展系列到此就結束了。 歡迎來到《用python拓展gdb》的最后一篇。第一篇結尾,我提到了通用語言相對于領域特定語言的一項優(yōu)勢,即在處理數(shù)據(jù)上更加靈活。其實通用語言還有著另一樣優(yōu)勢,領域特定語言只能局限在宿主程序中使用,而通用語言則無此限制。對于通...

    Seay 評論0 收藏0
  • Python 拓展 GDB(一)

    摘要:在末尾,我提到了也可以用來實現(xiàn)拓展腳本。其中最為常用的是和。接受一個字符串作為表達式,并以的形式返回表達式求值的結果。當觸發(fā)斷點或收到信號時,就會調(diào)用事先注冊的回調(diào)函數(shù)。對應的,撤銷回調(diào)函數(shù)的接口是。本教程剩余部分會提及這一點。 之前寫的《GDB 自動化操作的技術》一文介紹了可在gdb內(nèi)部使用的DSL(領域特定語言)來自動化gdb的操作。借助該DSL,我們分別實現(xiàn)了一個名為mv的自定義...

    Cheng_Gang 評論0 收藏0
  • Python 調(diào)試方法

    摘要:背景這幾天一直在查一個線上程序住的問題這個程序總是在運行分鐘后住通過以下的一些調(diào)試手段發(fā)現(xiàn)是打日志的時候因為滿被了日志是默認打到的無論日志級別而我這個程序是被另一個程序調(diào)起的父進程沒有接收子進程的導致了被打滿在調(diào)試的過程中用到了以下幾種調(diào)試 FROM http://kamushin.github.io/debug/python.html 背景 這幾天一直在查一個線上程序 hang 住的...

    klivitamJ 評論0 收藏0

發(fā)表評論

0條評論

AbnerMing

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<