diff options
Diffstat (limited to 'gdb/ppc-linux-nat.c')
-rw-r--r-- | gdb/ppc-linux-nat.c | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c index 6f11715..275de78 100644 --- a/gdb/ppc-linux-nat.c +++ b/gdb/ppc-linux-nat.c @@ -1739,6 +1739,64 @@ get_trigger_type (int rw) return t; } +/* Insert a new masked watchpoint at ADDR using the mask MASK. + RW may be hw_read for a read watchpoint, hw_write for a write watchpoint + or hw_access for an access watchpoint. Returns 0 on success and throws + an error on failure. */ + +static int +ppc_linux_insert_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr, + CORE_ADDR mask, int rw) +{ + ptid_t ptid; + struct lwp_info *lp; + struct ppc_hw_breakpoint p; + + gdb_assert (have_ptrace_booke_interface ()); + + p.version = PPC_DEBUG_CURRENT_VERSION; + p.trigger_type = get_trigger_type (rw); + p.addr_mode = PPC_BREAKPOINT_MODE_MASK; + p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE; + p.addr = addr; + p.addr2 = mask; + p.condition_value = 0; + + ALL_LWPS (lp, ptid) + booke_insert_point (&p, TIDGET (ptid)); + + return 0; +} + +/* Remove a masked watchpoint at ADDR with the mask MASK. + RW may be hw_read for a read watchpoint, hw_write for a write watchpoint + or hw_access for an access watchpoint. Returns 0 on success and throws + an error on failure. */ + +static int +ppc_linux_remove_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr, + CORE_ADDR mask, int rw) +{ + ptid_t ptid; + struct lwp_info *lp; + struct ppc_hw_breakpoint p; + + gdb_assert (have_ptrace_booke_interface ()); + + p.version = PPC_DEBUG_CURRENT_VERSION; + p.trigger_type = get_trigger_type (rw); + p.addr_mode = PPC_BREAKPOINT_MODE_MASK; + p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE; + p.addr = addr; + p.addr2 = mask; + p.condition_value = 0; + + ALL_LWPS (lp, ptid) + booke_remove_point (&p, TIDGET (ptid)); + + return 0; +} + /* Check whether we have at least one free DVC register. */ static int can_use_watchpoint_cond_accel (void) @@ -2224,6 +2282,26 @@ ppc_linux_watchpoint_addr_within_range (struct target_ops *target, return start <= addr + mask && start + length - 1 >= addr; } +/* Return the number of registers needed for a masked hardware watchpoint. */ + +static int +ppc_linux_masked_watch_num_registers (struct target_ops *target, + CORE_ADDR addr, CORE_ADDR mask) +{ + if (!have_ptrace_booke_interface () + || (booke_debug_info.features & PPC_DEBUG_FEATURE_DATA_BP_MASK) == 0) + return -1; + else if ((mask & 0xC0000000) != 0xC0000000) + { + warning (_("The given mask covers kernel address space " + "and cannot be used.\n")); + + return -2; + } + else + return 2; +} + static void ppc_linux_store_inferior_registers (struct target_ops *ops, struct regcache *regcache, int regno) @@ -2438,11 +2516,14 @@ _initialize_ppc_linux_nat (void) t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint; t->to_insert_watchpoint = ppc_linux_insert_watchpoint; t->to_remove_watchpoint = ppc_linux_remove_watchpoint; + t->to_insert_mask_watchpoint = ppc_linux_insert_mask_watchpoint; + t->to_remove_mask_watchpoint = ppc_linux_remove_mask_watchpoint; t->to_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint; t->to_stopped_data_address = ppc_linux_stopped_data_address; t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range; t->to_can_accel_watchpoint_condition = ppc_linux_can_accel_watchpoint_condition; + t->to_masked_watch_num_registers = ppc_linux_masked_watch_num_registers; t->to_ranged_break_num_registers = ppc_linux_ranged_break_num_registers; t->to_read_description = ppc_linux_read_description; |