diff options
-rw-r--r-- | gdb/ChangeLog | 10 | ||||
-rw-r--r-- | gdb/aarch64-tdep.c | 5 | ||||
-rw-r--r-- | gdb/gdbarch.c | 22 | ||||
-rw-r--r-- | gdb/gdbarch.h | 8 | ||||
-rwxr-xr-x | gdb/gdbarch.sh | 6 | ||||
-rw-r--r-- | gdb/target.c | 2 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/testsuite/gdb.arch/aarch64-tagged-pointer.c | 48 | ||||
-rw-r--r-- | gdb/testsuite/gdb.arch/aarch64-tagged-pointer.exp | 67 | ||||
-rw-r--r-- | gdb/utils.c | 17 | ||||
-rw-r--r-- | gdb/utils.h | 3 |
11 files changed, 193 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 21ddce0..952a2ff 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,13 @@ +2017-12-08 Yao Qi <yao.qi@linaro.org> + + * aarch64-tdep.c (aarch64_gdbarch_init): Install gdbarch + significant_addr_bit. + * gdbarch.sh (significant_addr_bit): New. + * gdbarch.c, gdbarch.h: Re-generated. + * target.c (memory_xfer_partial): Call address_significant. + * utils.c (address_significant): New function. + * utils.h (address_significant): Declare. + 2017-12-08 Tom Tromey <tom@tromey.com> * printcmd.c (ui_printf): Update. Use std::vector. diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index 6a0d4b7..383d584 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -2970,6 +2970,11 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_tdesc_pseudo_register_reggroup_p (gdbarch, aarch64_pseudo_register_reggroup_p); + /* The top byte of an address is known as the "tag" and is + ignored by the kernel, the hardware, etc. and can be regarded + as additional data associated with the address. */ + set_gdbarch_significant_addr_bit (gdbarch, 56); + /* ABI */ set_gdbarch_short_bit (gdbarch, 16); set_gdbarch_int_bit (gdbarch, 32); 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/ChangeLog b/gdb/testsuite/ChangeLog index 720a9ec..cc834de 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2017-12-08 Yao Qi <yao.qi@linaro.org> + + * gdb.arch/aarch64-tagged-pointer.c: New file. + * gdb.arch/aarch64-tagged-pointer.exp: New file. + 2017-12-08 Sergio Durigan Junior <sergiodj@redhat.com> * gdb.arch/i386-sse-stack-align.exp: Cast "print" function call 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); |