[RFC]: x86 threaded watchpoint support [2/3]

Jeff Johnston
2004-06-11T21:33:38Z

[-- Attachment #1: Type: text/plain, Size: 1229 bytes --]

This is the 2nd part of getting x86 threaded watchpoints to work. It involves
some fixes to breakpoint.c.

The most major change is that a check has been added for a hardware_watchpoint
to ensure that the stopped data address matches the watchpoint address. I do
not know if there are platforms that have hardware_watchpoints but cannot tell
what the data address is. If this problem exists, I can easily add a flag to
determine if the stopped address can be used or not. Alternatively, the default
stopped_data_address for such a platform could return a special value that the
comparison check could treat as "don't know".

Comments? Ok?

-- Jeff J.

2004-06-11 Jeff Johnston <jjohnstn@redhat.com>

* breakpoint.c (print_it_typical): Do not issue a warning message
if we find a bp_thread_event and there are other items on the
stop list.
(bpstat_stop_status): When dealing with a hardware_watchpoint,
check if the stopped data address matches the watched address
for the current breakpoint in the list. When dealing with a
read or access watchpoint, if the address does not match, remember
to turn off the print for the newly added bpstat.

[-- Attachment #2: x86-watchpoint.patch2 --]
[-- Type: text/plain, Size: 5430 bytes --]

Index: breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.174
diff -u -p -r1.174 breakpoint.c
--- breakpoint.c 7 Jun 2004 17:58:32 -0000 1.174
+++ breakpoint.c 11 Jun 2004 21:22:42 -0000
@@ -2120,8 +2120,13 @@ print_it_typical (bpstat bs)
break;

case bp_thread_event:
- /* Not sure how we will get here.
- GDB should not stop for these breakpoints. */
+ /* We can only get here legitimately if something further on the bs
+ list has caused the stop status to be noisy. A valid example
+ of this is a new thread event and a software watchpoint have
+ both occurred. */
+ if (bs->next)
+ return PRINT_UNKNOWN;
+
printf_filtered ("Thread Event Breakpoint: gdb should not stop!\n");
return PRINT_NOTHING;
break;
@@ -2683,45 +2688,100 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
if (b->type == bp_watchpoint ||
b->type == bp_hardware_watchpoint)
{
- char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n",
+ CORE_ADDR addr;
+ struct value *v;
+ int found = 0;
+
+ /* If we have a hardware watchpoint, ensure that the address
+ being watched caused the trap event. */
+ if (b->type == bp_hardware_watchpoint)
+ {
+ addr = target_stopped_data_address ();
+ if (addr == 0)
+ {
+ /* Don't stop. */
+ bs->print_it = print_it_noop;
+ bs->stop = 0;
+ continue;
+ }
+ for (v = b->val_chain; v; v = v->next)
+ {
+ 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)))
+ found = 1;
+ }
+ }
+ }
+ }
+ else /* For a non-hardware watchpoint we need to test values. */
+ found = 1;
+
+ if (found)
+ {
+ 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)
+ 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 /* found == 0 */
{
- 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. */
+ /* 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. */
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;
+ continue;
}
}
else if (b->type == bp_read_watchpoint ||
@@ -2733,7 +2793,12 @@ bpstat_stop_status (CORE_ADDR bp_addr, p

addr = target_stopped_data_address ();
if (addr == 0)
- continue;
+ {
+ /* Don't stop. */
+ bs->print_it = print_it_noop;
+ bs->stop = 0;
+ continue;
+ }
for (v = b->val_chain; v; v = v->next)
{
if (VALUE_LVAL (v) == lval_memory