From patchwork Thu Aug 23 23:43:55 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Weimin Pan X-Patchwork-Id: 29034 Received: (qmail 69521 invoked by alias); 24 Aug 2018 00:21:10 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 69505 invoked by uid 89); 24 Aug 2018 00:21:09 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_HELO_PASS, UNPARSEABLE_RELAY autolearn=ham version=3.3.2 spammy=150, sk:standar, D*oracle.com X-HELO: userp2130.oracle.com Received: from userp2130.oracle.com (HELO userp2130.oracle.com) (156.151.31.86) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 24 Aug 2018 00:21:07 +0000 Received: from pps.filterd (userp2130.oracle.com [127.0.0.1]) by userp2130.oracle.com (8.16.0.22/8.16.0.22) with SMTP id w7O0IwqP090877 for ; Fri, 24 Aug 2018 00:21:06 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : subject : date : message-id; s=corp-2018-07-02; bh=0wOOVe8IEB72smlJwzi7Xpx1mSSOQSlg5nUKzQpsevM=; b=z15U86S28/f29W7KuppRot9MrDgBUnnNcu8EAeYOj7h5hZIfU0+cVfQ6tXBDnJ6fdP2s 96nDIZrzxeWJx0q5KnEYyFif5cypD5l8Hc9Gmixb0FkuREOc3JNM7+pCf/7dSizUJRr9 Cmr0WHNrObYVmiHJanoOx6D2t3/BQidsMjTKcsUTe57cRTOawviJ4S/xiejLiJ+Q7OJd 9XqatIEtvQOgPh+yIz04xDizqebLzCTCdfgKv+p/cZl7nFMgsd9a933tZ7+6Yb0PW78Y r5T6oaTTPE4ttCbAcuauA59uPmAMD2fyQ3y92uOidvNIRH3kE8iaBcO9UIyc4E/OLD1C yw== Received: from aserv0022.oracle.com (aserv0022.oracle.com [141.146.126.234]) by userp2130.oracle.com with ESMTP id 2kxavu4chd-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Fri, 24 Aug 2018 00:21:06 +0000 Received: from aserv0122.oracle.com (aserv0122.oracle.com [141.146.126.236]) by aserv0022.oracle.com (8.14.4/8.14.4) with ESMTP id w7O0L4XK020571 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Fri, 24 Aug 2018 00:21:05 GMT Received: from abhmp0008.oracle.com (abhmp0008.oracle.com [141.146.116.14]) by aserv0122.oracle.com (8.14.4/8.14.4) with ESMTP id w7O0L4dO023862 for ; Fri, 24 Aug 2018 00:21:04 GMT Received: from wmpan.us.oracle.com (/10.147.27.127) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Thu, 23 Aug 2018 17:21:04 -0700 From: Weimin Pan To: gdb-patches@sourceware.org Subject: [PATCH v2 PR gdb/16841] virtual inheritance via typedef cannot find base Date: Thu, 23 Aug 2018 18:43:55 -0500 Message-Id: <1535067835-60808-1-git-send-email-weimin.pan@oracle.com> 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. A 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 $2 = 0 (gdb) p derived::base::i $3 = 0 (gdb) p derived::i $4 = 4196392 To fix the problem, we need to use "vptr" in the virtual class object, which indexes to its derived class's vtable, to fetch the virtual base offset. The offset is then added to the virtual class object to access its member in value_struct_elt_for_reference(). The new function add_virtual_base_offset searches recursively for the base class along the class hierarchy and returns the virtual base offset for the virtual class. Tested on amd64-linux-gnu. No regressions. --- gdb/ChangeLog | 7 +++++ gdb/testsuite/ChangeLog | 6 ++++ gdb/testsuite/gdb.cp/virtbase2.cc | 21 +++++++++++++++ gdb/testsuite/gdb.cp/virtbase2.exp | 50 ++++++++++++++++++++++++++++++++++++ gdb/valops.c | 38 +++++++++++++++++++++++++++ 5 files changed, 122 insertions(+), 0 deletions(-) create mode 100644 gdb/testsuite/gdb.cp/virtbase2.cc create mode 100644 gdb/testsuite/gdb.cp/virtbase2.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index c47c111..9d86f1c 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,10 @@ +2018-08-23 Weimin Pan + + PR gdb/16841 + * valops.c (add_virtual_base_offset): New function. + (value_struct_elt_for_reference): Use it to get virtual base offset + and add it in calculating class member address. + 2018-06-29 Pedro Alves * gdb/amd64-tdep.h (amd64_create_target_description): Add diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 93c849c..7be2e1d 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2018-08-23 Weimin Pan + + PR gdb/16841 + * gdb.cp/virtbase2.cc: New file. + * gdb.cp/virtbase2.exp: New file. + 2018-06-29 Pedro Alves * gdb.threads/names.exp: Adjust expected "info threads" output. diff --git a/gdb/testsuite/gdb.cp/virtbase2.cc b/gdb/testsuite/gdb.cp/virtbase2.cc new file mode 100644 index 0000000..4f7631e --- /dev/null +++ b/gdb/testsuite/gdb.cp/virtbase2.cc @@ -0,0 +1,21 @@ +struct base { + int i; double d; + base() : i(55), d(6.6) {} +}; +typedef base tbase; +struct derived: virtual tbase +{ + void func_d() { } +}; + +struct foo: virtual derived +{ + void func_f() { } +}; + +int main() +{ + derived().func_d(); + foo().func_f(); +} + diff --git a/gdb/testsuite/gdb.cp/virtbase2.exp b/gdb/testsuite/gdb.cp/virtbase2.exp new file mode 100644 index 0000000..c29ff1c --- /dev/null +++ b/gdb/testsuite/gdb.cp/virtbase2.exp @@ -0,0 +1,50 @@ +# Copyright 2018 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 . + +# Make sure printing virtual base class data member correctly (PR16841) + +if { [skip_cplus_tests] } { continue } + +standard_testfile .cc + +if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug c++}]} { + return -1 +} + +if {![runto_main]} then { + perror "couldn't run to main" + continue +} + +gdb_breakpoint "derived::func_d" +gdb_continue_to_breakpoint "continue to derived::func_d" +gdb_test "print i" " = 55" "i in base class" +gdb_test "print derived::i" " = 55" "i in base class" +gdb_test "print derived::base::i" " = 55" "i in base class" +gdb_test "print base::i" " = 55" "i in base class" +gdb_test "print d" " = 6.5999999999999996" "d in base class" +gdb_test "print derived::d" " = 6.5999999999999996" "d in base class" +gdb_test "print derived::base::d" " = 6.5999999999999996" "d in base class" +gdb_test "print base::d" " = 6.5999999999999996" "d in base class" +gdb_breakpoint "foo::func_f" +gdb_continue_to_breakpoint "continue to foo::func_f" +gdb_test "print i" " = 55" "i in base class" +gdb_test "print derived::i" " = 55" "i in base class" +gdb_test "print derived::base::i" " = 55" "i in base class" +gdb_test "print base::i" " = 55" "i in base class" +gdb_test "print d" " = 6.5999999999999996" "d in base class" +gdb_test "print derived::d" " = 6.5999999999999996" "d in base class" +gdb_test "print derived::base::d" " = 6.5999999999999996" "d in base class" +gdb_test "print base::d" " = 6.5999999999999996" "d in base class" diff --git a/gdb/valops.c b/gdb/valops.c index 9bdbf22..754e7d0 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -3329,6 +3329,35 @@ 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 and return its offset, + relative to VT, if it is a virtual base member. */ + +static int +add_virtual_base_offset (struct type *vt, struct type *cls, + struct value *v, int &boffs) +{ + for (int i = 0; i < TYPE_N_BASECLASSES (vt); i++) + { + struct type *ftype = TYPE_FIELD_TYPE (vt, i); + if (check_typedef (ftype) == 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); + } + return true; + } + + if (add_virtual_base_offset (ftype, cls, v, boffs)) + 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 @@ -3393,6 +3422,15 @@ 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) + { + struct value *v2 = value_of_this_silent (current_language); + struct type *vtype = check_typedef (value_type (v2)); + struct type *vt = check_typedef (TYPE_TARGET_TYPE (vtype)); + int base_offs = 0; + if (add_virtual_base_offset (vt, curtype, v, base_offs)) + mem_offset += base_offs; + } tmp = lookup_pointer_type (TYPE_TARGET_TYPE (type)); result = value_from_pointer (tmp, value_as_long (v) + mem_offset);