aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristina Schimpe <christina.schimpe@intel.com>2022-08-10 08:50:37 +0200
committerSchimpe, Christina <christina.schimpe@intel.com>2024-11-18 13:36:16 +0000
commit27e82ad68b5eead610aabaf0e60335cc65cbd738 (patch)
treec3d2afa19d4a85358da5f185093ba15abff0b70d
parent86bb38cee9399c4092e6fc5f280d296fab7e3327 (diff)
downloadfsf-binutils-gdb-27e82ad68b5eead610aabaf0e60335cc65cbd738.zip
fsf-binutils-gdb-27e82ad68b5eead610aabaf0e60335cc65cbd738.tar.gz
fsf-binutils-gdb-27e82ad68b5eead610aabaf0e60335cc65cbd738.tar.bz2
LAM: Enable tagged pointer support for watchpoints.
The Intel (R) linear address masking (LAM) feature modifies the checking applied to 64-bit linear addresses. With this so-called "modified canonicality check" the processor masks the metadata bits in a pointer before using it as a linear address. LAM supports two different modes that differ regarding which pointer bits are masked and can be used for metadata: LAM 48 resulting in a LAM width of 15 and LAM 57 resulting in a LAM width of 6. This patch adjusts watchpoint addresses based on the currently enabled LAM mode using the untag mask provided in the /proc/<pid>/status file. As LAM can be enabled at runtime or as the configuration may change when entering an enclave, GDB checks enablement state each time a watchpoint is updated. In contrast to the patch implemented for ARM's Top Byte Ignore "Clear non-significant bits of address on memory access", it is not necessary to adjust addresses before they are passed to the target layer cache, as for LAM tagged pointers are supported by the system call to read memory. Additionally, LAM applies only to addresses used for data accesses. Thus, it is sufficient to mask addresses used for watchpoints. The following examples are based on a LAM57 enabled program. Before this patch tagged pointers were not supported for watchpoints: ~~~ (gdb) print pi_tagged $2 = (int *) 0x10007ffffffffe004 (gdb) watch *pi_tagged Hardware watchpoint 2: *pi_tagged (gdb) c Continuing. Couldn't write debug register: Invalid argument. ~~~~ Once LAM 48 or LAM 57 is enabled for the current program, GDB can now specify watchpoints for tagged addresses with LAM width 15 or 6, respectively. Approved-By: Felix Willgerodt <felix.willgerodt@intel.com>
-rw-r--r--gdb/NEWS5
-rw-r--r--gdb/amd64-linux-tdep.c64
-rwxr-xr-xgdb/testsuite/gdb.arch/amd64-lam.c49
-rw-r--r--gdb/testsuite/gdb.arch/amd64-lam.exp46
-rw-r--r--gdb/testsuite/lib/gdb.exp64
5 files changed, 228 insertions, 0 deletions
diff --git a/gdb/NEWS b/gdb/NEWS
index 9641839..046daad 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,11 @@
*** Changes since GDB 15
+* GDB now supports watchpoints for tagged data pointers (see
+ https://en.wikipedia.org/wiki/Tagged_pointer) on amd64, such as the
+ one used by the Linear Address Masking (LAM) feature provided by
+ Intel.
+
* Debugging support for Intel MPX has been removed. This includes the
removal of
** MPX register support
diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index 77de821..2c76a1d 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -43,6 +43,7 @@
#include "target-descriptions.h"
#include "expop.h"
#include "arch/amd64-linux-tdesc.h"
+#include "inferior.h"
/* The syscall's XML filename for i386. */
#define XML_SYSCALL_FILENAME_AMD64 "syscalls/amd64-linux.xml"
@@ -50,6 +51,10 @@
#include "record-full.h"
#include "linux-record.h"
+#include <string_view>
+
+#define DEFAULT_TAG_MASK 0xffffffffffffffffULL
+
/* Mapping between the general-purpose registers in `struct user'
format and GDB's register cache layout. */
@@ -1767,6 +1772,62 @@ amd64_dtrace_parse_probe_argument (struct gdbarch *gdbarch,
}
}
+/* Extract the untagging mask based on the currently active linear address
+ masking (LAM) mode, which is stored in the /proc/<pid>/status file.
+ If we cannot extract the untag mask (for example, if we don't have
+ execution), we assume address tagging is not enabled and return the
+ DEFAULT_TAG_MASK. */
+
+static CORE_ADDR
+amd64_linux_lam_untag_mask ()
+{
+ if (!target_has_execution ())
+ return DEFAULT_TAG_MASK;
+
+ inferior *inf = current_inferior ();
+ if (inf->fake_pid_p)
+ return DEFAULT_TAG_MASK;
+
+ const std::string filename = string_printf ("/proc/%d/status", inf->pid);
+ gdb::unique_xmalloc_ptr<char> status_file
+ = target_fileio_read_stralloc (nullptr, filename.c_str ());
+
+ if (status_file == nullptr)
+ return DEFAULT_TAG_MASK;
+
+ std::string_view status_file_view (status_file.get ());
+ constexpr std::string_view untag_mask_str = "untag_mask:\t";
+ const size_t found = status_file_view.find (untag_mask_str);
+ if (found != std::string::npos)
+ {
+ const char* start = status_file_view.data() + found
+ + untag_mask_str.length ();
+ char* endptr;
+ errno = 0;
+ unsigned long long result = std::strtoul (start, &endptr, 0);
+ if (errno != 0 || endptr == start)
+ error (_("Failed to parse untag_mask from file %s."),
+ std::string (filename).c_str ());
+
+ return result;
+ }
+
+ return DEFAULT_TAG_MASK;
+}
+
+/* Adjust watchpoint address based on the currently active linear address
+ masking (LAM) mode using the untag mask. Check each time for a new
+ mask, as LAM is enabled at runtime. */
+
+static CORE_ADDR
+amd64_linux_remove_non_address_bits_watchpoint (gdbarch *gdbarch,
+ CORE_ADDR addr)
+{
+ /* Clear insignificant bits of a target address using the untag
+ mask. */
+ return (addr & amd64_linux_lam_untag_mask ());
+}
+
static void
amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch,
int num_disp_step_buffers)
@@ -1818,6 +1879,9 @@ amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch,
set_gdbarch_process_record (gdbarch, i386_process_record);
set_gdbarch_process_record_signal (gdbarch, amd64_linux_record_signal);
+
+ set_gdbarch_remove_non_address_bits_watchpoint
+ (gdbarch, amd64_linux_remove_non_address_bits_watchpoint);
}
static void
diff --git a/gdb/testsuite/gdb.arch/amd64-lam.c b/gdb/testsuite/gdb.arch/amd64-lam.c
new file mode 100755
index 0000000..0fe2bc6
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-lam.c
@@ -0,0 +1,49 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2023-2024 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/>. */
+
+#define _GNU_SOURCE
+#include <stdint.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/syscall.h>
+#include <assert.h>
+#include <errno.h>
+#include <asm/prctl.h>
+
+int
+main (int argc, char **argv)
+{
+ int i;
+ int* pi = &i;
+ int* pi_tagged;
+
+ /* Enable LAM 57. */
+ errno = 0;
+ syscall (SYS_arch_prctl, ARCH_ENABLE_TAGGED_ADDR, 6);
+ assert_perror (errno);
+
+ /* Add tagging at bit 61. */
+ pi_tagged = (int *) ((uintptr_t) pi | (1LL << 60));
+
+ i = 0; /* Breakpoint here. */
+ *pi = 1;
+ *pi_tagged = 2;
+ *pi = 3;
+ *pi_tagged = 4;
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-lam.exp b/gdb/testsuite/gdb.arch/amd64-lam.exp
new file mode 100644
index 0000000..0bcbb63
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-lam.exp
@@ -0,0 +1,46 @@
+# Copyright 2023-2024 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/>.
+
+# Test Linear Address Masking (LAM) support.
+
+require allow_lam_tests
+
+standard_testfile amd64-lam.c
+
+# Test LAM 57.
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
+ return -1
+}
+
+if { ![runto_main] } {
+ return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "Breakpoint here"]
+gdb_continue_to_breakpoint "Breakpoint here"
+
+# Test hw watchpoint for a tagged and an untagged address with hit on a
+# tagged and an untagged address each.
+
+foreach symbol {"pi" "pi_tagged"} {
+ gdb_test "watch *${symbol}"
+ gdb_test "continue" \
+ "Continuing\\..*Hardware watchpoint \[0-9\]+.*" \
+ "run until watchpoint on ${symbol}"
+ gdb_test "continue" \
+ "Continuing\\..*Hardware watchpoint \[0-9\]+.*" \
+ "run until watchpoint on ${symbol}, 2nd hit"
+ delete_breakpoints
+}
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 410f99e..5d4d9db 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -4323,6 +4323,70 @@ gdb_caching_proc allow_avx512fp16_tests {} {
return $allow_avx512fp16_tests
}
+# Run a test on the target to see if it supports LAM 57. Return 1 if so,
+# 0 if it does not. Based on the arch_prctl() handle ARCH_ENABLE_TAGGED_ADDR
+# to enable LAM which fails if the hardware or the OS does not support LAM.
+
+gdb_caching_proc allow_lam_tests {} {
+ global gdb_prompt inferior_exited_re
+
+ set me "allow_lam_tests"
+ if { ![istarget "x86_64-*-*"] } {
+ verbose "$me: target does not support LAM, returning 1" 2
+ return 0
+ }
+
+ # Compile a test program.
+ set src {
+ #define _GNU_SOURCE
+ #include <unistd.h>
+ #include <sys/syscall.h>
+ #include <assert.h>
+ #include <errno.h>
+ #include <asm/prctl.h>
+
+ int configure_lam ()
+ {
+ errno = 0;
+ syscall (SYS_arch_prctl, ARCH_ENABLE_TAGGED_ADDR, 6);
+ assert_perror (errno);
+ return errno;
+ }
+
+ int
+ main () { return configure_lam (); }
+ }
+
+ if {![gdb_simple_compile $me $src executable ""]} {
+ return 0
+ }
+ # No error message, compilation succeeded so now run it via gdb.
+
+ set allow_lam_tests 0
+ clean_restart $obj
+ gdb_run_cmd
+ gdb_expect {
+ -re ".*$inferior_exited_re with code.*${gdb_prompt} $" {
+ verbose -log "$me: LAM support not detected."
+ }
+ -re ".*Program received signal SIGABRT, Aborted.*${gdb_prompt} $" {
+ verbose -log "$me: LAM support not detected."
+ }
+ -re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
+ verbose -log "$me: LAM support detected."
+ set allow_lam_tests 1
+ }
+ default {
+ warning "\n$me: default case taken."
+ }
+ }
+ gdb_exit
+ remote_file build delete $obj
+
+ verbose "$me: returning $allow_lam_tests" 2
+ return $allow_lam_tests
+}
+
# Run a test on the target to see if it supports btrace hardware. Return 1 if so,
# 0 if it does not. Based on 'check_vmx_hw_available' from the GCC testsuite.