const gdb::byte_vector &tags, int type) 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;
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
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."));
+}
+
void _initialize_aarch64_linux_nat ();
void
_initialize_aarch64_linux_nat ()
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);
+
/* Register the target. */
linux_target = &the_aarch64_linux_nat_target;
add_inf_child_target (&the_aarch64_linux_nat_target);
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;
+}
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 */
const gdb::byte_vector &tags, int type) 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. */
packets and the tag violation stop replies. */
PACKET_memory_tagging_feature,
- /* Support for the qXfer:capa:read packet. */
+ /* Support for the qXfer:capa:read and qXfer:capa:write packets. */
PACKET_qXfer_capability,
PACKET_MAX
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;
}
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_inferior ()->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 ()
"memory-tagging-feature", "memory-tagging-feature", 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. */
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) \
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;
+ bool write_capability (CORE_ADDR arg0, gdb::array_view<const gdb_byte> arg1) override;
};
struct debug_target : public target_ops
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;
+ bool write_capability (CORE_ADDR arg0, gdb::array_view<const gdb_byte> arg1) override;
};
void
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;
+}
+
return current_inferior ()->top_target ()->read_capability (addr);
}
+/* See target.h. */
+
+bool
+target_write_capability (CORE_ADDR addr,
+ gdb::array_view<const gdb_byte> buffer)
+{
+ return current_inferior ()->top_target ()->write_capability (addr, buffer);
+}
+
\f
static char targ_desc[] =
/* 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
/* 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) */
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;
}
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[] =