From patchwork Fri Dec 8 10:04:29 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yao Qi X-Patchwork-Id: 24812 Received: (qmail 25546 invoked by alias); 8 Dec 2017 10:04:43 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 25367 invoked by uid 89); 8 Dec 2017 10:04:42 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-24.9 required=5.0 tests=BAYES_00, FREEMAIL_FROM, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_PASS, UNSUBSCRIBE_BODY autolearn=ham version=3.3.2 spammy=regarded, stepping X-HELO: mail-wr0-f196.google.com Received: from mail-wr0-f196.google.com (HELO mail-wr0-f196.google.com) (209.85.128.196) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 08 Dec 2017 10:04:39 +0000 Received: by mail-wr0-f196.google.com with SMTP id s66so10278262wrc.9 for ; Fri, 08 Dec 2017 02:04:39 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=cPYMyFh34AA6tiuKOg1LFam+becIOrDQRNhv8e+QJRo=; b=RWsqAMKNppzZJnkdJLx4Vr8jemMJHbsH1ZxD1Af6RhpUOng+h8JjFcJLO2fXDecjDQ 1PVXvr8aY9EZ1kI6KxEDKO/ufTsC0Hz64GRq8Da5gcQQVXrtMEYalFHIoQPdkAhF0IaX pJYfVWHLO3aX4onrOIp2iz+XCR377tNBJawsBYQ3zonwB7eWjXoXqvCyaPEr+u7i8Zb7 5kuIKJcyEhPs8zDlW+HmpFsBFRSRhVPGiOwWt+CTtQ1tW4rG9oZOW2u0bVT1gB17TkYS Dp2jIKpp3eqLhmGH4wi9P1Eg6ihQNatLp7FOUfA6SE+UG67R8mPEujAR9NHjlSKNEuqp UqZg== X-Gm-Message-State: AJaThX6fH0rm7mkf9cYQXKsjJR7ygFFEoS61aSv/xuQv97dp3TwgpWTV LP3xshUUK3hgZqlQkMgfvZaE8g== X-Google-Smtp-Source: AGs4zMZH3lKxwFBD69cJwoPzbI27Rvx1bj2Q91wN9emltmC5OU6mqDkvZUppbcQdi2ng2VnLHtimJQ== X-Received: by 10.223.178.130 with SMTP id g2mr24761075wrd.129.1512727477110; Fri, 08 Dec 2017 02:04:37 -0800 (PST) Received: from E107787-LIN.cambridge.arm.com (static.42.136.251.148.clients.your-server.de. [148.251.136.42]) by smtp.gmail.com with ESMTPSA id a22sm1194394wme.46.2017.12.08.02.04.36 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 08 Dec 2017 02:04:36 -0800 (PST) From: Yao Qi X-Google-Original-From: Yao Qi To: gdb-patches@sourceware.org Subject: [PATCH 1/3] Clear non-significant bits of address on memory access Date: Fri, 8 Dec 2017 10:04:29 +0000 Message-Id: <1512727471-30745-2-git-send-email-yao.qi@linaro.org> In-Reply-To: <1512727471-30745-1-git-send-email-yao.qi@linaro.org> References: <1512727471-30745-1-git-send-email-yao.qi@linaro.org> X-IsSubscribed: yes 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 : 0x00000000 (gdb) x/x 0xf000000000411030 0xf000000000411030: Cannot access memory at address 0xf000000000411030 After this patch, (gdb) x/x 0x0000000000411030 0x411030 : 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-10-19 Yao Qi * aarch64-linux-tdep.c (aarch64_linux_init_abi): 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-10-19 Yao Qi gdb/testsuite: * gdb.arch/aarch64-tagged-pointer.c: New file. * gdb.arch/aarch64-tagged-pointer.exp: New file. --- gdb/aarch64-linux-tdep.c | 2 + gdb/gdbarch.c | 22 ++++++++ gdb/gdbarch.h | 8 +++ gdb/gdbarch.sh | 6 ++ gdb/target.c | 2 + gdb/testsuite/gdb.arch/aarch64-tagged-pointer.c | 48 ++++++++++++++++ gdb/testsuite/gdb.arch/aarch64-tagged-pointer.exp | 67 +++++++++++++++++++++++ gdb/utils.c | 17 ++++++ gdb/utils.h | 3 + 9 files changed, 175 insertions(+) create mode 100644 gdb/testsuite/gdb.arch/aarch64-tagged-pointer.c create mode 100644 gdb/testsuite/gdb.arch/aarch64-tagged-pointer.exp diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c index c2c2c30..b6c2a81 100644 --- a/gdb/aarch64-linux-tdep.c +++ b/gdb/aarch64-linux-tdep.c @@ -1217,6 +1217,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_significant_addr_bit (gdbarch, 56); + /* Displaced stepping. */ set_gdbarch_max_insn_length (gdbarch, 4 * DISPLACED_MODIFIED_INSNS); set_gdbarch_displaced_step_copy_insn (gdbarch, 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/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 . */ + +#include + +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 . +# +# 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);