Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call constructor in gdb for pretty-printers

When debugging with GDB I would like to set a convenience variable to a newly constructed value.

I am programming using the Qt framework, so i would like to create a QString, but this is irrelevant to the question, since I would like to know how to do this with any class.

I tried

(gdb) set $str = 'QString::QString("abc")'
No symbol "QString::QString("abc")" in current context.

(gdb) set $str = QString::QString("abc")
Cannot resolve method QString::QString to any overloaded instance

(gdb) set $str = QString("abc")
A syntax error in expression, near `("abc")'.

then I tried using set overload-resolution off, resulting in the following:

set $str = QString::QString("abc")
non-unique member `QString' requires type instantiation

set $str = 'QString::QString(const char*)'("abc")
Too few arguments in function call.

So I assumed a this pointer is needed:

(gdb) set $str = 'QString::QString(const char*)'(malloc(sizeof(QString)), "abc")
(gdb) p $str
$8 = void

Okay, constructors return void, that means I have to save the return value of malloc somewhere:

(gdb) set $pointer = malloc(sizeof(QString))
(gdb) p $pointer
$9 = 6304560
(gdb) p/x $pointer
$10 = 0x603330
(gdb) set $str = 'QString::QString(const char*)'($pointer, "abc")
(gdb) p $str
$11 = void
(gdb) p $pointer
$12 = 6304560
(gdb) p *((QString*)$pointer)
$13 = "abc"

Okay, now this works as expected, however I want to use this code in gdb.parse_and_eval() for a python pretty printer. Now this will call malloc lots of times, creating a memory leak. So just call free()? Now something unexpected happens:

(gdb) call free($pointer)
$14 = 0
(gdb) p *((QString*)$pointer)
$15 = "abc"

The pointer still seems valid, which may of course be perfectly fine, since the memory has not been reused. However I am unsure whether this is okay because after allocating a few more memory blocks which fit exactly one QString the pointer value has still not been reused by malloc.

Am I creating a big memory-leak if I use this in a pretty-printer, which may well be called lots of times during a debug session? Is there any easier solution of creating the desired result (i.e. using the Python API)?

Also unrelated to this, why is free(3) giving me a return value of 0 while it is actually void?

like image 835
ar31 Avatar asked Aug 14 '11 22:08

ar31


People also ask

How do I enable pretty print in GDB?

in a directory of your choice (i.e. $(HOME)/distribs/gdb_printers). You will get 'python' subdirectory in the checkout directory. This makes pretty printing usable via command-line interface of gdb ( >(gdb) p my_std_string ).

What does incomplete type mean in GDB?

It means that the type of that variable has been incompletely specified. For example: struct hatstand; struct hatstand *foo; GDB knows that foo is a pointer to a hatstand structure, but the members of that structure haven't been defined. Hence, "incomplete type".


2 Answers

I do not know how to free the pointer. It seems to be impossible, but the memory leak created should be quite small. But I know how to remove the effect you described as

The pointer still seems valid, which may of course be perfectly fine, since the memory has not been reused. However I am unsure whether this is okay because after allocating a few more memory blocks which fit exactly one QString the pointer value has still not been reused by malloc.

See this code that should show how one could solve the problem (tested only on GNU gdb (GDB) SUSE (7.5.1-2.1.1))

(gdb) call malloc(sizeof(std::string))
$1 = (void *) 0x64e4d0
(gdb) call ((std::string*)0x64e4d0)->basic_string()
(gdb) call ((std::string*)0x64e4d0)->assign("Hello World")
$2 = "Hello World"
(gdb) call ((std::string*)0x64e4d0)->'~basic_string'((std::string*)0x64e4d0)
warning: Using non-standard conversion to match method std::string::~basic_string to supplied arguments
(gdb) print ((std::string*)0x64e4d0)
$3 = (std::string *) 0x64e4d0
(gdb) print *((std::string*)0x64e4d0)
$4 = ""
(gdb) call free(0x64e4d0)
(gdb) print *((std::string*)0x64e4d0)
$5 = ""

The reason why your version could not free the memory is that your free command only should affect the direct reserved memory (e.g. the pointers and basic types defined by the class), not the created object (meaning the memory reserved by the constructor and the methods of the object you might call).

One needs to call first the destructor of the created object and then free the pointer (line below $2 in my code).

As the last lines ($5) of my code imply the pretty printer of the gdb is able to restore the content of the object even when the memory of the object is not longer occupied by the process. The reason might be that the printer could do this with nearly every memory address and when no other process had written something to this place (that we had occupied a few seconds before) we would get the same results as when free was not called.

PS: The format of the destructor and the warning should show you that it is a little bit tricky to find the right expression of the destructor. I have no actual QT-Project to try this with QString, but it should be quite near that I have done.

like image 71
msebas Avatar answered Sep 19 '22 08:09

msebas


What are you trying to do? If you want to pretty-print a QString with gdb, use gdb's Python pretty printer API. See http://sourceware.org/gdb/onlinedocs/gdb/Pretty-Printing.html for details. You can use a Python printer class like the following:

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

    def to_string(self):
        if self.val['d'] == self.val['shared_null'].address:
            return 0

        dataptr = self.val['d']['data'].cast(gdb.lookup_type('char').pointer())
        size = self.val['d']['size']

        if sys.byteorder == 'little':
            enc = 'utf_16_le'
        else:
            enc = 'utf_16_be'
        return dataptr.string(enc, 'ignore', size * 2)

    def display_hint(self):
        return 'string'
like image 32
emkey08 Avatar answered Sep 22 '22 08:09

emkey08