X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdbserver%2Flinux-aarch64-low.cc;h=9a8cb4169a7101ef911fe7a70dba8c9c17316190;hb=eb79b2318066cafb75ffdce310e3bbd44f7c79e3;hp=44f729386cdfa34dfcb399a348c1756c99f31ef3;hpb=797bcff595c5e161b333077299fcaca19bb4fd17;p=deliverable%2Fbinutils-gdb.git diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc index 44f729386c..9a8cb4169a 100644 --- a/gdbserver/linux-aarch64-low.cc +++ b/gdbserver/linux-aarch64-low.cc @@ -1,7 +1,7 @@ /* GNU/Linux/AArch64 specific low level interface, for the remote server for GDB. - Copyright (C) 2009-2020 Free Software Foundation, Inc. + Copyright (C) 2009-2021 Free Software Foundation, Inc. Contributed by ARM Ltd. This file is part of GDB. @@ -40,8 +40,10 @@ #include "gdb_proc_service.h" #include "arch/aarch64.h" +#include "arch/aarch64-mte-linux.h" #include "linux-aarch32-tdesc.h" #include "linux-aarch64-tdesc.h" +#include "nat/aarch64-mte-linux-ptrace.h" #include "nat/aarch64-sve-linux-ptrace.h" #include "tdesc.h" @@ -49,21 +51,124 @@ #include #endif +#ifdef HAVE_GETAUXVAL +#include +#endif + /* Linux target op definitions for the AArch64 architecture. */ class aarch64_target : public linux_process_target { public: + const regs_info *get_regs_info () override; + + int breakpoint_kind_from_pc (CORE_ADDR *pcptr) override; + + int breakpoint_kind_from_current_state (CORE_ADDR *pcptr) override; + + const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override; + + bool supports_z_point_type (char z_type) override; + + bool supports_tracepoints () override; + + bool supports_fast_tracepoints () override; + + int install_fast_tracepoint_jump_pad + (CORE_ADDR tpoint, CORE_ADDR tpaddr, CORE_ADDR collector, + CORE_ADDR lockaddr, ULONGEST orig_size, CORE_ADDR *jump_entry, + CORE_ADDR *trampoline, ULONGEST *trampoline_size, + unsigned char *jjump_pad_insn, ULONGEST *jjump_pad_insn_size, + CORE_ADDR *adjusted_insn_addr, CORE_ADDR *adjusted_insn_addr_end, + char *err) override; + + int get_min_fast_tracepoint_insn_len () override; + + struct emit_ops *emit_ops () override; + + bool supports_memory_tagging () override; + + bool fetch_memtags (CORE_ADDR address, size_t len, + gdb::byte_vector &tags, int type) override; + + bool store_memtags (CORE_ADDR address, size_t len, + const gdb::byte_vector &tags, int type) override; + protected: void low_arch_setup () override; + + bool low_cannot_fetch_register (int regno) override; + + bool low_cannot_store_register (int regno) override; + + bool low_supports_breakpoints () override; + + CORE_ADDR low_get_pc (regcache *regcache) override; + + void low_set_pc (regcache *regcache, CORE_ADDR newpc) override; + + bool low_breakpoint_at (CORE_ADDR pc) override; + + int low_insert_point (raw_bkpt_type type, CORE_ADDR addr, + int size, raw_breakpoint *bp) override; + + int low_remove_point (raw_bkpt_type type, CORE_ADDR addr, + int size, raw_breakpoint *bp) override; + + bool low_stopped_by_watchpoint () override; + + CORE_ADDR low_stopped_data_address () override; + + bool low_siginfo_fixup (siginfo_t *native, gdb_byte *inf, + int direction) override; + + arch_process_info *low_new_process () override; + + void low_delete_process (arch_process_info *info) override; + + void low_new_thread (lwp_info *) override; + + void low_delete_thread (arch_lwp_info *) override; + + void low_new_fork (process_info *parent, process_info *child) override; + + void low_prepare_to_resume (lwp_info *lwp) override; + + int low_get_thread_area (int lwpid, CORE_ADDR *addrp) override; + + bool low_supports_range_stepping () override; + + bool low_supports_catch_syscall () override; + + void low_get_syscall_trapinfo (regcache *regcache, int *sysno) override; }; /* The singleton target ops object. */ static aarch64_target the_aarch64_target; +bool +aarch64_target::low_cannot_fetch_register (int regno) +{ + gdb_assert_not_reached ("linux target op low_cannot_fetch_register " + "is not implemented by the target"); +} + +bool +aarch64_target::low_cannot_store_register (int regno) +{ + gdb_assert_not_reached ("linux target op low_cannot_store_register " + "is not implemented by the target"); +} + +void +aarch64_target::low_prepare_to_resume (lwp_info *lwp) +{ + aarch64_linux_prepare_to_resume (lwp); +} + /* Per-process arch-specific data we want to keep. */ struct arch_process_info @@ -91,16 +196,6 @@ is_64bit_tdesc (void) return register_size (regcache->tdesc, 0) == 8; } -/* Return true if the regcache contains the number of SVE registers. */ - -static bool -is_sve_tdesc (void) -{ - struct regcache *regcache = get_thread_regcache (current_thread, 0); - - return tdesc_contains_feature (regcache->tdesc, "org.gnu.gdb.aarch64.sve"); -} - static void aarch64_fill_gregset (struct regcache *regcache, void *buf) { @@ -169,10 +264,39 @@ aarch64_store_pauthregset (struct regcache *regcache, const void *buf) &pauth_regset[1]); } -/* Implementation of linux_target_ops method "get_pc". */ +/* Fill BUF with the MTE registers from the regcache. */ -static CORE_ADDR -aarch64_get_pc (struct regcache *regcache) +static void +aarch64_fill_mteregset (struct regcache *regcache, void *buf) +{ + uint64_t *mte_regset = (uint64_t *) buf; + int mte_base = find_regno (regcache->tdesc, "tag_ctl"); + + collect_register (regcache, mte_base, mte_regset); +} + +/* Store the MTE registers to regcache. */ + +static void +aarch64_store_mteregset (struct regcache *regcache, const void *buf) +{ + uint64_t *mte_regset = (uint64_t *) buf; + int mte_base = find_regno (regcache->tdesc, "tag_ctl"); + + /* Tag Control register */ + supply_register (regcache, mte_base, mte_regset); +} + +bool +aarch64_target::low_supports_breakpoints () +{ + return true; +} + +/* Implementation of linux target ops method "low_get_pc". */ + +CORE_ADDR +aarch64_target::low_get_pc (regcache *regcache) { if (register_size (regcache->tdesc, 0) == 8) return linux_get_pc_64bit (regcache); @@ -180,10 +304,10 @@ aarch64_get_pc (struct regcache *regcache) return linux_get_pc_32bit (regcache); } -/* Implementation of linux_target_ops method "set_pc". */ +/* Implementation of linux target ops method "low_set_pc". */ -static void -aarch64_set_pc (struct regcache *regcache, CORE_ADDR pc) +void +aarch64_target::low_set_pc (regcache *regcache, CORE_ADDR pc) { if (register_size (regcache->tdesc, 0) == 8) linux_set_pc_64bit (regcache, pc); @@ -198,21 +322,20 @@ aarch64_set_pc (struct regcache *regcache, CORE_ADDR pc) (aarch64_default_breakpoint). */ static const gdb_byte aarch64_breakpoint[] = {0x00, 0x00, 0x20, 0xd4}; -/* Implementation of linux_target_ops method "breakpoint_at". */ +/* Implementation of linux target ops method "low_breakpoint_at". */ -static int -aarch64_breakpoint_at (CORE_ADDR where) +bool +aarch64_target::low_breakpoint_at (CORE_ADDR where) { if (is_64bit_tdesc ()) { gdb_byte insn[aarch64_breakpoint_len]; - the_target->read_memory (where, (unsigned char *) &insn, - aarch64_breakpoint_len); + read_memory (where, (unsigned char *) &insn, aarch64_breakpoint_len); if (memcmp (insn, aarch64_breakpoint, aarch64_breakpoint_len) == 0) - return 1; + return true; - return 0; + return false; } else return arm_breakpoint_at (where); @@ -249,10 +372,10 @@ aarch64_get_debug_reg_state (pid_t pid) return &proc->priv->arch_private->debug_reg_state; } -/* Implementation of linux_target_ops method "supports_z_point_type". */ +/* Implementation of target ops method "supports_z_point_type". */ -static int -aarch64_supports_z_point_type (char z_type) +bool +aarch64_target::supports_z_point_type (char z_type) { switch (z_type) { @@ -261,20 +384,20 @@ aarch64_supports_z_point_type (char z_type) case Z_PACKET_WRITE_WP: case Z_PACKET_READ_WP: case Z_PACKET_ACCESS_WP: - return 1; + return true; default: - return 0; + return false; } } -/* Implementation of linux_target_ops method "insert_point". +/* Implementation of linux target ops method "low_insert_point". It actually only records the info of the to-be-inserted bp/wp; the actual insertion will happen when threads are resumed. */ -static int -aarch64_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, - int len, struct raw_breakpoint *bp) +int +aarch64_target::low_insert_point (raw_bkpt_type type, CORE_ADDR addr, + int len, raw_breakpoint *bp) { int ret; enum target_hw_bp_type targ_type; @@ -316,14 +439,14 @@ aarch64_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, return ret; } -/* Implementation of linux_target_ops method "remove_point". +/* Implementation of linux target ops method "low_remove_point". It actually only records the info of the to-be-removed bp/wp, the actual removal will be done when threads are resumed. */ -static int -aarch64_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, - int len, struct raw_breakpoint *bp) +int +aarch64_target::low_remove_point (raw_bkpt_type type, CORE_ADDR addr, + int len, raw_breakpoint *bp) { int ret; enum target_hw_bp_type targ_type; @@ -362,10 +485,27 @@ aarch64_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, return ret; } -/* Implementation of linux_target_ops method "stopped_data_address". */ +/* Return the address only having significant bits. This is used to ignore + the top byte (TBI). */ static CORE_ADDR -aarch64_stopped_data_address (void) +address_significant (CORE_ADDR addr) +{ + /* Clear insignificant bits of a target address and sign extend resulting + address. */ + int addr_bit = 56; + + CORE_ADDR sign = (CORE_ADDR) 1 << (addr_bit - 1); + addr &= ((CORE_ADDR) 1 << addr_bit) - 1; + addr = (addr ^ sign) - sign; + + return addr; +} + +/* Implementation of linux target ops method "low_stopped_data_address". */ + +CORE_ADDR +aarch64_target::low_stopped_data_address () { siginfo_t siginfo; int pid, i; @@ -382,6 +522,12 @@ aarch64_stopped_data_address (void) || (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */) return (CORE_ADDR) 0; + /* Make sure to ignore the top byte, otherwise we may not recognize a + hardware watchpoint hit. The stopped data addresses coming from the + kernel can potentially be tagged addresses. */ + const CORE_ADDR addr_trap + = address_significant ((CORE_ADDR) siginfo.si_addr); + /* Check if the address matches any watched address. */ state = aarch64_get_debug_reg_state (pid_of (current_thread)); for (i = aarch64_num_wp_regs - 1; i >= 0; --i) @@ -389,7 +535,6 @@ aarch64_stopped_data_address (void) const unsigned int offset = aarch64_watchpoint_offset (state->dr_ctrl_wp[i]); const unsigned int len = aarch64_watchpoint_length (state->dr_ctrl_wp[i]); - const CORE_ADDR addr_trap = (CORE_ADDR) siginfo.si_addr; const CORE_ADDR addr_watch = state->dr_addr_wp[i] + offset; const CORE_ADDR addr_watch_aligned = align_down (state->dr_addr_wp[i], 8); const CORE_ADDR addr_orig = state->dr_addr_orig_wp[i]; @@ -424,15 +569,12 @@ aarch64_stopped_data_address (void) return (CORE_ADDR) 0; } -/* Implementation of linux_target_ops method "stopped_by_watchpoint". */ +/* Implementation of linux target ops method "low_stopped_by_watchpoint". */ -static int -aarch64_stopped_by_watchpoint (void) +bool +aarch64_target::low_stopped_by_watchpoint () { - if (aarch64_stopped_data_address () != 0) - return 1; - else - return 0; + return (low_stopped_data_address () != 0); } /* Fetch the thread-local storage pointer for libthread_db. */ @@ -445,10 +587,11 @@ ps_get_thread_area (struct ps_prochandle *ph, is_64bit_tdesc ()); } -/* Implementation of linux_target_ops method "siginfo_fixup". */ +/* Implementation of linux target ops method "low_siginfo_fixup". */ -static int -aarch64_linux_siginfo_fixup (siginfo_t *native, gdb_byte *inf, int direction) +bool +aarch64_target::low_siginfo_fixup (siginfo_t *native, gdb_byte *inf, + int direction) { /* Is the inferior 32-bit? If so, then fixup the siginfo object. */ if (!is_64bit_tdesc ()) @@ -460,16 +603,16 @@ aarch64_linux_siginfo_fixup (siginfo_t *native, gdb_byte *inf, int direction) aarch64_siginfo_from_compat_siginfo (native, (struct compat_siginfo *) inf); - return 1; + return true; } - return 0; + return false; } -/* Implementation of linux_target_ops method "new_process". */ +/* Implementation of linux target ops method "low_new_process". */ -static struct arch_process_info * -aarch64_linux_new_process (void) +arch_process_info * +aarch64_target::low_new_process () { struct arch_process_info *info = XCNEW (struct arch_process_info); @@ -478,19 +621,31 @@ aarch64_linux_new_process (void) return info; } -/* Implementation of linux_target_ops method "delete_process". */ +/* Implementation of linux target ops method "low_delete_process". */ -static void -aarch64_linux_delete_process (struct arch_process_info *info) +void +aarch64_target::low_delete_process (arch_process_info *info) { xfree (info); } -/* Implementation of linux_target_ops method "linux_new_fork". */ +void +aarch64_target::low_new_thread (lwp_info *lwp) +{ + aarch64_linux_new_thread (lwp); +} + +void +aarch64_target::low_delete_thread (arch_lwp_info *arch_lwp) +{ + aarch64_linux_delete_thread (arch_lwp); +} -static void -aarch64_linux_new_fork (struct process_info *parent, - struct process_info *child) +/* Implementation of linux target ops method "low_new_fork". */ + +void +aarch64_target::low_new_fork (process_info *parent, + process_info *child) { /* These are allocated by linux_add_process. */ gdb_assert (parent->priv != NULL @@ -515,36 +670,6 @@ aarch64_linux_new_fork (struct process_info *parent, *child->priv->arch_private = *parent->priv->arch_private; } -/* Matches HWCAP_PACA in kernel header arch/arm64/include/uapi/asm/hwcap.h. */ -#define AARCH64_HWCAP_PACA (1 << 30) - -/* Implementation of linux target ops method "low_arch_setup". */ - -void -aarch64_target::low_arch_setup () -{ - unsigned int machine; - int is_elf64; - int tid; - - tid = lwpid_of (current_thread); - - is_elf64 = linux_pid_exe_is_elf_64_file (tid, &machine); - - if (is_elf64) - { - uint64_t vq = aarch64_sve_get_vq (tid); - unsigned long hwcap = linux_get_hwcap (8); - bool pauth_p = hwcap & AARCH64_HWCAP_PACA; - - current_process ()->tdesc = aarch64_linux_read_description (vq, pauth_p); - } - else - current_process ()->tdesc = aarch32_linux_read_description (); - - aarch64_linux_get_debug_reg_capacity (lwpid_of (current_thread)); -} - /* Wrapper for aarch64_sve_regs_copy_to_reg_buf. */ static void @@ -561,18 +686,36 @@ aarch64_sve_regs_copy_from_regcache (struct regcache *regcache, void *buf) return aarch64_sve_regs_copy_from_reg_buf (regcache, buf); } +/* Array containing all the possible register sets for AArch64/Linux. During + architecture setup, these will be checked against the HWCAP/HWCAP2 bits for + validity and enabled/disabled accordingly. + + Their sizes are set to 0 here, but they will be adjusted later depending + on whether each register set is available or not. */ static struct regset_info aarch64_regsets[] = { + /* GPR registers. */ { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, - sizeof (struct user_pt_regs), GENERAL_REGS, + 0, GENERAL_REGS, aarch64_fill_gregset, aarch64_store_gregset }, + /* Floating Point (FPU) registers. */ { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET, - sizeof (struct user_fpsimd_state), FP_REGS, + 0, FP_REGS, aarch64_fill_fpregset, aarch64_store_fpregset }, + /* Scalable Vector Extension (SVE) registers. */ + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_SVE, + 0, EXTENDED_REGS, + aarch64_sve_regs_copy_from_regcache, aarch64_sve_regs_copy_to_regcache + }, + /* PAC registers. */ { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_PAC_MASK, - AARCH64_PAUTH_REGS_SIZE, OPTIONAL_REGS, - NULL, aarch64_store_pauthregset }, + 0, OPTIONAL_REGS, + nullptr, aarch64_store_pauthregset }, + /* Tagged address control / MTE registers. */ + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_TAGGED_ADDR_CTRL, + 0, OPTIONAL_REGS, + aarch64_fill_mteregset, aarch64_store_mteregset }, NULL_REGSET }; @@ -580,66 +723,115 @@ static struct regsets_info aarch64_regsets_info = { aarch64_regsets, /* regsets */ 0, /* num_regsets */ - NULL, /* disabled_regsets */ + nullptr, /* disabled_regsets */ }; static struct regs_info regs_info_aarch64 = { - NULL, /* regset_bitmap */ - NULL, /* usrregs */ + nullptr, /* regset_bitmap */ + nullptr, /* usrregs */ &aarch64_regsets_info, }; -static struct regset_info aarch64_sve_regsets[] = +/* Given FEATURES, adjust the available register sets by setting their + sizes. A size of 0 means the register set is disabled and won't be + used. */ + +static void +aarch64_adjust_register_sets (const struct aarch64_features &features) { - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, - sizeof (struct user_pt_regs), GENERAL_REGS, - aarch64_fill_gregset, aarch64_store_gregset }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_SVE, - SVE_PT_SIZE (AARCH64_MAX_SVE_VQ, SVE_PT_REGS_SVE), EXTENDED_REGS, - aarch64_sve_regs_copy_from_regcache, aarch64_sve_regs_copy_to_regcache - }, - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_PAC_MASK, - AARCH64_PAUTH_REGS_SIZE, OPTIONAL_REGS, - NULL, aarch64_store_pauthregset }, - NULL_REGSET -}; + struct regset_info *regset; -static struct regsets_info aarch64_sve_regsets_info = - { - aarch64_sve_regsets, /* regsets. */ - 0, /* num_regsets. */ - NULL, /* disabled_regsets. */ - }; + for (regset = aarch64_regsets; regset->size >= 0; regset++) + { + switch (regset->nt_type) + { + case NT_PRSTATUS: + /* General purpose registers are always present. */ + regset->size = sizeof (struct user_pt_regs); + break; + case NT_FPREGSET: + /* This is unavailable when SVE is present. */ + if (!features.sve) + regset->size = sizeof (struct user_fpsimd_state); + break; + case NT_ARM_SVE: + if (features.sve) + regset->size = SVE_PT_SIZE (AARCH64_MAX_SVE_VQ, SVE_PT_REGS_SVE); + break; + case NT_ARM_PAC_MASK: + if (features.pauth) + regset->size = AARCH64_PAUTH_REGS_SIZE; + break; + case NT_ARM_TAGGED_ADDR_CTRL: + if (features.mte) + regset->size = AARCH64_LINUX_SIZEOF_MTE; + break; + default: + gdb_assert_not_reached ("Unknown register set found."); + } + } +} -static struct regs_info regs_info_aarch64_sve = - { - NULL, /* regset_bitmap. */ - NULL, /* usrregs. */ - &aarch64_sve_regsets_info, - }; +/* Matches HWCAP_PACA in kernel header arch/arm64/include/uapi/asm/hwcap.h. */ +#define AARCH64_HWCAP_PACA (1 << 30) + +/* Implementation of linux target ops method "low_arch_setup". */ + +void +aarch64_target::low_arch_setup () +{ + unsigned int machine; + int is_elf64; + int tid; + + tid = lwpid_of (current_thread); + + is_elf64 = linux_pid_exe_is_elf_64_file (tid, &machine); -/* Implementation of linux_target_ops method "regs_info". */ + if (is_elf64) + { + struct aarch64_features features; + + uint64_t vq = aarch64_sve_get_vq (tid); + features.sve = (vq > 0); + /* A-profile PAC is 64-bit only. */ + features.pauth = linux_get_hwcap (8) & AARCH64_HWCAP_PACA; + /* A-profile MTE is 64-bit only. */ + features.mte = linux_get_hwcap2 (8) & HWCAP2_MTE; + + current_process ()->tdesc + = aarch64_linux_read_description (vq, features.pauth, features.mte); + + /* Adjust the register sets we should use for this particular set of + features. */ + aarch64_adjust_register_sets (features); + } + else + current_process ()->tdesc = aarch32_linux_read_description (); -static const struct regs_info * -aarch64_regs_info (void) + aarch64_linux_get_debug_reg_capacity (lwpid_of (current_thread)); +} + +/* Implementation of linux target ops method "get_regs_info". */ + +const regs_info * +aarch64_target::get_regs_info () { if (!is_64bit_tdesc ()) return ®s_info_aarch32; - if (is_sve_tdesc ()) - return ®s_info_aarch64_sve; - + /* AArch64 64-bit registers. */ return ®s_info_aarch64; } -/* Implementation of linux_target_ops method "supports_tracepoints". */ +/* Implementation of target ops method "supports_tracepoints". */ -static int -aarch64_supports_tracepoints (void) +bool +aarch64_target::supports_tracepoints () { if (current_thread == NULL) - return 1; + return true; else { /* We don't support tracepoints on aarch32 now. */ @@ -647,10 +839,10 @@ aarch64_supports_tracepoints (void) } } -/* Implementation of linux_target_ops method "get_thread_area". */ +/* Implementation of linux target ops method "low_get_thread_area". */ -static int -aarch64_get_thread_area (int lwpid, CORE_ADDR *addrp) +int +aarch64_target::low_get_thread_area (int lwpid, CORE_ADDR *addrp) { struct iovec iovec; uint64_t reg; @@ -666,10 +858,16 @@ aarch64_get_thread_area (int lwpid, CORE_ADDR *addrp) return 0; } -/* Implementation of linux_target_ops method "get_syscall_trapinfo". */ +bool +aarch64_target::low_supports_catch_syscall () +{ + return true; +} -static void -aarch64_get_syscall_trapinfo (struct regcache *regcache, int *sysno) +/* Implementation of linux target ops method "low_get_syscall_trapinfo". */ + +void +aarch64_target::low_get_syscall_trapinfo (regcache *regcache, int *sysno) { int use_64bit = register_size (regcache->tdesc, 0) == 8; @@ -1876,23 +2074,23 @@ static const struct aarch64_insn_visitor visitor = aarch64_ftrace_insn_reloc_others, }; -/* Implementation of linux_target_ops method +bool +aarch64_target::supports_fast_tracepoints () +{ + return true; +} + +/* Implementation of target ops method "install_fast_tracepoint_jump_pad". */ -static int -aarch64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, - CORE_ADDR tpaddr, - CORE_ADDR collector, - CORE_ADDR lockaddr, - ULONGEST orig_size, - CORE_ADDR *jump_entry, - CORE_ADDR *trampoline, - ULONGEST *trampoline_size, - unsigned char *jjump_pad_insn, - ULONGEST *jjump_pad_insn_size, - CORE_ADDR *adjusted_insn_addr, - CORE_ADDR *adjusted_insn_addr_end, - char *err) +int +aarch64_target::install_fast_tracepoint_jump_pad + (CORE_ADDR tpoint, CORE_ADDR tpaddr, CORE_ADDR collector, + CORE_ADDR lockaddr, ULONGEST orig_size, CORE_ADDR *jump_entry, + CORE_ADDR *trampoline, ULONGEST *trampoline_size, + unsigned char *jjump_pad_insn, ULONGEST *jjump_pad_insn_size, + CORE_ADDR *adjusted_insn_addr, CORE_ADDR *adjusted_insn_addr_end, + char *err) { uint32_t buf[256]; uint32_t *p = buf; @@ -2993,35 +3191,35 @@ static struct emit_ops aarch64_emit_ops_impl = aarch64_emit_ge_got, }; -/* Implementation of linux_target_ops method "emit_ops". */ +/* Implementation of target ops method "emit_ops". */ -static struct emit_ops * -aarch64_emit_ops (void) +emit_ops * +aarch64_target::emit_ops () { return &aarch64_emit_ops_impl; } -/* Implementation of linux_target_ops method +/* Implementation of target ops method "get_min_fast_tracepoint_insn_len". */ -static int -aarch64_get_min_fast_tracepoint_insn_len (void) +int +aarch64_target::get_min_fast_tracepoint_insn_len () { return 4; } -/* Implementation of linux_target_ops method "supports_range_stepping". */ +/* Implementation of linux target ops method "low_supports_range_stepping". */ -static int -aarch64_supports_range_stepping (void) +bool +aarch64_target::low_supports_range_stepping () { - return 1; + return true; } -/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ +/* Implementation of target ops method "sw_breakpoint_from_kind". */ -static const gdb_byte * -aarch64_sw_breakpoint_from_kind (int kind, int *size) +const gdb_byte * +aarch64_target::sw_breakpoint_from_kind (int kind, int *size) { if (is_64bit_tdesc ()) { @@ -3032,10 +3230,10 @@ aarch64_sw_breakpoint_from_kind (int kind, int *size) return arm_sw_breakpoint_from_kind (kind, size); } -/* Implementation of linux_target_ops method "breakpoint_kind_from_pc". */ +/* Implementation of target ops method "breakpoint_kind_from_pc". */ -static int -aarch64_breakpoint_kind_from_pc (CORE_ADDR *pcptr) +int +aarch64_target::breakpoint_kind_from_pc (CORE_ADDR *pcptr) { if (is_64bit_tdesc ()) return aarch64_breakpoint_len; @@ -3043,11 +3241,11 @@ aarch64_breakpoint_kind_from_pc (CORE_ADDR *pcptr) return arm_breakpoint_kind_from_pc (pcptr); } -/* Implementation of the linux_target_ops method +/* Implementation of the target ops method "breakpoint_kind_from_current_state". */ -static int -aarch64_breakpoint_kind_from_current_state (CORE_ADDR *pcptr) +int +aarch64_target::breakpoint_kind_from_current_state (CORE_ADDR *pcptr) { if (is_64bit_tdesc ()) return aarch64_breakpoint_len; @@ -3055,52 +3253,53 @@ aarch64_breakpoint_kind_from_current_state (CORE_ADDR *pcptr) return arm_breakpoint_kind_from_current_state (pcptr); } -/* Support for hardware single step. */ +/* Returns true if memory tagging is supported. */ +bool +aarch64_target::supports_memory_tagging () +{ + if (current_thread == NULL) + { + /* We don't have any processes running, so don't attempt to + use linux_get_hwcap2 as it will try to fetch the current + thread id. Instead, just fetch the auxv from the self + PID. */ +#ifdef HAVE_GETAUXVAL + return (getauxval (AT_HWCAP2) & HWCAP2_MTE) != 0; +#else + return true; +#endif + } + + return (linux_get_hwcap2 (8) & HWCAP2_MTE) != 0; +} + +bool +aarch64_target::fetch_memtags (CORE_ADDR address, size_t len, + gdb::byte_vector &tags, int type) +{ + /* Allocation tags are per-process, so any tid is fine. */ + int tid = lwpid_of (current_thread); -static int -aarch64_supports_hardware_single_step (void) -{ - return 1; -} - -struct linux_target_ops the_low_target = -{ - aarch64_regs_info, - NULL, /* cannot_fetch_register */ - NULL, /* cannot_store_register */ - NULL, /* fetch_register */ - aarch64_get_pc, - aarch64_set_pc, - aarch64_breakpoint_kind_from_pc, - aarch64_sw_breakpoint_from_kind, - NULL, /* get_next_pcs */ - 0, /* decr_pc_after_break */ - aarch64_breakpoint_at, - aarch64_supports_z_point_type, - aarch64_insert_point, - aarch64_remove_point, - aarch64_stopped_by_watchpoint, - aarch64_stopped_data_address, - NULL, /* collect_ptrace_register */ - NULL, /* supply_ptrace_register */ - aarch64_linux_siginfo_fixup, - aarch64_linux_new_process, - aarch64_linux_delete_process, - aarch64_linux_new_thread, - aarch64_linux_delete_thread, - aarch64_linux_new_fork, - aarch64_linux_prepare_to_resume, - NULL, /* process_qsupported */ - aarch64_supports_tracepoints, - aarch64_get_thread_area, - aarch64_install_fast_tracepoint_jump_pad, - aarch64_emit_ops, - aarch64_get_min_fast_tracepoint_insn_len, - aarch64_supports_range_stepping, - aarch64_breakpoint_kind_from_current_state, - aarch64_supports_hardware_single_step, - aarch64_get_syscall_trapinfo, -}; + /* Allocation tag? */ + if (type == static_cast (aarch64_memtag_type::mte_allocation)) + return aarch64_mte_fetch_memtags (tid, address, len, tags); + + return false; +} + +bool +aarch64_target::store_memtags (CORE_ADDR address, size_t len, + const gdb::byte_vector &tags, int type) +{ + /* Allocation tags are per-process, so any tid is fine. */ + int tid = lwpid_of (current_thread); + + /* Allocation tag? */ + if (type == static_cast (aarch64_memtag_type::mte_allocation)) + return aarch64_mte_store_memtags (tid, address, len, tags); + + return false; +} /* The linux target ops object. */ @@ -3112,5 +3311,4 @@ initialize_low_arch (void) initialize_low_arch_aarch32 (); initialize_regsets_info (&aarch64_regsets_info); - initialize_regsets_info (&aarch64_sve_regsets_info); }