32 #include "elf/common.h"
34 #include <sys/ptrace.h>
35 #include <sys/utsname.h>
36 #include <asm/ptrace.h>
44 #define TRAP_HWBKPT 0x0004
75 #define AARCH64_HBP_MAX_NUM 16
76 #define AARCH64_HWP_MAX_NUM 16
90 #define AARCH64_HBP_ALIGNMENT 4
91 #define AARCH64_HWP_ALIGNMENT 8
96 #define AARCH64_HWP_MAX_LEN_PER_REG 8
107 #define AARCH64_DEBUG_NUM_SLOTS(x) ((x) & 0xff)
108 #define AARCH64_DEBUG_ARCH(x) (((x) >> 8) & 0xff)
111 #define AARCH64_DEBUG_ARCH_V8 0x6
145 #define DR_MARK_ALL_CHANGED(x, m) \
148 gdb_assert (sizeof ((x)) * 8 >= (m)); \
149 (x) = (((dr_changed_t)1 << (m)) - 1); \
152 #define DR_MARK_N_CHANGED(x, n) \
155 (x) |= ((dr_changed_t)1 << (n)); \
158 #define DR_CLEAR_CHANGED(x) \
164 #define DR_HAS_CHANGED(x) ((x) != 0)
165 #define DR_N_HAS_CHANGED(x, n) ((x) & ((dr_changed_t)1 << (n)))
213 for (proc = aarch64_process_list; proc; proc = proc->
next)
214 if (proc->
pid == pid)
228 proc =
xcalloc (1,
sizeof (*proc));
232 aarch64_process_list = proc;
265 if (proc->
pid == pid)
267 *proc_link = proc->
next;
273 proc_link = &proc->
next;
306 struct user_hwdebug_state regs;
308 const unsigned int *ctrl;
310 memset (®s, 0,
sizeof (regs));
311 iov.iov_base = ®s;
317 iov.iov_len = (offsetof (
struct user_hwdebug_state, dbg_regs[count - 1])
318 +
sizeof (regs.dbg_regs [count - 1]));
320 for (i = 0; i < count; i++)
322 regs.dbg_regs[i].addr = addr[i];
323 regs.dbg_regs[i].ctrl = ctrl[i];
327 watchpoint ? NT_ARM_HW_WATCH : NT_ARM_HW_BREAK,
329 error (
_(
"Unexpected error setting hardware debug registers"));
363 "debug_reg_change_callback: \n\tOn entry:\n");
365 "\tpid%d, dr_changed_bp=0x%s, "
366 "dr_changed_wp=0x%s\n",
373 dr_changed = *dr_changed_ptr;
382 *dr_changed_ptr = dr_changed;
392 "\tOn exit:\n\tpid%d, dr_changed_bp=0x%s, "
393 "dr_changed_wp=0x%s\n",
432 (
unsigned long) addr, len,
433 type ==
hw_write ?
"hw-write-watchpoint"
434 : (type ==
hw_read ?
"hw-read-watchpoint"
435 : (type ==
hw_access ?
"hw-access-watchpoint"
443 "\tBP%d: addr=0x%08lx, ctrl=0x%08x, ref.count=%d\n",
450 "\tWP%d: addr=0x%08lx, ctrl=0x%08x, ref.count=%d\n",
467 iovec.iov_base = ®s;
468 iovec.iov_len =
sizeof (regs);
491 iovec.iov_base = ®s;
492 iovec.iov_len =
sizeof (regs);
520 iovec.iov_base = ®s;
521 iovec.iov_len =
sizeof (regs);
547 iovec.iov_base = ®s;
548 iovec.iov_len =
sizeof (regs);
729 *child_state = *parent_state;
738 lwpid_t lwpid,
int idx,
void **base)
743 iovec.iov_base = ®
744 iovec.iov_len =
sizeof (reg);
752 *base = (
void *) (reg - idx);
765 struct user_hwdebug_state dreg_state;
768 iov.iov_base = &dreg_state;
769 iov.iov_len =
sizeof (dreg_state);
778 warning (
_(
"Unexpected number of hardware watchpoint registers"
779 " reported by ptrace, got %d, expected %d."),
786 warning (
_(
"Unable to determine the number of hardware watchpoints"
798 warning (
_(
"Unexpected number of hardware breakpoint registers"
799 " reported by ptrace, got %d, expected %d."),
806 warning (
_(
"Unable to determine the number of hardware breakpoints"
852 int *aligned_len_p,
CORE_ADDR *next_addr_p,
869 offset = addr & (alignment - 1);
870 aligned_addr = addr -
offset;
872 gdb_assert (offset >= 0 && offset < alignment);
873 gdb_assert (aligned_addr >= 0 && aligned_addr <= addr);
876 if (offset + len >= max_wp_len)
880 aligned_len = max_wp_len;
881 len -= (max_wp_len -
offset);
882 addr += (max_wp_len -
offset);
889 static const unsigned char
891 { 1, 2, 4, 4, 8, 8, 8, 8 };
893 aligned_len = aligned_len_array[offset + len - 1];
899 *aligned_addr_p = aligned_addr;
901 *aligned_len_p = aligned_len;
927 int type,
int cnt,
int othertype)
941 #define DR_CONTROL_ENABLED(ctrl) (((ctrl) & 0x1) == 1)
942 #define DR_CONTROL_LENGTH(ctrl) (((ctrl) >> 5) & 0xff)
951 static inline unsigned int
976 unsigned int ctrl,
ttype;
999 ctrl |= ((1 <<
len) - 1) << 5;
1001 ctrl |= (2 << 1) | 1;
1025 if (addr & (alignment - 1))
1028 if (len != 8 && len != 4 && len != 2 && len != 1)
1067 for (i = 0; i < num_regs; ++i)
1069 if ((dr_ctrl_p[i] & 1) == 0)
1075 else if (dr_addr_p[i] == addr && dr_ctrl_p[i] == ctrl)
1088 if ((dr_ctrl_p[idx] & 1) == 0)
1091 dr_addr_p[idx] = addr;
1092 dr_ctrl_p[idx] = ctrl;
1093 dr_ref_count[idx] = 1;
1100 dr_ref_count[idx]++;
1138 for (i = 0; i < num_regs; ++i)
1139 if (dr_addr_p[i] == addr && dr_ctrl_p[i] == ctrl)
1150 if (--dr_ref_count[i] == 0)
1155 dr_ctrl_p[i] = ctrl;
1199 "insert_hw_breakpoint on entry (addr=0x%08lx, len=%d))\n",
1200 (
unsigned long) addr, len);
1210 "insert_hw_breakpoint", addr, len, type);
1231 (
gdb_stdlog,
"remove_hw_breakpoint on entry (addr=0x%08lx, len=%d))\n",
1232 (
unsigned long) addr, len);
1242 "remove_hw_watchpoint", addr, len, type);
1281 int aligned_len, ret;
1295 "handle_unaligned_watchpoint: is_insert: %d\n"
1296 " aligned_addr: 0x%08lx, aligned_len: %d\n"
1297 " next_addr: 0x%08lx, next_len: %d\n",
1298 is_insert, aligned_addr, aligned_len, addr, len);
1333 "insert_watchpoint on entry (addr=0x%08lx, len=%d)\n",
1334 (
unsigned long) addr, len);
1346 "insert_watchpoint", addr, len, type);
1366 "remove_watchpoint on entry (addr=0x%08lx, len=%d)\n",
1367 (
unsigned long) addr, len);
1379 "remove_watchpoint", addr, len, type);
1439 if (siginfo.si_signo != SIGTRAP
1453 && addr_trap >= addr_watch
1454 && addr_trap < addr_watch +
len)
1456 *addr_p = addr_trap;
1481 return start <= addr && start + length - 1 >= addr;
1493 Set whether to show variables that mirror the AArch64 debug registers."),
_(
"\
1494 Show whether to show variables that mirror the AArch64 debug registers."),
_(
"\
1495 Use \"on\" to enable, \"off\" to disable.\n\
1496 If enabled, the debug registers values are shown when GDB inserts\n\
1497 or removes a hardware breakpoint or watchpoint, and when the inferior\n\
1498 triggers a breakpoint or watchpoint."),
static const struct target_desc * aarch64_linux_read_description(struct target_ops *ops)
struct arch_lwp_info * arch_private
static unsigned int aarch64_point_encode_ctrl_reg(int type, int len)
static int aarch64_linux_insert_watchpoint(struct target_ops *self, CORE_ADDR addr, int len, int type, struct expression *cond)
const struct target_desc *(* to_read_description)(struct target_ops *ops) TARGET_DEFAULT_RETURN(NULL)
static int aarch64_linux_remove_watchpoint(struct target_ops *self, CORE_ADDR addr, int len, int type, struct expression *cond)
static struct aarch64_debug_reg_state * aarch64_get_debug_reg_state(pid_t pid)
#define AARCH64_HBP_MAX_NUM
static void fetch_fpregs_from_thread(struct regcache *regcache)
#define DR_MARK_N_CHANGED(x, n)
static void store_gregs_to_thread(const struct regcache *regcache)
void fill_gregset(const struct regcache *regcache, gdb_gregset_t *gregsetp, int regno)
void linux_stop_lwp(struct lwp_info *lwp)
static int get_thread_id(ptid_t ptid)
void linux_nat_set_new_thread(struct target_ops *t, void(*new_thread)(struct lwp_info *))
void warning(const char *fmt,...)
unsigned int dr_ref_count_wp[AARCH64_HWP_MAX_NUM]
static void aarch64_linux_child_post_startup_inferior(struct target_ops *self, ptid_t ptid)
static unsigned int aarch64_watchpoint_length(unsigned int ctrl)
char * phex(ULONGEST l, int sizeof_l)
static int dr_ref_count[4]
void regcache_supply_regset(const struct regset *regset, struct regcache *regcache, int regnum, const void *buf, size_t size)
static void add_show_debug_regs_command(void)
static int aarch64_handle_breakpoint(int type, CORE_ADDR addr, int len, int is_insert)
static int aarch64_handle_unaligned_watchpoint(int type, CORE_ADDR addr, int len, int is_insert)
#define DR_CONTROL_LENGTH(ctrl)
int(* to_region_ok_for_hw_watchpoint)(struct target_ops *, CORE_ADDR, int) TARGET_DEFAULT_FUNC(default_region_ok_for_hw_watchpoint)
int linux_nat_get_siginfo(ptid_t ptid, siginfo_t *siginfo)
static void aarch64_linux_prepare_to_resume(struct lwp_info *lwp)
void linux_nat_set_new_fork(struct target_ops *t, linux_nat_new_fork_ftype *new_fork)
static int aarch64_linux_can_use_hw_breakpoint(struct target_ops *self, int type, int cnt, int othertype)
struct target_desc * tdesc_aarch64
void fill_fpregset(const struct regcache *regcache, gdb_fpregset_t *fpregsetp, int regno)
struct cmd_list_element * maintenance_set_cmdlist
static void aarch64_linux_set_debug_regs(const struct aarch64_debug_reg_state *state, int tid, int watchpoint)
static void aarch64_linux_new_thread(struct lwp_info *lp)
static int debug_reg_change_callback(struct lwp_info *lwp, void *ptr)
int(* to_insert_watchpoint)(struct target_ops *, CORE_ADDR, int, int, struct expression *) TARGET_DEFAULT_RETURN(-1)
static int aarch64_linux_stopped_data_address(struct target_ops *target, CORE_ADDR *addr_p)
static int aarch64_point_is_aligned(int is_watchpoint, CORE_ADDR addr, int len)
static int aarch64_linux_region_ok_for_hw_watchpoint(struct target_ops *self, CORE_ADDR addr, int len)
static int aarch64_handle_watchpoint(int type, CORE_ADDR addr, int len, int is_insert)
static int aarch64_num_bp_regs
static int aarch64_dr_state_remove_one_point(struct aarch64_debug_reg_state *state, int type, CORE_ADDR addr, int len)
int(* to_watchpoint_addr_within_range)(struct target_ops *, CORE_ADDR, CORE_ADDR, int) TARGET_DEFAULT_FUNC(default_watchpoint_addr_within_range)
static int aarch64_linux_insert_hw_breakpoint(struct target_ops *self, struct gdbarch *gdbarch, struct bp_target_info *bp_tgt)
GDB_GREGSET_T gdb_gregset_t
#define AARCH64_DEBUG_NUM_SLOTS(x)
static struct aarch64_process_info * aarch64_add_process(pid_t pid)
static void store_fpregs_to_thread(const struct regcache *regcache)
int(* to_remove_watchpoint)(struct target_ops *, CORE_ADDR, int, int, struct expression *) TARGET_DEFAULT_RETURN(-1)
int is_watchpoint(const struct breakpoint *bpt)
void fprintf_unfiltered(struct ui_file *stream, const char *format,...)
GDB_FPREGSET_T gdb_fpregset_t
ptid_t pid_to_ptid(int pid)
#define AARCH64_HWP_MAX_LEN_PER_REG
void supply_gregset(struct regcache *regcache, const gdb_gregset_t *gregsetp)
void linux_nat_set_prepare_to_resume(struct target_ops *t, void(*prepare_to_resume)(struct lwp_info *))
void regcache_collect_regset(const struct regset *regset, const struct regcache *regcache, int regnum, void *buf, size_t size)
#define DR_MARK_ALL_CHANGED(x, m)
static void aarch64_linux_store_inferior_registers(struct target_ops *ops, struct regcache *regcache, int regno)
void linux_nat_add_target(struct target_ops *t)
static int aarch64_linux_watchpoint_addr_within_range(struct target_ops *target, CORE_ADDR addr, CORE_ADDR start, int length)
#define DR_HAS_CHANGED(x)
ps_err_e ps_get_thread_area(const struct ps_prochandle *ph, lwpid_t lwpid, int idx, void **base)
void _initialize_aarch64_linux_nat(void)
struct aarch64_process_info * next
CORE_ADDR dr_addr_bp[AARCH64_HBP_MAX_NUM]
struct target_ops * linux_target(void)
struct ui_file * gdb_stdlog
int(* to_insert_hw_breakpoint)(struct target_ops *, struct gdbarch *, struct bp_target_info *) TARGET_DEFAULT_RETURN(-1)
static void aarch64_forget_process(pid_t pid)
static struct aarch64_process_info * aarch64_process_info_get(pid_t pid)
int ptid_get_pid(ptid_t ptid)
const struct regset aarch64_linux_gregset
int(* to_remove_hw_breakpoint)(struct target_ops *, struct gdbarch *, struct bp_target_info *) TARGET_DEFAULT_RETURN(-1)
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)
static struct aarch64_process_info * aarch64_process_list
void(* to_fetch_registers)(struct target_ops *, struct regcache *, int) TARGET_DEFAULT_IGNORE()
static void fetch_gregs_from_thread(struct regcache *regcache)
void void void void void void void void void perror_with_name(const char *string) ATTRIBUTE_NORETURN
enum register_status regcache_register_status(const struct regcache *regcache, int regnum)
int(* to_can_use_hw_breakpoint)(struct target_ops *, int, int, int) TARGET_DEFAULT_RETURN(0)
static void aarch64_linux_fetch_inferior_registers(struct target_ops *ops, struct regcache *regcache, int regno)
#define AARCH64_LINUX_SIZEOF_FPREGSET
static int aarch64_num_wp_regs
static int aarch64_handle_aligned_watchpoint(int type, CORE_ADDR addr, int len, int is_insert)
static int aarch64_dr_state_insert_one_point(struct aarch64_debug_reg_state *state, int type, CORE_ADDR addr, int len)
dr_changed_t dr_changed_wp
static struct aarch64_process_info * aarch64_find_process_pid(pid_t pid)
int(* to_stopped_by_watchpoint)(struct target_ops *) TARGET_DEFAULT_RETURN(0)
#define AARCH64_LINUX_SIZEOF_GREGSET
#define AARCH64_DEBUG_ARCH(x)
unsigned int dr_ref_count_bp[AARCH64_HBP_MAX_NUM]
unsigned int dr_ctrl_wp[AARCH64_HWP_MAX_NUM]
void regcache_raw_supply(struct regcache *regcache, int regnum, const void *buf)
#define AARCH64_HWP_MAX_NUM
unsigned long long ULONGEST
#define AARCH64_DEBUG_ARCH_V8
static void aarch64_linux_get_debug_reg_capacity(void)
long ptid_get_lwp(ptid_t ptid)
void regcache_raw_collect(const struct regcache *regcache, int regnum, void *buf)
#define DR_CONTROL_ENABLED(ctrl)
struct aarch64_debug_reg_state state
static int aarch64_linux_stopped_by_watchpoint(struct target_ops *ops)
void linux_nat_set_forget_process(struct target_ops *t, linux_nat_forget_process_ftype *fn)
static int aarch64_linux_remove_hw_breakpoint(struct target_ops *self, struct gdbarch *gdbarch, struct bp_target_info *bp_tgt)
static void aarch64_notify_debug_reg_change(const struct aarch64_debug_reg_state *state, int is_watchpoint, unsigned int idx)
static void aarch64_show_debug_reg_state(struct aarch64_debug_reg_state *state, const char *func, CORE_ADDR addr, int len, int type)
int(* to_stopped_data_address)(struct target_ops *, CORE_ADDR *) TARGET_DEFAULT_RETURN(0)
dr_changed_t dr_changed_bp
static void(* super_post_startup_inferior)(struct target_ops *self, ptid_t ptid)
void(* to_store_registers)(struct target_ops *, struct regcache *, int) TARGET_DEFAULT_NORETURN(noprocess())
struct lwp_info * iterate_over_lwps(ptid_t filter, iterate_over_lwps_ftype callback, void *data)
#define AARCH64_HBP_ALIGNMENT
PTR xcalloc(size_t number, size_t size)
#define AARCH64_HWP_ALIGNMENT
struct cmd_list_element * maintenance_show_cmdlist
static void aarch64_linux_new_fork(struct lwp_info *parent, pid_t child_pid)
void error(const char *fmt,...)
unsigned int dr_ctrl_bp[AARCH64_HBP_MAX_NUM]
const struct regset aarch64_linux_fpregset
mach_port_t mach_port_t name mach_port_t mach_port_t name error_t int int rusage_t pid_t pid
void add_setshow_boolean_cmd(const char *name, enum command_class theclass, int *var, const char *set_doc, const char *show_doc, const char *help_doc, cmd_sfunc_ftype *set_func, show_value_ftype *show_func, struct cmd_list_element **set_list, struct cmd_list_element **show_list)
void(* to_post_startup_inferior)(struct target_ops *, ptid_t) TARGET_DEFAULT_IGNORE()
void supply_fpregset(struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
const ULONGEST const LONGEST len
CORE_ADDR dr_addr_wp[AARCH64_HWP_MAX_NUM]
#define DR_CLEAR_CHANGED(x)