aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog10
-rw-r--r--gdb/aarch64-tdep.c5
-rw-r--r--gdb/gdbarch.c22
-rw-r--r--gdb/gdbarch.h8
-rwxr-xr-xgdb/gdbarch.sh6
-rw-r--r--gdb/target.c2
-rw-r--r--gdb/testsuite/ChangeLog5
-rw-r--r--gdb/testsuite/gdb.arch/aarch64-tagged-pointer.c48
-rw-r--r--gdb/testsuite/gdb.arch/aarch64-tagged-pointer.exp67
-rw-r--r--gdb/utils.c17
-rw-r--r--gdb/utils.h3
11 files changed, 193 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 21ddce0..952a2ff 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,13 @@
+2017-12-08 Yao Qi <yao.qi@linaro.org>
+
+ * aarch64-tdep.c (aarch64_gdbarch_init): Install gdbarch
+ significant_addr_bit.
+ * gdbarch.sh (significant_addr_bit): New.
+ * gdbarch.c, gdbarch.h: Re-generated.
+ * target.c (memory_xfer_partial): Call address_significant.
+ * utils.c (address_significant): New function.
+ * utils.h (address_significant): Declare.
+
2017-12-08 Tom Tromey <tom@tromey.com>
* printcmd.c (ui_printf): Update. Use std::vector.
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index 6a0d4b7..383d584 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -2970,6 +2970,11 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_tdesc_pseudo_register_reggroup_p (gdbarch,
aarch64_pseudo_register_reggroup_p);
+ /* The top byte of an address is known as the "tag" and is
+ ignored by the kernel, the hardware, etc. and can be regarded
+ as additional data associated with the address. */
+ set_gdbarch_significant_addr_bit (gdbarch, 56);
+
/* ABI */
set_gdbarch_short_bit (gdbarch, 16);
set_gdbarch_int_bit (gdbarch, 32);
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 007392c..8177f05 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -259,6 +259,7 @@ struct gdbarch
int frame_red_zone_size;
gdbarch_convert_from_func_ptr_addr_ftype *convert_from_func_ptr_addr;
gdbarch_addr_bits_remove_ftype *addr_bits_remove;
+ int significant_addr_bit;
gdbarch_software_single_step_ftype *software_single_step;
gdbarch_single_step_through_delay_ftype *single_step_through_delay;
gdbarch_print_insn_ftype *print_insn;
@@ -618,6 +619,8 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of stabs_argument_has_addr, invalid_p == 0 */
/* Skip verify of convert_from_func_ptr_addr, invalid_p == 0 */
/* Skip verify of addr_bits_remove, invalid_p == 0 */
+ if (gdbarch->significant_addr_bit == 0)
+ gdbarch->significant_addr_bit = gdbarch_addr_bit (gdbarch);
/* Skip verify of software_single_step, has predicate. */
/* Skip verify of single_step_through_delay, has predicate. */
/* Skip verify of print_insn, invalid_p == 0 */
@@ -1325,6 +1328,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
"gdbarch_dump: short_bit = %s\n",
plongest (gdbarch->short_bit));
fprintf_unfiltered (file,
+ "gdbarch_dump: significant_addr_bit = %s\n",
+ plongest (gdbarch->significant_addr_bit));
+ fprintf_unfiltered (file,
"gdbarch_dump: gdbarch_single_step_through_delay_p() = %d\n",
gdbarch_single_step_through_delay_p (gdbarch));
fprintf_unfiltered (file,
@@ -3216,6 +3222,22 @@ set_gdbarch_addr_bits_remove (struct gdbarch *gdbarch,
}
int
+gdbarch_significant_addr_bit (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_significant_addr_bit called\n");
+ return gdbarch->significant_addr_bit;
+}
+
+void
+set_gdbarch_significant_addr_bit (struct gdbarch *gdbarch,
+ int significant_addr_bit)
+{
+ gdbarch->significant_addr_bit = significant_addr_bit;
+}
+
+int
gdbarch_software_single_step_p (struct gdbarch *gdbarch)
{
gdb_assert (gdbarch != NULL);
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index d2e6b6f..1a654b6 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -677,6 +677,14 @@ typedef CORE_ADDR (gdbarch_addr_bits_remove_ftype) (struct gdbarch *gdbarch, COR
extern CORE_ADDR gdbarch_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR addr);
extern void set_gdbarch_addr_bits_remove (struct gdbarch *gdbarch, gdbarch_addr_bits_remove_ftype *addr_bits_remove);
+/* On some machines, not all bits of an address word are significant.
+ For example, on AArch64, the top bits of an address known as the "tag"
+ are ignored by the kernel, the hardware, etc. and can be regarded as
+ additional data associated with the address. */
+
+extern int gdbarch_significant_addr_bit (struct gdbarch *gdbarch);
+extern void set_gdbarch_significant_addr_bit (struct gdbarch *gdbarch, int significant_addr_bit);
+
/* FIXME/cagney/2001-01-18: This should be split in two. A target method that
indicates if the target needs software single step. An ISA method to
implement it.
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 6459b12..1f165cf 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -621,6 +621,12 @@ m;CORE_ADDR;convert_from_func_ptr_addr;CORE_ADDR addr, struct target_ops *targ;a
# possible it should be in TARGET_READ_PC instead).
m;CORE_ADDR;addr_bits_remove;CORE_ADDR addr;addr;;core_addr_identity;;0
+# On some machines, not all bits of an address word are significant.
+# For example, on AArch64, the top bits of an address known as the "tag"
+# are ignored by the kernel, the hardware, etc. and can be regarded as
+# additional data associated with the address.
+v;int;significant_addr_bit;;;;;gdbarch_addr_bit (gdbarch);
+
# FIXME/cagney/2001-01-18: This should be split in two. A target method that
# indicates if the target needs software single step. An ISA method to
# implement it.
diff --git a/gdb/target.c b/gdb/target.c
index 3b8b8ea..767a2ad 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -1214,6 +1214,8 @@ memory_xfer_partial (struct target_ops *ops, enum target_object object,
if (len == 0)
return TARGET_XFER_EOF;
+ memaddr = address_significant (target_gdbarch (), memaddr);
+
/* Fill in READBUF with breakpoint shadows, or WRITEBUF with
breakpoint insns, thus hiding out from higher layers whether
there are software breakpoints inserted in the code stream. */
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 720a9ec..cc834de 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2017-12-08 Yao Qi <yao.qi@linaro.org>
+
+ * gdb.arch/aarch64-tagged-pointer.c: New file.
+ * gdb.arch/aarch64-tagged-pointer.exp: New file.
+
2017-12-08 Sergio Durigan Junior <sergiodj@redhat.com>
* gdb.arch/i386-sse-stack-align.exp: Cast "print" function call
diff --git a/gdb/testsuite/gdb.arch/aarch64-tagged-pointer.c b/gdb/testsuite/gdb.arch/aarch64-tagged-pointer.c
new file mode 100644
index 0000000..7c90132
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-tagged-pointer.c
@@ -0,0 +1,48 @@
+/* This file is part of GDB, the GNU debugger.
+
+ Copyright 2017 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/>. */
+
+#include <stdint.h>
+
+struct s
+{
+ int i;
+};
+
+static void
+foo (void)
+{
+}
+
+int
+main (void)
+{
+ struct s s1;
+ struct s *sp1, *sp2;
+ int i = 1234;
+ int *p1, *p2;
+
+ s1.i = 1234;
+ sp1 = &s1;
+ p1 = &i;
+ /* SP1 and SP2 have different tags, but point to the same address. */
+ sp2 = (struct s *) ((uintptr_t) sp1 | 0xf000000000000000ULL);
+ p2 = (int *) ((uintptr_t) p1 | 0xf000000000000000ULL);
+
+ void (*func_ptr) (void) = foo;
+ func_ptr = (void (*) (void)) ((uintptr_t) func_ptr | 0xf000000000000000ULL);
+ sp2->i = 4321; /* breakpoint here. */
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-tagged-pointer.exp b/gdb/testsuite/gdb.arch/aarch64-tagged-pointer.exp
new file mode 100644
index 0000000..4f2b44c
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-tagged-pointer.exp
@@ -0,0 +1,67 @@
+# Copyright 2017 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/>.
+#
+# This file is part of the gdb testsuite.
+
+if {![is_aarch64_target]} {
+ verbose "Skipping ${gdb_test_file_name}."
+ return
+}
+
+standard_testfile
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
+ return -1
+}
+
+if ![runto_main] {
+ untested "could not run to main"
+ return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "breakpoint here"]
+gdb_continue_to_breakpoint "breakpoint here"
+
+# Test that GDB manages caches correctly for tagged address.
+# Read from P2,
+gdb_test "x p2" "$hex:\[\t \]+0x000004d2"
+gdb_test_no_output "set variable i = 5678"
+# Test that *P2 is updated.
+gdb_test "x p2" "$hex:\[\t \]+0x0000162e"
+
+# Read from SP1->i,
+gdb_test "print sp1->i" " = 1234"
+# Write to SP2->i,
+gdb_test_no_output "set variable sp2->i = 5678"
+# Test that SP1->i is updated.
+gdb_test "print sp1->i" " = 5678"
+
+gdb_test "x/d &sp2->i" "$hex:\[\t \]+5678"
+gdb_test "x/d &sp1->i" "$hex:\[\t \]+5678"
+
+# Test that the same disassembly is got when disassembling function vs
+# tagged function pointer.
+set insn1 ""
+set insn2 ""
+set test "disassemble foo,+8"
+gdb_test_multiple $test $test {
+ -re ":\[\t \]+(\[a-z\]*)\[ \r\n\]+.*:\[\t \]+(\[a-z\]*).*$gdb_prompt $" {
+ set insn1 $expect_out(1,string)
+ set insn2 $expect_out(2,string)
+ pass $test
+ }
+}
+
+gdb_test "disassemble func_ptr,+8" \
+ ":\[\t \]+$insn1\[ \r\n\]+.*:\[\t \]+$insn2.*"
diff --git a/gdb/utils.c b/gdb/utils.c
index b95dcfd..2f8f06f 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -2724,6 +2724,23 @@ When set, debugging messages will be marked with seconds and microseconds."),
&setdebuglist, &showdebuglist);
}
+/* See utils.h. */
+
+CORE_ADDR
+address_significant (gdbarch *gdbarch, CORE_ADDR addr)
+{
+ /* Truncate address to the significant bits of a target address,
+ avoiding shifts larger or equal than the width of a CORE_ADDR.
+ The local variable ADDR_BIT stops the compiler reporting a shift
+ overflow when it won't occur. */
+ int addr_bit = gdbarch_significant_addr_bit (gdbarch);
+
+ if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
+ addr &= ((CORE_ADDR) 1 << addr_bit) - 1;
+
+ return addr;
+}
+
const char *
paddress (struct gdbarch *gdbarch, CORE_ADDR addr)
{
diff --git a/gdb/utils.h b/gdb/utils.h
index 349ab93..b2e3d57 100644
--- a/gdb/utils.h
+++ b/gdb/utils.h
@@ -438,6 +438,9 @@ extern void gdb_print_host_address_1 (const void *addr, struct ui_file *stream);
#define gdb_print_host_address(ADDR, STREAM) \
gdb_print_host_address_1 ((const void *) ADDR, STREAM)
+/* Return the address only having significant bits. */
+extern CORE_ADDR address_significant (gdbarch *gdbarch, CORE_ADDR addr);
+
/* Convert CORE_ADDR to string in platform-specific manner.
This is usually formatted similar to 0x%lx. */
extern const char *paddress (struct gdbarch *gdbarch, CORE_ADDR addr);