aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThiago Jung Bauermann <bauerman@br.ibm.com>2010-07-07 16:15:18 +0000
committerThiago Jung Bauermann <bauerman@br.ibm.com>2010-07-07 16:15:18 +0000
commit0cf6dd1543299e30c82397ef49d00b32af911a63 (patch)
treeae3f26f11acc891e1092331af2f955cc80b05896
parent6bd31874685a739404578403651d7b1ad5d20a3e (diff)
downloadfsf-binutils-gdb-0cf6dd1543299e30c82397ef49d00b32af911a63.zip
fsf-binutils-gdb-0cf6dd1543299e30c82397ef49d00b32af911a63.tar.gz
fsf-binutils-gdb-0cf6dd1543299e30c82397ef49d00b32af911a63.tar.bz2
2010-07-07 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>gdb_7_2-branchpoint
Thiago Jung Bauermann <bauerman@br.ibm.com> Support for hw accelerated condition watchpoints in booke powerpc. * breakpoint.c (fetch_watchpoint_value): Rename to fetch_subexp_value and move to eval.c. Change callers. (insert_bp_location): Pass watchpoint condition in target_insert_watchpoint. (remove_breakpoint_1) Pass watchpoint condition in target_remove_watchpoint. (watchpoint_locations_match): Call target_can_accel_watchpoint_condition. * eval.c: Include wrapper.h. (fetch_subexp_value): Moved from breakpoint.c. * ppc-linux-nat.c (ppc_linux_region_ok_for_hw_watchpoint): Formatting fix. (can_use_watchpoint_cond_accel): New function. (calculate_dvc): Likewise. (num_memory_accesses): Likewise. (check_condition): Likewise. (ppc_linux_can_accel_watchpoint_condition): Likewise (ppc_linux_insert_watchpoint): Call can_use_watchpoint_cond_accel, check_condition and calculate_dvc. (ppc_linux_remove_watchpoint): Likewise. (_initialize_ppc_linux_nat): Set to_can_accel_watchpoint_condition to ppc_linux_can_accel_watchpoint_condition * target.c (debug_to_insert_watchpoint): Add argument for watchpoint condition. (debug_to_remove_watchpoint): Likewise. (debug_to_can_accel_watchpoint_condition): New function. (update_current_target): Set to_can_accel_watchpoint_condition. (setup_target_debug): Set to_can_accel_watchpoint_condition. * target.h: Add opaque declaration for struct expression. (struct target_ops) <to_insert_watchpoint>, <to_remove_watchpoint>: Add new arguments to pass the watchpoint <to_can_accel_watchpoint_condition>: New member. condition. Update all callers and implementations. (target_can_accel_watchpoint_condition): New macro. * value.c (free_value_chain): New function. * value.h (fetch_subexp_value): New prototype. (free_value_chain): Likewise.
-rw-r--r--gdb/ChangeLog43
-rw-r--r--gdb/breakpoint.c112
-rw-r--r--gdb/eval.c79
-rw-r--r--gdb/i386-nat.c6
-rw-r--r--gdb/ia64-linux-nat.c6
-rw-r--r--gdb/inf-ttrace.c6
-rw-r--r--gdb/mips-linux-nat.c6
-rw-r--r--gdb/nto-procfs.c6
-rw-r--r--gdb/ppc-linux-nat.c234
-rw-r--r--gdb/procfs.c6
-rw-r--r--gdb/remote-m32r-sdi.c6
-rw-r--r--gdb/remote-mips.c6
-rw-r--r--gdb/remote.c6
-rw-r--r--gdb/s390-nat.c6
-rw-r--r--gdb/target.c53
-rw-r--r--gdb/target.h34
-rw-r--r--gdb/value.c14
-rw-r--r--gdb/value.h6
18 files changed, 503 insertions, 132 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 9408b1c..dd81237 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,46 @@
+2010-07-07 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
+ Thiago Jung Bauermann <bauerman@br.ibm.com>
+
+ Support for hw accelerated condition watchpoints in booke powerpc.
+
+ * breakpoint.c (fetch_watchpoint_value): Rename to fetch_subexp_value
+ and move to eval.c. Change callers.
+ (insert_bp_location): Pass watchpoint condition in
+ target_insert_watchpoint.
+ (remove_breakpoint_1) Pass watchpoint condition in
+ target_remove_watchpoint.
+ (watchpoint_locations_match): Call
+ target_can_accel_watchpoint_condition.
+ * eval.c: Include wrapper.h.
+ (fetch_subexp_value): Moved from breakpoint.c.
+ * ppc-linux-nat.c (ppc_linux_region_ok_for_hw_watchpoint):
+ Formatting fix.
+ (can_use_watchpoint_cond_accel): New function.
+ (calculate_dvc): Likewise.
+ (num_memory_accesses): Likewise.
+ (check_condition): Likewise.
+ (ppc_linux_can_accel_watchpoint_condition): Likewise
+ (ppc_linux_insert_watchpoint): Call can_use_watchpoint_cond_accel,
+ check_condition and calculate_dvc.
+ (ppc_linux_remove_watchpoint): Likewise.
+ (_initialize_ppc_linux_nat): Set to_can_accel_watchpoint_condition to
+ ppc_linux_can_accel_watchpoint_condition
+ * target.c (debug_to_insert_watchpoint): Add argument for watchpoint
+ condition.
+ (debug_to_remove_watchpoint): Likewise.
+ (debug_to_can_accel_watchpoint_condition): New function.
+ (update_current_target): Set to_can_accel_watchpoint_condition.
+ (setup_target_debug): Set to_can_accel_watchpoint_condition.
+ * target.h: Add opaque declaration for struct expression.
+ (struct target_ops) <to_insert_watchpoint>,
+ <to_remove_watchpoint>: Add new arguments to pass the watchpoint
+ <to_can_accel_watchpoint_condition>: New member.
+ condition. Update all callers and implementations.
+ (target_can_accel_watchpoint_condition): New macro.
+ * value.c (free_value_chain): New function.
+ * value.h (fetch_subexp_value): New prototype.
+ (free_value_chain): Likewise.
+
2010-07-07 Ulrich Weigand <uweigand@de.ibm.com>
* linux-nat.c (linux_nat_do_thread_registers): Use section size
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 3c93c4b..4affe0a 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1234,84 +1234,6 @@ is_watchpoint (const struct breakpoint *bpt)
|| bpt->type == bp_watchpoint);
}
-/* Find the current value of a watchpoint on EXP. Return the value in
- *VALP and *RESULTP and the chain of intermediate and final values
- in *VAL_CHAIN. RESULTP and VAL_CHAIN may be NULL if the caller does
- not need them.
-
- If a memory error occurs while evaluating the expression, *RESULTP will
- be set to NULL. *RESULTP may be a lazy value, if the result could
- not be read from memory. It is used to determine whether a value
- is user-specified (we should watch the whole value) or intermediate
- (we should watch only the bit used to locate the final value).
-
- If the final value, or any intermediate value, could not be read
- from memory, *VALP will be set to NULL. *VAL_CHAIN will still be
- set to any referenced values. *VALP will never be a lazy value.
- This is the value which we store in struct breakpoint.
-
- If VAL_CHAIN is non-NULL, *VAL_CHAIN will be released from the
- value chain. The caller must free the values individually. If
- VAL_CHAIN is NULL, all generated values will be left on the value
- chain. */
-
-static void
-fetch_watchpoint_value (struct expression *exp, struct value **valp,
- struct value **resultp, struct value **val_chain)
-{
- struct value *mark, *new_mark, *result;
- volatile struct gdb_exception ex;
-
- *valp = NULL;
- if (resultp)
- *resultp = NULL;
- if (val_chain)
- *val_chain = NULL;
-
- /* Evaluate the expression. */
- mark = value_mark ();
- result = NULL;
-
- TRY_CATCH (ex, RETURN_MASK_ALL)
- {
- result = evaluate_expression (exp);
- }
- if (ex.reason < 0)
- {
- /* Ignore memory errors, we want watchpoints pointing at
- inaccessible memory to still be created; otherwise, throw the
- error to some higher catcher. */
- switch (ex.error)
- {
- case MEMORY_ERROR:
- break;
- default:
- throw_exception (ex);
- break;
- }
- }
-
- new_mark = value_mark ();
- if (mark == new_mark)
- return;
- if (resultp)
- *resultp = result;
-
- /* Make sure it's not lazy, so that after the target stops again we
- have a non-lazy previous value to compare with. */
- if (result != NULL
- && (!value_lazy (result) || gdb_value_fetch_lazy (result)))
- *valp = result;
-
- if (val_chain)
- {
- /* Return the chain of intermediate values. We use this to
- decide which addresses to watch. */
- *val_chain = new_mark;
- value_release_to_mark (mark);
- }
-}
-
/* Assuming that B is a watchpoint: returns true if the current thread
and its running state are safe to evaluate or update watchpoint B.
Watchpoints on local expressions need to be evaluated in the
@@ -1469,10 +1391,11 @@ update_watchpoint (struct breakpoint *b, int reparse)
}
else if (within_current_scope && b->exp)
{
+ int pc = 0;
struct value *val_chain, *v, *result, *next;
struct program_space *frame_pspace;
- fetch_watchpoint_value (b->exp, &v, &result, &val_chain);
+ fetch_subexp_value (b->exp, &pc, &v, &result, &val_chain);
/* Avoid setting b->val if it's already set. The meaning of
b->val is 'the last value' user saw, and we should update
@@ -1828,7 +1751,8 @@ Note: automatically using hardware breakpoints for read-only addresses.\n"));
{
val = target_insert_watchpoint (bpt->address,
bpt->length,
- bpt->watchpoint_type);
+ bpt->watchpoint_type,
+ bpt->owner->cond_exp);
/* If trying to set a read-watchpoint, and it turns out it's not
supported, try emulating one with an access watchpoint. */
@@ -1856,7 +1780,8 @@ Note: automatically using hardware breakpoints for read-only addresses.\n"));
{
val = target_insert_watchpoint (bpt->address,
bpt->length,
- hw_access);
+ hw_access,
+ bpt->owner->cond_exp);
if (val == 0)
bpt->watchpoint_type = hw_access;
}
@@ -2525,8 +2450,8 @@ remove_breakpoint_1 (struct bp_location *b, insertion_state_t is)
else if (b->loc_type == bp_loc_hardware_watchpoint)
{
b->inserted = (is == mark_inserted);
- val = target_remove_watchpoint (b->address, b->length,
- b->watchpoint_type);
+ val = target_remove_watchpoint (b->address, b->length,
+ b->watchpoint_type, b->owner->cond_exp);
/* Failure to remove any of the hardware watchpoints comes here. */
if ((is == mark_uninserted) && (b->inserted))
@@ -3679,10 +3604,11 @@ watchpoint_check (void *p)
call free_all_values. We can't call free_all_values because
we might be in the middle of evaluating a function call. */
+ int pc = 0;
struct value *mark = value_mark ();
struct value *new_val;
- fetch_watchpoint_value (b->exp, &new_val, NULL, NULL);
+ fetch_subexp_value (b->exp, &pc, &new_val, NULL, NULL);
/* We use value_equal_contents instead of value_equal because the latter
coerces an array to a pointer, thus comparing just the address of the
@@ -5262,6 +5188,21 @@ watchpoint_locations_match (struct bp_location *loc1, struct bp_location *loc2)
gdb_assert (loc1->owner != NULL);
gdb_assert (loc2->owner != NULL);
+ /* If the target can evaluate the condition expression in hardware, then we
+ we need to insert both watchpoints even if they are at the same place.
+ Otherwise the watchpoint will only trigger when the condition of whichever
+ watchpoint was inserted evaluates to true, not giving a chance for GDB to
+ check the condition of the other watchpoint. */
+ if ((loc1->owner->cond_exp
+ && target_can_accel_watchpoint_condition (loc1->address, loc1->length,
+ loc1->watchpoint_type,
+ loc1->owner->cond_exp))
+ || (loc2->owner->cond_exp
+ && target_can_accel_watchpoint_condition (loc2->address, loc2->length,
+ loc2->watchpoint_type,
+ loc2->owner->cond_exp)))
+ return 0;
+
/* Note that this checks the owner's type, not the location's. In
case the target does not support read watchpoints, but does
support access watchpoints, we'll have bp_read_watchpoint
@@ -8057,6 +7998,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
enum bptype bp_type;
int mem_cnt = 0;
int thread = -1;
+ int pc = 0;
/* Make sure that we actually have parameters to parse. */
if (arg != NULL && arg[0] != '\0')
@@ -8143,7 +8085,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
exp_valid_block = innermost_block;
mark = value_mark ();
- fetch_watchpoint_value (exp, &val, NULL, NULL);
+ fetch_subexp_value (exp, &pc, &val, NULL, NULL);
if (val != NULL)
release_value (val);
diff --git a/gdb/eval.c b/gdb/eval.c
index 9a60616..ff17c34 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -43,6 +43,7 @@
#include "gdb_obstack.h"
#include "objfiles.h"
#include "python/python.h"
+#include "wrapper.h"
#include "gdb_assert.h"
@@ -186,6 +187,84 @@ evaluate_subexpression_type (struct expression *exp, int subexp)
return evaluate_subexp (NULL_TYPE, exp, &subexp, EVAL_AVOID_SIDE_EFFECTS);
}
+/* Find the current value of a watchpoint on EXP. Return the value in
+ *VALP and *RESULTP and the chain of intermediate and final values
+ in *VAL_CHAIN. RESULTP and VAL_CHAIN may be NULL if the caller does
+ not need them.
+
+ If a memory error occurs while evaluating the expression, *RESULTP will
+ be set to NULL. *RESULTP may be a lazy value, if the result could
+ not be read from memory. It is used to determine whether a value
+ is user-specified (we should watch the whole value) or intermediate
+ (we should watch only the bit used to locate the final value).
+
+ If the final value, or any intermediate value, could not be read
+ from memory, *VALP will be set to NULL. *VAL_CHAIN will still be
+ set to any referenced values. *VALP will never be a lazy value.
+ This is the value which we store in struct breakpoint.
+
+ If VAL_CHAIN is non-NULL, *VAL_CHAIN will be released from the
+ value chain. The caller must free the values individually. If
+ VAL_CHAIN is NULL, all generated values will be left on the value
+ chain. */
+
+void
+fetch_subexp_value (struct expression *exp, int *pc, struct value **valp,
+ struct value **resultp, struct value **val_chain)
+{
+ struct value *mark, *new_mark, *result;
+ volatile struct gdb_exception ex;
+
+ *valp = NULL;
+ if (resultp)
+ *resultp = NULL;
+ if (val_chain)
+ *val_chain = NULL;
+
+ /* Evaluate the expression. */
+ mark = value_mark ();
+ result = NULL;
+
+ TRY_CATCH (ex, RETURN_MASK_ALL)
+ {
+ result = evaluate_subexp (NULL_TYPE, exp, pc, EVAL_NORMAL);
+ }
+ if (ex.reason < 0)
+ {
+ /* Ignore memory errors, we want watchpoints pointing at
+ inaccessible memory to still be created; otherwise, throw the
+ error to some higher catcher. */
+ switch (ex.error)
+ {
+ case MEMORY_ERROR:
+ break;
+ default:
+ throw_exception (ex);
+ break;
+ }
+ }
+
+ new_mark = value_mark ();
+ if (mark == new_mark)
+ return;
+ if (resultp)
+ *resultp = result;
+
+ /* Make sure it's not lazy, so that after the target stops again we
+ have a non-lazy previous value to compare with. */
+ if (result != NULL
+ && (!value_lazy (result) || gdb_value_fetch_lazy (result)))
+ *valp = result;
+
+ if (val_chain)
+ {
+ /* Return the chain of intermediate values. We use this to
+ decide which addresses to watch. */
+ *val_chain = new_mark;
+ value_release_to_mark (mark);
+ }
+}
+
/* Extract a field operation from an expression. If the subexpression
of EXP starting at *SUBEXP is not a structure dereference
operation, return NULL. Otherwise, return the name of the
diff --git a/gdb/i386-nat.c b/gdb/i386-nat.c
index 82c51d7..eaa3644 100644
--- a/gdb/i386-nat.c
+++ b/gdb/i386-nat.c
@@ -484,7 +484,8 @@ Invalid value %d of operation in i386_handle_nonaligned_watchpoint.\n"),
of the type TYPE. Return 0 on success, -1 on failure. */
static int
-i386_insert_watchpoint (CORE_ADDR addr, int len, int type)
+i386_insert_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
int retval;
@@ -511,7 +512,8 @@ i386_insert_watchpoint (CORE_ADDR addr, int len, int type)
address ADDR, whose length is LEN bytes, and for accesses of the
type TYPE. Return 0 on success, -1 on failure. */
static int
-i386_remove_watchpoint (CORE_ADDR addr, int len, int type)
+i386_remove_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
int retval;
diff --git a/gdb/ia64-linux-nat.c b/gdb/ia64-linux-nat.c
index e6a7077..d33e88e 100644
--- a/gdb/ia64-linux-nat.c
+++ b/gdb/ia64-linux-nat.c
@@ -530,7 +530,8 @@ is_power_of_2 (int val)
}
static int
-ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
+ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
+ struct expression *cond)
{
struct lwp_info *lp;
ptid_t ptid;
@@ -584,7 +585,8 @@ ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
}
static int
-ia64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
+ia64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
int idx;
long dbr_addr, dbr_mask;
diff --git a/gdb/inf-ttrace.c b/gdb/inf-ttrace.c
index 199ceb9..aa0462f 100644
--- a/gdb/inf-ttrace.c
+++ b/gdb/inf-ttrace.c
@@ -314,7 +314,8 @@ inf_ttrace_disable_page_protections (pid_t pid)
type TYPE. */
static int
-inf_ttrace_insert_watchpoint (CORE_ADDR addr, int len, int type)
+inf_ttrace_insert_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
const int pagesize = inf_ttrace_page_dict.pagesize;
pid_t pid = ptid_get_pid (inferior_ptid);
@@ -337,7 +338,8 @@ inf_ttrace_insert_watchpoint (CORE_ADDR addr, int len, int type)
type TYPE. */
static int
-inf_ttrace_remove_watchpoint (CORE_ADDR addr, int len, int type)
+inf_ttrace_remove_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
const int pagesize = inf_ttrace_page_dict.pagesize;
pid_t pid = ptid_get_pid (inferior_ptid);
diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
index fe05192..e9e7c02 100644
--- a/gdb/mips-linux-nat.c
+++ b/gdb/mips-linux-nat.c
@@ -926,7 +926,8 @@ populate_regs_from_watches (struct pt_watch_regs *regs)
watch. Return zero on success. */
static int
-mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type)
+mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
struct pt_watch_regs regs;
struct mips_watchpoint *new_watch;
@@ -975,7 +976,8 @@ mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type)
Return zero on success. */
static int
-mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
+mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
int retval;
int deleted_one;
diff --git a/gdb/nto-procfs.c b/gdb/nto-procfs.c
index 2741ecf..a8cd1cd 100644
--- a/gdb/nto-procfs.c
+++ b/gdb/nto-procfs.c
@@ -1506,13 +1506,15 @@ procfs_can_use_hw_breakpoint (int type, int cnt, int othertype)
}
static int
-procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
return procfs_hw_watchpoint (addr, -1, type);
}
static int
-procfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
return procfs_hw_watchpoint (addr, len, type);
}
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index f61ac5d..e8d96f6 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1492,7 +1492,7 @@ ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
if (booke_debug_info.data_bp_alignment
&& (addr + len > (addr & ~(booke_debug_info.data_bp_alignment - 1))
+ booke_debug_info.data_bp_alignment))
- return 0;
+ return 0;
}
/* addr+len must fall in the 8 byte watchable region for DABR-based
processors (i.e., server processors). Without the new BookE ptrace
@@ -1685,8 +1685,202 @@ get_trigger_type (int rw)
return t;
}
+/* Check whether we have at least one free DVC register. */
+static int
+can_use_watchpoint_cond_accel (void)
+{
+ 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_booke_interface () || cnt == 0)
+ 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;
+ }
+
+ return 1;
+}
+
+/* Calculate the enable bits and the contents of the Data Value Compare
+ debug register present in BookE processors.
+
+ ADDR is the address to be watched, LEN is the length of watched data
+ and DATA_VALUE is the value which will trigger the watchpoint.
+ On exit, CONDITION_MODE will hold the enable bits for the DVC, and
+ CONDITION_VALUE will hold the value which should be put in the
+ DVC register. */
+static void
+calculate_dvc (CORE_ADDR addr, int len, CORE_ADDR data_value,
+ uint32_t *condition_mode, uint64_t *condition_value)
+{
+ int i, num_byte_enable, align_offset, num_bytes_off_dvc,
+ rightmost_enabled_byte;
+ CORE_ADDR addr_end_data, addr_end_dvc;
+
+ /* The DVC register compares bytes within fixed-length windows which
+ are word-aligned, with length equal to that of the DVC register.
+ We need to calculate where our watch region is relative to that
+ window and enable comparison of the bytes which fall within it. */
+
+ align_offset = addr % booke_debug_info.sizeof_condition;
+ addr_end_data = addr + len;
+ addr_end_dvc = (addr - align_offset
+ + booke_debug_info.sizeof_condition);
+ num_bytes_off_dvc = (addr_end_data > addr_end_dvc)?
+ addr_end_data - addr_end_dvc : 0;
+ num_byte_enable = len - num_bytes_off_dvc;
+ /* Here, bytes are numbered from right to left. */
+ rightmost_enabled_byte = (addr_end_data < addr_end_dvc)?
+ addr_end_dvc - addr_end_data : 0;
+
+ *condition_mode = PPC_BREAKPOINT_CONDITION_AND;
+ for (i = 0; i < num_byte_enable; i++)
+ *condition_mode |= PPC_BREAKPOINT_CONDITION_BE (i + rightmost_enabled_byte);
+
+ /* Now we need to match the position within the DVC of the comparison
+ value with where the watch region is relative to the window
+ (i.e., the ALIGN_OFFSET). */
+
+ *condition_value = ((uint64_t) data_value >> num_bytes_off_dvc * 8
+ << rightmost_enabled_byte * 8);
+}
+
+/* Return the number of memory locations that need to be accessed to
+ evaluate the expression which generated the given value chain.
+ Returns -1 if there's any register access involved, or if there are
+ other kinds of values which are not acceptable in a condition
+ expression (e.g., lval_computed or lval_internalvar). */
+static int
+num_memory_accesses (struct value *v)
+{
+ int found_memory_cnt = 0;
+ struct value *head = v;
+
+ /* The idea here is that evaluating an expression generates a series
+ of values, one holding the value of every subexpression. (The
+ expression a*b+c has five subexpressions: a, b, a*b, c, and
+ a*b+c.) GDB's values hold almost enough information to establish
+ the criteria given above --- they identify memory lvalues,
+ register lvalues, computed values, etcetera. So we can evaluate
+ the expression, and then scan the chain of values that leaves
+ behind to determine the memory locations involved in the evaluation
+ of an expression.
+
+ However, I don't think that the values returned by inferior
+ function calls are special in any way. So this function may not
+ notice that an expression contains an inferior function call.
+ FIXME. */
+
+ for (; v; v = value_next (v))
+ {
+ /* Constants and values from the history are fine. */
+ if (VALUE_LVAL (v) == not_lval || deprecated_value_modifiable (v) == 0)
+ continue;
+ else if (VALUE_LVAL (v) == lval_memory)
+ {
+ /* A lazy memory lvalue is one that GDB never needed to fetch;
+ we either just used its address (e.g., `a' in `a.b') or
+ we never needed it at all (e.g., `a' in `a,b'). */
+ if (!value_lazy (v))
+ found_memory_cnt++;
+ }
+ /* Other kinds of values are not fine. */
+ else
+ return -1;
+ }
+
+ return found_memory_cnt;
+}
+
+/* Verifies whether the expression COND can be implemented using the
+ DVC (Data Value Compare) register in BookE processors. The expression
+ must test the watch value for equality with a constant expression.
+ If the function returns 1, DATA_VALUE will contain the constant against
+ which the watch value should be compared. */
+static int
+check_condition (CORE_ADDR watch_addr, struct expression *cond,
+ CORE_ADDR *data_value)
+{
+ int pc = 1, num_accesses_left, num_accesses_right;
+ struct value *left_val, *right_val, *left_chain, *right_chain;
+
+ if (cond->elts[0].opcode != BINOP_EQUAL)
+ return 0;
+
+ fetch_subexp_value (cond, &pc, &left_val, NULL, &left_chain);
+ num_accesses_left = num_memory_accesses (left_chain);
+
+ if (left_val == NULL || num_accesses_left < 0)
+ {
+ free_value_chain (left_chain);
+
+ return 0;
+ }
+
+ fetch_subexp_value (cond, &pc, &right_val, NULL, &right_chain);
+ num_accesses_right = num_memory_accesses (right_chain);
+
+ if (right_val == NULL || num_accesses_right < 0)
+ {
+ free_value_chain (left_chain);
+ free_value_chain (right_chain);
+
+ return 0;
+ }
+
+ if (num_accesses_left == 1 && num_accesses_right == 0
+ && VALUE_LVAL (left_val) == lval_memory
+ && value_address (left_val) == watch_addr)
+ *data_value = value_as_long (right_val);
+ else if (num_accesses_left == 0 && num_accesses_right == 1
+ && VALUE_LVAL (right_val) == lval_memory
+ && value_address (right_val) == watch_addr)
+ *data_value = value_as_long (left_val);
+ else
+ {
+ free_value_chain (left_chain);
+ free_value_chain (right_chain);
+
+ return 0;
+ }
+
+ free_value_chain (left_chain);
+ free_value_chain (right_chain);
+
+ return 1;
+}
+
+/* Return non-zero if the target is capable of using hardware to evaluate
+ the condition expression, thus only triggering the watchpoint when it is
+ true. */
+static int
+ppc_linux_can_accel_watchpoint_condition (CORE_ADDR addr, int len, int rw,
+ struct expression *cond)
+{
+ CORE_ADDR data_value;
+
+ return (have_ptrace_booke_interface ()
+ && booke_debug_info.num_condition_regs > 0
+ && check_condition (addr, cond, &data_value));
+}
+
static int
-ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
+ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
+ struct expression *cond)
{
struct lwp_info *lp;
ptid_t ptid;
@@ -1695,14 +1889,23 @@ ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
if (have_ptrace_booke_interface ())
{
struct ppc_hw_breakpoint p;
+ CORE_ADDR data_value;
+
+ if (cond && can_use_watchpoint_cond_accel ()
+ && check_condition (addr, cond, &data_value))
+ calculate_dvc (addr, len, data_value, &p.condition_mode,
+ &p.condition_value);
+ else
+ {
+ p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+ p.condition_value = 0;
+ }
p.version = PPC_DEBUG_CURRENT_VERSION;
p.trigger_type = get_trigger_type (rw);
p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
- p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
p.addr = (uint64_t) addr;
p.addr2 = 0;
- p.condition_value = 0;
ALL_LWPS (lp, ptid)
booke_insert_point (&p, TIDGET (ptid));
@@ -1749,7 +1952,8 @@ ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
saved_dabr_value = dabr_value;
ALL_LWPS (lp, ptid)
- if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value) < 0)
+ if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0,
+ saved_dabr_value) < 0)
return -1;
ret = 0;
@@ -1759,7 +1963,8 @@ ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
}
static int
-ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw)
+ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw,
+ struct expression *cond)
{
struct lwp_info *lp;
ptid_t ptid;
@@ -1768,14 +1973,23 @@ ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw)
if (have_ptrace_booke_interface ())
{
struct ppc_hw_breakpoint p;
+ CORE_ADDR data_value;
+
+ if (cond && booke_debug_info.num_condition_regs > 0
+ && check_condition (addr, cond, &data_value))
+ calculate_dvc (addr, len, data_value, &p.condition_mode,
+ &p.condition_value);
+ else
+ {
+ p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+ p.condition_value = 0;
+ }
p.version = PPC_DEBUG_CURRENT_VERSION;
p.trigger_type = get_trigger_type (rw);
p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
- p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
p.addr = (uint64_t) addr;
p.addr2 = 0;
- p.condition_value = 0;
ALL_LWPS (lp, ptid)
booke_remove_point (&p, TIDGET (ptid));
@@ -1786,7 +2000,8 @@ ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw)
{
saved_dabr_value = 0;
ALL_LWPS (lp, ptid)
- if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value) < 0)
+ if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0,
+ saved_dabr_value) < 0)
return -1;
ret = 0;
@@ -2137,6 +2352,7 @@ _initialize_ppc_linux_nat (void)
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_read_description = ppc_linux_read_description;
t->to_auxv_parse = ppc_linux_auxv_parse;
diff --git a/gdb/procfs.c b/gdb/procfs.c
index 97a87e3..de8e26d 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -5161,7 +5161,8 @@ procfs_stopped_data_address (struct target_ops *targ, CORE_ADDR *addr)
}
static int
-procfs_insert_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_insert_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
if (!target_have_steppable_watchpoint
&& !gdbarch_have_nonsteppable_watchpoint (target_gdbarch))
@@ -5182,7 +5183,8 @@ procfs_insert_watchpoint (CORE_ADDR addr, int len, int type)
}
static int
-procfs_remove_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_remove_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
return procfs_set_watchpoint (inferior_ptid, addr, 0, 0, 0);
}
diff --git a/gdb/remote-m32r-sdi.c b/gdb/remote-m32r-sdi.c
index ad21774..ca450d5 100644
--- a/gdb/remote-m32r-sdi.c
+++ b/gdb/remote-m32r-sdi.c
@@ -1421,7 +1421,8 @@ m32r_can_use_hw_watchpoint (int type, int cnt, int othertype)
watchpoint. */
static int
-m32r_insert_watchpoint (CORE_ADDR addr, int len, int type)
+m32r_insert_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
int i;
@@ -1445,7 +1446,8 @@ m32r_insert_watchpoint (CORE_ADDR addr, int len, int type)
}
static int
-m32r_remove_watchpoint (CORE_ADDR addr, int len, int type)
+m32r_remove_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
int i;
diff --git a/gdb/remote-mips.c b/gdb/remote-mips.c
index 28d2ecb..ec2e5eb 100644
--- a/gdb/remote-mips.c
+++ b/gdb/remote-mips.c
@@ -2401,7 +2401,8 @@ calculate_mask (CORE_ADDR addr, int len)
watchpoint. */
int
-mips_insert_watchpoint (CORE_ADDR addr, int len, int type)
+mips_insert_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
if (mips_set_breakpoint (addr, len, type))
return -1;
@@ -2412,7 +2413,8 @@ mips_insert_watchpoint (CORE_ADDR addr, int len, int type)
/* Remove a watchpoint. */
int
-mips_remove_watchpoint (CORE_ADDR addr, int len, int type)
+mips_remove_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
if (mips_clear_breakpoint (addr, len, type))
return -1;
diff --git a/gdb/remote.c b/gdb/remote.c
index 385d62a..71eee5d 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -7646,7 +7646,8 @@ watchpoint_to_Z_packet (int type)
}
static int
-remote_insert_watchpoint (CORE_ADDR addr, int len, int type)
+remote_insert_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
struct remote_state *rs = get_remote_state ();
char *p;
@@ -7679,7 +7680,8 @@ remote_insert_watchpoint (CORE_ADDR addr, int len, int type)
static int
-remote_remove_watchpoint (CORE_ADDR addr, int len, int type)
+remote_remove_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
struct remote_state *rs = get_remote_state ();
char *p;
diff --git a/gdb/s390-nat.c b/gdb/s390-nat.c
index 3af42ff..b412fda 100644
--- a/gdb/s390-nat.c
+++ b/gdb/s390-nat.c
@@ -335,7 +335,8 @@ s390_fix_watch_points (ptid_t ptid)
}
static int
-s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
+s390_insert_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
struct lwp_info *lp;
ptid_t ptid;
@@ -356,7 +357,8 @@ s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
}
static int
-s390_remove_watchpoint (CORE_ADDR addr, int len, int type)
+s390_remove_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
struct lwp_info *lp;
ptid_t ptid;
diff --git a/gdb/target.c b/gdb/target.c
index 7c9793d..862df4e 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -117,9 +117,11 @@ static int debug_to_insert_hw_breakpoint (struct gdbarch *,
static int debug_to_remove_hw_breakpoint (struct gdbarch *,
struct bp_target_info *);
-static int debug_to_insert_watchpoint (CORE_ADDR, int, int);
+static int debug_to_insert_watchpoint (CORE_ADDR, int, int,
+ struct expression *);
-static int debug_to_remove_watchpoint (CORE_ADDR, int, int);
+static int debug_to_remove_watchpoint (CORE_ADDR, int, int,
+ struct expression *);
static int debug_to_stopped_by_watchpoint (void);
@@ -130,6 +132,9 @@ static int debug_to_watchpoint_addr_within_range (struct target_ops *,
static int debug_to_region_ok_for_hw_watchpoint (CORE_ADDR, int);
+static int debug_to_can_accel_watchpoint_condition (CORE_ADDR, int, int,
+ struct expression *);
+
static void debug_to_terminal_init (void);
static void debug_to_terminal_inferior (void);
@@ -607,6 +612,7 @@ update_current_target (void)
INHERIT (to_stopped_by_watchpoint, t);
INHERIT (to_watchpoint_addr_within_range, t);
INHERIT (to_region_ok_for_hw_watchpoint, t);
+ INHERIT (to_can_accel_watchpoint_condition, t);
INHERIT (to_terminal_init, t);
INHERIT (to_terminal_inferior, t);
INHERIT (to_terminal_ours_for_output, t);
@@ -728,10 +734,10 @@ update_current_target (void)
(int (*) (struct gdbarch *, struct bp_target_info *))
return_minus_one);
de_fault (to_insert_watchpoint,
- (int (*) (CORE_ADDR, int, int))
+ (int (*) (CORE_ADDR, int, int, struct expression *))
return_minus_one);
de_fault (to_remove_watchpoint,
- (int (*) (CORE_ADDR, int, int))
+ (int (*) (CORE_ADDR, int, int, struct expression *))
return_minus_one);
de_fault (to_stopped_by_watchpoint,
(int (*) (void))
@@ -743,6 +749,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_can_accel_watchpoint_condition,
+ (int (*) (CORE_ADDR, int, int, struct expression *))
+ return_zero);
de_fault (to_terminal_init,
(void (*) (void))
target_ignore);
@@ -3314,6 +3323,21 @@ debug_to_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
}
static int
+debug_to_can_accel_watchpoint_condition (CORE_ADDR addr, int len, int rw,
+ struct expression *cond)
+{
+ int retval;
+
+ retval = debug_target.to_can_accel_watchpoint_condition (addr, len, rw, cond);
+
+ fprintf_unfiltered (gdb_stdlog,
+ "target_can_accel_watchpoint_condition (0x%lx, %d, %d, 0x%lx) = %ld\n",
+ (unsigned long) addr, len, rw, (unsigned long) cond,
+ (unsigned long) retval);
+ return retval;
+}
+
+static int
debug_to_stopped_by_watchpoint (void)
{
int retval;
@@ -3388,28 +3412,32 @@ debug_to_remove_hw_breakpoint (struct gdbarch *gdbarch,
}
static int
-debug_to_insert_watchpoint (CORE_ADDR addr, int len, int type)
+debug_to_insert_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
int retval;
- retval = debug_target.to_insert_watchpoint (addr, len, type);
+ retval = debug_target.to_insert_watchpoint (addr, len, type, cond);
fprintf_unfiltered (gdb_stdlog,
- "target_insert_watchpoint (0x%lx, %d, %d) = %ld\n",
- (unsigned long) addr, len, type, (unsigned long) retval);
+ "target_insert_watchpoint (0x%lx, %d, %d, 0x%ld) = %ld\n",
+ (unsigned long) addr, len, type, (unsigned long) cond,
+ (unsigned long) retval);
return retval;
}
static int
-debug_to_remove_watchpoint (CORE_ADDR addr, int len, int type)
+debug_to_remove_watchpoint (CORE_ADDR addr, int len, int type,
+ struct expression *cond)
{
int retval;
- retval = debug_target.to_remove_watchpoint (addr, len, type);
+ retval = debug_target.to_remove_watchpoint (addr, len, type, cond);
fprintf_unfiltered (gdb_stdlog,
- "target_remove_watchpoint (0x%lx, %d, %d) = %ld\n",
- (unsigned long) addr, len, type, (unsigned long) retval);
+ "target_remove_watchpoint (0x%lx, %d, %d, 0x%ld) = %ld\n",
+ (unsigned long) addr, len, type, (unsigned long) cond,
+ (unsigned long) retval);
return retval;
}
@@ -3664,6 +3692,7 @@ setup_target_debug (void)
current_target.to_stopped_data_address = debug_to_stopped_data_address;
current_target.to_watchpoint_addr_within_range = debug_to_watchpoint_addr_within_range;
current_target.to_region_ok_for_hw_watchpoint = debug_to_region_ok_for_hw_watchpoint;
+ current_target.to_can_accel_watchpoint_condition = debug_to_can_accel_watchpoint_condition;
current_target.to_terminal_init = debug_to_terminal_init;
current_target.to_terminal_inferior = debug_to_terminal_inferior;
current_target.to_terminal_ours_for_output = debug_to_terminal_ours_for_output;
diff --git a/gdb/target.h b/gdb/target.h
index 3c8a616..3c8c017 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -37,6 +37,8 @@ struct uploaded_tsv;
struct uploaded_tp;
struct static_tracepoint_marker;
+struct expression;
+
/* 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
@@ -426,8 +428,12 @@ struct target_ops
int (*to_can_use_hw_breakpoint) (int, int, int);
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);
+
+ /* Documentation of what the two routines below are expected to do is
+ provided with the corresponding target_* macros. */
+ int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *);
+ int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *);
+
int (*to_stopped_by_watchpoint) (void);
int to_have_steppable_watchpoint;
int to_have_continuable_watchpoint;
@@ -435,6 +441,8 @@ struct target_ops
int (*to_watchpoint_addr_within_range) (struct target_ops *,
CORE_ADDR, CORE_ADDR, int);
int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int);
+ int (*to_can_accel_watchpoint_condition) (CORE_ADDR, int, int,
+ struct expression *);
void (*to_terminal_init) (void);
void (*to_terminal_inferior) (void);
void (*to_terminal_ours_for_output) (void);
@@ -1298,14 +1306,15 @@ extern char *normal_pid_to_str (ptid_t ptid);
/* 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.
+ COND is the expression for its condition, or NULL if there's none.
Returns 0 for success, 1 if the watchpoint type is not supported,
-1 for failure. */
-#define target_insert_watchpoint(addr, len, type) \
- (*current_target.to_insert_watchpoint) (addr, len, type)
+#define target_insert_watchpoint(addr, len, type, cond) \
+ (*current_target.to_insert_watchpoint) (addr, len, type, cond)
-#define target_remove_watchpoint(addr, len, type) \
- (*current_target.to_remove_watchpoint) (addr, len, type)
+#define target_remove_watchpoint(addr, len, type, cond) \
+ (*current_target.to_remove_watchpoint) (addr, len, type, cond)
#define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
(*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)
@@ -1322,6 +1331,19 @@ extern char *normal_pid_to_str (ptid_t ptid);
#define target_watchpoint_addr_within_range(target, addr, start, length) \
(*target.to_watchpoint_addr_within_range) (target, addr, start, length)
+/* Return non-zero if the target is capable of using hardware to evaluate
+ the condition expression. In this case, if the condition is false when
+ the watched memory location changes, execution may continue without the
+ debugger being notified.
+
+ Due to limitations in the hardware implementation, it may be capable of
+ avoiding triggering the watchpoint in some cases where the condition
+ expression is false, but may report some false positives as well.
+ For this reason, GDB will still evaluate the condition expression when
+ the watchpoint triggers. */
+#define target_can_accel_watchpoint_condition(addr, len, type, cond) \
+ (*current_target.to_can_accel_watchpoint_condition) (addr, len, type, cond)
+
/* Target can execute in reverse? */
#define target_can_execute_reverse \
(current_target.to_can_execute_reverse ? \
diff --git a/gdb/value.c b/gdb/value.c
index edcd4d0..d552402 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -722,6 +722,20 @@ free_all_values (void)
all_values = 0;
}
+/* Frees all the elements in a chain of values. */
+
+void
+free_value_chain (struct value *v)
+{
+ struct value *next;
+
+ for (; v; v = next)
+ {
+ next = value_next (v);
+ value_free (v);
+ }
+}
+
/* Remove VAL from the chain all_values
so it will not be freed automatically. */
diff --git a/gdb/value.h b/gdb/value.h
index 0634bb9..12cbc0a 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -538,6 +538,10 @@ extern struct value *evaluate_subexp (struct type *expect_type,
extern struct value *evaluate_subexpression_type (struct expression *exp,
int subexp);
+extern void fetch_subexp_value (struct expression *exp, int *pc,
+ struct value **valp, struct value **resultp,
+ struct value **val_chain);
+
extern char *extract_field_op (struct expression *exp, int *subexp);
extern struct value *evaluate_subexp_with_coercion (struct expression *,
@@ -635,6 +639,8 @@ extern void value_free (struct value *val);
extern void free_all_values (void);
+extern void free_value_chain (struct value *v);
+
extern void release_value (struct value *val);
extern int record_latest_value (struct value *val);