gdb/aarch64-linux-nat.c - gdb
Global variables defined
Data types defined
Functions defined
Macros defined
Source code
- #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-tdep.h"
- #include "aarch64-linux-tdep.h"
- #include "elf/common.h"
- #include <sys/ptrace.h>
- #include <sys/utsname.h>
- #include <asm/ptrace.h>
- #include "gregset.h"
- #include "features/aarch64.c"
- #include "gdb_proc_service.h"
- #ifndef TRAP_HWBKPT
- #define TRAP_HWBKPT 0x0004
- #endif
- static int
- get_thread_id (ptid_t ptid)
- {
- int tid = ptid_get_lwp (ptid);
- if (0 == tid)
- tid = ptid_get_pid (ptid);
- return tid;
- }
- #define AARCH64_HBP_MAX_NUM 16
- #define AARCH64_HWP_MAX_NUM 16
- #define AARCH64_HBP_ALIGNMENT 4
- #define AARCH64_HWP_ALIGNMENT 8
- #define AARCH64_HWP_MAX_LEN_PER_REG 8
- #define AARCH64_DEBUG_NUM_SLOTS(x) ((x) & 0xff)
- #define AARCH64_DEBUG_ARCH(x) (((x) >> 8) & 0xff)
- #define AARCH64_DEBUG_ARCH_V8 0x6
- static int aarch64_num_bp_regs;
- static int aarch64_num_wp_regs;
- typedef ULONGEST dr_changed_t;
- #define DR_MARK_ALL_CHANGED(x, m) \
- do \
- { \
- gdb_assert (sizeof ((x)) * 8 >= (m)); \
- (x) = (((dr_changed_t)1 << (m)) - 1); \
- } while (0)
- #define DR_MARK_N_CHANGED(x, n) \
- do \
- { \
- (x) |= ((dr_changed_t)1 << (n)); \
- } while (0)
- #define DR_CLEAR_CHANGED(x) \
- do \
- { \
- (x) = 0; \
- } while (0)
- #define DR_HAS_CHANGED(x) ((x) != 0)
- #define DR_N_HAS_CHANGED(x, n) ((x) & ((dr_changed_t)1 << (n)))
- struct aarch64_debug_reg_state
- {
-
- CORE_ADDR dr_addr_bp[AARCH64_HBP_MAX_NUM];
- unsigned int dr_ctrl_bp[AARCH64_HBP_MAX_NUM];
- unsigned int dr_ref_count_bp[AARCH64_HBP_MAX_NUM];
-
- CORE_ADDR dr_addr_wp[AARCH64_HWP_MAX_NUM];
- unsigned int dr_ctrl_wp[AARCH64_HWP_MAX_NUM];
- unsigned int dr_ref_count_wp[AARCH64_HWP_MAX_NUM];
- };
- struct aarch64_process_info
- {
-
- struct aarch64_process_info *next;
-
- pid_t pid;
-
- struct aarch64_debug_reg_state state;
- };
- static struct aarch64_process_info *aarch64_process_list = NULL;
- static struct aarch64_process_info *
- aarch64_find_process_pid (pid_t pid)
- {
- struct aarch64_process_info *proc;
- for (proc = aarch64_process_list; proc; proc = proc->next)
- if (proc->pid == pid)
- return proc;
- return NULL;
- }
- static struct aarch64_process_info *
- aarch64_add_process (pid_t pid)
- {
- struct aarch64_process_info *proc;
- proc = xcalloc (1, sizeof (*proc));
- proc->pid = pid;
- proc->next = aarch64_process_list;
- aarch64_process_list = proc;
- return proc;
- }
- static struct aarch64_process_info *
- aarch64_process_info_get (pid_t pid)
- {
- struct aarch64_process_info *proc;
- proc = aarch64_find_process_pid (pid);
- if (proc == NULL)
- proc = aarch64_add_process (pid);
- return proc;
- }
- static void
- aarch64_forget_process (pid_t pid)
- {
- struct aarch64_process_info *proc, **proc_link;
- proc = aarch64_process_list;
- proc_link = &aarch64_process_list;
- while (proc != NULL)
- {
- if (proc->pid == pid)
- {
- *proc_link = proc->next;
- xfree (proc);
- return;
- }
- proc_link = &proc->next;
- proc = *proc_link;
- }
- }
- static struct aarch64_debug_reg_state *
- aarch64_get_debug_reg_state (pid_t pid)
- {
- return &aarch64_process_info_get (pid)->state;
- }
- struct arch_lwp_info
- {
-
- dr_changed_t dr_changed_bp;
- dr_changed_t dr_changed_wp;
- };
- static void
- aarch64_linux_set_debug_regs (const struct aarch64_debug_reg_state *state,
- int tid, int watchpoint)
- {
- int i, count;
- struct iovec iov;
- struct user_hwdebug_state regs;
- const CORE_ADDR *addr;
- const unsigned int *ctrl;
- memset (®s, 0, sizeof (regs));
- iov.iov_base = ®s;
- count = watchpoint ? aarch64_num_wp_regs : aarch64_num_bp_regs;
- addr = watchpoint ? state->dr_addr_wp : state->dr_addr_bp;
- ctrl = watchpoint ? state->dr_ctrl_wp : state->dr_ctrl_bp;
- if (count == 0)
- return;
- iov.iov_len = (offsetof (struct user_hwdebug_state, dbg_regs[count - 1])
- + sizeof (regs.dbg_regs [count - 1]));
- for (i = 0; i < count; i++)
- {
- regs.dbg_regs[i].addr = addr[i];
- regs.dbg_regs[i].ctrl = ctrl[i];
- }
- if (ptrace (PTRACE_SETREGSET, tid,
- watchpoint ? NT_ARM_HW_WATCH : NT_ARM_HW_BREAK,
- (void *) &iov))
- error (_("Unexpected error setting hardware debug registers"));
- }
- struct aarch64_dr_update_callback_param
- {
- int is_watchpoint;
- unsigned int idx;
- };
- static int
- debug_reg_change_callback (struct lwp_info *lwp, void *ptr)
- {
- struct aarch64_dr_update_callback_param *param_p
- = (struct aarch64_dr_update_callback_param *) ptr;
- int pid = get_thread_id (lwp->ptid);
- int idx = param_p->idx;
- int is_watchpoint = param_p->is_watchpoint;
- struct arch_lwp_info *info = lwp->arch_private;
- dr_changed_t *dr_changed_ptr;
- dr_changed_t dr_changed;
- if (info == NULL)
- info = lwp->arch_private = XCNEW (struct arch_lwp_info);
- if (show_debug_regs)
- {
- fprintf_unfiltered (gdb_stdlog,
- "debug_reg_change_callback: \n\tOn entry:\n");
- fprintf_unfiltered (gdb_stdlog,
- "\tpid%d, dr_changed_bp=0x%s, "
- "dr_changed_wp=0x%s\n",
- pid, phex (info->dr_changed_bp, 8),
- phex (info->dr_changed_wp, 8));
- }
- dr_changed_ptr = is_watchpoint ? &info->dr_changed_wp
- : &info->dr_changed_bp;
- dr_changed = *dr_changed_ptr;
- gdb_assert (idx >= 0
- && (idx <= (is_watchpoint ? aarch64_num_wp_regs
- : aarch64_num_bp_regs)));
-
- DR_MARK_N_CHANGED (dr_changed, idx);
- *dr_changed_ptr = dr_changed;
-
- if (!lwp->stopped)
- linux_stop_lwp (lwp);
- if (show_debug_regs)
- {
- fprintf_unfiltered (gdb_stdlog,
- "\tOn exit:\n\tpid%d, dr_changed_bp=0x%s, "
- "dr_changed_wp=0x%s\n",
- pid, phex (info->dr_changed_bp, 8),
- phex (info->dr_changed_wp, 8));
- }
-
- return 0;
- }
- static void
- aarch64_notify_debug_reg_change (const struct aarch64_debug_reg_state *state,
- int is_watchpoint, unsigned int idx)
- {
- struct aarch64_dr_update_callback_param param;
- ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
- param.is_watchpoint = is_watchpoint;
- param.idx = idx;
- iterate_over_lwps (pid_ptid, debug_reg_change_callback, (void *) ¶m);
- }
- static void
- aarch64_show_debug_reg_state (struct aarch64_debug_reg_state *state,
- const char *func, CORE_ADDR addr,
- int len, int type)
- {
- int i;
- fprintf_unfiltered (gdb_stdlog, "%s", func);
- if (addr || len)
- fprintf_unfiltered (gdb_stdlog, " (addr=0x%08lx, len=%d, type=%s)",
- (unsigned long) addr, len,
- type == hw_write ? "hw-write-watchpoint"
- : (type == hw_read ? "hw-read-watchpoint"
- : (type == hw_access ? "hw-access-watchpoint"
- : (type == hw_execute ? "hw-breakpoint"
- : "??unknown??"))));
- fprintf_unfiltered (gdb_stdlog, ":\n");
- fprintf_unfiltered (gdb_stdlog, "\tBREAKPOINTs:\n");
- for (i = 0; i < aarch64_num_bp_regs; i++)
- fprintf_unfiltered (gdb_stdlog,
- "\tBP%d: addr=0x%08lx, ctrl=0x%08x, ref.count=%d\n",
- i, state->dr_addr_bp[i],
- state->dr_ctrl_bp[i], state->dr_ref_count_bp[i]);
- fprintf_unfiltered (gdb_stdlog, "\tWATCHPOINTs:\n");
- for (i = 0; i < aarch64_num_wp_regs; i++)
- fprintf_unfiltered (gdb_stdlog,
- "\tWP%d: addr=0x%08lx, ctrl=0x%08x, ref.count=%d\n",
- i, state->dr_addr_wp[i],
- state->dr_ctrl_wp[i], state->dr_ref_count_wp[i]);
- }
- static void
- fetch_gregs_from_thread (struct regcache *regcache)
- {
- int ret, regno, tid;
- elf_gregset_t regs;
- struct iovec iovec;
- tid = get_thread_id (inferior_ptid);
- iovec.iov_base = ®s;
- iovec.iov_len = sizeof (regs);
- ret = ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iovec);
- if (ret < 0)
- perror_with_name (_("Unable to fetch general registers."));
- for (regno = AARCH64_X0_REGNUM; regno <= AARCH64_CPSR_REGNUM; regno++)
- regcache_raw_supply (regcache, regno,
- (char *) ®s[regno - AARCH64_X0_REGNUM]);
- }
- static void
- store_gregs_to_thread (const struct regcache *regcache)
- {
- int ret, regno, tid;
- elf_gregset_t regs;
- struct iovec iovec;
- tid = get_thread_id (inferior_ptid);
- iovec.iov_base = ®s;
- iovec.iov_len = sizeof (regs);
- ret = ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iovec);
- if (ret < 0)
- perror_with_name (_("Unable to fetch general registers."));
- for (regno = AARCH64_X0_REGNUM; regno <= AARCH64_CPSR_REGNUM; regno++)
- if (REG_VALID == regcache_register_status (regcache, regno))
- regcache_raw_collect (regcache, regno,
- (char *) ®s[regno - AARCH64_X0_REGNUM]);
- ret = ptrace (PTRACE_SETREGSET, tid, NT_PRSTATUS, &iovec);
- if (ret < 0)
- perror_with_name (_("Unable to store general registers."));
- }
- static void
- fetch_fpregs_from_thread (struct regcache *regcache)
- {
- int ret, regno, tid;
- elf_fpregset_t regs;
- struct iovec iovec;
- tid = get_thread_id (inferior_ptid);
- iovec.iov_base = ®s;
- 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++)
- regcache_raw_supply (regcache, regno,
- (char *) ®s.vregs[regno - AARCH64_V0_REGNUM]);
- regcache_raw_supply (regcache, AARCH64_FPSR_REGNUM, (char *) ®s.fpsr);
- regcache_raw_supply (regcache, AARCH64_FPCR_REGNUM, (char *) ®s.fpcr);
- }
- static void
- store_fpregs_to_thread (const struct regcache *regcache)
- {
- int ret, regno, tid;
- elf_fpregset_t regs;
- struct iovec iovec;
- tid = get_thread_id (inferior_ptid);
- iovec.iov_base = ®s;
- 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_register_status (regcache, regno))
- regcache_raw_collect (regcache, regno,
- (char *) ®s.vregs[regno - AARCH64_V0_REGNUM]);
- if (REG_VALID == regcache_register_status (regcache, AARCH64_FPSR_REGNUM))
- regcache_raw_collect (regcache, AARCH64_FPSR_REGNUM, (char *) ®s.fpsr);
- if (REG_VALID == regcache_register_status (regcache, AARCH64_FPCR_REGNUM))
- regcache_raw_collect (regcache, AARCH64_FPCR_REGNUM, (char *) ®s.fpcr);
- ret = ptrace (PTRACE_SETREGSET, tid, NT_FPREGSET, &iovec);
- if (ret < 0)
- perror_with_name (_("Unable to store FP/SIMD registers."));
- }
- static void
- aarch64_linux_fetch_inferior_registers (struct target_ops *ops,
- struct regcache *regcache,
- int regno)
- {
- if (regno == -1)
- {
- fetch_gregs_from_thread (regcache);
- fetch_fpregs_from_thread (regcache);
- }
- else if (regno < AARCH64_V0_REGNUM)
- fetch_gregs_from_thread (regcache);
- else
- fetch_fpregs_from_thread (regcache);
- }
- static void
- aarch64_linux_store_inferior_registers (struct target_ops *ops,
- struct regcache *regcache,
- int regno)
- {
- if (regno == -1)
- {
- store_gregs_to_thread (regcache);
- store_fpregs_to_thread (regcache);
- }
- else if (regno < AARCH64_V0_REGNUM)
- store_gregs_to_thread (regcache);
- else
- store_fpregs_to_thread (regcache);
- }
- 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);
- }
- 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);
- }
- 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);
- }
- 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);
- }
- static void
- aarch64_linux_prepare_to_resume (struct lwp_info *lwp)
- {
- struct arch_lwp_info *info = lwp->arch_private;
-
- if (info == NULL)
- return;
- if (DR_HAS_CHANGED (info->dr_changed_bp)
- || DR_HAS_CHANGED (info->dr_changed_wp))
- {
- int tid = ptid_get_lwp (lwp->ptid);
- struct aarch64_debug_reg_state *state
- = aarch64_get_debug_reg_state (ptid_get_pid (lwp->ptid));
- if (show_debug_regs)
- fprintf_unfiltered (gdb_stdlog, "prepare_to_resume thread %d\n", tid);
-
- if (DR_HAS_CHANGED (info->dr_changed_wp))
- {
- aarch64_linux_set_debug_regs (state, tid, 1);
- DR_CLEAR_CHANGED (info->dr_changed_wp);
- }
-
- if (DR_HAS_CHANGED (info->dr_changed_bp))
- {
- aarch64_linux_set_debug_regs (state, tid, 0);
- DR_CLEAR_CHANGED (info->dr_changed_bp);
- }
- }
- }
- static void
- aarch64_linux_new_thread (struct lwp_info *lp)
- {
- struct arch_lwp_info *info = XCNEW (struct arch_lwp_info);
-
- DR_MARK_ALL_CHANGED (info->dr_changed_bp, aarch64_num_bp_regs);
- DR_MARK_ALL_CHANGED (info->dr_changed_wp, aarch64_num_wp_regs);
- lp->arch_private = info;
- }
- static void
- aarch64_linux_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;
-
- if (parent->arch_private == NULL)
- return;
-
- parent_pid = ptid_get_pid (parent->ptid);
- parent_state = aarch64_get_debug_reg_state (parent_pid);
- child_state = aarch64_get_debug_reg_state (child_pid);
- *child_state = *parent_state;
- }
- ps_err_e
- ps_get_thread_area (const struct ps_prochandle *ph,
- lwpid_t lwpid, int idx, void **base)
- {
- struct iovec iovec;
- uint64_t reg;
- iovec.iov_base = ®
- iovec.iov_len = sizeof (reg);
- if (ptrace (PTRACE_GETREGSET, lwpid, NT_ARM_TLS, &iovec) != 0)
- return PS_ERR;
-
- *base = (void *) (reg - idx);
- return PS_OK;
- }
- static void
- aarch64_linux_get_debug_reg_capacity (void)
- {
- int tid;
- struct iovec iov;
- struct user_hwdebug_state dreg_state;
- tid = get_thread_id (inferior_ptid);
- iov.iov_base = &dreg_state;
- iov.iov_len = sizeof (dreg_state);
-
- if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_HW_WATCH, &iov) == 0
- && AARCH64_DEBUG_ARCH (dreg_state.dbg_info) == AARCH64_DEBUG_ARCH_V8)
- {
- aarch64_num_wp_regs = AARCH64_DEBUG_NUM_SLOTS (dreg_state.dbg_info);
- if (aarch64_num_wp_regs > AARCH64_HWP_MAX_NUM)
- {
- warning (_("Unexpected number of hardware watchpoint registers"
- " reported by ptrace, got %d, expected %d."),
- aarch64_num_wp_regs, AARCH64_HWP_MAX_NUM);
- aarch64_num_wp_regs = AARCH64_HWP_MAX_NUM;
- }
- }
- else
- {
- warning (_("Unable to determine the number of hardware watchpoints"
- " available."));
- aarch64_num_wp_regs = 0;
- }
-
- if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_HW_BREAK, &iov) == 0
- && AARCH64_DEBUG_ARCH (dreg_state.dbg_info) == AARCH64_DEBUG_ARCH_V8)
- {
- aarch64_num_bp_regs = AARCH64_DEBUG_NUM_SLOTS (dreg_state.dbg_info);
- if (aarch64_num_bp_regs > AARCH64_HBP_MAX_NUM)
- {
- warning (_("Unexpected number of hardware breakpoint registers"
- " reported by ptrace, got %d, expected %d."),
- aarch64_num_bp_regs, AARCH64_HBP_MAX_NUM);
- aarch64_num_bp_regs = AARCH64_HBP_MAX_NUM;
- }
- }
- else
- {
- warning (_("Unable to determine the number of hardware breakpoints"
- " available."));
- aarch64_num_bp_regs = 0;
- }
- }
- static void (*super_post_startup_inferior) (struct target_ops *self,
- ptid_t ptid);
- static void
- aarch64_linux_child_post_startup_inferior (struct target_ops *self,
- ptid_t ptid)
- {
- aarch64_forget_process (ptid_get_pid (ptid));
- aarch64_linux_get_debug_reg_capacity ();
- super_post_startup_inferior (self, ptid);
- }
- static const struct target_desc *
- aarch64_linux_read_description (struct target_ops *ops)
- {
- initialize_tdesc_aarch64 ();
- return tdesc_aarch64;
- }
- static void
- aarch64_align_watchpoint (CORE_ADDR addr, int len, CORE_ADDR *aligned_addr_p,
- int *aligned_len_p, CORE_ADDR *next_addr_p,
- int *next_len_p)
- {
- int aligned_len;
- unsigned int offset;
- CORE_ADDR aligned_addr;
- const unsigned int alignment = AARCH64_HWP_ALIGNMENT;
- const unsigned int max_wp_len = AARCH64_HWP_MAX_LEN_PER_REG;
-
- gdb_assert (alignment == max_wp_len);
- if (len <= 0)
- return;
-
- offset = addr & (alignment - 1);
- aligned_addr = addr - offset;
- gdb_assert (offset >= 0 && offset < alignment);
- gdb_assert (aligned_addr >= 0 && aligned_addr <= addr);
- gdb_assert (offset + len > 0);
- if (offset + len >= max_wp_len)
- {
-
- aligned_len = max_wp_len;
- len -= (max_wp_len - offset);
- addr += (max_wp_len - offset);
- gdb_assert ((addr & (alignment - 1)) == 0);
- }
- else
- {
-
- static const unsigned char
- aligned_len_array[AARCH64_HWP_MAX_LEN_PER_REG] =
- { 1, 2, 4, 4, 8, 8, 8, 8 };
- aligned_len = aligned_len_array[offset + len - 1];
- addr += len;
- len = 0;
- }
- if (aligned_addr_p)
- *aligned_addr_p = aligned_addr;
- if (aligned_len_p)
- *aligned_len_p = aligned_len;
- if (next_addr_p)
- *next_addr_p = addr;
- if (next_len_p)
- *next_len_p = len;
- }
- static int
- aarch64_linux_can_use_hw_breakpoint (struct target_ops *self,
- int type, int cnt, int othertype)
- {
- return 1;
- }
- #define DR_CONTROL_ENABLED(ctrl) (((ctrl) & 0x1) == 1)
- #define DR_CONTROL_LENGTH(ctrl) (((ctrl) >> 5) & 0xff)
- static inline unsigned int
- aarch64_watchpoint_length (unsigned int ctrl)
- {
- switch (DR_CONTROL_LENGTH (ctrl))
- {
- case 0x01:
- return 1;
- case 0x03:
- return 2;
- case 0x0f:
- return 4;
- case 0xff:
- return 8;
- default:
- return 0;
- }
- }
- static unsigned int
- aarch64_point_encode_ctrl_reg (int type, int len)
- {
- unsigned int ctrl, ttype;
-
- switch (type)
- {
- case hw_write:
- ttype = 2;
- break;
- case hw_read:
- ttype = 1;
- break;
- case hw_access:
- ttype = 3;
- break;
- case hw_execute:
- ttype = 0;
- break;
- default:
- perror_with_name (_("Unrecognized breakpoint/watchpoint type"));
- }
- ctrl = ttype << 3;
-
- ctrl |= ((1 << len) - 1) << 5;
-
- ctrl |= (2 << 1) | 1;
- return ctrl;
- }
- static int
- aarch64_point_is_aligned (int is_watchpoint, CORE_ADDR addr, int len)
- {
- unsigned int alignment = is_watchpoint ? AARCH64_HWP_ALIGNMENT
- : AARCH64_HBP_ALIGNMENT;
- if (addr & (alignment - 1))
- return 0;
- if (len != 8 && len != 4 && len != 2 && len != 1)
- return 0;
- return 1;
- }
- static int
- aarch64_dr_state_insert_one_point (struct aarch64_debug_reg_state *state,
- int type, CORE_ADDR addr, int len)
- {
- int i, idx, num_regs, is_watchpoint;
- unsigned int ctrl, *dr_ctrl_p, *dr_ref_count;
- CORE_ADDR *dr_addr_p;
-
- is_watchpoint = (type != hw_execute);
- gdb_assert (aarch64_point_is_aligned (is_watchpoint, addr, len));
- if (is_watchpoint)
- {
- num_regs = aarch64_num_wp_regs;
- dr_addr_p = state->dr_addr_wp;
- dr_ctrl_p = state->dr_ctrl_wp;
- dr_ref_count = state->dr_ref_count_wp;
- }
- else
- {
- num_regs = aarch64_num_bp_regs;
- dr_addr_p = state->dr_addr_bp;
- dr_ctrl_p = state->dr_ctrl_bp;
- dr_ref_count = state->dr_ref_count_bp;
- }
- ctrl = aarch64_point_encode_ctrl_reg (type, len);
-
- idx = -1;
- for (i = 0; i < num_regs; ++i)
- {
- if ((dr_ctrl_p[i] & 1) == 0)
- {
- gdb_assert (dr_ref_count[i] == 0);
- idx = i;
-
- }
- else if (dr_addr_p[i] == addr && dr_ctrl_p[i] == ctrl)
- {
- gdb_assert (dr_ref_count[i] != 0);
- idx = i;
- break;
- }
- }
-
- if (idx == -1)
- return -1;
-
- if ((dr_ctrl_p[idx] & 1) == 0)
- {
-
- dr_addr_p[idx] = addr;
- dr_ctrl_p[idx] = ctrl;
- dr_ref_count[idx] = 1;
-
- aarch64_notify_debug_reg_change (state, is_watchpoint, idx);
- }
- else
- {
-
- dr_ref_count[idx]++;
- }
- return 0;
- }
- static int
- aarch64_dr_state_remove_one_point (struct aarch64_debug_reg_state *state,
- int type, CORE_ADDR addr, int len)
- {
- int i, num_regs, is_watchpoint;
- unsigned int ctrl, *dr_ctrl_p, *dr_ref_count;
- CORE_ADDR *dr_addr_p;
-
- is_watchpoint = (type != hw_execute);
- gdb_assert (aarch64_point_is_aligned (is_watchpoint, addr, len));
- if (is_watchpoint)
- {
- num_regs = aarch64_num_wp_regs;
- dr_addr_p = state->dr_addr_wp;
- dr_ctrl_p = state->dr_ctrl_wp;
- dr_ref_count = state->dr_ref_count_wp;
- }
- else
- {
- num_regs = aarch64_num_bp_regs;
- dr_addr_p = state->dr_addr_bp;
- dr_ctrl_p = state->dr_ctrl_bp;
- dr_ref_count = state->dr_ref_count_bp;
- }
- ctrl = aarch64_point_encode_ctrl_reg (type, len);
-
- for (i = 0; i < num_regs; ++i)
- if (dr_addr_p[i] == addr && dr_ctrl_p[i] == ctrl)
- {
- gdb_assert (dr_ref_count[i] != 0);
- break;
- }
-
- if (i == num_regs)
- return -1;
-
- if (--dr_ref_count[i] == 0)
- {
-
- ctrl &= ~1;
- dr_addr_p[i] = 0;
- dr_ctrl_p[i] = ctrl;
-
- aarch64_notify_debug_reg_change (state, is_watchpoint, i);
- }
- return 0;
- }
- static int
- aarch64_handle_breakpoint (int type, CORE_ADDR addr, int len, int is_insert)
- {
- struct aarch64_debug_reg_state *state;
-
- if (!aarch64_point_is_aligned (0 , addr, len))
- return -1;
- state = aarch64_get_debug_reg_state (ptid_get_pid (inferior_ptid));
- if (is_insert)
- return aarch64_dr_state_insert_one_point (state, type, addr, len);
- else
- return aarch64_dr_state_remove_one_point (state, type, addr, len);
- }
- static int
- aarch64_linux_insert_hw_breakpoint (struct target_ops *self,
- struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
- {
- int ret;
- CORE_ADDR addr = bp_tgt->placed_address = bp_tgt->reqstd_address;
- const int len = 4;
- const int type = hw_execute;
- if (show_debug_regs)
- fprintf_unfiltered
- (gdb_stdlog,
- "insert_hw_breakpoint on entry (addr=0x%08lx, len=%d))\n",
- (unsigned long) addr, len);
- ret = aarch64_handle_breakpoint (type, addr, len, 1 );
- if (show_debug_regs)
- {
- struct aarch64_debug_reg_state *state
- = aarch64_get_debug_reg_state (ptid_get_pid (inferior_ptid));
- aarch64_show_debug_reg_state (state,
- "insert_hw_watchpoint", addr, len, type);
- }
- return ret;
- }
- static int
- aarch64_linux_remove_hw_breakpoint (struct target_ops *self,
- struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
- {
- int ret;
- CORE_ADDR addr = bp_tgt->placed_address;
- const int len = 4;
- const int type = hw_execute;
- if (show_debug_regs)
- fprintf_unfiltered
- (gdb_stdlog, "remove_hw_breakpoint on entry (addr=0x%08lx, len=%d))\n",
- (unsigned long) addr, len);
- ret = aarch64_handle_breakpoint (type, addr, len, 0 );
- if (show_debug_regs)
- {
- struct aarch64_debug_reg_state *state
- = aarch64_get_debug_reg_state (ptid_get_pid (inferior_ptid));
- aarch64_show_debug_reg_state (state,
- "remove_hw_watchpoint", addr, len, type);
- }
- return ret;
- }
- static int
- aarch64_handle_aligned_watchpoint (int type, CORE_ADDR addr, int len,
- int is_insert)
- {
- struct aarch64_debug_reg_state *state
- = aarch64_get_debug_reg_state (ptid_get_pid (inferior_ptid));
- if (is_insert)
- return aarch64_dr_state_insert_one_point (state, type, addr, len);
- else
- return aarch64_dr_state_remove_one_point (state, type, addr, len);
- }
- static int
- aarch64_handle_unaligned_watchpoint (int type, CORE_ADDR addr, int len,
- int is_insert)
- {
- struct aarch64_debug_reg_state *state
- = aarch64_get_debug_reg_state (ptid_get_pid (inferior_ptid));
- while (len > 0)
- {
- CORE_ADDR aligned_addr;
- int aligned_len, ret;
- aarch64_align_watchpoint (addr, len, &aligned_addr, &aligned_len,
- &addr, &len);
- if (is_insert)
- ret = aarch64_dr_state_insert_one_point (state, type, aligned_addr,
- aligned_len);
- else
- ret = aarch64_dr_state_remove_one_point (state, type, aligned_addr,
- aligned_len);
- if (show_debug_regs)
- fprintf_unfiltered (gdb_stdlog,
- "handle_unaligned_watchpoint: is_insert: %d\n"
- " aligned_addr: 0x%08lx, aligned_len: %d\n"
- " next_addr: 0x%08lx, next_len: %d\n",
- is_insert, aligned_addr, aligned_len, addr, len);
- if (ret != 0)
- return ret;
- }
- return 0;
- }
- static int
- aarch64_handle_watchpoint (int type, CORE_ADDR addr, int len, int is_insert)
- {
- if (aarch64_point_is_aligned (1 , addr, len))
- return aarch64_handle_aligned_watchpoint (type, addr, len, is_insert);
- else
- return aarch64_handle_unaligned_watchpoint (type, addr, len, is_insert);
- }
- static int
- aarch64_linux_insert_watchpoint (struct target_ops *self,
- CORE_ADDR addr, int len, int type,
- struct expression *cond)
- {
- int ret;
- if (show_debug_regs)
- fprintf_unfiltered (gdb_stdlog,
- "insert_watchpoint on entry (addr=0x%08lx, len=%d)\n",
- (unsigned long) addr, len);
- gdb_assert (type != hw_execute);
- ret = aarch64_handle_watchpoint (type, addr, len, 1 );
- if (show_debug_regs)
- {
- struct aarch64_debug_reg_state *state
- = aarch64_get_debug_reg_state (ptid_get_pid (inferior_ptid));
- aarch64_show_debug_reg_state (state,
- "insert_watchpoint", addr, len, type);
- }
- return ret;
- }
- static int
- aarch64_linux_remove_watchpoint (struct target_ops *self,
- CORE_ADDR addr, int len, int type,
- struct expression *cond)
- {
- int ret;
- if (show_debug_regs)
- fprintf_unfiltered (gdb_stdlog,
- "remove_watchpoint on entry (addr=0x%08lx, len=%d)\n",
- (unsigned long) addr, len);
- gdb_assert (type != hw_execute);
- ret = aarch64_handle_watchpoint (type, addr, len, 0 );
- if (show_debug_regs)
- {
- struct aarch64_debug_reg_state *state
- = aarch64_get_debug_reg_state (ptid_get_pid (inferior_ptid));
- aarch64_show_debug_reg_state (state,
- "remove_watchpoint", addr, len, type);
- }
- return ret;
- }
- static int
- aarch64_linux_region_ok_for_hw_watchpoint (struct target_ops *self,
- CORE_ADDR addr, int len)
- {
- CORE_ADDR aligned_addr;
-
- if (len <= 0)
- return 0;
-
- if (aarch64_num_wp_regs == 0)
- return 0;
-
- aligned_addr = addr & ~(AARCH64_HWP_MAX_LEN_PER_REG - 1);
- if (aligned_addr + aarch64_num_wp_regs * AARCH64_HWP_MAX_LEN_PER_REG
- < addr + len)
- return 0;
-
- return 1;
- }
- static int
- aarch64_linux_stopped_data_address (struct target_ops *target,
- CORE_ADDR *addr_p)
- {
- siginfo_t siginfo;
- int i, tid;
- struct aarch64_debug_reg_state *state;
- if (!linux_nat_get_siginfo (inferior_ptid, &siginfo))
- return 0;
-
- if (siginfo.si_signo != SIGTRAP
- || (siginfo.si_code & 0xffff) != TRAP_HWBKPT)
- return 0;
-
- state = aarch64_get_debug_reg_state (ptid_get_pid (inferior_ptid));
- for (i = aarch64_num_wp_regs - 1; i >= 0; --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];
- if (state->dr_ref_count_wp[i]
- && DR_CONTROL_ENABLED (state->dr_ctrl_wp[i])
- && addr_trap >= addr_watch
- && addr_trap < addr_watch + len)
- {
- *addr_p = addr_trap;
- return 1;
- }
- }
- return 0;
- }
- static int
- aarch64_linux_stopped_by_watchpoint (struct target_ops *ops)
- {
- CORE_ADDR addr;
- return aarch64_linux_stopped_data_address (ops, &addr);
- }
- static int
- aarch64_linux_watchpoint_addr_within_range (struct target_ops *target,
- CORE_ADDR addr,
- CORE_ADDR start, int length)
- {
- return start <= addr && start + length - 1 >= addr;
- }
- static void
- add_show_debug_regs_command (void)
- {
-
- add_setshow_boolean_cmd ("show-debug-regs", class_maintenance,
- &show_debug_regs, _("\
- Set whether to show variables that mirror the AArch64 debug registers."), _("\
- Show whether to show variables that mirror the AArch64 debug registers."), _("\
- Use \"on\" to enable, \"off\" to disable.\n\
- If enabled, the debug registers values are shown when GDB inserts\n\
- or removes a hardware breakpoint or watchpoint, and when the inferior\n\
- triggers a breakpoint or watchpoint."),
- NULL,
- NULL,
- &maintenance_set_cmdlist,
- &maintenance_show_cmdlist);
- }
- void _initialize_aarch64_linux_nat (void);
- void
- _initialize_aarch64_linux_nat (void)
- {
- struct target_ops *t;
-
- t = linux_target ();
- add_show_debug_regs_command ();
-
- t->to_fetch_registers = aarch64_linux_fetch_inferior_registers;
- t->to_store_registers = aarch64_linux_store_inferior_registers;
- t->to_read_description = aarch64_linux_read_description;
- t->to_can_use_hw_breakpoint = aarch64_linux_can_use_hw_breakpoint;
- t->to_insert_hw_breakpoint = aarch64_linux_insert_hw_breakpoint;
- t->to_remove_hw_breakpoint = aarch64_linux_remove_hw_breakpoint;
- t->to_region_ok_for_hw_watchpoint =
- aarch64_linux_region_ok_for_hw_watchpoint;
- t->to_insert_watchpoint = aarch64_linux_insert_watchpoint;
- t->to_remove_watchpoint = aarch64_linux_remove_watchpoint;
- t->to_stopped_by_watchpoint = aarch64_linux_stopped_by_watchpoint;
- t->to_stopped_data_address = aarch64_linux_stopped_data_address;
- t->to_watchpoint_addr_within_range =
- aarch64_linux_watchpoint_addr_within_range;
-
- super_post_startup_inferior = t->to_post_startup_inferior;
- t->to_post_startup_inferior = aarch64_linux_child_post_startup_inferior;
-
- linux_nat_add_target (t);
- linux_nat_set_new_thread (t, aarch64_linux_new_thread);
- linux_nat_set_new_fork (t, aarch64_linux_new_fork);
- linux_nat_set_forget_process (t, aarch64_forget_process);
- linux_nat_set_prepare_to_resume (t, aarch64_linux_prepare_to_resume);
- }