public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] Resolve dynamic types before computing pointer size
@ 2021-09-16 16:42 Keith Seitz
  2021-10-19 16:21 ` Tom Tromey
  0 siblings, 1 reply; 7+ messages in thread
From: Keith Seitz @ 2021-09-16 16:42 UTC (permalink / raw)
  To: gdb-patches

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 <http://www.gnu.org/licenses/>.  */
+
+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 <http://www.gnu.org/licenses/>.
+
+# 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


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2022-02-24 19:52 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-16 16:42 [PATCH] Resolve dynamic types before computing pointer size Keith Seitz
2021-10-19 16:21 ` Tom Tromey
2021-10-20 19:29   ` Keith Seitz
2021-10-20 21:42     ` Tom Tromey
2021-10-21 18:19       ` Tom Tromey
2021-11-11 18:21         ` Keith Seitz
2022-02-24 19:51           ` Keith Seitz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).