* breakpoint.h (enum bptype): Add bp_hardware_watchpoint and

bp_watchpoint_scope breakpoints.
	(struct breakpoint): Add val_chain and related_breakpoint fields
	for use by watchpoints.

	* breakpoint.c (within_scope): Delete.  No longer used.
	(TARGET_CAN_USE_HARDWARE_WATCHPOINT): Provide default definition.
	(target_{remove,insert}_watchpoint): Likewise.
	(can_use_hardware_watchpoint): New function.
	(remove_breakpoint): New function to remove a single breakpoint
	or hardware watchpoint.
	(insert_breakpoints): Handle insertion of hardware watchpoints.
	Store a copy of the value chain derived from the watchpoint
	expression.
	(remove_breakpoints): Simplify by using remove_breakpoint.
	(delete_breakpoint): Likewise.
	(watchpoint_check): Delete the watchpoint and watchpoint scope
	breakpoints when the watchpoint goes out of scope.  Save & restore
	the current frame after checking watchpoints.
	(breakpoint_init_inferior): Likewise (restarting the program
	makes all local watchpoints go out of scope).
	(bpstat_stop_status): Handle hardware watchpoints much like normal
	watchpoints. Delete the watchpoint and watchpoint scope breakpoint
	when the watchpoint goes out of scope.  Remove and reinsert all
	breakpoints before returning if we stopped when a hardware watchpoint
	fired.
	(watch_command): Use a hardware watchpoint when possible.  If
	watching a local expression, build a scope breakpoint too.
	(map_breakpoint_numbers): Also call given function for any
	related breakpoints.
	(disable_breakpoint): Never disable a scope breakpoint.
	(enable_breakpoint): Handle hardware breakpoints much like normal
	breakpoints, but recompute the watchpoint_scope breakpoint's
	frame and address  (if we have an associated scope breakpoint).
	(read_memory_nobpt): Handle hardware watchpoints like normal
	watchpoints.  When necessary handle watchpoint_scope breakpoints.
	(print_it_normal, bpstat_what, breakpoint_1, mention): Likewise.
	(clear_command, breakpoint_re_set_one, enable_command): Likewise.
	(disable_command): Likewise.

	* blockframe.c (find_frame_addr_in_frame_chain): New function.
	Extern prototype added to frame.h

	* infrun.c (wait_for_inferior): Set current_frame and select
	a frame before checking if we stopped due to a hardare watchpoint
	firing.  Handle stepping over hardware watchpoints.
	(normal_stop): Remove unnecessary call to select_frame.

	* value.h (value_release_to_mark): Declare.
	* values.c (value_release_to_mark): New function.

	* procfs.c (procfs_wait): Add cases for hardware watchpoints.
	(procfs_set_watchpoint, procfs_stopped_by_watchpoint): New functions.

	* hppab-nat.c (hppa_set_watchpoint): New function.

	* config/pa/nm-hppab.h (STOPPED_BY_WATCHPOINT): Define.
	(HAVE_STEPPABLE_WATCHPOINT): Define.
	(TARGET_CAN_USE_HARDWARE_WATCHPOINT): Define.
	(target_{insert,delete}_watchpoint): Define.
This commit is contained in:
Jeff Law 1994-04-13 21:57:00 +00:00
parent ebc9eebab0
commit 999dd04b89
8 changed files with 583 additions and 152 deletions

View file

@ -1,3 +1,66 @@
Wed Apr 13 14:52:46 1994 Jeffrey A. Law (law@snake.cs.utah.edu)
* breakpoint.h (enum bptype): Add bp_hardware_watchpoint and
bp_watchpoint_scope breakpoints.
(struct breakpoint): Add val_chain and related_breakpoint fields
for use by watchpoints.
* breakpoint.c (within_scope): Delete. No longer used.
(TARGET_CAN_USE_HARDWARE_WATCHPOINT): Provide default definition.
(target_{remove,insert}_watchpoint): Likewise.
(can_use_hardware_watchpoint): New function.
(remove_breakpoint): New function to remove a single breakpoint
or hardware watchpoint.
(insert_breakpoints): Handle insertion of hardware watchpoints.
Store a copy of the value chain derived from the watchpoint
expression.
(remove_breakpoints): Simplify by using remove_breakpoint.
(delete_breakpoint): Likewise.
(watchpoint_check): Delete the watchpoint and watchpoint scope
breakpoints when the watchpoint goes out of scope. Save & restore
the current frame after checking watchpoints.
(breakpoint_init_inferior): Likewise (restarting the program
makes all local watchpoints go out of scope).
(bpstat_stop_status): Handle hardware watchpoints much like normal
watchpoints. Delete the watchpoint and watchpoint scope breakpoint
when the watchpoint goes out of scope. Remove and reinsert all
breakpoints before returning if we stopped when a hardware watchpoint
fired.
(watch_command): Use a hardware watchpoint when possible. If
watching a local expression, build a scope breakpoint too.
(map_breakpoint_numbers): Also call given function for any
related breakpoints.
(disable_breakpoint): Never disable a scope breakpoint.
(enable_breakpoint): Handle hardware breakpoints much like normal
breakpoints, but recompute the watchpoint_scope breakpoint's
frame and address (if we have an associated scope breakpoint).
(read_memory_nobpt): Handle hardware watchpoints like normal
watchpoints. When necessary handle watchpoint_scope breakpoints.
(print_it_normal, bpstat_what, breakpoint_1, mention): Likewise.
(clear_command, breakpoint_re_set_one, enable_command): Likewise.
(disable_command): Likewise.
* blockframe.c (find_frame_addr_in_frame_chain): New function.
Extern prototype added to frame.h
* infrun.c (wait_for_inferior): Set current_frame and select
a frame before checking if we stopped due to a hardare watchpoint
firing. Handle stepping over hardware watchpoints.
(normal_stop): Remove unnecessary call to select_frame.
* value.h (value_release_to_mark): Declare.
* values.c (value_release_to_mark): New function.
* procfs.c (procfs_wait): Add cases for hardware watchpoints.
(procfs_set_watchpoint, procfs_stopped_by_watchpoint): New functions.
* hppab-nat.c (hppa_set_watchpoint): New function.
* config/pa/nm-hppab.h (STOPPED_BY_WATCHPOINT): Define.
(HAVE_STEPPABLE_WATCHPOINT): Define.
(TARGET_CAN_USE_HARDWARE_WATCHPOINT): Define.
(target_{insert,delete}_watchpoint): Define.
Mon Apr 11 19:21:27 1994 Stu Grossman (grossman at cygnus.com)
* xcoffread.c (read_xcoff_symtab): Ignore symbols of class C_EXT,

View file

@ -805,6 +805,29 @@ block_innermost_frame (block)
}
}
/* Return the full FRAME which corresponds to the given FRAME_ADDR
or NULL if no FRAME on the chain corresponds to FRAME_ADDR. */
FRAME
find_frame_addr_in_frame_chain (frame_addr)
FRAME_ADDR frame_addr;
{
FRAME frame = NULL;
if (frame_addr == NULL)
return NULL;
while (1)
{
frame = get_prev_frame (frame);
if (frame == NULL)
return NULL;
if (FRAME_FP (frame) == frame_addr)
return frame;
}
}
#ifdef SIGCONTEXT_PC_OFFSET
/* Get saved user PC for sigtramp from sigcontext for BSD style sigtramp. */

View file

@ -89,6 +89,9 @@ get_catch_sals PARAMS ((int));
static void
watch_command PARAMS ((char *, int));
static int
can_use_hardware_watchpoint PARAMS ((struct breakpoint *));
static void
tbreak_command PARAMS ((char *, int));
@ -134,6 +137,8 @@ get_number PARAMS ((char **));
static void
set_breakpoint_count PARAMS ((int));
static int
remove_breakpoint PARAMS ((struct breakpoint *));
extern int addressprint; /* Print machine addresses? */
extern int demangle; /* Print de-mangled symbol names? */
@ -152,6 +157,13 @@ static int executing_breakpoint_commands;
b? (tmp=b->next, 1): 0; \
b = tmp)
/* By default no support for hardware watchpoints is assumed. */
#ifndef TARGET_CAN_USE_HARDWARE_WATCHPOINT
#define TARGET_CAN_USE_HARDWARE_WATCHPOINT(B) 0
#define target_remove_watchpoint(ADDR,LEN) -1
#define target_insert_watchpoint(ADDR,LEN) -1
#endif
/* Chain of all breakpoints defined. */
static struct breakpoint *breakpoint_chain;
@ -357,7 +369,9 @@ read_memory_nobpt (memaddr, myaddr, len)
ALL_BREAKPOINTS (b)
{
if (b->type == bp_watchpoint || !b->inserted)
if (b->type == bp_watchpoint
|| b->type == bp_hardware_watchpoint
|| !b->inserted)
continue;
else if (b->address + memory_breakpoint_size <= memaddr)
/* The breakpoint is entirely before the chunk of memory
@ -435,6 +449,7 @@ insert_breakpoints ()
ALL_BREAKPOINTS (b)
if (b->type != bp_watchpoint
&& b->type != bp_hardware_watchpoint
&& b->enable != disabled
&& ! b->inserted
&& ! b->duplicate)
@ -473,11 +488,86 @@ insert_breakpoints ()
else
b->inserted = 1;
}
else if (b->type == bp_hardware_watchpoint
&& b->enable == enabled
&& ! b->inserted
&& ! b->duplicate)
{
FRAME saved_frame;
int saved_level, within_current_scope;
value_ptr mark = value_mark ();
value_ptr v;
/* Save the current frame and level so we can restore it after
evaluating the watchpoint expression on its own frame. */
saved_frame = selected_frame;
saved_level = selected_frame_level;
/* Determine if the watchpoint is within scope. */
if (b->exp_valid_block == NULL)
within_current_scope = 1;
else
{
FRAME fr = find_frame_addr_in_frame_chain (b->watchpoint_frame);
within_current_scope = (fr != NULL);
if (within_current_scope)
select_frame (fr, -1);
}
if (within_current_scope)
{
/* Evaluate the expression and cut the chain of values
produced off from the value chain. */
v = evaluate_expression (b->exp);
value_release_to_mark (mark);
b->val_chain = v;
b->inserted = 1;
/* Look at each value on the value chain. */
for ( ; v; v=v->next)
{
/* If it's a memory location, then we must watch it. */
if (v->lval == lval_memory)
{
int addr, len;
addr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
len = TYPE_LENGTH (VALUE_TYPE (v));
val = target_insert_watchpoint (addr, len);
if (val == -1)
{
b->inserted = 0;
break;
}
val = 0;
}
}
/* Failure to insert a watchpoint on any memory value in the
value chain brings us here. */
if (!b->inserted)
warning ("Hardware watchpoint %d: Could not insert watchpoint\n",
b->number);
}
else
{
printf_filtered ("\
Hardware watchpoint %d deleted because the program has left the block in\n\
which its expression is valid.\n", b->number);
if (b->related_breakpoint)
delete_breakpoint (b->related_breakpoint);
delete_breakpoint (b);
}
/* Restore the frame and level. */
select_frame (saved_frame, saved_level);
}
if (disabled_breaks)
printf_filtered ("\n");
return val;
}
int
remove_breakpoints ()
{
@ -485,14 +575,70 @@ remove_breakpoints ()
int val;
ALL_BREAKPOINTS (b)
if (b->type != bp_watchpoint && b->inserted)
{
val = target_remove_breakpoint(b->address, b->shadow_contents);
if (val)
return val;
b->inserted = 0;
}
{
if (b->inserted)
{
val = remove_breakpoint (b);
if (val != 0)
return val;
}
}
return 0;
}
static int
remove_breakpoint (b)
struct breakpoint *b;
{
int val;
if (b->type != bp_watchpoint
&& b->type != bp_hardware_watchpoint)
{
val = target_remove_breakpoint(b->address, b->shadow_contents);
if (val)
return val;
b->inserted = 0;
}
else if (b->type == bp_hardware_watchpoint
&& b->enable == enabled
&& ! b->duplicate)
{
value_ptr v, n;
b->inserted = 0;
/* Walk down the saved value chain. */
for (v = b->val_chain; v; v = v->next)
{
/* For each memory reference remove the watchpoint
at that address. */
if (v->lval == lval_memory)
{
int addr, len;
addr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
len = TYPE_LENGTH (VALUE_TYPE (v));
val = target_remove_watchpoint (addr, len);
if (val == -1)
b->inserted = 1;
val = 0;
}
}
/* Failure to remove any of the hardware watchpoints comes here. */
if (b->inserted)
error ("Hardware watchpoint %d: Could not remove watchpoint\n",
b->number);
/* Free the saved value chain. We will construct a new one
the next time the watchpoint is inserted. */
for (v = b->val_chain; v; v = n)
{
n = v->next;
value_free (v);
}
b->val_chain = NULL;
}
return 0;
}
@ -524,6 +670,15 @@ breakpoint_init_inferior ()
get rid of it. */
if (b->type == bp_call_dummy)
delete_breakpoint (b);
/* Likewise for scope breakpoints. */
if (b->type == bp_watchpoint_scope)
delete_breakpoint (b);
/* Likewise for watchpoints on local expressions. */
if ((b->type == bp_watchpoint || b->type == bp_hardware_watchpoint)
&& b->exp_valid_block != NULL)
delete_breakpoint (b);
}
}
@ -771,7 +926,8 @@ print_it_normal (bs)
which has since been deleted. */
if (bs->breakpoint_at == NULL
|| (bs->breakpoint_at->type != bp_breakpoint
&& bs->breakpoint_at->type != bp_watchpoint))
&& bs->breakpoint_at->type != bp_watchpoint
&& bs->breakpoint_at->type != bp_hardware_watchpoint))
return 0;
if (bs->breakpoint_at->type == bp_breakpoint)
@ -860,125 +1016,12 @@ bpstat_alloc (b, cbs)
return bs;
}
/* Return the frame which we can use to evaluate the expression
whose valid block is valid_block, or NULL if not in scope.
This whole concept is probably not the way to do things (it is incredibly
slow being the main reason, not to mention fragile (e.g. the sparc
frame pointer being fetched as 0 bug causes it to stop)). Instead,
introduce a version of "struct frame" which survives over calls to the
inferior, but which is better than FRAME_ADDR in the sense that it lets
us evaluate expressions relative to that frame (on some machines, it
can just be a FRAME_ADDR). Save one of those instead of (or in addition
to) the exp_valid_block, and then use it to evaluate the watchpoint
expression, with no need to do all this backtracing every time.
Or better yet, what if it just copied the struct frame and its next
frame? Off the top of my head, I would think that would work
because things like (a29k) rsize and msize, or (sparc) bottom just
depend on the frame, and aren't going to be different just because
the inferior has done something. Trying to recalculate them
strikes me as a lot of work, possibly even impossible. Saving the
next frame is needed at least on a29k, where get_saved_register
uses fi->next->saved_msp. For figuring out whether that frame is
still on the stack, I guess this needs to be machine-specific (e.g.
a29k) but I think
read_fp () INNER_THAN watchpoint_frame->frame
would generally work.
Of course the scope of the expression could be less than a whole
function; perhaps if the innermost frame is the one which the
watchpoint is relative to (another machine-specific thing, usually
FRAMELESS_FUNCTION_INVOCATION (get_current_frame(), fromleaf)
read_fp () == wp_frame->frame
&& !fromleaf
), *then* it could do a
contained_in (get_current_block (), wp->exp_valid_block).
*/
FRAME
within_scope (valid_block)
struct block *valid_block;
{
FRAME fr = get_current_frame ();
struct frame_info *fi = get_frame_info (fr);
CORE_ADDR func_start;
/* If caller_pc_valid is true, we are stepping through
a function prologue, which is bounded by callee_func_start
(inclusive) and callee_prologue_end (exclusive).
caller_pc is the pc of the caller.
Yes, this is hairy. */
static int caller_pc_valid = 0;
static CORE_ADDR caller_pc;
static CORE_ADDR callee_func_start;
static CORE_ADDR callee_prologue_end;
find_pc_partial_function (fi->pc, (PTR)NULL, &func_start, (CORE_ADDR *)NULL);
func_start += FUNCTION_START_OFFSET;
if (fi->pc == func_start)
{
/* We just called a function. The only other case I
can think of where the pc would equal the pc of the
start of a function is a frameless function (i.e.
no prologue) where we branch back to the start
of the function. In that case, SKIP_PROLOGUE won't
find one, and we'll clear caller_pc_valid a few lines
down. */
caller_pc_valid = 1;
caller_pc = SAVED_PC_AFTER_CALL (fr);
callee_func_start = func_start;
SKIP_PROLOGUE (func_start);
callee_prologue_end = func_start;
}
if (caller_pc_valid)
{
if (fi->pc < callee_func_start
|| fi->pc >= callee_prologue_end)
caller_pc_valid = 0;
}
if (contained_in (block_for_pc (caller_pc_valid
? caller_pc
: fi->pc),
valid_block))
{
return fr;
}
fr = get_prev_frame (fr);
/* If any active frame is in the exp_valid_block, then it's
OK. Note that this might not be the same invocation of
the exp_valid_block that we were watching a little while
ago, or the same one as when the watchpoint was set (e.g.
we are watching a local variable in a recursive function.
When we return from a recursive invocation, then we are
suddenly watching a different instance of the variable).
At least for now I am going to consider this a feature. */
for (; fr != NULL; fr = get_prev_frame (fr))
{
fi = get_frame_info (fr);
if (contained_in (block_for_pc (fi->pc),
valid_block))
{
return fr;
}
}
return NULL;
}
/* Possible return values for watchpoint_check (this can't be an enum
because of check_errors). */
/* The watchpoint has been disabled. */
#define WP_DISABLED 1
/* The watchpoint has been deleted. */
#define WP_DELETED 1
/* The value has changed. */
#define WP_VALUE_CHANGED 2
/* The value has not changed. */
@ -990,15 +1033,21 @@ watchpoint_check (p)
char *p;
{
bpstat bs = (bpstat) p;
FRAME fr;
struct breakpoint *b;
FRAME saved_frame, fr;
int within_current_scope, saved_level;
/* Save the current frame and level so we can restore it after
evaluating the watchpoint expression on its own frame. */
saved_frame = selected_frame;
saved_level = selected_frame_level;
int within_current_scope;
if (bs->breakpoint_at->exp_valid_block == NULL)
within_current_scope = 1;
else
{
fr = within_scope (bs->breakpoint_at->exp_valid_block);
within_current_scope = fr != NULL;
fr = find_frame_addr_in_frame_chain (bs->breakpoint_at->watchpoint_frame);
within_current_scope = (fr != NULL);
if (within_current_scope)
/* If we end up stopping, the current frame will get selected
in normal_stop. So this call to select_frame won't affect
@ -1022,6 +1071,7 @@ watchpoint_check (p)
bs->old_val = bs->breakpoint_at->val;
bs->breakpoint_at->val = new_val;
/* We will stop here */
select_frame (saved_frame, saved_level);
return WP_VALUE_CHANGED;
}
else
@ -1029,6 +1079,7 @@ watchpoint_check (p)
/* Nothing changed, don't do anything. */
value_free_to_mark (mark);
/* We won't stop here */
select_frame (saved_frame, saved_level);
return WP_VALUE_NOT_CHANGED;
}
}
@ -1042,11 +1093,15 @@ watchpoint_check (p)
So we can't even detect the first assignment to it and
watch after that (since the garbage may or may not equal
the first value assigned). */
bs->breakpoint_at->enable = disabled;
printf_filtered ("\
Watchpoint %d disabled because the program has left the block in\n\
Watchpoint %d deleted because the program has left the block in\n\
which its expression is valid.\n", bs->breakpoint_at->number);
return WP_DISABLED;
if (bs->breakpoint_at->related_breakpoint)
delete_breakpoint (bs->breakpoint_at->related_breakpoint);
delete_breakpoint (bs->breakpoint_at);
select_frame (saved_frame, saved_level);
return WP_DELETED;
}
}
@ -1115,10 +1170,14 @@ bpstat_stop_status (pc, frame_address, not_a_breakpoint)
if (b->enable == disabled)
continue;
if (b->type != bp_watchpoint && b->address != bp_addr)
if (b->type != bp_watchpoint
&& b->type != bp_hardware_watchpoint
&& b->address != bp_addr)
continue;
if (b->type != bp_watchpoint && not_a_breakpoint)
if (b->type != bp_watchpoint
&& b->type != bp_hardware_watchpoint
&& not_a_breakpoint)
continue;
/* Come here if it's a watchpoint, or if the break address matches */
@ -1128,7 +1187,7 @@ bpstat_stop_status (pc, frame_address, not_a_breakpoint)
bs->stop = 1;
bs->print = 1;
if (b->type == bp_watchpoint)
if (b->type == bp_watchpoint || b->type == bp_hardware_watchpoint)
{
static char message1[] =
"Error evaluating expression for watchpoint %d\n";
@ -1137,7 +1196,7 @@ bpstat_stop_status (pc, frame_address, not_a_breakpoint)
switch (catch_errors (watchpoint_check, (char *) bs, message,
RETURN_MASK_ALL))
{
case WP_DISABLED:
case WP_DELETED:
/* We've already printed what needs to be printed. */
bs->print_it = print_it_done;
/* Stop. */
@ -1155,10 +1214,13 @@ bpstat_stop_status (pc, frame_address, not_a_breakpoint)
/* FALLTHROUGH */
case 0:
/* Error from catch_errors. */
b->enable = disabled;
printf_filtered ("Watchpoint %d disabled.\n", b->number);
printf_filtered ("Watchpoint %d deleted.\n", b->number);
if (b->related_breakpoint)
delete_breakpoint (b->related_breakpoint);
delete_breakpoint (b);
/* We've already printed what needs to be printed. */
bs->print_it = print_it_done;
/* Stop. */
break;
}
@ -1231,6 +1293,15 @@ bpstat_stop_status (pc, frame_address, not_a_breakpoint)
}
}
#endif /* DECR_PC_AFTER_BREAK != 0. */
/* The value of a hardware watchpoint hasn't changed, but the
intermediate memory locations we are watching may have. */
if (bs && ! bs->stop
&& bs->breakpoint_at->type == bp_hardware_watchpoint)
{
remove_breakpoints ();
insert_breakpoints ();
}
return bs;
}
@ -1361,6 +1432,7 @@ bpstat_what (bs)
bs_class = bp_nostop;
break;
case bp_watchpoint:
case bp_hardware_watchpoint:
if (bs->stop)
{
if (bs->print)
@ -1391,6 +1463,10 @@ bpstat_what (bs)
case bp_through_sigtramp:
bs_class = through_sig;
break;
case bp_watchpoint_scope:
bs_class = bp_nostop;
break;
case bp_call_dummy:
/* Make sure the action is stop (silent or noisy), so infrun.c
pops the dummy frame. */
@ -1433,8 +1509,9 @@ breakpoint_1 (bnum, allflag)
CORE_ADDR last_addr = (CORE_ADDR)-1;
int found_a_breakpoint = 0;
static char *bptypes[] = {"breakpoint", "until", "finish", "watchpoint",
"longjmp", "longjmp resume", "step resume",
"call dummy" };
"hardware watchpoint", "longjmp",
"longjmp resume", "step resume",
"watchpoint scope", "call dummy" };
static char *bpdisps[] = {"del", "dis", "keep"};
static char bpenables[] = "ny";
char wrap_indent[80];
@ -1446,7 +1523,8 @@ breakpoint_1 (bnum, allflag)
/* We only print out user settable breakpoints unless the allflag is set. */
if (!allflag
&& b->type != bp_breakpoint
&& b->type != bp_watchpoint)
&& b->type != bp_watchpoint
&& b->type != bp_hardware_watchpoint)
continue;
if (!found_a_breakpoint++)
@ -1464,6 +1542,7 @@ breakpoint_1 (bnum, allflag)
switch (b->type)
{
case bp_watchpoint:
case bp_hardware_watchpoint:
print_expression (b->exp, gdb_stdout);
break;
@ -1474,6 +1553,7 @@ breakpoint_1 (bnum, allflag)
case bp_longjmp_resume:
case bp_step_resume:
case bp_through_sigtramp:
case bp_watchpoint_scope:
case bp_call_dummy:
if (addressprint)
printf_filtered ("%s ", local_hex_string_custom ((unsigned long) b->address, "08l"));
@ -1829,6 +1909,10 @@ mention (b)
printf_filtered ("Watchpoint %d: ", b->number);
print_expression (b->exp, gdb_stdout);
break;
case bp_hardware_watchpoint:
printf_filtered ("Hardware watchpoint %d: ", b->number);
print_expression (b->exp, gdb_stdout);
break;
case bp_breakpoint:
printf_filtered ("Breakpoint %d at ", b->number);
print_address_numeric (b->address, gdb_stdout);
@ -1843,6 +1927,7 @@ mention (b)
case bp_step_resume:
case bp_through_sigtramp:
case bp_call_dummy:
case bp_watchpoint_scope:
break;
}
printf_filtered ("\n");
@ -2107,6 +2192,7 @@ watch_command (arg, from_tty)
struct expression *exp;
struct block *exp_valid_block;
struct value *val;
FRAME frame, prev_frame;
sal.pc = 0;
sal.symtab = NULL;
@ -2125,7 +2211,6 @@ watch_command (arg, from_tty)
b = set_raw_breakpoint (sal);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->type = bp_watchpoint;
b->disposition = donttouch;
b->exp = exp;
b->exp_valid_block = exp_valid_block;
@ -2133,8 +2218,93 @@ watch_command (arg, from_tty)
b->cond = 0;
b->cond_string = NULL;
b->exp_string = savestring (arg, strlen (arg));
frame = block_innermost_frame (exp_valid_block);
if (frame)
{
prev_frame = get_prev_frame (frame);
b->watchpoint_frame = FRAME_FP (frame);
}
else
b->watchpoint_frame = NULL;
if (can_use_hardware_watchpoint (b))
b->type = bp_hardware_watchpoint;
else
b->type = bp_watchpoint;
/* If the expression is "local", then set up a "watchpoint scope"
breakpoint at the point where we've left the scope of the watchpoint
expression. */
if (innermost_block)
{
struct breakpoint *scope_breakpoint;
struct symtab_and_line scope_sal;
if (prev_frame)
{
scope_sal.pc = get_frame_pc (prev_frame);
scope_sal.symtab = NULL;
scope_sal.line = 0;
scope_breakpoint = set_raw_breakpoint (scope_sal);
set_breakpoint_count (breakpoint_count + 1);
scope_breakpoint->number = breakpoint_count;
scope_breakpoint->type = bp_watchpoint_scope;
scope_breakpoint->enable = enabled;
/* Automatically delete the breakpoint when it hits. */
scope_breakpoint->disposition = delete;
/* Only break in the proper frame (help with recursion). */
scope_breakpoint->frame = prev_frame->frame;
/* Set the address at which we will stop. */
scope_breakpoint->address = get_frame_pc (prev_frame);
/* The scope breakpoint is related to the watchpoint. We
will need to act on them together. */
b->related_breakpoint = scope_breakpoint;
}
}
mention (b);
}
/* Return nonzero if the watchpoint described by B can be handled
completely in hardware. If the watchpoint can not be handled
in hardware return zero. */
static int
can_use_hardware_watchpoint (b)
struct breakpoint *b;
{
value_ptr mark = value_mark ();
value_ptr v = evaluate_expression (b->exp);
int found_memory = 0;
/* Make sure all the intermediate values are in memory. Also make sure
we found at least one memory expression. Guards against watch 0x12345,
which is meaningless, but could cause errors if one tries to insert a
hardware watchpoint for the constant expression. */
for ( ; v != mark; v = v->next)
{
if (!(v->lval == lval_memory)
|| v->lval == not_lval
|| (v->lval != not_lval
&& v->modifiable == false))
return 0;
else
if (v->lval == lval_memory)
found_memory = 1;
}
/* The expression itself looks suitable for using a hardware
watchpoint, but give the target machine a chance to reject it. */
return found_memory && TARGET_CAN_USE_HARDWARE_WATCHPOINT (b);
}
/*
* Helper routine for the until_command routine in infcmd.c. Here
@ -2577,6 +2747,7 @@ clear_command (arg, from_tty)
ALL_BREAKPOINTS (b)
while (b->next
&& b->next->type != bp_watchpoint
&& b->next->type != bp_hardware_watchpoint
&& (sal.pc
? b->next->address == sal.pc
: (b->next->source_file != NULL
@ -2635,8 +2806,8 @@ delete_breakpoint (bpt)
register bpstat bs;
if (bpt->inserted)
target_remove_breakpoint(bpt->address, bpt->shadow_contents);
remove_breakpoint (bpt);
if (breakpoint_chain == bpt)
breakpoint_chain = bpt->next;
@ -2650,7 +2821,8 @@ delete_breakpoint (bpt)
check_duplicates (bpt->address);
/* If this breakpoint was inserted, and there is another breakpoint
at the same address, we need to insert the other breakpoint. */
if (bpt->inserted)
if (bpt->inserted
&& bpt->type != bp_hardware_watchpoint)
{
ALL_BREAKPOINTS (b)
if (b->address == bpt->address
@ -2797,6 +2969,7 @@ breakpoint_re_set_one (bint)
break;
case bp_watchpoint:
case bp_hardware_watchpoint:
innermost_block = NULL;
/* The issue arises of what context to evaluate this in. The same
one as when it was set, but what does that mean when symbols have
@ -2829,6 +3002,7 @@ breakpoint_re_set_one (bint)
case bp_finish:
case bp_longjmp:
case bp_longjmp_resume:
case bp_watchpoint_scope:
case bp_call_dummy:
delete_breakpoint (b);
break;
@ -2958,7 +3132,10 @@ map_breakpoint_numbers (args, function)
ALL_BREAKPOINTS (b)
if (b->number == num)
{
struct breakpoint *related_breakpoint = b->related_breakpoint;
function (b);
if (related_breakpoint)
function (related_breakpoint);
goto win;
}
printf_unfiltered ("No breakpoint number %d.\n", num);
@ -2980,11 +3157,11 @@ enable_breakpoint (bpt)
printf_unfiltered ("breakpoint #%d enabled\n", bpt->number);
check_duplicates (bpt->address);
if (bpt->type == bp_watchpoint)
if (bpt->type == bp_watchpoint || bpt->type == bp_hardware_watchpoint)
{
if (bpt->exp_valid_block != NULL)
{
FRAME fr = within_scope (bpt->exp_valid_block);
FRAME fr = find_frame_addr_in_frame_chain (bpt->watchpoint_frame);
if (fr == NULL)
{
printf_filtered ("\
@ -2993,6 +3170,7 @@ is valid is not currently in scope.\n", bpt->number);
bpt->enable = disabled;
return;
}
save_selected_frame = selected_frame;
save_selected_frame_level = selected_frame_level;
select_frame (fr, -1);
@ -3023,6 +3201,7 @@ enable_command (args, from_tty)
{
case bp_breakpoint:
case bp_watchpoint:
case bp_hardware_watchpoint:
enable_breakpoint (bpt);
default:
continue;
@ -3035,6 +3214,12 @@ static void
disable_breakpoint (bpt)
struct breakpoint *bpt;
{
/* Never disable a watchpoint scope breakpoint; we want to
hit them when we leave scope so we can delete both the
watchpoint and its scope breakpoint at that time. */
if (bpt->type == bp_watchpoint_scope)
return;
bpt->enable = disabled;
if (xgdb_verbose && bpt->type == bp_breakpoint)
@ -3056,6 +3241,7 @@ disable_command (args, from_tty)
{
case bp_breakpoint:
case bp_watchpoint:
case bp_hardware_watchpoint:
disable_breakpoint (bpt);
default:
continue;

View file

@ -140,3 +140,62 @@ store_inferior_registers (regno)
return;
}
/* PT_PROT is specific to the PA BSD kernel and isn't documented
anywhere (except here).
PT_PROT allows one to enable/disable the data memory break bit
for pages of memory in an inferior process. This bit is used
to cause "Data memory break traps" to occur when the appropriate
page is written to.
The arguments are as follows:
PT_PROT -- The ptrace action to perform.
INFERIOR_PID -- The pid of the process who's page table entries
will be modified.
PT_ARGS -- The *address* of a 3 word block of memory which has
additional information:
word 0 -- The start address to watch. This should be a page-aligned
address.
word 1 -- The ending address to watch. Again, this should be a
page aligned address.
word 2 -- Nonzero to enable the data memory break bit on the
given address range or zero to disable the data memory break
bit on the given address range.
This call may fail if the given addresses are not valid in the inferior
process. This most often happens when restarting a program which
as watchpoints inserted on heap or stack memory. */
#define PT_PROT 21
int
hppa_set_watchpoint (addr, len, flag)
int addr, len, flag;
{
int pt_args[3];
pt_args[0] = addr;
pt_args[1] = addr + len;
pt_args[2] = flag;
/* Mask off the lower 12 bits since we want to work on a page basis. */
pt_args[0] >>= 12;
pt_args[1] >>= 12;
/* Rounding adjustments. */
pt_args[1] -= pt_args[0];
pt_args[1]++;
/* Put the lower 12 bits back as zero. */
pt_args[0] <<= 12;
pt_args[1] <<= 12;
/* Do it. */
return ptrace (PT_PROT, inferior_pid, (PTRACE_ARG3_TYPE) pt_args, 0);
}

View file

@ -624,8 +624,9 @@ switch_thread:
single_step (0); /* This actually cleans up the ss */
#endif /* NO_SINGLE_STEP */
/* If PC is pointing at a nullified instruction, then step beyond it so that
the user won't be confused when GDB appears to be ready to execute it. */
/* If PC is pointing at a nullified instruction, then step beyond
it so that the user won't be confused when GDB appears to be ready
to execute it. */
if (INSTRUCTION_NULLIFIED)
{
@ -633,7 +634,33 @@ switch_thread:
continue;
}
set_current_frame ( create_new_frame (read_fp (), stop_pc));
set_current_frame (create_new_frame (read_fp (), stop_pc));
select_frame (get_current_frame (), 0);
#ifdef HAVE_STEPPABLE_WATCHPOINT
/* It may not be necessary to disable the watchpoint to stop over
it. For example, the PA can (with some kernel cooperation)
single step over a watchpoint without disabling the watchpoint. */
if (STOPPED_BY_WATCHPOINT (w))
{
resume (1, 0);
continue;
}
#endif
#ifdef HAVE_NONSTEPPABLE_WATCHPOINT
/* It is far more common to need to disable a watchpoint
to step the inferior over it. FIXME. What else might
a debug register or page protection watchpoint scheme need
here? */
if (STOPPED_BY_WATCHPOINT (w))
{
remove_breakpoints ();
resume (1, 0);
insert_breakpoints ();
continue;
}
#endif
stop_frame_address = FRAME_FP (get_current_frame ());
stop_sp = read_sp ();
@ -1404,8 +1431,6 @@ Further execution is probably impossible.\n");
if we have one. */
if (!stop_stack_dummy)
{
select_frame (get_current_frame (), 0);
if (stop_print_frame)
{
int source_only;

View file

@ -2321,6 +2321,10 @@ wait_again:
break;
case FLTBPT:
case FLTTRACE:
statval = (SIGTRAP << 8) | 0177;
break;
case FLTWATCH:
case FLTKWATCH:
statval = (SIGTRAP << 8) | 0177;
break;
case FLTSTACK:
@ -3528,6 +3532,56 @@ procfs_can_run ()
{
return(1);
}
/* Insert a watchpoint */
int
procfs_set_watchpoint(pid, addr, len, rw)
int pid;
CORE_ADDR addr;
int len;
int rw;
{
struct procinfo *pi;
prwatch_t wpt;
pi = find_procinfo (pid == -1 ? inferior_pid : pid, 0);
wpt.pr_vaddr = (caddr_t)addr;
wpt.pr_size = len;
wpt.pr_wflags = ((rw & 1) ? MA_READ : 0) | ((rw & 2) ? MA_WRITE : 0);
if (ioctl (pi->fd, PIOCSWATCH, &wpt) < 0)
{
if (errno == E2BIG)
return -1;
/* Currently it sometimes happens that the same watchpoint gets
deleted twice - don't die in this case (FIXME please) */
if (errno == ESRCH && len == 0)
return 0;
print_sys_errmsg (pi->pathname, errno);
error ("PIOCSWATCH failed");
}
return 0;
}
int
procfs_stopped_by_watchpoint(pid)
int pid;
{
struct procinfo *pi;
short what;
short why;
pi = find_procinfo (pid == -1 ? inferior_pid : pid, 0);
if (pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP))
{
why = pi->prstatus.pr_why;
what = pi->prstatus.pr_what;
if (why == PR_FAULTED
&& (what == FLTWATCH) || (what == FLTKWATCH))
return what;
}
return 0;
}
struct target_ops procfs_ops = {
"procfs", /* to_shortname */

View file

@ -280,7 +280,7 @@ extern value_ptr value_neg PARAMS ((value_ptr arg1));
extern value_ptr value_complement PARAMS ((value_ptr arg1));
extern value_ptr value_struct_elt PARAMS ((value_ptr *argp, value *args,
extern value_ptr value_struct_elt PARAMS ((value_ptr *argp, value_ptr *args,
char *name,
int *static_memfuncp, char *err));
@ -433,6 +433,9 @@ print_floating PARAMS ((char *valaddr, struct type *type, GDB_FILE *stream));
extern int value_print PARAMS ((value_ptr val, GDB_FILE *stream, int format,
enum val_prettyprint pretty));
extern value_ptr
value_release_to_mark PARAMS ((value_ptr mark));
extern int
val_print PARAMS ((struct type *type, char *valaddr, CORE_ADDR address,
GDB_FILE *stream, int format, int deref_ref,

View file

@ -189,6 +189,24 @@ release_value (val)
}
}
/* Release all values up to mark */
value_ptr
value_release_to_mark (mark)
value_ptr mark;
{
value_ptr val, next;
for (val = next = all_values; next; next = VALUE_NEXT (next))
if (VALUE_NEXT (next) == mark)
{
all_values = VALUE_NEXT (next);
VALUE_NEXT (next) = 0;
return val;
}
all_values = 0;
return val;
}
/* Return a copy of the value ARG.
It contains the same contents, for same memory address,
but it's a different block of storage. */