View on GitHub

开源开发工具技术博客

编译器/工具链、模拟器、虚拟机、Linux内核、调试和性能分析工具

作者: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”