This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 3/3] [AArch64] Remove tag from address for watchpoint


Nowadays, GDB can't set watchpoint on tagged address,

(gdb) p p2
$1 = (int *) 0xf000fffffffff474
(gdb) watch *((int *) 0xf000fffffffff474)
Hardware watchpoint 2: *((int *) 0xf000fffffffff474)
(gdb) c
Continuing.
main () at
binutils-gdb/gdb/testsuite/gdb.arch/aarch64-tagged-pointer.c:45
45	  void (*func_ptr) (void) = foo;
Unexpected error setting hardware debug registers

This patch is about setting watchpoint on a tagged address.  Unlike
breakpoint, watchpoint record the expression rather than the address, and
when a watchpoint is fired, GDB checks the expression value changed
instead of matching address, so we can mask the watchpoint address for
aarch64, by adding a gdbarch method addr_tag_remove.

gdb:

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

	* aarch64-linux-tdep.c (aarch64_linux_addr_tag_remove): New method.
	(aarch64_linux_init_abi): Install gdbarch method.
	* gdbarch.sh (addr_tag_remove): New gdbarch method.
	* gdbarch.c: Re-generated.
	* gdbarch.h: Re-generated.
	* breakpoint.c (update_watchpoint):

gdb/testsuite:

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

	* gdb.arch/aarch64-tagged-pointer.exp: Add tests for watchpoint.
---
 gdb/aarch64-linux-tdep.c                          | 11 +++++++++++
 gdb/breakpoint.c                                  |  3 +--
 gdb/gdbarch.c                                     | 23 +++++++++++++++++++++++
 gdb/gdbarch.h                                     |  8 ++++++++
 gdb/gdbarch.sh                                    |  5 +++++
 gdb/testsuite/gdb.arch/aarch64-tagged-pointer.c   |  1 +
 gdb/testsuite/gdb.arch/aarch64-tagged-pointer.exp | 14 ++++++++++++++
 7 files changed, 63 insertions(+), 2 deletions(-)

diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index b6052ba..139f336 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -1001,6 +1001,15 @@ aarch64_linux_syscall_record (struct regcache *regcache,
   return 0;
 }
 
+/* Implement the "addr_tag_remove" gdbarch method.  */
+
+static CORE_ADDR
+aarch64_linux_addr_tag_remove (struct gdbarch *gdbarch, CORE_ADDR val)
+{
+  /* Ignore the top byte of virtual address.  */
+  return val & 0x0fffffffffffffffULL;
+}
+
 static void
 aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
@@ -1217,6 +1226,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_addr_tag_remove (gdbarch, aarch64_linux_addr_tag_remove);
+
   /* Displaced stepping.  */
   set_gdbarch_max_insn_length (gdbarch, 4 * DISPLACED_MODIFIED_INSNS);
   set_gdbarch_displaced_step_copy_insn (gdbarch,
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index e16cfb6..16f03ff 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1894,8 +1894,7 @@ update_watchpoint (struct watchpoint *b, int reparse)
 		  loc->gdbarch = get_type_arch (value_type (v));
 
 		  loc->pspace = frame_pspace;
-		  loc->address = addr;
-
+		  loc->address = gdbarch_addr_tag_remove (loc->gdbarch, addr);
 		  if (bitsize != 0)
 		    {
 		      /* Just cover the bytes that make up the bitfield.  */
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 007392c..76574d4 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;
+  gdbarch_addr_tag_remove_ftype *addr_tag_remove;
   gdbarch_software_single_step_ftype *software_single_step;
   gdbarch_single_step_through_delay_ftype *single_step_through_delay;
   gdbarch_print_insn_ftype *print_insn;
@@ -428,6 +429,7 @@ gdbarch_alloc (const struct gdbarch_info *info,
   gdbarch->stabs_argument_has_addr = default_stabs_argument_has_addr;
   gdbarch->convert_from_func_ptr_addr = convert_from_func_ptr_addr_identity;
   gdbarch->addr_bits_remove = core_addr_identity;
+  gdbarch->addr_tag_remove = core_addr_identity;
   gdbarch->print_insn = default_print_insn;
   gdbarch->skip_trampoline_code = generic_skip_trampoline_code;
   gdbarch->skip_solib_resolver = generic_skip_solib_resolver;
@@ -618,6 +620,7 @@ 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 */
+  /* Skip verify of addr_tag_remove, invalid_p == 0 */
   /* 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 */
@@ -737,6 +740,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
                       "gdbarch_dump: addr_bits_remove = <%s>\n",
                       host_address_to_string (gdbarch->addr_bits_remove));
   fprintf_unfiltered (file,
+                      "gdbarch_dump: addr_tag_remove = <%s>\n",
+                      host_address_to_string (gdbarch->addr_tag_remove));
+  fprintf_unfiltered (file,
                       "gdbarch_dump: gdbarch_address_class_name_to_type_flags_p() = %d\n",
                       gdbarch_address_class_name_to_type_flags_p (gdbarch));
   fprintf_unfiltered (file,
@@ -3215,6 +3221,23 @@ set_gdbarch_addr_bits_remove (struct gdbarch *gdbarch,
   gdbarch->addr_bits_remove = addr_bits_remove;
 }
 
+CORE_ADDR
+gdbarch_addr_tag_remove (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->addr_tag_remove != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_addr_tag_remove called\n");
+  return gdbarch->addr_tag_remove (gdbarch, addr);
+}
+
+void
+set_gdbarch_addr_tag_remove (struct gdbarch *gdbarch,
+                             gdbarch_addr_tag_remove_ftype addr_tag_remove)
+{
+  gdbarch->addr_tag_remove = addr_tag_remove;
+}
+
 int
 gdbarch_software_single_step_p (struct gdbarch *gdbarch)
 {
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index d2e6b6f..769c8fb 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, there are bits in address which are ignored by the
+   kernel, the hardeware, etc.  They are called "tag", which can be
+   regarded as additional data associated with the address. */
+
+typedef CORE_ADDR (gdbarch_addr_tag_remove_ftype) (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern CORE_ADDR gdbarch_addr_tag_remove (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern void set_gdbarch_addr_tag_remove (struct gdbarch *gdbarch, gdbarch_addr_tag_remove_ftype *addr_tag_remove);
+
 /* 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..1f673e7 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -621,6 +621,11 @@ 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, there are bits in address which are ignored by the
+# kernel, the hardeware, etc.  They are called "tag", which can be
+# regarded as additional data associated with the address.
+m;CORE_ADDR;addr_tag_remove;CORE_ADDR addr;addr;;core_addr_identity;;0
+
 # 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/testsuite/gdb.arch/aarch64-tagged-pointer.c b/gdb/testsuite/gdb.arch/aarch64-tagged-pointer.c
index ec3574d..19395f5 100644
--- a/gdb/testsuite/gdb.arch/aarch64-tagged-pointer.c
+++ b/gdb/testsuite/gdb.arch/aarch64-tagged-pointer.c
@@ -54,4 +54,5 @@ main (void)
     }
 
   sp1->i = 8765;
+  i = 1;
 }
diff --git a/gdb/testsuite/gdb.arch/aarch64-tagged-pointer.exp b/gdb/testsuite/gdb.arch/aarch64-tagged-pointer.exp
index 2a5b1eb..f38b876 100644
--- a/gdb/testsuite/gdb.arch/aarch64-tagged-pointer.exp
+++ b/gdb/testsuite/gdb.arch/aarch64-tagged-pointer.exp
@@ -90,3 +90,17 @@ foreach_with_prefix bptype {"hbreak" "break"} {
     gdb_test "up" "\\(\*func_ptr\\) \\(\\).*" "caller is *func_ptr"
     delete_breakpoints
 }
+
+gdb_test "down"
+gdb_test "finish"
+# Watch on tagged pointer.
+gdb_test "watch *sp2"
+gdb_test "continue" \
+    "Continuing\\..*Hardware watchpoint \[0-9\]+.*" \
+    "run until watchpoint on s1"
+delete_breakpoints
+
+gdb_test "watch *p2"
+gdb_test "continue" \
+    "Continuing\\..*Hardware watchpoint \[0-9\]+.*" \
+    "run until watchpoint on i"
-- 
1.9.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]