*** 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
#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"
#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. */
}
}
+/* 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)
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
--- /dev/null
+/* 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;
+}
--- /dev/null
+# 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
+}
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.