Fwd: Addresses in pretty-printing

Jim Blandy
2012-11-19T07:11:37Z

Quick summary: the patch discussed and approved in this long-ago
thread: http://sourceware.org/ml/gdb/2009-11/msg00105.html
causes silly output like this:

(gdb) print a
$1 = {ptr = }
(gdb) print s
$1 =

One particular patch is responsible. I suggest an extension to GDB's
Python interface that allows a cleaner solution.

In detail:

The original problem was that GDB showed string addresses where they
weren't wanted, according to gdb.python/py-prettyprint.exp. The test
wants the pretty-printer for this structure:

typedef struct string_repr
{
struct whybother
{
const char *contents;
} whybother;
} string;

to produce output like this:

$2 = "fnord"

instead of like this:

$1 = 0x403680 "fnord"

Here's the patch from that thread:

--- gdb/python/py-prettyprint.c#1 2009-11-09 17:58:39.000000000 -0800
+++ gdb/python/py-prettyprint.c 2009-11-09 16:51:16.862840000 -0800
@@ -209,7 +209,12 @@ print_string_repr (PyObject *printer, co
Py_DECREF (py_str);
}
else if (replacement)
- common_val_print (replacement, stream, recurse, options, language);
+ {
+ struct value_print_options opts = *options;
+
+ opts.addressprint = 0;
+ common_val_print (replacement, stream, recurse, &opts, language);
+ }
else
gdbpy_print_stack ();
}

It seems to me this change is over-broad: all addresses appearing
anywhere in the non-pretty printing of a replacement value get
omitted, even if they're, say, a 'void *' or a pointer to some
structure. For example, this is unhelpful:

$ cat pretty-printers.c
struct B { void *ptr; };
struct A { struct B b; };
int main() {
struct A a;
a.b.ptr = 0;
return 0;
};
$ cat pretty-printers-gdb.py
class ppA(object):
def __init__(self, value): self.value = value
def to_string(self): return self.value['b']
def lookup(value):
if value.type.tag == 'A': return ppA(value)
gdb.pretty_printers[:] = [lookup]
$ gcc -g3 -O0 pretty-printers.c -o pretty-printers
$ gdb pretty-printers
(gdb) break 6
Breakpoint 1 at 0x400538: file pretty-printers.c, line 6.
(gdb) run
Breakpoint 1, main () at pretty-printers.c:6
6 return 0;
(gdb) print a
$1 = {ptr = }
(gdb)

The pretty-printer returns a B as the replacement value, and since B
contains pointers, they don't print.

It's trouble for NULL 'char *' pointers too: we always omit the string
contents of a 'char *' when it's NULL, which makes sense; but if we
omit the address as well, then there's nothing left:

$ cat pp2.c
struct S { char *s; };
int main() {
struct S s;
s.s = 0;
return 0;
};
$ cat pp2-gdb.py
class ppS(object):
def __init__(self, value): self.value = value
def to_string(self): return self.value['s']
def lookup(value):
if value.type.tag == 'S': return ppS(value)
gdb.pretty_printers[:] = [lookup]
$ gcc -g3 -O0 pp2.c -o pp2
$ gdb pp2
(gdb) b 5
Breakpoint 1 at 0x400538: file pp2.c, line 5.
(gdb) run
Breakpoint 1, main () at pp2.c:5
5 return 0;
(gdb) p s
$1 =
(gdb)

That's not good.

Just on first principles, I think it's odd to answer the question "How
can I get GDB to print a string without the address?" with something
like "return it as a replacement value". But that's what the
aforementioned patch does. Whether a pretty-printer hands GDB a value
as a replacement value, or calls Python's 'str', or returns it as a
child, shouldn't affect whether addresses get printed.

I'd like to suggest an alternative: gdb.Value should have a 'format'
method that behaves almost like applying Python's 'str' built-in
function to the value, except that it allows you to specify print
options for that value and its sub-values. Thus, the pretty-printer in
py-prettyprint.exp would become, simply:

class string_print:
def __init__(self, val):
self.val = val

def to_string(self):
return self.val['whybother']['contents'].format({'address': False})

Here is proposed documentation for gdb.Value.format, and two
accompanying functions, gdb.value_print_options and
gdb.set_value_print_options. I'd be willing to implement something
like this.

@defun Value.format (print_options = None)
Return a string holding the text @value{GDBN} would produce if
printing this @code{gdb.Value}. If this value has a pretty-printer,
call that to produce the string; otherwise, use @value{GDBN}'s
built-in printing rules.

@var{print_options}, if given, is a dictionary of the sort returned by
@code{gdb.value_print_options}, binding names of print options to
values to use while formatting this value. These settings affect only
the formatting of this value and its children: when a call to this
function returns, all print settings remain as they were before the
call occurred.

The result of calling method is very similar to that of applying
Python's @code{str} built-in function to the @code{gdb.Value}
instance, except that one may pass a @var{print_options}
argument to affect the value's formatting.
@end defun

@findex gdb.value_print_options
@defun gdb.value_print_options ()
Return a dictionary providing the current values of @value{GDBN}'s
value printing settings, as controlled by the @code{set print} command
(and a few other @code{set} commands). The dictionary's keys are the
names of the print options; the value stored under each key is that
option's current value. The keys and their corresponding @code{set}
subcommands are as follows:

@table @code
@item 'output-radix'
@code{set output-radix}
@item 'elements'
@code{set print elements}
@item 'null-stop'
@code{set print null-stop}
@item 'repeats'
@code{set print repeats}
@item 'pretty'
@code{set print pretty}
@item 'union'
@code{set print union}
@item 'array'
@code{set print array}
@item 'address'
@code{set print address}
@item 'symbol'
@code{set print symbol}
@item 'array-indexes'
@code{set print array-indexes}
@item 'static-members'
@code{set print static-members}
@item 'vtbl'
@code{set print vtbl}
@item 'object'
@code{set print object}
@item 'pascal_static-members'
@code{set print pascal_static-members}
@item 'demangle'
@code{set print demangle}
@item 'asm-demangle'
@code{set print asm-demangle}
@item 'max-symbolic-offset'
@code{set print max-symbolic-offset}
@item 'symbol-filename'
@code{set print symbol-filename}
@item 'sevenbit-strings'
@code{set print sevenbit-strings}
@end table

The dictionary values are booleans or numbers, as appropriate for each
print setting.
@end defun

@findex gdb.set_value_print_options
@defun gdb.set_value_print_options (options)
Set the value printing options as given in @var{options}, a dictionary
whose items' keys name value printing options, and whose values are
the values to which those options should be set. Permitted keys are as
for @code{gdb.value_print_options}, described above.

Only those options named in the dictionary are affected, so you can
use this method to set individual options:

@smallexample
gdb.set_value_print_options({'demangle': False})
@end smallexample
@end defun