Clear non-significant bits of address on memory access

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 tag in the tagged address is modeled as non-significant bits in
address, so this patch adds a new gdbarch method significant_addr_bit and
clear the non-significant bits (the top byte in ARMv8) of the virtual
address at the point before passing address to target cache layer.  IOW,
the address used in the target cache layer is already cleared.

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

Note that I used address_significant in paddress, but it causes a
regression gdb.base/long_long.exp, because gdb clears the non-significant
bits in address, but test still expects them.

p/a val.oct^M
$24 = 0x2ee53977053977^M
(gdb) FAIL: gdb.base/long_long.exp: p/a val.oct

so I defer the change there.

gdb:

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  Yao Qi  <yao.qi@linaro.org>

gdb/testsuite:

	* gdb.arch/aarch64-tagged-pointer.c: New file.
	* gdb.arch/aarch64-tagged-pointer.exp: New file.
This commit is contained in:
Yao Qi
2017-12-08 17:27:03 +00:00
parent 8e481c3ba8
commit a738ea1d41
11 changed files with 193 additions and 0 deletions

View File

@ -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.

View File

@ -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);

View File

@ -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 */
@ -1324,6 +1327,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
fprintf_unfiltered (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));
@ -3215,6 +3221,22 @@ set_gdbarch_addr_bits_remove (struct gdbarch *gdbarch,
gdbarch->addr_bits_remove = addr_bits_remove;
}
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)
{

View File

@ -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.

View File

@ -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.

View File

@ -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. */

View File

@ -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

View File

@ -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. */
}

View File

@ -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.*"

View File

@ -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)
{

View File

@ -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);