用 Python 拓展 GDB(三)
admin
2023-07-31 01:47:01
0

欢迎来到《用python拓展gdb》的第三篇。上一篇我们谈到了pretty printer,一个需要python支持的特性。这一篇我们谈论另一个需要python支持的特性,convenience function。

什么是convenience function

所谓的convenience function,正如其名“便利函数”,指gdb会话中,可用于辅助数据处理的一类函数。

举个例子:

(gdb) print foo()
$1 = void
(gdb) print $_isvoid(foo())
$2 = 1

上面的$_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命令里移除目标断点。实现代码如下:

# mv2.gdb
# 使用python...end语句块,使得我们可以在gdb的DSL文件里面编写python代码。
python
import os
# 1. 继承gdb.Function
class FindBreakpoint(gdb.Function):
    \"Find specific breakpoint with location\"
    def __init__(self):
        # 2. 注册函数名字\'findBreakpoint\'
        super(self.__class__, self).__init__(\'findBreakpint\')

    def invoke(self, location):
        # 3. 不要忘了,invoke方法接受的参数是gdb.Value,所以后面我通过
        # string方法来获得字符串值。
        bps = gdb.breakpoints() # 获取全部断点
        if bps is None:
            raise gdb.GdbError(\'No breakpoints\')
        for bp in bps:
            # 由于断点的location属性返回的是绝对路径,把它转成相对路径
            if os.path.relpath(bp.location) == location.string():
                # 4. convenience function需要返回值,gdb会把它包装成gdb.Value类型
                return bp.number
        raise gdb.GdbError(\"Specific breakpoint can\'t be found.\")

# 5. 最后一步,向gdb会话注册该函数
FindBreakpoint()
end

define mv
    if $argc == 2
        # 调用它的时候不要忘记\'$\'前缀
        set $i = $findBreakpint($arg0)
        delete $i
        # 看到我在上面耍的一个trick吗?
        # findBreakpint返回的是一个gdb.Value,
        # 需要把它绑定到DSL变量上,才能在DSL中使用。
        break $arg1
    ...

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

(gdb) help function
...
function findBreakpint -- Find specific breakpoint with location
...
(gdb) mv \"gdb.c:4\" 5

注意mv第一个参数需要用双引号括起来,否则gdb会报错,说找不到符号gdb.c

小结

下篇将会是本教程的最后一篇。在这最后一篇里,我们会看到,如何用python在gdb内跟外部程序交互。希望“gdb + X”的想法能让你脑洞大开,激发出更多的玩法。敬请期待!

相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
项目管理和工程管理的区别 项目管理 项目管理,顾名思义就是专注于开发和完成项目的管理,以实现目标并满足成功标准和项目要求。 工...