]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Read capability tags from memory
authorLuis Machado <luis.machado@linaro.org>
Mon, 21 Dec 2020 14:44:23 +0000 (11:44 -0300)
committerJohn Baldwin <jhb@FreeBSD.org>
Thu, 1 Sep 2022 22:57:13 +0000 (15:57 -0700)
This patch enables capability reads from memory, including the tag bit.

It enables both native GDB and gdbserver to do so.

gdb/ChangeLog:

2021-01-15  Luis Machado  <luis.machado@arm.com>

* aarch64-linux-nat.c (aarch64_linux_nat_target)
<read_capability>: New function override.
(aarch64_linux_nat_target::read_capability): New function.
(maint_print_cap_from_addr_cmd): New function.
(add_show_debug_regs_command): Register new maintenance command.
* aarch64-linux-tdep.c: Include target.h.
(aarch64_linux_get_cap_tag_from_address): New function.
(aarch64_linux_init_abi): Register hook for
gdbarch_get_cap_tag_from_address
* arch-utils.c (default_get_cap_tag_from_address): New function.
* arch-utils.h (default_get_cap_tag_from_address): New prototype.
* configure.nat: Add nat/aarch64-cap-linux.o to the list of object
files for AArch64-Linux.
* gdbarch.c: Regenerate.
* gdbarch.h: Regenerate.
* gdbarch.sh (get_cap_tag_from_address): New gdbarch hook.
* nat/aarch64-cap-linux.c: New file.
* nat/aarch64-cap-linux.h (aarch64_linux_read_capability): New
prototype.
* remote.c (remote_target) <read_capability>: New function override.
(PACKET_qXfer_capability): New enum.
(remote_target::xfer_partial): Handle TARGET_OBJECT_CAPABILITY.
(remote_target::read_capability): New member function.
(_initialize_remote): Add new packet configuration.
* target-delegates.c: Regenerate.
* target.c (target_read_capability): New function.
* target.h (target_object) <TARGET_OBJECT_CAPABILITY>: New enum field.
(struct target_ops) <read_capability>: New virtual member function.
(target_read_capability): New prototype.
* valprint.c (generic_value_print_capability): Handle tags from
capabilities stored in memory.
* value.c (value_fetch_lazy_memory): Fetch tag if reading a capability.

gdbserver/ChangeLog

2021-01-15  Luis Machado  <luis.machado@arm.com>

* configure.srv: Add nat/aarch64-cap-linux.o to the list of object
files for AArch64-Linux
* linux-aarch64-low.cc (aarch64_target) <supports_qxfer_capability>
<qxfer_capability>: New member function overrides.
(aarch64_target::supports_qxfer_capability): New function.
(aarch64_target::qxfer_capability): New function.
* server.cc (handle_qxfer_capability): New function.
(qxfer_packets): Add "capa" packet.
* target.cc (process_stratum_target::supports_qxfer_capability)
(process_stratum_target::qxfer_capability): New functions.
* target.h (process_stratum_target) <supports_qxfer_capability>
<qxfer_capability>: New virtual member functions.

21 files changed:
gdb/aarch64-linux-nat.c
gdb/aarch64-linux-tdep.c
gdb/arch-utils.c
gdb/arch-utils.h
gdb/configure.nat
gdb/gdbarch-components.py
gdb/gdbarch-gen.h
gdb/gdbarch.c
gdb/nat/aarch64-cap-linux.c [new file with mode: 0644]
gdb/nat/aarch64-cap-linux.h
gdb/remote.c
gdb/target-delegates.c
gdb/target.c
gdb/target.h
gdb/valprint.c
gdb/value.c
gdbserver/configure.srv
gdbserver/linux-aarch64-low.cc
gdbserver/server.cc
gdbserver/target.cc
gdbserver/target.h

index 5a5ebcc96e8c18de4c0da6f4d0bed14139620312..cffd41455678d0a667291047a688edaa9ba1a762 100644 (file)
@@ -109,6 +109,8 @@ public:
   /* Write allocation tags to memory via PTRACE.  */
   bool store_memtags (CORE_ADDR address, size_t len,
                      const gdb::byte_vector &tags, int type) override;
+
+  gdb::byte_vector read_capability (CORE_ADDR addr) override;
 };
 
 static aarch64_linux_nat_target the_aarch64_linux_nat_target;
@@ -939,12 +941,50 @@ aarch64_linux_nat_target::store_memtags (CORE_ADDR address, size_t len,
   return false;
 }
 
+/* Implement the "read_capability" target_ops method.  */
+
+gdb::byte_vector
+aarch64_linux_nat_target::read_capability (CORE_ADDR addr)
+{
+  int tid = get_ptrace_pid (inferior_ptid);
+
+  struct user_cap cap;
+
+  if (!aarch64_linux_read_capability (tid, addr, cap))
+    perror_with_name (_("Unable to read capability from address."));
+
+  gdb::byte_vector cap_vec (17);
+  memcpy (cap_vec.data (), &cap.tag, 1);
+  memcpy (cap_vec.data () + 1, &cap.val, 16);
+
+  return cap_vec;
+}
+
+/* Implement the maintenance print capability tag command.  */
+
+static void
+maint_print_cap_from_addr_cmd (const char *args, int from_tty)
+{
+  gdb::byte_vector cap;
+  CORE_ADDR addr = parse_and_eval_address (args);
+  cap = target_read_capability (addr);
+
+  for (auto it : cap)
+    fprintf_unfiltered (gdb_stdlog, "%x ", it);
+
+  fputs_unfiltered ("\n", gdb_stdlog);
+}
+
 void _initialize_aarch64_linux_nat ();
 void
 _initialize_aarch64_linux_nat ()
 {
   aarch64_initialize_hw_point ();
 
+  add_cmd ("cap_from_addr", class_maintenance, maint_print_cap_from_addr_cmd, _("\
+Print the capability from addr."),
+          &maintenanceprintlist);
+
   /* Register the target.  */
   linux_target = &the_aarch64_linux_nat_target;
   add_inf_child_target (&the_aarch64_linux_nat_target);
index 98d17b2deb97b6fc397f92ceebcab7f0a1491f92..66d3a929af29bfd80800905294461acf955f056e 100644 (file)
@@ -2109,6 +2109,22 @@ aarch64_linux_decode_memtag_section (struct gdbarch *gdbarch,
   return tags;
 }
 
+/* AArch64 Linux implementation of the get_cap_tag_from_address gdbarch
+   hook.  Returns the tag from the capability located at ADDR.  */
+
+static bool
+aarch64_linux_get_cap_tag_from_address (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  gdb::byte_vector cap;
+
+  cap = target_read_capability (addr);
+
+  if (cap.size () == 0)
+    return false;
+
+  return cap[0] != 0;
+}
+
 static void
 aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
@@ -2389,6 +2405,8 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 
       set_gdbarch_report_signal_info (gdbarch,
                                      aarch64_linux_report_signal_info);
+      set_gdbarch_get_cap_tag_from_address (gdbarch,
+                                           aarch64_linux_get_cap_tag_from_address);
     }
   else
     {
index 46af565f324b7eb6af9c4b7d62ec4376a199457b..66c19059db2fae6354a2886528d55c18f4810a13 100644 (file)
@@ -1110,6 +1110,13 @@ default_register_tag (struct gdbarch *gdbarch,
   return false;
 }
 
+/* See arch-utils.h.  */
+bool default_get_cap_tag_from_address (struct gdbarch *gdbarch,
+                                      CORE_ADDR addr)
+{
+  return false;
+}
+
 /* Static function declarations */
 
 static void alloc_gdbarch_data (struct gdbarch *);
index 67d96e529f8b898611e2c8591e583e6d3ceaf50f..90469d2cb6af6c5a72838e813f833870965d5494 100644 (file)
@@ -310,4 +310,8 @@ extern bool default_register_has_tag (struct gdbarch *gdbarch,
 extern bool default_register_tag (struct gdbarch *gdbarch,
                                  readable_regcache *regcache,
                                  int cookednum);
+
+/* Default implementation of gdbarch_cap_tag_from_address.  */
+extern bool default_get_cap_tag_from_address (struct gdbarch *gdbarch,
+                                             CORE_ADDR addr);
 #endif /* ARCH_UTILS_H */
index d219d6a960c396056571cc9af2e07c47930f6507..649f9a2ec740a3ced13d7db868d53450cfe896c4 100644 (file)
@@ -237,7 +237,7 @@ case ${gdb_host} in
                NATDEPFILES="${NATDEPFILES} aarch64-nat.o aarch64-linux-nat.o \
                aarch32-linux-nat.o nat/aarch64-hw-point.o \
                nat/aarch64-linux-hw-point.o \
-               nat/aarch64-linux.o \
+               nat/aarch64-cap-linux.o nat/aarch64-linux.o \
                nat/aarch64-sve-linux-ptrace.o \
                nat/aarch64-mte-linux-ptrace.o"
                ;;
index 18b5dbc3baaf109974d3c74e1c49ca9bf962a09f..10e8da1732a968f18a681a77c346aaeb76e8f4ef 100644 (file)
@@ -1022,6 +1022,17 @@ register.  Normally the identity mapping.
     invalid=False,
 )
 
+Method(
+    comment="""
+Return the tag from a capability stored at address ADDR.
+""",
+    type="bool",
+    name="get_cap_tag_from_address",
+    params=[("CORE_ADDR", "addr")],
+    predefault="default_get_cap_tag_from_address",
+    invalid=False,
+)
+
 Function(
     comment="""
 Fetch the target specific address used to represent a load module.
index 770601cf53fb1c2c778d3edc01a4e17a6104180a..bc3ab2a7f8727851672ba62ac509af2585200cad 100644 (file)
@@ -547,6 +547,12 @@ typedef int (gdbarch_remote_register_number_ftype) (struct gdbarch *gdbarch, int
 extern int gdbarch_remote_register_number (struct gdbarch *gdbarch, int regno);
 extern void set_gdbarch_remote_register_number (struct gdbarch *gdbarch, gdbarch_remote_register_number_ftype *remote_register_number);
 
+/* Return the tag from a capability stored at address ADDR. */
+
+typedef bool (gdbarch_get_cap_tag_from_address_ftype) (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern bool gdbarch_get_cap_tag_from_address (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern void set_gdbarch_get_cap_tag_from_address (struct gdbarch *gdbarch, gdbarch_get_cap_tag_from_address_ftype *get_cap_tag_from_address);
+
 /* Fetch the target specific address used to represent a load module. */
 
 extern bool gdbarch_fetch_tls_load_module_address_p (struct gdbarch *gdbarch);
index e9d6ccd2e1f68e5ad89fef545fe911d799322e84..27ed53950be42cb75b413517ff937f710951c2f7 100644 (file)
@@ -130,6 +130,7 @@ struct gdbarch
   CORE_ADDR decr_pc_after_break;
   CORE_ADDR deprecated_function_start_offset;
   gdbarch_remote_register_number_ftype *remote_register_number;
+  gdbarch_get_cap_tag_from_address_ftype *get_cap_tag_from_address;
   gdbarch_fetch_tls_load_module_address_ftype *fetch_tls_load_module_address;
   gdbarch_get_thread_local_address_ftype *get_thread_local_address;
   CORE_ADDR frame_args_skip;
@@ -328,6 +329,7 @@ gdbarch_alloc (const struct gdbarch_info *info,
   gdbarch->memory_insert_breakpoint = default_memory_insert_breakpoint;
   gdbarch->memory_remove_breakpoint = default_memory_remove_breakpoint;
   gdbarch->remote_register_number = default_remote_register_number;
+  gdbarch->get_cap_tag_from_address = default_get_cap_tag_from_address;
   gdbarch->unwind_pc = default_unwind_pc;
   gdbarch->unwind_sp = default_unwind_sp;
   gdbarch->stabs_argument_has_addr = default_stabs_argument_has_addr;
@@ -495,6 +497,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of decr_pc_after_break, invalid_p == 0 */
   /* Skip verify of deprecated_function_start_offset, invalid_p == 0 */
   /* Skip verify of remote_register_number, invalid_p == 0 */
+  /* Skip verify of get_cap_tag_from_address, invalid_p == 0 */
   /* Skip verify of fetch_tls_load_module_address, has predicate.  */
   /* Skip verify of get_thread_local_address, has predicate.  */
   /* Skip verify of frame_args_skip, invalid_p == 0 */
@@ -946,6 +949,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   fprintf_filtered (file,
                       "gdbarch_dump: remote_register_number = <%s>\n",
                       host_address_to_string (gdbarch->remote_register_number));
+  fprintf_filtered (file,
+                      "gdbarch_dump: get_cap_tag_from_address = <%s>\n",
+                      host_address_to_string (gdbarch->get_cap_tag_from_address));
   fprintf_filtered (file,
                       "gdbarch_dump: gdbarch_fetch_tls_load_module_address_p() = %d\n",
                       gdbarch_fetch_tls_load_module_address_p (gdbarch));
@@ -2992,6 +2998,23 @@ set_gdbarch_remote_register_number (struct gdbarch *gdbarch,
   gdbarch->remote_register_number = remote_register_number;
 }
 
+bool
+gdbarch_get_cap_tag_from_address (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->get_cap_tag_from_address != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_get_cap_tag_from_address called\n");
+  return gdbarch->get_cap_tag_from_address (gdbarch, addr);
+}
+
+void
+set_gdbarch_get_cap_tag_from_address (struct gdbarch *gdbarch,
+                                      gdbarch_get_cap_tag_from_address_ftype get_cap_tag_from_address)
+{
+  gdbarch->get_cap_tag_from_address = get_cap_tag_from_address;
+}
+
 bool
 gdbarch_fetch_tls_load_module_address_p (struct gdbarch *gdbarch)
 {
diff --git a/gdb/nat/aarch64-cap-linux.c b/gdb/nat/aarch64-cap-linux.c
new file mode 100644 (file)
index 0000000..cd204d1
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 "gdbsupport/common-defs.h"
+#include "aarch64-cap-linux.h"
+#include "gdb_ptrace.h"
+
+/* See aarch64-cap-linux.h */
+
+bool
+aarch64_linux_read_capability (int tid, CORE_ADDR address,
+                              user_cap &cap)
+{
+  cap.val = 0;
+  cap.tag = 0;
+  memset (cap.__reserved, 0, 15);
+
+  /* Fetch the tag from ptrace.  */
+  if (ptrace (PTRACE_PEEKCAP, tid, address, &cap) < 0)
+    return false;
+
+  return true;
+}
index 2b3c1dc5f3e48684095104f0a4d42cac7776256d..b5394704e4ff0bdb3bb9ea7ad1db606498d7fa1c 100644 (file)
@@ -58,4 +58,11 @@ struct user_cap {
   uint8_t __reserved[15];
 };
 
+/* From thread TID, read a capability from memory at ADDRESS and store
+   it into CAP.
+
+   Return true if successful and false otherwise.  */
+
+extern bool aarch64_linux_read_capability (int tid, CORE_ADDR address,
+                                          user_cap &cap);
 #endif /* NAT_AARCH64_CAP_LINUX_H */
index 1a34812a4b82252a0b408982945316c332377435..68511621772a6c20e39a1ed1d639d78c8493c54a 100644 (file)
@@ -689,6 +689,8 @@ public:
   bool store_memtags (CORE_ADDR address, size_t len,
                      const gdb::byte_vector &tags, int type) override;
 
+  gdb::byte_vector read_capability (CORE_ADDR addr) override;
+
 public: /* Remote specific methods.  */
 
   void remote_download_command_source (int num, ULONGEST addr,
@@ -2213,6 +2215,9 @@ enum {
      packets and the tag violation stop replies.  */
   PACKET_memory_tagging_feature,
 
+  /* Support for the qXfer:capa:read packet.  */
+  PACKET_qXfer_capability,
+
   PACKET_MAX
 };
 
@@ -11263,6 +11268,19 @@ remote_target::xfer_partial (enum target_object object,
        return TARGET_XFER_E_IO;
     }
 
+
+  /* Read CHERI capabilities.  */
+  if (object == TARGET_OBJECT_CAPABILITY)
+    {
+      if (readbuf)
+       return remote_read_qxfer ("capa", annex,
+                                 readbuf, offset, len, xfered_len,
+                                 &remote_protocol_packets
+                                 [PACKET_qXfer_capability]);
+      else
+       return TARGET_XFER_E_IO;
+    }
+
   /* Only handle flash writes.  */
   if (writebuf != NULL)
     {
@@ -14906,6 +14924,27 @@ test_memory_tagging_functions ()
 } // namespace selftests
 #endif /* GDB_SELF_TEST */
 
+/* Implementation of the read_capability method.  */
+
+gdb::byte_vector
+remote_target::read_capability (CORE_ADDR addr)
+{
+  gdb::optional<gdb::byte_vector> cap;
+  gdb::byte_vector cap_vec;
+
+  std::string addr_str = string_printf ("%s", phex_nz (addr, 0));
+
+  cap = target_read_alloc (current_inferior ()->top_target (),
+                          TARGET_OBJECT_CAPABILITY, addr_str.c_str ());
+
+  if (cap.has_value ())
+    cap_vec = *cap;
+  else
+    perror_with_name (_("Unable to read capability from address."));
+
+  return cap_vec;
+}
+
 void _initialize_remote ();
 void
 _initialize_remote ()
@@ -15302,6 +15341,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
   add_packet_config_cmd (&remote_protocol_packets[PACKET_memory_tagging_feature],
                         "memory-tagging-feature", "memory-tagging-feature", 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_capability],
+                        "qXfer:capa:read", "read-capability", 0);
+
   /* Assert that we've registered "set remote foo-packet" commands
      for all packet configs.  */
   {
index fd01b640f7c700f94e90190086fe74fa38cda9c1..c2e4d6e266651a74ef6349b575aaf9b12616fdcf 100644 (file)
@@ -196,6 +196,7 @@ struct dummy_target : public target_ops
   bool supports_memory_tagging () override;
   bool fetch_memtags (CORE_ADDR arg0, size_t arg1, gdb::byte_vector &arg2, int arg3) override;
   bool store_memtags (CORE_ADDR arg0, size_t arg1, const gdb::byte_vector &arg2, int arg3) override;
+  gdb::byte_vector read_capability (CORE_ADDR arg0) override;
 };
 
 struct debug_target : public target_ops
@@ -370,6 +371,7 @@ struct debug_target : public target_ops
   bool supports_memory_tagging () override;
   bool fetch_memtags (CORE_ADDR arg0, size_t arg1, gdb::byte_vector &arg2, int arg3) override;
   bool store_memtags (CORE_ADDR arg0, size_t arg1, const gdb::byte_vector &arg2, int arg3) override;
+  gdb::byte_vector read_capability (CORE_ADDR arg0) override;
 };
 
 void
@@ -4536,3 +4538,29 @@ debug_target::store_memtags (CORE_ADDR arg0, size_t arg1, const gdb::byte_vector
   return result;
 }
 
+gdb::byte_vector
+target_ops::read_capability (CORE_ADDR arg0)
+{
+  return this->beneath ()->read_capability (arg0);
+}
+
+gdb::byte_vector
+dummy_target::read_capability (CORE_ADDR arg0)
+{
+  tcomplain ();
+}
+
+gdb::byte_vector
+debug_target::read_capability (CORE_ADDR arg0)
+{
+  gdb::byte_vector result;
+  fprintf_unfiltered (gdb_stdlog, "-> %s->read_capability (...)\n", this->beneath ()->shortname ());
+  result = this->beneath ()->read_capability (arg0);
+  fprintf_unfiltered (gdb_stdlog, "<- %s->read_capability (", this->beneath ()->shortname ());
+  target_debug_print_CORE_ADDR (arg0);
+  fputs_unfiltered (") = ", gdb_stdlog);
+  target_debug_print_gdb_byte_vector (result);
+  fputs_unfiltered ("\n", gdb_stdlog);
+  return result;
+}
+
index 1ee051b520a54521e3b8c2a41de0fa94061840b0..529d28af7caaa62e70fd4d1bec8106d96235873b 100644 (file)
@@ -4291,6 +4291,14 @@ target_done_generating_core (void)
   current_inferior ()->top_target ()->done_generating_core ();
 }
 
+/* See target.h.  */
+
+gdb::byte_vector
+target_read_capability (CORE_ADDR addr)
+{
+  return current_inferior ()->top_target ()->read_capability (addr);
+}
+
 \f
 
 static char targ_desc[] =
index 4cc79df05b41e40713586b4b897bedcc9324a341..eb99cff174b28ea5843af83a15e8956317fd701b 100644 (file)
@@ -204,6 +204,8 @@ enum target_object
   TARGET_OBJECT_FREEBSD_VMMAP,
   /* FreeBSD process strings.  */
   TARGET_OBJECT_FREEBSD_PS_STRINGS,
+  /* CHERI capabilities.  */
+  TARGET_OBJECT_CAPABILITY,
   /* Possible future objects: TARGET_OBJECT_FILE, ...  */
 };
 
@@ -1320,6 +1322,10 @@ struct target_ops
     virtual bool store_memtags (CORE_ADDR address, size_t len,
                                const gdb::byte_vector &tags, int type)
       TARGET_DEFAULT_NORETURN (tcomplain ());
+
+    /* Read a capability from ADDR.  */
+    virtual gdb::byte_vector read_capability (CORE_ADDR addr)
+      TARGET_DEFAULT_NORETURN (tcomplain ());
   };
 
 /* Deleter for std::unique_ptr.  See comments in
@@ -2580,4 +2586,7 @@ extern void target_prepare_to_generate_core (void);
 /* See to_done_generating_core.  */
 extern void target_done_generating_core (void);
 
+/* See read_capability.  */
+extern gdb::byte_vector target_read_capability (CORE_ADDR addr);
+
 #endif /* !defined (TARGET_H) */
index fc54a9f2fbafe05f22aa29104f355c92d6941555..9830c5c4e5668c5b1b7ec63eb6183822ce9a809d 100644 (file)
@@ -526,9 +526,10 @@ generic_value_print_capability (struct value *val, struct ui_file *stream,
          tag = value_tag (val);
        break;
       case lval_memory:
-       /* TODO-Morello: Add hook that reads capabilities from memory.  We
-          should use those here to fetch the tag from a memory location.  */
-       tag = true;
+       {
+         struct gdbarch *gdbarch = type->arch ();
+         tag = gdbarch_get_cap_tag_from_address (gdbarch, value_address (val));
+       }
        break;
       default:
        break;
index 92769824e619328853e915101f8f15a3e86af07a..9ac3e014776681f006c6ec9ac457b5aca042455a 100644 (file)
@@ -3961,6 +3961,13 @@ value_fetch_lazy_memory (struct value *val)
       read_value_memory (val, 0, value_stack (val),
                         addr, value_contents_all_raw (val).data (),
                         type_length_units (type));
+
+  if (TYPE_CAPABILITY (type))
+    {
+      set_value_tagged (val, true);
+      bool tag = gdbarch_get_cap_tag_from_address (get_value_arch (val), addr);
+      set_value_tag (val, tag);
+    }
 }
 
 /* Helper for value_fetch_lazy when the value is in a register.  */
index d37053628fc4a03fe2a28d7e204d07b28cc3b424..682b3919ea7fffaadac2c4790e428ff8298cbc03 100644 (file)
@@ -45,6 +45,7 @@ case "${gdbserver_host}" in
                        srv_tgtobj="$srv_tgtobj linux-aarch32-tdesc.o"
                        srv_tgtobj="${srv_tgtobj} arch/aarch32.o"
                        srv_tgtobj="${srv_tgtobj} arch/arm.o"
+                       srv_tgtobj="$srv_tgtobj nat/aarch64-cap-linux.o"
                        srv_tgtobj="$srv_tgtobj nat/aarch64-linux.o"
                        srv_tgtobj="$srv_tgtobj arch/aarch64-insn.o"
                        srv_tgtobj="$srv_tgtobj arch/aarch64.o"
index 78c57b031e370d4ca3901ef1f6d01b7ed1f90033..cd68eaecc354e8a0f25e48685c12d2ea48cb3e7c 100644 (file)
@@ -97,6 +97,12 @@ public:
   bool store_memtags (CORE_ADDR address, size_t len,
                      const gdb::byte_vector &tags, int type) override;
 
+  bool supports_qxfer_capability () override;
+
+  int qxfer_capability (const CORE_ADDR address, unsigned char *readbuf,
+                       unsigned const char *writebuf,
+                       CORE_ADDR offset, int len) override;
+
 protected:
 
   void low_arch_setup () override;
@@ -3372,6 +3378,40 @@ aarch64_target::store_memtags (CORE_ADDR address, size_t len,
   return false;
 }
 
+/* Implementation of targets ops method "supports_qxfer_capability.  */
+
+bool
+aarch64_target::supports_qxfer_capability ()
+{
+  unsigned long hwcap2 = linux_get_hwcap2 (8);
+
+  return (hwcap2 & HWCAP2_MORELLO) != 0;
+}
+
+/* Implementation of targets ops method "qxfer_capability.  */
+
+int
+aarch64_target::qxfer_capability (const CORE_ADDR address,
+                                 unsigned char *readbuf,
+                                 unsigned const char *writebuf,
+                                 CORE_ADDR offset, int len)
+{
+  int tid = pid_of (current_thread);
+
+  struct user_cap cap;
+
+  if (!aarch64_linux_read_capability (tid, address, cap))
+    {
+      warning (_("Unable to read capability from address."));
+      return 0;
+    }
+
+  memcpy (readbuf, &cap.tag, 1);
+  memcpy (readbuf + 1, &cap.val, 16);
+
+  return sizeof (cap.val) + 1;
+}
+
 /* The linux target ops object.  */
 
 linux_process_target *the_linux_target = &the_aarch64_target;
index 8e53f226d3c06230070096a90683aaf0d29562b9..99dff6a383c29f1ad431aa3876b72450060c5b54 100644 (file)
@@ -2009,11 +2009,29 @@ handle_qxfer_btrace_conf (const char *annex,
   return len;
 }
 
+/* Handle qXfer:capa:read.  */
+
+static int
+handle_qxfer_capability (const char *annex, gdb_byte *readbuf,
+                        const gdb_byte *writebuf, ULONGEST offset,
+                        LONGEST len)
+{
+   if (!the_target->supports_qxfer_capability () || writebuf != NULL)
+    return -2;
+
+  CORE_ADDR addr;
+  unpack_varlen_hex (annex, &addr);
+
+  /* Read a capability and its tag.  */
+  return the_target->qxfer_capability (addr, readbuf, NULL, offset, len);
+}
+
 static const struct qxfer qxfer_packets[] =
   {
     { "auxv", handle_qxfer_auxv },
     { "btrace", handle_qxfer_btrace },
     { "btrace-conf", handle_qxfer_btrace_conf },
+    { "capa", handle_qxfer_capability },
     { "exec-file", handle_qxfer_exec_file},
     { "fdpic", handle_qxfer_fdpic},
     { "features", handle_qxfer_features },
index 5009146d66373665ea74c92ffc42a5cd0a377e9e..b20e07f93bcf07d701e20e5eb71520f78b5b3c97 100644 (file)
@@ -532,6 +532,21 @@ process_stratum_target::qxfer_siginfo (const char *annex,
   gdb_assert_not_reached ("target op qxfer_siginfo not supported");
 }
 
+bool
+process_stratum_target::supports_qxfer_capability ()
+{
+  return false;
+}
+
+int
+process_stratum_target::qxfer_capability (const CORE_ADDR address,
+                                         unsigned char *readbuf,
+                                         unsigned const char *writebuf,
+                                         CORE_ADDR offset, int len)
+{
+  gdb_assert_not_reached ("target op qxfer_capability not supported");
+}
+
 bool
 process_stratum_target::supports_non_stop ()
 {
index aaa9dab742c2bfcc0997589f9b643e98b5b00e0e..55ce2dec366e145edf4f23115a5cb55382bcf910 100644 (file)
@@ -264,6 +264,14 @@ public:
                            unsigned const char *writebuf,
                            CORE_ADDR offset, int len);
 
+  /* Return true if the qxfer_capability target op is supported.  */
+  virtual bool supports_qxfer_capability ();
+
+  /* Read a capability using qXfer packets.  */
+  virtual int qxfer_capability (const CORE_ADDR address, unsigned char *readbuf,
+                               unsigned const char *writebuf, CORE_ADDR offset,
+                               int len);
+
   /* Return true if the qxfer_siginfo target op is supported.  */
   virtual bool supports_qxfer_siginfo ();