Hexagon GDB Debugger介绍(46)

240 篇文章 11 订阅

4.5.2.6 Pretty-printing

调试器提供了一种机制,允许使用Python代码对数值进行pretty-printing。pretty-printer API允许特定应用的代码大大简化了复杂对象的显示。这种机制对MI和CLI都有效。
例如,下面是一个C++ std::string在没有pretty-printer的情况下的样子。

   (gdb) print s
   $1 = {
   static npos = 4294967295,
   _M_dataplus = {
   <std::allocator<char>> = {
   <__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data
   fields>},
   members of std::basic_string<char, std::char_traits<char>,
   std::allocator<char> >::_Alloc_hider:
   _M_p = 0x804a014 "abcd"
   }
}

安装了std::string的pretty-printer后,只打印内容。

   (gdb) print s
   $2 = "abcd"

一个pretty-printer被定义为一个持有一个值的对象,并实现一个由以下操作组成的特定接口。
children (self)
调试器在pretty-printer上调用这个方法来计算pretty-printer的值的子代。
这个方法必须返回一个符合Python迭代器协议的对象。迭代器返回的每个项目必须是一个持有两个元素的元组。第一个元素是孩子的 “名字”;第二个元素是孩子的值。这个值可以是任何可以转换为调试器值的Python对象。
这个方法是可选的。如果它不存在,调试器就像该值没有孩子一样。
display_hint (self)
调试器的命令行界面(CLI)可以调用此方法并使用其结果来改变一个值的格式。该结果也会作为被打印变量的displayhint属性提供给MI消费者。
这个方法是可选的。如果它确实存在,这个方法必须返回一个字符串。
以下显示提示是由调试器预定义的。
array
表示被打印的对象是 “类数组”。CLI用它来尊重参数,如set print elements和set print array。
map
表示被打印的对象是 “类地图”,该值的子代可以假定在键和值之间交替出现。
string
表示被打印的对象是 “类字符串”。如果打印机的to_string方法返回某种Python字符串,那么调试器就会调用其内部特定语言的字符串打印函数来格式化该字符串。对于 CLI 来说,这意味着要添加引号,可能还要转义一些字符,尊重集合打印元素,等等。

4.5.2.7 Selecting pretty-printers

Python列表gdb.pretty_printers包含一个已经通过加法注册为pretty-printer的函数数组。每个gdb.Objfile也包含一个pretty_printers属性。
这些列表中的一个函数被传递一个gdb.Value参数,并且应该返回一个符合上述接口定义(第4.5.2.6节)的pretty-printer对象。如果一个函数不能为该值创建一个pretty-printer,它应该返回None。
调试器首先检查每个gdb.Objfile的pretty_printers属性,并迭代调用该gdb.Objfile列表中的每个函数,直到收到一个pretty-print对象。在这些列表用完后,它尝试全局gdb.pretty- printers列表,再次调用每个函数,直到返回一个对象。
搜索objfiles的顺序没有被指定。对于一个给定的列表,函数总是从列表的头部开始调用,并依次迭代,直到列表的末端,或者返回一个打印机对象。
下面是一个显示如何编写std::string打印机的例子: class StdStringPrinter:
“打印一个std::字符串”

class StdStringPrinter:
       "Print a std::string"
   def __init__ (self, val):
       self.val = val
   def to_string (self):
       return self.val[’_M_dataplus’][’_M_p’]
   def display_hint (self):
       return ’string’

下面是一个例子,显示了如何为上面的打印机例子写一个查找函数。

   def str_lookup_function (val):
       lookup_tag = val.type.tag
       regex = re.compile ("^std::basic_string<char,.*>$")
       if lookup_tag == None:
           return None
       if regex.match (lookup_tag):
           return StdStringPrinter (val)
       return None

这个例子中的查找函数提取了值的类型,并试图将其与一个它可以pretty-print的类型相匹配。如果它是一个打印机可以pretty-print的类型,它将返回一个打印机对象。如果不是,它将返回 None。
我们建议你把你的核心 pretty-printers 放到一个 Python 包中。如果你的 pretty-printers 是和一个库一起使用的,我们进一步建议在包的名称中嵌入一个版本号。这种做法使调试器能够同时加载多个版本的 pretty-printers,因为它们有不同的名字。
你应该编写自动加载的代码(第4.5.2.3节),使其可以被多次评估而不改变其意义。一个理想的自动加载文件只包括导入你的打印机模块,然后调用当前obj文件中的注册pretty-printers。
作为一个整体,这种方法可以很好地扩展到多个下级,每个下级可能使用不同的库版本。在Python包的名称中嵌入一个版本号,确保调试器能够同时加载两套打印机。然后,由于搜索pretty-printers是按objfile进行的,而且你的自动加载代码注意了用特定的objfile注册你的库的打印机,调试器为每个下级使用的库的特定版本找到正确的打印机。
继续std::string的例子(第4.5.2.6节),以下代码可能出现在gdb.libstdcxx.v6中。

   def register_printers (objfile):
   objfile.pretty_printers.add (str_lookup_function)

自动加载文件的相应内容将是:


   import gdb.libstdcxx.v6
   gdb.libstdcxx.v6.register_printers (gdb.current_objfile ())
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值