From: Luis Machado Date: Mon, 21 Dec 2020 14:44:23 +0000 (-0300) Subject: Read capability tags from memory X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c7c3ac5d096c8287050bc988dc799c95d024b8b4;p=thirdparty%2Fbinutils-gdb.git Read capability tags from memory 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 * aarch64-linux-nat.c (aarch64_linux_nat_target) : 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) : 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) : New enum field. (struct target_ops) : 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 * configure.srv: Add nat/aarch64-cap-linux.o to the list of object files for AArch64-Linux * linux-aarch64-low.cc (aarch64_target) : 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) : New virtual member functions. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index f454cf3c1f2..3634fbe030d 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,38 @@ +2021-01-15 Luis Machado + + * aarch64-linux-nat.c (aarch64_linux_nat_target) + : 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) : 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) : New enum field. + (struct target_ops) : 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 * aarch64-tdep.c (aarch64_prologue_prev_register) diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c index 91130520db8..5bc7ef2f3f0 100644 --- a/gdb/aarch64-linux-nat.c +++ b/gdb/aarch64-linux-nat.c @@ -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 (); diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c index 9c4d27610c0..42e04ee423f 100644 --- a/gdb/aarch64-linux-tdep.c +++ b/gdb/aarch64-linux-tdep.c @@ -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 { diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index c68add668db..2136e8a2225 100644 --- a/gdb/arch-utils.c +++ b/gdb/arch-utils.c @@ -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 () diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h index b23dc17cb33..fb35d731a42 100644 --- a/gdb/arch-utils.h +++ b/gdb/arch-utils.h @@ -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 */ diff --git a/gdb/configure.nat b/gdb/configure.nat index ef2218f0b8d..aa5d4c8dcb6 100644 --- a/gdb/configure.nat +++ b/gdb/configure.nat @@ -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) diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index 00f62722436..b79a1bcd492 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -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) { diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index b36dbd0ab20..a1d9895c967 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -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); diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index f7f727611fc..9aabc1eda42 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -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 index 00000000000..cd204d11e47 --- /dev/null +++ b/gdb/nat/aarch64-cap-linux.c @@ -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 . */ + +#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; +} diff --git a/gdb/nat/aarch64-cap-linux.h b/gdb/nat/aarch64-cap-linux.h index 2b3c1dc5f3e..b5394704e4f 100644 --- a/gdb/nat/aarch64-cap-linux.h +++ b/gdb/nat/aarch64-cap-linux.h @@ -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 */ diff --git a/gdb/remote.c b/gdb/remote.c index 9ee1e8cbcf9..5abf8d3ed36 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -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 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. */ { diff --git a/gdb/target-delegates.c b/gdb/target-delegates.c index e9c349fb7ba..0475538e904 100644 --- a/gdb/target-delegates.c +++ b/gdb/target-delegates.c @@ -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; +} + diff --git a/gdb/target.c b/gdb/target.c index a111ea3c333..a7f0597339a 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -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); +} + static char targ_desc[] = diff --git a/gdb/target.h b/gdb/target.h index 7e152fa6e15..87e91f5f944 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -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) */ diff --git a/gdb/valprint.c b/gdb/valprint.c index 3794e6c1326..8c0a72c40ae 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -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; diff --git a/gdb/value.c b/gdb/value.c index 01f47af7466..bea273ab7d1 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -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. */ diff --git a/gdbserver/ChangeLog b/gdbserver/ChangeLog index e4bccab0cd0..f7e079ee988 100644 --- a/gdbserver/ChangeLog +++ b/gdbserver/ChangeLog @@ -1,3 +1,18 @@ +2021-01-15 Luis Machado + + * configure.srv: Add nat/aarch64-cap-linux.o to the list of object + files for AArch64-Linux + * linux-aarch64-low.cc (aarch64_target) + : 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) + : New virtual member functions. + 2021-01-15 Luis Machado * linux-aarch64-low.cc: Include nat/aarch64-cap-linux.h. diff --git a/gdbserver/configure.srv b/gdbserver/configure.srv index 833ad27c4c4..f2d4905441f 100644 --- a/gdbserver/configure.srv +++ b/gdbserver/configure.srv @@ -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" diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc index 4fe7e536d18..1cc3e35e6fe 100644 --- a/gdbserver/linux-aarch64-low.cc +++ b/gdbserver/linux-aarch64-low.cc @@ -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; diff --git a/gdbserver/server.cc b/gdbserver/server.cc index 4a211a48187..c62dac5cd36 100644 --- a/gdbserver/server.cc +++ b/gdbserver/server.cc @@ -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 }, diff --git a/gdbserver/target.cc b/gdbserver/target.cc index 921d26fcf79..2693bd5843a 100644 --- a/gdbserver/target.cc +++ b/gdbserver/target.cc @@ -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 () { diff --git a/gdbserver/target.h b/gdbserver/target.h index c2245ebfe85..fbffc96085a 100644 --- a/gdbserver/target.h +++ b/gdbserver/target.h @@ -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 ();