--- gdb/doc/gdb.texinfo (revision 4579) +++ gdb/doc/gdb.texinfo (local) @@ -19304,7 +19304,9 @@ access this functionality: @item @code{-var-info-type} @tab show the type of this variable object @item @code{-var-info-expression} -@tab print what this variable object represents +@tab print parent-relative expression that this variable object represents +@item @code{-var-info-path-expression} +@tab print full expression that this variable object represents @item @code{-var-show-attributes} @tab is this variable editable? does it exist here? @item @code{-var-evaluate-expression} @@ -19505,8 +19507,36 @@ returned as a string in the same format -var-info-expression @var{name} @end smallexample -Returns what is represented by the variable object @var{name}: +Returns the expression that is represented by the variable object +@var{name}, that is relative to parent variable object and is +suitable for presenting this variable object is user interface: + +@smallexample + lang=@var{lang-spec},exp=@var{expression} +@end smallexample + +@noindent +where @var{lang-spec} is @code{@{"C" | "C++" | "Java"@}}. + +@subheading The @code{-var-info-path-expression} Command +@findex -var-info-path-expression + +@subsubheading Synopsis + +@smallexample + -var-info-path-expression @var{name} +@end smallexample + +Returns a full expression that can be evaluated in the current +context and corresponds to the variable object. Unlike the +@code{-var-info-expression} command, the returned expression is not relative +to parent and can be used to create another variable object that will +always have the same value as the other variable object. Typical +use of @code{-var-info-path-expression} is creating a watchpoint from +a variable object. + +Example output: @smallexample lang=@var{lang-spec},exp=@var{expression} @end smallexample --- gdb/mi/mi-cmd-var.c (revision 4579) +++ gdb/mi/mi-cmd-var.c (local) @@ -422,7 +422,7 @@ mi_cmd_var_info_path_expression (char *c if (argc != 1) error (_("Usage: NAME.")); - /* Get varobj handle, if a valid var obj name was specified */ + /* Get varobj handle, if a valid var obj name was specified. */ var = varobj_get_handle (argv[0]); if (var == NULL) error (_("Variable object not found")); --- gdb/testsuite/gdb.mi/mi-var-cp.cc (revision 4579) +++ gdb/testsuite/gdb.mi/mi-var-cp.cc (local) @@ -121,11 +121,97 @@ int reference_to_struct () /*: END: reference_to_struct :*/ } +struct Base1 +{ + int i; +}; + +struct Base2 +{ + int i; +}; + +struct Derived : public Base1, public Base2 +{ + int i; +}; + +/* Test for the -var-info-path-expression command. Although + said command is not specific to C++, it's of more importance + to C++ than to C, so we test it in mi-var-cp test. */ +int path_expression () +{ + /*: BEGIN: path_expression :*/ + int i = 10; + int *ip = &i; + /*: mi_create_varobj IP ip "create varobj for ip" + mi_list_varobj_children IP {{IP.\\*ip \\*ip 0 int}} "list children of IP" + mi_gdb_test "-var-info-path-expression IP.*ip" \ + "\\^done,path_expr=\"\\*\\(ip\\)\"" \ + "-var-info-path-expression IP.*ip" + :*/ + Derived d; + Derived *dp = &d; + /*: mi_create_varobj DP dp "create varobj for dp" + mi_list_varobj_children DP \ + {{DP.Base1 Base1 1 Base1} \ + {DP.Base2 Base2 1 Base2} \ + {DP.public public 1}} "list children of DP" + mi_gdb_test "-var-info-path-expression DP.Base1" \ + "\\^done,path_expr=\"\\(\\*\\(Base1\\*\\) dp\\)\"" \ + "-var-info-path-expression DP.Base1" + mi_list_varobj_children DP.public { \ + {DP.public.i i 0 int} \ + } "list children of DP.public" + mi_gdb_test "-var-info-path-expression DP.public.i" \ + "\\^done,path_expr=\"\\(\\(dp\\)->i\\)\"" \ + "-var-info-path-expression DP.public.i" + mi_list_varobj_children DP.Base1 { \ + {DP.Base1.public public 1} \ + } "list children of DP.Base1" + mi_list_varobj_children DP.Base1.public { \ + {DP.Base1.public.i i 0 int} \ + } "list children of DP.Base1.public" + mi_gdb_test "-var-info-path-expression DP.Base1.public.i" \ + "\\^done,path_expr=\"\\(\\(\\(\\*\\(Base1\\*\\) dp\\)\\).i\\)\"" \ + "-var-info-path-expression DP.Base1.public.i" + + mi_gdb_test "-var-info-path-expression DP.public" \ + "\\^done,path_expr=\"\"" \ + "-var-info-path-expression DP.public" + + mi_create_varobj D d "create varobj for d" + mi_list_varobj_children D \ + {{D.Base1 Base1 1 Base1} \ + {D.Base2 Base2 1 Base2} \ + {D.public public 1}} "list children of D" + mi_gdb_test "-var-info-path-expression D.Base1" \ + "\\^done,path_expr=\"\\(\\(Base1\\) d\\)\"" \ + "-var-info-path-expression D.Base1" + :*/ + int array[4] = {1,2,3}; + array[3] = 10; + /*: mi_create_varobj A array "create varobj for array" + mi_list_varobj_children A { \ + {A.0 0 0 int} + {A.1 1 0 int} + {A.2 2 0 int} + {A.3 3 0 int}} "list children of A" + mi_gdb_test "-var-info-path-expression A.2" \ + "\\^done,path_expr=\"\\(array\\)\\\[2\\\]\"" \ + "-var-info-path-expression A.2" + :*/ + + return 99; + /*: END: path_expression :*/ +} + int main () { reference_update_tests (); base_in_reference_test_main (); reference_to_pointer (); reference_to_struct (); + path_expression (); return 0; } --- gdb/testsuite/gdb.mi/mi-var-cp.exp (revision 4579) +++ gdb/testsuite/gdb.mi/mi-var-cp.exp (local) @@ -45,6 +45,7 @@ mi_run_inline_test reference_update mi_run_inline_test base_in_reference mi_run_inline_test reference_to_pointer mi_run_inline_test reference_to_struct +mi_run_inline_test path_expression mi_gdb_exit return 0 --- gdb/varobj.c (revision 4579) +++ gdb/varobj.c (local) @@ -102,7 +102,7 @@ struct varobj char *name; /* Alloc'd expression for this child. Can be used to create a - root variable corresponding to this child. */ + root variable corresponding to this child. */ char *path_expr; /* The alloc'd name for this variable's object. This is here for @@ -829,7 +829,7 @@ varobj_get_gdb_type (struct varobj *var) } /* Return a pointer to the full rooted expression of varobj VAR. - If it has not been computed yet, compute it */ + If it has not been computed yet, compute it. */ char * varobj_get_path_expr (struct varobj *var) { @@ -2497,8 +2497,16 @@ cplus_describe_child (struct varobj *par if (cfull_expression) { - char *ptr = was_ptr ? " *" : ""; - *cfull_expression = xstrprintf ("((%s%s) %s)", + char *ptr = was_ptr ? "*" : ""; + /* Cast the parent to the base' type. Note that in gdb, + expression like + (Base1)d + will create an lvalue, for all appearences, so we don't + need to use more fancy: + *(Base1*)(&d) + construct. */ + *cfull_expression = xstrprintf ("(%s(%s%s) %s)", + ptr, TYPE_FIELD_NAME (type, index), ptr, parent_expression);