2

There is a difference in using print and printf commands in GDB: print may print related fields if the argument is an object, while printf strictly expects format specifiers and C-style strings.

What I'd like to do, is to "get" the output of a gdb print expression, and use it as a string data with a %s format specifier. Usually, that doesn't work - with this test.cpp program:

// g++ --std=c++11 -g test.cpp -o test.exe

#include <iostream>
#include <set>

std::string aa; // just to have reference to std::string

int main()
{
  std::set<std::string> my_set;
  my_set.insert("AA");
  my_set.insert("BB");
  std::cout << "Hello World!" << std::endl;
  return 0;
}

I can get output like this:

$ gdb --args ./test.exe
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
...
Breakpoint 1, main () at test.cpp:13
13    std::cout << "Hello World!" << std::endl;
(gdb) p my_set
$1 = std::set with 2 elements = {[0] = "AA", [1] = "BB"}
(gdb) p *my_set
No symbol "operator*" in current context.
(gdb) p my_set->begin()
Cannot resolve method std::set<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::begin to any overloaded instance

... but I cannot just use my_set as argument of printf, since there a char array would be expected:

(gdb) printf "it is: '%s'\n", my_set
it is: 'Value can't be converted to integer.

So, is it possible to somehow obtain the representation of an object of print as a string, to use it as an argument of printf? Assuming pseudocode function print_repr(), I'd like to achieve this:

(gdb) printf "it is: '%s'\n", print_repr(my_set)
it is: '= std::set with 2 elements = {[0] = "AA", [1] = "BB"}'

... and also would like the same to function for errors, say:

(gdb) printf "it is: '%s'\n", print_repr(*my_set)
it is: 'No symbol "operator*" in current context.'

Is something like this possible?

3 Answers 3

1

First of all, let me say that there's no really good reason, IMO, that gdb can't do this via a special printf substitution. Why not? The whole thing is under gdb's control

That said, is possible, sort of, using the gdb CLI, however it is pretty difficult. You have to do a funny dance involving set logging, then use shell to rewrite the output file to a gdb script, then source it. Possible, but gross.

It's somewhat simpler with Python. You can write a convenience function in Python that returns the value as a string. Then you can just write something like:

(gdb) printf "%s", $_print_repr(whatever)

The gdb manual has a section on writing new convenience functions. It is pretty easy.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for that, @TomTromey - this answers it, so I'm accepting, although I haven't tried it yet; cheers!
I forgot to mention -- another option for formatted output in gdb is the output command. This works like print but doesn't affect the value history. So, you can also mix printf and output calls to achieve the effect you want.
0

I just tried this using @TomTromey's pointers, but it wasn't exactly trivial, so I'm posting this as an answer, tested on gdb 7.7.1. First, I added this to my ~/.gdbinit file:

python
# https://sourceware.org/gdb/onlinedocs/gdb/Python-API.html#Python-API
# https://sourceware.org/gdb/onlinedocs/gdb/Functions-In-Python.html
class Greet (gdb.Function):
  """Return string to greet someone.
  Takes a name as argument."""
  def __init__ (self):
    super (Greet, self).__init__ ("greet")
  def invoke (self, name):
    return "Hello, %s!" % name.string ()
Greet() # instantiate; then call in gdb: p $greet("myname")

#(gdb) python gdb.execute("p 22")
#$2 = 22

class Strp (gdb.Function):
  """Get a representation of gdb's printout as string
  Argument: the gdb command as string."""
  def __init__ (self):
    super (Strp, self).__init__ ("strp")
  def invoke (self, incmd):
    incmds = str(incmd)
    #print("is",incmds)
    # strip quotes
    if (incmds[0] == incmds[-1]) and incmds.startswith(("'", '"')):
      incmds = incmds[1:-1]
    rets=""
    try:
      rets += gdb.execute(incmds, from_tty=True, to_string=True)
    except Exception as e:
      rets += "Exception: {0}".format(e)
    #print("ret",ret)
    return rets
Strp() # instantiate; then call in gdb: p $strp("p 22")
# quotes end up in arg string, so by default getting Python Exception <class 'gdb.error'> Undefined command: "".  Try "help".: ... but then, if call WITHOUT quotes p $strp(p aa), gdb may interpret "p" as symbol (which doesn't exist) before it is sent as arg to python; therefore, use quotes, then strip them
end

Then, I can do in gdb:

(gdb) p $strp("x 22")
$1 = "Exception: Cannot access memory at address 0x16"
(gdb) p $strp("p 22")
$3 = "$2 = 22\n"
(gdb) p $strp("p aa")
$4 = "Exception: No symbol \"aa\" in current context."
(gdb) printf "%s\n", $strp("p 22")
You can't do that without a process to debug.

So, the regular gdb print does not need a process, however printf does - so after setting a breakpoint, and running the program/process in gdb, finally one can use both the Python function and printf at the prompt:

Breakpoint 1, main () at /...:17
17  int main( ){
(gdb) printf "%s\n", "aa"
aa
(gdb) printf "%s\n", $strp("p 22")
$12 = 22

(gdb) printf "%s\n", $strp("x 22")
Exception: Cannot access memory at address 0x16
(gdb) printf "%s\n", $strp("p aa")
Exception: No symbol "aa" in current context.
(gdb) printf "%s -- %s\n", $strp("p aa"), $strp("p 22")
Exception: No symbol "aa" in current context. -- $13 = 22

Comments

0

While you cannot do this without jumping through heroic means:

(gdb) printf "it is: '%s'\n", my_set
it is: 'Value can't be converted to integer.

You can break it down into more than one step. Perhaps not ideal, but it doesn't require creating a bunch of Python wrapper goo.

printf "it is: '"
output my_set
printf "'\n"

This of course is a little less useful interactively, but is perfectly reasonable in a custom-defined GDB command. This is probably the genesis of your question, as printfing to yourself in the interactive debugger is a little strange, but not wrong of course.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.