This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [patch 2/4] Fix hw watchpoints: reordered / simultaneously hit [fixup #1]
On Wed, 07 Oct 2009 20:38:58 +0200, Joel Brobecker wrote:
> My suggestion, instead of wrapping that one call to
> target_stopped_by_watchpoint was to turn that macro into a function which
> does the wrapping for you, before it eventually calls the target_ops method.
Provided some patch, it is regression tested on
{x86_64,x86_64-m32,i686}-fedora11-linux-gnu, it would be better to regression
test it in with the hw-watchpoints patchset after its complete regression
testing also for the upgraded (not deprecated_* symbols using) targets ia64,
ppc*, s390*.
If we should do the upgrade my primary reason for this change is that I find
the single functionality being split into two target functions
(to_stopped_by_watchpoint and to_stopped_data_address) to be confusing. Chose
a new name to easily be able to keep the old deprecated implementations
working until its host maintainers can get to update them as I cannot even
compile some of the host files.
Asking if this is approved to rebase the hw-watchpoints fixes on top of this
patch.
This patch also changes the former sentence in the doc which I was not aware
of before as internally x86 was violating this rule:
Then @value{GDBN} calls @code{target_stopped_data_address} exactly
once.
But maybe if this rule is still valid linux_nat_stopped_data_address can be
dropped and I should rework the patchset including this patch instead.
> I cannot find the linux_nat_stopped_data_address that you are refering to,
[patch 2/4] Fix hw watchpoints: reordered / simultaneously hit [fixup #1]
http://sourceware.org/ml/gdb-patches/2009-10/msg00075.html
Thanks,
Jan
gdb/
Introduce new target_thread_stopped_by_watchpoint.
* amd64-linux-nat.c (amd64_linux_dr_set, amd64_linux_dr_set_control)
(amd64_linux_dr_set_addr, amd64_linux_dr_reset_addr): New comments.
(amd64_linux_dr_get_status): New parameter ptid, use it, new comment.
* breakpoint.c (update_watchpoint): Extend the comment.
(watchpoints_triggered): Drop the parameter ws, new parameter ptid.
Call the new relay target_thread_stopped_by_watchpoint. Move the state
specific code to ...
(watchpoints_triggered_no, watchpoints_triggered_yes_address_unknown)
(watchpoints_triggered_yes_address_known): ... these new functions.
* breakpoint.h (watchpoints_triggered): Update the prototype.
* go32-nat.c (go32_get_dr6): New parameter ptid.
* i386-darwin-nat.c (i386_darwin_dr_get_status): Likewise.
* i386-linux-nat.c (i386_linux_dr_get, i386_linux_dr_set)
(i386_linux_dr_set_control, i386_linux_dr_set_addr)
(i386_linux_dr_reset_addr): New comments.
(i386_linux_dr_get_status): New parameter ptid, use it, new comment.
* i386-nat.c (i386_stopped_data_address): Rename to ...
(i386_thread_stopped_by_watchpoint): ... this function, drop parameter
ops, new parameter ptid, new return type. Call i386_dr_low.get_status
with new ptid. Drop variables addr and rc. Permit addr_p to be NULL.
Drop redundant check of addr if maint_show_dr.
(i386_stopped_by_watchpoint): Remove.
(i386_use_watchpoints): Drop the initialization of
to_stopped_by_watchpoint and to_stopped_data_address. New
initialization of to_thread_stopped_by_watchpoint.
* i386-nat.h (struct i386_dr_low_type): Extend comments for
set_control, set_addr, reset_addr and get_status.
(struct i386_dr_low_type <get_status>): New parameter ptid.
* i386bsd-nat.c (i386bsd_dr_get_status): New parameter ptid, use it.
* i386bsd-nat.h (i386bsd_dr_get_status): New parameter ptid.
* ia64-linux-nat.c (ia64_linux_stopped_data_address): Rename to ...
(ia64_linux_thread_stopped_by_watchpoint): ... this function, drop
parameter ops, new parameter ptid, use it, rename addr_p to
data_address_p, new return type. Move the regcache initialization
later. Permit data_address_p to be NULL.
(ia64_linux_stopped_by_watchpoint): Remove.
(_initialize_ia64_linux_nat): Drop the initialization of
to_stopped_by_watchpoint and to_stopped_data_address. New
initialization of to_thread_stopped_by_watchpoint.
* inf-ttrace.c (inf_ttrace_target): Rename to_stopped_by_watchpoint to
deprecated_stopped_by_watchpoint.
* infrun.c (handle_inferior_event <debug_infrun>): Rename the variable
addr as data_address. Convert the call of target_stopped_by_watchpoint
and target_stopped_data_address to target_thread_stopped_by_watchpoint.
(handle_inferior_event): Update the parameters of watchpoints_triggered.
* mips-linux-nat.c: Rename to_stopped_by_watchpoint to
deprecated_stopped_by_watchpoint. Rename to_stopped_data_address to
deprecated_stopped_data_address.
* nto-procfs.c (init_procfs_ops): Rename to_stopped_by_watchpoint to
deprecated_stopped_by_watchpoint.
* ppc-linux-nat.c (ppc_linux_stopped_data_address): Rename to ...
(ppc_linux_thread_stopped_by_watchpoint): ... this function, drop
parameter ops, new parameter ptid, use it, rename addr_p to
data_address_p, new return type. Permit data_address_p to be NULL.
(ppc_linux_stopped_by_watchpoint): Remove.
(_initialize_ppc_linux_nat): Drop the initialization of
to_stopped_by_watchpoint and to_stopped_data_address. New
initialization of to_thread_stopped_by_watchpoint.
* procfs.c (procfs_use_watchpoints): Rename to_stopped_by_watchpoint to
deprecated_stopped_by_watchpoint.
* remote-m32r-sdi.c (init_m32r_ops): Rename to_stopped_by_watchpoint to
deprecated_stopped_by_watchpoint. Rename to_stopped_data_address to
deprecated_stopped_data_address.
* remote-mips.c (_initialize_remote_mips): Rename
to_stopped_by_watchpoint to deprecated_stopped_by_watchpoint.
* remote.c (init_remote_ops): Rename to_stopped_by_watchpoint to
deprecated_stopped_by_watchpoint. Rename to_stopped_data_address to
deprecated_stopped_data_address.
* s390-nat.c (s390_stopped_by_watchpoint): Rename to ...
(s390_thread_stopped_by_watchpoint): ... this function, new parameter
ptid, use it, new parameter data_address_p, new return type, new
variable tid, initialize it. New FIXME comment on removing the trigger.
(_initialize_s390_nat): Drop the initialization of
to_stopped_by_watchpoint. New initialization of
to_thread_stopped_by_watchpoint.
* score-tdep.c (score_stopped_by_watch): Rename
to_stopped_by_watchpoint to deprecated_stopped_by_watchpoint.
* target.c (debug_to_stopped_by_watchpoint)
(debug_to_stopped_data_address): Remove.
(update_current_target): Stop calling INHERIT and de_fault for
to_stopped_data_address and to_stopped_by_watchpoint. New comment for
to_thread_stopped_by_watchpoint.
(target_thread_stopped_by_watchpoint): New function.
(setup_target_debug): Drop the initialization of
to_stopped_by_watchpoint and to_stopped_data_address.
* target.h (struct target_ops): Rename to_stopped_by_watchpoint to
deprecated_stopped_by_watchpoint. Rename to_stopped_data_address to
deprecated_stopped_data_address. New field
to_thread_stopped_by_watchpoint.
(target_stopped_by_watchpoint, target_stopped_data_address): Remove.
(enum stopped_by_watchpoint, target_thread_stopped_by_watchpoint): New.
* windows-nat.c (cygwin_get_dr6): New parameter ptid.
gdb/doc/
* gdbint.texinfo (Watchpoints): Change STOPPED_BY_WATCHPOINT with
target_stopped_data_address to target_thread_stopped_by_watchpoint,
note the new return value.
(target_stopped_data_address): Together with ...
(STOPPED_BY_WATCHPOINT): ... merge and rename to ...
(target_thread_stopped_by_watchpoint): ... a new node, describe the new
parameters and return value. Reference the update_watchpoint comment.
(target_watchpoint_addr_within_range): Update the former reference to
target_stopped_data_address.
(Watchpoints and Threads): Rename former STOPPED_BY_WATCHPOINT.
(i386_stopped_data_address): Rename to ...
(i386_thread_stopped_by_watchpoint): ... this function.
(i386_stopped_by_watchpoint): Remove.
--- a/gdb/amd64-linux-nat.c
+++ b/gdb/amd64-linux-nat.c
@@ -270,6 +270,8 @@ amd64_linux_dr_get (ptid_t ptid, int regnum)
return value;
}
+/* Set debug register REGNUM to VALUE in only the one LWP of PTID. */
+
static void
amd64_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
{
@@ -286,6 +288,8 @@ amd64_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
perror_with_name (_("Couldn't write debug register"));
}
+/* Set DR_CONTROL to ADDR in all LWPs of LWP_LIST. */
+
static void
amd64_linux_dr_set_control (unsigned long control)
{
@@ -297,6 +301,8 @@ amd64_linux_dr_set_control (unsigned long control)
amd64_linux_dr_set (ptid, DR_CONTROL, control);
}
+/* Set address REGNUM (zero based) to ADDR in all LWPs of LWP_LIST. */
+
static void
amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
{
@@ -310,16 +316,20 @@ amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
amd64_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr);
}
+/* Set address REGNUM (zero based) to zero in all LWPs of LWP_LIST. */
+
static void
amd64_linux_dr_reset_addr (int regnum)
{
amd64_linux_dr_set_addr (regnum, 0);
}
+/* Get DR_STATUS from only the one LWP PTID. */
+
static unsigned long
-amd64_linux_dr_get_status (void)
+amd64_linux_dr_get_status (ptid_t ptid)
{
- return amd64_linux_dr_get (inferior_ptid, DR_STATUS);
+ return amd64_linux_dr_get (ptid, DR_STATUS);
}
static void
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -903,7 +903,46 @@ fetch_watchpoint_value (struct expression *exp, struct value **valp,
- Update the list of values that must be watched in B->loc.
If the watchpoint disposition is disp_del_at_next_stop, then do nothing.
- If this is local watchpoint that is out of scope, delete it. */
+ If this is local watchpoint that is out of scope, delete it.
+
+ Even with `set breakpoint always-inserted on' the watchpoints are removed
+ + inserted on each stop here. Normal breakpoints must never be removed
+ because they might be missed by a running thread when debugging in non-stop
+ mode. On the other hand, hardware watchpoints (is_hardware_watchpoint;
+ processed here) are specific to each LWP since they are stored in each LWP's
+ hardware debug registers. Therefore, such LWP must be stopped first in
+ order to be able to modify its hardware watchpoints.
+
+ Hardware watchpoints must be reset exactly once after being presented to the
+ user. It cannot be done sooner, because it would reset the data used to
+ present the watchpoint hit to the user. And it must not be done later
+ because it could display the same single watchpoint hit during multiple GDB
+ stops. Note that the latter is relevant only to the hardware watchpoint
+ types bp_read_watchpoint and bp_access_watchpoint. False hit by
+ bp_hardware_watchpoint is not user-visible - its hit is suppressed if the
+ memory content has not changed.
+
+ The following constraints influence the location where we can reset hardware
+ watchpoints:
+
+ * target_stopped_by_watchpoint and target_stopped_data_address are called
+ several times when GDB stops.
+
+ [linux]
+ * Multiple hardware watchpoints can be hit at the same time, causing GDB to
+ stop. GDB only presents one hardware watchpoint hit at a time as the
+ reason for stopping, and all the other hits are presented later, one after
+ the other, each time the user requests the execution to be resumed.
+ Execution is not resumed for the threads still having pending hit event
+ stored in LWP_INFO->STATUS. While the watchpoint is already removed from
+ the inferior on the first stop the thread hit event is kept being reported
+ from its cached value by linux_nat_stopped_data_address until the real
+ thread resume happens after the watchpoint gets presented and thus its
+ LWP_INFO->STATUS gets reset.
+
+ Therefore the hardware watchpoint hit can get safely reset on the watchpoint
+ removal from inferior. */
+
static void
update_watchpoint (struct breakpoint *b, int reparse)
{
@@ -2721,46 +2760,44 @@ bpstat_alloc (const struct bp_location *bl, bpstat cbs /* Current "bs" value */
bs->print_it = print_it_normal;
return bs;
}
-
-/* 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)
+/* We were not stopped by a watchpoint. Mark all watchpoints as not triggered.
+ */
+
+static void
+watchpoints_triggered_no (void)
{
- int stopped_by_watchpoint = target_stopped_by_watchpoint ();
- 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;
+ 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;
- }
+/* We were stopped by a watchpoint, but we don't know where. Mark all
+ watchpoints as unknown. */
- 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;
+static void
+watchpoints_triggered_yes_address_unknown (void)
+{
+ struct breakpoint *b;
- return stopped_by_watchpoint;
- }
+ 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;
+}
- /* The target could report the data address. Mark watchpoints
- affected by this data address as triggered, and all others as not
- triggered. */
+/* The target could report the data address. Mark watchpoints affected by this
+ data address as triggered, and all others as not triggered. */
+
+static void
+watchpoints_triggered_yes_address_known (CORE_ADDR data_address)
+{
+ struct breakpoint *b;
ALL_BREAKPOINTS (b)
if (b->type == bp_hardware_watchpoint
@@ -2775,15 +2812,40 @@ watchpoints_triggered (struct target_waitstatus *ws)
/* Exact match not required. Within range is
sufficient. */
if (target_watchpoint_addr_within_range (¤t_target,
- addr, loc->address,
+ data_address, loc->address,
loc->length))
{
b->watchpoint_triggered = watch_triggered_yes;
break;
}
}
+}
- return 1;
+/* The target has stopped with waitstatus WS. Check if any hardware
+ watchpoints have triggered, according to the target. */
+
+int
+watchpoints_triggered (ptid_t ptid)
+{
+ CORE_ADDR data_address;
+
+ switch (target_thread_stopped_by_watchpoint (ptid, &data_address))
+ {
+ case stopped_by_watchpoint_no:
+ watchpoints_triggered_no ();
+ return 0;
+
+ case stopped_by_watchpoint_yes_address_unknown:
+ watchpoints_triggered_yes_address_unknown ();
+ return 1;
+
+ case stopped_by_watchpoint_yes_address_known:
+ watchpoints_triggered_yes_address_known (data_address);
+ return 1;
+ }
+
+ /* NOTREACHED */
+ return 0;
}
/* Possible return values for watchpoint_check (this can't be an enum
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -918,9 +918,10 @@ extern void remove_single_step_breakpoints (void);
extern void *deprecated_insert_raw_breakpoint (struct gdbarch *, CORE_ADDR);
extern int deprecated_remove_raw_breakpoint (struct gdbarch *, void *);
-/* Check if any hardware watchpoints have triggered, according to the
- target. */
-int watchpoints_triggered (struct target_waitstatus *);
+/* Check if any hardware watchpoints have triggered in thread PTID, according
+ to the target. */
+
+int watchpoints_triggered (ptid_t ptid);
/* Update BUF, which is LEN bytes read from the target address MEMADDR,
by replacing any memory breakpoints with their shadowed contents. */
--- a/gdb/doc/gdbint.texinfo
+++ b/gdb/doc/gdbint.texinfo
@@ -667,11 +667,11 @@ section is mostly irrelevant for software watchpoints.
When the inferior stops, @value{GDBN} tries to establish, among other
possible reasons, whether it stopped due to a watchpoint being hit.
-It first uses @code{STOPPED_BY_WATCHPOINT} to see if any watchpoint
-was hit. If not, all watchpoint checking is skipped.
+It uses @code{target_thread_stopped_by_watchpoint} to see if any watchpoint was
+hit. If its returns @code{stopped_by_watchpoint_no}, 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
+This can also return 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.
@@ -733,24 +733,30 @@ defined by @file{breakpoint.h} as follows:
@noindent
These two macros should return 0 for success, non-zero for failure.
-@findex target_stopped_data_address
-@item target_stopped_data_address (@var{addr_p})
+@findex target_thread_stopped_by_watchpoint
+@item target_thread_stopped_by_watchpoint (@var{ptid}, @var{data_address_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. 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.
+@var{data_address_p} and return @code{stopped_by_watchpoint_yes_address_known}.
+If some watchpoint has triggered but the target does not know any specific
+location, return @code{stopped_by_watchpoint_yes_address_unknown}. Otherwise,
+return @code{stopped_by_watchpoint_no}. 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.
+
+See the comment at function @code{update_watchpoint} for more info.
+
+@value{GDBN} does not require the
+@code{stopped_by_watchpoint_yes_address_unknown} vs.
+@code{stopped_by_watchpoint_no} determination to be 100% correct, so if
+a target cannot determine for sure whether the inferior stopped due to
+a watchpoint, it could return @code{stopped_by_watchpoint_yes_address_unknown}
+``just in case''.
@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 @code{target_stopped_data_address})
+Check whether @var{addr} (as returned in @code{data_address_p}
+from @code{target_thread_stopped_by_watchpoint})
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
@@ -785,21 +791,6 @@ read or write.
@item CANNOT_STEP_HW_WATCHPOINTS
If this is defined to a non-zero value, @value{GDBN} will remove all
watchpoints before stepping the inferior.
-
-@findex STOPPED_BY_WATCHPOINT
-@item STOPPED_BY_WATCHPOINT (@var{wait_status})
-Return non-zero if stopped by a watchpoint. @var{wait_status} is of
-the type @code{struct target_waitstatus}, defined by @file{target.h}.
-Normally, this macro is defined to invoke the function pointed to by
-the @code{to_stopped_by_watchpoint} member of the structure (of the
-type @code{target_ops}, defined on @file{target.h}) that describes the
-target-specific operations; @code{to_stopped_by_watchpoint} ignores
-the @var{wait_status} argument.
-
-@value{GDBN} does not require the non-zero value returned by
-@code{STOPPED_BY_WATCHPOINT} to be 100% correct, so if a target cannot
-determine for sure whether the inferior stopped due to a watchpoint,
-it could return non-zero ``just in case''.
@end table
@subsection Watchpoints and Threads
@@ -822,11 +813,10 @@ threads.
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.
+is resumed. This means that @code{thread_stopped_by_watchpoint} only needs to
+consult the specified thread's state. If two threads have hit watchpoints
+simultaneously, that routine will be called a second time for the second
+thread.
@subsection x86 Watchpoints
@cindex x86 debug registers
@@ -921,26 +911,16 @@ watch a given region, and returns a non-zero value if that number is
less than 4, the number of debug registers available to x86
processors.
-@findex i386_stopped_data_address
-@item i386_stopped_data_address (@var{addr_p})
+@findex i386_thread_stopped_by_watchpoint
+@item i386_thread_stopped_by_watchpoint (@var{ptid}, @var{addr_p})
The target function
-@code{target_stopped_data_address} is set to call this function.
+@code{target_thread_stopped_by_watchpoint} is set to call this function.
This
function examines the breakpoint condition bits in the DR6 Debug
Status register, as returned by the @code{I386_DR_LOW_GET_STATUS}
macro, and returns the address associated with the first bit that is
set in DR6.
-@findex i386_stopped_by_watchpoint
-@item i386_stopped_by_watchpoint (void)
-The macro @code{STOPPED_BY_WATCHPOINT}
-is set to call this function. The
-argument passed to @code{STOPPED_BY_WATCHPOINT} is ignored. This
-function examines the breakpoint condition bits in the DR6 Debug
-Status register, as returned by the @code{I386_DR_LOW_GET_STATUS}
-macro, and returns true if any bit is set. Otherwise, false is
-returned.
-
@findex i386_insert_watchpoint
@findex i386_remove_watchpoint
@item i386_insert_watchpoint (@var{addr}, @var{len}, @var{type})
--- a/gdb/go32-nat.c
+++ b/gdb/go32-nat.c
@@ -791,7 +791,7 @@ go32_set_dr7 (unsigned long val)
Here we just return the value stored in D_REGS, as we've got it
from the last go32_wait call. */
static unsigned long
-go32_get_dr6 (void)
+go32_get_dr6 (ptid_t ptid)
{
return STATUS;
}
--- a/gdb/i386-darwin-nat.c
+++ b/gdb/i386-darwin-nat.c
@@ -404,7 +404,7 @@ i386_darwin_dr_reset_addr (int regnum)
}
unsigned long
-i386_darwin_dr_get_status (void)
+i386_darwin_dr_get_status (ptid_t ptid)
{
return i386_darwin_dr_get (DR_STATUS);
}
--- a/gdb/i386-linux-nat.c
+++ b/gdb/i386-linux-nat.c
@@ -586,6 +586,8 @@ i386_linux_store_inferior_registers (struct target_ops *ops,
static unsigned long i386_linux_dr[DR_CONTROL + 1];
+/* Get debug register REGNUM value from only the one LWP of PTID. */
+
static unsigned long
i386_linux_dr_get (ptid_t ptid, int regnum)
{
@@ -614,6 +616,8 @@ i386_linux_dr_get (ptid_t ptid, int regnum)
return value;
}
+/* Set debug register REGNUM to VALUE in only the one LWP of PTID. */
+
static void
i386_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
{
@@ -630,6 +634,8 @@ i386_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
perror_with_name (_("Couldn't write debug register"));
}
+/* Set DR_CONTROL to ADDR in all LWPs of LWP_LIST. */
+
static void
i386_linux_dr_set_control (unsigned long control)
{
@@ -641,6 +647,8 @@ i386_linux_dr_set_control (unsigned long control)
i386_linux_dr_set (ptid, DR_CONTROL, control);
}
+/* Set address REGNUM (zero based) to ADDR in all LWPs of LWP_LIST. */
+
static void
i386_linux_dr_set_addr (int regnum, CORE_ADDR addr)
{
@@ -654,16 +662,20 @@ i386_linux_dr_set_addr (int regnum, CORE_ADDR addr)
i386_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr);
}
+/* Set address REGNUM (zero based) to zero in all LWPs of LWP_LIST. */
+
static void
i386_linux_dr_reset_addr (int regnum)
{
i386_linux_dr_set_addr (regnum, 0);
}
+/* Get DR_STATUS from only the one LWP PTID. */
+
static unsigned long
-i386_linux_dr_get_status (void)
+i386_linux_dr_get_status (ptid_t ptid)
{
- return i386_linux_dr_get (inferior_ptid, DR_STATUS);
+ return i386_linux_dr_get (ptid, DR_STATUS);
}
static void
--- a/gdb/i386-nat.c
+++ b/gdb/i386-nat.c
@@ -538,14 +538,12 @@ i386_region_ok_for_watchpoint (CORE_ADDR addr, int len)
address associated with that watchpoint and return non-zero.
Otherwise, return zero. */
-static int
-i386_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
+static enum stopped_by_watchpoint
+i386_thread_stopped_by_watchpoint (ptid_t ptid, CORE_ADDR *addr_p)
{
- CORE_ADDR addr = 0;
int i;
- int rc = 0;
- dr_status_mirror = i386_dr_low.get_status ();
+ dr_status_mirror = i386_dr_low.get_status (ptid);
ALL_DEBUG_REGISTERS(i)
{
@@ -560,25 +558,17 @@ i386_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
avoids false positives in windows-nat.c. */
&& !I386_DR_VACANT (i))
{
- addr = dr_mirror[i];
- rc = 1;
+ if (addr_p)
+ *addr_p = dr_mirror[i];
if (maint_show_dr)
- i386_show_dr ("watchpoint_hit", addr, -1, hw_write);
+ i386_show_dr ("watchpoint_hit", dr_mirror[i], -1, hw_write);
+ return stopped_by_watchpoint_yes_address_known;
}
}
- if (maint_show_dr && addr == 0)
+ if (maint_show_dr)
i386_show_dr ("stopped_data_addr", 0, 0, hw_write);
- if (rc)
- *addr_p = addr;
- return rc;
-}
-
-static int
-i386_stopped_by_watchpoint (void)
-{
- CORE_ADDR addr = 0;
- return i386_stopped_data_address (¤t_target, &addr);
+ return stopped_by_watchpoint_no;
}
/* Insert a hardware-assisted breakpoint at BP_TGT->placed_address.
@@ -668,8 +658,7 @@ i386_use_watchpoints (struct target_ops *t)
t->to_can_use_hw_breakpoint = i386_can_use_hw_breakpoint;
t->to_region_ok_for_hw_watchpoint = i386_region_ok_for_watchpoint;
- t->to_stopped_by_watchpoint = i386_stopped_by_watchpoint;
- t->to_stopped_data_address = i386_stopped_data_address;
+ t->to_thread_stopped_by_watchpoint = i386_thread_stopped_by_watchpoint;
t->to_insert_watchpoint = i386_insert_watchpoint;
t->to_remove_watchpoint = i386_remove_watchpoint;
t->to_insert_hw_breakpoint = i386_insert_hw_breakpoint;
--- a/gdb/i386-nat.h
+++ b/gdb/i386-nat.h
@@ -49,16 +49,16 @@ extern void i386_use_watchpoints (struct target_ops *);
functions are:
set_control -- set the debug control (DR7)
- register to a given value
+ register to a given value for all LWPs
set_addr -- put an address into one debug
- register
+ register for all LWPs
reset_addr -- reset the address stored in
- one debug register
+ one debug register for all LWPs
get_status -- return the value of the debug
- status (DR6) register.
+ status (DR6) register for LWP PTID
Additionally, the native file should set the debug_register_length
field to 4 or 8 depending on the number of bytes used for
@@ -69,7 +69,7 @@ struct i386_dr_low_type
void (*set_control) (unsigned long);
void (*set_addr) (int, CORE_ADDR);
void (*reset_addr) (int);
- unsigned long (*get_status) (void);
+ unsigned long (*get_status) (ptid_t ptid);
int debug_register_length;
};
--- a/gdb/i386bsd-nat.c
+++ b/gdb/i386bsd-nat.c
@@ -308,7 +308,7 @@ i386bsd_dr_reset_addr (int regnum)
}
unsigned long
-i386bsd_dr_get_status (void)
+i386bsd_dr_get_status (ptid_t ptid)
{
struct dbreg dbregs;
@@ -317,7 +317,7 @@ i386bsd_dr_get_status (void)
way to fix this is to add the hardware breakpoint and watchpoint
stuff to the target vector. For now, just return zero if the
ptrace call fails. */
- if (ptrace (PT_GETDBREGS, PIDGET (inferior_ptid),
+ if (ptrace (PT_GETDBREGS, PIDGET (ptid),
(PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
#if 0
perror_with_name (_("Couldn't read debug registers"));
--- a/gdb/i386bsd-nat.h
+++ b/gdb/i386bsd-nat.h
@@ -33,6 +33,6 @@ extern void i386bsd_dr_set_addr (int regnum, CORE_ADDR addr);
extern void i386bsd_dr_reset_addr (int regnum);
-extern unsigned long i386bsd_dr_get_status (void);
+extern unsigned long i386bsd_dr_get_status (ptid_t ptid);
#endif /* i386bsd-nat.h */
--- a/gdb/ia64-linux-nat.c
+++ b/gdb/ia64-linux-nat.c
@@ -633,33 +633,29 @@ ia64_linux_new_thread (ptid_t ptid)
enable_watchpoints_in_psr (ptid);
}
-static int
-ia64_linux_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
+static enum stopped_by_watchpoint
+ia64_linux_thread_stopped_by_watchpoint (ptid_t ptid, CORE_ADDR *data_address_p)
{
CORE_ADDR psr;
struct siginfo *siginfo_p;
- struct regcache *regcache = get_current_regcache ();
-
- siginfo_p = linux_nat_get_siginfo (inferior_ptid);
+ struct regcache *regcache;
+
+ siginfo_p = linux_nat_get_siginfo (ptid);
if (siginfo_p->si_signo != SIGTRAP
|| (siginfo_p->si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
- return 0;
+ return stopped_by_watchpoint_no;
+
+ regcache = get_thread_regcache (ptid);
regcache_cooked_read_unsigned (regcache, IA64_PSR_REGNUM, &psr);
psr |= IA64_PSR_DD; /* Set the dd bit - this will disable the watchpoint
for the next instruction */
regcache_cooked_write_unsigned (regcache, IA64_PSR_REGNUM, psr);
- *addr_p = (CORE_ADDR)siginfo_p->si_addr;
- return 1;
-}
-
-static int
-ia64_linux_stopped_by_watchpoint (void)
-{
- CORE_ADDR addr;
- return ia64_linux_stopped_data_address (¤t_target, &addr);
+ if (data_address_p)
+ *data_address_p = (uintptr_t) siginfo_p->si_addr;
+ return stopped_by_watchpoint_yes_address_known;
}
static int
@@ -831,15 +827,14 @@ _initialize_ia64_linux_nat (void)
it again) if the "dd" (data debug fault disable) bit in the processor
status word is set.
- This PSR bit is set in ia64_linux_stopped_by_watchpoint when the
+ This PSR bit is set in ia64_linux_thread_stopped_by_watchpoint when the
code there has determined that a hardware watchpoint has indeed
been hit. The CPU will then be able to execute one instruction
without triggering a watchpoint. */
t->to_have_steppable_watchpoint = 1;
t->to_can_use_hw_breakpoint = ia64_linux_can_use_hw_breakpoint;
- t->to_stopped_by_watchpoint = ia64_linux_stopped_by_watchpoint;
- t->to_stopped_data_address = ia64_linux_stopped_data_address;
+ t->to_thread_stopped_by_watchpoint = ia64_linux_thread_stopped_by_watchpoint;
t->to_insert_watchpoint = ia64_linux_insert_watchpoint;
t->to_remove_watchpoint = ia64_linux_remove_watchpoint;
--- a/gdb/inf-ttrace.c
+++ b/gdb/inf-ttrace.c
@@ -1260,7 +1260,7 @@ inf_ttrace_target (void)
t->to_can_use_hw_breakpoint = inf_ttrace_can_use_hw_breakpoint;
t->to_insert_watchpoint = inf_ttrace_insert_watchpoint;
t->to_remove_watchpoint = inf_ttrace_remove_watchpoint;
- t->to_stopped_by_watchpoint = inf_ttrace_stopped_by_watchpoint;
+ t->deprecated_stopped_by_watchpoint = inf_ttrace_stopped_by_watchpoint;
t->to_region_ok_for_hw_watchpoint =
inf_ttrace_region_ok_for_hw_watchpoint;
t->to_kill = inf_ttrace_kill;
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -2837,21 +2837,28 @@ targets should add new threads to the thread list themselves in non-stop mode.")
{
struct regcache *regcache = get_thread_regcache (ecs->ptid);
struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ CORE_ADDR data_address;
fprintf_unfiltered (gdb_stdlog, "infrun: stop_pc = %s\n",
paddress (gdbarch, stop_pc));
- if (target_stopped_by_watchpoint ())
+
+ switch (target_thread_stopped_by_watchpoint (ecs->ptid, &data_address))
{
- CORE_ADDR addr;
- fprintf_unfiltered (gdb_stdlog, "infrun: stopped by watchpoint\n");
+ case stopped_by_watchpoint_no:
+ break;
- if (target_stopped_data_address (¤t_target, &addr))
- fprintf_unfiltered (gdb_stdlog,
- "infrun: stopped data address = %s\n",
- paddress (gdbarch, addr));
- else
- fprintf_unfiltered (gdb_stdlog,
- "infrun: (no data address available)\n");
+ case stopped_by_watchpoint_yes_address_unknown:
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: stopped by watchpoint\n"
+ "infrun: (no data address available)\n");
+ break;
+
+ case stopped_by_watchpoint_yes_address_known:
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: stopped by watchpoint\n"
+ "infrun: stopped data address = %s\n",
+ paddress (gdbarch, data_address));
+ break;
}
}
@@ -3099,7 +3106,7 @@ targets should add new threads to the thread list themselves in non-stop mode.")
if (stepped_after_stopped_by_watchpoint)
stopped_by_watchpoint = 0;
else
- stopped_by_watchpoint = watchpoints_triggered (&ecs->ws);
+ stopped_by_watchpoint = watchpoints_triggered (ecs->ptid);
/* If necessary, step over this watchpoint. We'll be back to display
it in a moment. */
--- a/gdb/mips-linux-nat.c
+++ b/gdb/mips-linux-nat.c
@@ -708,7 +708,7 @@ mips_linux_can_use_hw_breakpoint (int type, int cnt, int ot)
return (cnt == 0) ? 1 : 0;
}
-/* Target to_stopped_by_watchpoint implementation. Return 1 if
+/* Target deprecated_stopped_by_watchpoint implementation. Return 1 if
stopped by watchpoint. The watchhi R and W bits indicate the watch
register triggered. */
@@ -730,7 +730,7 @@ mips_linux_stopped_by_watchpoint (void)
return 0;
}
-/* Target to_stopped_data_address implementation. Set the address
+/* Target deprecated_stopped_data_address implementation. Set the address
where the watch triggered (if known). Return 1 if the address was
known. */
@@ -1074,8 +1074,8 @@ triggers a breakpoint or watchpoint."),
t->to_can_use_hw_breakpoint = mips_linux_can_use_hw_breakpoint;
t->to_remove_watchpoint = mips_linux_remove_watchpoint;
t->to_insert_watchpoint = mips_linux_insert_watchpoint;
- t->to_stopped_by_watchpoint = mips_linux_stopped_by_watchpoint;
- t->to_stopped_data_address = mips_linux_stopped_data_address;
+ t->deprecated_stopped_by_watchpoint = mips_linux_stopped_by_watchpoint;
+ t->deprecated_stopped_data_address = mips_linux_stopped_data_address;
t->to_region_ok_for_hw_watchpoint = mips_linux_region_ok_for_hw_watchpoint;
t->to_read_description = mips_linux_read_description;
--- a/gdb/nto-procfs.c
+++ b/gdb/nto-procfs.c
@@ -1413,7 +1413,7 @@ init_procfs_ops (void)
procfs_ops.to_remove_hw_breakpoint = procfs_remove_breakpoint;
procfs_ops.to_insert_watchpoint = procfs_insert_hw_watchpoint;
procfs_ops.to_remove_watchpoint = procfs_remove_hw_watchpoint;
- procfs_ops.to_stopped_by_watchpoint = procfs_stopped_by_watchpoint;
+ procfs_ops.deprecated_stopped_by_watchpoint = procfs_stopped_by_watchpoint;
procfs_ops.to_terminal_init = terminal_init_inferior;
procfs_ops.to_terminal_inferior = terminal_inferior;
procfs_ops.to_terminal_ours_for_output = terminal_ours_for_output;
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1397,26 +1397,20 @@ ppc_linux_new_thread (ptid_t ptid)
ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value);
}
-static int
-ppc_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
+static enum stopped_by_watchpoint
+ppc_linux_thread_stopped_by_watchpoint (ptid_t ptid, CORE_ADDR *data_address_p)
{
struct siginfo *siginfo_p;
- siginfo_p = linux_nat_get_siginfo (inferior_ptid);
+ siginfo_p = linux_nat_get_siginfo (ptid);
if (siginfo_p->si_signo != SIGTRAP
|| (siginfo_p->si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
- return 0;
+ return stopped_by_watchpoint_no;
- *addr_p = (CORE_ADDR) (uintptr_t) siginfo_p->si_addr;
- return 1;
-}
-
-static int
-ppc_linux_stopped_by_watchpoint (void)
-{
- CORE_ADDR addr;
- return ppc_linux_stopped_data_address (¤t_target, &addr);
+ if (data_address_p)
+ *data_address_p = (uintptr_t) siginfo_p->si_addr;
+ return stopped_by_watchpoint_yes_address_known;
}
static int
@@ -1648,8 +1642,7 @@ _initialize_ppc_linux_nat (void)
t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
t->to_insert_watchpoint = ppc_linux_insert_watchpoint;
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_thread_stopped_by_watchpoint = ppc_linux_thread_stopped_by_watchpoint;
t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
t->to_read_description = ppc_linux_read_description;
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -5390,7 +5390,7 @@ procfs_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
void
procfs_use_watchpoints (struct target_ops *t)
{
- t->to_stopped_by_watchpoint = procfs_stopped_by_watchpoint;
+ t->deprecated_stopped_by_watchpoint = procfs_stopped_by_watchpoint;
t->to_insert_watchpoint = procfs_insert_watchpoint;
t->to_remove_watchpoint = procfs_remove_watchpoint;
t->to_region_ok_for_hw_watchpoint = procfs_region_ok_for_hw_watchpoint;
--- a/gdb/remote-m32r-sdi.c
+++ b/gdb/remote-m32r-sdi.c
@@ -1625,8 +1625,8 @@ init_m32r_ops (void)
m32r_ops.to_can_use_hw_breakpoint = m32r_can_use_hw_watchpoint;
m32r_ops.to_insert_watchpoint = m32r_insert_watchpoint;
m32r_ops.to_remove_watchpoint = m32r_remove_watchpoint;
- m32r_ops.to_stopped_by_watchpoint = m32r_stopped_by_watchpoint;
- m32r_ops.to_stopped_data_address = m32r_stopped_data_address;
+ m32r_ops.deprecated_stopped_by_watchpoint = m32r_stopped_by_watchpoint;
+ m32r_ops.deprecated_stopped_data_address = m32r_stopped_data_address;
m32r_ops.to_kill = m32r_kill;
m32r_ops.to_load = m32r_load;
m32r_ops.to_create_inferior = m32r_create_inferior;
--- a/gdb/remote-mips.c
+++ b/gdb/remote-mips.c
@@ -3345,7 +3345,7 @@ _initialize_remote_mips (void)
mips_ops.to_remove_breakpoint = mips_remove_breakpoint;
mips_ops.to_insert_watchpoint = mips_insert_watchpoint;
mips_ops.to_remove_watchpoint = mips_remove_watchpoint;
- mips_ops.to_stopped_by_watchpoint = mips_stopped_by_watchpoint;
+ mips_ops.deprecated_stopped_by_watchpoint = mips_stopped_by_watchpoint;
mips_ops.to_can_use_hw_breakpoint = mips_can_use_watchpoint;
mips_ops.to_kill = mips_kill;
mips_ops.to_load = mips_load;
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -8798,8 +8798,8 @@ Specify the serial device it is connected to\n\
remote_ops.to_files_info = remote_files_info;
remote_ops.to_insert_breakpoint = remote_insert_breakpoint;
remote_ops.to_remove_breakpoint = remote_remove_breakpoint;
- remote_ops.to_stopped_by_watchpoint = remote_stopped_by_watchpoint;
- remote_ops.to_stopped_data_address = remote_stopped_data_address;
+ remote_ops.deprecated_stopped_by_watchpoint = remote_stopped_by_watchpoint;
+ remote_ops.deprecated_stopped_data_address = remote_stopped_data_address;
remote_ops.to_can_use_hw_breakpoint = remote_check_watch_resources;
remote_ops.to_insert_hw_breakpoint = remote_insert_hw_breakpoint;
remote_ops.to_remove_hw_breakpoint = remote_remove_hw_breakpoint;
--- a/gdb/s390-nat.c
+++ b/gdb/s390-nat.c
@@ -253,35 +253,42 @@ struct watch_area
static struct watch_area *watch_base = NULL;
-static int
-s390_stopped_by_watchpoint (void)
+static enum stopped_by_watchpoint
+s390_thread_stopped_by_watchpoint (ptid_t ptid, CORE_ADDR *data_address_p)
{
per_lowcore_bits per_lowcore;
ptrace_area parea;
int result;
+ int tid;
/* Speed up common case. */
if (!watch_base)
- return 0;
+ return stopped_by_watchpoint_no;
+
+ tid = TIDGET (ptid);
+ if (tid == 0)
+ tid = PIDGET (ptid);
parea.len = sizeof (per_lowcore);
parea.process_addr = (addr_t) & per_lowcore;
parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore);
- if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0)
+ if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea) < 0)
perror_with_name (_("Couldn't retrieve watchpoint status"));
result = (per_lowcore.perc_storage_alteration == 1
&& per_lowcore.perc_store_real_address == 0);
+ /* FIXME: To be done only in s390_remove_watchpoint. */
if (result)
{
/* Do not report this watchpoint again. */
memset (&per_lowcore, 0, sizeof (per_lowcore));
- if (ptrace (PTRACE_POKEUSR_AREA, s390_inferior_tid (), &parea) < 0)
+ if (ptrace (PTRACE_POKEUSR_AREA, tid, &parea) < 0)
perror_with_name (_("Couldn't clear watchpoint status"));
}
- return result;
+ return result ? stopped_by_watchpoint_yes_address_unknown
+ : stopped_by_watchpoint_no;
}
static void
@@ -408,7 +415,7 @@ _initialize_s390_nat (void)
t->to_can_use_hw_breakpoint = s390_can_use_hw_breakpoint;
t->to_region_ok_for_hw_watchpoint = s390_region_ok_for_hw_watchpoint;
t->to_have_continuable_watchpoint = 1;
- t->to_stopped_by_watchpoint = s390_stopped_by_watchpoint;
+ t->to_thread_stopped_by_watchpoint = s390_thread_stopped_by_watchpoint;
t->to_insert_watchpoint = s390_insert_watchpoint;
t->to_remove_watchpoint = s390_remove_watchpoint;
--- a/gdb/score-tdep.c
+++ b/gdb/score-tdep.c
@@ -70,7 +70,7 @@ score_stopped_by_watch (void)
{
if (strcmp (current_target.to_shortname, "sim") == 0)
return soc_gh_stopped_by_watch ();
- return (*current_target.to_stopped_by_watchpoint) ();
+ return (*current_target.deprecated_stopped_by_watchpoint) ();
}
int
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -124,10 +124,6 @@ static int debug_to_insert_watchpoint (CORE_ADDR, int, int);
static int debug_to_remove_watchpoint (CORE_ADDR, int, int);
-static int debug_to_stopped_by_watchpoint (void);
-
-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);
@@ -622,10 +618,9 @@ update_current_target (void)
INHERIT (to_remove_hw_breakpoint, t);
INHERIT (to_insert_watchpoint, t);
INHERIT (to_remove_watchpoint, t);
- INHERIT (to_stopped_data_address, t);
INHERIT (to_have_steppable_watchpoint, t);
INHERIT (to_have_continuable_watchpoint, t);
- INHERIT (to_stopped_by_watchpoint, t);
+ /* Do not inherit to_thread_stopped_by_watchpoint. */
INHERIT (to_watchpoint_addr_within_range, t);
INHERIT (to_region_ok_for_hw_watchpoint, t);
INHERIT (to_terminal_init, t);
@@ -733,12 +728,6 @@ update_current_target (void)
de_fault (to_remove_watchpoint,
(int (*) (CORE_ADDR, int, int))
return_minus_one);
- de_fault (to_stopped_by_watchpoint,
- (int (*) (void))
- return_zero);
- 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,
@@ -2207,6 +2196,79 @@ target_mourn_inferior (void)
"could not find a target to follow mourn inferiour");
}
+enum stopped_by_watchpoint
+target_thread_stopped_by_watchpoint (ptid_t ptid, CORE_ADDR *data_address_p)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ {
+ enum stopped_by_watchpoint retval;
+
+ if (t->to_thread_stopped_by_watchpoint != NULL)
+ retval = t->to_thread_stopped_by_watchpoint (ptid, data_address_p);
+ /* Deprecated. */
+ else if (t->deprecated_stopped_by_watchpoint != NULL)
+ {
+ CORE_ADDR data_address;
+ struct cleanup *old_chain = save_inferior_ptid ();
+
+ inferior_ptid = ptid;
+
+ if (!t->deprecated_stopped_by_watchpoint ())
+ retval = stopped_by_watchpoint_no;
+ else if (t->deprecated_stopped_data_address == NULL
+ || !t->deprecated_stopped_data_address (t, &data_address))
+ retval = stopped_by_watchpoint_yes_address_unknown;
+ else
+ {
+ retval = stopped_by_watchpoint_yes_address_known;
+ if (data_address_p)
+ *data_address_p = data_address;
+ }
+
+ do_cleanups (old_chain);
+ }
+ else
+ continue;
+
+ if (targetdebug)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "target_thread_stopped_by_watchpoint (");
+ if (TIDGET (ptid) != 0)
+ fprintf_unfiltered (gdb_stdlog, "TID %ld", TIDGET (ptid));
+ else
+ fprintf_unfiltered (gdb_stdlog, "PID %d", PIDGET (ptid));
+ fprintf_unfiltered (gdb_stdlog, ") = ");
+ switch (retval)
+ {
+ case stopped_by_watchpoint_no:
+ fprintf_unfiltered (gdb_stdlog, "stopped_by_watchpoint_no");
+ break;
+ case stopped_by_watchpoint_yes_address_unknown:
+ fprintf_unfiltered (gdb_stdlog,
+ "stopped_by_watchpoint_yes_address_unknown");
+ break;
+ case stopped_by_watchpoint_yes_address_known:
+ fprintf_unfiltered (gdb_stdlog,
+ "stopped_by_watchpoint_yes_address_known ");
+ if (data_address_p)
+ fprintf_unfiltered (gdb_stdlog, "(%s)",
+ paddress (target_gdbarch, *data_address_p));
+ else
+ fprintf_unfiltered (gdb_stdlog, "<NULL>");
+ break;
+ }
+ fprintf_unfiltered (gdb_stdlog, "\n");
+ }
+
+ return retval;
+ }
+
+ return stopped_by_watchpoint_no;
+}
+
/* Look for a target which can describe architectural features, starting
from TARGET. If we find one, return its description. */
@@ -3074,33 +3136,6 @@ debug_to_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
}
static int
-debug_to_stopped_by_watchpoint (void)
-{
- int retval;
-
- retval = debug_target.to_stopped_by_watchpoint ();
-
- fprintf_unfiltered (gdb_stdlog,
- "target_stopped_by_watchpoint () = %ld\n",
- (unsigned long) retval);
- return retval;
-}
-
-static int
-debug_to_stopped_data_address (struct target_ops *target, CORE_ADDR *addr)
-{
- int retval;
-
- retval = debug_target.to_stopped_data_address (target, addr);
-
- fprintf_unfiltered (gdb_stdlog,
- "target_stopped_data_address ([0x%lx]) = %ld\n",
- (unsigned long)*addr,
- (unsigned long)retval);
- return retval;
-}
-
-static int
debug_to_watchpoint_addr_within_range (struct target_ops *target,
CORE_ADDR addr,
CORE_ADDR start, int length)
@@ -3420,8 +3455,6 @@ setup_target_debug (void)
current_target.to_remove_hw_breakpoint = debug_to_remove_hw_breakpoint;
current_target.to_insert_watchpoint = debug_to_insert_watchpoint;
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;
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -395,10 +395,14 @@ struct target_ops
int (*to_remove_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
int (*to_remove_watchpoint) (CORE_ADDR, int, int);
int (*to_insert_watchpoint) (CORE_ADDR, int, int);
- int (*to_stopped_by_watchpoint) (void);
+ enum stopped_by_watchpoint (*to_thread_stopped_by_watchpoint)
+ (ptid_t ptid, CORE_ADDR *data_address_p);
+ /* Deprecated, to be replaced by to_thread_stopped_by_watchpoint. */
+ int (*deprecated_stopped_by_watchpoint) (void);
+ /* Deprecated, to be replaced by to_thread_stopped_by_watchpoint. */
+ int (*deprecated_stopped_data_address) (struct target_ops *, CORE_ADDR *);
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);
@@ -1126,8 +1130,15 @@ extern char *normal_pid_to_str (ptid_t ptid);
/* Returns non-zero if we were stopped by a hardware watchpoint (memory read or
write). */
-#define target_stopped_by_watchpoint \
- (*current_target.to_stopped_by_watchpoint)
+enum stopped_by_watchpoint
+ {
+ stopped_by_watchpoint_no,
+ stopped_by_watchpoint_yes_address_unknown,
+ stopped_by_watchpoint_yes_address_known
+ };
+
+extern enum stopped_by_watchpoint target_thread_stopped_by_watchpoint
+ (ptid_t ptid, CORE_ADDR *data_address_p);
/* Non-zero if we have steppable watchpoints */
@@ -1172,9 +1183,6 @@ extern char *normal_pid_to_str (ptid_t ptid);
#define target_remove_hw_breakpoint(gdbarch, bp_tgt) \
(*current_target.to_remove_hw_breakpoint) (gdbarch, bp_tgt)
-#define target_stopped_data_address(target, x) \
- (*target.to_stopped_data_address) (target, x)
-
#define target_watchpoint_addr_within_range(target, addr, start, length) \
(*target.to_watchpoint_addr_within_range) (target, addr, start, length)
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -143,7 +143,7 @@ static void windows_kill_inferior (struct target_ops *);
static void cygwin_set_dr (int i, CORE_ADDR addr);
static void cygwin_set_dr7 (unsigned long val);
-static unsigned long cygwin_get_dr6 (void);
+static unsigned long cygwin_get_dr6 (ptid_t ptid);
static enum target_signal last_sig = TARGET_SIGNAL_0;
/* Set if a signal was received from the debugged process */
@@ -2313,7 +2313,7 @@ cygwin_set_dr7 (unsigned long val)
Here we just return the value stored in dr[6]
by the last call to thread_rec for current_event.dwThreadId id. */
static unsigned long
-cygwin_get_dr6 (void)
+cygwin_get_dr6 (ptid_t ptid)
{
return (unsigned long) dr[6];
}