[2/3,AArch64] Adjust breakpoint on tagged address
Commit Message
Nowadays, GDB can't set breakpoint on a tagged address, because kernel
requires tag bits should be removed, and reject the request,
(gdb) hbreak *func_ptr
gdb.execute_unwinders function is missing:
Hardware assisted breakpoint 2 at 0xf0000000004006f0
(gdb) c
Continuing.
main () at binutils-gdb/gdb/testsuite/gdb.arch/aarch64-tagged-pointer.c:47
47 sp2->i = 4321; /* breakpoint here. */
Unexpected error setting hardware debug registers
With this patch, when user sets a breakpoint on tagged address, GDB will
drop the top byte of address, and put breakpoint at the new place, as
shown below,
(gdb) hbreak *func_ptr
warning: Breakpoint address adjusted from 0xf000000000400690 to 0x00400690.
Hardware assisted breakpoint 2 at 0x400690
(gdb) break *func_ptr
warning: Breakpoint address adjusted from 0xf000000000400690 to 0x00400690.
Breakpoint 3 at 0x400690
When program hits a breakpoint, the stopped pc reported by Linux kernle is
the address *without* tag, so it is better the address recorded in
breakpoint location is the one without tag too, so we can still match
breakpoint location address and stopped pc reported by Linux kernel, by
simple compare. I did try the different approach, that is keep the tag in
the address saved in the breakpoint location, but I need to change many
places of "loc->address == pc", so I give up on this way.
gdb:
2017-10-24 Yao Qi <yao.qi@linaro.org>
* aarch64-tdep.c (aarch64_adjust_breakpoint_address): New
function.
(aarch64_gdbarch_init): Install adjust_breakpoint_address.
gdb/testsuite:
2017-10-24 Yao Qi <yao.qi@linaro.org>
* gdb.arch/aarch64-tagged-pointer.c (main): Update.
* gdb.arch/aarch64-tagged-pointer.exp: Add test for breakpoint.
---
gdb/aarch64-tdep.c | 10 ++++++++++
gdb/testsuite/gdb.arch/aarch64-tagged-pointer.c | 9 +++++++++
gdb/testsuite/gdb.arch/aarch64-tagged-pointer.exp | 24 +++++++++++++++++++++++
3 files changed, 43 insertions(+)
@@ -2828,6 +2828,14 @@ aarch64_displaced_step_hw_singlestep (struct gdbarch *gdbarch,
return 1;
}
+/* Implement the "adjust_breakpoint_address" gdbarch method. */
+
+static CORE_ADDR
+aarch64_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
+{
+ return bpaddr & 0x0fffffffffffffffULL;
+}
+
/* Initialize the current architecture based on INFO. If possible,
re-use an architecture from ARCHES, which is a list of
architectures already created during this debugging session.
@@ -2945,6 +2953,8 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
aarch64_breakpoint::bp_from_kind);
set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
set_gdbarch_software_single_step (gdbarch, aarch64_software_single_step);
+ set_gdbarch_adjust_breakpoint_address (gdbarch,
+ aarch64_adjust_breakpoint_address);
/* Information about registers, etc. */
set_gdbarch_sp_regnum (gdbarch, AARCH64_SP_REGNUM);
@@ -45,4 +45,13 @@ main (void)
void (*func_ptr) (void) = foo;
func_ptr = (void (*) (void)) ((uintptr_t) func_ptr | 0xf000000000000000ULL);
sp2->i = 4321; /* breakpoint here. */
+
+ int j;
+ for (j = 0; j < 2; j++)
+ {
+ foo ();
+ (*func_ptr) ();
+ }
+
+ sp1->i = 8765;
}
@@ -66,3 +66,27 @@ gdb_test_multiple $test $test {
gdb_test "disassemble func_ptr,+8" \
":\[\t \]+$insn1\[ \r\n\]+.*:\[\t \]+$insn2.*"
+
+foreach_with_prefix bptype {"hbreak" "break"} {
+
+ # Set a breakpoint on a tagged address, func_ptr,
+ gdb_test "$bptype *func_ptr" \
+ "warning: Breakpoint address adjusted from .*reakpoint $decimal at .*" \
+ "breakpoint at *func_ptr"
+ # Resume the program and expect it hits foo,
+ gdb_test "continue" \
+ "Continuing\\..*Breakpoint \[0-9\]+, foo \\(\\) at .*" \
+ "run until breakpoint set *func_ptr"
+ gdb_test "up" "foo \\(\\).*" "caller is foo"
+ delete_breakpoints
+
+ # Set a breakpoint on normal function, call it through tagged
+ # function pointer.
+ gdb_test "$bptype foo" "reakpoint $decimal at .*" \
+ "hardware breakpoint at foo"
+ gdb_test "continue" \
+ "Continuing\\..*Breakpoint \[0-9\]+, foo \\(\\) at .*" \
+ "run until breakpoint set foo"
+ gdb_test "up" "\\(\*func_ptr\\) \\(\\).*" "caller is *func_ptr"
+ delete_breakpoints
+}