如何使 C++ 类 gdb 友好?

Posted

技术标签:

【中文标题】如何使 C++ 类 gdb 友好?【英文标题】:How to make a C++ class gdb-friendly? 【发布时间】:2020-09-16 17:06:46 【问题描述】:

考虑以下示例:

std::string s = "Hello!!";

(gdb) p s
$1 = "Hello!!";

本质上,只提供变量名就足以显示字符串。例如,我不必键入“p s.c_str()”。

gdb 是否使用任何隐式运算符来获取显示字符串?我需要为我的班级做类似的事情。这是我班级的一个简单示例:

class MyClass 

private:
  std::string _name;
;

【问题讨论】:

您需要使用 gdb 的脚本工具来为您自己的类型添加漂亮的打印机。请参阅:***.com/questions/12574253/… 它是gdb的特性之一,实际上有pretty-printers用来显示标准类,可以用来表示自定义。对于std::string,旧版本的 gdb 无法做到这一点。要创建自定义漂亮打印机,可以在 gdb 命令行中使用定义命令或编写 python 漂亮打印机。像这样的简单案例可以用我的宏来完成。 kurokatta.org/grumble/2018/05/gdb-pretty 确保在构建时启用了调试符号。 【参考方案1】:

你需要为你的班级写一个漂亮的打印机。这不是您在 C++ 类中执行的操作,而是您在 gdb 中执行的操作(尽管与您的 C++ 类匹配)。最简单的方法是通过 gdb 的 Python API(您也可以使用 Guile 语言)。

GDB 已经为大多数标准库类提供了漂亮的打印机,这就是为什么您可以轻松看到 std::string 对象、std::vector 等。如果您在 gdb 中键入 info pretty-printer,它会告诉您关于它目前知道的漂亮打印机,你会注意到很多std::something漂亮的打印机。

如果您使用 pass /r 到 gdb 中的打印命令,它将打印变量,而不使用任何可能的注册漂亮打印机匹配它。用std::string 试试看,如果 gdb 没有为它提供漂亮的打印机,它会如何打印。


那么,您如何编写自己的漂亮打印机呢?为此,您应该阅读有关此主题的 GDB's documentation。但我发现通过阅读和调整一些现有的漂亮打印机开始更容易,然后阅读 gdb 的文档了解详细信息。

例如,我的一个项目中有一个Coordinate 类,如下所示

class Coordinate 
private:
    double x;
    double y;
    double z;

public:
    ...

为这个类写一个漂亮的打印机很容易。您使用以下代码创建一个 python 文件

class CoordinatePrinter:
    def __init__(self, val):
        # val is the python representation of you C++ variable. 
        # It is a "gdb.Value" object and you can query the member 
        # atributes of the C++ object as below. Since the result is
        # another "gdb.Value" I'am converting it to a python float
        self.x = float(val['x'])
        self.y = float(val['y'])
        self.z = float(val['z'])

    # Whatever the `to_string` method returns is what will be printed in  
    # gdb when this pretty-printer is used
    def to_string(self):
        return "Coordinate(x=:.2G, y=:.2G, z=:.2G)".format(self.x, self.y, self.z)



import gdb.printing
# Create a "collection" of pretty-printers
# Note that the argument passed to "RegexpCollectionPrettyPrinter" is the name of the pretty-printer and you can choose your own
pp = gdb.printing.RegexpCollectionPrettyPrinter('cppsim')
# Register a pretty-printer for the Coordinate class. The second argument is a 
# regular expression and my Coordinate class is in a namespace called `cppsim`
pp.add_printer('Coordinate', '^cppsim::Coordinate$', CoordinatePrinter)
# Register our collection into GDB
gdb.printing.register_pretty_printer(gdb.current_objfile(), pp, replace=True)

现在我们需要做的就是source gdb 中的这个 python 文件。为此,请写入您的 .gdbinit 文件

source full_path_to_your_python_file_with_pretty_printers.py

当您启动 gdb 时,它将运行您的 .gdbinit 文件,该文件将加载您的漂亮打印机。请注意,这些漂亮的打印机通常也可以在使用 gdb 的 IDE 中工作。

如果您对更多示例感兴趣,我已经为Armadillo 库(向量、矩阵和一般线性代数)中的某些类创建了漂亮的打印机,这些类可在here 获得。

【讨论】:

【参考方案2】:

如果您安装了libstdc++ pretty-printers(您已经安装了它们),那么您的类已经是 gdb 友好的,因为它们将在打印您的类的成员时被调用。如果除了_name 之外还有很多其他班级成员,您还可以使用set print pretty 更容易区分它们:

(gdb) p my_class 
$1 = _name = ""
(gdb) set print pretty 
(gdb) p my_class 
$2 = 
  _name = ""

(gdb) 

【讨论】:

以上是关于如何使 C++ 类 gdb 友好?的主要内容,如果未能解决你的问题,请参考以下文章

成员函数的 C++ GDB 断点

如何获取 gdb tui 程序集输出以显示指令?

如何制作一个 PInvoke 友好的原生 API?

如何使 GDB 与外部程序一起工作

如何在 C++ 头文件上使用 gdb?

如何使用 gdb 制作一个可以漂亮地打印每个对象的 C++ 函数?