Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Yao Qi <qiyaoltc@gmail.com>
To: gdb-patches@sourceware.org
Subject: [PATCH 1/3] [AArch64 Linux] Get rid of top byte from tagged address on memory access
Date: Thu, 26 Oct 2017 08:30:00 -0000	[thread overview]
Message-ID: <1509006590-9401-2-git-send-email-yao.qi@linaro.org> (raw)
In-Reply-To: <1509006590-9401-1-git-send-email-yao.qi@linaro.org>

ARMv8 supports tagged address, that is, the top one byte in address
is ignored.  It is always enabled on aarch64-linux.  See
https://www.kernel.org/doc/Documentation/arm64/tagged-pointers.txt

The patch clear the top byte of the virtual address, at the point before
GDB/GDBserver pass the address to /proc or ptrace syscall on memory access.
The top byte of address is  still retained in the rest of GDB, because
these bits can be used by different applications in different ways.
That is reason I didn't implement gdbarch method addr_bits_remove to get
rid of them.

Before this patch,
(gdb) x/x 0x0000000000411030
0x411030 <global>:	0x00000000
(gdb) x/x 0xf000000000411030
0xf000000000411030:	Cannot access memory at address 0xf000000000411030

After this patch,

(gdb) x/x 0x0000000000411030
0x411030 <global>:	0x00000000
(gdb) x/x 0xf000000000411030
0xf000000000411030:	0x00000000

With the tagged address, the variables/memory can be access via different
addresses (or tags), but GDB uses cache for stack variable access and code
access to speed up remote debugging.  Fortunately, tagged address and
GDB stack/code cache can coexist, because,

 - 'x' command doesn't go through cache, so we don't have to worry,
 - gdb only uses stack cache when it believes the variable is on stack,

   int i;
   int *p = &i;

   when print 'i' or 'p', gdb uses stack caches, but when print '*p', gdb
   only uses stack caches to get 'p', and get '*p' without cache, because
   gdb doesn't know the address p points to is on stack or not.
 - gdb uses code caches to access code, do disassembly for example, when
   gdb does disassembly for a function (without tag) and a tagged function
   pointer, gdb creates thinks they are different addresses, and creates
   two different cache lines, but we only have cache when inferior stops,
   and code caches are regarded read-only.

gdb:

2017-10-19  Yao Qi  <yao.qi@linaro.org>

	* aarch64-linux-nat.c (super_xfer_partial): New function pointer.
	(aarch64_linux_xfer_partial): New function.
	(_initialize_aarch64_linux_nat): Initialize super_xfer_partial,
	and update to_xfer_partial.

gdb/gdbserver:

2017-10-19  Yao Qi  <yao.qi@linaro.org>

	* linux-aarch64-low.c (super_read_memory): New function pointer.
	(super_write_memory): Likewise.
	(aarch64_linux_read_memory): New function.
	(aarch64_linux_write_memory): New function.
	(initialize_low_arch): Initialize super_read_memory and
	super_write_memory.  Update read_memory and write_memory.

2017-10-19  Yao Qi  <yao.qi@linaro.org>

gdb/testsuite:

	* gdb.arch/aarch64-tagged-pointer.c: New file.
	* gdb.arch/aarch64-tagged-pointer.exp: New file.
---
 gdb/aarch64-linux-nat.c                           | 25 +++++++++
 gdb/gdbserver/linux-aarch64-low.c                 | 33 +++++++++++
 gdb/testsuite/gdb.arch/aarch64-tagged-pointer.c   | 48 ++++++++++++++++
 gdb/testsuite/gdb.arch/aarch64-tagged-pointer.exp | 68 +++++++++++++++++++++++
 4 files changed, 174 insertions(+)
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-tagged-pointer.c
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-tagged-pointer.exp

diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index de18edd..78c038b 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -780,6 +780,27 @@ aarch64_linux_can_do_single_step (struct target_ops *target)
   return 1;
 }
 
+static target_xfer_partial_ftype *super_xfer_partial;
+
+/* Implement the "to_xfer_partial" target_ops method.  */
+
+static enum target_xfer_status
+aarch64_linux_xfer_partial (struct target_ops *ops, enum target_object object,
+			    const char *annex, gdb_byte *readbuf,
+			    const gdb_byte *writebuf, ULONGEST offset,
+			    ULONGEST len, ULONGEST *xfered_len)
+{
+  if (object == TARGET_OBJECT_MEMORY)
+    {
+      /* ARMv8 supports tagged address, that is, the top one byte in
+	 virtual address is ignored.  */
+      offset &= 0x0fffffffffffffffULL;
+    }
+
+  return super_xfer_partial (ops, object, annex, readbuf, writebuf,
+			     offset, len, xfered_len);
+}
+
 /* Define AArch64 maintenance commands.  */
 
 static void
@@ -834,6 +855,10 @@ _initialize_aarch64_linux_nat (void)
   super_post_startup_inferior = t->to_post_startup_inferior;
   t->to_post_startup_inferior = aarch64_linux_child_post_startup_inferior;
 
+  /* Override the default to_xfer_partial.  */
+  super_xfer_partial = t->to_xfer_partial;
+  t->to_xfer_partial = aarch64_linux_xfer_partial;
+
   /* Register the target.  */
   linux_nat_add_target (t);
   linux_nat_set_new_thread (t, aarch64_linux_new_thread);
diff --git a/gdb/gdbserver/linux-aarch64-low.c b/gdb/gdbserver/linux-aarch64-low.c
index b00d5c5..bc44092 100644
--- a/gdb/gdbserver/linux-aarch64-low.c
+++ b/gdb/gdbserver/linux-aarch64-low.c
@@ -3004,6 +3004,31 @@ struct linux_target_ops the_low_target =
   aarch64_get_syscall_trapinfo,
 };
 
+static int (*super_read_memory) (CORE_ADDR memaddr, unsigned char *myaddr,
+				 int len);
+
+static  int (*super_write_memory) (CORE_ADDR memaddr,
+				   const unsigned char *myaddr, int len);
+
+static int
+aarch64_linux_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
+{
+  /* ARMv8 supports tagged address, that is, the top one byte in
+     virtual address is ignored.  */
+  memaddr &= 0x0fffffffffffffffULL;
+  return super_read_memory (memaddr, myaddr, len);
+}
+
+static int
+aarch64_linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr,
+			    int len)
+{
+  /* ARMv8 supports tagged address, that is, the top one byte in
+     virtual address is ignored.  */
+  memaddr &= 0x0fffffffffffffffULL;
+  return super_write_memory (memaddr, myaddr, len);
+}
+
 void
 initialize_low_arch (void)
 {
@@ -3012,4 +3037,12 @@ initialize_low_arch (void)
   initialize_low_arch_aarch32 ();
 
   initialize_regsets_info (&aarch64_regsets_info);
+
+  /* Override the default read_memory.  */
+  super_read_memory = the_target->read_memory;
+  the_target->read_memory = aarch64_linux_read_memory;
+
+  /* Override the default write_memory.  */
+  super_write_memory = the_target->write_memory;
+  the_target->write_memory = aarch64_linux_write_memory;
 }
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..4d36d09
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-tagged-pointer.exp
@@ -0,0 +1,68 @@
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# 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.*"
-- 
1.9.1


  parent reply	other threads:[~2017-10-26  8:30 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-10-26  8:29 [PATCH 0/3 v2] [AArch64] Support tagged pointer Yao Qi
2017-10-26  8:30 ` [PATCH 2/3] [AArch64] Adjust breakpoint on tagged address Yao Qi
2017-10-26  8:30 ` [PATCH 3/3] [AArch64] Remove tag from address for watchpoint Yao Qi
2017-11-09 20:30   ` Pedro Alves
2017-11-09 21:08     ` Simon Marchi
2017-11-09 21:20       ` Yao Qi
2017-11-09 21:09     ` Yao Qi
2017-11-09 22:25       ` Pedro Alves
2017-10-26  8:30 ` Yao Qi [this message]
2017-11-09 20:24   ` [PATCH 1/3] [AArch64 Linux] Get rid of top byte from tagged address on memory access Pedro Alves

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1509006590-9401-2-git-send-email-yao.qi@linaro.org \
    --to=qiyaoltc@gmail.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox