22

How do you call operator<<(std::ostream &os, const ClassX &x) from inside gdb ?

In other words, how do you print an object in gdb ?

call std::cout<<x or call operator<<(std::cout, x) don't seems to work for me!

Any ideas?

Ben
  • 7,372
  • 8
  • 38
  • 46
  • I type in the command `print` to print variables and objects. – Thomas Matthews Sep 30 '10 at 17:29
  • 6
    I am working with a class in which the operator<< does a lot so the information is readable, so it's a bit annoying to use print and have raw data. – Ben Sep 30 '10 at 17:53

4 Answers4

12

The only way I found was this:

call 'operator<<(std::ostream&, myclass&)'(mycout, c)

Since std::cout wasn't visible to gdb for some reason, I had to resort to creating my own like this:

std::ostream mycout(std::cout.rdbuf());

You haven't stated any reasons for wanting to do this but won't print yourvariable be easier?

If this is an absolute must you could have a Print method in your class and call that from operator<< and then call the Print method on your object from gdb.

Do take note that stdout is probably buffered in gdb so you won't be seeing any output unless you redirect it somehow.

See this discussion from gdb's mailing archive regarding this issue.

Idan K
  • 20,443
  • 10
  • 63
  • 83
7

You can also define a function like:

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

And use it like:

printType ClassX objectOfClassX

Jose Moreno
  • 71
  • 1
  • 4
  • On Ubuntu 18.04, GDB 8.1.0, you don't need to pass the class type explicitly, as C++ can deduce template types from arguments. However for some reason `cout` didn't work, only `cerr`, likely due to a missing flush. But I can't flush as explained at: https://stackoverflow.com/questions/3832964/calling-operator-in-gdb#comment102981298_48601472 – Ciro Santilli OurBigBook.com Oct 09 '19 at 18:13
2

For me call operator<< ran without error, but didn't print. Turns out I needed a call to flush. Here's a useful function you can put in .gdbinit:

define str
    call (void)operator<<(std::cout, $arg0)
    call (void)std::cout.flush()
    printf "\n"
end
Dan Stahlke
  • 1,417
  • 1
  • 15
  • 20
  • How would you call this from the gdb console? – Michael Mar 27 '18 at 01:43
  • Call it with no parentheses, like so: `str my_variable` – Dan Stahlke Mar 27 '18 at 02:39
  • 1
    On Ubuntu 18.04, GDB 8.1.0 this fails with `Couldn't find method std::ostream::flush` and this minimal example: https://gist.github.com/cirosantilli/d438e38f05a92422f909c0571a2dac16 `cerr` worked though without flush for some reason. `call fflush(0)` did work though, but not sure how sane that is. – Ciro Santilli OurBigBook.com Oct 09 '19 at 18:34
  • It could be that nothing in your program calls std::flush and so that function is not linked into your executable. You do use std::endl, which does a flush, but perhaps libstdc++ does this flush directly rather than via std::flush. Try adding an explicit std::flush into your example. Of course, if fflush(0) works, then you are already set. – Dan Stahlke Oct 10 '19 at 18:36
2

I have the following in my .gdbinit. The previous answers here did not work for me when the operator<< is a template or required a lot of typing to get the types right. This approach searches the symbol table to find the correct operator<<. This only works if the operators have been instantiated explicitly.

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   

In GDB I use it like this:

(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?

This is mostly a hack of course that likely breaks if you have changed how GDB prints info functions, but it works well for my purposes.

saraedum
  • 1,389
  • 1
  • 11
  • 7