diff options
author | Weimin Pan <weimin.pan@oracle.com> | 2018-10-08 21:16:59 +0000 |
---|---|---|
committer | Weimin Pan <weimin.pan@oracle.com> | 2018-10-08 21:23:50 +0000 |
commit | 9f6b697b0efd4ba4e2cb21ac17d2b18a23f81abd (patch) | |
tree | c9b6950d1f7a4e1618079b5f27b652523c795e19 /gdb/valops.c | |
parent | 780f601cf3bfd2eb141c2ea32b673b5bd0956a33 (diff) | |
download | gdb-9f6b697b0efd4ba4e2cb21ac17d2b18a23f81abd.zip gdb-9f6b697b0efd4ba4e2cb21ac17d2b18a23f81abd.tar.gz gdb-9f6b697b0efd4ba4e2cb21ac17d2b18a23f81abd.tar.bz2 |
Finding data member in virtual base class
This patch fixes the original problem - printing member in a virtual base,
using various expressions, do not yield the same value. Simple test case
below demonstrates the problem:
% cat t.cc
struct base { int i; };
typedef base tbase;
struct derived: virtual tbase { void func() { } };
int main() { derived().func(); }
% g++ -g t.cc
% gdb a.out
(gdb) break derived::func
(gdb) run
(gdb) p i
$1 = 0
(gdb) p base::i
$3 = 0
(gdb) p derived::i
$4 = 4196392
To fix the problem, add function get_baseclass_offset() which searches
recursively for the base class along the class hierarchy. If the base
is virtual, it uses "vptr" in virtual class object, which indexes to
its derived class's vtable, to get and returns the baseclass offset.
If the base is non-virtual, it returns the accumulated offset of its
parent classes. The offset is then added to the address of the class
object to access its member in value_struct_elt_for_reference().
Diffstat (limited to 'gdb/valops.c')
-rw-r--r-- | gdb/valops.c | 63 |
1 files changed, 62 insertions, 1 deletions
diff --git a/gdb/valops.c b/gdb/valops.c index e6e11a6..99b1275 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -3321,6 +3321,49 @@ compare_parameters (struct type *t1, struct type *t2, int skip_artificial) return 0; } +/* C++: Given an aggregate type VT, and a class type CLS, search + recursively for CLS using value V; If found, store the offset + which is either fetched from the virtual base pointer if CLS + is virtual or accumulated offset of its parent classes if + CLS is non-virtual in *BOFFS, set ISVIRT to indicate if CLS + is virtual, and return true. If not found, return false. */ + +static bool +get_baseclass_offset (struct type *vt, struct type *cls, + struct value *v, int *boffs, bool *isvirt) +{ + for (int i = 0; i < TYPE_N_BASECLASSES (vt); i++) + { + struct type *t = TYPE_FIELD_TYPE (vt, i); + if (types_equal (t, cls)) + { + if (BASETYPE_VIA_VIRTUAL (vt, i)) + { + const gdb_byte *adr = value_contents_for_printing (v); + *boffs = baseclass_offset (vt, i, adr, value_offset (v), + value_as_long (v), v); + *isvirt = true; + } + else + *isvirt = false; + return true; + } + + if (get_baseclass_offset (check_typedef (t), cls, v, boffs, isvirt)) + { + if (*isvirt == false) /* Add non-virtual base offset. */ + { + const gdb_byte *adr = value_contents_for_printing (v); + *boffs += baseclass_offset (vt, i, adr, value_offset (v), + value_as_long (v), v); + } + return true; + } + } + + return false; +} + /* C++: Given an aggregate type CURTYPE, and a member name NAME, return the address of this member as a "pointer to member" type. If INTYPE is non-null, then it will be the type of the member we @@ -3374,7 +3417,7 @@ value_struct_elt_for_reference (struct type *domain, int offset, struct value *v = value_of_this_silent (current_language); if (v != NULL) { - struct value *ptr; + struct value *ptr, *this_v = v; long mem_offset; struct type *type, *tmp; @@ -3385,6 +3428,24 @@ value_struct_elt_for_reference (struct type *domain, int offset, tmp = lookup_pointer_type (TYPE_SELF_TYPE (type)); v = value_cast_pointers (tmp, v, 1); mem_offset = value_as_long (ptr); + if (domain != curtype) + { + /* Find class offset of type CURTYPE from either its + parent type DOMAIN or the type of implied this. */ + int boff = 0; + bool isvirt = false; + if (get_baseclass_offset (domain, curtype, v, &boff, + &isvirt)) + mem_offset += boff; + else + { + struct type *t = check_typedef (value_type (this_v)); + t = check_typedef (TYPE_TARGET_TYPE (t)); + if (get_baseclass_offset (t, curtype, this_v, + &boff, &isvirt)) + mem_offset += boff; + } + } tmp = lookup_pointer_type (TYPE_TARGET_TYPE (type)); result = value_from_pointer (tmp, value_as_long (v) + mem_offset); |