From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by sourceware.org (Postfix) with ESMTP id D550D3858D3C for ; Thu, 16 Sep 2021 16:42:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org D550D3858D3C Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-415-i4DyIdydPtSDbNvkUNVKHA-1; Thu, 16 Sep 2021 12:42:49 -0400 X-MC-Unique: i4DyIdydPtSDbNvkUNVKHA-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 0D014800FF4 for ; Thu, 16 Sep 2021 16:42:49 +0000 (UTC) Received: from guittard.redhat.com (ovpn-114-222.phx2.redhat.com [10.3.114.222]) by smtp.corp.redhat.com (Postfix) with ESMTP id D968969FC8 for ; Thu, 16 Sep 2021 16:42:48 +0000 (UTC) From: Keith Seitz To: gdb-patches@sourceware.org Subject: [PATCH] Resolve dynamic types before computing pointer size Date: Thu, 16 Sep 2021 09:42:48 -0700 Message-Id: <20210916164248.2065236-1-keiths@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset="US-ASCII" X-Spam-Status: No, score=-13.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 16 Sep 2021 16:42:53 -0000 Consider the following code: int get(int n, int m, int arr[n][m], int x, int y) { arr[x][y] += 100; return arr[x][y]; } If we break in this function and attempt to print arr[x][y], we get an error: "Cannot perform pointer math on incomplete types, try casting to a known type, or void *." The DWARF information for this contains the array bounds, bound to a local variable: <1><1aa>: Abbrev Number: 3 (DW_TAG_array_type) <1ab> DW_AT_type : <0x6d> <1af> DW_AT_sibling : <0x1bd> <2><1b3>: Abbrev Number: 4 (DW_TAG_subrange_type) <1b4> DW_AT_type : <0x8a> <1b8> DW_AT_upper_bound : 3 byte block: 91 68 6 (DW_OP_fbreg: -24; DW_OP_deref) In value_ptradd, where we attempt to do the pointer math, we completely ignore the fact that the pointer's target type is an unresolved dynamic type. This patch addresses this by changing the API for find_size_for_pointer so that it takes the actual struct value of the pointer variable, resolves the pointer's target type if it is dynamic, and returns a size based on this resolved type. As a consequence of this dynamic type resolution, we must now also pass this new resolved type to the caller via an out parameter. --- gdb/testsuite/gdb.base/vla-multi-array.c | 58 ++++++++++++++++++++++ gdb/testsuite/gdb.base/vla-multi-array.exp | 53 ++++++++++++++++++++ gdb/valarith.c | 18 +++++-- 3 files changed, 125 insertions(+), 4 deletions(-) create mode 100644 gdb/testsuite/gdb.base/vla-multi-array.c create mode 100644 gdb/testsuite/gdb.base/vla-multi-array.exp diff --git a/gdb/testsuite/gdb.base/vla-multi-array.c b/gdb/testsuite/gdb.base/vla-multi-array.c new file mode 100644 index 00000000000..c4ee223a6f1 --- /dev/null +++ b/gdb/testsuite/gdb.base/vla-multi-array.c @@ -0,0 +1,58 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2021 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 . */ + +int +get2 (int n, int m, int arr[n][m], int x, int y) +{ + return arr[x][y]; /* break-here 2 */ +} + +int +get3 (int n, int m, int o, int arr[n][m][o], int x, int y, int z) +{ + return arr[x][y][z]; /* break-here 3 */ +} + +int +main (void) +{ + int array2[3][4]; + int array3[2][2][2]; + + array2[0][0] = 0; + array2[0][1] = 1; + array2[0][2] = 2; + array2[0][3] = 3; + array2[1][0] = 10; + array2[1][1] = 11; + array2[1][2] = 12; + array2[1][3] = 13; + array2[2][0] = 20; + array2[2][1] = 21; + array2[2][2] = 22; + array2[2][3] = 23; + array3[0][0][0] = 0; + array3[0][0][1] = 1; + array3[0][1][0] = 10; + array3[0][1][1] = 11; + array3[1][0][0] = 100; + array3[1][0][1] = 101; + array3[1][1][0] = 110; + array3[1][1][1] = 111; + + return get2 (3, 4, array2, 0, 0) + get3 (2, 2, 2, array3, 1, 1, 1); +} diff --git a/gdb/testsuite/gdb.base/vla-multi-array.exp b/gdb/testsuite/gdb.base/vla-multi-array.exp new file mode 100644 index 00000000000..c93cf013055 --- /dev/null +++ b/gdb/testsuite/gdb.base/vla-multi-array.exp @@ -0,0 +1,53 @@ +# Copyright 2021 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 . + +# Test multi-dimensional VLA arrays. + +standard_testfile + +if {[prepare_for_testing "failed to prepare" $testfile $srcfile debug]} { + return +} + +if {![runto_main]} { + untested "couldn't run to main" + return +} + +# A note on column values. It would be easiest to use "expr ${i}${j}${k}", +# but when I is 0, Tcl interprets this as octal input. Tcl < 8.7 does not +# support a decimal prefix (0d), so work around this by using regsub. + +# Check all values of array2. +gdb_breakpoint [gdb_get_line_number "break-here 2"] +gdb_continue_to_breakpoint "break-here 2" +for {set i 0} {$i < 3} {incr i} { + for {set j 0} {$j < 4} {incr j} { + set pattern [regsub "^(0)" "${i}${j}" ""] + gdb_test "p arr\[$i\]\[$j\]" "= $pattern" + } +} + +# Check all values of array3. +gdb_breakpoint [gdb_get_line_number "break-here 3"] +gdb_continue_to_breakpoint "break-here 3" +for {set i 0} {$i < 2} {incr i} { + for {set j 0} {$j < 2} {incr j} { + for {set k 0} {$k < 2} {incr k} { + set pattern [regsub "^(0|00)" "${i}${j}${k}" ""] + gdb_test "p arr\[$i\]\[$j\]\[$k\]" "= $pattern" + } + } +} diff --git a/gdb/valarith.c b/gdb/valarith.c index 9ebad648b27..b7f4f3a71a6 100644 --- a/gdb/valarith.c +++ b/gdb/valarith.c @@ -36,21 +36,31 @@ #define TRUNCATION_TOWARDS_ZERO ((-5 / 2) == -2) #endif -/* Given a pointer, return the size of its target. +/* Given a pointer variable, return the size of its target. If the pointer type is void *, then return 1. If the target type is incomplete, then error out. + PTR_TYPE_OUT will contain the the actual pointer target type, + which may be a resolved dynamic type. This isn't a general purpose function, but just a helper for value_ptradd. */ static LONGEST -find_size_for_pointer_math (struct type *ptr_type) +find_size_for_pointer_math (struct value *ptr_var, struct type **ptr_type_out) { LONGEST sz = -1; struct type *ptr_target; + struct type *ptr_type = check_typedef (value_type (ptr_var)); gdb_assert (ptr_type->code () == TYPE_CODE_PTR); ptr_target = check_typedef (TYPE_TARGET_TYPE (ptr_type)); + if (is_dynamic_type (ptr_target)) + { + ptr_target + = resolve_dynamic_type (ptr_target, {}, value_address (ptr_var)); + ptr_type = make_pointer_type (ptr_target, nullptr); + } + sz = type_length_units (ptr_target); if (sz == 0) { @@ -69,6 +79,7 @@ find_size_for_pointer_math (struct type *ptr_type) "try casting to a known type, or void *."), name); } } + *ptr_type_out = ptr_type; return sz; } @@ -83,8 +94,7 @@ value_ptradd (struct value *arg1, LONGEST arg2) struct value *result; arg1 = coerce_array (arg1); - valptrtype = check_typedef (value_type (arg1)); - sz = find_size_for_pointer_math (valptrtype); + sz = find_size_for_pointer_math (arg1, &valptrtype); result = value_from_pointer (valptrtype, value_as_address (arg1) + sz * arg2); -- 2.31.1