作者:xmj
1、GDB提供了Pretty Printer功能,可以在调试程序的时候,通过自定义的打印程序来更好的显示一个数据结构的值。
相关信息可以参考gdb手册: 23.2.2.7 Writing a Pretty-Printer https://sourceware.org/gdb/current/onlinedocs/gdb/Writing-a-Pretty_002dPrinter.html#Writing-a-Pretty_002dPrinter
2、Go源码包里的dist目录,go/src/cmd/dist,是Go的bootstraping工具,用来自举go编译器,以及各种可以使用脚本来完成的杂活。其本身是用C写的,里面有两个常用的数据类型,定义在a.h里:
// A Buf is a byte buffer, like Go’s []byte. typedef struct Buf Buf; struct Buf { char *p; int len; int cap; };
// A Vec is a string vector, like Go’s []string. typedef struct Vec Vec; struct Vec { char **p; int len; int cap; };
我们在gdb中调试dist的时候,如果想查看一个Buf或者Vec的内容,如下:
(gdb) p b $1 = {p = 0x80574b8, len = 0x3, cap = 0x40} (gdb) p gccargs $2 = {p = 0x8059778, len = 0x4, cap = 0x40}
显然,不是很令人满意。
3、为此,我们可以为其定义pretty printers。这里,需要两部分内容,首先创建一个目录,以及一个文件:python/printers.py,内容如下:
import gdb
class BufPrinter(object): “Print a struct Buf.”
def \_\_init\_\_ (self, val):
self.val = val
def to\_string (self):
p = self.val\['p'\]
l = self.val\['len'\]
ret = "\\""
ret += p.string(length = l)
ret += "\\""
return ret
class VecPrinter(object): “Print a struct Vec.”
def \_\_init\_\_ (self, val):
self.val = val
def to\_string (self):
p = self.val\['p'\]
l = self.val\['len'\]
ret = "\\""
for i in range(l):
if i > 0:
ret += " "
ret += p\[i\].string()
ret += "\\""
return ret
def build_pretty_printer(): pp = gdb.printing.RegexpCollectionPrettyPrinter(“golang”) pp.add_printer(‘Buf’, ‘^Buf$’, BufPrinter) pp.add_printer(‘Vec’, ‘^Vec$’, VecPrinter) return pp
def register_golang_printer(): gdb.printing.register_pretty_printer( gdb.current_objfile(), build_pretty_printer())
然后,在~/.gdbinit里,增加如下代码:
python import sys sys.path.insert(0, ‘/path/to/your/python’) from printers import register_golang_printer register_golang_printer () end
4、此时,再通过gdb调试dist,显示如下:
(gdb) p b $1 = “gcc” (gdb) p gccargs $2 = “gcc -Wall -Wstrict-prototypes -Wextra”