From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 22206 invoked by alias); 14 Mar 2010 18:50:59 -0000 Received: (qmail 22196 invoked by uid 22791); 14 Mar 2010 18:50:58 -0000 X-SWARE-Spam-Status: No, hits=-2.5 required=5.0 tests=AWL,BAYES_00 X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (38.113.113.100) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sun, 14 Mar 2010 18:50:54 +0000 Received: (qmail 6635 invoked from network); 14 Mar 2010 18:50:52 -0000 Received: from unknown (HELO orlando.localnet) (pedro@127.0.0.2) by mail.codesourcery.com with ESMTPA; 14 Mar 2010 18:50:52 -0000 From: Pedro Alves To: gdb-patches@sourceware.org Subject: Fix watchthreads-reorder.exp fails in linux gdbserver Date: Sun, 14 Mar 2010 18:50:00 -0000 User-Agent: KMail/1.12.2 (Linux/2.6.31-19-generic; KDE/4.3.2; x86_64; ; ) MIME-Version: 1.0 Content-Type: Text/Plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Message-Id: <201003141850.49563.pedro@codesourcery.com> 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: 2010-03/txt/msg00501.txt.bz2 I've applied the patch below, to address in linux gdbserver the problem watchthreads-reorder.exp uncovers, similarly to how it was fixed in linux-nat.c. Fixes: -FAIL: gdb.threads/watchthreads-reorder.exp: reorder1: continue b +PASS: gdb.threads/watchthreads-reorder.exp: reorder1: continue b -- Pedro Alves 2010-03-14 Pedro Alves gdb/gdbserver/ * linux-low.h (struct lwp_info): New fields `stopped_by_watchpoint' and `stopped_data_address'. * linux-low.c (linux_wait_for_lwp): Check for watchpoint triggers here, and cache them in the lwp object. (wait_for_sigstop): Check stopped_by_watchpoint lwp field directly. (linux_resume_one_lwp): Clear the lwp's stopped_by_watchpoint field. (linux_stopped_by_watchpoint): Rewrite. (linux_stopped_data_address): Rewrite. --- gdb/gdbserver/linux-low.c | 62 +++++++++++++++++++++++++++++++++++++++------- gdb/gdbserver/linux-low.h | 10 +++++++ 2 files changed, 63 insertions(+), 9 deletions(-) Index: src/gdb/gdbserver/linux-low.c =================================================================== --- src.orig/gdb/gdbserver/linux-low.c 2010-03-14 18:31:41.000000000 +0000 +++ src/gdb/gdbserver/linux-low.c 2010-03-14 18:40:46.000000000 +0000 @@ -1062,6 +1062,51 @@ retry: new_inferior = 0; } + /* Fetch the possibly triggered data watchpoint info and store it in + CHILD. + + 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 CHILD stop with a SIGTRAP. If GDB + changes the debug registers meanwhile, we have the cached data we + can rely on. */ + + if (WIFSTOPPED (*wstatp) && WSTOPSIG (*wstatp) == SIGTRAP) + { + if (the_low_target.stopped_by_watchpoint == NULL) + { + child->stopped_by_watchpoint = 0; + } + else + { + struct thread_info *saved_inferior; + + saved_inferior = current_inferior; + current_inferior = get_lwp_thread (child); + + child->stopped_by_watchpoint + = the_low_target.stopped_by_watchpoint (); + + if (child->stopped_by_watchpoint) + { + if (the_low_target.stopped_data_address != NULL) + child->stopped_data_address + = the_low_target.stopped_data_address (); + else + child->stopped_data_address = 0; + } + + current_inferior = saved_inferior; + } + } + if (debug_threads && WIFSTOPPED (*wstatp) && the_low_target.get_pc != NULL) @@ -1724,7 +1769,7 @@ wait_for_sigstop (struct inferior_list_e signal. */ if (WSTOPSIG (wstat) == SIGTRAP && lwp->stepping - && !linux_stopped_by_watchpoint ()) + && !lwp->stopped_by_watchpoint) { if (debug_threads) fprintf (stderr, " single-step SIGTRAP ignored\n"); @@ -1878,6 +1923,7 @@ linux_resume_one_lwp (struct lwp_info *l get_lwp_thread (lwp)); errno = 0; lwp->stopped = 0; + lwp->stopped_by_watchpoint = 0; lwp->stepping = step; ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, lwpid_of (lwp), 0, /* Coerce to a uintptr_t first to avoid potential gcc warning @@ -2817,19 +2863,17 @@ linux_remove_point (char type, CORE_ADDR static int linux_stopped_by_watchpoint (void) { - if (the_low_target.stopped_by_watchpoint != NULL) - return the_low_target.stopped_by_watchpoint (); - else - return 0; + struct lwp_info *lwp = get_thread_lwp (current_inferior); + + return lwp->stopped_by_watchpoint; } static CORE_ADDR linux_stopped_data_address (void) { - if (the_low_target.stopped_data_address != NULL) - return the_low_target.stopped_data_address (); - else - return 0; + struct lwp_info *lwp = get_thread_lwp (current_inferior); + + return lwp->stopped_data_address; } #if defined(__UCLIBC__) && defined(HAS_NOMMU) Index: src/gdb/gdbserver/linux-low.h =================================================================== --- src.orig/gdb/gdbserver/linux-low.h 2010-03-14 18:31:41.000000000 +0000 +++ src/gdb/gdbserver/linux-low.h 2010-03-14 18:32:00.000000000 +0000 @@ -161,6 +161,16 @@ struct lwp_info int pending_is_breakpoint; CORE_ADDR pending_stop_pc; + /* STOPPED_BY_WATCHPOINT is non-zero if this LWP stopped with a data + watchpoint trap. */ + int stopped_by_watchpoint; + + /* On architectures where it is possible to know the data address of + a triggered watchpoint, STOPPED_DATA_ADDRESS is non-zero, and + contains such data address. Only valid if STOPPED_BY_WATCHPOINT + is true. */ + CORE_ADDR stopped_data_address; + /* If this is non-zero, it is a breakpoint to be reinserted at our next stop (SIGTRAP stops only). */ CORE_ADDR bp_reinsert;