static CORE_ADDR aarch64_stopped_data_address (void) { siginfo_t siginfo; int pid, i; struct aarch64_debug_reg_state *state; pid = lwpid_of (current_thread); /* Get the siginfo. */ if (ptrace (PTRACE_GETSIGINFO, pid, NULL, &siginfo) != 0) return (CORE_ADDR) 0; /* Need to be a hardware breakpoint/watchpoint trap. */ if (siginfo.si_signo != SIGTRAP || (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */) return (CORE_ADDR) 0; /* 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) { 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) return addr_trap; } return (CORE_ADDR) 0; }
static int aarch64_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, int len, struct raw_breakpoint *bp) { int ret; enum target_hw_bp_type targ_type; if (show_debug_regs) fprintf (stderr, "insert_point on entry (addr=0x%08lx, len=%d)\n", (unsigned long) addr, len); /* Determine the type from the raw breakpoint type. */ targ_type = raw_bkpt_type_to_target_hw_bp_type (type); if (targ_type != hw_execute) ret = aarch64_handle_watchpoint (targ_type, addr, len, 1 /* is_insert */); else ret = aarch64_handle_breakpoint (targ_type, addr, len, 1 /* is_insert */); if (show_debug_regs) aarch64_show_debug_reg_state (aarch64_get_debug_reg_state (), "insert_point", addr, len, targ_type); return ret; }
static int aarch64_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, int len, struct raw_breakpoint *bp) { int ret; enum target_hw_bp_type targ_type; struct aarch64_debug_reg_state *state = aarch64_get_debug_reg_state (pid_of (current_thread)); if (show_debug_regs) fprintf (stderr, "remove_point on entry (addr=0x%08lx, len=%d)\n", (unsigned long) addr, len); /* Determine the type from the raw breakpoint type. */ targ_type = raw_bkpt_type_to_target_hw_bp_type (type); /* Set up state pointers. */ if (targ_type != hw_execute) ret = aarch64_handle_watchpoint (targ_type, addr, len, 0 /* is_insert */, state); else ret = aarch64_handle_breakpoint (targ_type, addr, len, 0 /* is_insert */, state); if (show_debug_regs) aarch64_show_debug_reg_state (state, "remove_point", addr, len, targ_type); return ret; }
static int aarch64_insert_point (char type, CORE_ADDR addr, int len) { int ret; enum target_point_type targ_type; if (debug_hw_points) fprintf (stderr, "insert_point on entry (addr=0x%08lx, len=%d)\n", (unsigned long) addr, len); /* Determine the type from the packet. */ targ_type = Z_packet_to_point_type (type); if (targ_type == point_type_unsupported) return 1; if (targ_type != hw_execute) ret = aarch64_handle_watchpoint (targ_type, addr, len, 1 /* is_insert */); else ret = aarch64_handle_breakpoint (targ_type, addr, len, 1 /* is_insert */); if (debug_hw_points > 1) aarch64_show_debug_reg_state (aarch64_get_debug_reg_state (), "insert_point", addr, len, targ_type); return ret; }
static int aarch64_handle_aligned_watchpoint (enum target_hw_bp_type type, CORE_ADDR addr, int len, int is_insert) { struct aarch64_debug_reg_state *state; state = aarch64_get_debug_reg_state (); 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_breakpoint (enum target_hw_bp_type type, CORE_ADDR addr, int len, int is_insert) { struct aarch64_debug_reg_state *state; /* The hardware breakpoint on AArch64 should always be 4-byte aligned. */ if (!aarch64_point_is_aligned (0 /* is_watchpoint */ , addr, len)) return -1; state = aarch64_get_debug_reg_state (); 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); }
void aarch64_linux_prepare_to_resume (struct lwp_info *lwp) { struct arch_lwp_info *info = lwp_arch_private_info (lwp); /* NULL means this is the main thread still going through the shell, or, no watchpoint has been set yet. In that case, there's nothing to do. */ if (info == NULL) return; if (DR_HAS_CHANGED (info->dr_changed_bp) || DR_HAS_CHANGED (info->dr_changed_wp)) { ptid_t ptid = ptid_of_lwp (lwp); int tid = ptid_get_lwp (ptid); struct aarch64_debug_reg_state *state = aarch64_get_debug_reg_state (ptid_get_pid (ptid)); if (show_debug_regs) debug_printf ("prepare_to_resume thread %d\n", tid); /* Watchpoints. */ if (DR_HAS_CHANGED (info->dr_changed_wp)) { aarch64_linux_set_debug_regs (state, tid, 1); DR_CLEAR_CHANGED (info->dr_changed_wp); } /* Breakpoints. */ if (DR_HAS_CHANGED (info->dr_changed_bp)) { aarch64_linux_set_debug_regs (state, tid, 0); DR_CLEAR_CHANGED (info->dr_changed_bp); } } }
static int aarch64_handle_unaligned_watchpoint (enum target_hw_bp_type type, CORE_ADDR addr, int len, int is_insert) { struct aarch64_debug_reg_state *state = aarch64_get_debug_reg_state (); 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 (stderr, "handle_unaligned_watchpoint: is_insert: %d\n" " aligned_addr: 0x%s, aligned_len: %d\n" " next_addr: 0x%s, next_len: %d\n", is_insert, paddress (aligned_addr), aligned_len, paddress (addr), len); if (ret != 0) return ret; } return 0; }