gdb/
* Makefile.in (SFILES): Add c-varobj.c and jv-varobj.c.
(COMMON_OBS): Add c-varobj.o and jv-varobj.o.
* ada-varobj.c: Include "varobj.h".
(ada_number_of_children): New. Moved from varobj.c.
(ada_name_of_variable, ada_name_of_child): Likewise.
(ada_path_expr_of_child, ada_value_of_child): Likewise.
(ada_type_of_child, ada_value_of_variable): Likewise.
(ada_value_is_changeable_p, ada_value_has_mutated): Likewise.
(ada_varobj_ops): New.
* c-varobj.c, jv-varobj.c: New file. Moved from varobj.c.
* gdbtypes.c (get_target_type): New. Moved from varobj.c.
* gdbtypes.h (get_target_type): Declare.
* varobj.c: Remove the inclusion of "ada-varobj.h" and
"ada-lang.h".
(ANONYMOUS_STRUCT_NAME): Move it to c-varobj.c.
(ANONYMOUS_UNION_NAME): Likewise.
(get_type, get_value_type, get_target_type): Remove declarations.
(value_get_print_value, varobj_value_get_print_value): Likewise.
(c_number_of_children, c_name_of_variable): Likewise.
(c_name_of_child, c_path_expr_of_child): Likewise.
(c_value_of_child, c_type_of_child): Likewise.
(c_value_of_variable, cplus_number_of_children): Likewise.
(cplus_class_num_children, cplus_name_of_variable): Likewise.
(cplus_name_of_child, cplus_path_expr_of_child): Likewise.
(cplus_value_of_child, cplus_type_of_child): Likewise.
(cplus_value_of_variable, java_number_of_children): Likewise.
(java_name_of_variable, java_name_of_child): Likewise.
(java_path_expr_of_child, java_value_of_child): Likewise.
(java_type_of_child, java_value_of_variable): Likewise.
(ada_number_of_children, ada_name_of_variable): Likewise.
(ada_name_of_child, ada_path_expr_of_child): Likewise.
(ada_value_of_child, ada_type_of_child): Likewise.
(ada_value_of_variable, ada_value_is_changeable_p): Likewise.
(ada_value_has_mutated): Likewise.
(struct language_specific): Move it to varobj.h.
(CPLUS_FAKE_CHILD): Move it to varobj.h.
(restrict_range): Rename it varobj_restrict_range. Make it extern.
Callers update.
(get_path_expr_parent): Rename it to varobj_get_path_expr_parent.
Make it extern.
(is_anonymous_child): Move it to c-varobj.c and rename to
varobj_is_anonymous_child. Caller update.
(get_type): Move it to c-varobj.c.
(get_value_type): Rename it varobj_get_value_type. Make it
extern.
(get_target_type): Move it gdbtypes.c.
(varobj_formatted_print_options): New function.
(value_get_print_value): Rename it to
varobj_value_get_print_value and make it extern.
(varobj_value_is_changeable_p): Make it extern.
(adjust_value_for_child_access): Move it to c-varobj.c.
(default_value_is_changeable_p): Rename it to
varobj_default_value_is_changeable_p. Make it extern.
(c_number_of_children, c_name_of_variable): Move it to c-varobj.c
(c_name_of_child, c_path_expr_of_child): Likewise.
(c_value_of_child, c_type_of_child): Likewise.
(c_value_of_variable, cplus_number_of_children): Likewise.
(cplus_class_num_children, cplus_name_of_variable): Likewise.
(cplus_name_of_child, cplus_path_expr_of_child): Likewise.
(cplus_value_of_child, cplus_type_of_child): Likewise.
(cplus_value_of_variable): Likewise.
(java_number_of_children, java_name_of_variable): Move it to jv-varobj.c.
(java_name_of_child, java_path_expr_of_child): Likewise.
(java_value_of_child, java_type_of_child): Likewise.
(java_value_of_variable): Likewise.
(ada_number_of_children, ada_name_of_variable): Move it to ada-varobj.c.
(ada_name_of_child, ada_path_expr_of_child): Likewise.
(ada_value_of_child, ada_type_of_child): Likewise.
(ada_value_of_variable, ada_value_is_changeable_p): Likewise.
(ada_value_has_mutated): Likewise.
* varobj.h (CPLUS_FAKE_CHILD): New macro, moved from varobj.c.
(struct lang_varobj_ops): New. Renamed by 'struct language_specific'.
(c_varobj_ops, cplus_varobj_ops): Declare.
(java_varobj_ops, ada_varobj_ops): Declare.
(varobj_default_value_is_changeable_p): Declare.
(varobj_value_is_changeable_p): Declare.
(varobj_get_value_type, varobj_is_anonymous_child): Declare.
(varobj_get_path_expr_parent): Declare.
(varobj_value_get_print_value): Declare.
(varobj_formatted_print_options): Declare.
(varobj_restrict_range): Declare.
2013-10-17 21:28:37 +08:00
|
|
|
|
/* varobj support for C and C++.
|
|
|
|
|
|
2015-01-01 17:32:14 +08:00
|
|
|
|
Copyright (C) 1999-2015 Free Software Foundation, Inc.
|
gdb/
* Makefile.in (SFILES): Add c-varobj.c and jv-varobj.c.
(COMMON_OBS): Add c-varobj.o and jv-varobj.o.
* ada-varobj.c: Include "varobj.h".
(ada_number_of_children): New. Moved from varobj.c.
(ada_name_of_variable, ada_name_of_child): Likewise.
(ada_path_expr_of_child, ada_value_of_child): Likewise.
(ada_type_of_child, ada_value_of_variable): Likewise.
(ada_value_is_changeable_p, ada_value_has_mutated): Likewise.
(ada_varobj_ops): New.
* c-varobj.c, jv-varobj.c: New file. Moved from varobj.c.
* gdbtypes.c (get_target_type): New. Moved from varobj.c.
* gdbtypes.h (get_target_type): Declare.
* varobj.c: Remove the inclusion of "ada-varobj.h" and
"ada-lang.h".
(ANONYMOUS_STRUCT_NAME): Move it to c-varobj.c.
(ANONYMOUS_UNION_NAME): Likewise.
(get_type, get_value_type, get_target_type): Remove declarations.
(value_get_print_value, varobj_value_get_print_value): Likewise.
(c_number_of_children, c_name_of_variable): Likewise.
(c_name_of_child, c_path_expr_of_child): Likewise.
(c_value_of_child, c_type_of_child): Likewise.
(c_value_of_variable, cplus_number_of_children): Likewise.
(cplus_class_num_children, cplus_name_of_variable): Likewise.
(cplus_name_of_child, cplus_path_expr_of_child): Likewise.
(cplus_value_of_child, cplus_type_of_child): Likewise.
(cplus_value_of_variable, java_number_of_children): Likewise.
(java_name_of_variable, java_name_of_child): Likewise.
(java_path_expr_of_child, java_value_of_child): Likewise.
(java_type_of_child, java_value_of_variable): Likewise.
(ada_number_of_children, ada_name_of_variable): Likewise.
(ada_name_of_child, ada_path_expr_of_child): Likewise.
(ada_value_of_child, ada_type_of_child): Likewise.
(ada_value_of_variable, ada_value_is_changeable_p): Likewise.
(ada_value_has_mutated): Likewise.
(struct language_specific): Move it to varobj.h.
(CPLUS_FAKE_CHILD): Move it to varobj.h.
(restrict_range): Rename it varobj_restrict_range. Make it extern.
Callers update.
(get_path_expr_parent): Rename it to varobj_get_path_expr_parent.
Make it extern.
(is_anonymous_child): Move it to c-varobj.c and rename to
varobj_is_anonymous_child. Caller update.
(get_type): Move it to c-varobj.c.
(get_value_type): Rename it varobj_get_value_type. Make it
extern.
(get_target_type): Move it gdbtypes.c.
(varobj_formatted_print_options): New function.
(value_get_print_value): Rename it to
varobj_value_get_print_value and make it extern.
(varobj_value_is_changeable_p): Make it extern.
(adjust_value_for_child_access): Move it to c-varobj.c.
(default_value_is_changeable_p): Rename it to
varobj_default_value_is_changeable_p. Make it extern.
(c_number_of_children, c_name_of_variable): Move it to c-varobj.c
(c_name_of_child, c_path_expr_of_child): Likewise.
(c_value_of_child, c_type_of_child): Likewise.
(c_value_of_variable, cplus_number_of_children): Likewise.
(cplus_class_num_children, cplus_name_of_variable): Likewise.
(cplus_name_of_child, cplus_path_expr_of_child): Likewise.
(cplus_value_of_child, cplus_type_of_child): Likewise.
(cplus_value_of_variable): Likewise.
(java_number_of_children, java_name_of_variable): Move it to jv-varobj.c.
(java_name_of_child, java_path_expr_of_child): Likewise.
(java_value_of_child, java_type_of_child): Likewise.
(java_value_of_variable): Likewise.
(ada_number_of_children, ada_name_of_variable): Move it to ada-varobj.c.
(ada_name_of_child, ada_path_expr_of_child): Likewise.
(ada_value_of_child, ada_type_of_child): Likewise.
(ada_value_of_variable, ada_value_is_changeable_p): Likewise.
(ada_value_has_mutated): Likewise.
* varobj.h (CPLUS_FAKE_CHILD): New macro, moved from varobj.c.
(struct lang_varobj_ops): New. Renamed by 'struct language_specific'.
(c_varobj_ops, cplus_varobj_ops): Declare.
(java_varobj_ops, ada_varobj_ops): Declare.
(varobj_default_value_is_changeable_p): Declare.
(varobj_value_is_changeable_p): Declare.
(varobj_get_value_type, varobj_is_anonymous_child): Declare.
(varobj_get_path_expr_parent): Declare.
(varobj_value_get_print_value): Declare.
(varobj_formatted_print_options): Declare.
(varobj_restrict_range): Declare.
2013-10-17 21:28:37 +08:00
|
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
|
|
|
|
|
|
#include "defs.h"
|
|
|
|
|
#include "value.h"
|
|
|
|
|
#include "varobj.h"
|
|
|
|
|
#include "gdbthread.h"
|
|
|
|
|
#include "valprint.h"
|
|
|
|
|
|
|
|
|
|
static void cplus_class_num_children (struct type *type, int children[3]);
|
|
|
|
|
|
|
|
|
|
/* The names of varobjs representing anonymous structs or unions. */
|
|
|
|
|
#define ANONYMOUS_STRUCT_NAME _("<anonymous struct>")
|
|
|
|
|
#define ANONYMOUS_UNION_NAME _("<anonymous union>")
|
|
|
|
|
|
|
|
|
|
/* Does CHILD represent a child with no name? This happens when
|
|
|
|
|
the child is an anonmous struct or union and it has no field name
|
|
|
|
|
in its parent variable.
|
|
|
|
|
|
|
|
|
|
This has already been determined by *_describe_child. The easiest
|
|
|
|
|
thing to do is to compare the child's name with ANONYMOUS_*_NAME. */
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
varobj_is_anonymous_child (struct varobj *child)
|
|
|
|
|
{
|
|
|
|
|
return (strcmp (child->name, ANONYMOUS_STRUCT_NAME) == 0
|
|
|
|
|
|| strcmp (child->name, ANONYMOUS_UNION_NAME) == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Given the value and the type of a variable object,
|
|
|
|
|
adjust the value and type to those necessary
|
|
|
|
|
for getting children of the variable object.
|
|
|
|
|
This includes dereferencing top-level references
|
|
|
|
|
to all types and dereferencing pointers to
|
|
|
|
|
structures.
|
|
|
|
|
|
|
|
|
|
If LOOKUP_ACTUAL_TYPE is set the enclosing type of the
|
|
|
|
|
value will be fetched and if it differs from static type
|
|
|
|
|
the value will be casted to it.
|
|
|
|
|
|
|
|
|
|
Both TYPE and *TYPE should be non-null. VALUE
|
|
|
|
|
can be null if we want to only translate type.
|
|
|
|
|
*VALUE can be null as well -- if the parent
|
|
|
|
|
value is not known.
|
|
|
|
|
|
|
|
|
|
If WAS_PTR is not NULL, set *WAS_PTR to 0 or 1
|
|
|
|
|
depending on whether pointer was dereferenced
|
|
|
|
|
in this function. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
adjust_value_for_child_access (struct value **value,
|
|
|
|
|
struct type **type,
|
|
|
|
|
int *was_ptr,
|
|
|
|
|
int lookup_actual_type)
|
|
|
|
|
{
|
|
|
|
|
gdb_assert (type && *type);
|
|
|
|
|
|
|
|
|
|
if (was_ptr)
|
|
|
|
|
*was_ptr = 0;
|
|
|
|
|
|
|
|
|
|
*type = check_typedef (*type);
|
|
|
|
|
|
|
|
|
|
/* The type of value stored in varobj, that is passed
|
|
|
|
|
to us, is already supposed to be
|
|
|
|
|
reference-stripped. */
|
|
|
|
|
|
|
|
|
|
gdb_assert (TYPE_CODE (*type) != TYPE_CODE_REF);
|
|
|
|
|
|
|
|
|
|
/* Pointers to structures are treated just like
|
|
|
|
|
structures when accessing children. Don't
|
|
|
|
|
dererences pointers to other types. */
|
|
|
|
|
if (TYPE_CODE (*type) == TYPE_CODE_PTR)
|
|
|
|
|
{
|
|
|
|
|
struct type *target_type = get_target_type (*type);
|
|
|
|
|
if (TYPE_CODE (target_type) == TYPE_CODE_STRUCT
|
|
|
|
|
|| TYPE_CODE (target_type) == TYPE_CODE_UNION)
|
|
|
|
|
{
|
|
|
|
|
if (value && *value)
|
|
|
|
|
{
|
|
|
|
|
volatile struct gdb_exception except;
|
|
|
|
|
|
|
|
|
|
TRY_CATCH (except, RETURN_MASK_ERROR)
|
|
|
|
|
{
|
|
|
|
|
*value = value_ind (*value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (except.reason < 0)
|
|
|
|
|
*value = NULL;
|
|
|
|
|
}
|
|
|
|
|
*type = target_type;
|
|
|
|
|
if (was_ptr)
|
|
|
|
|
*was_ptr = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The 'get_target_type' function calls check_typedef on
|
|
|
|
|
result, so we can immediately check type code. No
|
|
|
|
|
need to call check_typedef here. */
|
|
|
|
|
|
|
|
|
|
/* Access a real type of the value (if necessary and possible). */
|
|
|
|
|
if (value && *value && lookup_actual_type)
|
|
|
|
|
{
|
|
|
|
|
struct type *enclosing_type;
|
|
|
|
|
int real_type_found = 0;
|
|
|
|
|
|
|
|
|
|
enclosing_type = value_actual_type (*value, 1, &real_type_found);
|
|
|
|
|
if (real_type_found)
|
|
|
|
|
{
|
|
|
|
|
*type = enclosing_type;
|
|
|
|
|
*value = value_cast (enclosing_type, *value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Improve MI -var-info-path-expression for nested struct/union case.
https://sourceware.org/ml/gdb-patches/2014-05/msg00383.html
The MI command -var-info-path-expression currently does not handle
non-anonymous structs / unions nested within other structs / unions,
it will skip parts of the expression. Consider this example:
## START EXAMPLE ##
$ cat ex.c
#include <string.h>
int
main ()
{
struct s1
{
int a;
};
struct ss
{
struct s1 x;
};
struct ss an_ss;
memset (&an_ss, 0, sizeof (an_ss));
return 0;
}
$ gcc -g -o ex.x ex.c
$ gdb ex.x
(gdb) break 18
Breakpoint 1 at 0x80483ba: file ex.c, line 18.
(gdb) run
Starting program: /home/user/ex.x
Breakpoint 1, main () at ex.c:18
18 return 0;
(gdb) interpreter-exec mi "-var-create an_ss * an_ss"
(gdb) interpreter-exec mi "-var-list-children an_ss"
^done,numchild="1",children=[child={name="an_ss.x",exp="x",numchild="1",type="struct s1",thread-id="1"}],has_more="0"
(gdb) interpreter-exec mi "-var-list-children an_ss.x"
^done,numchild="1",children=[child={name="an_ss.x.a",exp="a",numchild="0",type="int",thread-id="1"}],has_more="0"
(gdb) interpreter-exec mi "-var-list-children an_ss.x.a"
^done,numchild="0",has_more="0"
(gdb) interpreter-exec mi "-var-info-path-expression an_ss.x.a"
^done,path_expr="(an_ss).a"
(gdb) print (an_ss).a
There is no member named a.
## END EXAMPLE ##
Notice that the path expression returned is wrong, and as a result
the print command fails.
This patch adds a new method to the varobj_ops structure called
is_path_expr_parent, to allow language specific control over finding
the parent varobj, the current logic becomes the C/C++ version and is
extended to handle the nested cases. No other language currently uses
this code, so all other languages just get a default method.
With this patch, the above example now finishes like this:
## START EXAMPLE ##
$ gdb ex.x
(gdb) break 18
Breakpoint 1 at 0x80483ba: file ex.c, line 18.
(gdb) run
Starting program: /home/user/ex.x
Breakpoint 1, main () at ex.c:18
18 return 0;
(gdb) interpreter-exec mi "-var-list-children an_ss"
^done,numchild="1",children=[child={name="an_ss.x",exp="x",numchild="1",type="struct s1",thread-id="1"}],has_more="0"
(gdb) interpreter-exec mi "-var-list-children an_ss.x"
^done,numchild="1",children=[child={name="an_ss.x.a",exp="a",numchild="0",type="int",thread-id="1"}],has_more="0"
(gdb) interpreter-exec mi "-var-list-children an_ss.x.a"
^done,numchild="0",has_more="0"
(gdb) interpreter-exec mi "-var-info-path-expression an_ss.x.a"
^done,path_expr="((an_ss).x).a"
(gdb) print ((an_ss).x).a
$1 = 0
## END EXAMPLE ##
Notice that the path expression is now correct, and the print is a
success.
gdb/ChangeLog:
* ada-varobj.c (ada_varobj_ops): Fill in is_path_expr_parent
field.
* c-varobj.c (c_is_path_expr_parent): New function, moved core
from varobj.c, with additional checks.
(c_varobj_ops): Fill in is_path_expr_parent field.
(cplus_varobj_ops): Fill in is_path_expr_parent field.
* jv-varobj.c (java_varobj_ops): Fill in is_path_expr_parent
field.
* varobj.c (is_path_expr_parent): Call is_path_expr_parent varobj
ops method.
(varobj_default_is_path_expr_parent): New function.
* varobj.h (lang_varobj_ops): Add is_path_expr_parent field.
(varobj_default_is_path_expr_parent): Declare new function.
gdb/testsuite/ChangeLog:
* gdb.mi/var-cmd.c (do_nested_struct_union_tests): New function
setting up test structures.
(main): Call new test function.
* gdb.mi/mi2-var-child.exp: Create additional breakpoint in new
test function, continue into test function and walk test
structures.
2014-07-08 02:22:36 +08:00
|
|
|
|
/* Is VAR a path expression parent, i.e., can it be used to construct
|
|
|
|
|
a valid path expression? */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
c_is_path_expr_parent (struct varobj *var)
|
|
|
|
|
{
|
|
|
|
|
struct type *type;
|
|
|
|
|
|
|
|
|
|
/* "Fake" children are not path_expr parents. */
|
|
|
|
|
if (CPLUS_FAKE_CHILD (var))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
type = varobj_get_gdb_type (var);
|
|
|
|
|
|
|
|
|
|
/* Anonymous unions and structs are also not path_expr parents. */
|
|
|
|
|
if ((TYPE_CODE (type) == TYPE_CODE_STRUCT
|
|
|
|
|
|| TYPE_CODE (type) == TYPE_CODE_UNION)
|
|
|
|
|
&& TYPE_NAME (type) == NULL
|
|
|
|
|
&& TYPE_TAG_NAME (type) == NULL)
|
|
|
|
|
{
|
|
|
|
|
struct varobj *parent = var->parent;
|
|
|
|
|
|
|
|
|
|
while (parent != NULL && CPLUS_FAKE_CHILD (parent))
|
|
|
|
|
parent = parent->parent;
|
|
|
|
|
|
|
|
|
|
if (parent != NULL)
|
|
|
|
|
{
|
|
|
|
|
struct type *parent_type;
|
|
|
|
|
int was_ptr;
|
|
|
|
|
|
|
|
|
|
parent_type = varobj_get_value_type (parent);
|
|
|
|
|
adjust_value_for_child_access (NULL, &parent_type, &was_ptr, 0);
|
|
|
|
|
|
|
|
|
|
if (TYPE_CODE (parent_type) == TYPE_CODE_STRUCT
|
|
|
|
|
|| TYPE_CODE (parent_type) == TYPE_CODE_UNION)
|
|
|
|
|
{
|
|
|
|
|
const char *field_name;
|
|
|
|
|
|
|
|
|
|
gdb_assert (var->index < TYPE_NFIELDS (parent_type));
|
|
|
|
|
field_name = TYPE_FIELD_NAME (parent_type, var->index);
|
|
|
|
|
return !(field_name == NULL || *field_name == '\0');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
gdb/
* Makefile.in (SFILES): Add c-varobj.c and jv-varobj.c.
(COMMON_OBS): Add c-varobj.o and jv-varobj.o.
* ada-varobj.c: Include "varobj.h".
(ada_number_of_children): New. Moved from varobj.c.
(ada_name_of_variable, ada_name_of_child): Likewise.
(ada_path_expr_of_child, ada_value_of_child): Likewise.
(ada_type_of_child, ada_value_of_variable): Likewise.
(ada_value_is_changeable_p, ada_value_has_mutated): Likewise.
(ada_varobj_ops): New.
* c-varobj.c, jv-varobj.c: New file. Moved from varobj.c.
* gdbtypes.c (get_target_type): New. Moved from varobj.c.
* gdbtypes.h (get_target_type): Declare.
* varobj.c: Remove the inclusion of "ada-varobj.h" and
"ada-lang.h".
(ANONYMOUS_STRUCT_NAME): Move it to c-varobj.c.
(ANONYMOUS_UNION_NAME): Likewise.
(get_type, get_value_type, get_target_type): Remove declarations.
(value_get_print_value, varobj_value_get_print_value): Likewise.
(c_number_of_children, c_name_of_variable): Likewise.
(c_name_of_child, c_path_expr_of_child): Likewise.
(c_value_of_child, c_type_of_child): Likewise.
(c_value_of_variable, cplus_number_of_children): Likewise.
(cplus_class_num_children, cplus_name_of_variable): Likewise.
(cplus_name_of_child, cplus_path_expr_of_child): Likewise.
(cplus_value_of_child, cplus_type_of_child): Likewise.
(cplus_value_of_variable, java_number_of_children): Likewise.
(java_name_of_variable, java_name_of_child): Likewise.
(java_path_expr_of_child, java_value_of_child): Likewise.
(java_type_of_child, java_value_of_variable): Likewise.
(ada_number_of_children, ada_name_of_variable): Likewise.
(ada_name_of_child, ada_path_expr_of_child): Likewise.
(ada_value_of_child, ada_type_of_child): Likewise.
(ada_value_of_variable, ada_value_is_changeable_p): Likewise.
(ada_value_has_mutated): Likewise.
(struct language_specific): Move it to varobj.h.
(CPLUS_FAKE_CHILD): Move it to varobj.h.
(restrict_range): Rename it varobj_restrict_range. Make it extern.
Callers update.
(get_path_expr_parent): Rename it to varobj_get_path_expr_parent.
Make it extern.
(is_anonymous_child): Move it to c-varobj.c and rename to
varobj_is_anonymous_child. Caller update.
(get_type): Move it to c-varobj.c.
(get_value_type): Rename it varobj_get_value_type. Make it
extern.
(get_target_type): Move it gdbtypes.c.
(varobj_formatted_print_options): New function.
(value_get_print_value): Rename it to
varobj_value_get_print_value and make it extern.
(varobj_value_is_changeable_p): Make it extern.
(adjust_value_for_child_access): Move it to c-varobj.c.
(default_value_is_changeable_p): Rename it to
varobj_default_value_is_changeable_p. Make it extern.
(c_number_of_children, c_name_of_variable): Move it to c-varobj.c
(c_name_of_child, c_path_expr_of_child): Likewise.
(c_value_of_child, c_type_of_child): Likewise.
(c_value_of_variable, cplus_number_of_children): Likewise.
(cplus_class_num_children, cplus_name_of_variable): Likewise.
(cplus_name_of_child, cplus_path_expr_of_child): Likewise.
(cplus_value_of_child, cplus_type_of_child): Likewise.
(cplus_value_of_variable): Likewise.
(java_number_of_children, java_name_of_variable): Move it to jv-varobj.c.
(java_name_of_child, java_path_expr_of_child): Likewise.
(java_value_of_child, java_type_of_child): Likewise.
(java_value_of_variable): Likewise.
(ada_number_of_children, ada_name_of_variable): Move it to ada-varobj.c.
(ada_name_of_child, ada_path_expr_of_child): Likewise.
(ada_value_of_child, ada_type_of_child): Likewise.
(ada_value_of_variable, ada_value_is_changeable_p): Likewise.
(ada_value_has_mutated): Likewise.
* varobj.h (CPLUS_FAKE_CHILD): New macro, moved from varobj.c.
(struct lang_varobj_ops): New. Renamed by 'struct language_specific'.
(c_varobj_ops, cplus_varobj_ops): Declare.
(java_varobj_ops, ada_varobj_ops): Declare.
(varobj_default_value_is_changeable_p): Declare.
(varobj_value_is_changeable_p): Declare.
(varobj_get_value_type, varobj_is_anonymous_child): Declare.
(varobj_get_path_expr_parent): Declare.
(varobj_value_get_print_value): Declare.
(varobj_formatted_print_options): Declare.
(varobj_restrict_range): Declare.
2013-10-17 21:28:37 +08:00
|
|
|
|
/* C */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
c_number_of_children (struct varobj *var)
|
|
|
|
|
{
|
|
|
|
|
struct type *type = varobj_get_value_type (var);
|
|
|
|
|
int children = 0;
|
|
|
|
|
struct type *target;
|
|
|
|
|
|
|
|
|
|
adjust_value_for_child_access (NULL, &type, NULL, 0);
|
|
|
|
|
target = get_target_type (type);
|
|
|
|
|
|
|
|
|
|
switch (TYPE_CODE (type))
|
|
|
|
|
{
|
|
|
|
|
case TYPE_CODE_ARRAY:
|
|
|
|
|
if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (target) > 0
|
|
|
|
|
&& !TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED (type))
|
|
|
|
|
children = TYPE_LENGTH (type) / TYPE_LENGTH (target);
|
|
|
|
|
else
|
|
|
|
|
/* If we don't know how many elements there are, don't display
|
|
|
|
|
any. */
|
|
|
|
|
children = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TYPE_CODE_STRUCT:
|
|
|
|
|
case TYPE_CODE_UNION:
|
|
|
|
|
children = TYPE_NFIELDS (type);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TYPE_CODE_PTR:
|
|
|
|
|
/* The type here is a pointer to non-struct. Typically, pointers
|
|
|
|
|
have one child, except for function ptrs, which have no children,
|
|
|
|
|
and except for void*, as we don't know what to show.
|
|
|
|
|
|
|
|
|
|
We can show char* so we allow it to be dereferenced. If you decide
|
|
|
|
|
to test for it, please mind that a little magic is necessary to
|
|
|
|
|
properly identify it: char* has TYPE_CODE == TYPE_CODE_INT and
|
|
|
|
|
TYPE_NAME == "char". */
|
|
|
|
|
if (TYPE_CODE (target) == TYPE_CODE_FUNC
|
|
|
|
|
|| TYPE_CODE (target) == TYPE_CODE_VOID)
|
|
|
|
|
children = 0;
|
|
|
|
|
else
|
|
|
|
|
children = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
/* Other types have no children. */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return children;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
c_name_of_variable (struct varobj *parent)
|
|
|
|
|
{
|
|
|
|
|
return xstrdup (parent->name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return the value of element TYPE_INDEX of a structure
|
|
|
|
|
value VALUE. VALUE's type should be a structure,
|
|
|
|
|
or union, or a typedef to struct/union.
|
|
|
|
|
|
|
|
|
|
Returns NULL if getting the value fails. Never throws. */
|
|
|
|
|
|
|
|
|
|
static struct value *
|
|
|
|
|
value_struct_element_index (struct value *value, int type_index)
|
|
|
|
|
{
|
|
|
|
|
struct value *result = NULL;
|
|
|
|
|
volatile struct gdb_exception e;
|
|
|
|
|
struct type *type = value_type (value);
|
|
|
|
|
|
|
|
|
|
type = check_typedef (type);
|
|
|
|
|
|
|
|
|
|
gdb_assert (TYPE_CODE (type) == TYPE_CODE_STRUCT
|
|
|
|
|
|| TYPE_CODE (type) == TYPE_CODE_UNION);
|
|
|
|
|
|
|
|
|
|
TRY_CATCH (e, RETURN_MASK_ERROR)
|
|
|
|
|
{
|
|
|
|
|
if (field_is_static (&TYPE_FIELD (type, type_index)))
|
|
|
|
|
result = value_static_field (type, type_index);
|
|
|
|
|
else
|
|
|
|
|
result = value_primitive_field (value, 0, type_index, type);
|
|
|
|
|
}
|
|
|
|
|
if (e.reason < 0)
|
|
|
|
|
{
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Obtain the information about child INDEX of the variable
|
|
|
|
|
object PARENT.
|
|
|
|
|
If CNAME is not null, sets *CNAME to the name of the child relative
|
|
|
|
|
to the parent.
|
|
|
|
|
If CVALUE is not null, sets *CVALUE to the value of the child.
|
|
|
|
|
If CTYPE is not null, sets *CTYPE to the type of the child.
|
|
|
|
|
|
|
|
|
|
If any of CNAME, CVALUE, or CTYPE is not null, but the corresponding
|
|
|
|
|
information cannot be determined, set *CNAME, *CVALUE, or *CTYPE
|
|
|
|
|
to NULL. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
c_describe_child (struct varobj *parent, int index,
|
|
|
|
|
char **cname, struct value **cvalue, struct type **ctype,
|
|
|
|
|
char **cfull_expression)
|
|
|
|
|
{
|
|
|
|
|
struct value *value = parent->value;
|
|
|
|
|
struct type *type = varobj_get_value_type (parent);
|
|
|
|
|
char *parent_expression = NULL;
|
|
|
|
|
int was_ptr;
|
|
|
|
|
volatile struct gdb_exception except;
|
|
|
|
|
|
|
|
|
|
if (cname)
|
|
|
|
|
*cname = NULL;
|
|
|
|
|
if (cvalue)
|
|
|
|
|
*cvalue = NULL;
|
|
|
|
|
if (ctype)
|
|
|
|
|
*ctype = NULL;
|
|
|
|
|
if (cfull_expression)
|
|
|
|
|
{
|
|
|
|
|
*cfull_expression = NULL;
|
|
|
|
|
parent_expression
|
|
|
|
|
= varobj_get_path_expr (varobj_get_path_expr_parent (parent));
|
|
|
|
|
}
|
|
|
|
|
adjust_value_for_child_access (&value, &type, &was_ptr, 0);
|
|
|
|
|
|
|
|
|
|
switch (TYPE_CODE (type))
|
|
|
|
|
{
|
|
|
|
|
case TYPE_CODE_ARRAY:
|
|
|
|
|
if (cname)
|
|
|
|
|
*cname
|
|
|
|
|
= xstrdup (int_string (index
|
|
|
|
|
+ TYPE_LOW_BOUND (TYPE_INDEX_TYPE (type)),
|
|
|
|
|
10, 1, 0, 0));
|
|
|
|
|
|
|
|
|
|
if (cvalue && value)
|
|
|
|
|
{
|
|
|
|
|
int real_index = index + TYPE_LOW_BOUND (TYPE_INDEX_TYPE (type));
|
|
|
|
|
|
|
|
|
|
TRY_CATCH (except, RETURN_MASK_ERROR)
|
|
|
|
|
{
|
|
|
|
|
*cvalue = value_subscript (value, real_index);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ctype)
|
|
|
|
|
*ctype = get_target_type (type);
|
|
|
|
|
|
|
|
|
|
if (cfull_expression)
|
|
|
|
|
*cfull_expression =
|
|
|
|
|
xstrprintf ("(%s)[%s]", parent_expression,
|
|
|
|
|
int_string (index
|
|
|
|
|
+ TYPE_LOW_BOUND (TYPE_INDEX_TYPE (type)),
|
|
|
|
|
10, 1, 0, 0));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TYPE_CODE_STRUCT:
|
|
|
|
|
case TYPE_CODE_UNION:
|
|
|
|
|
{
|
|
|
|
|
const char *field_name;
|
|
|
|
|
|
|
|
|
|
/* If the type is anonymous and the field has no name,
|
|
|
|
|
set an appropriate name. */
|
|
|
|
|
field_name = TYPE_FIELD_NAME (type, index);
|
|
|
|
|
if (field_name == NULL || *field_name == '\0')
|
|
|
|
|
{
|
|
|
|
|
if (cname)
|
|
|
|
|
{
|
|
|
|
|
if (TYPE_CODE (TYPE_FIELD_TYPE (type, index))
|
|
|
|
|
== TYPE_CODE_STRUCT)
|
|
|
|
|
*cname = xstrdup (ANONYMOUS_STRUCT_NAME);
|
|
|
|
|
else
|
|
|
|
|
*cname = xstrdup (ANONYMOUS_UNION_NAME);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cfull_expression)
|
|
|
|
|
*cfull_expression = xstrdup ("");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (cname)
|
|
|
|
|
*cname = xstrdup (field_name);
|
|
|
|
|
|
|
|
|
|
if (cfull_expression)
|
|
|
|
|
{
|
|
|
|
|
char *join = was_ptr ? "->" : ".";
|
|
|
|
|
|
|
|
|
|
*cfull_expression = xstrprintf ("(%s)%s%s", parent_expression,
|
|
|
|
|
join, field_name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cvalue && value)
|
|
|
|
|
{
|
|
|
|
|
/* For C, varobj index is the same as type index. */
|
|
|
|
|
*cvalue = value_struct_element_index (value, index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ctype)
|
|
|
|
|
*ctype = TYPE_FIELD_TYPE (type, index);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TYPE_CODE_PTR:
|
|
|
|
|
if (cname)
|
|
|
|
|
*cname = xstrprintf ("*%s", parent->name);
|
|
|
|
|
|
|
|
|
|
if (cvalue && value)
|
|
|
|
|
{
|
|
|
|
|
TRY_CATCH (except, RETURN_MASK_ERROR)
|
|
|
|
|
{
|
|
|
|
|
*cvalue = value_ind (value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (except.reason < 0)
|
|
|
|
|
*cvalue = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Don't use get_target_type because it calls
|
|
|
|
|
check_typedef and here, we want to show the true
|
|
|
|
|
declared type of the variable. */
|
|
|
|
|
if (ctype)
|
|
|
|
|
*ctype = TYPE_TARGET_TYPE (type);
|
|
|
|
|
|
|
|
|
|
if (cfull_expression)
|
|
|
|
|
*cfull_expression = xstrprintf ("*(%s)", parent_expression);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
/* This should not happen. */
|
|
|
|
|
if (cname)
|
|
|
|
|
*cname = xstrdup ("???");
|
|
|
|
|
if (cfull_expression)
|
|
|
|
|
*cfull_expression = xstrdup ("???");
|
|
|
|
|
/* Don't set value and type, we don't know then. */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
c_name_of_child (struct varobj *parent, int index)
|
|
|
|
|
{
|
|
|
|
|
char *name;
|
|
|
|
|
|
|
|
|
|
c_describe_child (parent, index, &name, NULL, NULL, NULL);
|
|
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
c_path_expr_of_child (struct varobj *child)
|
|
|
|
|
{
|
|
|
|
|
c_describe_child (child->parent, child->index, NULL, NULL, NULL,
|
|
|
|
|
&child->path_expr);
|
|
|
|
|
return child->path_expr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct value *
|
|
|
|
|
c_value_of_child (struct varobj *parent, int index)
|
|
|
|
|
{
|
|
|
|
|
struct value *value = NULL;
|
|
|
|
|
|
|
|
|
|
c_describe_child (parent, index, NULL, &value, NULL, NULL);
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct type *
|
|
|
|
|
c_type_of_child (struct varobj *parent, int index)
|
|
|
|
|
{
|
|
|
|
|
struct type *type = NULL;
|
|
|
|
|
|
|
|
|
|
c_describe_child (parent, index, NULL, NULL, &type, NULL);
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This returns the type of the variable. It also skips past typedefs
|
|
|
|
|
to return the real type of the variable. */
|
|
|
|
|
|
|
|
|
|
static struct type *
|
|
|
|
|
get_type (struct varobj *var)
|
|
|
|
|
{
|
|
|
|
|
struct type *type;
|
|
|
|
|
|
|
|
|
|
type = var->type;
|
|
|
|
|
if (type != NULL)
|
|
|
|
|
type = check_typedef (type);
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
c_value_of_variable (struct varobj *var, enum varobj_display_formats format)
|
|
|
|
|
{
|
|
|
|
|
/* BOGUS: if val_print sees a struct/class, or a reference to one,
|
|
|
|
|
it will print out its children instead of "{...}". So we need to
|
|
|
|
|
catch that case explicitly. */
|
|
|
|
|
struct type *type = get_type (var);
|
|
|
|
|
|
|
|
|
|
/* Strip top-level references. */
|
|
|
|
|
while (TYPE_CODE (type) == TYPE_CODE_REF)
|
|
|
|
|
type = check_typedef (TYPE_TARGET_TYPE (type));
|
|
|
|
|
|
|
|
|
|
switch (TYPE_CODE (type))
|
|
|
|
|
{
|
|
|
|
|
case TYPE_CODE_STRUCT:
|
|
|
|
|
case TYPE_CODE_UNION:
|
|
|
|
|
return xstrdup ("{...}");
|
|
|
|
|
/* break; */
|
|
|
|
|
|
|
|
|
|
case TYPE_CODE_ARRAY:
|
|
|
|
|
{
|
|
|
|
|
char *number;
|
|
|
|
|
|
|
|
|
|
number = xstrprintf ("[%d]", var->num_children);
|
|
|
|
|
return (number);
|
|
|
|
|
}
|
|
|
|
|
/* break; */
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
if (var->value == NULL)
|
|
|
|
|
{
|
|
|
|
|
/* This can happen if we attempt to get the value of a struct
|
|
|
|
|
member when the parent is an invalid pointer. This is an
|
|
|
|
|
error condition, so we should tell the caller. */
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (var->not_fetched && value_lazy (var->value))
|
|
|
|
|
/* Frozen variable and no value yet. We don't
|
|
|
|
|
implicitly fetch the value. MI response will
|
|
|
|
|
use empty string for the value, which is OK. */
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
gdb_assert (varobj_value_is_changeable_p (var));
|
|
|
|
|
gdb_assert (!value_lazy (var->value));
|
|
|
|
|
|
|
|
|
|
/* If the specified format is the current one,
|
|
|
|
|
we can reuse print_value. */
|
|
|
|
|
if (format == var->format)
|
|
|
|
|
return xstrdup (var->print_value);
|
|
|
|
|
else
|
|
|
|
|
return varobj_value_get_print_value (var->value, format, var);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* varobj operations for c. */
|
|
|
|
|
|
|
|
|
|
const struct lang_varobj_ops c_varobj_ops =
|
|
|
|
|
{
|
|
|
|
|
c_number_of_children,
|
|
|
|
|
c_name_of_variable,
|
|
|
|
|
c_name_of_child,
|
|
|
|
|
c_path_expr_of_child,
|
|
|
|
|
c_value_of_child,
|
|
|
|
|
c_type_of_child,
|
|
|
|
|
c_value_of_variable,
|
|
|
|
|
varobj_default_value_is_changeable_p,
|
Improve MI -var-info-path-expression for nested struct/union case.
https://sourceware.org/ml/gdb-patches/2014-05/msg00383.html
The MI command -var-info-path-expression currently does not handle
non-anonymous structs / unions nested within other structs / unions,
it will skip parts of the expression. Consider this example:
## START EXAMPLE ##
$ cat ex.c
#include <string.h>
int
main ()
{
struct s1
{
int a;
};
struct ss
{
struct s1 x;
};
struct ss an_ss;
memset (&an_ss, 0, sizeof (an_ss));
return 0;
}
$ gcc -g -o ex.x ex.c
$ gdb ex.x
(gdb) break 18
Breakpoint 1 at 0x80483ba: file ex.c, line 18.
(gdb) run
Starting program: /home/user/ex.x
Breakpoint 1, main () at ex.c:18
18 return 0;
(gdb) interpreter-exec mi "-var-create an_ss * an_ss"
(gdb) interpreter-exec mi "-var-list-children an_ss"
^done,numchild="1",children=[child={name="an_ss.x",exp="x",numchild="1",type="struct s1",thread-id="1"}],has_more="0"
(gdb) interpreter-exec mi "-var-list-children an_ss.x"
^done,numchild="1",children=[child={name="an_ss.x.a",exp="a",numchild="0",type="int",thread-id="1"}],has_more="0"
(gdb) interpreter-exec mi "-var-list-children an_ss.x.a"
^done,numchild="0",has_more="0"
(gdb) interpreter-exec mi "-var-info-path-expression an_ss.x.a"
^done,path_expr="(an_ss).a"
(gdb) print (an_ss).a
There is no member named a.
## END EXAMPLE ##
Notice that the path expression returned is wrong, and as a result
the print command fails.
This patch adds a new method to the varobj_ops structure called
is_path_expr_parent, to allow language specific control over finding
the parent varobj, the current logic becomes the C/C++ version and is
extended to handle the nested cases. No other language currently uses
this code, so all other languages just get a default method.
With this patch, the above example now finishes like this:
## START EXAMPLE ##
$ gdb ex.x
(gdb) break 18
Breakpoint 1 at 0x80483ba: file ex.c, line 18.
(gdb) run
Starting program: /home/user/ex.x
Breakpoint 1, main () at ex.c:18
18 return 0;
(gdb) interpreter-exec mi "-var-list-children an_ss"
^done,numchild="1",children=[child={name="an_ss.x",exp="x",numchild="1",type="struct s1",thread-id="1"}],has_more="0"
(gdb) interpreter-exec mi "-var-list-children an_ss.x"
^done,numchild="1",children=[child={name="an_ss.x.a",exp="a",numchild="0",type="int",thread-id="1"}],has_more="0"
(gdb) interpreter-exec mi "-var-list-children an_ss.x.a"
^done,numchild="0",has_more="0"
(gdb) interpreter-exec mi "-var-info-path-expression an_ss.x.a"
^done,path_expr="((an_ss).x).a"
(gdb) print ((an_ss).x).a
$1 = 0
## END EXAMPLE ##
Notice that the path expression is now correct, and the print is a
success.
gdb/ChangeLog:
* ada-varobj.c (ada_varobj_ops): Fill in is_path_expr_parent
field.
* c-varobj.c (c_is_path_expr_parent): New function, moved core
from varobj.c, with additional checks.
(c_varobj_ops): Fill in is_path_expr_parent field.
(cplus_varobj_ops): Fill in is_path_expr_parent field.
* jv-varobj.c (java_varobj_ops): Fill in is_path_expr_parent
field.
* varobj.c (is_path_expr_parent): Call is_path_expr_parent varobj
ops method.
(varobj_default_is_path_expr_parent): New function.
* varobj.h (lang_varobj_ops): Add is_path_expr_parent field.
(varobj_default_is_path_expr_parent): Declare new function.
gdb/testsuite/ChangeLog:
* gdb.mi/var-cmd.c (do_nested_struct_union_tests): New function
setting up test structures.
(main): Call new test function.
* gdb.mi/mi2-var-child.exp: Create additional breakpoint in new
test function, continue into test function and walk test
structures.
2014-07-08 02:22:36 +08:00
|
|
|
|
NULL, /* value_has_mutated */
|
|
|
|
|
c_is_path_expr_parent /* is_path_expr_parent */
|
gdb/
* Makefile.in (SFILES): Add c-varobj.c and jv-varobj.c.
(COMMON_OBS): Add c-varobj.o and jv-varobj.o.
* ada-varobj.c: Include "varobj.h".
(ada_number_of_children): New. Moved from varobj.c.
(ada_name_of_variable, ada_name_of_child): Likewise.
(ada_path_expr_of_child, ada_value_of_child): Likewise.
(ada_type_of_child, ada_value_of_variable): Likewise.
(ada_value_is_changeable_p, ada_value_has_mutated): Likewise.
(ada_varobj_ops): New.
* c-varobj.c, jv-varobj.c: New file. Moved from varobj.c.
* gdbtypes.c (get_target_type): New. Moved from varobj.c.
* gdbtypes.h (get_target_type): Declare.
* varobj.c: Remove the inclusion of "ada-varobj.h" and
"ada-lang.h".
(ANONYMOUS_STRUCT_NAME): Move it to c-varobj.c.
(ANONYMOUS_UNION_NAME): Likewise.
(get_type, get_value_type, get_target_type): Remove declarations.
(value_get_print_value, varobj_value_get_print_value): Likewise.
(c_number_of_children, c_name_of_variable): Likewise.
(c_name_of_child, c_path_expr_of_child): Likewise.
(c_value_of_child, c_type_of_child): Likewise.
(c_value_of_variable, cplus_number_of_children): Likewise.
(cplus_class_num_children, cplus_name_of_variable): Likewise.
(cplus_name_of_child, cplus_path_expr_of_child): Likewise.
(cplus_value_of_child, cplus_type_of_child): Likewise.
(cplus_value_of_variable, java_number_of_children): Likewise.
(java_name_of_variable, java_name_of_child): Likewise.
(java_path_expr_of_child, java_value_of_child): Likewise.
(java_type_of_child, java_value_of_variable): Likewise.
(ada_number_of_children, ada_name_of_variable): Likewise.
(ada_name_of_child, ada_path_expr_of_child): Likewise.
(ada_value_of_child, ada_type_of_child): Likewise.
(ada_value_of_variable, ada_value_is_changeable_p): Likewise.
(ada_value_has_mutated): Likewise.
(struct language_specific): Move it to varobj.h.
(CPLUS_FAKE_CHILD): Move it to varobj.h.
(restrict_range): Rename it varobj_restrict_range. Make it extern.
Callers update.
(get_path_expr_parent): Rename it to varobj_get_path_expr_parent.
Make it extern.
(is_anonymous_child): Move it to c-varobj.c and rename to
varobj_is_anonymous_child. Caller update.
(get_type): Move it to c-varobj.c.
(get_value_type): Rename it varobj_get_value_type. Make it
extern.
(get_target_type): Move it gdbtypes.c.
(varobj_formatted_print_options): New function.
(value_get_print_value): Rename it to
varobj_value_get_print_value and make it extern.
(varobj_value_is_changeable_p): Make it extern.
(adjust_value_for_child_access): Move it to c-varobj.c.
(default_value_is_changeable_p): Rename it to
varobj_default_value_is_changeable_p. Make it extern.
(c_number_of_children, c_name_of_variable): Move it to c-varobj.c
(c_name_of_child, c_path_expr_of_child): Likewise.
(c_value_of_child, c_type_of_child): Likewise.
(c_value_of_variable, cplus_number_of_children): Likewise.
(cplus_class_num_children, cplus_name_of_variable): Likewise.
(cplus_name_of_child, cplus_path_expr_of_child): Likewise.
(cplus_value_of_child, cplus_type_of_child): Likewise.
(cplus_value_of_variable): Likewise.
(java_number_of_children, java_name_of_variable): Move it to jv-varobj.c.
(java_name_of_child, java_path_expr_of_child): Likewise.
(java_value_of_child, java_type_of_child): Likewise.
(java_value_of_variable): Likewise.
(ada_number_of_children, ada_name_of_variable): Move it to ada-varobj.c.
(ada_name_of_child, ada_path_expr_of_child): Likewise.
(ada_value_of_child, ada_type_of_child): Likewise.
(ada_value_of_variable, ada_value_is_changeable_p): Likewise.
(ada_value_has_mutated): Likewise.
* varobj.h (CPLUS_FAKE_CHILD): New macro, moved from varobj.c.
(struct lang_varobj_ops): New. Renamed by 'struct language_specific'.
(c_varobj_ops, cplus_varobj_ops): Declare.
(java_varobj_ops, ada_varobj_ops): Declare.
(varobj_default_value_is_changeable_p): Declare.
(varobj_value_is_changeable_p): Declare.
(varobj_get_value_type, varobj_is_anonymous_child): Declare.
(varobj_get_path_expr_parent): Declare.
(varobj_value_get_print_value): Declare.
(varobj_formatted_print_options): Declare.
(varobj_restrict_range): Declare.
2013-10-17 21:28:37 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* A little convenience enum for dealing with C++/Java. */
|
|
|
|
|
enum vsections
|
|
|
|
|
{
|
|
|
|
|
v_public = 0, v_private, v_protected
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* C++ */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
cplus_number_of_children (struct varobj *var)
|
|
|
|
|
{
|
|
|
|
|
struct value *value = NULL;
|
|
|
|
|
struct type *type;
|
|
|
|
|
int children, dont_know;
|
|
|
|
|
int lookup_actual_type = 0;
|
|
|
|
|
struct value_print_options opts;
|
|
|
|
|
|
|
|
|
|
dont_know = 1;
|
|
|
|
|
children = 0;
|
|
|
|
|
|
|
|
|
|
get_user_print_options (&opts);
|
|
|
|
|
|
|
|
|
|
if (!CPLUS_FAKE_CHILD (var))
|
|
|
|
|
{
|
|
|
|
|
type = varobj_get_value_type (var);
|
|
|
|
|
|
|
|
|
|
/* It is necessary to access a real type (via RTTI). */
|
|
|
|
|
if (opts.objectprint)
|
|
|
|
|
{
|
|
|
|
|
value = var->value;
|
|
|
|
|
lookup_actual_type = (TYPE_CODE (var->type) == TYPE_CODE_REF
|
|
|
|
|
|| TYPE_CODE (var->type) == TYPE_CODE_PTR);
|
|
|
|
|
}
|
|
|
|
|
adjust_value_for_child_access (&value, &type, NULL, lookup_actual_type);
|
|
|
|
|
|
2013-10-18 10:09:57 +08:00
|
|
|
|
if (((TYPE_CODE (type)) == TYPE_CODE_STRUCT)
|
|
|
|
|
|| ((TYPE_CODE (type)) == TYPE_CODE_UNION))
|
gdb/
* Makefile.in (SFILES): Add c-varobj.c and jv-varobj.c.
(COMMON_OBS): Add c-varobj.o and jv-varobj.o.
* ada-varobj.c: Include "varobj.h".
(ada_number_of_children): New. Moved from varobj.c.
(ada_name_of_variable, ada_name_of_child): Likewise.
(ada_path_expr_of_child, ada_value_of_child): Likewise.
(ada_type_of_child, ada_value_of_variable): Likewise.
(ada_value_is_changeable_p, ada_value_has_mutated): Likewise.
(ada_varobj_ops): New.
* c-varobj.c, jv-varobj.c: New file. Moved from varobj.c.
* gdbtypes.c (get_target_type): New. Moved from varobj.c.
* gdbtypes.h (get_target_type): Declare.
* varobj.c: Remove the inclusion of "ada-varobj.h" and
"ada-lang.h".
(ANONYMOUS_STRUCT_NAME): Move it to c-varobj.c.
(ANONYMOUS_UNION_NAME): Likewise.
(get_type, get_value_type, get_target_type): Remove declarations.
(value_get_print_value, varobj_value_get_print_value): Likewise.
(c_number_of_children, c_name_of_variable): Likewise.
(c_name_of_child, c_path_expr_of_child): Likewise.
(c_value_of_child, c_type_of_child): Likewise.
(c_value_of_variable, cplus_number_of_children): Likewise.
(cplus_class_num_children, cplus_name_of_variable): Likewise.
(cplus_name_of_child, cplus_path_expr_of_child): Likewise.
(cplus_value_of_child, cplus_type_of_child): Likewise.
(cplus_value_of_variable, java_number_of_children): Likewise.
(java_name_of_variable, java_name_of_child): Likewise.
(java_path_expr_of_child, java_value_of_child): Likewise.
(java_type_of_child, java_value_of_variable): Likewise.
(ada_number_of_children, ada_name_of_variable): Likewise.
(ada_name_of_child, ada_path_expr_of_child): Likewise.
(ada_value_of_child, ada_type_of_child): Likewise.
(ada_value_of_variable, ada_value_is_changeable_p): Likewise.
(ada_value_has_mutated): Likewise.
(struct language_specific): Move it to varobj.h.
(CPLUS_FAKE_CHILD): Move it to varobj.h.
(restrict_range): Rename it varobj_restrict_range. Make it extern.
Callers update.
(get_path_expr_parent): Rename it to varobj_get_path_expr_parent.
Make it extern.
(is_anonymous_child): Move it to c-varobj.c and rename to
varobj_is_anonymous_child. Caller update.
(get_type): Move it to c-varobj.c.
(get_value_type): Rename it varobj_get_value_type. Make it
extern.
(get_target_type): Move it gdbtypes.c.
(varobj_formatted_print_options): New function.
(value_get_print_value): Rename it to
varobj_value_get_print_value and make it extern.
(varobj_value_is_changeable_p): Make it extern.
(adjust_value_for_child_access): Move it to c-varobj.c.
(default_value_is_changeable_p): Rename it to
varobj_default_value_is_changeable_p. Make it extern.
(c_number_of_children, c_name_of_variable): Move it to c-varobj.c
(c_name_of_child, c_path_expr_of_child): Likewise.
(c_value_of_child, c_type_of_child): Likewise.
(c_value_of_variable, cplus_number_of_children): Likewise.
(cplus_class_num_children, cplus_name_of_variable): Likewise.
(cplus_name_of_child, cplus_path_expr_of_child): Likewise.
(cplus_value_of_child, cplus_type_of_child): Likewise.
(cplus_value_of_variable): Likewise.
(java_number_of_children, java_name_of_variable): Move it to jv-varobj.c.
(java_name_of_child, java_path_expr_of_child): Likewise.
(java_value_of_child, java_type_of_child): Likewise.
(java_value_of_variable): Likewise.
(ada_number_of_children, ada_name_of_variable): Move it to ada-varobj.c.
(ada_name_of_child, ada_path_expr_of_child): Likewise.
(ada_value_of_child, ada_type_of_child): Likewise.
(ada_value_of_variable, ada_value_is_changeable_p): Likewise.
(ada_value_has_mutated): Likewise.
* varobj.h (CPLUS_FAKE_CHILD): New macro, moved from varobj.c.
(struct lang_varobj_ops): New. Renamed by 'struct language_specific'.
(c_varobj_ops, cplus_varobj_ops): Declare.
(java_varobj_ops, ada_varobj_ops): Declare.
(varobj_default_value_is_changeable_p): Declare.
(varobj_value_is_changeable_p): Declare.
(varobj_get_value_type, varobj_is_anonymous_child): Declare.
(varobj_get_path_expr_parent): Declare.
(varobj_value_get_print_value): Declare.
(varobj_formatted_print_options): Declare.
(varobj_restrict_range): Declare.
2013-10-17 21:28:37 +08:00
|
|
|
|
{
|
|
|
|
|
int kids[3];
|
|
|
|
|
|
|
|
|
|
cplus_class_num_children (type, kids);
|
|
|
|
|
if (kids[v_public] != 0)
|
|
|
|
|
children++;
|
|
|
|
|
if (kids[v_private] != 0)
|
|
|
|
|
children++;
|
|
|
|
|
if (kids[v_protected] != 0)
|
|
|
|
|
children++;
|
|
|
|
|
|
|
|
|
|
/* Add any baseclasses. */
|
|
|
|
|
children += TYPE_N_BASECLASSES (type);
|
|
|
|
|
dont_know = 0;
|
|
|
|
|
|
|
|
|
|
/* FIXME: save children in var. */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int kids[3];
|
|
|
|
|
|
|
|
|
|
type = varobj_get_value_type (var->parent);
|
|
|
|
|
|
|
|
|
|
/* It is necessary to access a real type (via RTTI). */
|
|
|
|
|
if (opts.objectprint)
|
|
|
|
|
{
|
|
|
|
|
struct varobj *parent = var->parent;
|
|
|
|
|
|
|
|
|
|
value = parent->value;
|
|
|
|
|
lookup_actual_type = (TYPE_CODE (parent->type) == TYPE_CODE_REF
|
|
|
|
|
|| TYPE_CODE (parent->type) == TYPE_CODE_PTR);
|
|
|
|
|
}
|
|
|
|
|
adjust_value_for_child_access (&value, &type, NULL, lookup_actual_type);
|
|
|
|
|
|
|
|
|
|
cplus_class_num_children (type, kids);
|
|
|
|
|
if (strcmp (var->name, "public") == 0)
|
|
|
|
|
children = kids[v_public];
|
|
|
|
|
else if (strcmp (var->name, "private") == 0)
|
|
|
|
|
children = kids[v_private];
|
|
|
|
|
else
|
|
|
|
|
children = kids[v_protected];
|
|
|
|
|
dont_know = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dont_know)
|
|
|
|
|
children = c_number_of_children (var);
|
|
|
|
|
|
|
|
|
|
return children;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Compute # of public, private, and protected variables in this class.
|
|
|
|
|
That means we need to descend into all baseclasses and find out
|
|
|
|
|
how many are there, too. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
cplus_class_num_children (struct type *type, int children[3])
|
|
|
|
|
{
|
|
|
|
|
int i, vptr_fieldno;
|
|
|
|
|
struct type *basetype = NULL;
|
|
|
|
|
|
|
|
|
|
children[v_public] = 0;
|
|
|
|
|
children[v_private] = 0;
|
|
|
|
|
children[v_protected] = 0;
|
|
|
|
|
|
|
|
|
|
vptr_fieldno = get_vptr_fieldno (type, &basetype);
|
|
|
|
|
for (i = TYPE_N_BASECLASSES (type); i < TYPE_NFIELDS (type); i++)
|
|
|
|
|
{
|
|
|
|
|
/* If we have a virtual table pointer, omit it. Even if virtual
|
|
|
|
|
table pointers are not specifically marked in the debug info,
|
|
|
|
|
they should be artificial. */
|
|
|
|
|
if ((type == basetype && i == vptr_fieldno)
|
|
|
|
|
|| TYPE_FIELD_ARTIFICIAL (type, i))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (TYPE_FIELD_PROTECTED (type, i))
|
|
|
|
|
children[v_protected]++;
|
|
|
|
|
else if (TYPE_FIELD_PRIVATE (type, i))
|
|
|
|
|
children[v_private]++;
|
|
|
|
|
else
|
|
|
|
|
children[v_public]++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
cplus_name_of_variable (struct varobj *parent)
|
|
|
|
|
{
|
|
|
|
|
return c_name_of_variable (parent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum accessibility { private_field, protected_field, public_field };
|
|
|
|
|
|
|
|
|
|
/* Check if field INDEX of TYPE has the specified accessibility.
|
|
|
|
|
Return 0 if so and 1 otherwise. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
match_accessibility (struct type *type, int index, enum accessibility acc)
|
|
|
|
|
{
|
|
|
|
|
if (acc == private_field && TYPE_FIELD_PRIVATE (type, index))
|
|
|
|
|
return 1;
|
|
|
|
|
else if (acc == protected_field && TYPE_FIELD_PROTECTED (type, index))
|
|
|
|
|
return 1;
|
|
|
|
|
else if (acc == public_field && !TYPE_FIELD_PRIVATE (type, index)
|
|
|
|
|
&& !TYPE_FIELD_PROTECTED (type, index))
|
|
|
|
|
return 1;
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
cplus_describe_child (struct varobj *parent, int index,
|
|
|
|
|
char **cname, struct value **cvalue, struct type **ctype,
|
|
|
|
|
char **cfull_expression)
|
|
|
|
|
{
|
|
|
|
|
struct value *value;
|
|
|
|
|
struct type *type;
|
|
|
|
|
int was_ptr;
|
|
|
|
|
int lookup_actual_type = 0;
|
|
|
|
|
char *parent_expression = NULL;
|
|
|
|
|
struct varobj *var;
|
|
|
|
|
struct value_print_options opts;
|
|
|
|
|
|
|
|
|
|
if (cname)
|
|
|
|
|
*cname = NULL;
|
|
|
|
|
if (cvalue)
|
|
|
|
|
*cvalue = NULL;
|
|
|
|
|
if (ctype)
|
|
|
|
|
*ctype = NULL;
|
|
|
|
|
if (cfull_expression)
|
|
|
|
|
*cfull_expression = NULL;
|
|
|
|
|
|
|
|
|
|
get_user_print_options (&opts);
|
|
|
|
|
|
|
|
|
|
var = (CPLUS_FAKE_CHILD (parent)) ? parent->parent : parent;
|
|
|
|
|
if (opts.objectprint)
|
|
|
|
|
lookup_actual_type = (TYPE_CODE (var->type) == TYPE_CODE_REF
|
|
|
|
|
|| TYPE_CODE (var->type) == TYPE_CODE_PTR);
|
|
|
|
|
value = var->value;
|
|
|
|
|
type = varobj_get_value_type (var);
|
|
|
|
|
if (cfull_expression)
|
|
|
|
|
parent_expression
|
|
|
|
|
= varobj_get_path_expr (varobj_get_path_expr_parent (var));
|
|
|
|
|
|
|
|
|
|
adjust_value_for_child_access (&value, &type, &was_ptr, lookup_actual_type);
|
|
|
|
|
|
|
|
|
|
if (TYPE_CODE (type) == TYPE_CODE_STRUCT
|
|
|
|
|
|| TYPE_CODE (type) == TYPE_CODE_UNION)
|
|
|
|
|
{
|
|
|
|
|
char *join = was_ptr ? "->" : ".";
|
|
|
|
|
|
|
|
|
|
if (CPLUS_FAKE_CHILD (parent))
|
|
|
|
|
{
|
|
|
|
|
/* The fields of the class type are ordered as they
|
|
|
|
|
appear in the class. We are given an index for a
|
|
|
|
|
particular access control type ("public","protected",
|
|
|
|
|
or "private"). We must skip over fields that don't
|
|
|
|
|
have the access control we are looking for to properly
|
|
|
|
|
find the indexed field. */
|
|
|
|
|
int type_index = TYPE_N_BASECLASSES (type);
|
|
|
|
|
enum accessibility acc = public_field;
|
|
|
|
|
int vptr_fieldno;
|
|
|
|
|
struct type *basetype = NULL;
|
|
|
|
|
const char *field_name;
|
|
|
|
|
|
|
|
|
|
vptr_fieldno = get_vptr_fieldno (type, &basetype);
|
|
|
|
|
if (strcmp (parent->name, "private") == 0)
|
|
|
|
|
acc = private_field;
|
|
|
|
|
else if (strcmp (parent->name, "protected") == 0)
|
|
|
|
|
acc = protected_field;
|
|
|
|
|
|
|
|
|
|
while (index >= 0)
|
|
|
|
|
{
|
|
|
|
|
if ((type == basetype && type_index == vptr_fieldno)
|
|
|
|
|
|| TYPE_FIELD_ARTIFICIAL (type, type_index))
|
|
|
|
|
; /* ignore vptr */
|
|
|
|
|
else if (match_accessibility (type, type_index, acc))
|
|
|
|
|
--index;
|
|
|
|
|
++type_index;
|
|
|
|
|
}
|
|
|
|
|
--type_index;
|
|
|
|
|
|
|
|
|
|
/* If the type is anonymous and the field has no name,
|
|
|
|
|
set an appopriate name. */
|
|
|
|
|
field_name = TYPE_FIELD_NAME (type, type_index);
|
|
|
|
|
if (field_name == NULL || *field_name == '\0')
|
|
|
|
|
{
|
|
|
|
|
if (cname)
|
|
|
|
|
{
|
|
|
|
|
if (TYPE_CODE (TYPE_FIELD_TYPE (type, type_index))
|
|
|
|
|
== TYPE_CODE_STRUCT)
|
|
|
|
|
*cname = xstrdup (ANONYMOUS_STRUCT_NAME);
|
|
|
|
|
else if (TYPE_CODE (TYPE_FIELD_TYPE (type, type_index))
|
|
|
|
|
== TYPE_CODE_UNION)
|
|
|
|
|
*cname = xstrdup (ANONYMOUS_UNION_NAME);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cfull_expression)
|
|
|
|
|
*cfull_expression = xstrdup ("");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (cname)
|
|
|
|
|
*cname = xstrdup (TYPE_FIELD_NAME (type, type_index));
|
|
|
|
|
|
|
|
|
|
if (cfull_expression)
|
|
|
|
|
*cfull_expression
|
|
|
|
|
= xstrprintf ("((%s)%s%s)", parent_expression, join,
|
|
|
|
|
field_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cvalue && value)
|
|
|
|
|
*cvalue = value_struct_element_index (value, type_index);
|
|
|
|
|
|
|
|
|
|
if (ctype)
|
|
|
|
|
*ctype = TYPE_FIELD_TYPE (type, type_index);
|
|
|
|
|
}
|
|
|
|
|
else if (index < TYPE_N_BASECLASSES (type))
|
|
|
|
|
{
|
|
|
|
|
/* This is a baseclass. */
|
|
|
|
|
if (cname)
|
|
|
|
|
*cname = xstrdup (TYPE_FIELD_NAME (type, index));
|
|
|
|
|
|
|
|
|
|
if (cvalue && value)
|
|
|
|
|
*cvalue = value_cast (TYPE_FIELD_TYPE (type, index), value);
|
|
|
|
|
|
|
|
|
|
if (ctype)
|
|
|
|
|
{
|
|
|
|
|
*ctype = TYPE_FIELD_TYPE (type, index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cfull_expression)
|
|
|
|
|
{
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
When we are in the scope of the base class or of one
|
|
|
|
|
of its children, the type field name will be interpreted
|
|
|
|
|
as a constructor, if it exists. Therefore, we must
|
|
|
|
|
indicate that the name is a class name by using the
|
|
|
|
|
'class' keyword. See PR mi/11912 */
|
|
|
|
|
*cfull_expression = xstrprintf ("(%s(class %s%s) %s)",
|
|
|
|
|
ptr,
|
|
|
|
|
TYPE_FIELD_NAME (type, index),
|
|
|
|
|
ptr,
|
|
|
|
|
parent_expression);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
char *access = NULL;
|
|
|
|
|
int children[3];
|
|
|
|
|
|
|
|
|
|
cplus_class_num_children (type, children);
|
|
|
|
|
|
|
|
|
|
/* Everything beyond the baseclasses can
|
|
|
|
|
only be "public", "private", or "protected"
|
|
|
|
|
|
|
|
|
|
The special "fake" children are always output by varobj in
|
|
|
|
|
this order. So if INDEX == 2, it MUST be "protected". */
|
|
|
|
|
index -= TYPE_N_BASECLASSES (type);
|
|
|
|
|
switch (index)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
if (children[v_public] > 0)
|
|
|
|
|
access = "public";
|
|
|
|
|
else if (children[v_private] > 0)
|
|
|
|
|
access = "private";
|
|
|
|
|
else
|
|
|
|
|
access = "protected";
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
if (children[v_public] > 0)
|
|
|
|
|
{
|
|
|
|
|
if (children[v_private] > 0)
|
|
|
|
|
access = "private";
|
|
|
|
|
else
|
|
|
|
|
access = "protected";
|
|
|
|
|
}
|
|
|
|
|
else if (children[v_private] > 0)
|
|
|
|
|
access = "protected";
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
/* Must be protected. */
|
|
|
|
|
access = "protected";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/* error! */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gdb_assert (access);
|
|
|
|
|
if (cname)
|
|
|
|
|
*cname = xstrdup (access);
|
|
|
|
|
|
|
|
|
|
/* Value and type and full expression are null here. */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
c_describe_child (parent, index, cname, cvalue, ctype, cfull_expression);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
cplus_name_of_child (struct varobj *parent, int index)
|
|
|
|
|
{
|
|
|
|
|
char *name = NULL;
|
|
|
|
|
|
|
|
|
|
cplus_describe_child (parent, index, &name, NULL, NULL, NULL);
|
|
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
cplus_path_expr_of_child (struct varobj *child)
|
|
|
|
|
{
|
|
|
|
|
cplus_describe_child (child->parent, child->index, NULL, NULL, NULL,
|
|
|
|
|
&child->path_expr);
|
|
|
|
|
return child->path_expr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct value *
|
|
|
|
|
cplus_value_of_child (struct varobj *parent, int index)
|
|
|
|
|
{
|
|
|
|
|
struct value *value = NULL;
|
|
|
|
|
|
|
|
|
|
cplus_describe_child (parent, index, NULL, &value, NULL, NULL);
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct type *
|
|
|
|
|
cplus_type_of_child (struct varobj *parent, int index)
|
|
|
|
|
{
|
|
|
|
|
struct type *type = NULL;
|
|
|
|
|
|
|
|
|
|
cplus_describe_child (parent, index, NULL, NULL, &type, NULL);
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
cplus_value_of_variable (struct varobj *var,
|
|
|
|
|
enum varobj_display_formats format)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/* If we have one of our special types, don't print out
|
|
|
|
|
any value. */
|
|
|
|
|
if (CPLUS_FAKE_CHILD (var))
|
|
|
|
|
return xstrdup ("");
|
|
|
|
|
|
|
|
|
|
return c_value_of_variable (var, format);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* varobj operations for c++. */
|
|
|
|
|
|
|
|
|
|
const struct lang_varobj_ops cplus_varobj_ops =
|
|
|
|
|
{
|
|
|
|
|
cplus_number_of_children,
|
|
|
|
|
cplus_name_of_variable,
|
|
|
|
|
cplus_name_of_child,
|
|
|
|
|
cplus_path_expr_of_child,
|
|
|
|
|
cplus_value_of_child,
|
|
|
|
|
cplus_type_of_child,
|
|
|
|
|
cplus_value_of_variable,
|
|
|
|
|
varobj_default_value_is_changeable_p,
|
Improve MI -var-info-path-expression for nested struct/union case.
https://sourceware.org/ml/gdb-patches/2014-05/msg00383.html
The MI command -var-info-path-expression currently does not handle
non-anonymous structs / unions nested within other structs / unions,
it will skip parts of the expression. Consider this example:
## START EXAMPLE ##
$ cat ex.c
#include <string.h>
int
main ()
{
struct s1
{
int a;
};
struct ss
{
struct s1 x;
};
struct ss an_ss;
memset (&an_ss, 0, sizeof (an_ss));
return 0;
}
$ gcc -g -o ex.x ex.c
$ gdb ex.x
(gdb) break 18
Breakpoint 1 at 0x80483ba: file ex.c, line 18.
(gdb) run
Starting program: /home/user/ex.x
Breakpoint 1, main () at ex.c:18
18 return 0;
(gdb) interpreter-exec mi "-var-create an_ss * an_ss"
(gdb) interpreter-exec mi "-var-list-children an_ss"
^done,numchild="1",children=[child={name="an_ss.x",exp="x",numchild="1",type="struct s1",thread-id="1"}],has_more="0"
(gdb) interpreter-exec mi "-var-list-children an_ss.x"
^done,numchild="1",children=[child={name="an_ss.x.a",exp="a",numchild="0",type="int",thread-id="1"}],has_more="0"
(gdb) interpreter-exec mi "-var-list-children an_ss.x.a"
^done,numchild="0",has_more="0"
(gdb) interpreter-exec mi "-var-info-path-expression an_ss.x.a"
^done,path_expr="(an_ss).a"
(gdb) print (an_ss).a
There is no member named a.
## END EXAMPLE ##
Notice that the path expression returned is wrong, and as a result
the print command fails.
This patch adds a new method to the varobj_ops structure called
is_path_expr_parent, to allow language specific control over finding
the parent varobj, the current logic becomes the C/C++ version and is
extended to handle the nested cases. No other language currently uses
this code, so all other languages just get a default method.
With this patch, the above example now finishes like this:
## START EXAMPLE ##
$ gdb ex.x
(gdb) break 18
Breakpoint 1 at 0x80483ba: file ex.c, line 18.
(gdb) run
Starting program: /home/user/ex.x
Breakpoint 1, main () at ex.c:18
18 return 0;
(gdb) interpreter-exec mi "-var-list-children an_ss"
^done,numchild="1",children=[child={name="an_ss.x",exp="x",numchild="1",type="struct s1",thread-id="1"}],has_more="0"
(gdb) interpreter-exec mi "-var-list-children an_ss.x"
^done,numchild="1",children=[child={name="an_ss.x.a",exp="a",numchild="0",type="int",thread-id="1"}],has_more="0"
(gdb) interpreter-exec mi "-var-list-children an_ss.x.a"
^done,numchild="0",has_more="0"
(gdb) interpreter-exec mi "-var-info-path-expression an_ss.x.a"
^done,path_expr="((an_ss).x).a"
(gdb) print ((an_ss).x).a
$1 = 0
## END EXAMPLE ##
Notice that the path expression is now correct, and the print is a
success.
gdb/ChangeLog:
* ada-varobj.c (ada_varobj_ops): Fill in is_path_expr_parent
field.
* c-varobj.c (c_is_path_expr_parent): New function, moved core
from varobj.c, with additional checks.
(c_varobj_ops): Fill in is_path_expr_parent field.
(cplus_varobj_ops): Fill in is_path_expr_parent field.
* jv-varobj.c (java_varobj_ops): Fill in is_path_expr_parent
field.
* varobj.c (is_path_expr_parent): Call is_path_expr_parent varobj
ops method.
(varobj_default_is_path_expr_parent): New function.
* varobj.h (lang_varobj_ops): Add is_path_expr_parent field.
(varobj_default_is_path_expr_parent): Declare new function.
gdb/testsuite/ChangeLog:
* gdb.mi/var-cmd.c (do_nested_struct_union_tests): New function
setting up test structures.
(main): Call new test function.
* gdb.mi/mi2-var-child.exp: Create additional breakpoint in new
test function, continue into test function and walk test
structures.
2014-07-08 02:22:36 +08:00
|
|
|
|
NULL, /* value_has_mutated */
|
|
|
|
|
c_is_path_expr_parent /* is_path_expr_parent */
|
gdb/
* Makefile.in (SFILES): Add c-varobj.c and jv-varobj.c.
(COMMON_OBS): Add c-varobj.o and jv-varobj.o.
* ada-varobj.c: Include "varobj.h".
(ada_number_of_children): New. Moved from varobj.c.
(ada_name_of_variable, ada_name_of_child): Likewise.
(ada_path_expr_of_child, ada_value_of_child): Likewise.
(ada_type_of_child, ada_value_of_variable): Likewise.
(ada_value_is_changeable_p, ada_value_has_mutated): Likewise.
(ada_varobj_ops): New.
* c-varobj.c, jv-varobj.c: New file. Moved from varobj.c.
* gdbtypes.c (get_target_type): New. Moved from varobj.c.
* gdbtypes.h (get_target_type): Declare.
* varobj.c: Remove the inclusion of "ada-varobj.h" and
"ada-lang.h".
(ANONYMOUS_STRUCT_NAME): Move it to c-varobj.c.
(ANONYMOUS_UNION_NAME): Likewise.
(get_type, get_value_type, get_target_type): Remove declarations.
(value_get_print_value, varobj_value_get_print_value): Likewise.
(c_number_of_children, c_name_of_variable): Likewise.
(c_name_of_child, c_path_expr_of_child): Likewise.
(c_value_of_child, c_type_of_child): Likewise.
(c_value_of_variable, cplus_number_of_children): Likewise.
(cplus_class_num_children, cplus_name_of_variable): Likewise.
(cplus_name_of_child, cplus_path_expr_of_child): Likewise.
(cplus_value_of_child, cplus_type_of_child): Likewise.
(cplus_value_of_variable, java_number_of_children): Likewise.
(java_name_of_variable, java_name_of_child): Likewise.
(java_path_expr_of_child, java_value_of_child): Likewise.
(java_type_of_child, java_value_of_variable): Likewise.
(ada_number_of_children, ada_name_of_variable): Likewise.
(ada_name_of_child, ada_path_expr_of_child): Likewise.
(ada_value_of_child, ada_type_of_child): Likewise.
(ada_value_of_variable, ada_value_is_changeable_p): Likewise.
(ada_value_has_mutated): Likewise.
(struct language_specific): Move it to varobj.h.
(CPLUS_FAKE_CHILD): Move it to varobj.h.
(restrict_range): Rename it varobj_restrict_range. Make it extern.
Callers update.
(get_path_expr_parent): Rename it to varobj_get_path_expr_parent.
Make it extern.
(is_anonymous_child): Move it to c-varobj.c and rename to
varobj_is_anonymous_child. Caller update.
(get_type): Move it to c-varobj.c.
(get_value_type): Rename it varobj_get_value_type. Make it
extern.
(get_target_type): Move it gdbtypes.c.
(varobj_formatted_print_options): New function.
(value_get_print_value): Rename it to
varobj_value_get_print_value and make it extern.
(varobj_value_is_changeable_p): Make it extern.
(adjust_value_for_child_access): Move it to c-varobj.c.
(default_value_is_changeable_p): Rename it to
varobj_default_value_is_changeable_p. Make it extern.
(c_number_of_children, c_name_of_variable): Move it to c-varobj.c
(c_name_of_child, c_path_expr_of_child): Likewise.
(c_value_of_child, c_type_of_child): Likewise.
(c_value_of_variable, cplus_number_of_children): Likewise.
(cplus_class_num_children, cplus_name_of_variable): Likewise.
(cplus_name_of_child, cplus_path_expr_of_child): Likewise.
(cplus_value_of_child, cplus_type_of_child): Likewise.
(cplus_value_of_variable): Likewise.
(java_number_of_children, java_name_of_variable): Move it to jv-varobj.c.
(java_name_of_child, java_path_expr_of_child): Likewise.
(java_value_of_child, java_type_of_child): Likewise.
(java_value_of_variable): Likewise.
(ada_number_of_children, ada_name_of_variable): Move it to ada-varobj.c.
(ada_name_of_child, ada_path_expr_of_child): Likewise.
(ada_value_of_child, ada_type_of_child): Likewise.
(ada_value_of_variable, ada_value_is_changeable_p): Likewise.
(ada_value_has_mutated): Likewise.
* varobj.h (CPLUS_FAKE_CHILD): New macro, moved from varobj.c.
(struct lang_varobj_ops): New. Renamed by 'struct language_specific'.
(c_varobj_ops, cplus_varobj_ops): Declare.
(java_varobj_ops, ada_varobj_ops): Declare.
(varobj_default_value_is_changeable_p): Declare.
(varobj_value_is_changeable_p): Declare.
(varobj_get_value_type, varobj_is_anonymous_child): Declare.
(varobj_get_path_expr_parent): Declare.
(varobj_value_get_print_value): Declare.
(varobj_formatted_print_options): Declare.
(varobj_restrict_range): Declare.
2013-10-17 21:28:37 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|