在gdb中调用operator<<函数

22

如何在gdb中调用operator<<(std::ostream &os, const ClassX &x)

换句话说,如何在gdb中打印一个对象?

call std::cout<<xcall operator<<(std::cout, x) 对我都不起作用!

有什么想法吗?


我输入“print”命令来打印变量和对象。 - Thomas Matthews
6
我正在处理一个类,其中operator<<做了很多工作,以便信息易于阅读,因此使用print并获得原始数据有点烦人。 - Ben
4个回答

12
我唯一发现的方法是这样的:
call 'operator<<(std::ostream&, myclass&)'(mycout, c)

由于某些原因,std::cout对gdb不可见,所以我不得不像这样创建自己的输出流:

std::ostream mycout(std::cout.rdbuf());
你没有说明想要这样做的原因,但是使用print yourvariable是否更容易呢?
如果这是必须的,你可以在你的类中创建一个Print方法并从operator<<中调用它,然后从gdb上调用对象的Print方法。
请注意,stdout在gdb中可能会被缓存,因此除非以某种方式重定向,否则您将看不到任何输出。
有关此问题,请参见gdb邮件存档中的讨论。

7
你可以这样定义一个函数:

你也可以这样定义一个函数:

define printType
call operator<<(std::ostream&, const $arg0 &)(std::cerr, $arg1)
end

并像这样使用:

printType 类X 类X的对象


注:该段文本是关于如何使用某个类的示例代码。

在Ubuntu 18.04上,使用GDB 8.1.0时,您不需要显式传递类类型,因为C++可以从参数中推断模板类型。但是由于缺少刷新,某些原因导致cout无法工作,只有cerr可以。但是我无法刷新,如下所述:https://stackoverflow.com/questions/3832964/calling-operator-in-gdb#comment102981298_48601472 - Ciro Santilli OurBigBook.com

2

对我来说,call operator<<运行时没有错误,但没有打印输出。原来我需要调用flush函数。这里是一个有用的函数,你可以将它放在.gdbinit文件中:

define str
    call (void)operator<<(std::cout, $arg0)
    call (void)std::cout.flush()
    printf "\n"
end

你如何从gdb控制台中调用这个? - Michael
不需要括号调用,像这样:str my_variable - Dan Stahlke
1
在Ubuntu 18.04上,GDB 8.1.0会出现Couldn't find method std::ostream::flush的错误,并且这个最小化的例子:https://gist.github.com/cirosantilli/d438e38f05a92422f909c0571a2dac16。不过,由于某种原因,`cerr`没有使用flush也可以工作。`call fflush(0)`确实可以工作,但是不确定它是否合理。 - Ciro Santilli OurBigBook.com
可能是因为您的程序中没有调用std::flush函数,因此该函数未链接到可执行文件中。您确实使用了std::endl,它会执行刷新操作,但是libstdc++可能会直接执行此刷新操作,而不是通过std::flush执行。请尝试在示例中添加显式的std::flush。当然,如果fflush(0)有效,则已经设置好了。 - Dan Stahlke

2
我在我的.gdbinit中有以下内容。之前这里的答案对我没有用,当operator<<是一个模板或需要大量输入才能正确获取类型时。这种方法搜索符号表以找到正确的operator<<。这仅在操作符已明确实例化时才有效。
python
import gdb
import re
class LexicalCast(gdb.Command):
    def __init__(self):
        super(LexicalCast, self).__init__("lexical_cast", gdb.COMMAND_DATA)

    def matches(self, symbol, type, exact=True):
        params = symbol.find('('), symbol.find(')')
        if -1 in params: return False
        params = symbol[params[0]+1 : params[1]]
        if re.match("^%s, %s( const)?&?$"%(re.escape("std::ostream&"), re.escape(type)), params): return True
        if not exact and re.match("^%s, .*::%s( const)?&?$"%(re.escape("std::ostream&"), re.escape(type)), params): return True
        return False

    def invoke(self, arg, from_tty):
        value = gdb.parse_and_eval(arg)
        type = str(value.type.strip_typedefs().unqualified())
        # isn't unqualified() supposed to do that already?
        if type.startswith("const "): type = type[6:]
        if type.startswith("struct "): type = type[7:]
        if type.endswith(" &"): type = type[:-2]
        # there's probably a better way to browse the list of symbols ...
        shift_operators = gdb.execute("info functions operator<<", False, True).split('\n')  
        matching_operators = [ op for op in shift_operators if self.matches(op, type)]
        if not matching_operators:
            gdb.write("No operator<<(std::ostream&, const %s&) found in the symbols. Trying to find a match with additional namespace qualifiers.\n"%(type,))
            matching_operators = [ op for op in shift_operators if self.matches(op, type, False)]

        if not matching_operators:
            gdb.write("No operator<<(std::ostream&, const .*::%s&) found in the symbols. Did you forget to explicitly instantiate your operator?\n"%(type,))     
        else:
            if len(matching_operators) > 1:
                gdb.write("Found multiple operator<< matching this expression; trying to call each one of them...\n")                          
            for op in matching_operators:
                try:                     
                    op = op.split('  ', 1)[1][:-4] if op.endswith("@plt") else op.split(':', 1)[1].split('&', 1)[1].strip()[:-1]
                    gdb.execute("call (void)'%s'((std::cout), (%s))"%(op, arg))      
                    gdb.execute("call (void)std::cout.put('\\n')")
                    gdb.execute("call (void)std::cout.flush()")
                    break
                except Exception as e:
                    gdb.write("Could not invoke %s: %s\n"%(op, e))

LexicalCast()
end   

我在 GDB 中这样使用:

(gdb) lex sector[0]
4: 1 ~ ([-3.00170 +/- 3.86e-6], [-1.73303 +/- 7.55e-8])
(gdb) lex 123
No operator<<(std::ostream&, const int&) found in the symbols. Did you explicitly instantiate that operator?

当然,这基本上是一种黑客方式,如果您更改了GDB打印info functions的方式,它很可能会出现错误,但对于我的目的而言,它运行良好。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接