This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH 2/4] Hardware accelerated watchpoint conditions
- From: Thiago Jung Bauermann <bauerman at br dot ibm dot com>
- To: gdb-patches at sourceware dot org
- Cc: Luis Machado <luisgpm at linux dot vnet dot ibm dot com>, Matt Tyrlik <tyrlik at us dot ibm dot com>
- Date: Wed, 23 Dec 2009 22:31:01 -0200
- Subject: [PATCH 2/4] Hardware accelerated watchpoint conditions
This patch teaches GDB the concept of hardware accelerated watchpoint
conditions, and enables the target to say when a condition can be
accelerated or not.
In the case of BookE processors, the condition will be accelerated
when the user types "watch A if A == B", where A and B are either
address (e.g. "*0x12345678") or variables.
--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
2009-12-23 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
Thiago Jung Bauermann <bauerman@br.ibm.com>
* breakpoint.c (update_watchpoint): Disabled watchpoints before
checking the used count. Handled the case when the hardware supports
the acceleration of the watchpoint's condition evaluation.
(insert_bp_location): Calling the correct insertion method according
to the type of the hardware watchpoint.
(remove_breakpoint_1): Calling the correct deletion method according
to the type of the hardware watchpoint.
(set_raw_breakpoint_without_location): Setting the flag to zero.
(watch_command_1): Handling the creation of hardware-accelerated
condition watchpoint.
(update_breakpoint_locations): Handling the case of a hardware
watchpoint with a condition begin hardware-accelerated.
(exp_is_address_p): New function.
(exp_is_var_p): Ditto.
(cond_is_address_equal_literal_p): Ditto.
(cond_is_var_equal_literal_p): Ditto.
(get_var_address): Ditto.
(default_watch_address_if_var_equal_literal_p): Ditto.
(default_watch_var_if_address_equal_literal_p): Ditto.
(default_watch_var_if_var_equal_literal_p): Ditto.
(default_watch_address_if_address_equal_literal_p): Ditto.
* breakpoint.h (struct bp_target_info) <length>: New field.
(struct bp_location) <cond_hw_accel>, <cond_hw_addr>: New
fields.
(enum hw_point_flag): New.
(struct breakpoint) <hw_point_flag>: New field.
(default_watch_address_if_address_equal_literal_p): Declare.
(default_watch_var_if_var_equal_literal_p): Ditto.
(default_watch_address_if_var_equal_literal_p): Ditto.
(default_watch_var_if_address_equal_literal_p): Ditto.
* ppc-linux-nat.c (ppc_linux_can_use_special_hw_point_p): New function.
(ppc_linux_insert_cond_accel_watchpoint): Ditto.
(ppc_linux_remove_cond_accel_watchpoint): Ditto.
(ppc_linux_get_watchpoint_cond_accel_addr): Ditto.
(ppc_linux_can_use_watchpoint_cond_accel_p): Ditto.
(_initialize_ppc_linux_nat): Initialize to_can_use_special_hw_point_p,
to_get_watchpoint_cond_accel_addr, co_can_use_watchpoint_cond_accel_p
to_insert_cond_accel_watchpoint and to_remove_cond_accel_watchpoint.
* target.c (update_current_target): Add to_can_use_special_hw_point_p,
to_get_watchpoint_cond_accel_addr, co_can_use_watchpoint_cond_accel_p
to_insert_cond_accel_watchpoint and to_remove_cond_accel_watchpoint.
* target.h: Add opaque declarations for bp_location, breakpoint and
hw_point_flag.
(struct target_ops <to_can_use_special_hw_point_p>,
<to_can_use_watchpoint_cond_accel_p>,
<to_insert_cond_accel_watchpoint>,
<to_remove_cond_accel_watchpoint>,
<to_get_watchpoint_cond_accel_addr>): New callbacks.
(target_region_ok_for_hw_watchpoint): Surround with ifndef.
(target_can_use_special_hw_point_p): New define.
(target_can_use_watchpoint_cond_accel_p): Ditto.
(target_get_watchpoint_cond_accel_addr): Ditto.
(target_insert_cond_accel_watchpoint): Ditto.
(target_remove_cond_accel_watchpoint): Ditto.
Index: gdb/gdb/breakpoint.c
===================================================================
--- gdb.orig/gdb/breakpoint.c 2009-12-23 15:14:03.000000000 -0200
+++ gdb/gdb/breakpoint.c 2009-12-23 17:07:34.000000000 -0200
@@ -1151,6 +1151,13 @@ update_watchpoint (struct breakpoint *b,
&& reparse)
{
int i, mem_cnt, other_type_used;
+ enum enable_state e;
+
+ /* We have to temporary disable this watchpoint, otherwise
+ we will count it twice (once as being inserted, and once
+ as a watchpoint that we want to insert). */
+ e = b->enable_state;
+ b->enable_state = bp_disabled;
i = hw_watchpoint_used_count (bp_hardware_watchpoint,
&other_type_used);
@@ -1167,6 +1174,8 @@ update_watchpoint (struct breakpoint *b,
else
b->type = bp_hardware_watchpoint;
}
+ /* Restoring the original state. */
+ b->enable_state = e;
}
frame_pspace = get_frame_program_space (get_selected_frame (NULL));
@@ -1229,6 +1238,17 @@ update_watchpoint (struct breakpoint *b,
{
char *s = b->cond_string;
b->loc->cond = parse_exp_1 (&s, b->exp_valid_block, 0);
+
+ if (b->type == bp_hardware_watchpoint
+ && target_can_use_special_hw_point_p (HW_POINT_COND_HW_ACCEL)
+ && target_can_use_watchpoint_cond_accel_p (b->loc))
+ {
+ target_get_watchpoint_cond_accel_addr (b->loc,
+ &b->loc->cond_hw_addr);
+ b->hw_point_flag = HW_POINT_COND_HW_ACCEL;
+ }
+ else
+ b->hw_point_flag = HW_POINT_NONE;
}
}
else if (!within_current_scope)
@@ -1472,9 +1492,15 @@ Note: automatically using hardware break
watchpoints. It's not clear that it's necessary... */
&& bpt->owner->disposition != disp_del_at_next_stop)
{
- val = target_insert_watchpoint (bpt->address,
- bpt->length,
- bpt->watchpoint_type);
+ if (bpt->owner->hw_point_flag == HW_POINT_COND_HW_ACCEL)
+ val = target_insert_cond_accel_watchpoint (bpt->address,
+ bpt->length,
+ bpt->watchpoint_type,
+ bpt->cond_hw_addr);
+ else
+ val = target_insert_watchpoint (bpt->address,
+ bpt->length,
+ bpt->watchpoint_type);
bpt->inserted = (val != -1);
}
@@ -2100,8 +2126,13 @@ remove_breakpoint_1 (struct bp_location
struct value *n;
b->inserted = (is == mark_inserted);
- val = target_remove_watchpoint (b->address, b->length,
- b->watchpoint_type);
+ if (b->owner->hw_point_flag == HW_POINT_COND_HW_ACCEL)
+ val = target_remove_cond_accel_watchpoint (b->address, b->length,
+ b->watchpoint_type,
+ b->cond_hw_addr);
+ else
+ val = target_remove_watchpoint (b->address, b->length,
+ b->watchpoint_type);
/* Failure to remove any of the hardware watchpoints comes here. */
if ((is == mark_uninserted) && (b->inserted))
@@ -4850,6 +4881,7 @@ set_raw_breakpoint_without_location (str
b->syscalls_to_be_caught = NULL;
b->ops = NULL;
b->condition_not_parsed = 0;
+ b->hw_point_flag = HW_POINT_NONE;
/* Add this breakpoint to the end of the chain
so that a list of breakpoints will come out in order
@@ -7300,6 +7332,10 @@ watch_command_1 (char *arg, int accessfl
that should be inserted. */
update_watchpoint (b, 1);
+ if (b->hw_point_flag == HW_POINT_COND_HW_ACCEL)
+ printf_filtered (_("This watchpoint will have its condition evaluation \
+assisted by hardware.\n"));
+
mention (b);
update_global_location_list (1);
}
@@ -8854,6 +8890,18 @@ update_breakpoint_locations (struct brea
b->number, e.message);
new_loc->enabled = 0;
}
+
+ if (b->type == bp_hardware_watchpoint
+ && new_loc->cond
+ && target_can_use_special_hw_point_p (HW_POINT_COND_HW_ACCEL)
+ && target_can_use_watchpoint_cond_accel_p (new_loc))
+ {
+ target_get_watchpoint_cond_accel_addr (new_loc,
+ &new_loc->cond_hw_addr);
+ new_loc->owner->hw_point_flag = HW_POINT_COND_HW_ACCEL;
+ }
+ else
+ new_loc->owner->hw_point_flag = HW_POINT_NONE;
}
if (b->source_file != NULL)
@@ -10019,6 +10067,242 @@ tracepoint_save_command (char *args, int
return;
}
+/* This function checks if the expression associated
+ with the breakpoint `b' is of the form "*<address>".
+ It returns 1 if it is, 0 otherwise. */
+static int
+exp_is_address_p (struct breakpoint *b)
+{
+ /* Check that the associated tree corresponds to that expression,
+ that is 5 elements, first a UNOP_IND, and then an OP_LONG. */
+ if (b->exp->nelts != 5
+ || b->exp->elts[0].opcode != UNOP_IND
+ || b->exp->elts[1].opcode != OP_LONG)
+ return 0;
+ return 1;
+}
+
+/* This function checks if the expression associated
+ with the breakpoint `b' is of the form "<var>".
+ It returns 1 if it is, 0 otherwise. */
+static int
+exp_is_var_p (struct breakpoint *b)
+{
+ /* Check that the associated tree corresponds to that expression,
+ that is 4 elements, first a OP_VAR_VALUE. */
+ if (b->exp->nelts != 4
+ || b->exp->elts[0].opcode != OP_VAR_VALUE)
+ return 0;
+ return 1;
+}
+
+/* This function checks if the condition associated
+ with the bp_location `b' is of the form "*<address> == LITERAL".
+ It returns 1 if it is, 0 otherwise. */
+static int
+cond_is_address_equal_literal_p (struct bp_location *b)
+{
+ /* Check the watchpoint condition expression. It should be
+ of the form "*<address> EQUAL <litteral>", where EQUAL is the
+ equality binary operator. */
+ if (b->cond->nelts == 10
+ && b->cond->elts[0].opcode == BINOP_EQUAL
+ && b->cond->elts[1].opcode == UNOP_IND
+ && b->cond->elts[2].opcode == OP_LONG
+ && b->cond->elts[6].opcode == OP_LONG)
+ return 1;
+ else if (b->cond->nelts == 11
+ && b->cond->elts[0].opcode == BINOP_EQUAL
+ && b->cond->elts[1].opcode == UNOP_IND
+ && b->cond->elts[2].opcode == OP_LONG
+ && b->cond->elts[6].opcode == UNOP_NEG
+ && b->cond->elts[7].opcode == OP_LONG)
+ return 1;
+
+ return 0;
+}
+
+/* This function checks if the condition associated
+ with the bp_location `b' is of the form "<var> == LITERAL".
+ It returns 1 if it is, 0 otherwise. */
+static int
+cond_is_var_equal_literal_p (struct bp_location *b)
+{
+ /* Check the watchpoint condition expression. It should be
+ of the form "<variable> EQUAL <literal>", where EQUAL is the
+ equality binary operator. */
+ if (b->cond->nelts == 9
+ && b->cond->elts[0].opcode == BINOP_EQUAL
+ && b->cond->elts[1].opcode == OP_VAR_VALUE
+ && b->cond->elts[5].opcode == OP_LONG)
+ return 1;
+ else if (b->cond->nelts == 10
+ && b->cond->elts[0].opcode == BINOP_EQUAL
+ && b->cond->elts[1].opcode == OP_VAR_VALUE
+ && b->cond->elts[5].opcode == UNOP_NEG
+ && b->cond->elts[6].opcode == OP_LONG)
+ return 1;
+
+ return 0;
+}
+
+/* This function is used to determine whether the condition associated
+ with bp_location B is of the form:
+
+ watch *<ADDRESS> if <VAR> == <LITERAL>
+
+ If it is, then it sets DATA_VALUE to LITERAL and returns 1.
+ Otherwise, it returns 0. */
+int
+default_watch_address_if_var_equal_literal_p (struct bp_location *b,
+ CORE_ADDR *data_value)
+{
+ int pc;
+ CORE_ADDR exp_address,
+ cond_address;
+ struct breakpoint *bp = b->owner;
+
+ if (!exp_is_address_p (bp)
+ || !cond_is_var_equal_literal_p (b))
+ return 0;
+
+ exp_address = bp->exp->elts[3].longconst;
+ cond_address = value_as_address (address_of_variable (b->cond->elts[3].symbol,
+ b->cond->elts[2].block));
+
+ /* Make sure that the two addresses are the same. */
+ if (exp_address != cond_address)
+ {
+ printf_filtered ("Addresses in location and condition are different.\n");
+ return 0;
+ }
+
+ /* At this point, all verifications were positive, so we can use
+ hardware-assisted data-matching. Set the data value, and return
+ non-zero. */
+ pc = 5;
+ *data_value = value_as_long (evaluate_subexp (NULL_TYPE, b->cond, &pc, EVAL_NORMAL));
+
+ return 1;
+}
+
+/* This function is used to determine whether the condition associated
+ with bp_location B is of the form:
+
+ watch <VAR> if *<ADDRESS> == <LITERAL>
+
+ If it is, then it sets DATA_VALUE to LITERAL and returns 1.
+ Otherwise, it returns 0. */
+int
+default_watch_var_if_address_equal_literal_p (struct bp_location *b,
+ CORE_ADDR *data_value)
+{
+ int pc;
+ CORE_ADDR exp_address,
+ cond_address;
+ struct breakpoint *bp = b->owner;
+
+ if (!exp_is_var_p (bp)
+ || !cond_is_address_equal_literal_p (b))
+ return 0;
+
+ exp_address = value_as_address (address_of_variable (bp->exp->elts[2].symbol,
+ bp->exp->elts[1].block));
+ cond_address = b->cond->elts[4].longconst;
+
+ /* Make sure that the two addresses are the same. */
+ if (exp_address != cond_address)
+ {
+ printf_filtered ("Addresses in location and condition are different.\n");
+ return 0;
+ }
+
+ /* At this point, all verifications were positive, so we can use
+ hardware-assisted data-matching. Set the data value, and return
+ non-zero. */
+ pc = 6;
+ *data_value = value_as_long (evaluate_subexp (NULL_TYPE, b->cond, &pc, EVAL_NORMAL));
+
+ return 1;
+}
+
+/* This function is used to determine whether the condition associated
+ with bp_location B is of the form:
+
+ watch <VAR> if <VAR> == <LITERAL>
+
+ If it is, then it sets DATA_VALUE to LITERAL and returns 1.
+ Otherwise, it returns 0. */
+int
+default_watch_var_if_var_equal_literal_p (struct bp_location *b,
+ CORE_ADDR *data_value)
+{
+ int pc;
+ char *name_exp, *name_cond;
+ struct breakpoint *bp = b->owner;
+
+ if (!exp_is_var_p (bp)
+ || !cond_is_var_equal_literal_p (b))
+ return 0;
+
+ name_exp = bp->exp->elts[2].symbol->ginfo.name;
+ name_cond = b->cond->elts[3].symbol->ginfo.name;
+
+ /* Make sure that the two variables' names are the same. */
+ if (strcmp (name_cond, name_exp) != 0)
+ {
+ printf_filtered ("Addresses in location and condition are different.\n");
+ return 0;
+ }
+
+ /* At this point, all verifications were positive, so we can use
+ hardware-assisted data-matching. Set the data value, and return
+ non-zero. */
+ pc = 5;
+ *data_value = value_as_long (evaluate_subexp (NULL_TYPE, b->cond, &pc, EVAL_NORMAL));
+
+ return 1;
+}
+
+/* This function is used to determine whether the condition associated
+ with bp_location B is of the form:
+
+ watch *<ADDRESS> if *<ADDRESS> == <LITERAL>
+
+ If it is, then it sets DATA_VALUE to LITERAL and returns 1.
+ Otherwise, it returns 0. */
+int
+default_watch_address_if_address_equal_literal_p (struct bp_location *b,
+ CORE_ADDR *data_value)
+{
+ int pc;
+ CORE_ADDR exp_address,
+ cond_address;
+ struct breakpoint *bp = b->owner;
+
+ if (!exp_is_address_p (bp)
+ || !cond_is_address_equal_literal_p (b))
+ return 0;
+
+ exp_address = bp->exp->elts[3].longconst;
+ cond_address = b->cond->elts[4].longconst;
+
+ /* Make sure that the two addresses are the same. */
+ if (exp_address != cond_address)
+ {
+ printf_filtered ("Addresses in location and condition are different.\n");
+ return 0;
+ }
+
+ /* At this point, all verifications were positive, so we can use
+ hardware-assisted data-matching. Set the data value, and return
+ non-zero. */
+ pc = 6;
+ *data_value = value_as_long (evaluate_subexp (NULL_TYPE, b->cond, &pc, EVAL_NORMAL));
+
+ return 1;
+}
+
/* Create a vector of all tracepoints. */
VEC(breakpoint_p) *
Index: gdb/gdb/breakpoint.h
===================================================================
--- gdb.orig/gdb/breakpoint.h 2009-12-23 15:14:03.000000000 -0200
+++ gdb/gdb/breakpoint.h 2009-12-23 17:04:23.000000000 -0200
@@ -186,6 +186,11 @@ struct bp_target_info
is used to determine the type of breakpoint to insert. */
CORE_ADDR placed_address;
+ /* If this is a ranged hardware breakpoint, then we can use this
+ field in order to store the length of the range that will be
+ watched for execution. */
+ ULONGEST length;
+
/* If the breakpoint lives in memory and reading that memory would
give back the breakpoint, instead of the original contents, then
the original contents are cached here. Only SHADOW_LEN bytes of
@@ -246,6 +251,17 @@ struct bp_location
different locations. */
struct expression *cond;
+ /* Flag to indicate if the condition is going to be accelerated
+ by hardware. If its value is non-zero, then GDB checks the
+ condition using hardware acceleration; otherwise it uses the
+ regular software-based checking. */
+ int cond_hw_accel : 1;
+
+ /* If the condition can be hardware-accelerated, then we must
+ get the condition's variable address so that GDB can
+ properly set the evaluation via hardware. */
+ CORE_ADDR cond_hw_addr;
+
/* This location's address is in an unloaded solib, and so this
location should not be inserted. It will be automatically
enabled when that solib is loaded. */
@@ -373,6 +389,13 @@ DEF_VEC_I(int);
typedef struct bp_location *bp_location_p;
DEF_VEC_P(bp_location_p);
+/* Special flags for hardware breakpoints/watchpoints. */
+enum hw_point_flag {
+ HW_POINT_NONE = 0,
+ HW_POINT_COND_HW_ACCEL, /* Hardware watchpoint with condition
+ hardware-accelerated. */
+};
+
/* Note that the ->silent field is not currently used by any commands
(though the code is in there if it was to be, and set_raw_breakpoint
does set it to 0). I implemented it because I thought it would be
@@ -512,6 +535,9 @@ struct breakpoint
/* Chain of action lines to execute when this tracepoint is hit. */
struct action_line *actions;
+
+ /* Special flags. */
+ enum hw_point_flag hw_point_flag;
};
typedef struct breakpoint *breakpoint_p;
@@ -992,4 +1018,20 @@ extern struct breakpoint *get_tracepoint
is newly allocated; the caller should free when done with it. */
extern VEC(breakpoint_p) *all_tracepoints (void);
+/* Return greater than zero if the condition associated with
+ the watchpoint `b' can be treated by the hardware; zero otherwise.
+
+ Also stores the data value in `data_value'. */
+extern int default_watch_address_if_address_equal_literal_p (struct bp_location *b,
+ CORE_ADDR *data_value);
+
+extern int default_watch_var_if_var_equal_literal_p (struct bp_location *b,
+ CORE_ADDR *data_value);
+
+extern int default_watch_address_if_var_equal_literal_p (struct bp_location *b,
+ CORE_ADDR *data_value);
+
+extern int default_watch_var_if_address_equal_literal_p (struct bp_location *b,
+ CORE_ADDR *data_value);
+
#endif /* !defined (BREAKPOINT_H) */
Index: gdb/gdb/ppc-linux-nat.c
===================================================================
--- gdb.orig/gdb/ppc-linux-nat.c 2009-12-23 15:15:13.000000000 -0200
+++ gdb/gdb/ppc-linux-nat.c 2009-12-23 17:04:23.000000000 -0200
@@ -1452,6 +1452,26 @@ ppc_linux_can_use_hw_breakpoint (int typ
}
static int
+ppc_linux_can_use_special_hw_point_p (enum hw_point_flag flag)
+{
+ uint64_t features = booke_debug_info.features;
+
+ if (!have_ptrace_new_debug_booke)
+ return 0;
+
+ switch (flag)
+ {
+ case HW_POINT_COND_HW_ACCEL:
+ return booke_debug_info.num_condition_regs > 0;
+ /* We also accept non-special *points. */
+ case HW_POINT_NONE:
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
{
/* Handle sub-8-byte quantities. */
@@ -1657,6 +1677,76 @@ ppc_linux_remove_hw_breakpoint (struct g
t = PPC_BREAKPOINT_TRIGGER_READ | PPC_BREAKPOINT_TRIGGER_WRITE;
static int
+ppc_linux_insert_cond_accel_watchpoint (CORE_ADDR addr, int len, int rw,
+ CORE_ADDR cond)
+{
+ struct ppc_hw_breakpoint p;
+ uint32_t trigger;
+ unsigned long a = (unsigned long) addr,
+ c = (unsigned long) cond;
+ struct lwp_info *lp;
+ ptid_t ptid;
+ int byte_to_enable;
+
+ if (!have_ptrace_new_debug_booke)
+ return -1;
+
+ HW_WATCH_RW_TRIGGER (trigger, rw);
+
+ byte_to_enable = a % 4;
+ c >>= (byte_to_enable * 8);
+
+ p.version = PPC_DEBUG_CURRENT_VERSION;
+ p.trigger_type = trigger;
+ p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
+ p.condition_mode = PPC_BREAKPOINT_CONDITION_AND
+ | PPC_BREAKPOINT_CONDITION_BE (byte_to_enable);
+ p.addr = (uint64_t) a;
+ p.addr2 = 0;
+ p.condition_value = (uint64_t) c;
+
+ ALL_LWPS (lp, ptid)
+ booke_insert_point (&p, TIDGET (ptid));
+
+ return 0;
+}
+
+static int
+ppc_linux_remove_cond_accel_watchpoint (CORE_ADDR addr, int len, int rw,
+ CORE_ADDR cond)
+{
+ struct ppc_hw_breakpoint p;
+ uint32_t trigger;
+ unsigned long a = (unsigned long) addr,
+ c = (unsigned long) cond;
+ struct lwp_info *lp;
+ ptid_t ptid;
+ int byte_to_enable;
+
+ if (!have_ptrace_new_debug_booke)
+ return -1;
+
+ HW_WATCH_RW_TRIGGER (trigger, rw);
+
+ byte_to_enable = a % 4;
+ c >>= (byte_to_enable * 8);
+
+ p.version = PPC_DEBUG_CURRENT_VERSION;
+ p.trigger_type = trigger;
+ p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
+ p.condition_mode = PPC_BREAKPOINT_CONDITION_AND
+ | PPC_BREAKPOINT_CONDITION_BE (byte_to_enable);
+ p.addr = (uint64_t) a;
+ p.addr2 = 0;
+ p.condition_value = (uint64_t) c;
+
+ ALL_LWPS (lp, ptid)
+ booke_remove_point (&p, TIDGET (ptid));
+
+ return 0;
+}
+
+static int
ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
{
struct lwp_info *lp;
@@ -1872,6 +1962,52 @@ ppc_linux_watchpoint_addr_within_range (
return start <= addr + mask && start + length - 1 >= addr;
}
+static int
+ppc_linux_get_watchpoint_cond_accel_addr (struct bp_location *b,
+ CORE_ADDR *addr)
+{
+ if (have_ptrace_new_debug_booke)
+ return default_watch_address_if_address_equal_literal_p (b, addr)
+ || default_watch_var_if_var_equal_literal_p (b, addr)
+ || default_watch_var_if_address_equal_literal_p (b, addr)
+ || default_watch_address_if_var_equal_literal_p (b, addr);
+
+ *addr = 0;
+
+ return 0;
+}
+
+static int
+ppc_linux_can_use_watchpoint_cond_accel_p (struct bp_location *b)
+{
+ struct thread_points *p;
+ int tid = TIDGET (inferior_ptid);
+ int cnt = booke_debug_info.num_condition_regs, i;
+ CORE_ADDR tmp_value;
+
+ if (!have_ptrace_new_debug_booke)
+ return 0;
+
+ p = booke_find_thread_points_by_tid (tid, 0);
+
+ if (p)
+ {
+ for (i = 0; i < max_slots_number; i++)
+ if (p->hw_breaks[i].hw_break != NULL
+ && p->hw_breaks[i].hw_break->condition_mode
+ != PPC_BREAKPOINT_CONDITION_NONE)
+ cnt--;
+
+ /* There are no available slots now. */
+ if (cnt <= 0)
+ return 0;
+ }
+
+ /* We have to know if the condition associated with the bp_location
+ can be hardware-accelerated. */
+ return ppc_linux_get_watchpoint_cond_accel_addr (b, &tmp_value);
+}
+
static void
ppc_linux_store_inferior_registers (struct target_ops *ops,
struct regcache *regcache, int regno)
@@ -2094,11 +2230,18 @@ _initialize_ppc_linux_nat (void)
/* Add our breakpoint/watchpoint methods. */
t->to_can_use_hw_breakpoint = ppc_linux_can_use_hw_breakpoint;
+ t->to_can_use_special_hw_point_p = ppc_linux_can_use_special_hw_point_p;
t->to_insert_hw_breakpoint = ppc_linux_insert_hw_breakpoint;
t->to_remove_hw_breakpoint = ppc_linux_remove_hw_breakpoint;
t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
+ t->to_get_watchpoint_cond_accel_addr =
+ ppc_linux_get_watchpoint_cond_accel_addr;
+ t->to_can_use_watchpoint_cond_accel_p =
+ ppc_linux_can_use_watchpoint_cond_accel_p;
t->to_insert_watchpoint = ppc_linux_insert_watchpoint;
t->to_remove_watchpoint = ppc_linux_remove_watchpoint;
+ t->to_insert_cond_accel_watchpoint = ppc_linux_insert_cond_accel_watchpoint;
+ t->to_remove_cond_accel_watchpoint = ppc_linux_remove_cond_accel_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;
Index: gdb/gdb/target.c
===================================================================
--- gdb.orig/gdb/target.c 2009-12-23 15:14:03.000000000 -0200
+++ gdb/gdb/target.c 2009-12-23 17:04:23.000000000 -0200
@@ -619,11 +619,16 @@ update_current_target (void)
INHERIT (to_files_info, t);
INHERIT (to_insert_breakpoint, t);
INHERIT (to_remove_breakpoint, t);
+ INHERIT (to_can_use_special_hw_point_p, t);
+ INHERIT (to_can_use_watchpoint_cond_accel_p, t);
INHERIT (to_can_use_hw_breakpoint, t);
INHERIT (to_insert_hw_breakpoint, t);
INHERIT (to_remove_hw_breakpoint, t);
INHERIT (to_insert_watchpoint, t);
INHERIT (to_remove_watchpoint, t);
+ INHERIT (to_insert_cond_accel_watchpoint, t);
+ INHERIT (to_remove_cond_accel_watchpoint, t);
+ INHERIT (to_get_watchpoint_cond_accel_addr, t);
INHERIT (to_stopped_data_address, t);
INHERIT (to_have_steppable_watchpoint, t);
INHERIT (to_have_continuable_watchpoint, t);
@@ -725,6 +730,12 @@ update_current_target (void)
de_fault (to_can_use_hw_breakpoint,
(int (*) (int, int, int))
return_zero);
+ de_fault (to_can_use_special_hw_point_p,
+ (int (*) (enum hw_point_flag))
+ return_zero);
+ de_fault (to_can_use_watchpoint_cond_accel_p,
+ (int (*) (struct bp_location *))
+ return_zero);
de_fault (to_insert_hw_breakpoint,
(int (*) (struct gdbarch *, struct bp_target_info *))
return_minus_one);
@@ -737,6 +748,12 @@ update_current_target (void)
de_fault (to_remove_watchpoint,
(int (*) (CORE_ADDR, int, int))
return_minus_one);
+ de_fault (to_insert_cond_accel_watchpoint,
+ (int (*) (CORE_ADDR, int, int, CORE_ADDR))
+ return_minus_one);
+ de_fault (to_remove_cond_accel_watchpoint,
+ (int (*) (CORE_ADDR, int, int, CORE_ADDR))
+ return_minus_one);
de_fault (to_stopped_by_watchpoint,
(int (*) (void))
return_zero);
@@ -747,6 +764,9 @@ update_current_target (void)
default_watchpoint_addr_within_range);
de_fault (to_region_ok_for_hw_watchpoint,
default_region_ok_for_hw_watchpoint);
+ de_fault (to_get_watchpoint_cond_accel_addr,
+ (int (*) (struct bp_location *, CORE_ADDR *))
+ return_zero);
de_fault (to_terminal_init,
(void (*) (void))
target_ignore);
Index: gdb/gdb/target.h
===================================================================
--- gdb.orig/gdb/target.h 2009-12-23 15:14:03.000000000 -0200
+++ gdb/gdb/target.h 2009-12-23 17:06:07.000000000 -0200
@@ -32,6 +32,11 @@ struct bp_target_info;
struct regcache;
struct target_section_table;
+struct bp_location;
+struct breakpoint;
+
+enum hw_point_flag;
+
/* This include file defines the interface between the main part
of the debugger, and the part which is target-specific, or
specific to the communications interface between us and the
@@ -400,16 +405,22 @@ struct target_ops
int (*to_insert_breakpoint) (struct gdbarch *, struct bp_target_info *);
int (*to_remove_breakpoint) (struct gdbarch *, struct bp_target_info *);
int (*to_can_use_hw_breakpoint) (int, int, int);
+ int (*to_can_use_special_hw_point_p) (enum hw_point_flag);
+ int (*to_can_use_watchpoint_cond_accel_p) (struct bp_location *);
int (*to_insert_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
int (*to_remove_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
int (*to_remove_watchpoint) (CORE_ADDR, int, int);
int (*to_insert_watchpoint) (CORE_ADDR, int, int);
+ int (*to_insert_cond_accel_watchpoint) (CORE_ADDR, int, int, CORE_ADDR);
+ int (*to_remove_cond_accel_watchpoint) (CORE_ADDR, int, int, CORE_ADDR);
int (*to_stopped_by_watchpoint) (void);
int to_have_steppable_watchpoint;
int to_have_continuable_watchpoint;
int (*to_stopped_data_address) (struct target_ops *, CORE_ADDR *);
int (*to_watchpoint_addr_within_range) (struct target_ops *,
CORE_ADDR, CORE_ADDR, int);
+ int (*to_get_watchpoint_cond_accel_addr) (struct bp_location *,
+ CORE_ADDR *);
int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int);
void (*to_terminal_init) (void);
void (*to_terminal_inferior) (void);
@@ -1184,9 +1195,29 @@ extern char *normal_pid_to_str (ptid_t p
#define target_can_use_hardware_watchpoint(TYPE,CNT,OTHERTYPE) \
(*current_target.to_can_use_hw_breakpoint) (TYPE, CNT, OTHERTYPE);
+#ifndef target_region_ok_for_hw_watchpoint
#define target_region_ok_for_hw_watchpoint(addr, len) \
(*current_target.to_region_ok_for_hw_watchpoint) (addr, len)
+#endif
+/* Returns non-zero if the target supports the special type of hardware
+ breakpoint/watchpoint represented by FLAG. */
+#ifndef target_can_use_special_hw_point_p
+#define target_can_use_special_hw_point_p(flag) \
+ (*current_target.to_can_use_special_hw_point_p) (flag)
+#endif
+
+/* Returns greater than zero if the target supports hardware-accelerated
+ condition. */
+#ifndef target_can_use_watchpoint_cond_accel_p
+#define target_can_use_watchpoint_cond_accel_p(loc) \
+ (*current_target.to_can_use_watchpoint_cond_accel_p) (loc)
+#endif
+
+#ifndef target_get_watchpoint_cond_accel_addr
+#define target_get_watchpoint_cond_accel_addr(loc, addr) \
+ (*current_target.to_get_watchpoint_cond_accel_addr) (loc, addr)
+#endif
/* Set/clear a hardware watchpoint starting at ADDR, for LEN bytes. TYPE is 0
for write, 1 for read, and 2 for read/write accesses. Returns 0 for
@@ -1198,6 +1229,18 @@ extern char *normal_pid_to_str (ptid_t p
#define target_remove_watchpoint(addr, len, type) \
(*current_target.to_remove_watchpoint) (addr, len, type)
+/* Hardware watchpoint with a condition associated (to be
+ hardware-accelerated). */
+#ifndef target_insert_cond_accel_watchpoint
+#define target_insert_cond_accel_watchpoint(addr, len, type, cond) \
+ (*current_target.to_insert_cond_accel_watchpoint) (addr, len, type, cond)
+#endif
+
+#ifndef target_remove_cond_accel_watchpoint
+#define target_remove_cond_accel_watchpoint(addr, len, type, cond) \
+ (*current_target.to_remove_cond_accel_watchpoint) (addr, len, type, cond)
+#endif
+
#define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
(*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)