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.
This commit is contained in:
Anton Gorenkov 2012-04-14 12:18:50 +00:00
parent 5f18041e78
commit 8264ba82b7
10 changed files with 742 additions and 42 deletions

View File

@ -1,3 +1,23 @@
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.
2012-04-14 Yao Qi <yao@codesourcery.com>
Import gnulib module inttypes from git

View File

@ -1,3 +1,11 @@
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.
2012-04-11 Siva Chandra Reddy <sivachandra@google.com>
* gdb.texinfo (Examining Data): Document the 'explore' command.

View File

@ -8666,7 +8666,8 @@ When displaying a pointer to an object, identify the @emph{actual}
the virtual function table. Note that the virtual function table is
required---this feature can only work for objects that have run-time
type identification; a single virtual method in the object's declared
type is sufficient.
type is sufficient. Note that this setting is also taken into account when
working with variable objects via MI (@pxref{GDB/MI}).
@item set print object off
Display only the declared type of objects, without reference to the
@ -29103,7 +29104,10 @@ will not be interesting.
@item type
The varobj's type. This is a string representation of the type, as
would be printed by the @value{GDBN} CLI.
would be printed by the @value{GDBN} CLI. If @samp{print object}
(@pxref{Print Settings, set print object}) is set to @code{on}, the
@emph{actual} (derived) type of the object is shown rather than the
@emph{declared} one.
@item thread-id
If a variable object is bound to a specific thread, then this is the
@ -29274,7 +29278,10 @@ Number of children this child has. For a dynamic varobj, this will be
0.
@item type
The type of the child.
The type of the child. If @samp{print object}
(@pxref{Print Settings, set print object}) is set to @code{on}, the
@emph{actual} (derived) type of the object is shown rather than the
@emph{declared} one.
@item value
If values were requested, this is the value.

View File

@ -1,3 +1,12 @@
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.
2012-04-11 Siva Chandra Reddy <sivachandra@google.com>
* gdb.python/Makefile.in: Add py-explore and py-explore-cc to

View File

@ -0,0 +1,360 @@
/* Copyright 2012 Free Software Foundation, Inc.
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/>.
*/
struct Base {
Base() : A(1) {}
virtual ~Base() {} // Enforce type to have vtable
int A;
};
struct Derived : public Base {
Derived() : B(2), C(3) {}
int B;
int C;
};
void use_rtti_for_ptr_test ()
{
/*: BEGIN: use_rtti_for_ptr :*/
Derived d;
Base* ptr = &d;
const Base* constPtr = &d;
Base* const ptrConst = &d;
Base const* const constPtrConst = &d;
/*:
set testname use_rtti_for_ptr
set_print_object off $testname
check_new_derived_without_rtti ptr {Base \*} $testname
check_new_derived_without_rtti constPtr {const Base \*} $testname
check_new_derived_without_rtti ptrConst {Base \* const} $testname
check_new_derived_without_rtti constPtrConst {const Base \* const} \
$testname
set_print_object on $testname
check_new_derived_with_rtti ptr {Derived \*} $testname
check_new_derived_with_rtti constPtr {const Derived \*} $testname
check_new_derived_with_rtti ptrConst {Derived \* const} $testname
check_new_derived_with_rtti constPtrConst {const Derived \* const} \
$testname
:*/
return;
/*: END: use_rtti_for_ptr :*/
}
void use_rtti_for_ref_test ()
{
/*: BEGIN: use_rtti_for_ref :*/
Derived d;
Base& ref = d;
const Base& constRef = d;
/*:
set testname use_rtti_for_ref
set_print_object off $testname
check_new_derived_without_rtti ref {Base \&} $testname
check_new_derived_without_rtti constRef {const Base \&} $testname
set_print_object on $testname
check_new_derived_with_rtti ref {Derived \&} $testname
check_new_derived_with_rtti constRef {const Derived \&} $testname
:*/
return;
/*: END: use_rtti_for_ref :*/
}
void use_rtti_for_ptr_child_test ()
{
/*: BEGIN: use_rtti_for_ptr_child :*/
Derived d;
struct S {
Base* ptr;
const Base* constPtr;
Base* const ptrConst;
Base const* const constPtrConst;
S ( Base* v ) :
ptr ( v ),
constPtr ( v ),
ptrConst ( v ),
constPtrConst ( v ) {}
} s ( &d );
/*:
set testname use_rtti_for_ptr_child
set_print_object off $testname
mi_create_varobj VAR s "create varobj for s (without RTTI) in $testname"
mi_list_varobj_children VAR {
{ VAR.public public 4 }
} "list children of s (without RTTI) in $testname"
mi_list_varobj_children VAR.public {
{ VAR.public.ptr ptr 1 {Base \*} }
{ VAR.public.constPtr constPtr 1 {const Base \*} }
{ VAR.public.ptrConst ptrConst 1 {Base \* const} }
{ VAR.public.constPtrConst constPtrConst 1 {const Base \* const} }
} "list children of s.public (without RTTI) in $testname"
check_derived_without_rtti VAR.public.ptr s.ptr $testname
check_derived_without_rtti VAR.public.constPtr s.constPtr $testname
check_derived_without_rtti VAR.public.ptrConst s.ptrConst $testname
check_derived_without_rtti VAR.public.constPtrConst s.constPtrConst \
$testname
mi_delete_varobj VAR "delete varobj for s (without RTTI) in $testname"
set_print_object on $testname
mi_create_varobj VAR s "create varobj for s (with RTTI) in $testname"
mi_list_varobj_children VAR {
{ VAR.public public 4 }
} "list children of s (with RTTI) in $testname"
mi_list_varobj_children VAR.public {
{ VAR.public.ptr ptr 2 {Derived \*} }
{ VAR.public.constPtr constPtr 2 {const Derived \*} }
{ VAR.public.ptrConst ptrConst 2 {Derived \* const} }
{ VAR.public.constPtrConst constPtrConst 2 {const Derived \* const}}
} "list children of s.public (with RTTI) in $testname"
check_derived_with_rtti VAR.public.ptr s.ptr $testname
check_derived_with_rtti VAR.public.constPtr s.constPtr $testname
check_derived_with_rtti VAR.public.ptrConst s.ptrConst $testname
check_derived_with_rtti VAR.public.constPtrConst s.constPtrConst \
$testname
mi_delete_varobj VAR "delete varobj for s (with RTTI) in $testname"
:*/
return;
/*: END: use_rtti_for_ptr_child :*/
}
void use_rtti_for_ref_child_test ()
{
/*: BEGIN: use_rtti_for_ref_child :*/
Derived d;
struct S {
Base& ref;
const Base& constRef;
S ( Base& v ) :
ref ( v ),
constRef ( v ) {}
} s ( d );
/*:
set testname use_rtti_for_ref_child
set_print_object off $testname
mi_create_varobj VAR s "create varobj for s (without RTTI) in $testname"
mi_list_varobj_children VAR {
{ VAR.public public 2 }
} "list children of s (without RTTI) in $testname"
mi_list_varobj_children VAR.public {
{ VAR.public.ref ref 1 {Base \&} }
{ VAR.public.constRef constRef 1 {const Base \&} }
} "list children of s.public (without RTTI) in $testname"
check_derived_without_rtti VAR.public.ref s.ref $testname
check_derived_without_rtti VAR.public.constRef s.constRef $testname
mi_delete_varobj VAR "delete varobj for s (without RTTI) in $testname"
set_print_object on $testname
mi_create_varobj VAR s "create varobj for s (with RTTI) in $testname"
mi_list_varobj_children VAR {
{ VAR.public public 2 }
} "list children of s (with RTTI) in $testname"
mi_list_varobj_children VAR.public {
{ VAR.public.ref ref 2 {Derived \&} }
{ VAR.public.constRef constRef 2 {const Derived \&} }
} "list children of s.public (with RTTI) in $testname"
check_derived_with_rtti VAR.public.ref s.ref $testname
check_derived_with_rtti VAR.public.constRef s.constRef $testname
mi_delete_varobj VAR "delete varobj for s (with RTTI) in $testname"
:*/
return;
/*: END: use_rtti_for_ref_child :*/
}
struct First {
First() : F(-1) {}
int F;
};
struct MultipleDerived : public First, Base {
MultipleDerived() : B(2), C(3) {}
int B;
int C;
};
void use_rtti_with_multiple_inheritence_test ()
{
/*: BEGIN: use_rtti_with_multiple_inheritence :*/
MultipleDerived d;
Base* ptr = &d;
Base& ref = d;
/*:
set testname use_rtti_with_multiple_inheritence
set_print_object off $testname
check_new_derived_without_rtti ptr {Base \*} $testname
check_new_derived_without_rtti ref {Base \&} $testname
set_print_object on $testname
mi_create_varobj_checked VAR ptr {MultipleDerived \*} \
"create varobj for ptr (with RTTI) in $testname"
mi_list_varobj_children VAR {
{ VAR.First First 1 First }
{ VAR.Base Base 1 Base }
{ VAR.public public 2 }
} "list children of ptr (with RTTI) in $testname"
mi_list_varobj_children "VAR.First" {
{ VAR.First.public public 1 }
} "list children of ptr.First (with RTTI) in $testname"
mi_list_varobj_children "VAR.First.public" {
{ VAR.First.public.F F 0 int }
} "list children of ptr.Base.public (with RTTI) in $testname"
mi_list_varobj_children "VAR.Base" {
{ VAR.Base.public public 1 }
} "list children of ptr.Base (with RTTI) in $testname"
mi_list_varobj_children "VAR.Base.public" {
{ VAR.Base.public.A A 0 int }
} "list children of ptr.Base.public (with RTTI) in $testname"
mi_list_varobj_children "VAR.public" {
{ VAR.public.B B 0 int }
{ VAR.public.C C 0 int }
} "list children of ptr.public (with RTTI) in $testname"
mi_delete_varobj VAR \
"delete varobj for ptr (with RTTI) in $testname"
:*/
return;
/*: END: use_rtti_with_multiple_inheritence :*/
}
void type_update_when_use_rtti_test ()
{
/*: BEGIN: type_update_when_use_rtti :*/
Derived d;
/*:
set testname type_update_when_use_rtti
set_print_object on $testname
mi_create_varobj_checked PTR ptr {Base \*} \
"create varobj for ptr in $testname"
check_derived_children_without_rtti PTR ptr $testname
mi_create_varobj S s "create varobj for S in $testname"
mi_list_varobj_children S {
{ S.public public 1 }
} "list children of s in $testname"
mi_list_varobj_children S.public {
{ S.public.ptr ptr 1 {Base \*} }
} "list children of s.public in $testname"
check_derived_children_without_rtti S.public.ptr s.ptr $testname
:*/
Base* ptr = &d;
struct S {
Base* ptr;
S ( Base* v ) :
ptr ( v ) {}
} s ( &d );
/*:
mi_varobj_update_with_type_change PTR {Derived \*} 2 \
"update ptr to derived in $testname"
check_derived_with_rtti PTR ptr $testname
mi_varobj_update_with_child_type_change S S.public.ptr {Derived \*} 2 \
"update s.ptr to derived in $testname"
check_derived_with_rtti S.public.ptr s.ptr $testname
:*/
ptr = 0;
s.ptr = 0;
/*:
mi_varobj_update_with_type_change PTR {Base \*} 1 \
"update ptr back to base type in $testname"
mi_delete_varobj PTR "delete varobj for ptr in $testname"
mi_varobj_update_with_child_type_change S S.public.ptr {Base \*} 1 \
"update s.ptr back to base type in $testname"
mi_delete_varobj S "delete varobj for s in $testname"
:*/
return;
/*: END: type_update_when_use_rtti :*/
}
void skip_type_update_when_not_use_rtti_test ()
{
/*: BEGIN: skip_type_update_when_not_use_rtti :*/
Derived d;
/*:
set testname skip_type_update_when_not_use_rtti
set_print_object off $testname
mi_create_varobj_checked PTR ptr {Base \*} \
"create varobj for ptr in $testname"
check_derived_children_without_rtti PTR ptr $testname
mi_create_varobj S s "create varobj for S in $testname"
mi_list_varobj_children S {
{ S.public public 1 }
} "list children of s in $testname"
mi_list_varobj_children S.public {
{ S.public.ptr ptr 1 {Base \*} }
} "list children of s.public in $testname"
check_derived_children_without_rtti S.public.ptr s.ptr $testname
:*/
Base* ptr = &d;
struct S {
Base* ptr;
S ( Base* v ) :
ptr ( v ) {}
} s ( &d );
/*:
mi_varobj_update PTR {PTR PTR.public.A} \
"update ptr to derived type in $testname"
check_derived_without_rtti PTR ptr $testname
mi_varobj_update S {S.public.ptr S.public.ptr.public.A} \
"update s to derived type in $testname"
check_derived_without_rtti S.public.ptr s.ptr $testname
:*/
ptr = 0;
s.ptr = 0;
/*:
mi_varobj_update PTR {PTR PTR.public.A} \
"update ptr back to base type in $testname"
mi_delete_varobj PTR "delete varobj for ptr in $testname"
mi_varobj_update S {S.public.ptr S.public.ptr.public.A} \
"update s back to base type in $testname"
mi_delete_varobj S "delete varobj for s in $testname"
:*/
return;
/*: END: skip_type_update_when_not_use_rtti :*/
}
int main ()
{
use_rtti_for_ptr_test();
use_rtti_for_ref_test();
use_rtti_for_ptr_child_test();
use_rtti_for_ref_child_test();
use_rtti_with_multiple_inheritence_test();
type_update_when_use_rtti_test();
skip_type_update_when_not_use_rtti_test();
return 0;
}

View File

@ -0,0 +1,124 @@
# Copyright 2012 Free Software Foundation, Inc.
# 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/>.
if { [skip_cplus_tests] } { continue }
load_lib mi-support.exp
set MIFLAGS "-i=mi"
gdb_exit
if [mi_gdb_start] {
continue
}
set testfile mi-var-rtti
set srcfile "$testfile.cc"
set executable ${testfile}
set binfile $objdir/$subdir/$testfile
set opts {debug c++}
if [build_executable $testfile.exp $executable $srcfile $opts] {
return -1;
}
mi_gdb_load ${binfile}
mi_prepare_inline_tests $srcfile
# Enable using RTTI to determine real types of the objects
proc set_print_object {state testname} {
mi_gdb_test "-interpreter-exec console \"set print object ${state}\"" \
{\^done} \
"-interpreter-exec console \"set print object ${state}\" in $testname"
}
proc check_derived_children_without_rtti {varobj_name var_name testname} {
mi_list_varobj_children ${varobj_name} "
{ ${varobj_name}.public public 1 }
" "list children of ${var_name} (without RTTI) in $testname"
mi_list_varobj_children "${varobj_name}.public" "
{ ${varobj_name}.public.A A 0 int }
" "list children of ${var_name}.public (without RTTI) in $testname"
}
proc check_derived_content_without_rtti {varobj_name var_name testname} {
mi_check_varobj_value ${varobj_name}.public.A 1 \
"check ${var_name}->A (without RTTI) in $testname"
}
proc check_derived_without_rtti {varobj_name var_name testname} {
check_derived_children_without_rtti ${varobj_name} ${var_name} ${testname}
check_derived_content_without_rtti ${varobj_name} ${var_name} ${testname}
}
proc check_new_derived_without_rtti {var_name var_type testname} {
set varobj_name VAR
mi_create_varobj_checked ${varobj_name} ${var_name} ${var_type} \
"create varobj for ${var_name} (without RTTI) in ${testname}"
check_derived_without_rtti ${varobj_name} ${var_name} ${testname}
mi_delete_varobj ${varobj_name} \
"delete varobj for ${var_name} (without RTTI) in ${testname}"
}
proc check_derived_children_with_rtti {varobj_name var_name testname} {
mi_list_varobj_children ${varobj_name} "
{ ${varobj_name}.Base Base 1 Base }
{ ${varobj_name}.public public 2 }
" "list children of ${var_name} (with RTTI) in $testname"
mi_list_varobj_children "${varobj_name}.Base" "
{ ${varobj_name}.Base.public public 1 }
" "list children of ${var_name}.Base (with RTTI) in $testname"
mi_list_varobj_children "${varobj_name}.Base.public" "
{ ${varobj_name}.Base.public.A A 0 int }
" "list children of ${var_name}.Base.public (with RTTI) in $testname"
mi_list_varobj_children "${varobj_name}.public" "
{ ${varobj_name}.public.B B 0 int }
{ ${varobj_name}.public.C C 0 int }
" "list children of ${var_name}.public (with RTTI) in $testname"
}
proc check_derived_content_with_rtti {varobj_name var_name testname} {
mi_check_varobj_value ${varobj_name}.Base.public.A 1 \
"check ${var_name}->A (with RTTI) in $testname"
mi_check_varobj_value ${varobj_name}.public.B 2 \
"check ${var_name}->B (with RTTI) in $testname"
mi_check_varobj_value ${varobj_name}.public.C 3 \
"check ${var_name}->C (with RTTI) in $testname"
}
proc check_derived_with_rtti {varobj_name var_name testname} {
check_derived_children_with_rtti ${varobj_name} ${var_name} $testname
check_derived_content_with_rtti ${varobj_name} ${var_name} $testname
}
proc check_new_derived_with_rtti {var_name var_type testname} {
set varobj_name VAR
mi_create_varobj_checked ${varobj_name} ${var_name} ${var_type} \
"create varobj for ${var_name} (with RTTI) in $testname"
check_derived_with_rtti ${varobj_name} ${var_name} $testname
mi_delete_varobj ${varobj_name} \
"delete varobj for ${var_name} (with RTTI) in $testname"
}
mi_run_inline_test use_rtti_for_ptr
mi_run_inline_test use_rtti_for_ref
mi_run_inline_test use_rtti_for_ptr_child
mi_run_inline_test use_rtti_for_ref_child
mi_run_inline_test use_rtti_with_multiple_inheritence
mi_run_inline_test type_update_when_use_rtti
mi_run_inline_test skip_type_update_when_not_use_rtti
mi_gdb_exit
return 0

View File

@ -1298,13 +1298,17 @@ proc mi_varobj_update { name expected testname } {
mi_gdb_test "-var-update $name" $er $testname
}
proc mi_varobj_update_with_type_change { name new_type new_children testname } {
set v "{name=\"$name\",in_scope=\"true\",type_changed=\"true\",new_type=\"$new_type\",new_num_children=\"$new_children\",has_more=\".\"}"
proc mi_varobj_update_with_child_type_change { name child_name new_type new_children testname } {
set v "{name=\"$child_name\",in_scope=\"true\",type_changed=\"true\",new_type=\"$new_type\",new_num_children=\"$new_children\",has_more=\".\"}"
set er "\\^done,changelist=\\\[$v\\\]"
verbose -log "Expecting: $er"
mi_gdb_test "-var-update $name" $er $testname
}
proc mi_varobj_update_with_type_change { name new_type new_children testname } {
mi_varobj_update_with_child_type_change $name $name $new_type $new_children $testname
}
# A helper that turns a key/value list into a regular expression
# matching some MI output.
proc mi_varobj_update_kv_helper {list} {

View File

@ -834,6 +834,47 @@ value_enclosing_type (struct value *value)
return value->enclosing_type;
}
/* Look at value.h for description. */
struct type *
value_actual_type (struct value *value, int resolve_simple_types,
int *real_type_found)
{
struct value_print_options opts;
struct value *target;
struct type *result;
get_user_print_options (&opts);
if (real_type_found)
*real_type_found = 0;
result = value_type (value);
if (opts.objectprint)
{
if (TYPE_CODE (result) == TYPE_CODE_PTR
|| TYPE_CODE (result) == TYPE_CODE_REF)
{
struct type *real_type;
real_type = value_rtti_indirect_type (value, NULL, NULL, NULL);
if (real_type)
{
if (real_type_found)
*real_type_found = 1;
result = real_type;
}
}
else if (resolve_simple_types)
{
if (real_type_found)
*real_type_found = 1;
result = value_enclosing_type (value);
}
}
return result;
}
static void
require_not_optimized_out (const struct value *value)
{

View File

@ -138,6 +138,22 @@ extern struct type *value_enclosing_type (struct value *);
extern void set_value_enclosing_type (struct value *val,
struct type *new_type);
/* Returns value_type or value_enclosing_type depending on
value_print_options.objectprint.
If RESOLVE_SIMPLE_TYPES is 0 the enclosing type will be resolved
only for pointers and references, else it will be returned
for all the types (e.g. structures). This option is useful
to prevent retrieving enclosing type for the base classes fields.
REAL_TYPE_FOUND is used to inform whether the real type was found
(or just static type was used). The NULL may be passed if it is not
necessary. */
extern struct type *value_actual_type (struct value *value,
int resolve_simple_types,
int *real_type_found);
extern int value_pointed_to_offset (struct value *value);
extern void set_value_pointed_to_offset (struct value *value, int val);
extern int value_embedded_offset (struct value *value);

View File

@ -270,6 +270,9 @@ static void cppush (struct cpstack **pstack, char *name);
static char *cppop (struct cpstack **pstack);
static int update_type_if_necessary (struct varobj *var,
struct value *new_value);
static int install_new_value (struct varobj *var, struct value *value,
int initial);
@ -716,8 +719,14 @@ varobj_create (char *objname,
var->type = value_type (type_only_value);
}
else
var->type = value_type (value);
else
{
int real_type_found = 0;
var->type = value_actual_type (value, 0, &real_type_found);
if (real_type_found)
value = value_cast (var->type, value);
}
/* Set language info */
lang = variable_language (var);
@ -1005,6 +1014,7 @@ restrict_range (VEC (varobj_p) *children, int *from, int *to)
static void
install_dynamic_child (struct varobj *var,
VEC (varobj_p) **changed,
VEC (varobj_p) **type_changed,
VEC (varobj_p) **new,
VEC (varobj_p) **unchanged,
int *cchanged,
@ -1027,12 +1037,18 @@ install_dynamic_child (struct varobj *var,
{
varobj_p existing = VEC_index (varobj_p, var->children, index);
int type_updated = update_type_if_necessary (existing, value);
if (type_updated)
{
if (type_changed)
VEC_safe_push (varobj_p, *type_changed, existing);
}
if (install_new_value (existing, value, 0))
{
if (changed)
if (!type_updated && changed)
VEC_safe_push (varobj_p, *changed, existing);
}
else if (unchanged)
else if (!type_updated && unchanged)
VEC_safe_push (varobj_p, *unchanged, existing);
}
}
@ -1055,6 +1071,7 @@ dynamic_varobj_has_child_method (struct varobj *var)
static int
update_dynamic_varobj_children (struct varobj *var,
VEC (varobj_p) **changed,
VEC (varobj_p) **type_changed,
VEC (varobj_p) **new,
VEC (varobj_p) **unchanged,
int *cchanged,
@ -1190,6 +1207,7 @@ update_dynamic_varobj_children (struct varobj *var,
if (v == NULL)
gdbpy_print_stack ();
install_dynamic_child (var, can_mention ? changed : NULL,
can_mention ? type_changed : NULL,
can_mention ? new : NULL,
can_mention ? unchanged : NULL,
can_mention ? cchanged : NULL, i, name, v);
@ -1245,7 +1263,7 @@ varobj_get_num_children (struct varobj *var)
/* If we have a dynamic varobj, don't report -1 children.
So, try to fetch some children first. */
update_dynamic_varobj_children (var, NULL, NULL, NULL, &dummy,
update_dynamic_varobj_children (var, NULL, NULL, NULL, NULL, &dummy,
0, 0, 0);
}
else
@ -1271,8 +1289,8 @@ varobj_list_children (struct varobj *var, int *from, int *to)
/* This, in theory, can result in the number of children changing without
frontend noticing. But well, calling -var-list-children on the same
varobj twice is not something a sane frontend would do. */
update_dynamic_varobj_children (var, NULL, NULL, NULL, &children_changed,
0, 0, *to);
update_dynamic_varobj_children (var, NULL, NULL, NULL, NULL,
&children_changed, 0, 0, *to);
restrict_range (var->children, from, to);
return var->children;
}
@ -1619,6 +1637,43 @@ install_new_value_visualizer (struct varobj *var)
#endif
}
/* When using RTTI to determine variable type it may be changed in runtime when
the variable value is changed. This function checks whether type of varobj
VAR will change when a new value NEW_VALUE is assigned and if it is so
updates the type of VAR. */
static int
update_type_if_necessary (struct varobj *var, struct value *new_value)
{
if (new_value)
{
struct value_print_options opts;
get_user_print_options (&opts);
if (opts.objectprint)
{
struct type *new_type;
char *curr_type_str, *new_type_str;
new_type = value_actual_type (new_value, 0, 0);
new_type_str = type_to_string (new_type);
curr_type_str = varobj_get_type (var);
if (strcmp (curr_type_str, new_type_str) != 0)
{
var->type = new_type;
/* This information may be not valid for a new type. */
varobj_delete (var, NULL, 1);
VEC_free (varobj_p, var->children);
var->num_children = -1;
return 1;
}
}
}
return 0;
}
/* Assign a new value to a variable object. If INITIAL is non-zero,
this is the first assignement after the variable object was just
created, or changed type. In that case, just assign the value
@ -1948,8 +2003,9 @@ varobj_update (struct varobj **varp, int explicit)
value_of_root variable dispose of the varobj if the type
has changed. */
new = value_of_root (varp, &type_changed);
if (update_type_if_necessary(*varp, new))
type_changed = 1;
r.varobj = *varp;
r.type_changed = type_changed;
if (install_new_value ((*varp), new, type_changed))
r.changed = 1;
@ -1990,6 +2046,8 @@ varobj_update (struct varobj **varp, int explicit)
struct type *new_type;
new = value_of_child (v->parent, v->index);
if (update_type_if_necessary(v, new))
r.type_changed = 1;
if (new)
new_type = value_type (new);
else
@ -2019,7 +2077,8 @@ varobj_update (struct varobj **varp, int explicit)
invoked. */
if (v->pretty_printer)
{
VEC (varobj_p) *changed = 0, *new = 0, *unchanged = 0;
VEC (varobj_p) *changed = 0, *type_changed = 0, *unchanged = 0;
VEC (varobj_p) *new = 0;
int i, children_changed = 0;
if (v->frozen)
@ -2037,7 +2096,7 @@ varobj_update (struct varobj **varp, int explicit)
it. */
if (!varobj_has_more (v, 0))
{
update_dynamic_varobj_children (v, NULL, NULL, NULL,
update_dynamic_varobj_children (v, NULL, NULL, NULL, NULL,
&dummy, 0, 0, 0);
if (varobj_has_more (v, 0))
r.changed = 1;
@ -2051,8 +2110,8 @@ varobj_update (struct varobj **varp, int explicit)
/* If update_dynamic_varobj_children returns 0, then we have
a non-conforming pretty-printer, so we skip it. */
if (update_dynamic_varobj_children (v, &changed, &new, &unchanged,
&children_changed, 1,
if (update_dynamic_varobj_children (v, &changed, &type_changed, &new,
&unchanged, &children_changed, 1,
v->from, v->to))
{
if (children_changed || new)
@ -2064,6 +2123,18 @@ varobj_update (struct varobj **varp, int explicit)
popped from the work stack first, and so will be
added to result first. This does not affect
correctness, just "nicer". */
for (i = VEC_length (varobj_p, type_changed) - 1; i >= 0; --i)
{
varobj_p tmp = VEC_index (varobj_p, type_changed, i);
varobj_update_result r = {0};
/* Type may change only if value was changed. */
r.varobj = tmp;
r.changed = 1;
r.type_changed = 1;
r.value_installed = 1;
VEC_safe_push (varobj_update_result, stack, &r);
}
for (i = VEC_length (varobj_p, changed) - 1; i >= 0; --i)
{
varobj_p tmp = VEC_index (varobj_p, changed, i);
@ -2090,9 +2161,10 @@ varobj_update (struct varobj **varp, int explicit)
if (r.changed || r.children_changed)
VEC_safe_push (varobj_update_result, result, &r);
/* Free CHANGED and UNCHANGED, but not NEW, because NEW
has been put into the result vector. */
/* Free CHANGED, TYPE_CHANGED and UNCHANGED, but not NEW,
because NEW has been put into the result vector. */
VEC_free (varobj_p, changed);
VEC_free (varobj_p, type_changed);
VEC_free (varobj_p, unchanged);
continue;
@ -2367,7 +2439,7 @@ create_child_with_value (struct varobj *parent, int index, const char *name,
if (value != NULL)
/* If the child had no evaluation errors, var->value
will be non-NULL and contain a valid type. */
child->type = value_type (value);
child->type = value_actual_type (value, 0, NULL);
else
/* Otherwise, we must compute the type. */
child->type = (*child->root->lang->type_of_child) (child->parent,
@ -2948,6 +3020,10 @@ varobj_floating_p (struct varobj *var)
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
@ -2959,7 +3035,8 @@ varobj_floating_p (struct varobj *var)
static void
adjust_value_for_child_access (struct value **value,
struct type **type,
int *was_ptr)
int *was_ptr,
int lookup_actual_type)
{
gdb_assert (type && *type);
@ -3004,6 +3081,20 @@ adjust_value_for_child_access (struct value **value,
/* 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);
}
}
}
/* Implement the "value_is_changeable_p" varobj callback for most
@ -3044,7 +3135,7 @@ c_number_of_children (struct varobj *var)
int children = 0;
struct type *target;
adjust_value_for_child_access (NULL, &type, NULL);
adjust_value_for_child_access (NULL, &type, NULL, 0);
target = get_target_type (type);
switch (TYPE_CODE (type))
@ -3160,7 +3251,7 @@ c_describe_child (struct varobj *parent, int index,
*cfull_expression = NULL;
parent_expression = varobj_get_path_expr (get_path_expr_parent (parent));
}
adjust_value_for_child_access (&value, &type, &was_ptr);
adjust_value_for_child_access (&value, &type, &was_ptr, 0);
switch (TYPE_CODE (type))
{
@ -3456,16 +3547,29 @@ c_value_of_variable (struct varobj *var, enum varobj_display_formats format)
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 = get_value_type (var);
adjust_value_for_child_access (NULL, &type, NULL);
/* 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);
if (((TYPE_CODE (type)) == TYPE_CODE_STRUCT) ||
((TYPE_CODE (type)) == TYPE_CODE_UNION))
@ -3492,7 +3596,17 @@ cplus_number_of_children (struct varobj *var)
int kids[3];
type = get_value_type (var->parent);
adjust_value_for_child_access (NULL, &type, NULL);
/* 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)
@ -3574,7 +3688,10 @@ cplus_describe_child (struct varobj *parent, int index,
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;
@ -3585,24 +3702,18 @@ cplus_describe_child (struct varobj *parent, int index,
if (cfull_expression)
*cfull_expression = NULL;
if (CPLUS_FAKE_CHILD (parent))
{
value = parent->parent->value;
type = get_value_type (parent->parent);
if (cfull_expression)
parent_expression
= varobj_get_path_expr (get_path_expr_parent (parent->parent));
}
else
{
value = parent->value;
type = get_value_type (parent);
if (cfull_expression)
parent_expression
= varobj_get_path_expr (get_path_expr_parent (parent));
}
get_user_print_options (&opts);
adjust_value_for_child_access (&value, &type, &was_ptr);
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 = get_value_type (var);
if (cfull_expression)
parent_expression = varobj_get_path_expr (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)