摘要:欢迎来到用拓展的第三篇。它们必须以开头,以此区别于来自于上下文的函数。提供的基类名为。不过有一个区别是,的方法通常会返回一个对象,表示调用该函数后的返回值。它不能像通常意义上的函数独立使用,只能跟某个命令搭配。具体实现参见用拓展第一篇。
欢迎来到《用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.Function的invoke方法通常会返回一个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”的想法能让你脑洞大开,激发出更多的玩法。敬请期待!
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/38017.html
摘要:欢迎来到用拓展的最后一篇。对于通用语言来说,暴露的接口不过是又一个库而已。这两者间的通讯使用协议。该客户端可以向外界暴露出调试时的信息。用拓展系列到此就结束了。 欢迎来到《用python拓展gdb》的最后一篇。第一篇结尾,我提到了通用语言相对于领域特定语言的一项优势,即在处理数据上更加灵活。其实通用语言还有着另一样优势,领域特定语言只能局限在宿主程序中使用,而通用语言则无此限制。对于通...
摘要:在末尾,我提到了也可以用来实现拓展脚本。其中最为常用的是和。接受一个字符串作为表达式,并以的形式返回表达式求值的结果。当触发断点或收到信号时,就会调用事先注册的回调函数。对应的,撤销回调函数的接口是。本教程剩余部分会提及这一点。 之前写的《GDB 自动化操作的技术》一文介绍了可在gdb内部使用的DSL(领域特定语言)来自动化gdb的操作。借助该DSL,我们分别实现了一个名为mv的自定义...
摘要:欢迎来到用拓展的第二篇。到目前为止,我们都是在用实现内置领域特定语言也能实现的效果。这就是的全部要求了。构造函数接收一个表示被打印的的必选。在后被调用,可用于打印复杂的成员。能通过来自定义打印方式,无疑为的使用打开新的大门。 欢迎来到《用python拓展gdb》的第二篇。在上一篇,我们学习了gdb提供的常用python接口,并用python实现了自定义命令和调试脚本。 到目前为止,我们...
摘要:背景这几天一直在查一个线上程序住的问题这个程序总是在运行分钟后住通过以下的一些调试手段发现是打日志的时候因为满被了日志是默认打到的无论日志级别而我这个程序是被另一个程序调起的父进程没有接收子进程的导致了被打满在调试的过程中用到了以下几种调试 FROM http://kamushin.github.io/debug/python.html 背景 这几天一直在查一个线上程序 hang 住的...
阅读 2505·2023-04-26 03:00
阅读 1348·2021-10-12 10:12
阅读 4132·2021-09-22 15:33
阅读 2874·2021-09-22 15:06
阅读 1480·2019-08-30 15:44
阅读 2079·2019-08-30 13:59
阅读 504·2019-08-30 11:24
阅读 2349·2019-08-29 17:07