【问题标题】:How to call constructor in gdb for pretty-printers如何在 gdb 中为漂亮的打印机调用构造函数
【发布时间】:2011-08-14 22:19:56
【问题描述】:

在使用 GDB 进行调试时,我想将便利变量设置为新构造的值。

我正在使用 Qt 框架进行编程,所以我想创建一个 QString,但这与问题无关,因为我想知道如何对任何类执行此操作。

我试过了

(gdb) set $str = 'QString::QString("abc")'
No symbol "QString::QString("abc")" in current context.

(gdb) set $str = QString::QString("abc")
Cannot resolve method QString::QString to any overloaded instance

(gdb) set $str = QString("abc")
A syntax error in expression, near `("abc")'.

然后我尝试使用set overload-resolution off,结果如下:

set $str = QString::QString("abc")
non-unique member `QString' requires type instantiation

set $str = 'QString::QString(const char*)'("abc")
Too few arguments in function call.

所以我假设需要一个 this 指针:

(gdb) set $str = 'QString::QString(const char*)'(malloc(sizeof(QString)), "abc")
(gdb) p $str
$8 = void

好的,构造函数返回void,这意味着我必须将malloc的返回值保存在某个地方:

(gdb) set $pointer = malloc(sizeof(QString))
(gdb) p $pointer
$9 = 6304560
(gdb) p/x $pointer
$10 = 0x603330
(gdb) set $str = 'QString::QString(const char*)'($pointer, "abc")
(gdb) p $str
$11 = void
(gdb) p $pointer
$12 = 6304560
(gdb) p *((QString*)$pointer)
$13 = "abc"

好的,现在这可以按预期工作,但是我想在 gdb.parse_and_eval() 中将此代码用于 python 漂亮的打印机。现在这将调用 malloc 很多次,造成内存泄漏。所以只需调用free()?现在发生了一些意想不到的事情:

(gdb) call free($pointer)
$14 = 0
(gdb) p *((QString*)$pointer)
$15 = "abc"

指针似乎仍然有效,这当然可以很好,因为内存没有被重用。但是我不确定这是否可以,因为在分配了更多正好适合一个 QString 的内存块之后,指针值仍然没有被 malloc 重用。

如果我在漂亮的打印机中使用它会造成很大的内存泄漏吗?在调试会话期间可能会被调用很多次?有没有更简单的解决方案来创建所需的结果(即使用 Python API)?

同样与此无关,为什么 free(3) 给我一个返回值 0 而它实际上是 void?

【问题讨论】:

    标签: c++ constructor gdb evaluate


    【解决方案1】:

    我不知道如何释放指针。这似乎是不可能的,但是造成的内存泄漏应该很小。但我知道如何消除你描述的效果

    指针似乎仍然有效,这当然可以很好,因为内存没有被重用。但是我不确定这是否可以,因为在分配了更多正好适合一个 QString 的内存块之后,指针值仍然没有被 malloc 重用。

    请参阅此代码,该代码应显示如何解决问题(仅在 GNU gdb (GDB) SUSE (7.5.1-2.1.1) 上测试)

    (gdb) call malloc(sizeof(std::string))
    $1 = (void *) 0x64e4d0
    (gdb) call ((std::string*)0x64e4d0)->basic_string()
    (gdb) call ((std::string*)0x64e4d0)->assign("Hello World")
    $2 = "Hello World"
    (gdb) call ((std::string*)0x64e4d0)->'~basic_string'((std::string*)0x64e4d0)
    warning: Using non-standard conversion to match method std::string::~basic_string to supplied arguments
    (gdb) print ((std::string*)0x64e4d0)
    $3 = (std::string *) 0x64e4d0
    (gdb) print *((std::string*)0x64e4d0)
    $4 = ""
    (gdb) call free(0x64e4d0)
    (gdb) print *((std::string*)0x64e4d0)
    $5 = ""
    

    你的版本无法释放内存的原因是你的free命令应该只影响直接保留的内存(例如类定义的指针和基本类型),而不是创建的对象(即构造函数保留的内存)以及您可能调用的对象的方法)。

    需要首先调用所创建对象的析构函数,然后释放指针(在我的代码中 $2 下面的行)。

    正如我的代码的最后几行 ($5) 所暗示的,即使对象的内存不再被进程占用,gdb 的漂亮打印机也能够恢复对象的内容。原因可能是打印机几乎可以对每个内存地址执行此操作,并且当没有其他进程向该位置写入内容时(我们之前已经占用了几秒钟),我们将获得与未调用 free 时相同的结果。

    PS:析构函数的格式和警告应该告诉你找到析构函数的正确表达式有点棘手。我没有实际的 QT-Project 来尝试使用 QString,但它应该非常接近我所做的。

    【讨论】:

      【解决方案2】:

      你想做什么?如果你想用 gdb 漂亮地打印 QString,请使用 gdb 的 Python 漂亮打印机 API。有关详细信息,请参阅http://sourceware.org/gdb/onlinedocs/gdb/Pretty-Printing.html。您可以使用 Python 打印机类,如下所示:

      class QStringPrinter:
          def __init__(self, val):
              self.val = val
      
          def to_string(self):
              if self.val['d'] == self.val['shared_null'].address:
                  return 0
      
              dataptr = self.val['d']['data'].cast(gdb.lookup_type('char').pointer())
              size = self.val['d']['size']
      
              if sys.byteorder == 'little':
                  enc = 'utf_16_le'
              else:
                  enc = 'utf_16_be'
              return dataptr.string(enc, 'ignore', size * 2)
      
          def display_hint(self):
              return 'string'
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-01-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多