123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803 |
- /* Native-dependent code for GNU/Linux AArch64.
- Copyright (C) 2011-2022 Free Software Foundation, Inc.
- Contributed by ARM Ltd.
- 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 "defs.h"
- #include "inferior.h"
- #include "gdbcore.h"
- #include "regcache.h"
- #include "linux-nat.h"
- #include "target-descriptions.h"
- #include "auxv.h"
- #include "gdbcmd.h"
- #include "aarch64-nat.h"
- #include "aarch64-tdep.h"
- #include "aarch64-linux-tdep.h"
- #include "aarch32-linux-nat.h"
- #include "aarch32-tdep.h"
- #include "arch/arm.h"
- #include "nat/aarch64-linux.h"
- #include "nat/aarch64-linux-hw-point.h"
- #include "nat/aarch64-sve-linux-ptrace.h"
- #include "elf/external.h"
- #include "elf/common.h"
- #include "nat/gdb_ptrace.h"
- #include <sys/utsname.h>
- #include <asm/ptrace.h>
- #include "gregset.h"
- #include "linux-tdep.h"
- /* Defines ps_err_e, struct ps_prochandle. */
- #include "gdb_proc_service.h"
- #include "arch-utils.h"
- #include "arch/aarch64-mte-linux.h"
- #include "nat/aarch64-mte-linux-ptrace.h"
- #ifndef TRAP_HWBKPT
- #define TRAP_HWBKPT 0x0004
- #endif
- class aarch64_linux_nat_target final
- : public aarch64_nat_target<linux_nat_target>
- {
- public:
- /* Add our register access methods. */
- void fetch_registers (struct regcache *, int) override;
- void store_registers (struct regcache *, int) override;
- const struct target_desc *read_description () override;
- /* Add our hardware breakpoint and watchpoint implementation. */
- bool stopped_by_watchpoint () override;
- bool stopped_data_address (CORE_ADDR *) override;
- int can_do_single_step () override;
- /* Override the GNU/Linux inferior startup hook. */
- void post_startup_inferior (ptid_t) override;
- /* Override the GNU/Linux post attach hook. */
- void post_attach (int pid) override;
- /* These three defer to common nat/ code. */
- void low_new_thread (struct lwp_info *lp) override
- { aarch64_linux_new_thread (lp); }
- void low_delete_thread (struct arch_lwp_info *lp) override
- { aarch64_linux_delete_thread (lp); }
- void low_prepare_to_resume (struct lwp_info *lp) override
- { aarch64_linux_prepare_to_resume (lp); }
- void low_new_fork (struct lwp_info *parent, pid_t child_pid) override;
- void low_forget_process (pid_t pid) override;
- /* Add our siginfo layout converter. */
- bool low_siginfo_fixup (siginfo_t *ptrace, gdb_byte *inf, int direction)
- override;
- struct gdbarch *thread_architecture (ptid_t) override;
- bool supports_memory_tagging () override;
- /* Read memory allocation tags from memory via PTRACE. */
- bool fetch_memtags (CORE_ADDR address, size_t len,
- gdb::byte_vector &tags, int type) override;
- /* Write allocation tags to memory via PTRACE. */
- bool store_memtags (CORE_ADDR address, size_t len,
- const gdb::byte_vector &tags, int type) override;
- };
- static aarch64_linux_nat_target the_aarch64_linux_nat_target;
- /* Called whenever GDB is no longer debugging process PID. It deletes
- data structures that keep track of debug register state. */
- void
- aarch64_linux_nat_target::low_forget_process (pid_t pid)
- {
- aarch64_remove_debug_reg_state (pid);
- }
- /* Fill GDB's register array with the general-purpose register values
- from the current thread. */
- static void
- fetch_gregs_from_thread (struct regcache *regcache)
- {
- int ret, tid;
- struct gdbarch *gdbarch = regcache->arch ();
- elf_gregset_t regs;
- struct iovec iovec;
- /* Make sure REGS can hold all registers contents on both aarch64
- and arm. */
- gdb_static_assert (sizeof (regs) >= 18 * 4);
- tid = regcache->ptid ().lwp ();
- iovec.iov_base = ®s;
- if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
- iovec.iov_len = 18 * 4;
- else
- iovec.iov_len = sizeof (regs);
- ret = ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iovec);
- if (ret < 0)
- perror_with_name (_("Unable to fetch general registers."));
- if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
- aarch32_gp_regcache_supply (regcache, (uint32_t *) regs, 1);
- else
- {
- int regno;
- for (regno = AARCH64_X0_REGNUM; regno <= AARCH64_CPSR_REGNUM; regno++)
- regcache->raw_supply (regno, ®s[regno - AARCH64_X0_REGNUM]);
- }
- }
- /* Store to the current thread the valid general-purpose register
- values in the GDB's register array. */
- static void
- store_gregs_to_thread (const struct regcache *regcache)
- {
- int ret, tid;
- elf_gregset_t regs;
- struct iovec iovec;
- struct gdbarch *gdbarch = regcache->arch ();
- /* Make sure REGS can hold all registers contents on both aarch64
- and arm. */
- gdb_static_assert (sizeof (regs) >= 18 * 4);
- tid = regcache->ptid ().lwp ();
- iovec.iov_base = ®s;
- if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
- iovec.iov_len = 18 * 4;
- else
- iovec.iov_len = sizeof (regs);
- ret = ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iovec);
- if (ret < 0)
- perror_with_name (_("Unable to fetch general registers."));
- if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
- aarch32_gp_regcache_collect (regcache, (uint32_t *) regs, 1);
- else
- {
- int regno;
- for (regno = AARCH64_X0_REGNUM; regno <= AARCH64_CPSR_REGNUM; regno++)
- if (REG_VALID == regcache->get_register_status (regno))
- regcache->raw_collect (regno, ®s[regno - AARCH64_X0_REGNUM]);
- }
- ret = ptrace (PTRACE_SETREGSET, tid, NT_PRSTATUS, &iovec);
- if (ret < 0)
- perror_with_name (_("Unable to store general registers."));
- }
- /* Fill GDB's register array with the fp/simd register values
- from the current thread. */
- static void
- fetch_fpregs_from_thread (struct regcache *regcache)
- {
- int ret, tid;
- elf_fpregset_t regs;
- struct iovec iovec;
- struct gdbarch *gdbarch = regcache->arch ();
- /* Make sure REGS can hold all VFP registers contents on both aarch64
- and arm. */
- gdb_static_assert (sizeof regs >= ARM_VFP3_REGS_SIZE);
- tid = regcache->ptid ().lwp ();
- iovec.iov_base = ®s;
- if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
- {
- iovec.iov_len = ARM_VFP3_REGS_SIZE;
- ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_VFP, &iovec);
- if (ret < 0)
- perror_with_name (_("Unable to fetch VFP registers."));
- aarch32_vfp_regcache_supply (regcache, (gdb_byte *) ®s, 32);
- }
- else
- {
- int regno;
- iovec.iov_len = sizeof (regs);
- ret = ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, &iovec);
- if (ret < 0)
- perror_with_name (_("Unable to fetch vFP/SIMD registers."));
- for (regno = AARCH64_V0_REGNUM; regno <= AARCH64_V31_REGNUM; regno++)
- regcache->raw_supply (regno, ®s.vregs[regno - AARCH64_V0_REGNUM]);
- regcache->raw_supply (AARCH64_FPSR_REGNUM, ®s.fpsr);
- regcache->raw_supply (AARCH64_FPCR_REGNUM, ®s.fpcr);
- }
- }
- /* Store to the current thread the valid fp/simd register
- values in the GDB's register array. */
- static void
- store_fpregs_to_thread (const struct regcache *regcache)
- {
- int ret, tid;
- elf_fpregset_t regs;
- struct iovec iovec;
- struct gdbarch *gdbarch = regcache->arch ();
- /* Make sure REGS can hold all VFP registers contents on both aarch64
- and arm. */
- gdb_static_assert (sizeof regs >= ARM_VFP3_REGS_SIZE);
- tid = regcache->ptid ().lwp ();
- iovec.iov_base = ®s;
- if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
- {
- iovec.iov_len = ARM_VFP3_REGS_SIZE;
- ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_VFP, &iovec);
- if (ret < 0)
- perror_with_name (_("Unable to fetch VFP registers."));
- aarch32_vfp_regcache_collect (regcache, (gdb_byte *) ®s, 32);
- }
- else
- {
- int regno;
- iovec.iov_len = sizeof (regs);
- ret = ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, &iovec);
- if (ret < 0)
- perror_with_name (_("Unable to fetch FP/SIMD registers."));
- for (regno = AARCH64_V0_REGNUM; regno <= AARCH64_V31_REGNUM; regno++)
- if (REG_VALID == regcache->get_register_status (regno))
- regcache->raw_collect
- (regno, (char *) ®s.vregs[regno - AARCH64_V0_REGNUM]);
- if (REG_VALID == regcache->get_register_status (AARCH64_FPSR_REGNUM))
- regcache->raw_collect (AARCH64_FPSR_REGNUM, (char *) ®s.fpsr);
- if (REG_VALID == regcache->get_register_status (AARCH64_FPCR_REGNUM))
- regcache->raw_collect (AARCH64_FPCR_REGNUM, (char *) ®s.fpcr);
- }
- if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
- {
- ret = ptrace (PTRACE_SETREGSET, tid, NT_ARM_VFP, &iovec);
- if (ret < 0)
- perror_with_name (_("Unable to store VFP registers."));
- }
- else
- {
- ret = ptrace (PTRACE_SETREGSET, tid, NT_FPREGSET, &iovec);
- if (ret < 0)
- perror_with_name (_("Unable to store FP/SIMD registers."));
- }
- }
- /* Fill GDB's register array with the sve register values
- from the current thread. */
- static void
- fetch_sveregs_from_thread (struct regcache *regcache)
- {
- std::unique_ptr<gdb_byte[]> base
- = aarch64_sve_get_sveregs (regcache->ptid ().lwp ());
- aarch64_sve_regs_copy_to_reg_buf (regcache, base.get ());
- }
- /* Store to the current thread the valid sve register
- values in the GDB's register array. */
- static void
- store_sveregs_to_thread (struct regcache *regcache)
- {
- int ret;
- struct iovec iovec;
- int tid = regcache->ptid ().lwp ();
- /* First store vector length to the thread. This is done first to ensure the
- ptrace buffers read from the kernel are the correct size. */
- if (!aarch64_sve_set_vq (tid, regcache))
- perror_with_name (_("Unable to set VG register."));
- /* Obtain a dump of SVE registers from ptrace. */
- std::unique_ptr<gdb_byte[]> base = aarch64_sve_get_sveregs (tid);
- /* Overwrite with regcache state. */
- aarch64_sve_regs_copy_from_reg_buf (regcache, base.get ());
- /* Write back to the kernel. */
- iovec.iov_base = base.get ();
- iovec.iov_len = ((struct user_sve_header *) base.get ())->size;
- ret = ptrace (PTRACE_SETREGSET, tid, NT_ARM_SVE, &iovec);
- if (ret < 0)
- perror_with_name (_("Unable to store sve registers"));
- }
- /* Fill GDB's register array with the pointer authentication mask values from
- the current thread. */
- static void
- fetch_pauth_masks_from_thread (struct regcache *regcache)
- {
- aarch64_gdbarch_tdep *tdep
- = (aarch64_gdbarch_tdep *) gdbarch_tdep (regcache->arch ());
- int ret;
- struct iovec iovec;
- uint64_t pauth_regset[2] = {0, 0};
- int tid = regcache->ptid ().lwp ();
- iovec.iov_base = &pauth_regset;
- iovec.iov_len = sizeof (pauth_regset);
- ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_PAC_MASK, &iovec);
- if (ret != 0)
- perror_with_name (_("unable to fetch pauth registers."));
- regcache->raw_supply (AARCH64_PAUTH_DMASK_REGNUM (tdep->pauth_reg_base),
- &pauth_regset[0]);
- regcache->raw_supply (AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base),
- &pauth_regset[1]);
- }
- /* Fill GDB's register array with the MTE register values from
- the current thread. */
- static void
- fetch_mteregs_from_thread (struct regcache *regcache)
- {
- aarch64_gdbarch_tdep *tdep
- = (aarch64_gdbarch_tdep *) gdbarch_tdep (regcache->arch ());
- int regno = tdep->mte_reg_base;
- gdb_assert (regno != -1);
- uint64_t tag_ctl = 0;
- struct iovec iovec;
- iovec.iov_base = &tag_ctl;
- iovec.iov_len = sizeof (tag_ctl);
- int tid = get_ptrace_pid (regcache->ptid ());
- if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TAGGED_ADDR_CTRL, &iovec) != 0)
- perror_with_name (_("unable to fetch MTE registers."));
- regcache->raw_supply (regno, &tag_ctl);
- }
- /* Store to the current thread the valid MTE register set in the GDB's
- register array. */
- static void
- store_mteregs_to_thread (struct regcache *regcache)
- {
- aarch64_gdbarch_tdep *tdep
- = (aarch64_gdbarch_tdep *) gdbarch_tdep (regcache->arch ());
- int regno = tdep->mte_reg_base;
- gdb_assert (regno != -1);
- uint64_t tag_ctl = 0;
- if (REG_VALID != regcache->get_register_status (regno))
- return;
- regcache->raw_collect (regno, (char *) &tag_ctl);
- struct iovec iovec;
- iovec.iov_base = &tag_ctl;
- iovec.iov_len = sizeof (tag_ctl);
- int tid = get_ptrace_pid (regcache->ptid ());
- if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_TAGGED_ADDR_CTRL, &iovec) != 0)
- perror_with_name (_("unable to store MTE registers."));
- }
- /* Implement the "fetch_registers" target_ops method. */
- void
- aarch64_linux_nat_target::fetch_registers (struct regcache *regcache,
- int regno)
- {
- aarch64_gdbarch_tdep *tdep
- = (aarch64_gdbarch_tdep *) gdbarch_tdep (regcache->arch ());
- if (regno == -1)
- {
- fetch_gregs_from_thread (regcache);
- if (tdep->has_sve ())
- fetch_sveregs_from_thread (regcache);
- else
- fetch_fpregs_from_thread (regcache);
- if (tdep->has_pauth ())
- fetch_pauth_masks_from_thread (regcache);
- if (tdep->has_mte ())
- fetch_mteregs_from_thread (regcache);
- }
- else if (regno < AARCH64_V0_REGNUM)
- fetch_gregs_from_thread (regcache);
- else if (tdep->has_sve ())
- fetch_sveregs_from_thread (regcache);
- else
- fetch_fpregs_from_thread (regcache);
- if (tdep->has_pauth ())
- {
- if (regno == AARCH64_PAUTH_DMASK_REGNUM (tdep->pauth_reg_base)
- || regno == AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base))
- fetch_pauth_masks_from_thread (regcache);
- }
- /* Fetch individual MTE registers. */
- if (tdep->has_mte ()
- && (regno == tdep->mte_reg_base))
- fetch_mteregs_from_thread (regcache);
- }
- /* Implement the "store_registers" target_ops method. */
- void
- aarch64_linux_nat_target::store_registers (struct regcache *regcache,
- int regno)
- {
- aarch64_gdbarch_tdep *tdep
- = (aarch64_gdbarch_tdep *) gdbarch_tdep (regcache->arch ());
- if (regno == -1)
- {
- store_gregs_to_thread (regcache);
- if (tdep->has_sve ())
- store_sveregs_to_thread (regcache);
- else
- store_fpregs_to_thread (regcache);
- if (tdep->has_mte ())
- store_mteregs_to_thread (regcache);
- }
- else if (regno < AARCH64_V0_REGNUM)
- store_gregs_to_thread (regcache);
- else if (tdep->has_sve ())
- store_sveregs_to_thread (regcache);
- else
- store_fpregs_to_thread (regcache);
- /* Store MTE registers. */
- if (tdep->has_mte ()
- && (regno == tdep->mte_reg_base))
- store_mteregs_to_thread (regcache);
- }
- /* Fill register REGNO (if it is a general-purpose register) in
- *GREGSETPS with the value in GDB's register array. If REGNO is -1,
- do this for all registers. */
- void
- fill_gregset (const struct regcache *regcache,
- gdb_gregset_t *gregsetp, int regno)
- {
- regcache_collect_regset (&aarch64_linux_gregset, regcache,
- regno, (gdb_byte *) gregsetp,
- AARCH64_LINUX_SIZEOF_GREGSET);
- }
- /* Fill GDB's register array with the general-purpose register values
- in *GREGSETP. */
- void
- supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
- {
- regcache_supply_regset (&aarch64_linux_gregset, regcache, -1,
- (const gdb_byte *) gregsetp,
- AARCH64_LINUX_SIZEOF_GREGSET);
- }
- /* Fill register REGNO (if it is a floating-point register) in
- *FPREGSETP with the value in GDB's register array. If REGNO is -1,
- do this for all registers. */
- void
- fill_fpregset (const struct regcache *regcache,
- gdb_fpregset_t *fpregsetp, int regno)
- {
- regcache_collect_regset (&aarch64_linux_fpregset, regcache,
- regno, (gdb_byte *) fpregsetp,
- AARCH64_LINUX_SIZEOF_FPREGSET);
- }
- /* Fill GDB's register array with the floating-point register values
- in *FPREGSETP. */
- void
- supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
- {
- regcache_supply_regset (&aarch64_linux_fpregset, regcache, -1,
- (const gdb_byte *) fpregsetp,
- AARCH64_LINUX_SIZEOF_FPREGSET);
- }
- /* linux_nat_new_fork hook. */
- void
- aarch64_linux_nat_target::low_new_fork (struct lwp_info *parent,
- pid_t child_pid)
- {
- pid_t parent_pid;
- struct aarch64_debug_reg_state *parent_state;
- struct aarch64_debug_reg_state *child_state;
- /* NULL means no watchpoint has ever been set in the parent. In
- that case, there's nothing to do. */
- if (parent->arch_private == NULL)
- return;
- /* GDB core assumes the child inherits the watchpoints/hw
- breakpoints of the parent, and will remove them all from the
- forked off process. Copy the debug registers mirrors into the
- new process so that all breakpoints and watchpoints can be
- removed together. */
- parent_pid = parent->ptid.pid ();
- parent_state = aarch64_get_debug_reg_state (parent_pid);
- child_state = aarch64_get_debug_reg_state (child_pid);
- *child_state = *parent_state;
- }
- /* Called by libthread_db. Returns a pointer to the thread local
- storage (or its descriptor). */
- ps_err_e
- ps_get_thread_area (struct ps_prochandle *ph,
- lwpid_t lwpid, int idx, void **base)
- {
- int is_64bit_p
- = (gdbarch_bfd_arch_info (target_gdbarch ())->bits_per_word == 64);
- return aarch64_ps_get_thread_area (ph, lwpid, idx, base, is_64bit_p);
- }
- /* Implement the virtual inf_ptrace_target::post_startup_inferior method. */
- void
- aarch64_linux_nat_target::post_startup_inferior (ptid_t ptid)
- {
- low_forget_process (ptid.pid ());
- aarch64_linux_get_debug_reg_capacity (ptid.pid ());
- linux_nat_target::post_startup_inferior (ptid);
- }
- /* Implement the "post_attach" target_ops method. */
- void
- aarch64_linux_nat_target::post_attach (int pid)
- {
- low_forget_process (pid);
- /* Set the hardware debug register capacity. If
- aarch64_linux_get_debug_reg_capacity is not called
- (as it is in aarch64_linux_child_post_startup_inferior) then
- software watchpoints will be used instead of hardware
- watchpoints when attaching to a target. */
- aarch64_linux_get_debug_reg_capacity (pid);
- linux_nat_target::post_attach (pid);
- }
- /* Implement the "read_description" target_ops method. */
- const struct target_desc *
- aarch64_linux_nat_target::read_description ()
- {
- int ret, tid;
- gdb_byte regbuf[ARM_VFP3_REGS_SIZE];
- struct iovec iovec;
- tid = inferior_ptid.pid ();
- iovec.iov_base = regbuf;
- iovec.iov_len = ARM_VFP3_REGS_SIZE;
- ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_VFP, &iovec);
- if (ret == 0)
- return aarch32_read_description ();
- CORE_ADDR hwcap = linux_get_hwcap (this);
- CORE_ADDR hwcap2 = linux_get_hwcap2 (this);
- bool pauth_p = hwcap & AARCH64_HWCAP_PACA;
- bool mte_p = hwcap2 & HWCAP2_MTE;
- return aarch64_read_description (aarch64_sve_get_vq (tid), pauth_p, mte_p);
- }
- /* Convert a native/host siginfo object, into/from the siginfo in the
- layout of the inferiors' architecture. Returns true if any
- conversion was done; false otherwise. If DIRECTION is 1, then copy
- from INF to NATIVE. If DIRECTION is 0, copy from NATIVE to
- INF. */
- bool
- aarch64_linux_nat_target::low_siginfo_fixup (siginfo_t *native, gdb_byte *inf,
- int direction)
- {
- struct gdbarch *gdbarch = get_frame_arch (get_current_frame ());
- /* Is the inferior 32-bit? If so, then do fixup the siginfo
- object. */
- if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
- {
- if (direction == 0)
- aarch64_compat_siginfo_from_siginfo ((struct compat_siginfo *) inf,
- native);
- else
- aarch64_siginfo_from_compat_siginfo (native,
- (struct compat_siginfo *) inf);
- return true;
- }
- return false;
- }
- /* Implement the "stopped_data_address" target_ops method. */
- bool
- aarch64_linux_nat_target::stopped_data_address (CORE_ADDR *addr_p)
- {
- siginfo_t siginfo;
- struct aarch64_debug_reg_state *state;
- if (!linux_nat_get_siginfo (inferior_ptid, &siginfo))
- return false;
- /* This must be a hardware breakpoint. */
- if (siginfo.si_signo != SIGTRAP
- || (siginfo.si_code & 0xffff) != TRAP_HWBKPT)
- return false;
- /* 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. */
- struct gdbarch *gdbarch = thread_architecture (inferior_ptid);
- const CORE_ADDR addr_trap
- = address_significant (gdbarch, (CORE_ADDR) siginfo.si_addr);
- /* Check if the address matches any watched address. */
- state = aarch64_get_debug_reg_state (inferior_ptid.pid ());
- return aarch64_stopped_data_address (state, addr_trap, addr_p);
- }
- /* Implement the "stopped_by_watchpoint" target_ops method. */
- bool
- aarch64_linux_nat_target::stopped_by_watchpoint ()
- {
- CORE_ADDR addr;
- return stopped_data_address (&addr);
- }
- /* Implement the "can_do_single_step" target_ops method. */
- int
- aarch64_linux_nat_target::can_do_single_step ()
- {
- return 1;
- }
- /* Implement the "thread_architecture" target_ops method. */
- struct gdbarch *
- aarch64_linux_nat_target::thread_architecture (ptid_t ptid)
- {
- /* Return the gdbarch for the current thread. If the vector length has
- changed since the last time this was called, then do a further lookup. */
- uint64_t vq = aarch64_sve_get_vq (ptid.lwp ());
- /* Find the current gdbarch the same way as process_stratum_target. Only
- return it if the current vector length matches the one in the tdep. */
- inferior *inf = find_inferior_ptid (this, ptid);
- gdb_assert (inf != NULL);
- aarch64_gdbarch_tdep *tdep
- = (aarch64_gdbarch_tdep *) gdbarch_tdep (inf->gdbarch);
- if (vq == tdep->vq)
- return inf->gdbarch;
- /* We reach here if the vector length for the thread is different from its
- value at process start. Lookup gdbarch via info (potentially creating a
- new one), stashing the vector length inside id. Use -1 for when SVE
- unavailable, to distinguish from an unset value of 0. */
- struct gdbarch_info info;
- info.bfd_arch_info = bfd_lookup_arch (bfd_arch_aarch64, bfd_mach_aarch64);
- info.id = (int *) (vq == 0 ? -1 : vq);
- return gdbarch_find_by_info (info);
- }
- /* Implement the "supports_memory_tagging" target_ops method. */
- bool
- aarch64_linux_nat_target::supports_memory_tagging ()
- {
- return (linux_get_hwcap2 (this) & HWCAP2_MTE) != 0;
- }
- /* Implement the "fetch_memtags" target_ops method. */
- bool
- aarch64_linux_nat_target::fetch_memtags (CORE_ADDR address, size_t len,
- gdb::byte_vector &tags, int type)
- {
- int tid = get_ptrace_pid (inferior_ptid);
- /* Allocation tags? */
- if (type == static_cast<int> (aarch64_memtag_type::mte_allocation))
- return aarch64_mte_fetch_memtags (tid, address, len, tags);
- return false;
- }
- /* Implement the "store_memtags" target_ops method. */
- bool
- aarch64_linux_nat_target::store_memtags (CORE_ADDR address, size_t len,
- const gdb::byte_vector &tags, int type)
- {
- int tid = get_ptrace_pid (inferior_ptid);
- /* Allocation tags? */
- if (type == static_cast<int> (aarch64_memtag_type::mte_allocation))
- return aarch64_mte_store_memtags (tid, address, len, tags);
- return false;
- }
- void _initialize_aarch64_linux_nat ();
- void
- _initialize_aarch64_linux_nat ()
- {
- aarch64_initialize_hw_point ();
- /* Register the target. */
- linux_target = &the_aarch64_linux_nat_target;
- add_inf_child_target (&the_aarch64_linux_nat_target);
- }
|