]> 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)
committerLuis Machado <luis.machado@linaro.org>
Fri, 15 Jan 2021 21:55:46 +0000 (18:55 -0300)
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.

23 files changed:
gdb/ChangeLog
gdb/aarch64-linux-nat.c
gdb/aarch64-linux-tdep.c
gdb/arch-utils.c
gdb/arch-utils.h
gdb/configure.nat
gdb/gdbarch.c
gdb/gdbarch.h
gdb/gdbarch.sh
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/ChangeLog
gdbserver/configure.srv
gdbserver/linux-aarch64-low.cc
gdbserver/server.cc
gdbserver/target.cc
gdbserver/target.h

index f454cf3c1f23c460b7ef18a9432504b28befc077..3634fbe030daae9677580748581645c3c8460dee 100644 (file)
@@ -1,3 +1,38 @@
+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.
+
 2021-01-15  Luis Machado  <luis.machado@arm.com>
 
        * aarch64-tdep.c (aarch64_prologue_prev_register)
index 91130520db8e07530cc1889deefb94093b251b6b..5bc7ef2f3f033d63f1def034113a69a22084b207 100644 (file)
@@ -102,6 +102,7 @@ public:
     override;
 
   struct gdbarch *thread_architecture (ptid_t) override;
+  gdb::byte_vector read_capability (CORE_ADDR addr) override;
 };
 
 static aarch64_linux_nat_target the_aarch64_linux_nat_target;
@@ -1056,6 +1057,40 @@ aarch64_linux_nat_target::thread_architecture (ptid_t ptid)
   return gdbarch_find_by_info (info);
 }
 
+/* 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);
+}
+
 /* Define AArch64 maintenance commands.  */
 
 static void
@@ -1075,6 +1110,10 @@ triggers a breakpoint or watchpoint."),
                           NULL,
                           &maintenance_set_cmdlist,
                           &maintenance_show_cmdlist);
+
+  add_cmd ("cap_from_addr", class_maintenance, maint_print_cap_from_addr_cmd, _("\
+Print the capability from addr."),
+                &maintenanceprintlist);
 }
 
 void _initialize_aarch64_linux_nat ();
index 9c4d27610c0fd58f4ccb74186f2540b8f81788cb..42e04ee423ffca1239025917ac7d6fd6e9637fa8 100644 (file)
@@ -32,6 +32,7 @@
 #include "tramp-frame.h"
 #include "trad-frame.h"
 #include "target/target.h"
+#include "target.h"
 
 #include "regcache.h"
 #include "regset.h"
@@ -1613,6 +1614,22 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
   uiout->text ("\n");
 }
 
+/* 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)
 {
@@ -1850,6 +1867,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 c68add668dbda56b1944c066131f0df0fd2458dc..2136e8a22257be25c32e95b80eda32d76677ae62 100644 (file)
@@ -1070,6 +1070,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;
+}
+
 void _initialize_gdbarch_utils ();
 void
 _initialize_gdbarch_utils ()
index b23dc17cb337e88110c78c3391be873dcbebf8e6..fb35d731a428206a23ceaaff20859a69e0371b81 100644 (file)
@@ -302,4 +302,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 ef2218f0b8d4debca2ef07e42671019105ee61dd..aa5d4c8dcb6d3a492602db7e718b1cbf69383095 100644 (file)
@@ -235,7 +235,7 @@ case ${gdb_host} in
                #  Host: AArch64 based machine running GNU/Linux
                NATDEPFILES="${NATDEPFILES} aarch64-linux-nat.o \
                aarch32-linux-nat.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"
                ;;
            arm)
index 00f6272243649958b15dbe76b2127bcae7531be8..b79a1bcd492e7a9ec33f2a31c347217c8631a4c2 100644 (file)
@@ -242,6 +242,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;
@@ -428,6 +429,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;
@@ -619,6 +621,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 */
@@ -1074,6 +1077,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                       "gdbarch_dump: gen_return_address = <%s>\n",
                       host_address_to_string (gdbarch->gen_return_address));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: get_cap_tag_from_address = <%s>\n",
+                      host_address_to_string (gdbarch->get_cap_tag_from_address));
   fprintf_unfiltered (file,
                       "gdbarch_dump: gdbarch_get_longjmp_target_p() = %d\n",
                       gdbarch_get_longjmp_target_p (gdbarch));
@@ -3068,6 +3074,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;
+}
+
 int
 gdbarch_fetch_tls_load_module_address_p (struct gdbarch *gdbarch)
 {
index b36dbd0ab202327e0b53efd2a6f2bbc19ff47228..a1d9895c967ae4f538447e2171c263ab853b8c7b 100644 (file)
@@ -639,6 +639,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 int gdbarch_fetch_tls_load_module_address_p (struct gdbarch *gdbarch);
index f7f727611fcf15b16aae10128e213877ed62ddea..9aabc1eda42fc939a4c36b2c4ba38c43d8a2efa4 100755 (executable)
@@ -571,6 +571,9 @@ v;CORE_ADDR;deprecated_function_start_offset;;;0;;;0
 # register.  Normally the identity mapping.
 m;int;remote_register_number;int regno;regno;;default_remote_register_number;;0
 
+# Return the tag from a capability stored at address ADDR.
+m;bool;get_cap_tag_from_address;CORE_ADDR addr;addr;0;default_get_cap_tag_from_address;;0
+
 # Fetch the target specific address used to represent a load module.
 F;CORE_ADDR;fetch_tls_load_module_address;struct objfile *objfile;objfile
 
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 9ee1e8cbcf9e9e1b9e3025d0ed94c23d06f4a2c6..5abf8d3ed36faa8af3fd55b94d45288cb6c009fc 100644 (file)
@@ -686,6 +686,8 @@ public:
   int remove_exec_catchpoint (int) override;
   enum exec_direction_kind execution_direction () override;
 
+  gdb::byte_vector read_capability (CORE_ADDR addr) override;
+
 public: /* Remote specific methods.  */
 
   void remote_download_command_source (int num, ULONGEST addr,
@@ -2094,6 +2096,9 @@ enum {
   /* Support TARGET_WAITKIND_NO_RESUMED.  */
   PACKET_no_resumed,
 
+  /* Support for the qXfer:capa:read packet.  */
+  PACKET_qXfer_capability,
+
   PACKET_MAX
 };
 
@@ -11016,6 +11021,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)
     {
@@ -14387,6 +14405,27 @@ set_range_stepping (const char *ignore_args, int from_tty,
     }
 }
 
+/* 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_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 ()
@@ -14786,6 +14825,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
   add_packet_config_cmd (&remote_protocol_packets[PACKET_no_resumed],
                         "N stop reply", "no-resumed-stop-reply", 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 e9c349fb7ba0677559f3a0b4d6d7b2c17132491c..0475538e904f91ee2ba9ba3cebca06d38b7c06dd 100644 (file)
@@ -173,6 +173,7 @@ struct dummy_target : public target_ops
   const struct frame_unwind *get_tailcall_unwinder () override;
   void prepare_to_generate_core () override;
   void done_generating_core () override;
+  gdb::byte_vector read_capability (CORE_ADDR arg0) override;
 };
 
 struct debug_target : public target_ops
@@ -344,6 +345,7 @@ struct debug_target : public target_ops
   const struct frame_unwind *get_tailcall_unwinder () override;
   void prepare_to_generate_core () override;
   void done_generating_core () override;
+  gdb::byte_vector read_capability (CORE_ADDR arg0) override;
 };
 
 void
@@ -4413,3 +4415,29 @@ debug_target::done_generating_core ()
   fputs_unfiltered (")\n", gdb_stdlog);
 }
 
+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 a111ea3c333661da5fd312eaa321307a97ee7ccf..a7f0597339aee0b747950e727102d3fba7c17f77 100644 (file)
@@ -3603,6 +3603,14 @@ target_done_generating_core (void)
   current_top_target ()->done_generating_core ();
 }
 
+/* See target.h.  */
+
+gdb::byte_vector
+target_read_capability (CORE_ADDR addr)
+{
+  return current_top_target ()->read_capability (addr);
+}
+
 \f
 
 static char targ_desc[] =
index 7e152fa6e151eee183b5c5550f507a09c7596926..87e91f5f944abf41607c1b5f3f8ce68bb06c57e5 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, ...  */
 };
 
@@ -1260,6 +1262,10 @@ struct target_ops
     /* Cleanup after generating a core file.  */
     virtual void done_generating_core ()
       TARGET_DEFAULT_IGNORE ();
+
+    /* 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
@@ -2585,4 +2591,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 3794e6c13267c4b65ae5afb55c53f1e47b9bb9f6..8c0a72c40aef3cb90115652bbb803360c14c3eea 100644 (file)
@@ -511,9 +511,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 = get_type_arch (type);
+         tag = gdbarch_get_cap_tag_from_address (gdbarch, value_address (val));
+       }
        break;
       default:
        break;
index 01f47af7466ee0938762d97d2236043cdafb6f16..bea273ab7d11e65dcfaf142b531b0972996c6572 100644 (file)
@@ -3854,6 +3854,13 @@ value_fetch_lazy_memory (struct value *val)
       read_value_memory (val, 0, value_stack (val),
                         addr, value_contents_all_raw (val),
                         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 e4bccab0cd03ab78b7bcb8fde02f5fc418e31df9..f7e079ee988510c5b498cd17d3bc81eff5e52d9f 100644 (file)
@@ -1,3 +1,18 @@
+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.
+
 2021-01-15  Luis Machado  <luis.machado@arm.com>
 
        * linux-aarch64-low.cc: Include nat/aarch64-cap-linux.h.
index 833ad27c4c4d17e0346060a53cdbf935f892aa87..f2d4905441f53a288048b5f3141b83e45ac6baa0 100644 (file)
@@ -49,6 +49,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 4fe7e536d18b54e6a91eee91b225bbb1bb6658fe..1cc3e35e6fecdd13bc3af9bd30b1a33946d2c97f 100644 (file)
@@ -83,6 +83,12 @@ public:
 
   struct emit_ops *emit_ops () 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;
@@ -3210,6 +3216,40 @@ aarch64_target::breakpoint_kind_from_current_state (CORE_ADDR *pcptr)
     return arm_breakpoint_kind_from_current_state (pcptr);
 }
 
+/* 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 4a211a481873371adccb287546a3d3bd6d558bc0..c62dac5cd36b5c6df6dc872a43afb2c1b772f9b5 100644 (file)
@@ -1906,11 +1906,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 921d26fcf79ca992dedde3213a65250867a5aaf8..2693bd5843af0c36b852cbcc07d02c3e6a782f1d 100644 (file)
@@ -521,6 +521,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 c2245ebfe85aeb627d09cb9d8ee3e08d0a5277e2..fbffc96085aab6bf7d194ea4c76b45e0f7f00823 100644 (file)
@@ -267,6 +267,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 ();