]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Enable capability writes to memory
authorLuis Machado <luis.machado@linaro.org>
Tue, 12 Jan 2021 18:53:00 +0000 (15:53 -0300)
committerLuis Machado <luis.machado@linaro.org>
Wed, 17 Mar 2021 13:40:01 +0000 (10:40 -0300)
Enable writing/forging capabilities to memory via the PTRACE_POKECAP ptrace
request.  This patch enables both GDB and gdbserver for Morello.

For remote writes, we use the qXfer:capa:write packet.

gdb/ChangeLog:

2021-03-17  Luis Machado  <luis.machado@arm.com>

* aarch64-linux-nat.c (aarch64_linux_nat_target)
<write_capability>: New member function override.
(aarch64_linux_nat_target::write_capability): New member
function.
(maint_print_cap_from_addr_cmd): Adjust printing format.
(maint_set_capability_in_memory_cmd): New maintenance function.
(add_show_debug_regs_command): Register new maintenance command.
* nat/aarch64-cap-linux.c (aarch64_linux_write_capability): New
function.
* nat/aarch64-cap-linux.h (aarch64_linux_write_capability): New
prototype.
* remote.c (remote_target)
<write_capability>: New member function override.
Adjust enum documentation for PACKET_qXfer_capability.
(remote_target::write_capability): New member function.
(_initialize_remote): Adjust documentation for
PACKET_qXfer_capability.
* target-debug.h
(target_debug_print_gdb_array_view_const_gdb_byte): New macro.
* target-delegates.c: Regenerate.
* target.c (target_write_capability): New function.
* target.h (struct target_ops) <write_capability>: New virtual member
function.
(target_write_capability): New prototype.

gdbserver/ChangeLog:

2021-03-17  Luis Machado  <luis.machado@arm.com>

* linux-aarch64-low.cc (aarch64_target::qxfer_capability): Handle
capability writes.
* server.cc (handle_qxfer_capability): Likewise.

12 files changed:
gdb/ChangeLog
gdb/aarch64-linux-nat.c
gdb/nat/aarch64-cap-linux.c
gdb/nat/aarch64-cap-linux.h
gdb/remote.c
gdb/target-debug.h
gdb/target-delegates.c
gdb/target.c
gdb/target.h
gdbserver/ChangeLog
gdbserver/linux-aarch64-low.cc
gdbserver/server.cc

index 02fc5b8c149f0dc17bcfd7ebcd70868de10528fd..67c68e473adec34af1fedc69e5e17208552bdb45 100644 (file)
@@ -1,3 +1,30 @@
+2021-03-17  Luis Machado  <luis.machado@arm.com>
+
+       * aarch64-linux-nat.c (aarch64_linux_nat_target)
+       <write_capability>: New member function override.
+       (aarch64_linux_nat_target::write_capability): New member
+       function.
+       (maint_print_cap_from_addr_cmd): Adjust printing format.
+       (maint_set_capability_in_memory_cmd): New maintenance function.
+       (add_show_debug_regs_command): Register new maintenance command.
+       * nat/aarch64-cap-linux.c (aarch64_linux_write_capability): New
+       function.
+       * nat/aarch64-cap-linux.h (aarch64_linux_write_capability): New
+       prototype.
+       * remote.c (remote_target)
+       <write_capability>: New member function override.
+       Adjust enum documentation for PACKET_qXfer_capability.
+       (remote_target::write_capability): New member function.
+       (_initialize_remote): Adjust documentation for
+       PACKET_qXfer_capability.
+       * target-debug.h
+       (target_debug_print_gdb_array_view_const_gdb_byte): New macro.
+       * target-delegates.c: Regenerate.
+       * target.c (target_write_capability): New function.
+       * target.h (struct target_ops) <write_capability>: New virtual member
+       function.
+       (target_write_capability): New prototype.
+
 2021-03-17  Luis Machado  <luis.machado@arm.com>
 
        * aarch64-tdep.c (aarch64_register_tag): Handle PCC/CSP tag
index 4891bcea90be3751752413d0c912e8535fced9d1..4b74c423f5d092de5006dce1de297a8d75259270 100644 (file)
@@ -103,6 +103,8 @@ public:
 
   struct gdbarch *thread_architecture (ptid_t) override;
   gdb::byte_vector read_capability (CORE_ADDR addr) override;
+  bool write_capability (CORE_ADDR addr,
+                        gdb::array_view<const gdb_byte> buffer) override;
 };
 
 static aarch64_linux_nat_target the_aarch64_linux_nat_target;
@@ -1107,6 +1109,25 @@ aarch64_linux_nat_target::read_capability (CORE_ADDR addr)
   return cap_vec;
 }
 
+/* Implement the "write_capability" target_ops method.  */
+
+bool
+aarch64_linux_nat_target::write_capability (CORE_ADDR addr,
+                                           gdb::array_view<const gdb_byte> buffer)
+{
+  int tid = get_ptrace_pid (inferior_ptid);
+
+  struct user_cap cap;
+
+  memcpy (&cap.tag, buffer.data (), 1);
+  memcpy (&cap.val, buffer.data () + 1, 16);
+
+  if (!aarch64_linux_write_capability (tid, addr, cap))
+    perror_with_name (_("Unable to write capability from address."));
+
+  return true;
+}
+
 /* Implement the maintenance print capability tag command.  */
 
 static void
@@ -1117,11 +1138,47 @@ maint_print_cap_from_addr_cmd (const char *args, int from_tty)
   cap = target_read_capability (addr);
 
   for (auto it : cap)
-    fprintf_unfiltered (gdb_stdlog, "%x ", it);
+    fprintf_unfiltered (gdb_stdlog, "%02x ", it);
 
   fputs_unfiltered ("\n", gdb_stdlog);
 }
 
+/* Implement the maintenance set capability in memory command.  */
+
+static void
+maint_set_capability_in_memory_cmd (const char *args, int from_tty)
+{
+  std::string addr_str, tag_str, upper_str, lower_str;
+  const char *args_ptr = args;
+
+  addr_str = extract_string_maybe_quoted (&args_ptr);
+  tag_str = extract_string_maybe_quoted (&args_ptr);
+  upper_str = extract_string_maybe_quoted (&args_ptr);
+  lower_str = extract_string_maybe_quoted (&args_ptr);
+
+  CORE_ADDR addr = parse_and_eval_address (addr_str.c_str ());
+  CORE_ADDR tag_part = parse_and_eval_address (tag_str.c_str ());
+  CORE_ADDR half_a = parse_and_eval_address (upper_str.c_str ());
+  CORE_ADDR half_b = parse_and_eval_address (lower_str.c_str ());
+
+  unsigned __int128 a, b;
+
+  a = half_a;
+  b = half_b;
+
+  a = (a << 64) | b;
+  bool tag = (tag_part != 0)? true : false;
+
+  gdb::byte_vector cap;
+
+  cap.resize (17);
+  memcpy (cap.data (), &tag, 1);
+  memcpy (cap.data () + 1, &a, 16);
+
+  if (!target_write_capability (addr, {cap.data (), cap.size ()}))
+    perror_with_name (_("Failed to set capability in memory."));
+}
+
 /* Define AArch64 maintenance commands.  */
 
 static void
@@ -1145,6 +1202,10 @@ triggers a breakpoint or watchpoint."),
   add_cmd ("cap_from_addr", class_maintenance, maint_print_cap_from_addr_cmd, _("\
 Print the capability from addr."),
                 &maintenanceprintlist);
+
+  add_cmd ("cap_in_memory", class_maintenance,
+          maint_set_capability_in_memory_cmd,
+          _("Print the capability from addr."), &maintenancelist);
 }
 
 void _initialize_aarch64_linux_nat ();
index cd204d11e479651d3597536b2c7f80296a12dd2b..1b427803c1636deb34803310bf96eef8210bd7aa 100644 (file)
@@ -35,3 +35,16 @@ aarch64_linux_read_capability (int tid, CORE_ADDR address,
 
   return true;
 }
+
+/* See aarch64-cap-linux.h */
+
+bool
+aarch64_linux_write_capability (int tid, CORE_ADDR address,
+                               const user_cap &cap)
+{
+  /* Fetch the tag from ptrace.  */
+  if (ptrace (PTRACE_POKECAP, tid, address, &cap) < 0)
+    return false;
+
+  return true;
+}
index b5394704e4ff0bdb3bb9ea7ad1db606498d7fa1c..3dc582a4c94d53fd049fde664ad508420e9ae865 100644 (file)
@@ -65,4 +65,11 @@ struct user_cap {
 
 extern bool aarch64_linux_read_capability (int tid, CORE_ADDR address,
                                           user_cap &cap);
+
+/* For thread TID, write capability CAP to the memory address ADDRESS.
+
+   Return true if successful and false otherwise.  */
+
+extern bool aarch64_linux_write_capability (int tid, CORE_ADDR address,
+                                           const user_cap &cap);
 #endif /* NAT_AARCH64_CAP_LINUX_H */
index 5abf8d3ed36faa8af3fd55b94d45288cb6c009fc..5fff3520e0db5970133199b5ba5b3aeb9a746490 100644 (file)
@@ -687,6 +687,8 @@ public:
   enum exec_direction_kind execution_direction () override;
 
   gdb::byte_vector read_capability (CORE_ADDR addr) override;
+  bool write_capability (CORE_ADDR addr,
+                        gdb::array_view<const gdb_byte> buffer) override;
 
 public: /* Remote specific methods.  */
 
@@ -2096,7 +2098,7 @@ enum {
   /* Support TARGET_WAITKIND_NO_RESUMED.  */
   PACKET_no_resumed,
 
-  /* Support for the qXfer:capa:read packet.  */
+  /* Support for the qXfer:capa:read and qXfer:capa:write packets.  */
   PACKET_qXfer_capability,
 
   PACKET_MAX
@@ -11030,6 +11032,10 @@ remote_target::xfer_partial (enum target_object object,
                                  readbuf, offset, len, xfered_len,
                                  &remote_protocol_packets
                                  [PACKET_qXfer_capability]);
+      else if (writebuf)
+       return remote_write_qxfer ("capa", annex, writebuf, offset, len,
+                                  xfered_len, &remote_protocol_packets
+                                  [PACKET_qXfer_capability]);
       else
        return TARGET_XFER_E_IO;
     }
@@ -14426,6 +14432,27 @@ remote_target::read_capability (CORE_ADDR addr)
   return cap_vec;
 }
 
+/* Implementation of the write_capability method.  */
+
+bool
+remote_target::write_capability (CORE_ADDR addr,
+                                gdb::array_view<const gdb_byte> buffer)
+{
+  gdb_assert (!buffer.empty ());
+  std::string addr_str = string_printf ("%s", phex_nz (addr, 0));
+  ULONGEST xfered_len;
+  enum target_xfer_status status;
+
+  status = target_xfer_partial (current_top_target (), TARGET_OBJECT_CAPABILITY,
+                               addr_str.c_str (), nullptr, buffer.data (), 0,
+                               buffer.size (), &xfered_len);
+
+  if (status != TARGET_XFER_OK)
+    perror_with_name (_("Unable to write capability to address."));
+
+  return true;
+}
+
 void _initialize_remote ();
 void
 _initialize_remote ()
@@ -14826,7 +14853,7 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
                         "N stop reply", "no-resumed-stop-reply", 0);
 
   add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_capability],
-                        "qXfer:capa:read", "read-capability", 0);
+                        "qXfer:capa:read", "read-write-capability", 0);
 
   /* Assert that we've registered "set remote foo-packet" commands
      for all packet configs.  */
index 65a14c41787432e6ece93c5c1b96cef1b064a043..9c15e103ad4f7bfecf41284b3d9bf43d5841599a 100644 (file)
   target_debug_do_print (host_address_to_string (X.get ()))
 #define target_debug_print_gdb_array_view_const_int(X) \
   target_debug_do_print (host_address_to_string (X.data ()))
+#define target_debug_print_gdb_array_view_const_gdb_byte(X)    \
+  target_debug_do_print (host_address_to_string (X.data ()))
 #define target_debug_print_inferior_p(inf) \
   target_debug_do_print (host_address_to_string (inf))
 #define target_debug_print_record_print_flags(X) \
index 0475538e904f91ee2ba9ba3cebca06d38b7c06dd..c949d9e5c1ff358d73e4e86cffd369f5b0236566 100644 (file)
@@ -174,6 +174,7 @@ struct dummy_target : public target_ops
   void prepare_to_generate_core () override;
   void done_generating_core () override;
   gdb::byte_vector read_capability (CORE_ADDR arg0) override;
+  bool write_capability (CORE_ADDR arg0, gdb::array_view<const gdb_byte> arg1) override;
 };
 
 struct debug_target : public target_ops
@@ -346,6 +347,7 @@ struct debug_target : public target_ops
   void prepare_to_generate_core () override;
   void done_generating_core () override;
   gdb::byte_vector read_capability (CORE_ADDR arg0) override;
+  bool write_capability (CORE_ADDR arg0, gdb::array_view<const gdb_byte> arg1) override;
 };
 
 void
@@ -4441,3 +4443,31 @@ debug_target::read_capability (CORE_ADDR arg0)
   return result;
 }
 
+bool
+target_ops::write_capability (CORE_ADDR arg0, gdb::array_view<const gdb_byte> arg1)
+{
+  return this->beneath ()->write_capability (arg0, arg1);
+}
+
+bool
+dummy_target::write_capability (CORE_ADDR arg0, gdb::array_view<const gdb_byte> arg1)
+{
+  tcomplain ();
+}
+
+bool
+debug_target::write_capability (CORE_ADDR arg0, gdb::array_view<const gdb_byte> arg1)
+{
+  bool result;
+  fprintf_unfiltered (gdb_stdlog, "-> %s->write_capability (...)\n", this->beneath ()->shortname ());
+  result = this->beneath ()->write_capability (arg0, arg1);
+  fprintf_unfiltered (gdb_stdlog, "<- %s->write_capability (", this->beneath ()->shortname ());
+  target_debug_print_CORE_ADDR (arg0);
+  fputs_unfiltered (", ", gdb_stdlog);
+  target_debug_print_gdb_array_view_const_gdb_byte (arg1);
+  fputs_unfiltered (") = ", gdb_stdlog);
+  target_debug_print_bool (result);
+  fputs_unfiltered ("\n", gdb_stdlog);
+  return result;
+}
+
index a7f0597339aee0b747950e727102d3fba7c17f77..4789e24673660d5df7d7cc9ef4e3781911fd655b 100644 (file)
@@ -3611,6 +3611,15 @@ target_read_capability (CORE_ADDR addr)
   return current_top_target ()->read_capability (addr);
 }
 
+/* See target.h.  */
+
+bool
+target_write_capability (CORE_ADDR addr,
+                        gdb::array_view<const gdb_byte> buffer)
+{
+  return current_top_target ()->write_capability (addr, buffer);
+}
+
 \f
 
 static char targ_desc[] =
index 87e91f5f944abf41607c1b5f3f8ce68bb06c57e5..0c1ad48e07ee3f096516c898a6e5eace81439329 100644 (file)
@@ -1266,6 +1266,11 @@ struct target_ops
     /* Read a capability from ADDR.  */
     virtual gdb::byte_vector read_capability (CORE_ADDR addr)
       TARGET_DEFAULT_NORETURN (tcomplain ());
+
+    /* Write CAPABILITY to ADDR.  */
+    virtual bool write_capability (CORE_ADDR addr,
+                                  gdb::array_view<const gdb_byte> buffer)
+      TARGET_DEFAULT_NORETURN (tcomplain ());
   };
 
 /* Deleter for std::unique_ptr.  See comments in
@@ -2594,4 +2599,8 @@ extern void target_done_generating_core (void);
 /* See read_capability.  */
 extern gdb::byte_vector target_read_capability (CORE_ADDR addr);
 
+/* See write_capability.  */
+extern bool target_write_capability (CORE_ADDR addr,
+                                    gdb::array_view<const gdb_byte> buffer);
+
 #endif /* !defined (TARGET_H) */
index 8ff020978898dc3a5fea8d8e76972c35d15b32f1..a56de0f53775fcf85f2aa8aaad702f7fc99b86f2 100644 (file)
@@ -1,3 +1,9 @@
+2021-03-17  Luis Machado  <luis.machado@arm.com>
+
+       * linux-aarch64-low.cc (aarch64_target::qxfer_capability): Handle
+       capability writes.
+       * server.cc (handle_qxfer_capability): Likewise.
+
 2021-01-15  Luis Machado  <luis.machado@arm.com>
 
        * linux-aarch64-low.cc (aarch64_fill_cregset): New function.
index 3919b126d3ecc0208af52b5439b1551bf85b5a9e..d0eaff553ae34c6f36834b8dc1fa7e669accc019 100644 (file)
@@ -3268,14 +3268,31 @@ aarch64_target::qxfer_capability (const CORE_ADDR address,
 
   struct user_cap cap;
 
-  if (!aarch64_linux_read_capability (tid, address, cap))
+  if (readbuf != nullptr)
     {
-      warning (_("Unable to read capability from address."));
-      return 0;
+      if (!aarch64_linux_read_capability (tid, address, cap))
+       {
+         warning (_("Unable to read capability from address."));
+         return 0;
+       }
+
+      /* Copy data to readbuf.  */
+      memcpy (readbuf, &cap.tag, 1);
+      memcpy (readbuf + 1, &cap.val, 16);
     }
+  else
+    {
+      /* Copy data from writebuf.  */
+      memcpy (&cap.tag, writebuf, 1);
+      memcpy (&cap.val, writebuf + 1, 16);
+      memset (&cap.__reserved, 0, 15);
 
-  memcpy (readbuf, &cap.tag, 1);
-  memcpy (readbuf + 1, &cap.val, 16);
+      if (!aarch64_linux_write_capability (tid, address, cap))
+       {
+         warning (_("Unable to write capability to address."));
+         return 0;
+       }
+    }
 
   return sizeof (cap.val) + 1;
 }
index c62dac5cd36b5c6df6dc872a43afb2c1b772f9b5..c40eda5eac3c8673502cd5edb3687b3c341ed2e6 100644 (file)
@@ -1913,14 +1913,27 @@ 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)
+  if (!the_target->supports_qxfer_capability ())
     return -2;
 
+  gdb_assert (readbuf != nullptr || writebuf != nullptr);
+
   CORE_ADDR addr;
   unpack_varlen_hex (annex, &addr);
 
-  /* Read a capability and its tag.  */
-  return the_target->qxfer_capability (addr, readbuf, NULL, offset, len);
+  if (readbuf != nullptr)
+    {
+      /* Read a capability and its tag.  */
+      return the_target->qxfer_capability (addr, readbuf, nullptr, offset, len);
+    }
+  else
+    {
+      /* Write a capability to memory.  */
+      return the_target->qxfer_capability (addr, nullptr, writebuf, offset,
+                                          len);
+    }
+
+  return -2;
 }
 
 static const struct qxfer qxfer_packets[] =