* [rfc, rfa/doc] Multi-threaded watchpoint improvements
@ 2007-09-16 18:40 Daniel Jacobowitz
2007-09-22 9:03 ` Eli Zaretskii
2007-10-01 0:20 ` Daniel Jacobowitz
0 siblings, 2 replies; 27+ messages in thread
From: Daniel Jacobowitz @ 2007-09-16 18:40 UTC (permalink / raw)
To: gdb-patches
I have (finally, sorry for the delay) finished revamping the
multi-threaded watchpoint patches Jeff submitted ages ago and Luis
resubmitted recently. This message contains all the changes except
for various native GNU/Linux target files. It includes manual and
gdbint changes describing what I've figured out to date.
The big change is in the handling of steppable and nonsteppable
watchpoints. Unlike continuable watchpoints, steppable and
nonsteppable watchpoints trigger before the monitored write (or read)
occurs. We detect the watchpoint and single step before displaying it
to the user, so that we can show the old and new values. Before the
attached patch, we called target_stopped_data_address after single
stepping. This patch rearranges things so that we figure out
which watchpoint triggered, or might have triggered, before
we single step. The horrible stepped_after_stopped_by_watchpoint
hack in remote.c goes away as a consequence.
infrun.c calls the new watchpoints_triggered function at each trap
event - except for the step after a steppable or nonsteppable
watchpoint, in which case we use the watchpoint status from right
after the trigger event. If we have not stopped based on a
watchpoint, we mark all hardware watchpoints as not triggered. If we
have stopped but the target doesn't implement
target_stopped_data_address, we mark each watchpoint as possibly
triggered. And if it does implement target_stopped_data_address, we
mark each watchpoint as triggered or not triggered based on the
reported address. When bpstat_stop_status is called, it uses
the triggered status and the type to determine whether we need
to check the watchpoint's value for changes.
A related change was to scope breakpoint handling. The change I
described in the previous paragraph causes GDB to not always check
each hardware watchpoint at every stop that might have been caused by
a watchpoint. This meant we weren't getting the expected stop and
message when a watchpoint went out of scope. I arranged to always
check a watchpoint when its corresponding scope breakpoint triggers.
This was already inconsistent for access and read watchpoints on local
variables, but those are used much less often than hardware
watchpoints, so it was never noticed.
By the way, the current WP_DELETED handling only worked when
STOPPED_BY_WATCHPOINT returned true after stopping on a scope
breakpoint. And you wouldn't expect it to, since the scope
breakpoint isn't a watchpoint. But in fact it usually was set. See
the paragraph I added in gdbint.texinfo about 'sticky' status.
The watchpoint triggered bits in i386's DR_STATUS register are
definitely sticky; they are only reset by "some events" according
to the architecture manual. I suspect those events are triggers
of other watchpoints or hardware breakpoints. This means access
watchpoints on i386 trigger too often (a separate bug not fixed
by this patch).
The change for bp_thread_event and bp_overlay_event prevents
displaying a confused message when a watchpoint triggers in
one thread and another thread reaches __nptl_create_event
while we are trying to stop all threads. The watchthreads.exp
testcase triggers this about half the time.
The code at the end of bpstat_stop_status to reset hardware
watchpoints only worked most of the time. It checked the
type of the first entry in the bpstat chain, but ordering
might mean that the watchpoint was the second or later
entry. I rewrote it to check the whole chain.
And last but not least, this patch makes the watchthreads.exp test
case work on targets where the stopped data address is not available;
on these it is unavoidable to detect two threads hitting watchpoints
simultaneously, since we do not know which thread has hit which
watchpoint. On other targets we serialize the watchpoint hits which
has the very useful benefit of showing the associated source location
for each watchpoint hit.
Do these changes look OK? If any part is confusing, just ask. I was
originally planning to submit this as several separate patches, but
the only one of any real size is the watchpoints_triggered patch
and the others are a little hard to separate from it due to textual
overlap.
This version was tested on x86_64-linux; prior versions have been
tested on ia64-linux, powerpc64-linux, s390-linux, and i386-linux.
That's every GNU/Linux target with hardware watchpoint support. I
can't readily test non-Linux targets, but I am very optimistic that I
didn't break anything.
--
Daniel Jacobowitz
CodeSourcery
2007-09-16 Daniel Jacobowitz <dan@codesourcery.com>
Jeff Johnston <jjohnstn@redhat.com>
* breakpoint.c (watchpoints_triggered): New.
(bpstat_stop_status): Remove STOPPED_BY_WATCHPOINT argument.
Check watchpoint_triggered instead. Combine handling for software
and hardware watchpoints. Do not use target_stopped_data_address
here. Always check a watchpoint if its scope breakpoint triggers.
Do not stop for thread or overlay events. Improve check for
triggered watchpoints without a value change.
(watch_command_1): Insert the scope breakpoint first. Link the
scope breakpoint to the watchpoint.
* breakpoint.h (enum watchpoint_triggered): New.
(struct breakpoint): Add watchpoint_triggered.
(bpstat_stop_status): Update prototype.
(watchpoints_triggered): Declare.
* infrun.c (enum infwait_status): Add infwait_step_watch_state.
(stepped_after_stopped_by_watchpoint): Delete.
(handle_inferior_event): Make stepped_after_stopped_by_watchpoint
local. Handle infwait_step_watch_state. Update calls to
bpstat_stop_status. Use watchpoints_triggered to check
watchpoints.
* remote.c (stepped_after_stopped_by_watchpoint): Remove extern.
(remote_stopped_data_address): Do not check it.
2007-09-16 Daniel Jacobowitz <dan@codesourcery.com>
* gdb.texinfo (Setting Watchpoints): Adjust warning text about
multi-threaded watchpoints.
* gdbint.texinfo (Watchpoints): Describe how watchpoints are
checked. Describe sticky notification. Expand description
of steppable and continuable watchpoints.
(Watchpoints and Threads): New subsection.
2007-09-16 Daniel Jacobowitz <dan@codesourcery.com>
* gdb.threads/watchthreads.c (thread_function): Sleep between
iterations.
* gdb.threads/watchthreads.exp: Allow two watchpoints to trigger
at once for S/390. Generate matching fails and passes.
Index: breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.263
diff -u -p -r1.263 breakpoint.c
--- breakpoint.c 29 Aug 2007 22:07:47 -0000 1.263
+++ breakpoint.c 16 Sep 2007 18:05:27 -0000
@@ -2519,6 +2519,83 @@ bpstat_alloc (struct breakpoint *b, bpst
return bs;
}
\f
+/* The target has stopped with waitstatus WS. Check if any hardware
+ watchpoints have triggered, according to the target. */
+
+int
+watchpoints_triggered (struct target_waitstatus *ws)
+{
+ int stopped_by_watchpoint = STOPPED_BY_WATCHPOINT (*ws);
+ CORE_ADDR addr;
+ struct breakpoint *b;
+
+ if (!stopped_by_watchpoint)
+ {
+ /* We were not stopped by a watchpoint. Mark all watchpoints
+ as not triggered. */
+ ALL_BREAKPOINTS (b)
+ if (b->type == bp_hardware_watchpoint
+ || b->type == bp_read_watchpoint
+ || b->type == bp_access_watchpoint)
+ b->watchpoint_triggered = watch_triggered_no;
+
+ return 0;
+ }
+
+ if (!target_stopped_data_address (¤t_target, &addr))
+ {
+ /* We were stopped by a watchpoint, but we don't know where.
+ Mark all watchpoints as unknown. */
+ ALL_BREAKPOINTS (b)
+ if (b->type == bp_hardware_watchpoint
+ || b->type == bp_read_watchpoint
+ || b->type == bp_access_watchpoint)
+ b->watchpoint_triggered = watch_triggered_unknown;
+
+ return stopped_by_watchpoint;
+ }
+
+ /* The target could report the data address. Mark watchpoints
+ affected by this data address as triggered, and all others as not
+ triggered. */
+
+ ALL_BREAKPOINTS (b)
+ if (b->type == bp_hardware_watchpoint
+ || b->type == bp_read_watchpoint
+ || b->type == bp_access_watchpoint)
+ {
+ struct value *v;
+
+ b->watchpoint_triggered = watch_triggered_no;
+ for (v = b->val_chain; v; v = value_next (v))
+ {
+ if (VALUE_LVAL (v) == lval_memory && ! value_lazy (v))
+ {
+ struct type *vtype = check_typedef (value_type (v));
+
+ if (v == b->val_chain
+ || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
+ && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
+ {
+ CORE_ADDR vaddr;
+
+ vaddr = VALUE_ADDRESS (v) + value_offset (v);
+ /* Exact match not required. Within range is
+ sufficient. */
+ if (addr >= vaddr
+ && addr < vaddr + TYPE_LENGTH (value_type (v)))
+ {
+ b->watchpoint_triggered = watch_triggered_yes;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return 1;
+}
+
/* Possible return values for watchpoint_check (this can't be an enum
because of check_errors). */
/* The watchpoint has been deleted. */
@@ -2637,11 +2714,9 @@ which its expression is valid.\n");
}
/* Get a bpstat associated with having just stopped at address
- BP_ADDR in thread PTID. STOPPED_BY_WATCHPOINT is 1 if the
- target thinks we stopped due to a hardware watchpoint, 0 if we
- know we did not trigger a hardware watchpoint, and -1 if we do not know. */
+ BP_ADDR in thread PTID.
-/* Determine whether we stopped at a breakpoint, etc, or whether we
+ Determine whether we stopped at a breakpoint, etc, or whether we
don't understand this stop. Result is a chain of bpstat's such that:
if we don't understand the stop, the result is a null pointer.
@@ -2656,7 +2731,7 @@ which its expression is valid.\n");
commands, FIXME??? fields. */
bpstat
-bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid, int stopped_by_watchpoint)
+bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid)
{
struct breakpoint *b, *temp;
/* True if we've hit a breakpoint (as opposed to a watchpoint). */
@@ -2691,16 +2766,17 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
continue;
}
- /* Continuable hardware watchpoints are treated as non-existent if the
- reason we stopped wasn't a hardware watchpoint (we didn't stop on
- some data address). Otherwise gdb won't stop on a break instruction
- in the code (not from a breakpoint) when a hardware watchpoint has
- been defined. */
+ /* Continuable hardware watchpoints are treated as non-existent if the
+ reason we stopped wasn't a hardware watchpoint (we didn't stop on
+ some data address). Otherwise gdb won't stop on a break instruction
+ in the code (not from a breakpoint) when a hardware watchpoint has
+ been defined. Also skip watchpoints which we know did not trigger
+ (did not match the data address). */
if ((b->type == bp_hardware_watchpoint
|| b->type == bp_read_watchpoint
|| b->type == bp_access_watchpoint)
- && !stopped_by_watchpoint)
+ && b->watchpoint_triggered == watch_triggered_no)
continue;
if (b->type == bp_hardware_breakpoint)
@@ -2766,82 +2842,33 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
bs->stop = 1;
bs->print = 1;
- if (b->type == bp_watchpoint ||
- b->type == bp_hardware_watchpoint)
- {
- char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n",
- b->number);
- struct cleanup *cleanups = make_cleanup (xfree, message);
- int e = catch_errors (watchpoint_check, bs, message,
- RETURN_MASK_ALL);
- do_cleanups (cleanups);
- switch (e)
- {
- case WP_DELETED:
- /* We've already printed what needs to be printed. */
- /* Actually this is superfluous, because by the time we
- call print_it_typical() the wp will be already deleted,
- and the function will return immediately. */
- bs->print_it = print_it_done;
- /* Stop. */
- break;
- case WP_VALUE_CHANGED:
- /* Stop. */
- ++(b->hit_count);
- break;
- case WP_VALUE_NOT_CHANGED:
- /* Don't stop. */
- bs->print_it = print_it_noop;
- bs->stop = 0;
- continue;
- default:
- /* Can't happen. */
- /* FALLTHROUGH */
- case 0:
- /* Error from catch_errors. */
- printf_filtered (_("Watchpoint %d deleted.\n"), b->number);
- if (b->related_breakpoint)
- b->related_breakpoint->disposition = disp_del_at_next_stop;
- b->disposition = disp_del_at_next_stop;
- /* We've already printed what needs to be printed. */
- bs->print_it = print_it_done;
-
- /* Stop. */
- break;
- }
- }
- else if (b->type == bp_read_watchpoint ||
- b->type == bp_access_watchpoint)
+ if (b->type == bp_watchpoint
+ || b->type == bp_read_watchpoint
+ || b->type == bp_access_watchpoint
+ || b->type == bp_hardware_watchpoint)
{
CORE_ADDR addr;
struct value *v;
- int found = 0;
+ int must_check_value = 0;
- if (!target_stopped_data_address (¤t_target, &addr))
- continue;
- for (v = b->val_chain; v; v = value_next (v))
- {
- if (VALUE_LVAL (v) == lval_memory
- && ! value_lazy (v))
- {
- struct type *vtype = check_typedef (value_type (v));
-
- if (v == b->val_chain
- || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
- && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
- {
- CORE_ADDR vaddr;
+ if (b->type == bp_watchpoint)
+ /* For a software watchpoint, we must always check the
+ watched value. */
+ must_check_value = 1;
+ else if (b->watchpoint_triggered == watch_triggered_yes)
+ /* We have a hardware watchpoint (read, write, or access)
+ and the target earlier reported an address watched by
+ this watchpoint. */
+ must_check_value = 1;
+ else if (b->watchpoint_triggered == watch_triggered_unknown
+ && b->type == bp_hardware_watchpoint)
+ /* We were stopped by a hardware watchpoint, but the target could
+ not report the data address. We must check the watchpoint's
+ value. Access and read watchpoints are out of luck; without
+ a data address, we can't figure it out. */
+ must_check_value = 1;
- vaddr = VALUE_ADDRESS (v) + value_offset (v);
- /* Exact match not required. Within range is
- sufficient. */
- if (addr >= vaddr &&
- addr < vaddr + TYPE_LENGTH (value_type (v)))
- found = 1;
- }
- }
- }
- if (found)
+ if (must_check_value)
{
char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n",
b->number);
@@ -2869,6 +2896,15 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
++(b->hit_count);
break;
case WP_VALUE_NOT_CHANGED:
+ if (b->type == bp_hardware_watchpoint
+ || b->type == bp_watchpoint)
+ {
+ /* Don't stop: write watchpoints shouldn't fire if
+ the value hasn't changed. */
+ bs->print_it = print_it_noop;
+ bs->stop = 0;
+ continue;
+ }
/* Stop. */
++(b->hit_count);
break;
@@ -2885,12 +2921,12 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
break;
}
}
- else /* found == 0 */
+ else /* must_check_value == 0 */
{
- /* This is a case where some watchpoint(s) triggered,
- but not at the address of this watchpoint (FOUND
- was left zero). So don't print anything for this
- watchpoint. */
+ /* This is a case where some watchpoint(s) triggered, but
+ not at the address of this watchpoint, or else no
+ watchpoint triggered after all. So don't print
+ anything for this watchpoint. */
bs->print_it = print_it_noop;
bs->stop = 0;
continue;
@@ -2912,6 +2948,13 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
{
int value_is_zero = 0;
+ /* If this is a scope breakpoint, mark the associated
+ watchpoint as triggered so that we will handle the
+ out-of-scope event. We'll get to the watchpoint next
+ iteration. */
+ if (b->type == bp_watchpoint_scope)
+ b->related_breakpoint->watchpoint_triggered = watch_triggered_yes;
+
if (b->cond)
{
/* Need to select the frame, with all that implies
@@ -2942,6 +2985,9 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
annotate_ignore_count_change ();
bs->stop = 0;
}
+ else if (b->type == bp_thread_event || b->type == bp_overlay_event)
+ /* We do not stop for these. */
+ bs->stop = 0;
else
{
/* We will stop here */
@@ -2968,17 +3014,27 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
bs->next = NULL; /* Terminate the chain */
bs = root_bs->next; /* Re-grab the head of the chain */
- /* 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 ||
- bs->breakpoint_at->type == bp_read_watchpoint ||
- bs->breakpoint_at->type == bp_access_watchpoint))
- {
- remove_breakpoints ();
- insert_breakpoints ();
- }
- return bs;
+ /* If we aren't stopping, the value of some hardware watchpoint may
+ not have changed, but the intermediate memory locations we are
+ watching may have. Don't bother if we're stopping; this will get
+ done later. */
+ for (bs = root_bs->next; bs != NULL; bs = bs->next)
+ if (bs->stop)
+ break;
+
+ if (bs == NULL)
+ for (bs = root_bs->next; bs != NULL; bs = bs->next)
+ if (!bs->stop
+ && (bs->breakpoint_at->type == bp_hardware_watchpoint
+ || bs->breakpoint_at->type == bp_read_watchpoint
+ || bs->breakpoint_at->type == bp_access_watchpoint))
+ {
+ remove_breakpoints ();
+ insert_breakpoints ();
+ break;
+ }
+
+ return root_bs->next;
}
\f
/* Tell what to do about this bpstat. */
@@ -5694,7 +5750,7 @@ stopat_command (char *arg, int from_tty)
static void
watch_command_1 (char *arg, int accessflag, int from_tty)
{
- struct breakpoint *b;
+ struct breakpoint *b, *scope_breakpoint = NULL;
struct symtab_and_line sal;
struct expression *exp;
struct block *exp_valid_block;
@@ -5772,6 +5828,37 @@ watch_command_1 (char *arg, int accessfl
if (!mem_cnt || target_resources_ok <= 0)
bp_type = bp_watchpoint;
+ frame = block_innermost_frame (exp_valid_block);
+ if (frame)
+ prev_frame = get_prev_frame (frame);
+ else
+ prev_frame = NULL;
+
+ /* 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. Create the scope breakpoint before the watchpoint, so
+ that we will encounter it first in bpstat_stop_status. */
+ if (innermost_block && prev_frame)
+ {
+ scope_breakpoint = create_internal_breakpoint (get_frame_pc (prev_frame),
+ bp_watchpoint_scope);
+
+ scope_breakpoint->enable_state = bp_enabled;
+
+ /* Automatically delete the breakpoint when it hits. */
+ scope_breakpoint->disposition = disp_del;
+
+ /* Only break in the proper frame (help with recursion). */
+ scope_breakpoint->frame_id = get_frame_id (prev_frame);
+
+ /* Set the address at which we will stop. */
+ scope_breakpoint->loc->requested_address
+ = get_frame_pc (prev_frame);
+ scope_breakpoint->loc->address
+ = adjust_breakpoint_address (scope_breakpoint->loc->requested_address,
+ scope_breakpoint->type);
+ }
+
/* Now set up the breakpoint. */
b = set_raw_breakpoint (sal, bp_type);
set_breakpoint_count (breakpoint_count + 1);
@@ -5787,48 +5874,19 @@ watch_command_1 (char *arg, int accessfl
else
b->cond_string = 0;
- frame = block_innermost_frame (exp_valid_block);
if (frame)
- {
- prev_frame = get_prev_frame (frame);
- b->watchpoint_frame = get_frame_id (frame);
- }
+ b->watchpoint_frame = get_frame_id (frame);
else
- {
- memset (&b->watchpoint_frame, 0, sizeof (b->watchpoint_frame));
- }
+ memset (&b->watchpoint_frame, 0, sizeof (b->watchpoint_frame));
- /* 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)
+ if (scope_breakpoint != NULL)
{
- if (prev_frame)
- {
- struct breakpoint *scope_breakpoint;
- scope_breakpoint = create_internal_breakpoint (get_frame_pc (prev_frame),
- bp_watchpoint_scope);
-
- scope_breakpoint->enable_state = bp_enabled;
-
- /* Automatically delete the breakpoint when it hits. */
- scope_breakpoint->disposition = disp_del;
-
- /* Only break in the proper frame (help with recursion). */
- scope_breakpoint->frame_id = get_frame_id (prev_frame);
-
- /* Set the address at which we will stop. */
- scope_breakpoint->loc->requested_address
- = get_frame_pc (prev_frame);
- scope_breakpoint->loc->address
- = adjust_breakpoint_address (scope_breakpoint->loc->requested_address,
- scope_breakpoint->type);
-
- /* The scope breakpoint is related to the watchpoint. We
- will need to act on them together. */
- b->related_breakpoint = scope_breakpoint;
- }
+ /* The scope breakpoint is related to the watchpoint. We will
+ need to act on them together. */
+ b->related_breakpoint = scope_breakpoint;
+ scope_breakpoint->related_breakpoint = b;
}
+
value_free_to_mark (mark);
mention (b);
}
Index: breakpoint.h
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.h,v
retrieving revision 1.47
diff -u -p -r1.47 breakpoint.h
--- breakpoint.h 23 Aug 2007 18:08:26 -0000 1.47
+++ breakpoint.h 16 Sep 2007 18:05:27 -0000
@@ -299,6 +299,19 @@ struct breakpoint_ops
void (*print_mention) (struct breakpoint *);
};
+enum watchpoint_triggered
+{
+ /* This watchpoint definitely did not trigger. */
+ watch_triggered_no = 0,
+
+ /* Some hardware watchpoint triggered, and it might have been this
+ one, but we do not know which it was. */
+ watch_triggered_unknown,
+
+ /* This hardware watchpoint definitely did trigger. */
+ watch_triggered_yes
+};
+
/* Note that the ->silent field is not currently used by any commands
(though the code is in there if it was to be, and set_raw_breakpoint
does set it to 0). I implemented it because I thought it would be
@@ -378,6 +391,10 @@ struct breakpoint
should be evaluated on the outermost frame. */
struct frame_id watchpoint_frame;
+ /* For hardware watchpoints, the triggered status according to the
+ hardware. */
+ enum watchpoint_triggered watchpoint_triggered;
+
/* Thread number for thread-specific breakpoint, or -1 if don't care */
int thread;
@@ -440,8 +457,7 @@ extern void bpstat_clear (bpstat *);
is part of the bpstat is copied as well. */
extern bpstat bpstat_copy (bpstat);
-extern bpstat bpstat_stop_status (CORE_ADDR pc, ptid_t ptid,
- int stopped_by_watchpoint);
+extern bpstat bpstat_stop_status (CORE_ADDR pc, ptid_t ptid);
\f
/* This bpstat_what stuff tells wait_for_inferior what to do with a
breakpoint (a challenging task). */
@@ -836,4 +852,8 @@ extern void remove_single_step_breakpoin
extern void *deprecated_insert_raw_breakpoint (CORE_ADDR);
extern int deprecated_remove_raw_breakpoint (void *);
+/* Check if any hardware watchpoints have triggered, according to the
+ target. */
+int watchpoints_triggered (struct target_waitstatus *);
+
#endif /* !defined (BREAKPOINT_H) */
Index: infrun.c
===================================================================
RCS file: /cvs/src/src/gdb/infrun.c,v
retrieving revision 1.245
diff -u -p -r1.245 infrun.c
--- infrun.c 23 Aug 2007 18:08:35 -0000 1.245
+++ infrun.c 16 Sep 2007 18:05:28 -0000
@@ -882,6 +882,7 @@ enum infwait_states
{
infwait_normal_state,
infwait_thread_hop_state,
+ infwait_step_watch_state,
infwait_nonstep_watch_state
};
@@ -1221,17 +1222,12 @@ adjust_pc_after_break (struct execution_
by an event from the inferior, figure out what it means and take
appropriate action. */
-int stepped_after_stopped_by_watchpoint;
-
void
handle_inferior_event (struct execution_control_state *ecs)
{
- /* NOTE: bje/2005-05-02: If you're looking at this code and thinking
- that the variable stepped_after_stopped_by_watchpoint isn't used,
- then you're wrong! See remote.c:remote_stopped_data_address. */
-
int sw_single_step_trap_p = 0;
- int stopped_by_watchpoint = -1; /* Mark as unknown. */
+ int stopped_by_watchpoint;
+ int stepped_after_stopped_by_watchpoint = 0;
/* Cache the last pid/waitstatus. */
target_last_wait_ptid = ecs->ptid;
@@ -1251,7 +1247,14 @@ handle_inferior_event (struct execution_
case infwait_normal_state:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: infwait_normal_state\n");
- stepped_after_stopped_by_watchpoint = 0;
+ break;
+
+ case infwait_step_watch_state:
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: infwait_step_watch_state\n");
+
+ stepped_after_stopped_by_watchpoint = 1;
break;
case infwait_nonstep_watch_state:
@@ -1440,7 +1443,7 @@ handle_inferior_event (struct execution_
stop_pc = read_pc ();
- stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid, 0);
+ stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
@@ -1488,7 +1491,7 @@ handle_inferior_event (struct execution_
ecs->saved_inferior_ptid = inferior_ptid;
inferior_ptid = ecs->ptid;
- stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid, 0);
+ stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
inferior_ptid = ecs->saved_inferior_ptid;
@@ -1770,24 +1773,20 @@ handle_inferior_event (struct execution_
singlestep_breakpoints_inserted_p = 0;
}
- /* 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 (HAVE_STEPPABLE_WATCHPOINT && STOPPED_BY_WATCHPOINT (ecs->ws))
+ if (stepped_after_stopped_by_watchpoint)
+ stopped_by_watchpoint = 0;
+ else
+ stopped_by_watchpoint = watchpoints_triggered (&ecs->ws);
+
+ /* If necessary, step over this watchpoint. We'll be back to display
+ it in a moment. */
+ if (stopped_by_watchpoint
+ && (HAVE_STEPPABLE_WATCHPOINT
+ || gdbarch_have_nonsteppable_watchpoint (current_gdbarch)))
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n");
- resume (1, 0);
- prepare_to_wait (ecs);
- return;
- }
- /* 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 (gdbarch_have_nonsteppable_watchpoint (current_gdbarch)
- && STOPPED_BY_WATCHPOINT (ecs->ws))
- {
/* At this point, we are stopped at an instruction which has
attempted to write to a piece of memory under control of
a watchpoint. The instruction hasn't actually executed
@@ -1797,31 +1796,31 @@ handle_inferior_event (struct execution_
In order to make watchpoints work `right', we really need
to complete the memory write, and then evaluate the
- watchpoint expression. The following code does that by
- removing the watchpoint (actually, all watchpoints and
- breakpoints), single-stepping the target, re-inserting
- watchpoints, and then falling through to let normal
- single-step processing handle proceed. Since this
- includes evaluating watchpoints, things will come to a
- stop in the correct manner. */
+ watchpoint expression. We do this by single-stepping the
+ target.
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n");
- remove_breakpoints ();
+ 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.
+
+ It is far more common to need to disable a watchpoint to step
+ the inferior over it. If we have non-steppable watchpoints,
+ we must disable the current watchpoint; it's simplest to
+ disable all watchpoints and breakpoints. */
+
+ if (!HAVE_STEPPABLE_WATCHPOINT)
+ remove_breakpoints ();
registers_changed ();
target_resume (ecs->ptid, 1, TARGET_SIGNAL_0); /* Single step */
-
ecs->waiton_ptid = ecs->ptid;
- ecs->wp = &(ecs->ws);
- ecs->infwait_state = infwait_nonstep_watch_state;
+ if (HAVE_STEPPABLE_WATCHPOINT)
+ ecs->infwait_state = infwait_step_watch_state;
+ else
+ ecs->infwait_state = infwait_nonstep_watch_state;
prepare_to_wait (ecs);
return;
}
- /* It may be possible to simply continue after a watchpoint. */
- if (HAVE_CONTINUABLE_WATCHPOINT)
- stopped_by_watchpoint = STOPPED_BY_WATCHPOINT (ecs->ws);
-
ecs->stop_func_start = 0;
ecs->stop_func_end = 0;
ecs->stop_func_name = 0;
@@ -1943,8 +1942,7 @@ handle_inferior_event (struct execution_
else
{
/* See if there is a breakpoint at the current PC. */
- stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid,
- stopped_by_watchpoint);
+ stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
/* Following in case break condition called a
function. */
Index: remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.266
diff -u -p -r1.266 remote.c
--- remote.c 23 Aug 2007 18:08:36 -0000 1.266
+++ remote.c 16 Sep 2007 18:05:29 -0000
@@ -5410,14 +5410,11 @@ remote_stopped_by_watchpoint (void)
return remote_stopped_by_watchpoint_p;
}
-extern int stepped_after_stopped_by_watchpoint;
-
static int
remote_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
{
int rc = 0;
- if (remote_stopped_by_watchpoint ()
- || stepped_after_stopped_by_watchpoint)
+ if (remote_stopped_by_watchpoint ())
{
*addr_p = remote_watch_data_address;
rc = 1;
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.428
diff -u -p -r1.428 gdb.texinfo
--- doc/gdb.texinfo 2 Sep 2007 20:02:12 -0000 1.428
+++ doc/gdb.texinfo 16 Sep 2007 18:05:31 -0000
@@ -3290,20 +3290,13 @@ rerun the program, you will need to set
way of doing that would be to set a code breakpoint at the entry to the
@code{main} function and when it breaks, set all the watchpoints.
-@quotation
@cindex watchpoints and threads
@cindex threads and watchpoints
-@emph{Warning:} In multi-thread programs, watchpoints have only limited
-usefulness. With the current watchpoint implementation, @value{GDBN}
-can only watch the value of an expression @emph{in a single thread}. If
-you are confident that the expression can only change due to the current
-thread's activity (and if you are also confident that no other thread
-can become current), then you can use watchpoints as usual. However,
-@value{GDBN} may not notice when a non-current thread's activity changes
-the expression.
+In multi-threaded programs, watchpoints will detect changes to the
+watched expression from every thread.
-@c FIXME: this is almost identical to the previous paragraph.
-@emph{HP-UX Warning:} In multi-thread programs, software watchpoints
+@quotation
+@emph{Warning:} In multi-threaded programs, software watchpoints
have only limited usefulness. If @value{GDBN} creates a software
watchpoint, it can only watch the value of an expression @emph{in a
single thread}. If you are confident that the expression can only
Index: doc/gdbint.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdbint.texinfo,v
retrieving revision 1.266
diff -u -p -r1.266 gdbint.texinfo
--- doc/gdbint.texinfo 5 Jul 2007 12:22:32 -0000 1.266
+++ doc/gdbint.texinfo 16 Sep 2007 18:05:32 -0000
@@ -660,15 +660,21 @@ section is mostly irrelevant for softwar
When the inferior stops, @value{GDBN} tries to establish, among other
possible reasons, whether it stopped due to a watchpoint being hit.
-For a data-write watchpoint, it does so by evaluating, for each
-watchpoint, the expression whose value is being watched, and testing
-whether the watched value has changed. For data-read and data-access
-watchpoints, @value{GDBN} needs the target to supply a primitive that
-returns the address of the data that was accessed or read (see the
-description of @code{target_stopped_data_address} below): if this
-primitive returns a valid address, @value{GDBN} infers that a
-watchpoint triggered if it watches an expression whose evaluation uses
-that address.
+It first uses @code{STOPPED_BY_WATCHPOINT} to see if any watchpoint
+was hit. If not, all watchpoint checking is skipped.
+
+Then @value{GDBN} calls @code{target_stopped_data_address} exactly
+once. This method returns the address of the watchpoint which
+triggered, if the target can determine it. The returned address is
+compared to each watched memory address in each active watchpoint.
+Data-read and data-access watchpoints rely on this; if the triggered
+address is not available, read and access watchpoints will not work.
+If the triggered address is available, @value{GDBN} will only check
+data-write watchpoints which match the triggered address. If it is
+not available, @value{GDBN} will consider all data-write watchpoints.
+For each data-write watchpoint that @value{GDBN} considers, it does so
+by evaluating the expression whose value is being watched, and testing
+whether the watched value has changed.
@value{GDBN} uses several macros and primitives to support hardware
watchpoints:
@@ -721,26 +727,40 @@ These two macros should return 0 for suc
@item target_stopped_data_address (@var{addr_p})
If the inferior has some watchpoint that triggered, place the address
associated with the watchpoint at the location pointed to by
-@var{addr_p} and return non-zero. Otherwise, return zero. Note that
-this primitive is used by @value{GDBN} only on targets that support
-data-read or data-access type watchpoints, so targets that have
-support only for data-write watchpoints need not implement these
-primitives.
+@var{addr_p} and return non-zero. Otherwise, return zero. This
+is required for data-read and data-access watchpoints. It is
+not required for data-write watchpoints, but @value{GDBN} uses
+it to improve handling of those also.
+
+@value{GDBN} will only call this method once per watchpoint stop,
+immediately after calling @code{STOPPED_BY_WATCHPOINT}. If the
+target's watchpoint indication is sticky, i.e., stays set after
+resuming, this method should clear it. For instance, the x86 debug
+control register has sticky triggered flags.
@findex HAVE_STEPPABLE_WATCHPOINT
@item HAVE_STEPPABLE_WATCHPOINT
If defined to a non-zero value, it is not necessary to disable a
-watchpoint to step over it.
+watchpoint to step over it. Like @code{gdbarch_have_nonsteppable_watchpoint},
+this is usually set when watchpoints trigger at the instruction
+which will perform an interesting read or write. It should be
+set if there is a temporary disable bit which allows the processor
+to step over the interesting instruction without raising the
+watchpoint exception again.
@findex gdbarch_have_nonsteppable_watchpoint
@item int gdbarch_have_nonsteppable_watchpoint (@var{gdbarch})
If it returns a non-zero value, @value{GDBN} should disable a
-watchpoint to step the inferior over it.
+watchpoint to step the inferior over it. This is usually set when
+watchpoints trigger at the instruction which will perform an
+interesting read or write.
@findex HAVE_CONTINUABLE_WATCHPOINT
@item HAVE_CONTINUABLE_WATCHPOINT
If defined to a non-zero value, it is possible to continue the
-inferior after a watchpoint has been hit.
+inferior after a watchpoint has been hit. This is usually set
+when watchpoints trigger at the instruction following an interesting
+read or write.
@findex CANNOT_STEP_HW_WATCHPOINTS
@item CANNOT_STEP_HW_WATCHPOINTS
@@ -763,6 +783,27 @@ determine for sure whether the inferior
it could return non-zero ``just in case''.
@end table
+@subsection Watchpoints and Threads
+@cindex watchpoints, with threads
+
+@value{GDBN} only supports process-wide watchpoints. If the target
+supports threads and per-thread debug registers, it should set the
+per-thread debug registers for all threads to the same value. On
+@sc{gnu}/Linux native targets, this is accomplished by using
+@code{ALL_LWPS} in @code{target_insert_watchpoint} and
+@code{target_remove_watchpoint} and by using @code{linux_set_new_thread}
+to register a handler for newly created threads.
+
+@value{GDBN}'s @sc{gnu}/Linux support only reports a single event
+at a time, although multiple events can trigger simultaneously for
+multi-threaded programs. When multiple events occur, @file{linux-nat.c}
+queues subsequent events and returns them the next time the program
+is resumed. This means that @code{STOPPED_BY_WATCHPOINT} and
+@code{target_stopped_data_address} only need to consult the current
+thread's state---the thread indicated by @code{inferior_ptid}. If
+two threads have hit watchpoints simultaneously, those routines
+will be called a second time for the second thread.
+
@subsection x86 Watchpoints
@cindex x86 debug registers
@cindex watchpoints, on x86
Index: testsuite/gdb.threads/watchthreads.c
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.threads/watchthreads.c,v
retrieving revision 1.3
diff -u -p -r1.3 watchthreads.c
--- testsuite/gdb.threads/watchthreads.c 23 Aug 2007 18:08:50 -0000 1.3
+++ testsuite/gdb.threads/watchthreads.c 16 Sep 2007 18:05:32 -0000
@@ -56,7 +56,7 @@ void *thread_function(void *arg) {
/* Don't run forever. Run just short of it :) */
while (*myp > 0)
{
- (*myp) ++; /* Loop increment. */
+ (*myp) ++; usleep (1); /* Loop increment. */
}
pthread_exit(NULL);
Index: testsuite/gdb.threads/watchthreads.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.threads/watchthreads.exp,v
retrieving revision 1.4
diff -u -p -r1.4 watchthreads.exp
--- testsuite/gdb.threads/watchthreads.exp 23 Aug 2007 18:14:19 -0000 1.4
+++ testsuite/gdb.threads/watchthreads.exp 16 Sep 2007 18:05:32 -0000
@@ -30,6 +30,10 @@ if [target_info exists gdb,no_hardware_w
return 0;
}
+proc target_no_stopped_data { } {
+ return [istarget s390*-*-*]
+}
+
set testfile "watchthreads"
set srcfile ${testfile}.c
set binfile ${objdir}/${subdir}/${testfile}
@@ -61,20 +65,56 @@ gdb_test "watch args\[1\]" "Hardware wat
set init_line [expr [gdb_get_line_number "Init value"]+1]
set inc_line [gdb_get_line_number "Loop increment"]
+set main_loc "main \\\(\\\) at .*watchthreads.c:$init_line"
+set thread0_loc "thread_function \\\(arg=0x0\\\) at .*watchthreads.c:$inc_line"
+set thread1_loc "thread_function \\\(arg=0x1\\\) at .*watchthreads.c:$inc_line"
# Loop and continue to allow both watchpoints to be triggered.
for {set i 0} {$i < 30} {incr i} {
+ set test_flag_0 0
+ set test_flag_1 0
set test_flag 0
gdb_test_multiple "continue" "threaded watch loop" {
- -re "Hardware watchpoint 2: args\\\[0\\\].*Old value = 0.*New value = 1.*main \\\(\\\) at .*watchthreads.c:$init_line.*$gdb_prompt $"
- { set args_0 1; set test_flag 1 }
- -re "Hardware watchpoint 3: args\\\[1\\\].*Old value = 0.*New value = 1.*main \\\(\\\) at .*watchthreads.c:$init_line.*$gdb_prompt $"
- { set args_1 1; set test_flag 1 }
- -re "Hardware watchpoint 2: args\\\[0\\\].*Old value = $args_0.*New value = [expr $args_0+1].*in thread_function \\\(arg=0x0\\\) at .*watchthreads.c:$inc_line.*$gdb_prompt $"
- { set args_0 [expr $args_0+1]; set test_flag 1 }
- -re "Hardware watchpoint 3: args\\\[1\\\].*Old value = $args_1.*New value = [expr $args_1+1].*in thread_function \\\(arg=0x1\\\) at .*watchthreads.c:$inc_line.*$gdb_prompt $"
- { set args_1 [expr $args_1+1]; set test_flag 1 }
+ -re "(.*Hardware watchpoint.*)$gdb_prompt $" {
+ # At least one hardware watchpoint was hit. Check if both were.
+ set string $expect_out(1,string)
+
+ if [regexp "Hardware watchpoint 2: args\\\[0\\\]\[^\r\]*\r\[^\r\]*\r\[^\r\]*Old value = $args_0\[^\r\]*\r\[^\r\]*New value = [expr $args_0+1]\r" $string] {
+ incr args_0
+ incr test_flag_0
+ }
+ if [regexp "Hardware watchpoint 3: args\\\[1\\\]\[^\r\]*\r\[^\r\]*\r\[^\r\]*Old value = $args_1\[^\r\]*\r\[^\r\]*New value = [expr $args_1+1]\r" $string] {
+ incr args_1
+ incr test_flag_1
+ }
+
+ set expected_loc "bogus location"
+ if { $test_flag_0 == 1 && $test_flag_1 == 0 && $args_0 == 1 } {
+ set expected_loc $main_loc
+ } elseif { $test_flag_0 == 0 && $test_flag_1 == 1 && $args_1 == 1 } {
+ set expected_loc $main_loc
+ } elseif { $test_flag_0 == 1 && $test_flag_1 == 0 } {
+ set expected_loc $thread0_loc
+ } elseif { $test_flag_0 == 0 && $test_flag_1 == 1 } {
+ set expected_loc $thread1_loc
+ } elseif { $test_flag_0 + $test_flag_1 == 2 } {
+ # On S/390, or any other system which can not report the
+ # stopped data address, it is OK to report two watchpoints
+ # at once in this test. Make sure the reported location
+ # corresponds to at least one of the watchpoints (and not,
+ # e.g., __nptl_create_event). On other systems, we should
+ # report the two watchpoints serially.
+ if { [target_no_stopped_data] } {
+ set expected_loc "($main_loc|$thread0_loc|$thread1_loc)"
+ }
+ }
+
+ if [ regexp "$expected_loc" $string ] {
+ set test_flag 1
+ }
+ }
}
+
# If we fail above, don't bother continuing loop
if { $test_flag == 0 } {
set i 30;
@@ -84,6 +124,8 @@ for {set i 0} {$i < 30} {incr i} {
# Print success message if loop succeeded.
if { $test_flag == 1 } {
pass "threaded watch loop"
+} else {
+ fail "threaded watch loop"
}
# Verify that we hit first watchpoint in main thread.
@@ -120,7 +162,14 @@ if { $args_1 > 1 } {
# Verify that all watchpoint hits are accounted for.
set message "combination of threaded watchpoints = 30"
-if { [expr $args_0+$args_1] == 30 } {
+if { [target_no_stopped_data] } {
+ # See above. If we allow two watchpoints to be hit at once, we
+ # may have more than 30 hits total.
+ set result [expr $args_0 + $args_1 >= 30]
+} else {
+ set result [expr $args_0 + $args_1 == 30]
+}
+if { $result } {
pass $message
} else {
fail $message
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2007-09-16 18:40 [rfc, rfa/doc] Multi-threaded watchpoint improvements Daniel Jacobowitz
@ 2007-09-22 9:03 ` Eli Zaretskii
2007-09-22 14:04 ` Daniel Jacobowitz
2007-10-01 0:20 ` Daniel Jacobowitz
1 sibling, 1 reply; 27+ messages in thread
From: Eli Zaretskii @ 2007-09-22 9:03 UTC (permalink / raw)
To: Daniel Jacobowitz; +Cc: gdb-patches
> Date: Sun, 16 Sep 2007 14:39:49 -0400
> From: Daniel Jacobowitz <drow@false.org>
>
> I have (finally, sorry for the delay) finished revamping the
> multi-threaded watchpoint patches Jeff submitted ages ago and Luis
> resubmitted recently. This message contains all the changes except
> for various native GNU/Linux target files. It includes manual and
> gdbint changes describing what I've figured out to date.
Thanks (and sorry for the delay in reviewing: it was a busy week).
> Do these changes look OK?
The changes to the manuals are okay with me, except for the following:
> --- doc/gdbint.texinfo 5 Jul 2007 12:22:32 -0000 1.266
> +++ doc/gdbint.texinfo 16 Sep 2007 18:05:32 -0000
> @@ -660,15 +660,21 @@ section is mostly irrelevant for softwar
>
> When the inferior stops, @value{GDBN} tries to establish, among other
> possible reasons, whether it stopped due to a watchpoint being hit.
> -For a data-write watchpoint, it does so by evaluating, for each
> -watchpoint, the expression whose value is being watched, and testing
> -whether the watched value has changed. For data-read and data-access
> -watchpoints, @value{GDBN} needs the target to supply a primitive that
> -returns the address of the data that was accessed or read (see the
> -description of @code{target_stopped_data_address} below): if this
> -primitive returns a valid address, @value{GDBN} infers that a
> -watchpoint triggered if it watches an expression whose evaluation uses
> -that address.
> +It first uses @code{STOPPED_BY_WATCHPOINT} to see if any watchpoint
> +was hit. If not, all watchpoint checking is skipped.
> +
> +Then @value{GDBN} calls @code{target_stopped_data_address} exactly
> +once. This method returns the address of the watchpoint which
> +triggered, if the target can determine it. The returned address is
> +compared to each watched memory address in each active watchpoint.
> +Data-read and data-access watchpoints rely on this; if the triggered
> +address is not available, read and access watchpoints will not work.
> +If the triggered address is available, @value{GDBN} will only check
> +data-write watchpoints which match the triggered address. If it is
> +not available, @value{GDBN} will consider all data-write watchpoints.
> +For each data-write watchpoint that @value{GDBN} considers, it does so
> +by evaluating the expression whose value is being watched, and testing
> +whether the watched value has changed.
The old text clearly separated the description of what GDB does for
data-write watchpoints from what it does for date-read/data-access
watchpoints. The new text confuses things, because it doesn't keep
that separation. I suggest to rephrase the last paragraph as follows:
Then @value{GDBN} calls @code{target_stopped_data_address} exactly
once. This method returns the address of the watchpoint which
triggered, if the target can determine it. If the triggered address
is available, @value{GDBN} compares the address returned by this
method with each watched memory address in each active watchpoint.
For data-read and data-access watchpoints, @value{GDBN} announces
every watchpoint that watches the triggered address as being hit.
For this reason, data-read and data-access watchpoints
@emph{require} that the triggered address be available; if not, read
and access watchpoints will never be considered hit. For data-write
watchpoints, if the triggered address is available, @value{GDBN}
considers only those watchpoints which match that address;
otherwise, @value{GDBN} considers all data-write watchpoints. For
each data-write watchpoint that @value{GDBN} considers, it evaluates
the expression whose value is being watched, and tests whether the
watched value has changed. Watchpoints whose watched values has
changed are announced as hit.
Also, I don't understand the purpose of this sentence:
> +@value{GDBN} only supports process-wide watchpoints.
"Process-wide watchpoints'' as opposed to what?
The text then goes on like this:
> If the target
> +supports threads and per-thread debug registers, it should set the
> +per-thread debug registers for all threads to the same value. On
> +@sc{gnu}/Linux native targets, this is accomplished by using
> +@code{ALL_LWPS} in @code{target_insert_watchpoint} and
> +@code{target_remove_watchpoint} and by using @code{linux_set_new_thread}
> +to register a handler for newly created threads.
Is this perhaps the opposite of ``process-wide watchpoints''? If so,
it sounds like a contradiction: first you say we don't support
per-thread watchpoints, then you say we do (for some platforms).
What am I missing here?
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2007-09-22 9:03 ` Eli Zaretskii
@ 2007-09-22 14:04 ` Daniel Jacobowitz
2007-09-22 14:13 ` Eli Zaretskii
0 siblings, 1 reply; 27+ messages in thread
From: Daniel Jacobowitz @ 2007-09-22 14:04 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
On Sat, Sep 22, 2007 at 11:03:43AM +0200, Eli Zaretskii wrote:
> Thanks (and sorry for the delay in reviewing: it was a busy week).
No problem - I appreciate your looking at it!
> The old text clearly separated the description of what GDB does for
> data-write watchpoints from what it does for date-read/data-access
> watchpoints. The new text confuses things, because it doesn't keep
> that separation. I suggest to rephrase the last paragraph as follows:
I like your version.
> watched value has changed. Watchpoints whose watched values has
> changed are announced as hit.
"have changed", right?
> Also, I don't understand the purpose of this sentence:
>
> > +@value{GDBN} only supports process-wide watchpoints.
>
> "Process-wide watchpoints'' as opposed to what?
As opposed to thread-specific watchpoints. We can make a watchpoint
act like it is thread-specific (or we will be able to once Luis's
patch is done), but we don't support setting hardware watchpoints that
only trigger in a specific thread. Yet, anyway.
> Is this perhaps the opposite of ``process-wide watchpoints''? If so,
> it sounds like a contradiction: first you say we don't support
> per-thread watchpoints, then you say we do (for some platforms).
>
> What am I missing here?
This is how I implement a process-wide watchpoint -- which is what the
core target-independent parts of GDB support -- using thread-specific
watchpoint registers supported by i386 GNU/Linux.
Does that clarify? Something like "process-wide watchpoints, which
trigger in all threads"?
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2007-09-22 14:04 ` Daniel Jacobowitz
@ 2007-09-22 14:13 ` Eli Zaretskii
2007-09-22 15:37 ` Daniel Jacobowitz
0 siblings, 1 reply; 27+ messages in thread
From: Eli Zaretskii @ 2007-09-22 14:13 UTC (permalink / raw)
To: Daniel Jacobowitz; +Cc: gdb-patches
> Date: Sat, 22 Sep 2007 10:04:09 -0400
> From: Daniel Jacobowitz <drow@false.org>
> Cc: gdb-patches@sourceware.org
>
> > watched value has changed. Watchpoints whose watched values has
> > changed are announced as hit.
>
> "have changed", right?
Blush. Yes, of course.
> > > +@value{GDBN} only supports process-wide watchpoints.
> >
> > "Process-wide watchpoints'' as opposed to what?
>
> As opposed to thread-specific watchpoints. We can make a watchpoint
> act like it is thread-specific (or we will be able to once Luis's
> patch is done), but we don't support setting hardware watchpoints that
> only trigger in a specific thread. Yet, anyway.
I think you should add something like this explanation, to make the
intent clear.
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2007-09-22 14:13 ` Eli Zaretskii
@ 2007-09-22 15:37 ` Daniel Jacobowitz
2007-09-22 15:46 ` Eli Zaretskii
0 siblings, 1 reply; 27+ messages in thread
From: Daniel Jacobowitz @ 2007-09-22 15:37 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
On Sat, Sep 22, 2007 at 04:13:24PM +0200, Eli Zaretskii wrote:
> > > > +@value{GDBN} only supports process-wide watchpoints.
> > >
> > > "Process-wide watchpoints'' as opposed to what?
> >
> > As opposed to thread-specific watchpoints. We can make a watchpoint
> > act like it is thread-specific (or we will be able to once Luis's
> > patch is done), but we don't support setting hardware watchpoints that
> > only trigger in a specific thread. Yet, anyway.
>
> I think you should add something like this explanation, to make the
> intent clear.
Is this clearer?
@value{GDBN} only supports process-wide watchpoints, which trigger in
all threads. If the target supports threads, per-thread debug
registers, and watchpoints which only affect a single thread, it
should set the per-thread debug registers for all threads to the same
value. On @sc{gnu}/Linux native targets, this is accomplished by
using @code{ALL_LWPS} in @code{target_insert_watchpoint} and
@code{target_remove_watchpoint} and by using
@code{linux_set_new_thread} to register a handler for newly created
threads.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2007-09-22 15:37 ` Daniel Jacobowitz
@ 2007-09-22 15:46 ` Eli Zaretskii
2007-09-22 18:28 ` Daniel Jacobowitz
0 siblings, 1 reply; 27+ messages in thread
From: Eli Zaretskii @ 2007-09-22 15:46 UTC (permalink / raw)
To: Daniel Jacobowitz; +Cc: gdb-patches
> Date: Sat, 22 Sep 2007 11:37:09 -0400
> From: Daniel Jacobowitz <drow@false.org>
> Cc: gdb-patches@sourceware.org
>
> On Sat, Sep 22, 2007 at 04:13:24PM +0200, Eli Zaretskii wrote:
> > > > > +@value{GDBN} only supports process-wide watchpoints.
> > > >
> > > > "Process-wide watchpoints'' as opposed to what?
> > >
> > > As opposed to thread-specific watchpoints. We can make a watchpoint
> > > act like it is thread-specific (or we will be able to once Luis's
> > > patch is done), but we don't support setting hardware watchpoints that
> > > only trigger in a specific thread. Yet, anyway.
> >
> > I think you should add something like this explanation, to make the
> > intent clear.
>
> Is this clearer?
>
> @value{GDBN} only supports process-wide watchpoints, which trigger in
> all threads. If the target supports threads, per-thread debug
> registers, and watchpoints which only affect a single thread, it
> should set the per-thread debug registers for all threads to the same
> value. On @sc{gnu}/Linux native targets, this is accomplished by
> using @code{ALL_LWPS} in @code{target_insert_watchpoint} and
> @code{target_remove_watchpoint} and by using
> @code{linux_set_new_thread} to register a handler for newly created
> threads.
A bit clearer, but not yet where I'd be happy. The following version
expands the description a little, using your mail explanations almost
intact:
@value{GDBN} only supports process-wide watchpoints, which trigger
in all threads. @value{GDBN} uses the thread ID to make watchpoints
act as if they were thread-specific, but it cannot set hardware
watchpoints that only trigger in a specific thread. Therefore, even
if the target supports threads, per-thread debug registers, and
watchpoints which only affect a single thread, it should set the
per-thread debug registers for all threads to the same value. On
@sc{gnu}/Linux native targets, this is accomplished by using
@code{ALL_LWPS} in @code{target_insert_watchpoint} and
@code{target_remove_watchpoint} and by using
@code{linux_set_new_thread} to register a handler for newly created
threads.
WDYT?
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2007-09-22 15:46 ` Eli Zaretskii
@ 2007-09-22 18:28 ` Daniel Jacobowitz
0 siblings, 0 replies; 27+ messages in thread
From: Daniel Jacobowitz @ 2007-09-22 18:28 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
On Sat, Sep 22, 2007 at 05:46:34PM +0200, Eli Zaretskii wrote:
> A bit clearer, but not yet where I'd be happy. The following version
> expands the description a little, using your mail explanations almost
> intact:
Thanks - let's use yours.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2007-09-16 18:40 [rfc, rfa/doc] Multi-threaded watchpoint improvements Daniel Jacobowitz
2007-09-22 9:03 ` Eli Zaretskii
@ 2007-10-01 0:20 ` Daniel Jacobowitz
2007-10-24 14:59 ` Luis Machado
2008-04-16 22:57 ` Andreas Schwab
1 sibling, 2 replies; 27+ messages in thread
From: Daniel Jacobowitz @ 2007-10-01 0:20 UTC (permalink / raw)
To: gdb-patches
On Sun, Sep 16, 2007 at 02:39:49PM -0400, Daniel Jacobowitz wrote:
> I have (finally, sorry for the delay) finished revamping the
> multi-threaded watchpoint patches Jeff submitted ages ago and Luis
> resubmitted recently. This message contains all the changes except
> for various native GNU/Linux target files. It includes manual and
> gdbint changes describing what I've figured out to date.
Here's the version I've checked in. There was a merge conflict in
breakpoint.c, at the end of bpstat_stop_status. I think the code I'm
removing is wrong - b->type refers back to the breakpoint b inside the
loop, not necessarily the one in the bpstat.
--
Daniel Jacobowitz
CodeSourcery
2007-09-30 Daniel Jacobowitz <dan@codesourcery.com>
Jeff Johnston <jjohnstn@redhat.com>
* breakpoint.c (watchpoints_triggered): New.
(bpstat_stop_status): Remove STOPPED_BY_WATCHPOINT argument.
Check watchpoint_triggered instead. Combine handling for software
and hardware watchpoints. Do not use target_stopped_data_address
here. Always check a watchpoint if its scope breakpoint triggers.
Do not stop for thread or overlay events. Improve check for
triggered watchpoints without a value change.
(watch_command_1): Insert the scope breakpoint first. Link the
scope breakpoint to the watchpoint.
* breakpoint.h (enum watchpoint_triggered): New.
(struct breakpoint): Add watchpoint_triggered.
(bpstat_stop_status): Update prototype.
(watchpoints_triggered): Declare.
* infrun.c (enum infwait_status): Add infwait_step_watch_state.
(stepped_after_stopped_by_watchpoint): Delete.
(handle_inferior_event): Make stepped_after_stopped_by_watchpoint
local. Handle infwait_step_watch_state. Update calls to
bpstat_stop_status. Use watchpoints_triggered to check
watchpoints.
* remote.c (stepped_after_stopped_by_watchpoint): Remove extern.
(remote_stopped_data_address): Do not check it.
2007-09-30 Daniel Jacobowitz <dan@codesourcery.com>
* gdb.texinfo (Setting Watchpoints): Adjust warning text about
multi-threaded watchpoints.
* gdbint.texinfo (Watchpoints): Describe how watchpoints are
checked. Describe sticky notification. Expand description
of steppable and continuable watchpoints.
(Watchpoints and Threads): New subsection.
2007-09-30 Daniel Jacobowitz <dan@codesourcery.com>
* gdb.threads/watchthreads.c (thread_function): Sleep between
iterations.
* gdb.threads/watchthreads.exp: Allow two watchpoints to trigger
at once for S/390. Generate matching fails and passes.
Index: breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.270
diff -u -p -r1.270 breakpoint.c
--- breakpoint.c 26 Sep 2007 18:44:55 -0000 1.270
+++ breakpoint.c 1 Oct 2007 00:11:08 -0000
@@ -2537,6 +2537,83 @@ bpstat_alloc (struct bp_location *bl, bp
return bs;
}
\f
+/* The target has stopped with waitstatus WS. Check if any hardware
+ watchpoints have triggered, according to the target. */
+
+int
+watchpoints_triggered (struct target_waitstatus *ws)
+{
+ int stopped_by_watchpoint = STOPPED_BY_WATCHPOINT (*ws);
+ CORE_ADDR addr;
+ struct breakpoint *b;
+
+ if (!stopped_by_watchpoint)
+ {
+ /* We were not stopped by a watchpoint. Mark all watchpoints
+ as not triggered. */
+ ALL_BREAKPOINTS (b)
+ if (b->type == bp_hardware_watchpoint
+ || b->type == bp_read_watchpoint
+ || b->type == bp_access_watchpoint)
+ b->watchpoint_triggered = watch_triggered_no;
+
+ return 0;
+ }
+
+ if (!target_stopped_data_address (¤t_target, &addr))
+ {
+ /* We were stopped by a watchpoint, but we don't know where.
+ Mark all watchpoints as unknown. */
+ ALL_BREAKPOINTS (b)
+ if (b->type == bp_hardware_watchpoint
+ || b->type == bp_read_watchpoint
+ || b->type == bp_access_watchpoint)
+ b->watchpoint_triggered = watch_triggered_unknown;
+
+ return stopped_by_watchpoint;
+ }
+
+ /* The target could report the data address. Mark watchpoints
+ affected by this data address as triggered, and all others as not
+ triggered. */
+
+ ALL_BREAKPOINTS (b)
+ if (b->type == bp_hardware_watchpoint
+ || b->type == bp_read_watchpoint
+ || b->type == bp_access_watchpoint)
+ {
+ struct value *v;
+
+ b->watchpoint_triggered = watch_triggered_no;
+ for (v = b->val_chain; v; v = value_next (v))
+ {
+ if (VALUE_LVAL (v) == lval_memory && ! value_lazy (v))
+ {
+ struct type *vtype = check_typedef (value_type (v));
+
+ if (v == b->val_chain
+ || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
+ && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
+ {
+ CORE_ADDR vaddr;
+
+ vaddr = VALUE_ADDRESS (v) + value_offset (v);
+ /* Exact match not required. Within range is
+ sufficient. */
+ if (addr >= vaddr
+ && addr < vaddr + TYPE_LENGTH (value_type (v)))
+ {
+ b->watchpoint_triggered = watch_triggered_yes;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return 1;
+}
+
/* Possible return values for watchpoint_check (this can't be an enum
because of check_errors). */
/* The watchpoint has been deleted. */
@@ -2655,11 +2732,9 @@ which its expression is valid.\n");
}
/* Get a bpstat associated with having just stopped at address
- BP_ADDR in thread PTID. STOPPED_BY_WATCHPOINT is 1 if the
- target thinks we stopped due to a hardware watchpoint, 0 if we
- know we did not trigger a hardware watchpoint, and -1 if we do not know. */
+ BP_ADDR in thread PTID.
-/* Determine whether we stopped at a breakpoint, etc, or whether we
+ Determine whether we stopped at a breakpoint, etc, or whether we
don't understand this stop. Result is a chain of bpstat's such that:
if we don't understand the stop, the result is a null pointer.
@@ -2674,7 +2749,7 @@ which its expression is valid.\n");
commands, FIXME??? fields. */
bpstat
-bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid, int stopped_by_watchpoint)
+bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid)
{
struct breakpoint *b = NULL;
struct bp_location *bl;
@@ -2712,16 +2787,17 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
continue;
}
- /* Continuable hardware watchpoints are treated as non-existent if the
- reason we stopped wasn't a hardware watchpoint (we didn't stop on
- some data address). Otherwise gdb won't stop on a break instruction
- in the code (not from a breakpoint) when a hardware watchpoint has
- been defined. */
+ /* Continuable hardware watchpoints are treated as non-existent if the
+ reason we stopped wasn't a hardware watchpoint (we didn't stop on
+ some data address). Otherwise gdb won't stop on a break instruction
+ in the code (not from a breakpoint) when a hardware watchpoint has
+ been defined. Also skip watchpoints which we know did not trigger
+ (did not match the data address). */
if ((b->type == bp_hardware_watchpoint
|| b->type == bp_read_watchpoint
|| b->type == bp_access_watchpoint)
- && !stopped_by_watchpoint)
+ && b->watchpoint_triggered == watch_triggered_no)
continue;
if (b->type == bp_hardware_breakpoint)
@@ -2787,82 +2863,33 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
bs->stop = 1;
bs->print = 1;
- if (b->type == bp_watchpoint ||
- b->type == bp_hardware_watchpoint)
- {
- char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n",
- b->number);
- struct cleanup *cleanups = make_cleanup (xfree, message);
- int e = catch_errors (watchpoint_check, bs, message,
- RETURN_MASK_ALL);
- do_cleanups (cleanups);
- switch (e)
- {
- case WP_DELETED:
- /* We've already printed what needs to be printed. */
- /* Actually this is superfluous, because by the time we
- call print_it_typical() the wp will be already deleted,
- and the function will return immediately. */
- bs->print_it = print_it_done;
- /* Stop. */
- break;
- case WP_VALUE_CHANGED:
- /* Stop. */
- ++(b->hit_count);
- break;
- case WP_VALUE_NOT_CHANGED:
- /* Don't stop. */
- bs->print_it = print_it_noop;
- bs->stop = 0;
- continue;
- default:
- /* Can't happen. */
- /* FALLTHROUGH */
- case 0:
- /* Error from catch_errors. */
- printf_filtered (_("Watchpoint %d deleted.\n"), b->number);
- if (b->related_breakpoint)
- b->related_breakpoint->disposition = disp_del_at_next_stop;
- b->disposition = disp_del_at_next_stop;
- /* We've already printed what needs to be printed. */
- bs->print_it = print_it_done;
-
- /* Stop. */
- break;
- }
- }
- else if (b->type == bp_read_watchpoint ||
- b->type == bp_access_watchpoint)
+ if (b->type == bp_watchpoint
+ || b->type == bp_read_watchpoint
+ || b->type == bp_access_watchpoint
+ || b->type == bp_hardware_watchpoint)
{
CORE_ADDR addr;
struct value *v;
- int found = 0;
+ int must_check_value = 0;
- if (!target_stopped_data_address (¤t_target, &addr))
- continue;
- for (v = b->val_chain; v; v = value_next (v))
- {
- if (VALUE_LVAL (v) == lval_memory
- && ! value_lazy (v))
- {
- struct type *vtype = check_typedef (value_type (v));
-
- if (v == b->val_chain
- || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
- && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
- {
- CORE_ADDR vaddr;
+ if (b->type == bp_watchpoint)
+ /* For a software watchpoint, we must always check the
+ watched value. */
+ must_check_value = 1;
+ else if (b->watchpoint_triggered == watch_triggered_yes)
+ /* We have a hardware watchpoint (read, write, or access)
+ and the target earlier reported an address watched by
+ this watchpoint. */
+ must_check_value = 1;
+ else if (b->watchpoint_triggered == watch_triggered_unknown
+ && b->type == bp_hardware_watchpoint)
+ /* We were stopped by a hardware watchpoint, but the target could
+ not report the data address. We must check the watchpoint's
+ value. Access and read watchpoints are out of luck; without
+ a data address, we can't figure it out. */
+ must_check_value = 1;
- vaddr = VALUE_ADDRESS (v) + value_offset (v);
- /* Exact match not required. Within range is
- sufficient. */
- if (addr >= vaddr &&
- addr < vaddr + TYPE_LENGTH (value_type (v)))
- found = 1;
- }
- }
- }
- if (found)
+ if (must_check_value)
{
char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n",
b->number);
@@ -2890,6 +2917,15 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
++(b->hit_count);
break;
case WP_VALUE_NOT_CHANGED:
+ if (b->type == bp_hardware_watchpoint
+ || b->type == bp_watchpoint)
+ {
+ /* Don't stop: write watchpoints shouldn't fire if
+ the value hasn't changed. */
+ bs->print_it = print_it_noop;
+ bs->stop = 0;
+ continue;
+ }
/* Stop. */
++(b->hit_count);
break;
@@ -2906,12 +2942,12 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
break;
}
}
- else /* found == 0 */
+ else /* must_check_value == 0 */
{
- /* This is a case where some watchpoint(s) triggered,
- but not at the address of this watchpoint (FOUND
- was left zero). So don't print anything for this
- watchpoint. */
+ /* This is a case where some watchpoint(s) triggered, but
+ not at the address of this watchpoint, or else no
+ watchpoint triggered after all. So don't print
+ anything for this watchpoint. */
bs->print_it = print_it_noop;
bs->stop = 0;
continue;
@@ -2933,6 +2969,13 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
{
int value_is_zero = 0;
+ /* If this is a scope breakpoint, mark the associated
+ watchpoint as triggered so that we will handle the
+ out-of-scope event. We'll get to the watchpoint next
+ iteration. */
+ if (b->type == bp_watchpoint_scope)
+ b->related_breakpoint->watchpoint_triggered = watch_triggered_yes;
+
if (bl->cond)
{
/* Need to select the frame, with all that implies
@@ -2963,6 +3006,9 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
annotate_ignore_count_change ();
bs->stop = 0;
}
+ else if (b->type == bp_thread_event || b->type == bp_overlay_event)
+ /* We do not stop for these. */
+ bs->stop = 0;
else
{
/* We will stop here */
@@ -2989,17 +3035,27 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
bs->next = NULL; /* Terminate the chain */
bs = root_bs->next; /* Re-grab the head of the chain */
- /* The value of a hardware watchpoint hasn't changed, but the
- intermediate memory locations we are watching may have. */
- if (bs && !bs->stop &&
- (b->type == bp_hardware_watchpoint ||
- b->type == bp_read_watchpoint ||
- b->type == bp_access_watchpoint))
- {
- remove_breakpoints ();
- insert_breakpoints ();
- }
- return bs;
+ /* If we aren't stopping, the value of some hardware watchpoint may
+ not have changed, but the intermediate memory locations we are
+ watching may have. Don't bother if we're stopping; this will get
+ done later. */
+ for (bs = root_bs->next; bs != NULL; bs = bs->next)
+ if (bs->stop)
+ break;
+
+ if (bs == NULL)
+ for (bs = root_bs->next; bs != NULL; bs = bs->next)
+ if (!bs->stop
+ && (bs->breakpoint_at->owner->type == bp_hardware_watchpoint
+ || bs->breakpoint_at->owner->type == bp_read_watchpoint
+ || bs->breakpoint_at->owner->type == bp_access_watchpoint))
+ {
+ remove_breakpoints ();
+ insert_breakpoints ();
+ break;
+ }
+
+ return root_bs->next;
}
\f
/* Tell what to do about this bpstat. */
@@ -5965,7 +6021,7 @@ stopat_command (char *arg, int from_tty)
static void
watch_command_1 (char *arg, int accessflag, int from_tty)
{
- struct breakpoint *b;
+ struct breakpoint *b, *scope_breakpoint = NULL;
struct symtab_and_line sal;
struct expression *exp;
struct block *exp_valid_block;
@@ -6043,6 +6099,37 @@ watch_command_1 (char *arg, int accessfl
if (!mem_cnt || target_resources_ok <= 0)
bp_type = bp_watchpoint;
+ frame = block_innermost_frame (exp_valid_block);
+ if (frame)
+ prev_frame = get_prev_frame (frame);
+ else
+ prev_frame = NULL;
+
+ /* 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. Create the scope breakpoint before the watchpoint, so
+ that we will encounter it first in bpstat_stop_status. */
+ if (innermost_block && prev_frame)
+ {
+ scope_breakpoint = create_internal_breakpoint (get_frame_pc (prev_frame),
+ bp_watchpoint_scope);
+
+ scope_breakpoint->enable_state = bp_enabled;
+
+ /* Automatically delete the breakpoint when it hits. */
+ scope_breakpoint->disposition = disp_del;
+
+ /* Only break in the proper frame (help with recursion). */
+ scope_breakpoint->frame_id = get_frame_id (prev_frame);
+
+ /* Set the address at which we will stop. */
+ scope_breakpoint->loc->requested_address
+ = get_frame_pc (prev_frame);
+ scope_breakpoint->loc->address
+ = adjust_breakpoint_address (scope_breakpoint->loc->requested_address,
+ scope_breakpoint->type);
+ }
+
/* Now set up the breakpoint. */
b = set_raw_breakpoint (sal, bp_type);
set_breakpoint_count (breakpoint_count + 1);
@@ -6058,48 +6145,19 @@ watch_command_1 (char *arg, int accessfl
else
b->cond_string = 0;
- frame = block_innermost_frame (exp_valid_block);
if (frame)
- {
- prev_frame = get_prev_frame (frame);
- b->watchpoint_frame = get_frame_id (frame);
- }
+ b->watchpoint_frame = get_frame_id (frame);
else
- {
- memset (&b->watchpoint_frame, 0, sizeof (b->watchpoint_frame));
- }
+ memset (&b->watchpoint_frame, 0, sizeof (b->watchpoint_frame));
- /* 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)
+ if (scope_breakpoint != NULL)
{
- if (prev_frame)
- {
- struct breakpoint *scope_breakpoint;
- scope_breakpoint = create_internal_breakpoint (get_frame_pc (prev_frame),
- bp_watchpoint_scope);
-
- scope_breakpoint->enable_state = bp_enabled;
-
- /* Automatically delete the breakpoint when it hits. */
- scope_breakpoint->disposition = disp_del;
-
- /* Only break in the proper frame (help with recursion). */
- scope_breakpoint->frame_id = get_frame_id (prev_frame);
-
- /* Set the address at which we will stop. */
- scope_breakpoint->loc->requested_address
- = get_frame_pc (prev_frame);
- scope_breakpoint->loc->address
- = adjust_breakpoint_address (scope_breakpoint->loc->requested_address,
- scope_breakpoint->type);
-
- /* The scope breakpoint is related to the watchpoint. We
- will need to act on them together. */
- b->related_breakpoint = scope_breakpoint;
- }
+ /* The scope breakpoint is related to the watchpoint. We will
+ need to act on them together. */
+ b->related_breakpoint = scope_breakpoint;
+ scope_breakpoint->related_breakpoint = b;
}
+
value_free_to_mark (mark);
mention (b);
}
Index: breakpoint.h
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.h,v
retrieving revision 1.51
diff -u -p -r1.51 breakpoint.h
--- breakpoint.h 23 Sep 2007 07:56:22 -0000 1.51
+++ breakpoint.h 1 Oct 2007 00:11:08 -0000
@@ -318,6 +318,19 @@ struct breakpoint_ops
void (*print_mention) (struct breakpoint *);
};
+enum watchpoint_triggered
+{
+ /* This watchpoint definitely did not trigger. */
+ watch_triggered_no = 0,
+
+ /* Some hardware watchpoint triggered, and it might have been this
+ one, but we do not know which it was. */
+ watch_triggered_unknown,
+
+ /* This hardware watchpoint definitely did trigger. */
+ watch_triggered_yes
+};
+
/* Note that the ->silent field is not currently used by any commands
(though the code is in there if it was to be, and set_raw_breakpoint
does set it to 0). I implemented it because I thought it would be
@@ -395,6 +408,10 @@ struct breakpoint
should be evaluated on the outermost frame. */
struct frame_id watchpoint_frame;
+ /* For hardware watchpoints, the triggered status according to the
+ hardware. */
+ enum watchpoint_triggered watchpoint_triggered;
+
/* Thread number for thread-specific breakpoint, or -1 if don't care */
int thread;
@@ -459,8 +476,7 @@ extern void bpstat_clear (bpstat *);
is part of the bpstat is copied as well. */
extern bpstat bpstat_copy (bpstat);
-extern bpstat bpstat_stop_status (CORE_ADDR pc, ptid_t ptid,
- int stopped_by_watchpoint);
+extern bpstat bpstat_stop_status (CORE_ADDR pc, ptid_t ptid);
\f
/* This bpstat_what stuff tells wait_for_inferior what to do with a
breakpoint (a challenging task). */
@@ -853,4 +869,8 @@ extern void remove_single_step_breakpoin
extern void *deprecated_insert_raw_breakpoint (CORE_ADDR);
extern int deprecated_remove_raw_breakpoint (void *);
+/* Check if any hardware watchpoints have triggered, according to the
+ target. */
+int watchpoints_triggered (struct target_waitstatus *);
+
#endif /* !defined (BREAKPOINT_H) */
Index: infrun.c
===================================================================
RCS file: /cvs/src/src/gdb/infrun.c,v
retrieving revision 1.248
diff -u -p -r1.248 infrun.c
--- infrun.c 22 Sep 2007 19:33:31 -0000 1.248
+++ infrun.c 1 Oct 2007 00:11:09 -0000
@@ -881,6 +881,7 @@ enum infwait_states
{
infwait_normal_state,
infwait_thread_hop_state,
+ infwait_step_watch_state,
infwait_nonstep_watch_state
};
@@ -1220,17 +1221,12 @@ adjust_pc_after_break (struct execution_
by an event from the inferior, figure out what it means and take
appropriate action. */
-int stepped_after_stopped_by_watchpoint;
-
void
handle_inferior_event (struct execution_control_state *ecs)
{
- /* NOTE: bje/2005-05-02: If you're looking at this code and thinking
- that the variable stepped_after_stopped_by_watchpoint isn't used,
- then you're wrong! See remote.c:remote_stopped_data_address. */
-
int sw_single_step_trap_p = 0;
- int stopped_by_watchpoint = -1; /* Mark as unknown. */
+ int stopped_by_watchpoint;
+ int stepped_after_stopped_by_watchpoint = 0;
/* Cache the last pid/waitstatus. */
target_last_wait_ptid = ecs->ptid;
@@ -1250,7 +1246,14 @@ handle_inferior_event (struct execution_
case infwait_normal_state:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: infwait_normal_state\n");
- stepped_after_stopped_by_watchpoint = 0;
+ break;
+
+ case infwait_step_watch_state:
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: infwait_step_watch_state\n");
+
+ stepped_after_stopped_by_watchpoint = 1;
break;
case infwait_nonstep_watch_state:
@@ -1435,7 +1438,7 @@ handle_inferior_event (struct execution_
stop_pc = read_pc ();
- stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid, 0);
+ stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
@@ -1483,7 +1486,7 @@ handle_inferior_event (struct execution_
ecs->saved_inferior_ptid = inferior_ptid;
inferior_ptid = ecs->ptid;
- stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid, 0);
+ stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
inferior_ptid = ecs->saved_inferior_ptid;
@@ -1796,24 +1799,20 @@ handle_inferior_event (struct execution_
singlestep_breakpoints_inserted_p = 0;
}
- /* 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 (HAVE_STEPPABLE_WATCHPOINT && STOPPED_BY_WATCHPOINT (ecs->ws))
+ if (stepped_after_stopped_by_watchpoint)
+ stopped_by_watchpoint = 0;
+ else
+ stopped_by_watchpoint = watchpoints_triggered (&ecs->ws);
+
+ /* If necessary, step over this watchpoint. We'll be back to display
+ it in a moment. */
+ if (stopped_by_watchpoint
+ && (HAVE_STEPPABLE_WATCHPOINT
+ || gdbarch_have_nonsteppable_watchpoint (current_gdbarch)))
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n");
- resume (1, 0);
- prepare_to_wait (ecs);
- return;
- }
- /* 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 (gdbarch_have_nonsteppable_watchpoint (current_gdbarch)
- && STOPPED_BY_WATCHPOINT (ecs->ws))
- {
/* At this point, we are stopped at an instruction which has
attempted to write to a piece of memory under control of
a watchpoint. The instruction hasn't actually executed
@@ -1823,31 +1822,31 @@ handle_inferior_event (struct execution_
In order to make watchpoints work `right', we really need
to complete the memory write, and then evaluate the
- watchpoint expression. The following code does that by
- removing the watchpoint (actually, all watchpoints and
- breakpoints), single-stepping the target, re-inserting
- watchpoints, and then falling through to let normal
- single-step processing handle proceed. Since this
- includes evaluating watchpoints, things will come to a
- stop in the correct manner. */
+ watchpoint expression. We do this by single-stepping the
+ target.
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n");
- remove_breakpoints ();
+ 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.
+
+ It is far more common to need to disable a watchpoint to step
+ the inferior over it. If we have non-steppable watchpoints,
+ we must disable the current watchpoint; it's simplest to
+ disable all watchpoints and breakpoints. */
+
+ if (!HAVE_STEPPABLE_WATCHPOINT)
+ remove_breakpoints ();
registers_changed ();
target_resume (ecs->ptid, 1, TARGET_SIGNAL_0); /* Single step */
-
ecs->waiton_ptid = ecs->ptid;
- ecs->wp = &(ecs->ws);
- ecs->infwait_state = infwait_nonstep_watch_state;
+ if (HAVE_STEPPABLE_WATCHPOINT)
+ ecs->infwait_state = infwait_step_watch_state;
+ else
+ ecs->infwait_state = infwait_nonstep_watch_state;
prepare_to_wait (ecs);
return;
}
- /* It may be possible to simply continue after a watchpoint. */
- if (HAVE_CONTINUABLE_WATCHPOINT)
- stopped_by_watchpoint = STOPPED_BY_WATCHPOINT (ecs->ws);
-
ecs->stop_func_start = 0;
ecs->stop_func_end = 0;
ecs->stop_func_name = 0;
@@ -1969,8 +1968,7 @@ handle_inferior_event (struct execution_
else
{
/* See if there is a breakpoint at the current PC. */
- stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid,
- stopped_by_watchpoint);
+ stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
/* Following in case break condition called a
function. */
Index: remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.268
diff -u -p -r1.268 remote.c
--- remote.c 26 Sep 2007 18:32:54 -0000 1.268
+++ remote.c 1 Oct 2007 00:11:09 -0000
@@ -5406,14 +5406,11 @@ remote_stopped_by_watchpoint (void)
return remote_stopped_by_watchpoint_p;
}
-extern int stepped_after_stopped_by_watchpoint;
-
static int
remote_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
{
int rc = 0;
- if (remote_stopped_by_watchpoint ()
- || stepped_after_stopped_by_watchpoint)
+ if (remote_stopped_by_watchpoint ())
{
*addr_p = remote_watch_data_address;
rc = 1;
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.434
diff -u -p -r1.434 gdb.texinfo
--- doc/gdb.texinfo 28 Sep 2007 11:09:55 -0000 1.434
+++ doc/gdb.texinfo 1 Oct 2007 00:11:12 -0000
@@ -3346,20 +3346,13 @@ rerun the program, you will need to set
way of doing that would be to set a code breakpoint at the entry to the
@code{main} function and when it breaks, set all the watchpoints.
-@quotation
@cindex watchpoints and threads
@cindex threads and watchpoints
-@emph{Warning:} In multi-thread programs, watchpoints have only limited
-usefulness. With the current watchpoint implementation, @value{GDBN}
-can only watch the value of an expression @emph{in a single thread}. If
-you are confident that the expression can only change due to the current
-thread's activity (and if you are also confident that no other thread
-can become current), then you can use watchpoints as usual. However,
-@value{GDBN} may not notice when a non-current thread's activity changes
-the expression.
+In multi-threaded programs, watchpoints will detect changes to the
+watched expression from every thread.
-@c FIXME: this is almost identical to the previous paragraph.
-@emph{HP-UX Warning:} In multi-thread programs, software watchpoints
+@quotation
+@emph{Warning:} In multi-threaded programs, software watchpoints
have only limited usefulness. If @value{GDBN} creates a software
watchpoint, it can only watch the value of an expression @emph{in a
single thread}. If you are confident that the expression can only
Index: doc/gdbint.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdbint.texinfo,v
retrieving revision 1.266
diff -u -p -r1.266 gdbint.texinfo
--- doc/gdbint.texinfo 5 Jul 2007 12:22:32 -0000 1.266
+++ doc/gdbint.texinfo 1 Oct 2007 00:11:12 -0000
@@ -660,15 +660,26 @@ section is mostly irrelevant for softwar
When the inferior stops, @value{GDBN} tries to establish, among other
possible reasons, whether it stopped due to a watchpoint being hit.
-For a data-write watchpoint, it does so by evaluating, for each
-watchpoint, the expression whose value is being watched, and testing
-whether the watched value has changed. For data-read and data-access
-watchpoints, @value{GDBN} needs the target to supply a primitive that
-returns the address of the data that was accessed or read (see the
-description of @code{target_stopped_data_address} below): if this
-primitive returns a valid address, @value{GDBN} infers that a
-watchpoint triggered if it watches an expression whose evaluation uses
-that address.
+It first uses @code{STOPPED_BY_WATCHPOINT} to see if any watchpoint
+was hit. If not, all watchpoint checking is skipped.
+
+Then @value{GDBN} calls @code{target_stopped_data_address} exactly
+once. This method returns the address of the watchpoint which
+triggered, if the target can determine it. If the triggered address
+is available, @value{GDBN} compares the address returned by this
+method with each watched memory address in each active watchpoint.
+For data-read and data-access watchpoints, @value{GDBN} announces
+every watchpoint that watches the triggered address as being hit.
+For this reason, data-read and data-access watchpoints
+@emph{require} that the triggered address be available; if not, read
+and access watchpoints will never be considered hit. For data-write
+watchpoints, if the triggered address is available, @value{GDBN}
+considers only those watchpoints which match that address;
+otherwise, @value{GDBN} considers all data-write watchpoints. For
+each data-write watchpoint that @value{GDBN} considers, it evaluates
+the expression whose value is being watched, and tests whether the
+watched value has changed. Watchpoints whose watched values have
+changed are announced as hit.
@value{GDBN} uses several macros and primitives to support hardware
watchpoints:
@@ -721,26 +732,40 @@ These two macros should return 0 for suc
@item target_stopped_data_address (@var{addr_p})
If the inferior has some watchpoint that triggered, place the address
associated with the watchpoint at the location pointed to by
-@var{addr_p} and return non-zero. Otherwise, return zero. Note that
-this primitive is used by @value{GDBN} only on targets that support
-data-read or data-access type watchpoints, so targets that have
-support only for data-write watchpoints need not implement these
-primitives.
+@var{addr_p} and return non-zero. Otherwise, return zero. This
+is required for data-read and data-access watchpoints. It is
+not required for data-write watchpoints, but @value{GDBN} uses
+it to improve handling of those also.
+
+@value{GDBN} will only call this method once per watchpoint stop,
+immediately after calling @code{STOPPED_BY_WATCHPOINT}. If the
+target's watchpoint indication is sticky, i.e., stays set after
+resuming, this method should clear it. For instance, the x86 debug
+control register has sticky triggered flags.
@findex HAVE_STEPPABLE_WATCHPOINT
@item HAVE_STEPPABLE_WATCHPOINT
If defined to a non-zero value, it is not necessary to disable a
-watchpoint to step over it.
+watchpoint to step over it. Like @code{gdbarch_have_nonsteppable_watchpoint},
+this is usually set when watchpoints trigger at the instruction
+which will perform an interesting read or write. It should be
+set if there is a temporary disable bit which allows the processor
+to step over the interesting instruction without raising the
+watchpoint exception again.
@findex gdbarch_have_nonsteppable_watchpoint
@item int gdbarch_have_nonsteppable_watchpoint (@var{gdbarch})
If it returns a non-zero value, @value{GDBN} should disable a
-watchpoint to step the inferior over it.
+watchpoint to step the inferior over it. This is usually set when
+watchpoints trigger at the instruction which will perform an
+interesting read or write.
@findex HAVE_CONTINUABLE_WATCHPOINT
@item HAVE_CONTINUABLE_WATCHPOINT
If defined to a non-zero value, it is possible to continue the
-inferior after a watchpoint has been hit.
+inferior after a watchpoint has been hit. This is usually set
+when watchpoints trigger at the instruction following an interesting
+read or write.
@findex CANNOT_STEP_HW_WATCHPOINTS
@item CANNOT_STEP_HW_WATCHPOINTS
@@ -763,6 +788,32 @@ determine for sure whether the inferior
it could return non-zero ``just in case''.
@end table
+@subsection Watchpoints and Threads
+@cindex watchpoints, with threads
+
+@value{GDBN} only supports process-wide watchpoints, which trigger
+in all threads. @value{GDBN} uses the thread ID to make watchpoints
+act as if they were thread-specific, but it cannot set hardware
+watchpoints that only trigger in a specific thread. Therefore, even
+if the target supports threads, per-thread debug registers, and
+watchpoints which only affect a single thread, it should set the
+per-thread debug registers for all threads to the same value. On
+@sc{gnu}/Linux native targets, this is accomplished by using
+@code{ALL_LWPS} in @code{target_insert_watchpoint} and
+@code{target_remove_watchpoint} and by using
+@code{linux_set_new_thread} to register a handler for newly created
+threads.
+
+@value{GDBN}'s @sc{gnu}/Linux support only reports a single event
+at a time, although multiple events can trigger simultaneously for
+multi-threaded programs. When multiple events occur, @file{linux-nat.c}
+queues subsequent events and returns them the next time the program
+is resumed. This means that @code{STOPPED_BY_WATCHPOINT} and
+@code{target_stopped_data_address} only need to consult the current
+thread's state---the thread indicated by @code{inferior_ptid}. If
+two threads have hit watchpoints simultaneously, those routines
+will be called a second time for the second thread.
+
@subsection x86 Watchpoints
@cindex x86 debug registers
@cindex watchpoints, on x86
Index: testsuite/gdb.threads/watchthreads.c
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.threads/watchthreads.c,v
retrieving revision 1.3
diff -u -p -r1.3 watchthreads.c
--- testsuite/gdb.threads/watchthreads.c 23 Aug 2007 18:08:50 -0000 1.3
+++ testsuite/gdb.threads/watchthreads.c 1 Oct 2007 00:11:12 -0000
@@ -56,7 +56,7 @@ void *thread_function(void *arg) {
/* Don't run forever. Run just short of it :) */
while (*myp > 0)
{
- (*myp) ++; /* Loop increment. */
+ (*myp) ++; usleep (1); /* Loop increment. */
}
pthread_exit(NULL);
Index: testsuite/gdb.threads/watchthreads.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.threads/watchthreads.exp,v
retrieving revision 1.4
diff -u -p -r1.4 watchthreads.exp
--- testsuite/gdb.threads/watchthreads.exp 23 Aug 2007 18:14:19 -0000 1.4
+++ testsuite/gdb.threads/watchthreads.exp 1 Oct 2007 00:11:12 -0000
@@ -30,6 +30,10 @@ if [target_info exists gdb,no_hardware_w
return 0;
}
+proc target_no_stopped_data { } {
+ return [istarget s390*-*-*]
+}
+
set testfile "watchthreads"
set srcfile ${testfile}.c
set binfile ${objdir}/${subdir}/${testfile}
@@ -61,20 +65,58 @@ gdb_test "watch args\[1\]" "Hardware wat
set init_line [expr [gdb_get_line_number "Init value"]+1]
set inc_line [gdb_get_line_number "Loop increment"]
+set main_loc "main \\\(\\\) at .*watchthreads.c:$init_line"
+set thread0_loc "thread_function \\\(arg=0x0\\\) at .*watchthreads.c:$inc_line"
+set thread1_loc "thread_function \\\(arg=0x1\\\) at .*watchthreads.c:$inc_line"
# Loop and continue to allow both watchpoints to be triggered.
for {set i 0} {$i < 30} {incr i} {
+ set test_flag_0 0
+ set test_flag_1 0
set test_flag 0
gdb_test_multiple "continue" "threaded watch loop" {
- -re "Hardware watchpoint 2: args\\\[0\\\].*Old value = 0.*New value = 1.*main \\\(\\\) at .*watchthreads.c:$init_line.*$gdb_prompt $"
- { set args_0 1; set test_flag 1 }
- -re "Hardware watchpoint 3: args\\\[1\\\].*Old value = 0.*New value = 1.*main \\\(\\\) at .*watchthreads.c:$init_line.*$gdb_prompt $"
- { set args_1 1; set test_flag 1 }
- -re "Hardware watchpoint 2: args\\\[0\\\].*Old value = $args_0.*New value = [expr $args_0+1].*in thread_function \\\(arg=0x0\\\) at .*watchthreads.c:$inc_line.*$gdb_prompt $"
- { set args_0 [expr $args_0+1]; set test_flag 1 }
- -re "Hardware watchpoint 3: args\\\[1\\\].*Old value = $args_1.*New value = [expr $args_1+1].*in thread_function \\\(arg=0x1\\\) at .*watchthreads.c:$inc_line.*$gdb_prompt $"
- { set args_1 [expr $args_1+1]; set test_flag 1 }
+ -re "(.*Hardware watchpoint.*)$gdb_prompt $" {
+ # At least one hardware watchpoint was hit. Check if both were.
+ set string $expect_out(1,string)
+
+ if [regexp "Hardware watchpoint 2: args\\\[0\\\]\[^\r\]*\r\[^\r\]*\r\[^\r\]*Old value = $args_0\[^\r\]*\r\[^\r\]*New value = [expr $args_0+1]\r" $string] {
+ incr args_0
+ incr test_flag_0
+ }
+ if [regexp "Hardware watchpoint 3: args\\\[1\\\]\[^\r\]*\r\[^\r\]*\r\[^\r\]*Old value = $args_1\[^\r\]*\r\[^\r\]*New value = [expr $args_1+1]\r" $string] {
+ incr args_1
+ incr test_flag_1
+ }
+
+ set expected_loc "bogus location"
+ if { $test_flag_0 == 1 && $test_flag_1 == 0 && $args_0 == 1 } {
+ set expected_loc $main_loc
+ } elseif { $test_flag_0 == 0 && $test_flag_1 == 1 && $args_1 == 1 } {
+ set expected_loc $main_loc
+ } elseif { $test_flag_0 == 1 && $test_flag_1 == 0 } {
+ set expected_loc $thread0_loc
+ } elseif { $test_flag_0 == 0 && $test_flag_1 == 1 } {
+ set expected_loc $thread1_loc
+ } elseif { $test_flag_0 + $test_flag_1 == 2 } {
+ # On S/390, or any other system which can not report the
+ # stopped data address, it is OK to report two watchpoints
+ # at once in this test. Make sure the reported location
+ # corresponds to at least one of the watchpoints (and not,
+ # e.g., __nptl_create_event). On other systems, we should
+ # report the two watchpoints serially.
+ if { [target_no_stopped_data] } {
+ set expected_loc "($main_loc|$thread0_loc|$thread1_loc)"
+ }
+ }
+
+ if [ regexp "$expected_loc" $string ] {
+ set test_flag 1
+ } else {
+ fail "threaded watch loop"
+ }
+ }
}
+
# If we fail above, don't bother continuing loop
if { $test_flag == 0 } {
set i 30;
@@ -120,7 +162,14 @@ if { $args_1 > 1 } {
# Verify that all watchpoint hits are accounted for.
set message "combination of threaded watchpoints = 30"
-if { [expr $args_0+$args_1] == 30 } {
+if { [target_no_stopped_data] } {
+ # See above. If we allow two watchpoints to be hit at once, we
+ # may have more than 30 hits total.
+ set result [expr $args_0 + $args_1 >= 30]
+} else {
+ set result [expr $args_0 + $args_1 == 30]
+}
+if { $result } {
pass $message
} else {
fail $message
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2007-10-01 0:20 ` Daniel Jacobowitz
@ 2007-10-24 14:59 ` Luis Machado
2007-10-24 16:00 ` Daniel Jacobowitz
2008-04-16 22:57 ` Andreas Schwab
1 sibling, 1 reply; 27+ messages in thread
From: Luis Machado @ 2007-10-24 14:59 UTC (permalink / raw)
To: Daniel Jacobowitz; +Cc: gdb-patches
Daniel,
Somehow this patch has broken ppc software/hardware watchpoints. They
won't trigger anymore, no matter what, but they're still being correctly
created though. I'm not sure exactly where the problem is, but they
trigger when i revert this patch. It might be something on infrun.c
involving stopped_by_watchpoint.
I'll keep on looking at the code. If you need further details, i can
provide it.
Regards,
On Sun, 2007-09-30 at 20:20 -0400, Daniel Jacobowitz wrote:
> On Sun, Sep 16, 2007 at 02:39:49PM -0400, Daniel Jacobowitz wrote:
> > I have (finally, sorry for the delay) finished revamping the
> > multi-threaded watchpoint patches Jeff submitted ages ago and Luis
> > resubmitted recently. This message contains all the changes except
> > for various native GNU/Linux target files. It includes manual and
> > gdbint changes describing what I've figured out to date.
>
> Here's the version I've checked in. There was a merge conflict in
> breakpoint.c, at the end of bpstat_stop_status. I think the code I'm
> removing is wrong - b->type refers back to the breakpoint b inside the
> loop, not necessarily the one in the bpstat.
>
> --
> Daniel Jacobowitz
> CodeSourcery
>
> 2007-09-30 Daniel Jacobowitz <dan@codesourcery.com>
> Jeff Johnston <jjohnstn@redhat.com>
>
> * breakpoint.c (watchpoints_triggered): New.
> (bpstat_stop_status): Remove STOPPED_BY_WATCHPOINT argument.
> Check watchpoint_triggered instead. Combine handling for software
> and hardware watchpoints. Do not use target_stopped_data_address
> here. Always check a watchpoint if its scope breakpoint triggers.
> Do not stop for thread or overlay events. Improve check for
> triggered watchpoints without a value change.
> (watch_command_1): Insert the scope breakpoint first. Link the
> scope breakpoint to the watchpoint.
> * breakpoint.h (enum watchpoint_triggered): New.
> (struct breakpoint): Add watchpoint_triggered.
> (bpstat_stop_status): Update prototype.
> (watchpoints_triggered): Declare.
> * infrun.c (enum infwait_status): Add infwait_step_watch_state.
> (stepped_after_stopped_by_watchpoint): Delete.
> (handle_inferior_event): Make stepped_after_stopped_by_watchpoint
> local. Handle infwait_step_watch_state. Update calls to
> bpstat_stop_status. Use watchpoints_triggered to check
> watchpoints.
> * remote.c (stepped_after_stopped_by_watchpoint): Remove extern.
> (remote_stopped_data_address): Do not check it.
>
> 2007-09-30 Daniel Jacobowitz <dan@codesourcery.com>
>
> * gdb.texinfo (Setting Watchpoints): Adjust warning text about
> multi-threaded watchpoints.
> * gdbint.texinfo (Watchpoints): Describe how watchpoints are
> checked. Describe sticky notification. Expand description
> of steppable and continuable watchpoints.
> (Watchpoints and Threads): New subsection.
>
> 2007-09-30 Daniel Jacobowitz <dan@codesourcery.com>
>
> * gdb.threads/watchthreads.c (thread_function): Sleep between
> iterations.
> * gdb.threads/watchthreads.exp: Allow two watchpoints to trigger
> at once for S/390. Generate matching fails and passes.
--
Luis Machado
IBM Linux Technology Center
e-mail: luisgpm@linux.vnet.ibm.com
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2007-10-24 14:59 ` Luis Machado
@ 2007-10-24 16:00 ` Daniel Jacobowitz
2007-10-24 16:42 ` Luis Machado
0 siblings, 1 reply; 27+ messages in thread
From: Daniel Jacobowitz @ 2007-10-24 16:00 UTC (permalink / raw)
To: Luis Machado; +Cc: gdb-patches
On Wed, Oct 24, 2007 at 12:56:09PM -0300, Luis Machado wrote:
> Daniel,
>
> Somehow this patch has broken ppc software/hardware watchpoints. They
> won't trigger anymore, no matter what, but they're still being correctly
> created though. I'm not sure exactly where the problem is, but they
> trigger when i revert this patch. It might be something on infrun.c
> involving stopped_by_watchpoint.
>
> I'll keep on looking at the code. If you need further details, i can
> provide it.
They'd help. I know I tested on PowerPC before checking it in, and
things still seemed OK. And it should not affect software watchpoints
at all.
I'd recommend starting with "set debug infrun 1".
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2007-10-24 16:00 ` Daniel Jacobowitz
@ 2007-10-24 16:42 ` Luis Machado
2007-10-24 16:51 ` Daniel Jacobowitz
0 siblings, 1 reply; 27+ messages in thread
From: Luis Machado @ 2007-10-24 16:42 UTC (permalink / raw)
To: Daniel Jacobowitz; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1846 bytes --]
Hi Daniel,
This is what i get while trying to use a hardware watchpoint to monitor
an int variable "i" that changes during a for statement (attached). Upon
further investigation, it seems GDB is only calling
"breakpoint_delete_event". I don't see GDB calling
"breakpoint_create_event" anywhere except in the momment i created the
watchpoint up there, so i presume that's the reason it's not triggering.
This is the event log:
(gdb) set debug event 1
(gdb) start
breakpoint_create_event (CREATED!)
Breakpoint 1 at 0x10000738: file testsuite/gdb.base/watch-thread_num.c,
line 39.
Starting program: /home/luis/src/gdb/gdb-head/git/gdb/test
[Thread debugging using libthread_db enabled]
[New Thread 0x400000257c0 (LWP 3287)]
[Switching to Thread 0x400000257c0 (LWP 3287)]
breakpoint_delete_event (DELETED!)
main () at testsuite/gdb.base/watch-thread_num.c:39
39 for (i = 0; i < NUM; i++)
(gdb) watch i
During symbol reading, incomplete CFI data; unspecified registers (e.g.,
r0) at 0x10000738.
breakpoint_create_event (CREATED!)
Hardware watchpoint 2: i
(gdb) n
41 res = pthread_create(&threads[i],
(gdb)
[New Thread 0x40000a26240 (LWP 3290)]
breakpoint_delete_event (DELETED! After this point, no more creations.)
39 for (i = 0; i < NUM; i++)
(gdb)
41 res = pthread_create(&threads[i],
(gdb)
[New Thread 0x40001226240 (LWP 3291)]
breakpoint_delete_event
39 for (i = 0; i < NUM; i++)
(gdb)
41 res = pthread_create(&threads[i],
(gdb)
[New Thread 0x40001a26240 (LWP 3292)]
breakpoint_delete_event
39 for (i = 0; i < NUM; i++)
(gdb)
Notice that after i create the watchpoint, gdb doesn't bring them back
during execution, only deletes them.
Regards
--
Luis Machado
IBM Linux Technology Center
e-mail: luisgpm@linux.vnet.ibm.com
[-- Attachment #2: ppc-watch-fail.log --]
[-- Type: text/x-log, Size: 16520 bytes --]
(gdb) watch i
During symbol reading, incomplete CFI data; unspecified registers (e.g., r0) at 0x10000738.
Hardware watchpoint 10: i
(gdb) set debug infrun 1
(gdb) n
infrun: proceed (addr=0xffffffffffffffff, signal=144, step=1)
infrun: resume (step=1, signal=0)
infrun: wait_for_inferior
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x1000073c
infrun: stepping inside range [0x10000738-0x10000744]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000740
infrun: stepping inside range [0x10000738-0x10000744]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000788
infrun: keep going
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x1000078c
infrun: stepping inside range [0x1000077c-0x10000794]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000790
infrun: stepping inside range [0x1000077c-0x10000794]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000744
infrun: stepped to a different line
infrun: stop_stepping
41 res = pthread_create(&threads[i],
(gdb)
infrun: proceed (addr=0xffffffffffffffff, signal=144, step=1)
infrun: resume (step=1, signal=0)
infrun: wait_for_inferior
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000748
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x1000074c
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000750
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000754
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000758
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x1000075c
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000760
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000764
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000768
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x1000076c
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000510
infrun: stepped into subroutine
infrun: inserting step-resume breakpoint at 0x10000770
infrun: resume (step=0, signal=0)
infrun: prepare_to_wait
[New Thread 0x40000a26240 (LWP 1646)]
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x40000066ef0
infrun: BPSTAT_WHAT_SINGLE
infrun: step-resume breakpoint is inserted
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x4000006885c
infrun: trap expected
infrun: step-resume breakpoint is inserted
infrun: resume (step=0, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000770
infrun: BPSTAT_WHAT_STEP_RESUME
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000774
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000778
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x1000077c
infrun: stepped to a different line
infrun: stop_stepping
39 for (i = 0; i < NUM; i++)
(gdb)
infrun: proceed (addr=0xffffffffffffffff, signal=144, step=1)
infrun: resume (step=1, signal=0)
infrun: wait_for_inferior
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000780
infrun: stepping inside range [0x1000077c-0x10000794]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000784
infrun: stepping inside range [0x1000077c-0x10000794]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000788
infrun: stepping inside range [0x1000077c-0x10000794]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x1000078c
infrun: stepping inside range [0x1000077c-0x10000794]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000790
infrun: stepping inside range [0x1000077c-0x10000794]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000744
infrun: stepped to a different line
infrun: stop_stepping
41 res = pthread_create(&threads[i],
(gdb)
infrun: proceed (addr=0xffffffffffffffff, signal=144, step=1)
infrun: resume (step=1, signal=0)
infrun: wait_for_inferior
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000748
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x1000074c
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000750
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000754
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000758
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x1000075c
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000760
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000764
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000768
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x1000076c
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000510
infrun: stepped into subroutine
infrun: inserting step-resume breakpoint at 0x10000770
infrun: resume (step=0, signal=0)
infrun: prepare_to_wait
[New Thread 0x40001226240 (LWP 1647)]
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x40000066ef0
infrun: BPSTAT_WHAT_SINGLE
infrun: step-resume breakpoint is inserted
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x4000006885c
infrun: trap expected
infrun: step-resume breakpoint is inserted
infrun: resume (step=0, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000770
infrun: BPSTAT_WHAT_STEP_RESUME
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000774
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000778
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x1000077c
infrun: stepped to a different line
infrun: stop_stepping
39 for (i = 0; i < NUM; i++)
(gdb)
infrun: proceed (addr=0xffffffffffffffff, signal=144, step=1)
infrun: resume (step=1, signal=0)
infrun: wait_for_inferior
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000780
infrun: stepping inside range [0x1000077c-0x10000794]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000784
infrun: stepping inside range [0x1000077c-0x10000794]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000788
infrun: stepping inside range [0x1000077c-0x10000794]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x1000078c
infrun: stepping inside range [0x1000077c-0x10000794]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000790
infrun: stepping inside range [0x1000077c-0x10000794]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000744
infrun: stepped to a different line
infrun: stop_stepping
41 res = pthread_create(&threads[i],
(gdb)
infrun: proceed (addr=0xffffffffffffffff, signal=144, step=1)
infrun: resume (step=1, signal=0)
infrun: wait_for_inferior
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000748
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x1000074c
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000750
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000754
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000758
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x1000075c
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000760
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000764
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000768
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x1000076c
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000510
infrun: stepped into subroutine
infrun: inserting step-resume breakpoint at 0x10000770
infrun: resume (step=0, signal=0)
infrun: prepare_to_wait
[New Thread 0x40001a26240 (LWP 1648)]
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x40000066ef0
infrun: BPSTAT_WHAT_SINGLE
infrun: step-resume breakpoint is inserted
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x4000006885c
infrun: trap expected
infrun: step-resume breakpoint is inserted
infrun: resume (step=0, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000770
infrun: BPSTAT_WHAT_STEP_RESUME
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000774
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000778
infrun: stepping inside range [0x10000744-0x1000077c]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x1000077c
infrun: stepped to a different line
infrun: stop_stepping
39 for (i = 0; i < NUM; i++)
(gdb)
infrun: proceed (addr=0xffffffffffffffff, signal=144, step=1)
infrun: resume (step=1, signal=0)
infrun: wait_for_inferior
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000780
infrun: stepping inside range [0x1000077c-0x10000794]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000784
infrun: stepping inside range [0x1000077c-0x10000794]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000788
infrun: stepping inside range [0x1000077c-0x10000794]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x1000078c
infrun: stepping inside range [0x1000077c-0x10000794]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000790
infrun: stepping inside range [0x1000077c-0x10000794]
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x10000744
infrun: stepped to a different line
infrun: stop_stepping
41 res = pthread_create(&threads[i],
(gdb)
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2007-10-24 16:42 ` Luis Machado
@ 2007-10-24 16:51 ` Daniel Jacobowitz
2007-10-24 18:08 ` Luis Machado
0 siblings, 1 reply; 27+ messages in thread
From: Daniel Jacobowitz @ 2007-10-24 16:51 UTC (permalink / raw)
To: Luis Machado; +Cc: gdb-patches
On Wed, Oct 24, 2007 at 02:22:00PM -0300, Luis Machado wrote:
> Hi Daniel,
>
> This is what i get while trying to use a hardware watchpoint to monitor
> an int variable "i" that changes during a for statement (attached). Upon
> further investigation, it seems GDB is only calling
> "breakpoint_delete_event". I don't see GDB calling
> "breakpoint_create_event" anywhere except in the momment i created the
> watchpoint up there, so i presume that's the reason it's not triggering.
That's the only time it is supposed to be called; it's the event at
the creation of a breakpoint. THe user creates it, it lives until it
is deleted.
> (gdb) watch i
> During symbol reading, incomplete CFI data; unspecified registers (e.g.,
> r0) at 0x10000738.
> breakpoint_create_event (CREATED!)
> Hardware watchpoint 2: i
> (gdb) n
> 41 res = pthread_create(&threads[i],
> (gdb)
> [New Thread 0x40000a26240 (LWP 3290)]
> breakpoint_delete_event (DELETED! After this point, no more creations.)
GDB has stopped for some reason and checked whether the watchpoint on
i is still in scope. It thinks it isn't. This may be an unwinder
problem. Since the scope is gone, the watchpoint is deleted.
When you have a problem with watchpoints it's useful to remember that
watchpoints on local variables are by far the most complicated kind.
See if they still work on a global variable or a memory location.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2007-10-24 16:51 ` Daniel Jacobowitz
@ 2007-10-24 18:08 ` Luis Machado
2007-10-24 18:20 ` Daniel Jacobowitz
0 siblings, 1 reply; 27+ messages in thread
From: Luis Machado @ 2007-10-24 18:08 UTC (permalink / raw)
To: Daniel Jacobowitz; +Cc: gdb-patches
Ok,
This is the event log without the patch applied. I can see that it does
have additional creation events occuring in the background, different
than what occurs with the patch. Same source code, same compile flags.
== code ==
(gdb) set debug event 1
(gdb) start
breakpoint_create_event
Breakpoint 1 at 0x10000738: file testsuite/gdb.base/watch-thread_num.c,
line 39.
Starting program: /home/luis/src/gdb/gdb-head/git/gdb/test
[Thread debugging using libthread_db enabled]
[New Thread 0x400000257c0 (LWP 4236)]
[Switching to Thread 0x400000257c0 (LWP 4236)]
breakpoint_delete_event
main () at testsuite/gdb.base/watch-thread_num.c:39
39 for (i = 0; i < NUM; i++)
(gdb) watch i
During symbol reading, incomplete CFI data; unspecified registers (e.g.,
r0) at 0x10000738.
breakpoint_create_event
Hardware watchpoint 2: i
(gdb) n
41 res = pthread_create(&threads[i],
(gdb)
[New Thread 0x40000a26240 (LWP 4239)]
breakpoint_delete_event
39 for (i = 0; i < NUM; i++)
(gdb)
breakpoint_create_event
Hardware watchpoint 2: i
Old value = 0
New value = 1
0x0000000010000788 in main () at
testsuite/gdb.base/watch-thread_num.c:39
39 for (i = 0; i < NUM; i++)
(gdb)
41 res = pthread_create(&threads[i],
(gdb)
[New Thread 0x40001226240 (LWP 4240)]
breakpoint_delete_event
39 for (i = 0; i < NUM; i++)
(gdb)
breakpoint_create_event
Hardware watchpoint 2: i
Old value = 1
New value = 2
0x0000000010000788 in main () at
testsuite/gdb.base/watch-thread_num.c:39
39 for (i = 0; i < NUM; i++)
(gdb) n
41 res = pthread_create(&threads[i],
(gdb)
[New Thread 0x40001a26240 (LWP 4241)]
breakpoint_delete_event
39 for (i = 0; i < NUM; i++)
(gdb)
breakpoint_create_event
Hardware watchpoint 2: i
Old value = 2
New value = 3
0x0000000010000788 in main () at
testsuite/gdb.base/watch-thread_num.c:39
39 for (i = 0; i < NUM; i++)
(gdb)
On Wed, 2007-10-24 at 12:47 -0400, Daniel Jacobowitz wrote:
> On Wed, Oct 24, 2007 at 02:22:00PM -0300, Luis Machado wrote:
> > Hi Daniel,
> >
> > This is what i get while trying to use a hardware watchpoint to monitor
> > an int variable "i" that changes during a for statement (attached). Upon
> > further investigation, it seems GDB is only calling
> > "breakpoint_delete_event". I don't see GDB calling
> > "breakpoint_create_event" anywhere except in the momment i created the
> > watchpoint up there, so i presume that's the reason it's not triggering.
>
> That's the only time it is supposed to be called; it's the event at
> the creation of a breakpoint. THe user creates it, it lives until it
> is deleted.
>
> > (gdb) watch i
> > During symbol reading, incomplete CFI data; unspecified registers (e.g.,
> > r0) at 0x10000738.
> > breakpoint_create_event (CREATED!)
> > Hardware watchpoint 2: i
> > (gdb) n
> > 41 res = pthread_create(&threads[i],
> > (gdb)
> > [New Thread 0x40000a26240 (LWP 3290)]
> > breakpoint_delete_event (DELETED! After this point, no more creations.)
>
> GDB has stopped for some reason and checked whether the watchpoint on
> i is still in scope. It thinks it isn't. This may be an unwinder
> problem. Since the scope is gone, the watchpoint is deleted.
>
> When you have a problem with watchpoints it's useful to remember that
> watchpoints on local variables are by far the most complicated kind.
> See if they still work on a global variable or a memory location.
>
--
Luis Machado
IBM Linux Technology Center
e-mail: luisgpm@linux.vnet.ibm.com
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2007-10-24 18:08 ` Luis Machado
@ 2007-10-24 18:20 ` Daniel Jacobowitz
0 siblings, 0 replies; 27+ messages in thread
From: Daniel Jacobowitz @ 2007-10-24 18:20 UTC (permalink / raw)
To: Luis Machado; +Cc: gdb-patches
On Wed, Oct 24, 2007 at 04:02:24PM -0300, Luis Machado wrote:
> Ok,
>
> This is the event log without the patch applied. I can see that it does
> have additional creation events occuring in the background, different
> than what occurs with the patch. Same source code, same compile flags.
This log isn't very useful, because it doesn't say _what_ is being
created. You might have better luck with the "set debug target 1"
logs, which will show watchpoints and breakpoints being inserted,
or "set debug frame 1" which will show you any failures to backtrace.
But after that you'll have to break out another copy of GDB.
Check when GDB is checking the watchpoint and what it finds out.
Might want to find a useful debug category to add some new messages
to :-)
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2007-10-01 0:20 ` Daniel Jacobowitz
2007-10-24 14:59 ` Luis Machado
@ 2008-04-16 22:57 ` Andreas Schwab
2008-04-16 23:05 ` Daniel Jacobowitz
1 sibling, 1 reply; 27+ messages in thread
From: Andreas Schwab @ 2008-04-16 22:57 UTC (permalink / raw)
To: gdb-patches
Daniel Jacobowitz <drow@false.org> writes:
> 2007-09-30 Daniel Jacobowitz <dan@codesourcery.com>
> Jeff Johnston <jjohnstn@redhat.com>
>
> * breakpoint.c (watchpoints_triggered): New.
> (bpstat_stop_status): Remove STOPPED_BY_WATCHPOINT argument.
> Check watchpoint_triggered instead. Combine handling for software
> and hardware watchpoints. Do not use target_stopped_data_address
> here. Always check a watchpoint if its scope breakpoint triggers.
> Do not stop for thread or overlay events. Improve check for
> triggered watchpoints without a value change.
> (watch_command_1): Insert the scope breakpoint first. Link the
> scope breakpoint to the watchpoint.
> * breakpoint.h (enum watchpoint_triggered): New.
> (struct breakpoint): Add watchpoint_triggered.
> (bpstat_stop_status): Update prototype.
> (watchpoints_triggered): Declare.
> * infrun.c (enum infwait_status): Add infwait_step_watch_state.
> (stepped_after_stopped_by_watchpoint): Delete.
> (handle_inferior_event): Make stepped_after_stopped_by_watchpoint
> local. Handle infwait_step_watch_state. Update calls to
> bpstat_stop_status. Use watchpoints_triggered to check
> watchpoints.
> * remote.c (stepped_after_stopped_by_watchpoint): Remove extern.
> (remote_stopped_data_address): Do not check it.
That completely broke watchpoints on ppc. They are no longer recognized
as such, and gdb is reporting a SIGTRAP instead.
Andreas.
--
Andreas Schwab, SuSE Labs, schwab@suse.de
SuSE Linux Products GmbH, MaxfeldstraÃe 5, 90409 Nürnberg, Germany
PGP key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2008-04-16 22:57 ` Andreas Schwab
@ 2008-04-16 23:05 ` Daniel Jacobowitz
2008-04-16 23:18 ` Andreas Schwab
2008-05-01 19:50 ` Luis Machado
0 siblings, 2 replies; 27+ messages in thread
From: Daniel Jacobowitz @ 2008-04-16 23:05 UTC (permalink / raw)
To: Andreas Schwab; +Cc: gdb-patches
On Thu, Apr 17, 2008 at 12:40:23AM +0200, Andreas Schwab wrote:
> That completely broke watchpoints on ppc. They are no longer recognized
> as such, and gdb is reporting a SIGTRAP instead.
Luis reported some problems, too (last October). The discussion
trailed off waiting for him to look at it further. I also tested on a
PowerPC system before committing the patch, so it's got to be some
combination of factors that didn't show up on my target.
Covering my ass out of the way, can you be a little more specific?
What CPU/kernel, any useful debug logs you have, et cetera.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2008-04-16 23:05 ` Daniel Jacobowitz
@ 2008-04-16 23:18 ` Andreas Schwab
2008-04-17 0:25 ` Daniel Jacobowitz
2008-05-01 19:50 ` Luis Machado
1 sibling, 1 reply; 27+ messages in thread
From: Andreas Schwab @ 2008-04-16 23:18 UTC (permalink / raw)
To: gdb-patches
Daniel Jacobowitz <drow@false.org> writes:
> Covering my ass out of the way, can you be a little more specific?
> What CPU/kernel, any useful debug logs you have, et cetera.
2.6.25-rc9 on G5.
infrun: wait_for_inferior (treat_exec_as_sigtrap=1)
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x40015c60
infrun: quietly stopped
infrun: stop_stepping
infrun: resume (step=0, signal=0)
infrun: wait_for_inferior (treat_exec_as_sigtrap=1)
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x40015c60
infrun: quietly stopped
infrun: stop_stepping
infrun: proceed (addr=0xffffffff, signal=0, step=0)
infrun: resume (step=0, signal=0)
infrun: wait_for_inferior (treat_exec_as_sigtrap=0)
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x4000f0bc
infrun: BPSTAT_WHAT_CHECK_SHLIBS
infrun: no stepping, continue
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x4000f0c0
infrun: no stepping, continue
infrun: resume (step=0, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x4000f0bc
infrun: BPSTAT_WHAT_CHECK_SHLIBS
infrun: no stepping, continue
infrun: resume (step=1, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x4000f0c0
infrun: no stepping, continue
infrun: resume (step=0, signal=0)
infrun: prepare_to_wait
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x100004ac
infrun: STOPPED_BY_WATCHPOINT
infrun: prepare_to_wait
infrun: infwait_nonstep_watch_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x100004b0
infrun: random signal 5
Andreas.
--
Andreas Schwab, SuSE Labs, schwab@suse.de
SuSE Linux Products GmbH, MaxfeldstraÃe 5, 90409 Nürnberg, Germany
PGP key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2008-04-16 23:18 ` Andreas Schwab
@ 2008-04-17 0:25 ` Daniel Jacobowitz
2008-04-17 9:52 ` Andreas Schwab
2008-04-17 10:17 ` Andreas Schwab
0 siblings, 2 replies; 27+ messages in thread
From: Daniel Jacobowitz @ 2008-04-17 0:25 UTC (permalink / raw)
To: Andreas Schwab; +Cc: gdb-patches
On Thu, Apr 17, 2008 at 01:04:56AM +0200, Andreas Schwab wrote:
> infrun: infwait_nonstep_watch_state
> infrun: TARGET_WAITKIND_STOPPED
> infrun: stop_pc = 0x100004b0
> infrun: random signal 5
Thanks, I can see the problem. stepped_after_stopped_by_watchpoint is
set, but nothing is using that to indicate that we should report the
watchpoint.
We need to communicate this to bpstat_stop_status again after the
step. It's supposed to happen automatically, because only a call to
watchpoints_triggered ever clears the watchpoint_triggered flag.
How is it getting lost? I assume that it is getting lost; you
could set a breakpoint on bpstat_stop_status when it is called
just before the "random signal 5", after infwait_nonstep_watch_state,
and check.
I wonder if this could be related to Vladimir's changes to watchpoint
locations. No, the flag is on struct breakpoint, not struct
bp_location. I'm mystified.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2008-04-17 0:25 ` Daniel Jacobowitz
@ 2008-04-17 9:52 ` Andreas Schwab
2008-04-17 9:59 ` Andreas Schwab
2008-04-17 10:17 ` Andreas Schwab
1 sibling, 1 reply; 27+ messages in thread
From: Andreas Schwab @ 2008-04-17 9:52 UTC (permalink / raw)
To: gdb-patches
Daniel Jacobowitz <drow@false.org> writes:
> We need to communicate this to bpstat_stop_status again after the
> step. It's supposed to happen automatically, because only a call to
> watchpoints_triggered ever clears the watchpoint_triggered flag.
> How is it getting lost? I assume that it is getting lost; you
> could set a breakpoint on bpstat_stop_status when it is called
> just before the "random signal 5", after infwait_nonstep_watch_state,
> and check.
watchpoint_triggered is not set. What does that mean?
Andreas.
--
Andreas Schwab, SuSE Labs, schwab@suse.de
SuSE Linux Products GmbH, MaxfeldstraÃe 5, 90409 Nürnberg, Germany
PGP key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2008-04-17 9:52 ` Andreas Schwab
@ 2008-04-17 9:59 ` Andreas Schwab
0 siblings, 0 replies; 27+ messages in thread
From: Andreas Schwab @ 2008-04-17 9:59 UTC (permalink / raw)
To: gdb-patches
Andreas Schwab <schwab@suse.de> writes:
> Daniel Jacobowitz <drow@false.org> writes:
>
>> We need to communicate this to bpstat_stop_status again after the
>> step. It's supposed to happen automatically, because only a call to
>> watchpoints_triggered ever clears the watchpoint_triggered flag.
>> How is it getting lost? I assume that it is getting lost; you
>> could set a breakpoint on bpstat_stop_status when it is called
>> just before the "random signal 5", after infwait_nonstep_watch_state,
>> and check.
>
> watchpoint_triggered is not set. What does that mean?
In fact, it's _never_ set.
Andreas.
--
Andreas Schwab, SuSE Labs, schwab@suse.de
SuSE Linux Products GmbH, MaxfeldstraÃe 5, 90409 Nürnberg, Germany
PGP key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2008-04-17 0:25 ` Daniel Jacobowitz
2008-04-17 9:52 ` Andreas Schwab
@ 2008-04-17 10:17 ` Andreas Schwab
2008-04-17 14:53 ` Daniel Jacobowitz
1 sibling, 1 reply; 27+ messages in thread
From: Andreas Schwab @ 2008-04-17 10:17 UTC (permalink / raw)
To: gdb-patches
Daniel Jacobowitz <drow@false.org> writes:
> On Thu, Apr 17, 2008 at 01:04:56AM +0200, Andreas Schwab wrote:
>> infrun: infwait_nonstep_watch_state
>> infrun: TARGET_WAITKIND_STOPPED
>> infrun: stop_pc = 0x100004b0
>> infrun: random signal 5
>
> Thanks, I can see the problem. stepped_after_stopped_by_watchpoint is
> set, but nothing is using that to indicate that we should report the
> watchpoint.
Looking closer, it is actually a kernel bug. PTRACE_GETSIGINFO is not
emulated for 32-bit processes, so that si_addr is set to the upper half
of the address, which is of course zero.
Andreas.
--
Andreas Schwab, SuSE Labs, schwab@suse.de
SuSE Linux Products GmbH, MaxfeldstraÃe 5, 90409 Nürnberg, Germany
PGP key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2008-04-17 10:17 ` Andreas Schwab
@ 2008-04-17 14:53 ` Daniel Jacobowitz
2008-04-20 2:35 ` Andreas Schwab
0 siblings, 1 reply; 27+ messages in thread
From: Daniel Jacobowitz @ 2008-04-17 14:53 UTC (permalink / raw)
To: gdb-patches
On Thu, Apr 17, 2008 at 11:52:31AM +0200, Andreas Schwab wrote:
> Looking closer, it is actually a kernel bug. PTRACE_GETSIGINFO is not
> emulated for 32-bit processes, so that si_addr is set to the upper half
> of the address, which is of course zero.
Glad you could track that down. Yes, my patch made GDB less tolerant
of targets which claim they can report the stopped data address, but
actually fail. It will only report watchpoints when the target
doesn't know what address has changed, or report a changed address
that falls on a particular watchpoint. This lets us keep track of
which thread hit each watchpoint.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2008-04-17 14:53 ` Daniel Jacobowitz
@ 2008-04-20 2:35 ` Andreas Schwab
2008-04-23 11:55 ` Andreas Schwab
0 siblings, 1 reply; 27+ messages in thread
From: Andreas Schwab @ 2008-04-20 2:35 UTC (permalink / raw)
To: gdb-patches
Daniel Jacobowitz <drow@false.org> writes:
> On Thu, Apr 17, 2008 at 11:52:31AM +0200, Andreas Schwab wrote:
>> Looking closer, it is actually a kernel bug. PTRACE_GETSIGINFO is not
>> emulated for 32-bit processes, so that si_addr is set to the upper half
>> of the address, which is of course zero.
>
> Glad you could track that down. Yes, my patch made GDB less tolerant
> of targets which claim they can report the stopped data address, but
> actually fail. It will only report watchpoints when the target
> doesn't know what address has changed, or report a changed address
> that falls on a particular watchpoint. This lets us keep track of
> which thread hit each watchpoint.
There is still a problem with that: if the watchpoint granularity is
bigger than the size of the data then gdb can still get this wrong. On
ppc64 the granularity is 8 bytes, so if you watch a 4 byte object you
also get a trap if the other 4 bytes of the watched 8 bytes are
modified, but gdb should ignore that trap. I think there needs to be a
target hook to tell watchpoints_triggered the granularity.
Andreas.
--
Andreas Schwab, SuSE Labs, schwab@suse.de
SuSE Linux Products GmbH, MaxfeldstraÃe 5, 90409 Nürnberg, Germany
PGP key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2008-04-20 2:35 ` Andreas Schwab
@ 2008-04-23 11:55 ` Andreas Schwab
2008-04-23 19:46 ` Eli Zaretskii
2008-05-01 19:30 ` Daniel Jacobowitz
0 siblings, 2 replies; 27+ messages in thread
From: Andreas Schwab @ 2008-04-23 11:55 UTC (permalink / raw)
To: gdb-patches
Andreas Schwab <schwab@suse.de> writes:
> Daniel Jacobowitz <drow@false.org> writes:
>
>> On Thu, Apr 17, 2008 at 11:52:31AM +0200, Andreas Schwab wrote:
>>> Looking closer, it is actually a kernel bug. PTRACE_GETSIGINFO is not
>>> emulated for 32-bit processes, so that si_addr is set to the upper half
>>> of the address, which is of course zero.
>>
>> Glad you could track that down. Yes, my patch made GDB less tolerant
>> of targets which claim they can report the stopped data address, but
>> actually fail. It will only report watchpoints when the target
>> doesn't know what address has changed, or report a changed address
>> that falls on a particular watchpoint. This lets us keep track of
>> which thread hit each watchpoint.
>
> There is still a problem with that: if the watchpoint granularity is
> bigger than the size of the data then gdb can still get this wrong.
Here's a patch. OK?
Andreas.
2008-04-23 Andreas Schwab <schwab@suse.de>
* target.h (struct target_ops): Add
to_watchpoint_addr_within_range.
(target_watchpoint_addr_within_range): New function.
* target.c (update_current_target): Inherit
to_watchpoint_addr_within_range, defaulting to
default_watchpoint_addr_within_range.
(default_watchpoint_addr_within_range): New function.
(debug_to_watchpoint_addr_within_range): New function.
(setup_target_debug): Set to_watchpoint_addr_within_range.
* ppc-linux-nat.c (ppc_linux_watchpoint_addr_within_range):
New function.
(_initialize_ppc_linux_nat): Set to_watchpoint_addr_within_range.
* breakpoint.c (watchpoints_triggered): Use
target_watchpoint_addr_within_range.
doc/:
* gdbint.texinfo (Algorithms): Describe
target_watchpoint_addr_within_range.
Index: breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.310
diff -u -a -p -a -u -p -r1.310 breakpoint.c
--- breakpoint.c 18 Apr 2008 00:41:28 -0000 1.310
+++ breakpoint.c 23 Apr 2008 11:00:51 -0000
@@ -2552,8 +2552,9 @@ watchpoints_triggered (struct target_wai
for (loc = b->loc; loc; loc = loc->next)
/* Exact match not required. Within range is
sufficient. */
- if (addr >= loc->address
- && addr < loc->address + loc->length)
+ if (target_watchpoint_addr_within_range (¤t_target,
+ addr, loc->address,
+ loc->length))
{
b->watchpoint_triggered = watch_triggered_yes;
break;
Index: ppc-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/ppc-linux-nat.c,v
retrieving revision 1.78
diff -u -a -p -a -u -p -r1.78 ppc-linux-nat.c
--- ppc-linux-nat.c 16 Jan 2008 04:48:55 -0000 1.78
+++ ppc-linux-nat.c 23 Apr 2008 11:00:52 -0000
@@ -889,6 +889,16 @@ ppc_linux_stopped_by_watchpoint (void)
return ppc_linux_stopped_data_address (¤t_target, &addr);
}
+static int
+ppc_linux_watchpoint_addr_within_range (struct target_ops *target,
+ CORE_ADDR addr,
+ CORE_ADDR start, int length)
+{
+ addr &= ~7;
+ /* Check whether [start, start+length-1] intersects [addr, addr+7]. */
+ return start <= addr + 7 && start + length - 1 >= addr;
+}
+
static void
ppc_linux_store_inferior_registers (struct regcache *regcache, int regno)
{
@@ -997,6 +1007,7 @@ _initialize_ppc_linux_nat (void)
t->to_remove_watchpoint = ppc_linux_remove_watchpoint;
t->to_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint;
t->to_stopped_data_address = ppc_linux_stopped_data_address;
+ t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
t->to_read_description = ppc_linux_read_description;
Index: target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.159
diff -u -a -p -a -u -p -r1.159 target.c
--- target.c 28 Mar 2008 16:37:08 -0000 1.159
+++ target.c 23 Apr 2008 11:00:52 -0000
@@ -49,6 +49,9 @@ static void kill_or_be_killed (int);
static void default_terminal_info (char *, int);
+static int default_watchpoint_addr_within_range (struct target_ops *,
+ CORE_ADDR, CORE_ADDR, int);
+
static int default_region_ok_for_hw_watchpoint (CORE_ADDR, int);
static int nosymbol (char *, CORE_ADDR *);
@@ -131,6 +134,9 @@ static int debug_to_stopped_by_watchpoin
static int debug_to_stopped_data_address (struct target_ops *, CORE_ADDR *);
+static int debug_to_watchpoint_addr_within_range (struct target_ops *,
+ CORE_ADDR, CORE_ADDR, int);
+
static int debug_to_region_ok_for_hw_watchpoint (CORE_ADDR, int);
static void debug_to_terminal_init (void);
@@ -416,9 +422,10 @@ update_current_target (void)
INHERIT (to_insert_watchpoint, t);
INHERIT (to_remove_watchpoint, t);
INHERIT (to_stopped_data_address, t);
- INHERIT (to_stopped_by_watchpoint, t);
INHERIT (to_have_steppable_watchpoint, t);
INHERIT (to_have_continuable_watchpoint, t);
+ INHERIT (to_stopped_by_watchpoint, t);
+ INHERIT (to_watchpoint_addr_within_range, t);
INHERIT (to_region_ok_for_hw_watchpoint, t);
INHERIT (to_terminal_init, t);
INHERIT (to_terminal_inferior, t);
@@ -544,6 +551,8 @@ update_current_target (void)
de_fault (to_stopped_data_address,
(int (*) (struct target_ops *, CORE_ADDR *))
return_zero);
+ de_fault (to_watchpoint_addr_within_range,
+ default_watchpoint_addr_within_range);
de_fault (to_region_ok_for_hw_watchpoint,
default_region_ok_for_hw_watchpoint);
de_fault (to_terminal_init,
@@ -1873,6 +1882,14 @@ default_region_ok_for_hw_watchpoint (COR
}
static int
+default_watchpoint_addr_within_range (struct target_ops *target,
+ CORE_ADDR addr,
+ CORE_ADDR start, int length)
+{
+ return addr >= start && addr < start + length;
+}
+
+static int
return_zero (void)
{
return 0;
@@ -2440,6 +2457,23 @@ debug_to_stopped_data_address (struct ta
}
static int
+debug_to_watchpoint_addr_within_range (struct target_ops *target,
+ CORE_ADDR addr,
+ CORE_ADDR start, int length)
+{
+ int retval;
+
+ retval = debug_target.to_watchpoint_addr_within_range (target, addr,
+ start, length);
+
+ fprintf_filtered (gdb_stdlog,
+ "target_watchpoint_addr_within_range (0x%lx, 0x%lx, %d) = %d\n",
+ (unsigned long) addr, (unsigned long) start, length,
+ retval);
+ return retval;
+}
+
+static int
debug_to_insert_hw_breakpoint (struct bp_target_info *bp_tgt)
{
int retval;
@@ -2782,6 +2816,7 @@ setup_target_debug (void)
current_target.to_remove_watchpoint = debug_to_remove_watchpoint;
current_target.to_stopped_by_watchpoint = debug_to_stopped_by_watchpoint;
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_terminal_init = debug_to_terminal_init;
current_target.to_terminal_inferior = debug_to_terminal_inferior;
Index: target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.116
diff -u -a -p -a -u -p -r1.116 target.h
--- target.h 8 Apr 2008 17:02:23 -0000 1.116
+++ target.h 23 Apr 2008 11:00:52 -0000
@@ -367,6 +367,8 @@ struct target_ops
int to_have_steppable_watchpoint;
int to_have_continuable_watchpoint;
int (*to_stopped_data_address) (struct target_ops *, CORE_ADDR *);
+ int (*to_watchpoint_addr_within_range) (struct target_ops *,
+ CORE_ADDR, CORE_ADDR, int);
int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int);
void (*to_terminal_init) (void);
void (*to_terminal_inferior) (void);
@@ -1093,6 +1095,9 @@ extern int target_stopped_data_address_p
#define target_stopped_data_address_p(CURRENT_TARGET) (1)
#endif
+#define target_watchpoint_addr_within_range(target, addr, start, length) \
+ (*target.to_watchpoint_addr_within_range) (target, addr, start, length)
+
extern const struct target_desc *target_read_description (struct target_ops *);
/* Command logging facility. */
--- doc/gdbint.texinfo.~1.281.~ 2008-04-22 11:46:53.000000000 +0200
+++ doc/gdbint.texinfo 2008-04-23 12:01:04.000000000 +0200
@@ -9,7 +9,7 @@
@ifinfo
This file documents the internals of the GNU debugger @value{GDBN}.
Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1998, 1999, 2000, 2001,
- 2002, 2003, 2004, 2005, 2006
+ 2002, 2003, 2004, 2005, 2006, 2008
Free Software Foundation, Inc.
Contributed by Cygnus Solutions. Written by John Gilmore.
Second Edition by Stan Shebs.
@@ -743,10 +743,19 @@ target's watchpoint indication is sticky
resuming, this method should clear it. For instance, the x86 debug
control register has sticky triggered flags.
+@findex target_watchpoint_addr_within_range
+@item target_watchpoint_addr_within_range (@var{target}, @var{addr}, @var{start}, @var{length})
+Check whether @var{addr} (as returned by target_stopped_data_address)
+lies within the hardware-defined watchpoint region described by
+@var{start} and @var{length}. This only needs to be provided if the
+granularity of a watchpoint is greater than one byte, i.e., if the
+watchpoint can also trigger on nearby addresses outside of the watched
+region.
+
@findex HAVE_STEPPABLE_WATCHPOINT
@item HAVE_STEPPABLE_WATCHPOINT
If defined to a non-zero value, it is not necessary to disable a
-watchpoint to step over it. Like @code{gdbarch_have_nonsteppable_watchpoint},
+watchpoint to step over it. Like @code{gdbarch_have_nonsteppable_watchpoint},
this is usually set when watchpoints trigger at the instruction
which will perform an interesting read or write. It should be
set if there is a temporary disable bit which allows the processor
--
Andreas Schwab, SuSE Labs, schwab@suse.de
SuSE Linux Products GmbH, MaxfeldstraÃe 5, 90409 Nürnberg, Germany
PGP key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2008-04-23 11:55 ` Andreas Schwab
@ 2008-04-23 19:46 ` Eli Zaretskii
2008-05-01 19:30 ` Daniel Jacobowitz
1 sibling, 0 replies; 27+ messages in thread
From: Eli Zaretskii @ 2008-04-23 19:46 UTC (permalink / raw)
To: Andreas Schwab; +Cc: gdb-patches
> From: Andreas Schwab <schwab@suse.de>
> Date: Wed, 23 Apr 2008 13:15:47 +0200
>
> Here's a patch. OK?
>
> Andreas.
>
> 2008-04-23 Andreas Schwab <schwab@suse.de>
>
> * target.h (struct target_ops): Add
> to_watchpoint_addr_within_range.
> (target_watchpoint_addr_within_range): New function.
> * target.c (update_current_target): Inherit
> to_watchpoint_addr_within_range, defaulting to
> default_watchpoint_addr_within_range.
> (default_watchpoint_addr_within_range): New function.
> (debug_to_watchpoint_addr_within_range): New function.
> (setup_target_debug): Set to_watchpoint_addr_within_range.
> * ppc-linux-nat.c (ppc_linux_watchpoint_addr_within_range):
> New function.
> (_initialize_ppc_linux_nat): Set to_watchpoint_addr_within_range.
> * breakpoint.c (watchpoints_triggered): Use
> target_watchpoint_addr_within_range.
>
> doc/:
> * gdbint.texinfo (Algorithms): Describe
> target_watchpoint_addr_within_range.
The patch to gdbint.texinfo is approved, with one comment:
> +Check whether @var{addr} (as returned by target_stopped_data_address)
target_stopped_data_address should have the @code markup, since it's a
C symbol.
> + This only needs to be provided if the
> +granularity of a watchpoint is greater than one byte
Strictly speaking, I think it's needed only if watchpoint's
granularity is greater than the granularity of data addresses, but
that's nitpicking.
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2008-04-23 11:55 ` Andreas Schwab
2008-04-23 19:46 ` Eli Zaretskii
@ 2008-05-01 19:30 ` Daniel Jacobowitz
1 sibling, 0 replies; 27+ messages in thread
From: Daniel Jacobowitz @ 2008-05-01 19:30 UTC (permalink / raw)
To: Andreas Schwab; +Cc: gdb-patches
On Wed, Apr 23, 2008 at 01:15:47PM +0200, Andreas Schwab wrote:
> > There is still a problem with that: if the watchpoint granularity is
> > bigger than the size of the data then gdb can still get this wrong.
>
> Here's a patch. OK?
Thanks for tracking this down. With Eli's suggestions for the manual,
this is OK.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [rfc, rfa/doc] Multi-threaded watchpoint improvements
2008-04-16 23:05 ` Daniel Jacobowitz
2008-04-16 23:18 ` Andreas Schwab
@ 2008-05-01 19:50 ` Luis Machado
1 sibling, 0 replies; 27+ messages in thread
From: Luis Machado @ 2008-05-01 19:50 UTC (permalink / raw)
To: Daniel Jacobowitz; +Cc: Andreas Schwab, gdb-patches
Hi,
> Luis reported some problems, too (last October). The discussion
> trailed off waiting for him to look at it further. I also tested on a
> PowerPC system before committing the patch, so it's got to be some
> combination of factors that didn't show up on my target.
Sorry i'm late on this. The problem i originally reported to Daniel back
then was actually a typo that happened in his patch, thus the hardware
watchpoint wasn't triggering at all. This happened because the address
wasn't being set. It was a quick fix.
Thanks for the improvement Andreas.
Best regards,
Luis
^ permalink raw reply [flat|nested] 27+ messages in thread
end of thread, other threads:[~2008-05-01 19:50 UTC | newest]
Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-09-16 18:40 [rfc, rfa/doc] Multi-threaded watchpoint improvements Daniel Jacobowitz
2007-09-22 9:03 ` Eli Zaretskii
2007-09-22 14:04 ` Daniel Jacobowitz
2007-09-22 14:13 ` Eli Zaretskii
2007-09-22 15:37 ` Daniel Jacobowitz
2007-09-22 15:46 ` Eli Zaretskii
2007-09-22 18:28 ` Daniel Jacobowitz
2007-10-01 0:20 ` Daniel Jacobowitz
2007-10-24 14:59 ` Luis Machado
2007-10-24 16:00 ` Daniel Jacobowitz
2007-10-24 16:42 ` Luis Machado
2007-10-24 16:51 ` Daniel Jacobowitz
2007-10-24 18:08 ` Luis Machado
2007-10-24 18:20 ` Daniel Jacobowitz
2008-04-16 22:57 ` Andreas Schwab
2008-04-16 23:05 ` Daniel Jacobowitz
2008-04-16 23:18 ` Andreas Schwab
2008-04-17 0:25 ` Daniel Jacobowitz
2008-04-17 9:52 ` Andreas Schwab
2008-04-17 9:59 ` Andreas Schwab
2008-04-17 10:17 ` Andreas Schwab
2008-04-17 14:53 ` Daniel Jacobowitz
2008-04-20 2:35 ` Andreas Schwab
2008-04-23 11:55 ` Andreas Schwab
2008-04-23 19:46 ` Eli Zaretskii
2008-05-01 19:30 ` Daniel Jacobowitz
2008-05-01 19:50 ` Luis Machado
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox