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.
This commit is contained in:
Thiago Jung Bauermann 2010-07-07 16:15:18 +00:00
parent 6bd3187468
commit 0cf6dd1543
18 changed files with 503 additions and 132 deletions

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);
}

View File

@ -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
ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
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,
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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);
@ -3313,6 +3322,21 @@ debug_to_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
return retval;
}
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)
{
@ -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;

View File

@ -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 ? \

View File

@ -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. */

View File

@ -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);