From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 28998 invoked by alias); 20 Nov 2009 21:06:52 -0000 Mailing-List: contact archer-commits-help@sourceware.org; run by ezmlm Sender: Precedence: bulk List-Post: List-Help: List-Subscribe: Received: (qmail 28968 invoked by uid 9674); 20 Nov 2009 21:06:51 -0000 Date: Fri, 20 Nov 2009 21:06:00 -0000 Message-ID: <20091120210651.28953.qmail@sourceware.org> From: jkratoch@sourceware.org To: archer-commits@sourceware.org Subject: [SCM] master: Merge remote branch 'gdb/master' X-Git-Refname: refs/heads/master X-Git-Reftype: branch X-Git-Oldrev: deab07c7cb44665e00edee54058070bb44822761 X-Git-Newrev: b36cedcbca4e38c1ec982db3727d8f39815d0005 X-SW-Source: 2009-q4/txt/msg00065.txt.bz2 List-Id: The branch, master has been updated via b36cedcbca4e38c1ec982db3727d8f39815d0005 (commit) via 7aee9d0d66a4c21f081f04a72dec87175393fc56 (commit) via ec27fce19a16df73e763281ce3a6d0cdb718174e (commit) via 6dd3967cc8e96057ec06b85b027e02e07f69f249 (commit) via 9d711e313e2ff01d2db87196f459bd10ee960b73 (commit) via 7140eec48baabba8bb3b643b2f5969ba8bc59b73 (commit) from deab07c7cb44665e00edee54058070bb44822761 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email. - Log ----------------------------------------------------------------- commit b36cedcbca4e38c1ec982db3727d8f39815d0005 Merge: deab07c7cb44665e00edee54058070bb44822761 7aee9d0d66a4c21f081f04a72dec87175393fc56 Author: Jan Kratochvil Date: Fri Nov 20 22:06:42 2009 +0100 Merge remote branch 'gdb/master' commit 7aee9d0d66a4c21f081f04a72dec87175393fc56 Author: Jan Kratochvil Date: Fri Nov 20 20:01:08 2009 +0000 gdb/ * breakpoint.c (bp_location_compare): Change parameter a to ap and b to bp. New variables a and b. (bp_location_compare_for_qsort): Remove. (update_global_location_list): Use now bp_location_compare. commit ec27fce19a16df73e763281ce3a6d0cdb718174e Author: Jan Kratochvil Date: Fri Nov 20 19:57:28 2009 +0000 gdb/ Fix repeated rwatch output. * amd64-linux-nat.c (amd64_linux_dr_set, amd64_linux_dr_set_control) (amd64_linux_dr_set_addr, amd64_linux_dr_reset_addr) (amd64_linux_dr_get_status): New comments. (amd64_linux_dr_unset_status): New function. (_initialize_amd64_linux_nat): Install it. * 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, i386_linux_dr_get_status): New comments. (i386_linux_dr_unset_status): New function. (_initialize_i386_linux_nat): Install it. * i386-nat.c (I386_DR_WATCH_MASK): New macro. (I386_DR_WATCH_HIT): Use I386_DR_WATCH_MASK. (i386_insert_aligned_watchpoint): Call i386_dr_low.unset_status. * i386-nat.h (struct i386_dr_low_type): Extend comments for set_control, set_addr, reset_addr and get_status. New unset_status. * breakpoint.c (update_watchpoint): Extend the comment. gdb/testsuite/ * gdb.base/watchpoint-hw-hit-once.exp, gdb.base/watchpoint-hw-hit-once.c: New. commit 6dd3967cc8e96057ec06b85b027e02e07f69f249 Author: Pedro Alves Date: Fri Nov 20 19:52:08 2009 +0000 gdb/ 2009-11-20 Jan Kratochvil Pedro Alves Fix reordered watchpoints triggered in other threads during all-stop. * linux-nat.c (resume_callback, linux_nat_resume): Clear stopped_by_watchpoint. (save_sigtrap, linux_nat_stopped_by_watchpoint) (linux_nat_stopped_data_address): New. (stop_wait_callback, linux_nat_filter_event): Call save_sigtrap. (linux_nat_add_target): Install linux_nat_stopped_by_watchpoint and linux_nat_stopped_data_address. * linux-nat.h (struct lwp_info): New fields stopped_by_watchpoint, stopped_data_address_p and stopped_data_address. gdb/testsuite/ 2009-11-20 Jan Kratochvil * gdb.base/watchthreads-reorder.exp, gdb.base/watchthreads-reorder.c: New. commit 9d711e313e2ff01d2db87196f459bd10ee960b73 Author: Pedro Alves Date: Fri Nov 20 19:48:45 2009 +0000 gdb/ 2009-11-20 Jan Kratochvil Pedro Alves Fix reordered watchpoints triggered in other threads during all-stop. * linux-nat.c (resume_callback, linux_nat_resume): Clear stopped_by_watchpoint. (save_sigtrap, linux_nat_stopped_by_watchpoint) (linux_nat_stopped_data_address): New. (stop_wait_callback, linux_nat_filter_event): Call save_sigtrap. (linux_nat_add_target): Install linux_nat_stopped_by_watchpoint and linux_nat_stopped_data_address. * linux-nat.h (struct lwp_info): New fields stopped_by_watchpoint, stopped_data_address_p and stopped_data_address. gdb/testsuite/ 2009-11-20 Jan Kratochvil * gdb.base/watchthreads-reorder.exp, gdb.base/watchthreads-reorder.c: New. commit 7140eec48baabba8bb3b643b2f5969ba8bc59b73 Author: Michael Snyder Date: Fri Nov 20 17:23:38 2009 +0000 2009-10-25 Michael Snyder * target.h (struct target_ops): New methods to_get_bookmark and to_goto_bookmark. (target_get_bookmark): New macro. (target_goto_bookmark): New macro. * target.c (dummy_get_bookmark): New function, default implementation. (dummy_goto_bookmark): New function, default implementation. (update_current_target): Inherit new methods. * record.c (record_get_bookmark): New function. (record_goto_bookmark): New function. (init_record_ops): Set to_get_bookmark and to_goto_bookmark methods. * reverse.c (struct bookmark): New type. (save_bookmark_command): New function (command). (delete_bookmark_command): New function (command). (goto_bookmark_command): New function (command). (bookmarks_info): New function (command). (_initialize_reverse): Add new bookmark commands. * command.h (enum command_class): Add class_bookmark. * NEWS: Mention bookmark commands. ----------------------------------------------------------------------- Summary of changes: gdb/ChangeLog | 63 ++++ gdb/amd64-linux-nat.c | 30 ++ gdb/breakpoint.c | 62 +++- gdb/command.h | 4 +- gdb/i386-linux-nat.c | 31 ++ gdb/i386-nat.c | 9 +- gdb/i386-nat.h | 12 +- gdb/linux-nat.c | 82 +++++- gdb/linux-nat.h | 12 + gdb/record.c | 157 +++++++++ gdb/reverse.c | 235 +++++++++++++ gdb/target.c | 19 + gdb/target.h | 14 +- gdb/testsuite/ChangeLog | 10 + gdb/testsuite/gdb.base/watchpoint-hw-hit-once.c | 34 ++ gdb/testsuite/gdb.base/watchpoint-hw-hit-once.exp | 43 +++ gdb/testsuite/gdb.threads/watchthreads-reorder.c | 369 ++++++++++++++++++++ gdb/testsuite/gdb.threads/watchthreads-reorder.exp | 103 ++++++ 18 files changed, 1264 insertions(+), 25 deletions(-) create mode 100644 gdb/testsuite/gdb.base/watchpoint-hw-hit-once.c create mode 100644 gdb/testsuite/gdb.base/watchpoint-hw-hit-once.exp create mode 100644 gdb/testsuite/gdb.threads/watchthreads-reorder.c create mode 100644 gdb/testsuite/gdb.threads/watchthreads-reorder.exp First 500 lines of diff: diff --git a/gdb/ChangeLog b/gdb/ChangeLog index a89482d..a74e149 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,66 @@ +2009-11-20 Jan Kratochvil + + * breakpoint.c (bp_location_compare): Change parameter a to ap and b to + bp. New variables a and b. + (bp_location_compare_for_qsort): Remove. + (update_global_location_list): Use now bp_location_compare. + +2009-11-20 Jan Kratochvil + + Fix repeated rwatch output. + * amd64-linux-nat.c (amd64_linux_dr_set, amd64_linux_dr_set_control) + (amd64_linux_dr_set_addr, amd64_linux_dr_reset_addr) + (amd64_linux_dr_get_status): New comments. + (amd64_linux_dr_unset_status): New function. + (_initialize_amd64_linux_nat): Install it. + * 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, i386_linux_dr_get_status): New comments. + (i386_linux_dr_unset_status): New function. + (_initialize_i386_linux_nat): Install it. + * i386-nat.c (I386_DR_WATCH_MASK): New macro. + (I386_DR_WATCH_HIT): Use I386_DR_WATCH_MASK. + (i386_insert_aligned_watchpoint): Call i386_dr_low.unset_status. + * i386-nat.h (struct i386_dr_low_type): Extend comments for + set_control, set_addr, reset_addr and get_status. New unset_status. + * breakpoint.c (update_watchpoint): Extend the comment. + +2009-11-20 Jan Kratochvil + Pedro Alves + + Fix reordered watchpoints triggered in other threads during all-stop. + + * linux-nat.c (resume_callback, linux_nat_resume): Clear + stopped_by_watchpoint. + (save_sigtrap, linux_nat_stopped_by_watchpoint) + (linux_nat_stopped_data_address): New. + (stop_wait_callback, linux_nat_filter_event): Call save_sigtrap. + (linux_nat_add_target): Install linux_nat_stopped_by_watchpoint + and linux_nat_stopped_data_address. + * linux-nat.h (struct lwp_info): New fields stopped_by_watchpoint, + stopped_data_address_p and stopped_data_address. + +2009-11-20 Michael Snyder + + * target.h (struct target_ops): New methods to_get_bookmark + and to_goto_bookmark. + (target_get_bookmark): New macro. + (target_goto_bookmark): New macro. + * target.c (dummy_get_bookmark): New function, default implementation. + (dummy_goto_bookmark): New function, default implementation. + (update_current_target): Inherit new methods. + * record.c (record_get_bookmark): New function. + (record_goto_bookmark): New function. + (init_record_ops): Set to_get_bookmark and to_goto_bookmark methods. + * reverse.c (struct bookmark): New type. + (save_bookmark_command): New function (command). + (delete_bookmark_command): New function (command). + (goto_bookmark_command): New function (command). + (bookmarks_info): New function (command). + (_initialize_reverse): Add new bookmark commands. + * command.h (enum command_class): Add class_bookmark. + * NEWS: Mention bookmark commands. + 2009-11-20 Pedro Alves * breakpoint.c (update_global_location_list): Fix duplicate diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c index 7d8461c..9ccd3b2 100644 --- 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,18 +316,41 @@ 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 of INFERIOR_PTID. */ + static unsigned long amd64_linux_dr_get_status (void) { return amd64_linux_dr_get (inferior_ptid, DR_STATUS); } +/* Unset MASK bits in DR_STATUS in all LWPs of LWP_LIST. */ + +static void +amd64_linux_dr_unset_status (unsigned long mask) +{ + struct lwp_info *lp; + ptid_t ptid; + + ALL_LWPS (lp, ptid) + { + unsigned long value; + + value = amd64_linux_dr_get (ptid, DR_STATUS); + value &= ~mask; + amd64_linux_dr_set (ptid, DR_STATUS, value); + } +} + + static void amd64_linux_new_thread (ptid_t ptid) { @@ -672,6 +701,7 @@ _initialize_amd64_linux_nat (void) i386_dr_low.set_addr = amd64_linux_dr_set_addr; i386_dr_low.reset_addr = amd64_linux_dr_reset_addr; i386_dr_low.get_status = amd64_linux_dr_get_status; + i386_dr_low.unset_status = amd64_linux_dr_unset_status; i386_set_debug_register_length (8); /* Override the GNU/Linux inferior startup hook. */ diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 4849d8f..bca923e 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -993,7 +993,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) { @@ -8073,15 +8112,17 @@ breakpoint_auto_delete (bpstat bs) } } -/* A comparison function for bp_location A and B being interfaced to qsort. +/* A comparison function for bp_location AP and BP being interfaced to qsort. Sort elements primarily by their ADDRESS (no matter what does breakpoint_address_is_meaningful say for its OWNER), secondarily by ordering first bp_permanent OWNERed elements and terciarily just ensuring the array is sorted stable way despite qsort being an instable algorithm. */ static int -bp_location_compare (struct bp_location *a, struct bp_location *b) +bp_location_compare (const void *ap, const void *bp) { + struct bp_location *a = *(void **) ap; + struct bp_location *b = *(void **) bp; int a_perm = a->owner->enable_state == bp_permanent; int b_perm = b->owner->enable_state == bp_permanent; @@ -8102,17 +8143,6 @@ bp_location_compare (struct bp_location *a, struct bp_location *b) return (a > b) - (a < b); } -/* Interface bp_location_compare as the COMPAR parameter of qsort function. */ - -static int -bp_location_compare_for_qsort (const void *ap, const void *bp) -{ - struct bp_location *a = *(void **) ap; - struct bp_location *b = *(void **) bp; - - return bp_location_compare (a, b); -} - /* Set bp_location_placed_address_before_address_max and bp_location_shadow_len_after_address_max according to the current content of the bp_location array. */ @@ -8196,7 +8226,7 @@ update_global_location_list (int should_insert) for (loc = b->loc; loc; loc = loc->next) *locp++ = loc; qsort (bp_location, bp_location_count, sizeof (*bp_location), - bp_location_compare_for_qsort); + bp_location_compare); bp_location_target_extensions_update (); @@ -10142,6 +10172,8 @@ is prefixed with \"server \".\n\n\ Convenience variable \"$bpnum\" contains the number of the last\n\ breakpoint set.")); + add_info_alias ("b", "breakpoints", 1); + if (xdb_commands) add_com ("lb", class_breakpoint, breakpoints_info, _("\ Status of user-settable breakpoints, or breakpoint number NUMBER.\n\ diff --git a/gdb/command.h b/gdb/command.h index 1a6bec4..8d9f0ca 100644 --- a/gdb/command.h +++ b/gdb/command.h @@ -32,8 +32,8 @@ enum command_class /* Classes of commands */ no_class = -1, class_run = 0, class_vars, class_stack, class_files, class_support, class_info, class_breakpoint, class_trace, - class_alias, class_obscure, class_user, class_maintenance, - class_pseudo, class_tui, class_xdb + class_alias, class_bookmark, class_obscure, class_maintenance, + class_pseudo, class_tui, class_user, class_xdb }; /* FIXME: cagney/2002-03-17: Once cmd_type() has been removed, ``enum diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c index fe848ff..186a2fd 100644 --- 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,18 +662,40 @@ 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 of INFERIOR_PTID. */ + static unsigned long i386_linux_dr_get_status (void) { return i386_linux_dr_get (inferior_ptid, DR_STATUS); } +/* Unset MASK bits in DR_STATUS in all LWPs of LWP_LIST. */ + +static void +i386_linux_dr_unset_status (unsigned long mask) +{ + struct lwp_info *lp; + ptid_t ptid; + + ALL_LWPS (lp, ptid) + { + unsigned long value; + + value = i386_linux_dr_get (ptid, DR_STATUS); + value &= ~mask; + i386_linux_dr_set (ptid, DR_STATUS, value); + } +} + static void i386_linux_new_thread (ptid_t ptid) { @@ -837,6 +867,7 @@ _initialize_i386_linux_nat (void) i386_dr_low.set_addr = i386_linux_dr_set_addr; i386_dr_low.reset_addr = i386_linux_dr_reset_addr; i386_dr_low.get_status = i386_linux_dr_get_status; + i386_dr_low.unset_status = i386_linux_dr_unset_status; i386_set_debug_register_length (4); /* Override the default ptrace resume method. */ diff --git a/gdb/i386-nat.c b/gdb/i386-nat.c index eb16687..edb78bf 100644 --- a/gdb/i386-nat.c +++ b/gdb/i386-nat.c @@ -137,8 +137,11 @@ struct i386_dr_low_type i386_dr_low; #define I386_DR_GET_RW_LEN(i) \ ((dr_control_mirror >> (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (i))) & 0x0f) +/* Mask that this I'th watchpoint has triggered. */ +#define I386_DR_WATCH_MASK(i) (1 << (i)) + /* Did the watchpoint whose address is in the I'th register break? */ -#define I386_DR_WATCH_HIT(i) (dr_status_mirror & (1 << (i))) +#define I386_DR_WATCH_HIT(i) (dr_status_mirror & I386_DR_WATCH_MASK (i)) /* A macro to loop over all debug registers. */ #define ALL_DEBUG_REGISTERS(i) for (i = 0; i < DR_NADDR; i++) @@ -358,6 +361,10 @@ i386_insert_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits) i386_dr_low.set_addr (i, addr); i386_dr_low.set_control (dr_control_mirror); + /* Only a sanity check for leftover bits (set possibly only by inferior). */ + if (i386_dr_low.unset_status) + i386_dr_low.unset_status (I386_DR_WATCH_MASK (i)); + return 0; } diff --git a/gdb/i386-nat.h b/gdb/i386-nat.h index f49b9f6..892a804 100644 --- a/gdb/i386-nat.h +++ b/gdb/i386-nat.h @@ -49,16 +49,19 @@ 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 current LWP + + unset_status -- unset the specified bits of the debug + status (DR6) register for all LWPs Additionally, the native file should set the debug_register_length field to 4 or 8 depending on the number of bytes used for @@ -70,6 +73,7 @@ struct i386_dr_low_type void (*set_addr) (int, CORE_ADDR); void (*reset_addr) (int); unsigned long (*get_status) (void); + void (*unset_status) (unsigned long); int debug_register_length; }; diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index 95feca6..c0afecd 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -1882,6 +1882,7 @@ resume_callback (struct lwp_info *lp, void *data) lp->stopped = 0; lp->step = 0; memset (&lp->siginfo, 0, sizeof (lp->siginfo)); + lp->stopped_by_watchpoint = 0; } else if (lp->stopped && debug_linux_nat) fprintf_unfiltered (gdb_stdlog, "RC: Not resuming sibling %s (has pending)\n", @@ -2019,6 +2020,7 @@ linux_nat_resume (struct target_ops *ops, linux_ops->to_resume (linux_ops, ptid, step, signo); memset (&lp->siginfo, 0, sizeof (lp->siginfo)); + lp->stopped_by_watchpoint = 0; if (debug_linux_nat) fprintf_unfiltered (gdb_stdlog, @@ -2570,6 +2572,74 @@ maybe_clear_ignore_sigint (struct lwp_info *lp) } } +/* Fetch the possible triggered data watchpoint info and store it in + LP. + + On some archs, like x86, that use debug registers to set + watchpoints, it's possible that the way to know which watched + address trapped, is to check the register that is used to select + which address to watch. Problem is, between setting the watchpoint + and reading back which data address trapped, the user may change + the set of watchpoints, and, as a consequence, GDB changes the + debug registers in the inferior. To avoid reading back a stale + stopped-data-address when that happens, we cache in LP the fact + that a watchpoint trapped, and the corresponding data address, as + soon as we see LP stop with a SIGTRAP. If GDB changes the debug + registers meanwhile, we have the cached data we can rely on. */ + +static void +save_sigtrap (struct lwp_info *lp) +{ + struct cleanup *old_chain; + + if (linux_ops->to_stopped_by_watchpoint == NULL) + { + lp->stopped_by_watchpoint = 0; + return; + } + + old_chain = save_inferior_ptid (); + inferior_ptid = lp->ptid; + + lp->stopped_by_watchpoint = linux_ops->to_stopped_by_watchpoint (); + + if (lp->stopped_by_watchpoint) + { + if (linux_ops->to_stopped_data_address != NULL) + lp->stopped_data_address_p = + linux_ops->to_stopped_data_address (¤t_target, + &lp->stopped_data_address); + else + lp->stopped_data_address_p = 0; + } + + do_cleanups (old_chain); +} + +/* See save_sigtrap. */ + +static int +linux_nat_stopped_by_watchpoint (void) hooks/post-receive -- Repository for Project Archer.