diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index c2c2c30..b6c2a81 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -1217,6 +1217,8 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   set_xml_syscall_file_name (gdbarch, "syscalls/aarch64-linux.xml");
   set_gdbarch_get_syscall_number (gdbarch, aarch64_linux_get_syscall_number);
 
+  set_gdbarch_significant_addr_bit (gdbarch, 56);
+
   /* Displaced stepping.  */
   set_gdbarch_max_insn_length (gdbarch, 4 * DISPLACED_MODIFIED_INSNS);
   set_gdbarch_displaced_step_copy_insn (gdbarch,
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/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);
