用 Python 擴充 GDB(三)

發表於2016-06-21

歡迎來到《用python擴充gdb》的第三篇。上一篇我們談到了pretty printer,一個需要python支援的特性。這一篇我們談論另一個需要python支援的特性,convenience function。

什麼是convenience function

所謂的convenience function,正如其名“便利函式”,指gdb會話中,可用於輔助資料處理的一類函式。

舉個例子:

上面的$_isvoid就是convenience functions。它們必須以$開頭,以此區別於來自於C/C++上下文的函式。

gdb中內建了一些convenience functions,可惜它們的數量並不多。還好gdb提供了python介面,讓我們能夠新增自定義的convenience functions。

跟自定義命令一樣,該介面也需要使用者繼承特定的類。convenience function提供的基類名為gdb.Function。使用者需要實現其中的__init__invoke(self, *args)兩個方法,然後通過構造一個物件來向gdb註冊該函式。基本上就是自定義命令的一個翻版。不過有一個區別是,gdb.Functioninvoke方法通常會返回一個gdb.Value物件,表示呼叫該函式後的返回值。如果返回的不是gdb.Value物件,gdb會嘗試把它轉化成對應的gdb.Value物件。比方說,如果invoke方法返回的是一個字串,那麼gdb會把該字串包裝成表示字串的gdb.Value

比起自定義命令,convenience function有一個劣勢。它不能(像通常意義上的函式)獨立使用,只能跟某個命令搭配。舉個例子,(gdb) $aryType()是語法不正確的,你只能(gdb) p $aryType()。即使在除錯指令碼里這一條也成立,單獨一個$setSize("ary", 20)就不行,需要用p $setSize("ary", 20)繞過。事實上,用自定義命令setSize "ary" 20看上去會更順眼。convenience function能幹的事,自定義命令大部分也能幹,導致它的存在感一向很稀薄。

當然,它也不全是個雞肋。convenience function有一個優勢,它可以返回值。這是自定義命令做不到的。屬於它的生存空間也就剩下這麼一點了。

實現一個convenience function

老規矩,還是用我最愛的教學方式,先上示例程式碼。

這次我們嘗試用DSL實現mv命令的第二版。該版本的mv接受兩個引數,一個是待移除斷點的位置,另一個是待設定斷點的位置。

mv具體實現參見《用python擴充gdb》第一篇。由於DSL裡面沒有函式,我們會用python程式碼實現名為findBreakpoint的convenience function。當然了,如果我們選擇用python實現mv,就沒有這個需求了。還是創造下機會讓convenience function上一會場吧。

findBreakpoint的功能是接受一個位置,返回該位置上首個斷點的編號,這樣就能在delete命令裡移除目標斷點。實現程式碼如下:

使用方式:gdb a.out -x mv2.gdb

注意mv第一個引數需要用雙引號括起來,否則gdb會報錯,說找不到符號gdb.c

小結

下篇將會是本教程的最後一篇。在這最後一篇裡,我們會看到,如何用python在gdb內跟外部程式互動。希望“gdb + X”的想法能讓你腦洞大開,激發出更多的玩法。敬請期待!

相關文章