printing gmp/mpfr/mpc types from gdb

Emmanuel Thomé Emmanuel.Thome at gmail.com
Tue Apr 19 22:49:21 CEST 2011


Dear GMP folks.

I am here drawing your attention to a recent evolution to the GNU
debugger program, which is potentially tremendously useful for GMP users
(at least those who occasionally write programs with bugs ;-). When I
first came across this, a bleeding edge version of gdb was needed. Now
that gdb has been out for a while, I think most people can use this
solution ``out of the box'' on their linux distribution. This might be
standard stuff for some, but it's good to know, and interesting enough to
be publicized also for those who are not aware of it already.

The documentation text follows. Example code is attached.

Best,

E.



This mail describes a way to print gmp/mpfr/mpc types from the gdb
debugger, which has been made possible with the inclusion of python
scripting support by Tom Tromey in recent gdb releases:

http://sourceware.org/gdb/current/onlinedocs/gdb/Python.html

For the documented approach to work, I think gdb 7.1 is absolutely
mandatory, and gdb 7.2 is recommended because of a nasty bug which has
been fixed
(http://comments.gmane.org/gmane.comp.gdb.patches/59238)

There are several folklore ways to print e.g. gmp types from gdb:
 - include a debug printing function inside the code. This has its
   merits, but just to mention the downside, this requires
   recompiling, introduces bloat in code, and turns out to be fragile
   when the program's memory is slightly corrupted. At least it causes
   the program to do malloc's
 - call gmp_printf from gdb. Does not require recompiling, but works only
   if the function is linked from the code. Requires knowing the mangled
   name, requires stdout to be accessible, often needs explicit fflush(),
   and is overall just as fragile as above.
 - use gdb macros in a .gdbinit file. Not as intrusive as the above,
   works solid, but does not do much since the gdb macro language is
   not very powerful.

The fourth way I'm describing calls a python script to do the printing.
gdb has now an interface which exposes requested portion of the memory of
the guest (debugged program) to a python script which is being run by the
host (debugger). This interface creates a python object from any guest
data, and it's possible to cast anything from this python object to
fields of the desired type.

Then it's possible to register a hook function which reads the type of a
to-be-printed guest object, and based on this, returns another python
object (typically of a sub-class inheriting from the python-ified guest
object). The to_string() of the latter object is then used to do the
printing. It's the python script's job to do the printing, and this
printing task has to be run from the host.

The attached mp_types.py is an example of what it takes to have it work.
For convenience, the suggested solution uses the gmpy python module for
the purpose of converting long integers to strings (the debian package is
python-gmpy).

Consider the example code in test.c (attached).
The python script mp_types.py is attached.

Here is a transcript of a gdb session:

    tiramisu ~ $ gdb -q ./test 
    Reading symbols from /users/caramel/thome/test...done.
    (gdb) b f
    Breakpoint 1 at 0x4009c9: file test.c, line 8.
    (gdb) r
    Starting program: /users/caramel/thome/test 

    Breakpoint 1, f (z=0x7fffffffdf50, r=0x7fffffffdf30, c=0x7fffffffdef0)
        at test.c:8
    8           mpz_mul(z,z,z);


Usual.

    (gdb) source mp_types.py
    (gdb) c
    Continuing.

    Breakpoint 1, f (z=289, r=17.6399999999999999999999...<11>...35454, c=
        1.12000000000000000000000...<11>...97597+i*-0.6600000000000000000000...<13>...31604) at test.c:8
    8           mpz_mul(z,z,z);

See how the function's arguments are now pretty-printed. The angle
brackets are here to guard against possibly huge data.

I can now also print mpz's as if they were normal integers.

    (gdb) p z
    $1 = 289
    (gdb) n
    9           mpfr_mul(r,r,r,GMP_RNDN);
    (gdb) p z
    $2 = 83521
    (gdb) c
    Continuing.

    Breakpoint 1, f (z=83521, r=311.169599999999999999999...<11>...73915, c=
        0.81880000000000000000000...<11>...59456+i*-1.4784000000000000000000...<12>...47297) at test.c:8
    8           mpz_mul(z,z,z);

Now I can continue and have larger data to print:

    (gdb) c 8
    Will ignore next 7 crossings of breakpoint 1.  Continuing.

    Breakpoint 1, f (z=9543232209081078068902717...<1230>...97121, r=
        1.61165977814096161493177...<15>...9e638, c=
        -1.7020615426923067363920...<15>...87e58+i*-1.3664614788900630293395...<15>...01e58) at test.c:8
    8           mpz_mul(z,z,z);

The issue here is that for mpz's, or any large data involving megabytes
of mutiprecision data, you don't want this pretty-printing to happen
every so often. However I believe this illustrates the advantages of the
approach. Python is easy to hack, and I believe the interested readers
should be able to work around this issue (in fact it's left as an
exercise).

E.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: test.c
Type: text/x-csrc
Size: 659 bytes
Desc: not available
URL: <http://gmplib.org/list-archives/gmp-discuss/attachments/20110419/54e93657/attachment.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: mp_types.py
Type: text/x-python
Size: 5772 bytes
Desc: not available
URL: <http://gmplib.org/list-archives/gmp-discuss/attachments/20110419/54e93657/attachment.py>


More information about the gmp-discuss mailing list