Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Luis Machado <luis.machado@arm.com>
To: "Schimpe, Christina" <christina.schimpe@intel.com>,
	gdb-patches@sourceware.org
Subject: Re: [PATCH 2/3] LAM: Enable tagged pointer support for watchpoints.
Date: Thu, 28 Mar 2024 12:50:48 +0000	[thread overview]
Message-ID: <3e6ee87e-5b3a-4487-8e25-794419bebf26@arm.com> (raw)
In-Reply-To: <20240327074739.2969623-3-christina.schimpe@intel.com>

On 3/27/24 07:47, Schimpe, Christina wrote:
> From: Christina Schimpe <christina.schimpe@intel.com>
> 
> 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.
> ---
>  gdb/NEWS                             |  2 +
>  gdb/amd64-linux-tdep.c               | 67 ++++++++++++++++++++++++++++
>  gdb/testsuite/gdb.arch/amd64-lam.c   | 49 ++++++++++++++++++++
>  gdb/testsuite/gdb.arch/amd64-lam.exp | 45 +++++++++++++++++++
>  gdb/testsuite/lib/gdb.exp            | 62 +++++++++++++++++++++++++
>  5 files changed, 225 insertions(+)
>  create mode 100755 gdb/testsuite/gdb.arch/amd64-lam.c
>  create mode 100644 gdb/testsuite/gdb.arch/amd64-lam.exp
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index feb3a37393a..295f2147def 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -3,6 +3,8 @@
>  
>  *** Changes since GDB 14
>  
> +* GDB now supports watchpoints for tagged data pointers on amd64.
> +
>  * The MPX commands "show/set mpx bound" have been deprecated, as Intel
>    listed MPX as removed in 2019.
>  
> diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
> index 9d560ac4fbf..94c62277623 100644
> --- a/gdb/amd64-linux-tdep.c
> +++ b/gdb/amd64-linux-tdep.c
> @@ -41,6 +41,7 @@
>  #include "arch/amd64.h"
>  #include "target-descriptions.h"
>  #include "expop.h"
> +#include "inferior.h"
>  
>  /* The syscall's XML filename for i386.  */
>  #define XML_SYSCALL_FILENAME_AMD64 "syscalls/amd64-linux.xml"
> @@ -48,6 +49,10 @@
>  #include "record-full.h"
>  #include "linux-record.h"
>  
> +#include <sstream>
> +
> +#define DEFAULT_TAG_MASK 0xffffffffffffffffULL
> +
>  /* Mapping between the general-purpose registers in `struct user'
>     format and GDB's register cache layout.  */
>  
> @@ -1794,6 +1799,65 @@ 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;
> +
> +  /* Construct status file name and read the file's content.  */
> +  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;
> +
> +  /* Parse the status file line-by-line and look for the untag mask.  */
> +  std::istringstream strm_status_file (status_file.get ());
> +  std::string line;
> +  const std::string untag_mask_str ("untag_mask:\t");
> +  while (std::getline (strm_status_file, line))
> +    {
> +      const size_t found = line.find (untag_mask_str);
> +      if (found != std::string::npos)
> +	{
> +	  const size_t tag_length = untag_mask_str.length();
> +	  return std::strtoul (&line[found + tag_length], nullptr, 0);
> +	}
> +    }
> +
> +   return DEFAULT_TAG_MASK;
> +}
> +
> +/* Adjust watchpoint address based on the tagging mode which is currently
> +   enabled.  For now, linear address masking (LAM) is the only feature
> +   which allows to store metadata in pointer values for amd64.  Thus, we
> +   adjust the watchpoint address based on the currently active LAM mode
> +   using the untag mask provided by the linux kernel.  Check each time for
> +   a new mask, as LAM is enabled at runtime.  Also, the LAM configuration
> +   may change when entering an enclave.  No untagging will be applied if
> +   this function is called while we don't have execution.  */
> +
> +static CORE_ADDR
> +amd64_linux_remove_non_addr_bits_wpt (gdbarch *gdbarch, CORE_ADDR addr)
> +{
> +  /* Clear insignificant bits of a target address using the untag mask.
> +     The untag mask preserves the topmost bit, which distinguishes user space
> +     from kernel space address.  */
> +  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)
> @@ -1848,6 +1912,9 @@ amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch,
>  
>    set_gdbarch_get_siginfo_type (gdbarch, x86_linux_get_siginfo_type);
>    set_gdbarch_report_signal_info (gdbarch, i386_linux_report_signal_info);
> +
> +  set_gdbarch_remove_non_addr_bits_wpt (gdbarch,
> +					amd64_linux_remove_non_addr_bits_wpt);
>  }
>  
>  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 00000000000..28786389a9a
> --- /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 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 00000000000..8274c3adf97
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/amd64-lam.exp
> @@ -0,0 +1,45 @@
> +# Copyright 2023 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 tagged and untagged address with hit on untagged
> +# and tagged adress.
> +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 d48ea37c0cc..c7d15f82da1 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -9285,6 +9285,68 @@ gdb_caching_proc allow_ctf_tests {} {
>  
>      return $can_ctf
>  }
> +# 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 <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
> +}
>  
>  # Return 1 if compiler supports -gstatement-frontiers.  Otherwise,
>  # return 0.

I'll leave the amd64-specific bits for the responsible maintainers. But I noticed the
copyright year is wrong (2023 -> 2024).

  parent reply	other threads:[~2024-03-28 12:51 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-03-27  7:47 [PATCH 0/3] Add amd64 LAM watchpoint support Schimpe, Christina
2024-03-27  7:47 ` [PATCH 1/3] gdb: Make tagged pointer support configurable Schimpe, Christina
2024-03-28 11:58   ` Luis Machado
2024-04-04  8:18     ` Schimpe, Christina
2024-04-04  8:50       ` Luis Machado
2024-04-24 11:10   ` Willgerodt, Felix
2024-03-27  7:47 ` [PATCH 2/3] LAM: Enable tagged pointer support for watchpoints Schimpe, Christina
2024-03-27 12:37   ` Eli Zaretskii
2024-03-28 12:50   ` Luis Machado [this message]
2024-04-24 11:11   ` Willgerodt, Felix
2024-03-27  7:47 ` [PATCH 3/3] LAM: Support kernel space debugging Schimpe, Christina
2024-04-24 11:11   ` Willgerodt, Felix
2024-04-15 11:26 ` [PING][PATCH 0/3] Add amd64 LAM watchpoint support Schimpe, Christina
2024-04-22  7:17   ` [PING*2][PATCH " Schimpe, Christina

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3e6ee87e-5b3a-4487-8e25-794419bebf26@arm.com \
    --to=luis.machado@arm.com \
    --cc=christina.schimpe@intel.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox