[PATCH] [AArch64 Linux] Get rid of top byte from tagged address

Yao Qi
2017-10-19T08:08:57Z

ARMv8 supports tagged address, that is, the top one byte in address
is ignored. It is always enabled on aarch64-linux. The patch clear
the top byte of the virtual address, at the point before GDB/GDBserver
pass the address to /proc or ptrace syscall. 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

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.
---
gdb/aarch64-linux-nat.c | 25 +++++++++++++++++++++++++
gdb/gdbserver/linux-aarch64-low.c | 33 +++++++++++++++++++++++++++++++++
2 files changed, 58 insertions(+)

diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index 4feaec3..3c6fe2c 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 = 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 6d5c4e5..a78f023 100644
--- a/gdb/gdbserver/linux-aarch64-low.c
+++ b/gdb/gdbserver/linux-aarch64-low.c
@@ -3015,6 +3015,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 = 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 = memaddr & 0x0fffffffffffffffULL;
+ return super_write_memory (memaddr, myaddr, len);
+}
+
void
initialize_low_arch (void)
{
@@ -3023,4 +3048,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;
}
--
1.9.1