Bug 13393 - There is no way to access runtime type of C++ variable via MI (using RTTI)
Summary: There is no way to access runtime type of C++ variable via MI (using RTTI)
Status: RESOLVED FIXED
Alias: None
Product: gdb
Classification: Unclassified
Component: mi (show other bugs)
Version: 7.3
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
: 10715 (view as bug list)
Depends on:
Blocks:
 
Reported: 2011-11-08 08:31 UTC by Anton
Modified: 2012-04-14 12:23 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments
Screenshot of Qt Creator display (29.32 KB, image/png)
2011-11-09 07:17 UTC, Andre'
Details
proposed fixture (297 bytes, patch)
2011-11-10 09:09 UTC, Anton
Details | Diff
Proposed fixture (see details in comment) (5.23 KB, patch)
2011-11-28 17:13 UTC, Anton
Details | Diff
Proposed fixture with type update and a few small corrections (5.84 KB, patch)
2011-12-02 17:16 UTC, Anton
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Anton 2011-11-08 08:31:37 UTC
The CLI "print" command shows user runtime type of C++ variable based on RTTI if "set print object" is "on". So gdb can show "real" type name for the objects that are stored by the interfaces and show their internals. Unfortunately, this information is not available via MI, so a lot of GUI tools that use it (like Eclipse CDT, Qt Creator, ...) cann't access it.

Here is an example that demonstrates the case described above:

struct Base {
    Base() : a(1) {}
    virtual ~Base() {}  // Enforce type to have RTTI
    int a;
};

struct Derived : public Base {
    Derived() : b(2) {}
    int b;
};

int main() {
    Derived b;
    Base* aPtr = &b;
    return 0;          // <= Set breakpoint here
}

Here is an example of CLI session:
(gdb) p b
$1 = (Derived) {<Base> = {_vptr.Base = 0x8048788, a = 1}, b = 2}
(gdb) p *aPtr
$2 = {_vptr.Base = 0x8048788, a = 1}
(gdb) set print object on
(gdb) p *aPtr
$3 = (Derived) {<Base> = {_vptr.Base = 0x8048788, a = 1}, b = 2}

Here is a fragment of MI session by Eclipse CDT ("set print object on" is done in .gdbinit):
782,149 (gdb)
782,149 23-var-create --thread 1 --frame 0 - * b
782,150 24-var-create --thread 1 --frame 0 - * aPtr
782,150 23^done,name="var1",numchild="2",value="{...}",type="Derived",thread-id="1",has_more="0"
782,150 (gdb)
782,150 24^done,name="var2",numchild="1",value="0xbffff428",type="Base *",thread-id="1",has_more="0"\


So can the "-var-create" command be extended to provide such information? Or maybe another command that will do it? Or the value of "type" field of "-var-create" command result will depend on "set print object"?

Maybe the next bugs are connected to this one:
Bug 9197 - Type printing uses different code from value access.
Bug 9257 - set print object on does not work
Comment 1 Tom Tromey 2011-11-08 16:41:57 UTC
*** Bug 10715 has been marked as a duplicate of this bug. ***
Comment 2 Andre' 2011-11-08 16:55:47 UTC
Qt Creator properly displays the "Derived" type in this case.
Comment 3 Anton 2011-11-08 21:37:47 UTC
(In reply to comment #2)
> Qt Creator properly displays the "Derived" type in this case.

On what platform and for what debugger (AFAIK it supports gdb & cdb)? If gdb - can you clarify, how does it work? Does it use its own dumpers system?
Comment 4 Andre' 2011-11-09 07:17:00 UTC
Created attachment 6045 [details]
Screenshot of Qt Creator display
Comment 5 Anton 2011-11-09 11:36:30 UTC
Ok, I figured out that Qt Creator uses its own dumping system that relies on python interface to gdb. So it just use "dynamic_type" property of gdb value object. However, Eclipse CDT (and many other tools, I believe) uses standard MI interface.

So I am wondering what is the preferable way to provide this information:
  - the "-var-create" command extension;
  - some another command creation;
  - "set print object" should affect MI interface;
  - some MI analogs of "set print object" command should be implemented;
Comment 6 Andre' 2011-11-09 13:17:35 UTC
I've been using the MI/varobj approach for quite some time (and unfortunately still have to on Mac) and it simply does not scale beyond simple scenarios like, say dumping a std::vector or std::map or such. For more complex displays it is far too inflexible and requires too many roundtrips translating directly into "waiting time" for the user. It's strictly no fun to work with, both from a frontend implementor's and an end user's perspective. An "all python" approach for data display is much more flexible, faster, and easier to extend for users.

Also, gdb/MI in general has essentially been unmaintained for a more than year now (yes, I am aware of the added breakpoint notifications last April...),
whereas gdb/Python has improved a lot in the meantime. So even assuming that the general MI/varobj approach would feasible in general (which I honestly doubt, e.g. the question which kind of data is "needed" in a response can never be answered in a frontend agnostic way and just spawned endless discussions with no tangible outcome in the past) I don't see evidence that gdb/MI could catch up to where gdb/Python already is in any interesting time frame. -- -- It's dead, Jim ;-|
Comment 7 Tom Tromey 2011-11-09 15:25:24 UTC
(In reply to comment #5)

> So I am wondering what is the preferable way to provide this information:
[...]
>   - "set print object" should affect MI interface;

I think this would be a natural approach.
Comment 8 Anton 2011-11-10 09:09:25 UTC
Created attachment 6047 [details]
proposed fixture

Here is the proposed fixture of the problem.
Comment 9 Anton 2011-11-10 09:12:01 UTC
Here are a few MI commands to reproduce the problem on example posted above:
-interpreter-exec console "set print object on"
-break-insert test_case.cpp:19
-exec-run
-var-create v * *aPtr

Actual behavior: type of varobj v is Base.
Expected: type of varobj v is Derived.
Comment 10 Tom Tromey 2011-11-10 21:05:41 UTC
I think this patch is probably necessary, but I am not certain
that it is sufficient.  E.g., why isn't create_child_with_value modified?
Comment 11 Anton 2011-11-11 20:13:43 UTC
You are right. I have missed a few places. I'll try to provide a new patch soon.
Comment 12 Anton 2011-11-28 17:13:45 UTC
Created attachment 6076 [details]
Proposed fixture (see details in comment)

Ok, finally I have researched this problem more carefully and I am ready to propose a new patch. However there are a few notes that I want to share:
- currently gdb loses cv-qualifiers after RTTI type access. The simplest way to check it - make a print command on any "const Base*" value. It will be "Derived*" if "set print object" is on (by the way, Qt Creator loses it too). This patch fixes this problem for gdb MI&CLI (and maybe for Qt Creator too - a didn't check it)
- whatis command does not work for C++ references. It prints an error instead of reference type. The proposed patch fixes this problem for gdb MI&CLI too (by the way, Qt Creator does not show a real type for references too, but I think this patch will not help it).
- indirect pointers (I mean pointer to pointer or reference to pointer and so on) do not have a real type in whatis/print commands. The proposed patch does not fix this problem because there is another problem in gdb which does not allow to cast pointer to reference to pointer ("T*" => "T*&"). If it will be fixed it is quite easy to provide support of indirect references too (a few changes in value_rtti_target_type() should be enough).
- the last unresolved problem is type update when value changed. I am not sure about how it should be done. Should we just set "type_changed" & "new_type" properties in the result of -var-update command? If so I think not all frontends will support it (at least Eclipse will not - I have checked it). Or maybe we should create dynamic varobj some how? Can somebody advice me something about it?
Comment 13 Anton 2011-11-28 17:17:06 UTC
An extended example:


#include <boost/shared_ptr.hpp>

struct Base {
    Base() : a(1) {}
    virtual ~Base() {}  // Enforce type to have RTTI
    int a;
};


struct Derived : public Base {
    Derived() : b(2), c(3) {}
    int b;
    int c;
};


struct S
{
	Base* ptr;
	const Base* ptrConst;
	Base& ref;
	const Base& refConst;

	S(Derived& d)
		:	ptr ( &d )
		,	ptrConst ( &d )
		,	ref ( d )
		,	refConst ( d ) {};
};

int main() {
	Derived d;
	S s(d);
	Base* ptr = &d;
	const Base* ptrConst = &d;
	Base& ref = d;
	const Base& refConst = d;
	Base** ptrToPtr = &ptr;
        // Interesting if pretty printer is used
	boost::shared_ptr<Base> sharedPtr (new Derived());  
	return 0;
}
Comment 14 Andre' 2011-11-28 17:33:03 UTC
The dropping of "const" and "&" in the display in Qt Creator is intentional. Showing it (which had been possible in the past) is considered unhelpful noise with negligible benefit in fringe cases only. The "real" type is accessible through the main editor/F2 anyway. So if you can trigger a display of (toplevel) "const" or "&" for any output gdb (with or without your improvements) produces, please file a bug.
Comment 15 Anton 2011-11-28 17:56:34 UTC
(In reply to comment #14)
> The dropping of "const" and "&" in the display in Qt Creator is intentional.
> Showing it (which had been possible in the past) is considered unhelpful noise
> with negligible benefit in fringe cases only. The "real" type is accessible
> through the main editor/F2 anyway. So if you can trigger a display of
> (toplevel) "const" or "&" for any output gdb (with or without your
> improvements) produces, please file a bug.

Thanks for clarification. I did not check Qt Creator with gdb patched by me (because I cannot force it to use custom gdb), I have just made a few assumptions based on how it looks from inside. Maybe I am wrong.

However, I don't think that "const" and "&" is unhelpful noise I can remove these changes from my patch.

P.S. I have just checked Microsoft Visual Studio 2008 and find out that it shows "const" and "&" too.
Comment 16 Anton 2011-12-02 09:29:54 UTC
So... Can anybody review my patch or answer my questions above (one is about type update when the value is changed and the second is about "T*" => "T*&" conversion issue in gdb)? Should I do something else to make it happen (e.g. write to the gdb-dev mailing list or something else)?
Comment 17 Anton 2011-12-02 17:16:15 UTC
Created attachment 6085 [details]
Proposed fixture with type update and a few small corrections

Finally I decided to set "type_changed" & "new_type" properties in the result of -var-update command cause dynamic variables seem to be something different. Moreover, this patch also fixes type names of children that were obtained from pretty printers.
Comment 18 Tom Tromey 2011-12-02 19:00:51 UTC
(In reply to comment #12)
> Created attachment 6076 [details]

> - indirect pointers (I mean pointer to pointer or reference to pointer and so
> on) do not have a real type in whatis/print commands. The proposed patch does
> not fix this problem because there is another problem in gdb which does not
> allow to cast pointer to reference to pointer ("T*" => "T*&"). If it will be
> fixed it is quite easy to provide support of indirect references too (a few
> changes in value_rtti_target_type() should be enough).

Please file a separate bug for the cast problem.

> - the last unresolved problem is type update when value changed. I am not sure
> about how it should be done. Should we just set "type_changed" & "new_type"
> properties in the result of -var-update command? If so I think not all
> frontends will support it (at least Eclipse will not - I have checked it). Or
> maybe we should create dynamic varobj some how? Can somebody advice me
> something about it?

I think it is fine to add new fields to varobj without expecting all front
ends to immediately respect them.  So, emitting type_changed and new_type is
fine.  Front ends are supposed to ignore fields they don't understand.
Comment 19 Tom Tromey 2011-12-02 19:02:38 UTC
(In reply to comment #16)
> So... Can anybody review my patch or answer my questions above (one is about
> type update when the value is changed and the second is about "T*" => "T*&"
> conversion issue in gdb)? Should I do something else to make it happen (e.g.
> write to the gdb-dev mailing list or something else)?

The best way is to submit it to gdb-patches following the contribution
instructions

http://sourceware.org/gdb/contribute/
Comment 20 Anton 2011-12-16 08:07:33 UTC
Some time ago I have provided a patch (http://sourceware.org/ml/gdb-patches/2011-12/msg00052.html) the fixes the problem, but have not receive any response. So I try to pay attention on it once again via this bug.
Comment 21 Tom Tromey 2011-12-16 14:48:27 UTC
(In reply to comment #20)
> Some time ago I have provided a patch
> (http://sourceware.org/ml/gdb-patches/2011-12/msg00052.html) the fixes the
> problem, but have not receive any response. So I try to pay attention on it
> once again via this bug.

We haven't forgotten, someone will review it eventually.
I suggest sending a ping email after a week or so,and then once
per week thereafter until someone replies.
Comment 22 Sourceware Commits 2012-04-14 12:19:05 UTC
CVSROOT:	/cvs/src
Module name:	src
Changes by:	xgsa@sourceware.org	2012-04-14 12:18:51

Modified files:
	gdb/doc        : gdb.texinfo ChangeLog 
	gdb/testsuite/lib: mi-support.exp 
	gdb            : ChangeLog value.h varobj.c value.c 
	gdb/testsuite  : ChangeLog 
Added files:
	gdb/testsuite/gdb.mi: mi-var-rtti.cc mi-var-rtti.exp 

Log message:
	gdb/doc/ChangeLog:
	
	2012-04-14  Anton Gorenkov <xgsa@yandex.ru>
	
	PR mi/13393
	* gdb.texinfo (Print Settings): Extend the description for "set print
	object".
	(GDB/MI Variable Objects): Extend the description for -var-create and
	-var-list-children.
	
	gdb/testsuite/ChangeLog:
	
	2012-04-14  Anton Gorenkov <xgsa@yandex.ru>
	
	PR mi/13393
	* gdb.mi/mi-var-rtti.cc: New file.
	* gdb.mi/mi-var-rtti.exp: New file.
	* lib/mi-support.exp (mi_varobj_update_with_child_type_change): New
	function.
	(mi_varobj_update_with_type_change): updated to avoid code duplication.
	
	gdb/ChangeLog:
	
	2012-04-14  Anton Gorenkov <xgsa@yandex.ru>
	
	PR mi/13393
	* value.c (value_actual_type): New function.
	* value.h (value_actual_type): New declaration.
	* varobj.c (update_type_if_necessary): New function.
	(varobj_create): Call value_actual_type instead of
	value_type.
	(install_dynamic_child): distinct changed and type changed MI variable
	objects.
	(update_dynamic_varobj_children): Updated for install_dynamic_child
	change.  All callers updated.
	(varobj_update): Support for MI variable object type change if
	the value changed and RTTI is used to determine the type.
	(create_child_with_value): Call value_actual_type instead of
	value_type.
	(adjust_value_for_child_access): Extended with a new parameter which
	specify whether the given value should be casted to enclosing type.
	All callers updated.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/testsuite/gdb.mi/mi-var-rtti.cc.diff?cvsroot=src&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/testsuite/gdb.mi/mi-var-rtti.exp.diff?cvsroot=src&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/doc/gdb.texinfo.diff?cvsroot=src&r1=1.940&r2=1.941
http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/doc/ChangeLog.diff?cvsroot=src&r1=1.1293&r2=1.1294
http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/testsuite/lib/mi-support.exp.diff?cvsroot=src&r1=1.110&r2=1.111
http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/ChangeLog.diff?cvsroot=src&r1=1.14105&r2=1.14106
http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/value.h.diff?cvsroot=src&r1=1.200&r2=1.201
http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/varobj.c.diff?cvsroot=src&r1=1.194&r2=1.195
http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/value.c.diff?cvsroot=src&r1=1.155&r2=1.156
http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/testsuite/ChangeLog.diff?cvsroot=src&r1=1.3159&r2=1.3160
Comment 23 Anton 2012-04-14 12:23:56 UTC
The fix was checked in.