From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 839 invoked by alias); 12 Oct 2009 16:00:12 -0000 Received: (qmail 656 invoked by uid 22791); 12 Oct 2009 16:00:03 -0000 X-SWARE-Spam-Status: No, hits=-1.5 required=5.0 tests=AWL,BAYES_20,SPF_HELO_PASS,SPF_PASS X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 12 Oct 2009 15:59:51 +0000 Received: from int-mx08.intmail.prod.int.phx2.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id n9CFxRpB017210; Mon, 12 Oct 2009 11:59:27 -0400 Received: from host0.dyn.jankratochvil.net (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx08.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id n9CFxLvR015010 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Mon, 12 Oct 2009 11:59:25 -0400 Received: from host0.dyn.jankratochvil.net (localhost [127.0.0.1]) by host0.dyn.jankratochvil.net (8.14.3/8.14.3) with ESMTP id n9CFxKMt020222; Mon, 12 Oct 2009 17:59:20 +0200 Received: (from jkratoch@localhost) by host0.dyn.jankratochvil.net (8.14.3/8.14.3/Submit) id n9CFxH3x020217; Mon, 12 Oct 2009 17:59:17 +0200 Date: Mon, 12 Oct 2009 16:00:00 -0000 From: Jan Kratochvil To: Joel Brobecker Cc: gdb-patches@sourceware.org Subject: Re: [patch 2/4] Fix hw watchpoints: reordered / simultaneously hit [fixup #1] Message-ID: <20091012155916.GA20031@host0.dyn.jankratochvil.net> References: <20090817194612.GC10694@host0.dyn.jankratochvil.net> <20091002221254.GA7767@host0.dyn.jankratochvil.net> <20091002230124.GG10338@adacore.com> <20091003172302.GD26203@host0.dyn.jankratochvil.net> <20091007183858.GR5689@adacore.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20091007183858.GR5689@adacore.com> User-Agent: Mutt/1.5.20 (2009-08-17) X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2009-10/txt/msg00235.txt.bz2 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 ): 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 ): 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, ""); + 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]; }