* [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment.
@ 2012-08-06 14:33 Luis Gustavo
2012-08-06 18:40 ` Jan Kratochvil
2012-12-27 19:50 ` Luis Machado
0 siblings, 2 replies; 24+ messages in thread
From: Luis Gustavo @ 2012-08-06 14:33 UTC (permalink / raw)
To: gdb-patches; +Cc: prasad, benh
[-- Attachment #1: Type: text/plain, Size: 1371 bytes --]
Hi,
GDB has always assumed that hardware watchpoints and breakpoints should
be replicated for every new thread in ppc. This worked fine for the old
DABR-based mechanism since both server and embedded ppc's supported only
a single hw watchpoint or breakpoint.
With the somewhat recent booke kernel interface, more hw
watchpoints/breakpoints are available to GDB.
The logic of replicating the existing process' debug state to the new
thread is still there though, but the new booke interface in the kernel
already replicates that state. More precisely, the kernel gives the new
thread the debug state of its parent thread.
When GDB tries to replicate the debug state, it will actually cause the
kernel to allocate a new hw *point entry, leading to inadequate
consumption of hw debug resources.
It's still unclear if the kernel is supposed to do this and i'm chasing
answers with the ppc linux kernel folks
(https://lists.ozlabs.org/pipermail/linuxppc-dev/2012-August/100083.html).
Nonetheless, the kernel is out and it has such behavior.
This patch tries to address this problem by clearing any debug state
prior to replicating *points to the new thread. If the kernel is doing
something it's not supposed to, then this is a workaround for the broken
kernels.
This would be nice to include before 7.5, as it's an annoying problem.
OK?
Regards,
Luis
[-- Attachment #2: 0001-fix_ppc_hw_watch.diff --]
[-- Type: text/x-patch, Size: 1467 bytes --]
2012-08-06 Luis Machado <lgustavo@codesourcery.com>
* ppc-linux-nat.c (ppc_linux_new_thread): Clear the new thread's
debug state prior to replicating existing hardware watchpoints or
breakpoints.
Index: gdb_head/gdb/ppc-linux-nat.c
===================================================================
--- gdb_head.orig/gdb/ppc-linux-nat.c 2012-08-06 11:02:12.538532628 -0300
+++ gdb_head/gdb/ppc-linux-nat.c 2012-08-06 11:04:38.486536320 -0300
@@ -2179,7 +2179,21 @@ ppc_linux_new_thread (struct lwp_info *l
/* Copy that thread's breakpoints and watchpoints to the new thread. */
for (i = 0; i < max_slots_number; i++)
if (hw_breaks[i].hw_break)
- booke_insert_point (hw_breaks[i].hw_break, tid);
+ {
+ /* The ppc Linux kernel causes a thread to inherit its parent
+ thread's debug state, and that includes any hardware
+ watchpoints or breakpoints that the parent thread may have set.
+
+ For this reason, the debug state of the new thread is cleared
+ before trying to replicate any hardware watchpoints or
+ breakpoints contained in other threads. */
+
+ /* The ppc debug resource accounting is done through "slots".
+ Ask the kernel the deallocate this specific *point's slot. */
+ ptrace (PPC_PTRACE_DELHWDEBUG, tid, 0, hw_breaks[i].slot);
+
+ booke_insert_point (hw_breaks[i].hw_break, tid);
+ }
}
else
ptrace (PTRACE_SET_DEBUGREG, tid, 0, saved_dabr_value);
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment. 2012-08-06 14:33 [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment Luis Gustavo @ 2012-08-06 18:40 ` Jan Kratochvil 2012-08-06 19:02 ` Luis Gustavo 2012-12-27 19:50 ` Luis Machado 1 sibling, 1 reply; 24+ messages in thread From: Jan Kratochvil @ 2012-08-06 18:40 UTC (permalink / raw) To: Luis Gustavo; +Cc: gdb-patches, prasad, benh On Mon, 06 Aug 2012 16:33:58 +0200, Luis Gustavo wrote: > With the somewhat recent booke kernel interface, more hw > watchpoints/breakpoints are available to GDB. Which hardware can be BookE tested on? Red Hat has available for example PPC970FX, POWER5, POWER7 etc. but those AFAIK are not BookE. Or does it depend just on kernel? > The logic of replicating the existing process' debug state to the > new thread is still there though, but the new booke interface in the > kernel already replicates that state. More precisely, the kernel > gives the new thread the debug state of its parent thread. I have been testing it recently for fork() (processes, no threads) and my results were: kernel-3.3.4-5.fc17.ppc64 clears debug info in both parent (!) and child kernel-2.6.18-308.el5.ppc64 copies debug info to child and keeps it in parent > It's still unclear if the kernel is supposed to do this and i'm > chasing answers with the ppc linux kernel folks (https://lists.ozlabs.org/pipermail/linuxppc-dev/2012-August/100083.html). > Nonetheless, the kernel is out and it has such behavior. Yes, I agree GDB should cope with all these kinds of behavior. > --- gdb_head.orig/gdb/ppc-linux-nat.c 2012-08-06 11:02:12.538532628 -0300 > +++ gdb_head/gdb/ppc-linux-nat.c 2012-08-06 11:04:38.486536320 -0300 > @@ -2179,7 +2179,21 @@ ppc_linux_new_thread (struct lwp_info *l > /* Copy that thread's breakpoints and watchpoints to the new thread. */ > for (i = 0; i < max_slots_number; i++) > if (hw_breaks[i].hw_break) > - booke_insert_point (hw_breaks[i].hw_break, tid); > + { > + /* The ppc Linux kernel causes a thread to inherit its parent > + thread's debug state, and that includes any hardware > + watchpoints or breakpoints that the parent thread may have set. > + > + For this reason, the debug state of the new thread is cleared > + before trying to replicate any hardware watchpoints or > + breakpoints contained in other threads. */ > + > + /* The ppc debug resource accounting is done through "slots". > + Ask the kernel the deallocate this specific *point's slot. */ > + ptrace (PPC_PTRACE_DELHWDEBUG, tid, 0, hw_breaks[i].slot); > + > + booke_insert_point (hw_breaks[i].hw_break, tid); I agree with the patch. I was considering to call PPC_PTRACE_DELHWDEBUG unconditionally but that would be probably an unneeded overhead. Did you test that kernel really does not reorder the [i] slots during inheritance into the new thread? > + } > } > else > ptrace (PTRACE_SET_DEBUGREG, tid, 0, saved_dabr_value); > This would be nice to include before 7.5, as it's an annoying problem. Does this fix affect existing testcases on BookE? Otherwise a new testcase would be appropriate. Thanks, Jan ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment. 2012-08-06 18:40 ` Jan Kratochvil @ 2012-08-06 19:02 ` Luis Gustavo 2012-08-06 20:28 ` Jan Kratochvil 0 siblings, 1 reply; 24+ messages in thread From: Luis Gustavo @ 2012-08-06 19:02 UTC (permalink / raw) To: Jan Kratochvil; +Cc: gdb-patches, prasad, benh Hi Jan, On 08/06/2012 02:04 PM, Jan Kratochvil wrote: > On Mon, 06 Aug 2012 16:33:58 +0200, Luis Gustavo wrote: >> With the somewhat recent booke kernel interface, more hw >> watchpoints/breakpoints are available to GDB. > > Which hardware can be BookE tested on? Red Hat has available for example > PPC970FX, POWER5, POWER7 etc. but those AFAIK are not BookE. Or does it > depend just on kernel? The ones you listed are server processors, and they use the old kernel interface. Examples of BookE's are the 4xx family (405, 440, 460, 476 etc...) > > >> The logic of replicating the existing process' debug state to the >> new thread is still there though, but the new booke interface in the >> kernel already replicates that state. More precisely, the kernel >> gives the new thread the debug state of its parent thread. > > I have been testing it recently for fork() (processes, no threads) and my > results were: > > kernel-3.3.4-5.fc17.ppc64 clears debug info in both parent (!) and child > kernel-2.6.18-308.el5.ppc64 copies debug info to child and keeps it in parent Interesting. The kernel i was trying things on was 2.6.3x. The behavior you mention in 3.3.4 sounds odd to me. It would be nice to hear from the kernel folks if this is expected. Also, the ppc server kernel may differ from the booke one. > > >> It's still unclear if the kernel is supposed to do this and i'm >> chasing answers with the ppc linux kernel folks (https://lists.ozlabs.org/pipermail/linuxppc-dev/2012-August/100083.html). >> Nonetheless, the kernel is out and it has such behavior. > > Yes, I agree GDB should cope with all these kinds of behavior. > > >> --- gdb_head.orig/gdb/ppc-linux-nat.c 2012-08-06 11:02:12.538532628 -0300 >> +++ gdb_head/gdb/ppc-linux-nat.c 2012-08-06 11:04:38.486536320 -0300 >> @@ -2179,7 +2179,21 @@ ppc_linux_new_thread (struct lwp_info *l >> /* Copy that thread's breakpoints and watchpoints to the new thread. */ >> for (i = 0; i< max_slots_number; i++) >> if (hw_breaks[i].hw_break) >> - booke_insert_point (hw_breaks[i].hw_break, tid); >> + { >> + /* The ppc Linux kernel causes a thread to inherit its parent >> + thread's debug state, and that includes any hardware >> + watchpoints or breakpoints that the parent thread may have set. >> + >> + For this reason, the debug state of the new thread is cleared >> + before trying to replicate any hardware watchpoints or >> + breakpoints contained in other threads. */ >> + >> + /* The ppc debug resource accounting is done through "slots". >> + Ask the kernel the deallocate this specific *point's slot. */ >> + ptrace (PPC_PTRACE_DELHWDEBUG, tid, 0, hw_breaks[i].slot); >> + >> + booke_insert_point (hw_breaks[i].hw_break, tid); > > I agree with the patch. > > I was considering to call PPC_PTRACE_DELHWDEBUG unconditionally but that would > be probably an unneeded overhead. > > Did you test that kernel really does not reorder the [i] slots during > inheritance into the new thread? The tests i did indicate that the child thread inherits whatever slot is in use by the parent thread, and no reordering appears to happen. Otherwise we would need to do a complete cleanup of the debug state in GDB. What i saw with hardware that has 2 watchpoint slots (440): * Thread 1 creates a hw watch using slot 5 (first DAC register). * Thread 1 creates Thread 2. * GDB proceeds to replicate the hw watch from Thread 1 in Thread 2. * The kernel replies with slot 6, which indicates that a new DAC has been used (and also indicates slot 5 is currently in use) * Thread 2 creates Thread 3 * GDB proceeds to replicate both hw watches from Threads 1 and 2 in Thread 3. * Kernel replies -1, indicating there are no more slots left to create a new hw watchpoint. This shows slots 5 and 6 are in use in Thread 3. > > >> + } >> } >> else >> ptrace (PTRACE_SET_DEBUGREG, tid, 0, saved_dabr_value); > > >> This would be nice to include before 7.5, as it's an annoying problem. > > Does this fix affect existing testcases on BookE? > Otherwise a new testcase would be appropriate. I don't think it does. Hardware watchpoints haven't been reliably tested for embedded ppc's due to the variaty of debugging features between cpu's. Additionaly, this only shows up when using hw watchpoints with threaded inferiors. An appropriate test would be to run many threads and create the maximum amount of hw watchpoints and see if that works fine, but GDB's debug resource accounting is still a little awkward Luis ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment. 2012-08-06 19:02 ` Luis Gustavo @ 2012-08-06 20:28 ` Jan Kratochvil 2012-08-07 14:55 ` Luis Gustavo 0 siblings, 1 reply; 24+ messages in thread From: Jan Kratochvil @ 2012-08-06 20:28 UTC (permalink / raw) To: Luis Gustavo; +Cc: gdb-patches, prasad, benh On Mon, 06 Aug 2012 21:02:11 +0200, Luis Gustavo wrote: > The ones you listed are server processors, and they use the old > kernel interface. Examples of BookE's are the 4xx family (405, 440, > 460, 476 etc...) OK, thanks for info. I do not think I have those available. > An appropriate test would be to run many threads and create the > maximum amount of hw watchpoints and see if that works fine, but > GDB's debug resource accounting is still a little awkward One can test the number of registers in singlethreaded testcase and then run the real test with multithreaded program. A testcase would be nice, for example now the changes in archer-jankratochvil-watchpoint3 and pre-requisite of non-stop compatibility of hw watchpoints mean a lot of hw watchpoints rewrite in ppc-linux-nat.c. But if you are not going to write a testcase then I find it OK for both HEAD and 7.5. Thanks, Jan ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment. 2012-08-06 20:28 ` Jan Kratochvil @ 2012-08-07 14:55 ` Luis Gustavo 2012-08-07 15:00 ` Jan Kratochvil 0 siblings, 1 reply; 24+ messages in thread From: Luis Gustavo @ 2012-08-07 14:55 UTC (permalink / raw) To: Jan Kratochvil; +Cc: gdb-patches On 08/06/2012 05:27 PM, Jan Kratochvil wrote: > On Mon, 06 Aug 2012 21:02:11 +0200, Luis Gustavo wrote: >> The ones you listed are server processors, and they use the old >> kernel interface. Examples of BookE's are the 4xx family (405, 440, >> 460, 476 etc...) > > OK, thanks for info. I do not think I have those available. > > >> An appropriate test would be to run many threads and create the >> maximum amount of hw watchpoints and see if that works fine, but >> GDB's debug resource accounting is still a little awkward > > One can test the number of registers in singlethreaded testcase and then run > the real test with multithreaded program. Sounds good. > > A testcase would be nice, for example now the changes in > archer-jankratochvil-watchpoint3 and pre-requisite of non-stop compatibility > of hw watchpoints mean a lot of hw watchpoints rewrite in ppc-linux-nat.c. > > But if you are not going to write a testcase then I find it OK for both HEAD > and 7.5. I'm ok with coming up with that testcase. Should we go ahead and have this in and the test commited shortly afterwards? Luis ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment. 2012-08-07 14:55 ` Luis Gustavo @ 2012-08-07 15:00 ` Jan Kratochvil 2012-08-07 15:02 ` Luis Gustavo 0 siblings, 1 reply; 24+ messages in thread From: Jan Kratochvil @ 2012-08-07 15:00 UTC (permalink / raw) To: Luis Gustavo; +Cc: gdb-patches On Tue, 07 Aug 2012 16:55:15 +0200, Luis Gustavo wrote: > I'm ok with coming up with that testcase. Should we go ahead and > have this in and the test commited shortly afterwards? If you are really going to write that testcase I find it easier later during analyses to have fix + testcase in a single commit. The testcase should be simple, shouldn't be? 7.5 is not going to be released these days yet. Thanks, Jan ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment. 2012-08-07 15:00 ` Jan Kratochvil @ 2012-08-07 15:02 ` Luis Gustavo 0 siblings, 0 replies; 24+ messages in thread From: Luis Gustavo @ 2012-08-07 15:02 UTC (permalink / raw) To: Jan Kratochvil; +Cc: gdb-patches On 08/07/2012 11:59 AM, Jan Kratochvil wrote: > On Tue, 07 Aug 2012 16:55:15 +0200, Luis Gustavo wrote: >> I'm ok with coming up with that testcase. Should we go ahead and >> have this in and the test commited shortly afterwards? > > If you are really going to write that testcase I find it easier later during > analyses to have fix + testcase in a single commit. The testcase should be > simple, shouldn't be? 7.5 is not going to be released these days yet. Yeah. You're right. Luis ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment. 2012-08-06 14:33 [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment Luis Gustavo 2012-08-06 18:40 ` Jan Kratochvil @ 2012-12-27 19:50 ` Luis Machado 2013-01-22 12:12 ` Pedro Alves 1 sibling, 1 reply; 24+ messages in thread From: Luis Machado @ 2012-12-27 19:50 UTC (permalink / raw) Cc: gdb-patches, Jan Kratochvil [-- Attachment #1: Type: text/plain, Size: 2217 bytes --] Hi, On 08/06/2012 11:33 AM, Luis Gustavo wrote: > Hi, > > GDB has always assumed that hardware watchpoints and breakpoints should > be replicated for every new thread in ppc. This worked fine for the old > DABR-based mechanism since both server and embedded ppc's supported only > a single hw watchpoint or breakpoint. > > With the somewhat recent booke kernel interface, more hw > watchpoints/breakpoints are available to GDB. > > The logic of replicating the existing process' debug state to the new > thread is still there though, but the new booke interface in the kernel > already replicates that state. More precisely, the kernel gives the new > thread the debug state of its parent thread. > > When GDB tries to replicate the debug state, it will actually cause the > kernel to allocate a new hw *point entry, leading to inadequate > consumption of hw debug resources. > > It's still unclear if the kernel is supposed to do this and i'm chasing > answers with the ppc linux kernel folks > (https://lists.ozlabs.org/pipermail/linuxppc-dev/2012-August/100083.html). > Nonetheless, the kernel is out and it has such behavior. > > This patch tries to address this problem by clearing any debug state > prior to replicating *points to the new thread. If the kernel is doing > something it's not supposed to, then this is a workaround for the broken > kernels. This is an updated patch that includes a generic testcase. The fix is still the same, but the testcase exercises creation of hardware watchpoints and their replication to all existing threads. Each thread should cause a watchpoint trigger a certain number of times, and that's what we expect in the testcase. Without the fix, the affected ppc targets will throw an error after the third thread gets created. Curiously, x86 misses a watchpoint trigger every once in a while. Since only a single trigger is allowed per thread at a given time, that is, we try our best not to cause multiple triggers at once, this may be a different issue, not directly related to the testcase. It would be nice if someone could try this testcase on different targets and confirm how it behaves, as well as validate the overall testcase format. Regards, Luis [-- Attachment #2: 0002-watch_threads.diff --] [-- Type: text/x-patch, Size: 10618 bytes --] 2012-12-27 Luis Machado <lgustavo@codesourcery.com> * ppc-linux-nat.c (ppc_linux_new_thread): Clear the new thread's debug state prior to replicating existing hardware watchpoints or breakpoints. * gdb/testsuite/gdb.threads/watchthreads3.c: New file. * gdb/testsuite/gdb.threads/watchthreads3.exp: New file. Index: gdb/gdb/testsuite/gdb.threads/watchthreads3.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gdb/gdb/testsuite/gdb.threads/watchthreads3.c 2012-12-27 17:05:20.529201750 -0200 @@ -0,0 +1,144 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2012 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + Check that hardware watchpoints get propagated to all existing + threads when the hardware watchpoint is created. +*/ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdint.h> +#include <pthread.h> + +#ifndef NR_THREADS +#define NR_THREADS 4 +#endif + +#ifndef X_INCR_COUNT +#define X_INCR_COUNT 10 +#endif + +void *thread_function (void *arg); /* Function executed by each thread. */ + +/* Used to hold threads back until watchthreads3.exp is ready. */ +int test_ready = 0; + +/* Used to push the program out of the waiting loop after the + testcase is done counting the number of hardware watchpoints + available for our target. */ +int watch_count_done = 0; + +/* Array with elements we can create watchpoints for. */ +static int watched_data[NR_BYTES]; +pthread_mutex_t data_mutex; + +/* Wait function to keep threads busy while the testcase does + what it needs to do. */ +void empty_cycle (void) +{ + usleep (1); +} + +int +main () +{ + int res; + pthread_t threads[NR_THREADS]; + int i; + + while (watch_count_done == 0) + { + /* GDB will modify the value of "i" at runtime and we will + get past this point. */ + empty_cycle (); + } + + pthread_mutex_init (&data_mutex, NULL); + + for (i = 0; i < NR_THREADS; ++i) + { + res = pthread_create (&threads[i], + NULL, + thread_function, + (void *) (intptr_t) i); + if (res != 0) + { + fprintf (stderr, "error in thread %d create\n", i); + abort (); + } + } + + for (i = 0; i < NR_THREADS; ++i) + { + res = pthread_join (threads[i], NULL); + if (res != 0) + { + fprintf (stderr, "error in thread %d join\n", i); + abort (); + } + } + + exit (EXIT_SUCCESS); +} + +/* Easy place for a breakpoint. + watchthreads3.exp uses this to track when all threads are running + instead of, for example, the program keeping track + because we don't need the program to know when all threads are running, + instead we need gdb to know when all threads are running. + There is a delay between when a thread has started and when the thread + has been registered with gdb. */ + +void +thread_started () +{ +} + +void * +thread_function (void *arg) +{ + int i, j; + long thread_number = (long) arg; + + thread_started (); + + /* Don't start incrementing X until watchthreads3.exp is ready. */ + while (!test_ready) + usleep (1); + + for (i = 0; i < NR_TRIGGERS_PER_THREAD; ++i) + { + for (j = 0; j < NR_THREADS; j++) + { + pthread_mutex_lock (&data_mutex); + /* For debugging. */ + printf ("Thread %ld changing watch_thread[%d] data" + " from %d -> %d\n", thread_number, j, + watched_data[j], watched_data[j] + 1); + /* The call to usleep is so that when the watchpoint triggers, + the pc is still on the same line. */ + /* Increment the watched data field. */ + ++watched_data[j]; + usleep (1); + + pthread_mutex_unlock (&data_mutex); + } + } + + pthread_exit (NULL); +} Index: gdb/gdb/testsuite/gdb.threads/watchthreads3.exp =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gdb/gdb/testsuite/gdb.threads/watchthreads3.exp 2012-12-27 17:09:19.817211552 -0200 @@ -0,0 +1,143 @@ +# This testcase is part of GDB, the GNU debugger. + +# Copyright 2012 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Check that hardware watchpoints get propagated to all existing +# threads when the hardware watchpoint is created. + + +set NR_THREADS 4 +set NR_TRIGGERS_PER_THREAD 10 +set NR_BYTES 100 + +# This test verifies that a hardware watchpoint gets replicated to +# every existing thread and is detected properly. This test is +# only meaningful on a target with hardware watchpoints. +if {[skip_hw_watchpoint_tests]} { + return 0 +} + +standard_testfile +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "additional_flags=-DNR_THREADS=$NR_THREADS -DNR_TRIGGERS_PER_THREAD=$NR_TRIGGERS_PER_THREAD -DNR_BYTES=$NR_BYTES"]] != "" } { + return -1 +} + +clean_restart ${binfile} + +# Force hardware watchpoints to be used. +gdb_test_no_output "set can-use-hw-watchpoints 1" "" + +# Run to `main' where we begin our tests. +if ![runto_main] then { + gdb_suppress_tests +} + +# First, break at empty_cycle. +gdb_test "break empty_cycle" \ + "Breakpoint 2 at .*: file .*${srcfile}, line .*" \ + "breakpoint on empty_cycle" + +# Set some default values. +set hwatch_count 0 +set done 0 + +# Count the number of hardware watchpoints available on +# this target. +while { $done == 0 } { + + gdb_test "continue" \ + ".*Breakpoint 2, empty_cycle \\(\\) at .*${srcfile}.*" \ + "continue to empty_cycle" + + # Some targets do resource counting as we insert watchpoints. + # Such targets won't cause a watchpoint insertion failure, but + # will switch to software watchpoints silently. We check for + # both cases here. + gdb_test_multiple "watch watched_data\[$hwatch_count\]" \ + "watch watched_data\[$hwatch_count\]" { + -re "Hardware watchpoint .*" { + continue + } + -re "Watchpoint .*" { + set done 1 + break + } + } + + gdb_test_multiple "continue" "watchpoint created successfully" { + -re ".*Breakpoint 2, empty_cycle \\(\\).*$gdb_prompt $" { + incr hwatch_count + continue + } + -re ".*Could not insert hardware watchpoint.*" { + set done 1 + break + } + } +} + +if { $hwatch_count == 0} { + gdb_exit; +} + +# At this point, we know how many hardware watchpoints +# the target supports. Use that to do further testing. +delete_breakpoints + +# Break out of the empty_cycle loop by changing the +# controlling variable. +gdb_test_no_output "set var watch_count_done=1" \ + "set var watch_count_done=1" + +# Prepare to create all the threads. +gdb_test "break thread_started" \ + "Breakpoint \[0-9\]+ at .*: file .*${srcfile}, line .*" \ + "Breakpoint on thread_started" + +# Move all threads to where they're supposed to be for testing. +for { set i 0 } { $i < $NR_THREADS } { incr i} { + + # We want to set the maximum number of hardware watchpoints + # and make sure the target can handle that without an error. + # That will show us the watchpoints got replicated to all the + # threads correctly, and that no new watchpoints got created + # in the background for a specific thread. + if {$i < $hwatch_count} { + gdb_test "watch watched_data\[$i\]" \ + "Hardware watchpoint .*" \ + "watch watched_data\[$i\]" + } + + gdb_test continue "Continuing\\..*Breakpoint \[0-9\]+, thread_started \\(\\) at .*$srcfile.*" \ + "Break at thread_started" +} + +# Let the threads run and change the watched data, leading +# to watchpoint triggers. +gdb_test_no_output "set var test_ready=1" \ + "set var test_ready=1" + +# Set the number of expected watchpoint triggers. +set TRIGGERS [expr "$NR_THREADS * $NR_THREADS * $NR_TRIGGERS_PER_THREAD"] + +# Move the threads and hit the watchpoints +# TRIGGERS times. +for { set i 0 } { $i < $TRIGGERS } { incr i} { + gdb_test continue "Continuing\\..*Hardware watchpoint \[0-9\]+: watched_data\[\[0-9\]+\].*Old value = \[0-9\]+.*New value = \[0-9\]+.*thread_function \\(arg=$hex\\) at .*$srcfile.*" \ + "Continue to watchpoint trigger on watched_data" +} + +gdb_exit Index: gdb/gdb/ppc-linux-nat.c =================================================================== --- gdb.orig/gdb/ppc-linux-nat.c 2012-12-27 14:22:58.844802770 -0200 +++ gdb/gdb/ppc-linux-nat.c 2012-12-27 14:23:14.568803412 -0200 @@ -2179,7 +2179,21 @@ ppc_linux_new_thread (struct lwp_info *l /* Copy that thread's breakpoints and watchpoints to the new thread. */ for (i = 0; i < max_slots_number; i++) if (hw_breaks[i].hw_break) - booke_insert_point (hw_breaks[i].hw_break, tid); + { + /* The ppc Linux kernel causes a thread to inherit its parent + thread's debug state, and that includes any hardware + watchpoints or breakpoints that the parent thread may have set. + + For this reason, the debug state of the new thread is cleared + before trying to replicate any hardware watchpoints or + breakpoints contained in other threads. */ + + /* The ppc debug resource accounting is done through "slots". + Ask the kernel the deallocate this specific *point's slot. */ + ptrace (PPC_PTRACE_DELHWDEBUG, tid, 0, hw_breaks[i].slot); + + booke_insert_point (hw_breaks[i].hw_break, tid); + } } else ptrace (PTRACE_SET_DEBUGREG, tid, 0, saved_dabr_value); ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment. 2012-12-27 19:50 ` Luis Machado @ 2013-01-22 12:12 ` Pedro Alves 0 siblings, 0 replies; 24+ messages in thread From: Pedro Alves @ 2013-01-22 12:12 UTC (permalink / raw) To: lgustavo; +Cc: gdb-patches, Jan Kratochvil Hi Luis, On 12/27/2012 07:50 PM, Luis Machado wrote: > > This is an updated patch that includes a generic testcase. > > The fix is still the same, but the testcase exercises creation of > hardware watchpoints and their replication to all existing threads. > > Each thread should cause a watchpoint trigger a certain number of > times, and that's what we expect in the testcase. > > Without the fix, the affected ppc targets will throw an error after > the third thread gets created. > > Curiously, x86 misses a watchpoint trigger every once in a while. > Since only a single trigger is allowed per thread at a given time, > that is, we try our best not to cause multiple triggers at once, > this may be a different issue, not directly related to the testcase. > > It would be nice if someone could try this testcase on different > targets and confirm how it behaves, as well as validate the overall > testcase format. I'm looking at this, but I'd like to make sure I'm looking at the correct patch. > + # Some targets do resource counting as we insert watchpoints. > + # Such targets won't cause a watchpoint insertion failure, but > + # will switch to software watchpoints silently. We check for > + # both cases here. > + gdb_test_multiple "watch watched_data\[$hwatch_count\]" \ > + "watch watched_data\[$hwatch_count\]" { > + -re "Hardware watchpoint .*" { > + continue Because, testing on x86_64, this "continue" here makes it so that hwatch_count is never incremented at all (that bit is below, and never gets a chance to run). > + } > + -re "Watchpoint .*" { > + set done 1 > + break > + } > + } Also, both these patterns miss expecting the prompt, leading to races. Here's the patch I'm using on top of yours: diff --git c/gdb/testsuite/gdb.threads/watchthreads3.exp w/gdb/testsuite/gdb.threads/watchthreads3.exp index e2ee228..c958b31 100644 --- c/gdb/testsuite/gdb.threads/watchthreads3.exp +++ w/gdb/testsuite/gdb.threads/watchthreads3.exp @@ -68,10 +68,10 @@ while { $done == 0 } { # both cases here. gdb_test_multiple "watch watched_data\[$hwatch_count\]" \ "watch watched_data\[$hwatch_count\]" { - -re "Hardware watchpoint .*" { - continue + -re "Hardware watchpoint .*$gdb_prompt $" { +# continue } - -re "Watchpoint .*" { + -re "Watchpoint .*$gdb_prompt $" { set done 1 break } On 12/27/2012 07:50 PM, Luis Machado wrote: > Curiously, x86 misses a watchpoint trigger every once in a while. > Since only a single trigger is allowed per thread at a given time, > that is, we try our best not to cause multiple triggers at once, > this may be a different issue, not directly related to the testcase. I set the test to run in an inf loop, and I saw this after a few iterations: FAIL: gdb.threads/watchthreads3.exp: Continue to watchpoint trigger on watched_data (the program exited) === gdb Summary === # of expected passes 177 # of unexpected failures 1 I guess that's what you referred to. -- Pedro Alves ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment
@ 2013-04-17 20:33 Luis Machado
2013-04-18 0:19 ` Sergio Durigan Junior
2013-04-22 21:09 ` Luis Machado
0 siblings, 2 replies; 24+ messages in thread
From: Luis Machado @ 2013-04-17 20:33 UTC (permalink / raw)
To: 'gdb-patches@sourceware.org'
[-- Attachment #1: Type: text/plain, Size: 333 bytes --]
Hi,
This is an updated version of the patch i sent a while ago. It addresses
Pedro's comments and hopefully is OK now.
I renamed the testcase to something more meaningful than watchthreads3.
If this doesn't delay the release, it would be nice to include it since
it is an annoying issue for embedded ppc targets.
Regards,
Luis
[-- Attachment #2: hw_watch.diff --]
[-- Type: text/x-patch, Size: 10930 bytes --]
Index: gdb-head/gdb/ChangeLog
===================================================================
--- gdb-head.orig/gdb/ChangeLog 2013-04-17 11:13:12.551447594 +0200
+++ gdb-head/gdb/ChangeLog 2013-04-17 17:21:26.959055004 +0200
@@ -1,3 +1,12 @@
+2013-04-17 Luis Machado <lgustavo@codesourcery.com>
+
+ * ppc-linux-nat.c (ppc_linux_new_thread): Clear the new thread's
+ debug state prior to replicating existing hardware watchpoints or
+ breakpoints.
+
+ * gdb/testsuite/gdb.threads/wp-replication.c: New file.
+ * gdb/testsuite/gdb.threads/wp-replication.exp: New file.
+
2013-04-17 Yao Qi <yao@codesourcery.com>
* top.c (print_gdb_configuration): Print configure-time
Index: gdb-head/gdb/ppc-linux-nat.c
===================================================================
--- gdb-head.orig/gdb/ppc-linux-nat.c 2013-04-17 10:24:52.919499117 +0200
+++ gdb-head/gdb/ppc-linux-nat.c 2013-04-17 11:12:20.731448515 +0200
@@ -2179,6 +2179,21 @@ ppc_linux_new_thread (struct lwp_info *l
for (i = 0; i < max_slots_number; i++)
if (hw_breaks[i].hw_break)
booke_insert_point (hw_breaks[i].hw_break, tid);
+ {
+ /* The ppc Linux kernel causes a thread to inherit its parent
+ thread's debug state, and that includes any hardware
+ watchpoints or breakpoints that the parent thread may have set.
+
+ For this reason, the debug state of the new thread is cleared
+ before trying to replicate any hardware watchpoints or
+ breakpoints contained in other threads. */
+
+ /* The ppc debug resource accounting is done through "slots".
+ Ask the kernel the deallocate this specific *point's slot. */
+ ptrace (PPC_PTRACE_DELHWDEBUG, tid, 0, hw_breaks[i].slot);
+
+ booke_insert_point (hw_breaks[i].hw_break, tid);
+ }
}
else
ptrace (PTRACE_SET_DEBUGREG, tid, 0, saved_dabr_value);
Index: gdb-head/gdb/testsuite/gdb.threads/wp-replication.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb-head/gdb/testsuite/gdb.threads/wp-replication.c 2013-04-17 17:52:04.195022357 +0200
@@ -0,0 +1,144 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2013 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ Check that hardware watchpoints get propagated to all existing
+ threads when the hardware watchpoint is created.
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <pthread.h>
+
+#ifndef NR_THREADS
+#define NR_THREADS 4
+#endif
+
+#ifndef X_INCR_COUNT
+#define X_INCR_COUNT 10
+#endif
+
+void *thread_function (void *arg); /* Function executed by each thread. */
+
+/* Used to hold threads back until wp-replication.exp is ready. */
+int test_ready = 0;
+
+/* Used to push the program out of the waiting loop after the
+ testcase is done counting the number of hardware watchpoints
+ available for our target. */
+int watch_count_done = 0;
+
+/* Array with elements we can create watchpoints for. */
+static int watched_data[NR_BYTES];
+pthread_mutex_t data_mutex;
+
+/* Wait function to keep threads busy while the testcase does
+ what it needs to do. */
+void empty_cycle (void)
+{
+ usleep (1);
+}
+
+int
+main ()
+{
+ int res;
+ pthread_t threads[NR_THREADS];
+ int i;
+
+ while (watch_count_done == 0)
+ {
+ /* GDB will modify the value of "i" at runtime and we will
+ get past this point. */
+ empty_cycle ();
+ }
+
+ pthread_mutex_init (&data_mutex, NULL);
+
+ for (i = 0; i < NR_THREADS; ++i)
+ {
+ res = pthread_create (&threads[i],
+ NULL,
+ thread_function,
+ (void *) (intptr_t) i);
+ if (res != 0)
+ {
+ fprintf (stderr, "error in thread %d create\n", i);
+ abort ();
+ }
+ }
+
+ for (i = 0; i < NR_THREADS; ++i)
+ {
+ res = pthread_join (threads[i], NULL);
+ if (res != 0)
+ {
+ fprintf (stderr, "error in thread %d join\n", i);
+ abort ();
+ }
+ }
+
+ exit (EXIT_SUCCESS);
+}
+
+/* Easy place for a breakpoint.
+ wp-replication.exp uses this to track when all threads are running
+ instead of, for example, the program keeping track
+ because we don't need the program to know when all threads are running,
+ instead we need gdb to know when all threads are running.
+ There is a delay between when a thread has started and when the thread
+ has been registered with gdb. */
+
+void
+thread_started ()
+{
+}
+
+void *
+thread_function (void *arg)
+{
+ int i, j;
+ long thread_number = (long) arg;
+
+ thread_started ();
+
+ /* Don't start incrementing X until wp-replication.exp is ready. */
+ while (!test_ready)
+ usleep (1);
+
+ for (i = 0; i < NR_TRIGGERS_PER_THREAD; ++i)
+ {
+ for (j = 0; j < NR_THREADS; j++)
+ {
+ pthread_mutex_lock (&data_mutex);
+ /* For debugging. */
+ printf ("Thread %ld changing watch_thread[%d] data"
+ " from %d -> %d\n", thread_number, j,
+ watched_data[j], watched_data[j] + 1);
+ /* The call to usleep is so that when the watchpoint triggers,
+ the pc is still on the same line. */
+ /* Increment the watched data field. */
+ ++watched_data[j];
+ usleep (1);
+
+ pthread_mutex_unlock (&data_mutex);
+ }
+ }
+
+ pthread_exit (NULL);
+}
Index: gdb-head/gdb/testsuite/gdb.threads/wp-replication.exp
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb-head/gdb/testsuite/gdb.threads/wp-replication.exp 2013-04-17 16:12:01.807129012 +0200
@@ -0,0 +1,141 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2013 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Check that hardware watchpoints get replicated to all existing
+# threads when the hardware watchpoint is created.
+
+
+set NR_THREADS 4
+set NR_TRIGGERS_PER_THREAD 10
+set NR_BYTES 100
+
+# This test verifies that a hardware watchpoint gets replicated to
+# every existing thread and is detected properly. This test is
+# only meaningful on a target with hardware watchpoints.
+if {[skip_hw_watchpoint_tests]} {
+ return 0
+}
+
+standard_testfile
+if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "additional_flags=-DNR_THREADS=$NR_THREADS -DNR_TRIGGERS_PER_THREAD=$NR_TRIGGERS_PER_THREAD -DNR_BYTES=$NR_BYTES"]] != "" } {
+ return -1
+}
+
+clean_restart ${binfile}
+
+# Force hardware watchpoints to be used.
+gdb_test_no_output "set can-use-hw-watchpoints 1" ""
+
+# Run to `main' where we begin our tests.
+if ![runto_main] then {
+ gdb_suppress_tests
+}
+
+# First, break at empty_cycle.
+gdb_test "break empty_cycle" \
+ "Breakpoint 2 at .*: file .*${srcfile}, line .*" \
+ "breakpoint on empty_cycle"
+
+# Set some default values.
+set hwatch_count 0
+set done 0
+
+# Count the number of hardware watchpoints available on
+# this target.
+while { $done == 0 } {
+
+ gdb_test "continue" \
+ ".*Breakpoint 2, empty_cycle \\(\\) at .*${srcfile}.*" \
+ "continue to empty_cycle"
+
+ # Some targets do resource counting as we insert watchpoints.
+ # Such targets won't cause a watchpoint insertion failure, but
+ # will switch to software watchpoints silently. We check for
+ # both cases here.
+ gdb_test_multiple "watch watched_data\[$hwatch_count\]" \
+ "watch watched_data\[$hwatch_count\]" {
+ -re "Hardware watchpoint .*$gdb_prompt $" {
+ }
+ -re "Watchpoint .*$gdb_prompt $" {
+ set done 1
+ break
+ }
+ }
+
+ gdb_test_multiple "continue" "watchpoint created successfully" {
+ -re ".*Breakpoint 2, empty_cycle \\(\\).*$gdb_prompt $" {
+ incr hwatch_count
+ }
+ -re ".*Could not insert hardware watchpoint.*$gdb_prompt $" {
+ set done 1
+ break
+ }
+ }
+}
+
+if { $hwatch_count == 0} {
+ gdb_exit;
+}
+
+# At this point, we know how many hardware watchpoints
+# the target supports. Use that to do further testing.
+delete_breakpoints
+
+# Break out of the empty_cycle loop by changing the
+# controlling variable.
+gdb_test_no_output "set var watch_count_done=1" \
+ "set var watch_count_done=1"
+
+# Prepare to create all the threads.
+gdb_test "break thread_started" \
+ "Breakpoint \[0-9\]+ at .*: file .*${srcfile}, line .*" \
+ "Breakpoint on thread_started"
+
+# Move all threads to where they're supposed to be for testing.
+for { set i 0 } { $i < $NR_THREADS } { incr i} {
+
+ # We want to set the maximum number of hardware watchpoints
+ # and make sure the target can handle that without an error.
+ # That will show us the watchpoints got replicated to all the
+ # threads correctly, and that no new watchpoints got created
+ # in the background for a specific thread.
+ if {$i < $hwatch_count} {
+ gdb_test "watch watched_data\[$i\]" \
+ "Hardware watchpoint .*" \
+ "watch watched_data\[$i\]"
+ }
+
+ gdb_test continue "Continuing\\..*Breakpoint \[0-9\]+, thread_started \\(\\) at .*$srcfile.*" \
+ "Break at thread_started"
+}
+
+# Let the threads run and change the watched data, leading
+# to watchpoint triggers.
+gdb_test_no_output "set var test_ready=1" \
+ "set var test_ready=1"
+
+# Set the number of expected watchpoint triggers.
+set TRIGGERS [expr "$NR_THREADS * $NR_THREADS * $NR_TRIGGERS_PER_THREAD"]
+
+# Move the threads and hit the watchpoints
+# TRIGGERS times.
+for { set i 0 } { $i < $TRIGGERS } { incr i} {
+ gdb_test continue "Continuing\\..*Hardware watchpoint \[0-9\]+: watched_data\[\[0-9\]+\].*Old value = \[0-9\]+.*New value = \[0-9\]+.*thread_function \\(arg=$hex\\) at .*$srcfile.*" \
+ "Continue to watchpoint trigger on watched_data"
+}
+
+gdb_exit
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment 2013-04-17 20:33 Luis Machado @ 2013-04-18 0:19 ` Sergio Durigan Junior 2013-04-18 0:51 ` Luis Machado 2013-04-22 21:09 ` Luis Machado 1 sibling, 1 reply; 24+ messages in thread From: Sergio Durigan Junior @ 2013-04-18 0:19 UTC (permalink / raw) To: lgustavo; +Cc: 'gdb-patches@sourceware.org' Hey! Thank for the patch. One thing I noticed: On Wednesday, April 17 2013, Luis Machado wrote: > Index: gdb-head/gdb/ppc-linux-nat.c > =================================================================== > --- gdb-head.orig/gdb/ppc-linux-nat.c 2013-04-17 10:24:52.919499117 +0200 > +++ gdb-head/gdb/ppc-linux-nat.c 2013-04-17 11:12:20.731448515 +0200 > @@ -2179,6 +2179,21 @@ ppc_linux_new_thread (struct lwp_info *l > for (i = 0; i < max_slots_number; i++) > if (hw_breaks[i].hw_break) > booke_insert_point (hw_breaks[i].hw_break, tid); Didn't you forget to delete the previous line? :-) > + { > + /* The ppc Linux kernel causes a thread to inherit its parent > + thread's debug state, and that includes any hardware > + watchpoints or breakpoints that the parent thread may have set. > + > + For this reason, the debug state of the new thread is cleared > + before trying to replicate any hardware watchpoints or > + breakpoints contained in other threads. */ > + > + /* The ppc debug resource accounting is done through "slots". > + Ask the kernel the deallocate this specific *point's slot. */ > + ptrace (PPC_PTRACE_DELHWDEBUG, tid, 0, hw_breaks[i].slot); > + > + booke_insert_point (hw_breaks[i].hw_break, tid); > + } -- Sergio ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment 2013-04-18 0:19 ` Sergio Durigan Junior @ 2013-04-18 0:51 ` Luis Machado 0 siblings, 0 replies; 24+ messages in thread From: Luis Machado @ 2013-04-18 0:51 UTC (permalink / raw) To: Sergio Durigan Junior; +Cc: lgustavo, 'gdb-patches@sourceware.org' [-- Attachment #1: Type: text/plain, Size: 881 bytes --] On 04/17/2013 07:04 PM, Sergio Durigan Junior wrote: > Didn't you forget to delete the previous line? :-) > >> + { >> + /* The ppc Linux kernel causes a thread to inherit its parent >> + thread's debug state, and that includes any hardware >> + watchpoints or breakpoints that the parent thread may have set. >> + >> + For this reason, the debug state of the new thread is cleared >> + before trying to replicate any hardware watchpoints or >> + breakpoints contained in other threads. */ >> + >> + /* The ppc debug resource accounting is done through "slots". >> + Ask the kernel the deallocate this specific *point's slot. */ >> + ptrace (PPC_PTRACE_DELHWDEBUG, tid, 0, hw_breaks[i].slot); >> + >> + booke_insert_point (hw_breaks[i].hw_break, tid); >> + } > Heh, obviously! Updated patch attached. Thanks, Luis [-- Attachment #2: hw_watch.diff --] [-- Type: text/x-patch, Size: 11010 bytes --] Index: gdb-head/gdb/ChangeLog =================================================================== --- gdb-head.orig/gdb/ChangeLog 2013-04-17 11:13:12.551447594 +0200 +++ gdb-head/gdb/ChangeLog 2013-04-17 17:21:26.959055004 +0200 @@ -1,3 +1,12 @@ +2013-04-17 Luis Machado <lgustavo@codesourcery.com> + + * ppc-linux-nat.c (ppc_linux_new_thread): Clear the new thread's + debug state prior to replicating existing hardware watchpoints or + breakpoints. + + * gdb/testsuite/gdb.threads/wp-replication.c: New file. + * gdb/testsuite/gdb.threads/wp-replication.exp: New file. + 2013-04-17 Yao Qi <yao@codesourcery.com> * top.c (print_gdb_configuration): Print configure-time Index: gdb-head/gdb/ppc-linux-nat.c =================================================================== --- gdb-head.orig/gdb/ppc-linux-nat.c 2013-04-17 10:24:52.919499117 +0200 +++ gdb-head/gdb/ppc-linux-nat.c 2013-04-17 19:06:28.070943039 +0200 @@ -2178,7 +2178,21 @@ ppc_linux_new_thread (struct lwp_info *l /* Copy that thread's breakpoints and watchpoints to the new thread. */ for (i = 0; i < max_slots_number; i++) if (hw_breaks[i].hw_break) - booke_insert_point (hw_breaks[i].hw_break, tid); + { + /* The ppc Linux kernel causes a thread to inherit its parent + thread's debug state, and that includes any hardware + watchpoints or breakpoints that the parent thread may have set. + + For this reason, the debug state of the new thread is cleared + before trying to replicate any hardware watchpoints or + breakpoints contained in other threads. */ + + /* The ppc debug resource accounting is done through "slots". + Ask the kernel the deallocate this specific *point's slot. */ + ptrace (PPC_PTRACE_DELHWDEBUG, tid, 0, hw_breaks[i].slot); + + booke_insert_point (hw_breaks[i].hw_break, tid); + } } else ptrace (PTRACE_SET_DEBUGREG, tid, 0, saved_dabr_value); Index: gdb-head/gdb/testsuite/gdb.threads/wp-replication.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gdb-head/gdb/testsuite/gdb.threads/wp-replication.c 2013-04-17 17:52:04.195022357 +0200 @@ -0,0 +1,144 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2013 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + Check that hardware watchpoints get propagated to all existing + threads when the hardware watchpoint is created. +*/ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdint.h> +#include <pthread.h> + +#ifndef NR_THREADS +#define NR_THREADS 4 +#endif + +#ifndef X_INCR_COUNT +#define X_INCR_COUNT 10 +#endif + +void *thread_function (void *arg); /* Function executed by each thread. */ + +/* Used to hold threads back until wp-replication.exp is ready. */ +int test_ready = 0; + +/* Used to push the program out of the waiting loop after the + testcase is done counting the number of hardware watchpoints + available for our target. */ +int watch_count_done = 0; + +/* Array with elements we can create watchpoints for. */ +static int watched_data[NR_BYTES]; +pthread_mutex_t data_mutex; + +/* Wait function to keep threads busy while the testcase does + what it needs to do. */ +void empty_cycle (void) +{ + usleep (1); +} + +int +main () +{ + int res; + pthread_t threads[NR_THREADS]; + int i; + + while (watch_count_done == 0) + { + /* GDB will modify the value of "i" at runtime and we will + get past this point. */ + empty_cycle (); + } + + pthread_mutex_init (&data_mutex, NULL); + + for (i = 0; i < NR_THREADS; ++i) + { + res = pthread_create (&threads[i], + NULL, + thread_function, + (void *) (intptr_t) i); + if (res != 0) + { + fprintf (stderr, "error in thread %d create\n", i); + abort (); + } + } + + for (i = 0; i < NR_THREADS; ++i) + { + res = pthread_join (threads[i], NULL); + if (res != 0) + { + fprintf (stderr, "error in thread %d join\n", i); + abort (); + } + } + + exit (EXIT_SUCCESS); +} + +/* Easy place for a breakpoint. + wp-replication.exp uses this to track when all threads are running + instead of, for example, the program keeping track + because we don't need the program to know when all threads are running, + instead we need gdb to know when all threads are running. + There is a delay between when a thread has started and when the thread + has been registered with gdb. */ + +void +thread_started () +{ +} + +void * +thread_function (void *arg) +{ + int i, j; + long thread_number = (long) arg; + + thread_started (); + + /* Don't start incrementing X until wp-replication.exp is ready. */ + while (!test_ready) + usleep (1); + + for (i = 0; i < NR_TRIGGERS_PER_THREAD; ++i) + { + for (j = 0; j < NR_THREADS; j++) + { + pthread_mutex_lock (&data_mutex); + /* For debugging. */ + printf ("Thread %ld changing watch_thread[%d] data" + " from %d -> %d\n", thread_number, j, + watched_data[j], watched_data[j] + 1); + /* The call to usleep is so that when the watchpoint triggers, + the pc is still on the same line. */ + /* Increment the watched data field. */ + ++watched_data[j]; + usleep (1); + + pthread_mutex_unlock (&data_mutex); + } + } + + pthread_exit (NULL); +} Index: gdb-head/gdb/testsuite/gdb.threads/wp-replication.exp =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gdb-head/gdb/testsuite/gdb.threads/wp-replication.exp 2013-04-17 16:12:01.807129012 +0200 @@ -0,0 +1,141 @@ +# This testcase is part of GDB, the GNU debugger. + +# Copyright 2013 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Check that hardware watchpoints get replicated to all existing +# threads when the hardware watchpoint is created. + + +set NR_THREADS 4 +set NR_TRIGGERS_PER_THREAD 10 +set NR_BYTES 100 + +# This test verifies that a hardware watchpoint gets replicated to +# every existing thread and is detected properly. This test is +# only meaningful on a target with hardware watchpoints. +if {[skip_hw_watchpoint_tests]} { + return 0 +} + +standard_testfile +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "additional_flags=-DNR_THREADS=$NR_THREADS -DNR_TRIGGERS_PER_THREAD=$NR_TRIGGERS_PER_THREAD -DNR_BYTES=$NR_BYTES"]] != "" } { + return -1 +} + +clean_restart ${binfile} + +# Force hardware watchpoints to be used. +gdb_test_no_output "set can-use-hw-watchpoints 1" "" + +# Run to `main' where we begin our tests. +if ![runto_main] then { + gdb_suppress_tests +} + +# First, break at empty_cycle. +gdb_test "break empty_cycle" \ + "Breakpoint 2 at .*: file .*${srcfile}, line .*" \ + "breakpoint on empty_cycle" + +# Set some default values. +set hwatch_count 0 +set done 0 + +# Count the number of hardware watchpoints available on +# this target. +while { $done == 0 } { + + gdb_test "continue" \ + ".*Breakpoint 2, empty_cycle \\(\\) at .*${srcfile}.*" \ + "continue to empty_cycle" + + # Some targets do resource counting as we insert watchpoints. + # Such targets won't cause a watchpoint insertion failure, but + # will switch to software watchpoints silently. We check for + # both cases here. + gdb_test_multiple "watch watched_data\[$hwatch_count\]" \ + "watch watched_data\[$hwatch_count\]" { + -re "Hardware watchpoint .*$gdb_prompt $" { + } + -re "Watchpoint .*$gdb_prompt $" { + set done 1 + break + } + } + + gdb_test_multiple "continue" "watchpoint created successfully" { + -re ".*Breakpoint 2, empty_cycle \\(\\).*$gdb_prompt $" { + incr hwatch_count + } + -re ".*Could not insert hardware watchpoint.*$gdb_prompt $" { + set done 1 + break + } + } +} + +if { $hwatch_count == 0} { + gdb_exit; +} + +# At this point, we know how many hardware watchpoints +# the target supports. Use that to do further testing. +delete_breakpoints + +# Break out of the empty_cycle loop by changing the +# controlling variable. +gdb_test_no_output "set var watch_count_done=1" \ + "set var watch_count_done=1" + +# Prepare to create all the threads. +gdb_test "break thread_started" \ + "Breakpoint \[0-9\]+ at .*: file .*${srcfile}, line .*" \ + "Breakpoint on thread_started" + +# Move all threads to where they're supposed to be for testing. +for { set i 0 } { $i < $NR_THREADS } { incr i} { + + # We want to set the maximum number of hardware watchpoints + # and make sure the target can handle that without an error. + # That will show us the watchpoints got replicated to all the + # threads correctly, and that no new watchpoints got created + # in the background for a specific thread. + if {$i < $hwatch_count} { + gdb_test "watch watched_data\[$i\]" \ + "Hardware watchpoint .*" \ + "watch watched_data\[$i\]" + } + + gdb_test continue "Continuing\\..*Breakpoint \[0-9\]+, thread_started \\(\\) at .*$srcfile.*" \ + "Break at thread_started" +} + +# Let the threads run and change the watched data, leading +# to watchpoint triggers. +gdb_test_no_output "set var test_ready=1" \ + "set var test_ready=1" + +# Set the number of expected watchpoint triggers. +set TRIGGERS [expr "$NR_THREADS * $NR_THREADS * $NR_TRIGGERS_PER_THREAD"] + +# Move the threads and hit the watchpoints +# TRIGGERS times. +for { set i 0 } { $i < $TRIGGERS } { incr i} { + gdb_test continue "Continuing\\..*Hardware watchpoint \[0-9\]+: watched_data\[\[0-9\]+\].*Old value = \[0-9\]+.*New value = \[0-9\]+.*thread_function \\(arg=$hex\\) at .*$srcfile.*" \ + "Continue to watchpoint trigger on watched_data" +} + +gdb_exit ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment 2013-04-17 20:33 Luis Machado 2013-04-18 0:19 ` Sergio Durigan Junior @ 2013-04-22 21:09 ` Luis Machado 2013-04-22 21:09 ` Pedro Alves 1 sibling, 1 reply; 24+ messages in thread From: Luis Machado @ 2013-04-22 21:09 UTC (permalink / raw) Cc: 'gdb-patches@sourceware.org' On 04/17/2013 05:53 PM, Luis Machado wrote: > Hi, > > This is an updated version of the patch i sent a while ago. It addresses > Pedro's comments and hopefully is OK now. > > I renamed the testcase to something more meaningful than watchthreads3. > > If this doesn't delay the release, it would be nice to include it since > it is an annoying issue for embedded ppc targets. > > Regards, > Luis For the intermitent x86 failure, raising the usleep time a bit (1 to 5) seems to solve it. I blame this on something other than GDB then. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment 2013-04-22 21:09 ` Luis Machado @ 2013-04-22 21:09 ` Pedro Alves 2013-04-23 0:05 ` Pedro Alves 0 siblings, 1 reply; 24+ messages in thread From: Pedro Alves @ 2013-04-22 21:09 UTC (permalink / raw) To: lgustavo; +Cc: 'gdb-patches@sourceware.org' On 04/22/2013 04:32 PM, Luis Machado wrote: > For the intermitent x86 failure, raising the usleep time a bit (1 to 5) seems to solve it. > I blame this on something other than GDB then. Blaming the test itself is plausible. However, the extra usleep time just means the race window is smaller, not fixed, so still subject to the occasional racy failure. -- Pedro Alves ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment 2013-04-22 21:09 ` Pedro Alves @ 2013-04-23 0:05 ` Pedro Alves 2013-04-23 1:15 ` Pedro Alves 0 siblings, 1 reply; 24+ messages in thread From: Pedro Alves @ 2013-04-23 0:05 UTC (permalink / raw) To: Pedro Alves; +Cc: lgustavo, 'gdb-patches@sourceware.org' On 04/22/2013 04:42 PM, Pedro Alves wrote: > On 04/22/2013 04:32 PM, Luis Machado wrote: > >> For the intermitent x86 failure, raising the usleep time a bit (1 to 5) seems to solve it. > >> I blame this on something other than GDB then. > > Blaming the test itself is plausible. However, the extra usleep time just > means the race window is smaller, not fixed, so still subject to the > occasional racy failure. I hacked the test and GDB with the patch below, mainly to zone in on the issue with a "smaller" test (less threads, less iterations, etc.) and here's what I see (the FAIL is almost always reproducible to me this way). In the times the test fails, there's one watchpoint that is missed. ptrace does report the memory as having been touched, but then GDB compares the watchpoint's old/new values and decides nothing changed, so re-resumes the target immediately. The patch adds the fprintf_unfiltered (gdb_stdlog, "breakpoint: nothing changed\n"); line to breakpoint.c so we see that breakpoint logic triggering in the gdb.log. In the times the test passes completely, we don't see that line in the log. Here's the relevant snippet of the gdb.log showing that watchpoint missed case: Thread 1 changing watch_thread[1] data from 6 -> 7 sigchld LLW: enter LNW: waitpid(-1, ...) returned 21376, ERRNO-OK LLW: waitpid 21376 received Trace/breakpoint trap (stopped) LLTA: KILL(SIG0) Thread 0x7ffff77ca700 (LWP 21376) (OK) LLW: Candidate event Trace/breakpoint trap (stopped) in Thread 0x7ffff77ca700 (LWP 21376). SC: kill Thread 0x7ffff7fcb700 (LWP 21375) **<SIGSTOP>** SC: lwp kill 0 ERRNO-OK SC: kill Thread 0x7ffff7fcc740 (LWP 21362) **<SIGSTOP>** SC: lwp kill 0 ERRNO-OK WL: waitpid Thread 0x7ffff7fcb700 (LWP 21375) received Trace/breakpoint trap (stopped) SWC: Pending event Trace/breakpoint trap (stopped) in Thread 0x7ffff7fcb700 (LWP 21375) WL: waitpid Thread 0x7ffff7fcc740 (LWP 21362) received Stopped (signal) (stopped) SWC: Delayed SIGSTOP caught for Thread 0x7ffff7fcc740 (LWP 21362). SEL: Found 2 SIGTRAP events, selecting #1 LLW: trap ptid is Thread 0x7ffff7fcb700 (LWP 21375). LLW: exit sigchld infrun: target_wait (-1, status) = infrun: 21362 [Thread 0x7ffff7fcb700 (LWP 21375)], infrun: status->kind = stopped, signal = SIGTRAP infrun: infwait_normal_state infrun: TARGET_WAITKIND_STOPPED infrun: stop_pc = 0x3d25a0f680 infrun: context switch infrun: Switching context from Thread 0x7ffff77ca700 (LWP 21376) to Thread 0x7ffff7fcb700 (LWP 21375) infrun: BPSTAT_WHAT_SINGLE infrun: no stepping, continue infrun: resume (step=1, signal=0), trap_expected=1, current thread [Thread 0x7ffff7fcb700 (LWP 21375)] at 0x3d25a0f680 LLR: Preparing to step Thread 0x7ffff7fcb700 (LWP 21375), 0, inferior_ptid Thread 0x7ffff7fcb700 (LWP 21375) LLR: PTRACE_SINGLESTEP process 21375, 0 (resume event thread) sigchld infrun: prepare_to_wait linux_nat_wait: [process -1], [] LLW: enter LNW: waitpid(-1, ...) returned 21375, ERRNO-OK LLW: waitpid 21375 received Stopped (signal) (stopped) LLTA: KILL(SIG0) Thread 0x7ffff7fcb700 (LWP 21375) (OK) LLW: Delayed SIGSTOP caught for Thread 0x7ffff7fcb700 (LWP 21375). LLW: PTRACE_SINGLESTEP Thread 0x7ffff7fcb700 (LWP 21375), 0, 0 (discard SIGSTOP) LNW: waitpid(-1, ...) returned 21375, ERRNO-OK LLW: waitpid 21375 received Trace/breakpoint trap (stopped) LLTA: KILL(SIG0) Thread 0x7ffff7fcb700 (LWP 21375) (OK) LLW: Candidate event Trace/breakpoint trap (stopped) in Thread 0x7ffff7fcb700 (LWP 21375). SEL: Select single-step Thread 0x7ffff7fcb700 (LWP 21375) LLW: trap ptid is Thread 0x7ffff7fcb700 (LWP 21375). LLW: exit sigchld infrun: target_wait (-1, status) = infrun: 21362 [Thread 0x7ffff7fcb700 (LWP 21375)], infrun: status->kind = stopped, signal = SIGTRAP infrun: infwait_normal_state infrun: TARGET_WAITKIND_STOPPED infrun: stop_pc = 0x3d25a068d2 infrun: no stepping, continue infrun: resume (step=0, signal=0), trap_expected=0, current thread [Thread 0x7ffff7fcb700 (LWP 21375)] at 0x3d25a068d2 LLR: Preparing to resume process 21362, 0, inferior_ptid Thread 0x7ffff7fcb700 (LWP 21375) RC: Not resuming sibling Thread 0x7ffff77ca700 (LWP 21376) (has pending) RC: Not resuming sibling Thread 0x7ffff7fcb700 (LWP 21375) (not stopped) RC: Resuming sibling Thread 0x7ffff7fcc740 (LWP 21362), 0, resume LLR: PTRACE_CONT process 21375, 0 (resume event thread) sigchld infrun: prepare_to_wait linux_nat_wait: [process -1], [] LLW: enter LLW: Using pending wait status Trace/breakpoint trap (stopped) for Thread 0x7ffff77ca700 (LWP 21376). LLW: Candidate event Trace/breakpoint trap (stopped) in Thread 0x7ffff77ca700 (LWP 21376). SC: kill Thread 0x7ffff7fcb700 (LWP 21375) **<SIGSTOP>** SC: lwp kill 0 ERRNO-OK SC: kill Thread 0x7ffff7fcc740 (LWP 21362) **<SIGSTOP>** SC: lwp kill 0 ERRNO-OK WL: waitpid Thread 0x7ffff7fcb700 (LWP 21375) received Trace/breakpoint trap (stopped) SWC: Pending event Trace/breakpoint trap (stopped) in Thread 0x7ffff7fcb700 (LWP 21375) WL: waitpid Thread 0x7ffff7fcc740 (LWP 21362) received Stopped (signal) (stopped) SWC: Delayed SIGSTOP caught for Thread 0x7ffff7fcc740 (LWP 21362). SEL: Found 2 SIGTRAP events, selecting #1 LLW: trap ptid is Thread 0x7ffff7fcb700 (LWP 21375). LLW: exit sigchld infrun: target_wait (-1, status) = infrun: 21362 [Thread 0x7ffff7fcb700 (LWP 21375)], infrun: status->kind = stopped, signal = SIGTRAP infrun: infwait_normal_state infrun: TARGET_WAITKIND_STOPPED infrun: stop_pc = 0x3d25a0f680 infrun: BPSTAT_WHAT_SINGLE infrun: no stepping, continue infrun: resume (step=1, signal=0), trap_expected=1, current thread [Thread 0x7ffff7fcb700 (LWP 21375)] at 0x3d25a0f680 LLR: Preparing to step Thread 0x7ffff7fcb700 (LWP 21375), 0, inferior_ptid Thread 0x7ffff7fcb700 (LWP 21375) LLR: PTRACE_SINGLESTEP process 21375, 0 (resume event thread) sigchld infrun: prepare_to_wait linux_nat_wait: [process -1], [] LLW: enter LNW: waitpid(-1, ...) returned 21375, ERRNO-OK LLW: waitpid 21375 received Stopped (signal) (stopped) LLTA: KILL(SIG0) Thread 0x7ffff7fcb700 (LWP 21375) (OK) LLW: Delayed SIGSTOP caught for Thread 0x7ffff7fcb700 (LWP 21375). LLW: PTRACE_SINGLESTEP Thread 0x7ffff7fcb700 (LWP 21375), 0, 0 (discard SIGSTOP) LNW: waitpid(-1, ...) returned 21375, ERRNO-OK LLW: waitpid 21375 received Trace/breakpoint trap (stopped) LLTA: KILL(SIG0) Thread 0x7ffff7fcb700 (LWP 21375) (OK) LLW: Candidate event Trace/breakpoint trap (stopped) in Thread 0x7ffff7fcb700 (LWP 21375). SEL: Select single-step Thread 0x7ffff7fcb700 (LWP 21375) LLW: trap ptid is Thread 0x7ffff7fcb700 (LWP 21375). LLW: exit sigchld infrun: target_wait (-1, status) = infrun: 21362 [Thread 0x7ffff7fcb700 (LWP 21375)], infrun: status->kind = stopped, signal = SIGTRAP infrun: infwait_normal_state infrun: TARGET_WAITKIND_STOPPED infrun: stop_pc = 0x3d25a130a5 infrun: no stepping, continue infrun: resume (step=0, signal=0), trap_expected=0, current thread [Thread 0x7ffff7fcb700 (LWP 21375)] at 0x3d25a130a5 LLR: Preparing to resume process 21362, 0, inferior_ptid Thread 0x7ffff7fcb700 (LWP 21375) RC: Not resuming sibling Thread 0x7ffff77ca700 (LWP 21376) (has pending) RC: Not resuming sibling Thread 0x7ffff7fcb700 (LWP 21375) (not stopped) RC: Resuming sibling Thread 0x7ffff7fcc740 (LWP 21362), 0, resume LLR: PTRACE_CONT process 21375, 0 (resume event thread) sigchld infrun: prepare_to_wait linux_nat_wait: [process -1], [] LLW: enter LLW: Using pending wait status Trace/breakpoint trap (stopped) for Thread 0x7ffff77ca700 (LWP 21376). LLW: Candidate event Trace/breakpoint trap (stopped) in Thread 0x7ffff77ca700 (LWP 21376). SC: kill Thread 0x7ffff7fcb700 (LWP 21375) **<SIGSTOP>** SC: lwp kill 0 ERRNO-OK SC: kill Thread 0x7ffff7fcc740 (LWP 21362) **<SIGSTOP>** SC: lwp kill 0 ERRNO-OK WL: waitpid Thread 0x7ffff7fcb700 (LWP 21375) received Trace/breakpoint trap (stopped) SWC: Pending event Trace/breakpoint trap (stopped) in Thread 0x7ffff7fcb700 (LWP 21375) WL: waitpid Thread 0x7ffff7fcc740 (LWP 21362) received Stopped (signal) (stopped) SWC: Delayed SIGSTOP caught for Thread 0x7ffff7fcc740 (LWP 21362). SEL: Found 2 SIGTRAP events, selecting #0 CB: Push back breakpoint for Thread 0x7ffff7fcb700 (LWP 21375) LLW: trap ptid is Thread 0x7ffff77ca700 (LWP 21376). LLW: exit sigchld infrun: target_wait (-1, status) = infrun: 21362 [Thread 0x7ffff77ca700 (LWP 21376)], infrun: status->kind = stopped, signal = SIGTRAP infrun: infwait_normal_state infrun: TARGET_WAITKIND_STOPPED infrun: stop_pc = 0x400aa0 infrun: stopped by watchpoint infrun: stopped data address = 0x6012e4 infrun: context switch infrun: Switching context from Thread 0x7ffff7fcb700 (LWP 21375) to Thread 0x7ffff77ca700 (LWP 21376) breakpoint: nothing changed I suspect the reason this doesn't trigger on ppc may be related to the fact that x86 watchpoints are continuable while ppc reports the watchpoint hit before the memory changes (thus triggering a different sequence of events, as gdb single-steps the thread that triggers the watchpoint to get the new value). I haven't really examined the log to try to figure out why is really going wrong. Seems plausible to me that GDB could be at fault. BTW, the test has lots of weird indenting. I re-indented it automatically with emacs, so the below is a "git diff -w" patch. BTW, what's NR_BYTES supposed to be? See patch. diff --git c/gdb/breakpoint.c w/gdb/breakpoint.c index 2757c6b..d33842a 100644 --- c/gdb/breakpoint.c +++ w/gdb/breakpoint.c @@ -4807,6 +4807,7 @@ watchpoint_check (void *p) } else { + fprintf_unfiltered (gdb_stdlog, "breakpoint: nothing changed\n"); /* Nothing changed. */ value_free_to_mark (mark); return WP_VALUE_NOT_CHANGED; diff --git c/gdb/testsuite/gdb.threads/wp-replication.c w/gdb/testsuite/gdb.threads/wp-replication.c index 4d79d56..8f0c5d2 100644 --- c/gdb/testsuite/gdb.threads/wp-replication.c +++ w/gdb/testsuite/gdb.threads/wp-replication.c @@ -44,7 +44,7 @@ int test_ready = 0; int watch_count_done = 0; /* Array with elements we can create watchpoints for. */ -static int watched_data[NR_BYTES]; +static int watched_data[NR_TRIGGERS_PER_THREAD * NR_THREADS]; pthread_mutex_t data_mutex; /* Wait function to keep threads busy while the testcase does @@ -121,11 +121,11 @@ thread_function (void *arg) while (!test_ready) usleep (1); + pthread_mutex_lock (&data_mutex); for (i = 0; i < NR_TRIGGERS_PER_THREAD; ++i) { for (j = 0; j < NR_THREADS; j++) { - pthread_mutex_lock (&data_mutex); /* For debugging. */ printf ("Thread %ld changing watch_thread[%d] data" " from %d -> %d\n", thread_number, j, @@ -134,11 +134,11 @@ thread_function (void *arg) the pc is still on the same line. */ /* Increment the watched data field. */ ++watched_data[j]; - usleep (1); + usleep (5); - pthread_mutex_unlock (&data_mutex); } } + pthread_mutex_unlock (&data_mutex); pthread_exit (NULL); } diff --git c/gdb/testsuite/gdb.threads/wp-replication.exp w/gdb/testsuite/gdb.threads/wp-replication.exp index 449423f..937c9e6 100644 --- c/gdb/testsuite/gdb.threads/wp-replication.exp +++ w/gdb/testsuite/gdb.threads/wp-replication.exp @@ -19,8 +19,8 @@ # threads when the hardware watchpoint is created. -set NR_THREADS 4 -set NR_TRIGGERS_PER_THREAD 10 +set NR_THREADS 2 +set NR_TRIGGERS_PER_THREAD 4 set NR_BYTES 100 # This test verifies that a hardware watchpoint gets replicated to @@ -105,6 +105,9 @@ gdb_test "break thread_started" \ "Breakpoint \[0-9\]+ at .*: file .*${srcfile}, line .*" \ "Breakpoint on thread_started" +verbose -log "hwatch_count = $hwatch_count" +verbose -log "NR_THREADS = $NR_THREADS" + # Move all threads to where they're supposed to be for testing. for { set i 0 } { $i < $NR_THREADS } { incr i} { @@ -117,6 +120,8 @@ for { set i 0 } { $i < $NR_THREADS } { incr i} { gdb_test "watch watched_data\[$i\]" \ "Hardware watchpoint .*" \ "watch watched_data\[$i\]" + } else { + verbose -log "not setting watchpoint for watched_data\[$i\]\n" } gdb_test continue "Continuing\\..*Breakpoint \[0-9\]+, thread_started \\(\\) at .*$srcfile.*" \ @@ -131,6 +136,9 @@ gdb_test_no_output "set var test_ready=1" \ # Set the number of expected watchpoint triggers. set TRIGGERS [expr "$NR_THREADS * $NR_THREADS * $NR_TRIGGERS_PER_THREAD"] +gdb_test_no_output "set debug infrun 1" +gdb_test_no_output "set debug lin-lwp 1" + # Move the threads and hit the watchpoints # TRIGGERS times. for { set i 0 } { $i < $TRIGGERS } { incr i} { ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment 2013-04-23 0:05 ` Pedro Alves @ 2013-04-23 1:15 ` Pedro Alves 2013-04-23 20:25 ` Luis Machado 2013-04-23 23:18 ` Luis Machado 0 siblings, 2 replies; 24+ messages in thread From: Pedro Alves @ 2013-04-23 1:15 UTC (permalink / raw) To: lgustavo; +Cc: 'gdb-patches@sourceware.org' I hacked GDB some more, and I have further insight. GDB _is_ to blame. Updated GDB/test hack patch at the bottom. New gdb.log snippet: infrun: resume (step=0, signal=0), trap_expected=0, current thread [Thread 0x7ffff7fcb700 (LWP 29305)] at 0x3d25a068d2 LLR: Preparing to resume process 29301, 0, inferior_ptid Thread 0x7ffff7fcb700 (LWP 29305) RC: Resuming sibling Thread 0x7ffff77ca700 (LWP 29306), 0, resume RC: Not resuming sibling Thread 0x7ffff7fcb700 (LWP 29305) (not stopped) RC: Resuming sibling Thread 0x7ffff7fcc740 (LWP 29301), 0, resume Thread 1 [0xf77ca700 (LWP 29306)] changing watch_thread[1] data from 4 -> 5 LLR: PTRACE_CONT process 29305, 0 (resume event thread) sigchld infrun: prepare_to_wait linux_nat_wait: [process -1], [] LLW: enter LNW: waitpid(-1, ...) returned 29306, ERRNO-OK LLW: waitpid 29306 received Trace/breakpoint trap (stopped) LLTA: KILL(SIG0) Thread 0x7ffff77ca700 (LWP 29306) (OK) LLW: Candidate event Trace/breakpoint trap (stopped) in Thread 0x7ffff77ca700 (LWP 29306). SC: kill Thread 0x7ffff7fcb700 (LWP 29305) **<SIGSTOP>** SC: lwp kill 0 ERRNO-OK SC: kill Thread 0x7ffff7fcc740 (LWP 29301) **<SIGSTOP>** SC: lwp kill 0 ERRNO-OK WL: waitpid Thread 0x7ffff7fcb700 (LWP 29305) received Trace/breakpoint trap (stopped) SWC: Pending event Trace/breakpoint trap (stopped) in Thread 0x7ffff7fcb700 (LWP 29305) WL: waitpid Thread 0x7ffff7fcc740 (LWP 29301) received Stopped (signal) (stopped) SWC: Delayed SIGSTOP caught for Thread 0x7ffff7fcc740 (LWP 29301). SEL: Found 2 SIGTRAP events, selecting #1 LLW: trap ptid is Thread 0x7ffff7fcb700 (LWP 29305). LLW: exit sigchld infrun: target_wait (-1, status) = infrun: 29301 [Thread 0x7ffff7fcb700 (LWP 29305)], infrun: status->kind = stopped, signal = SIGTRAP infrun: infwait_normal_state infrun: TARGET_WAITKIND_STOPPED infrun: stop_pc = 0x3d25a0f680 breakpoint: forced reparse breakpoint: value reparsed. New=5 breakpoint: forced reparse breakpoint: value reparsed. New=5 infrun: BPSTAT_WHAT_SINGLE infrun: no stepping, continue infrun: resume (step=1, signal=0), trap_expected=1, current thread [Thread 0x7ffff7fcb700 (LWP 29305)] at 0x3d25a0f680 LLR: Preparing to step Thread 0x7ffff7fcb700 (LWP 29305), 0, inferior_ptid Thread 0x7ffff7fcb700 (LWP 29305) LLR: PTRACE_SINGLESTEP process 29305, 0 (resume event thread) sigchld infrun: prepare_to_wait linux_nat_wait: [process -1], [] LLW: enter LNW: waitpid(-1, ...) returned 29305, ERRNO-OK LLW: waitpid 29305 received Stopped (signal) (stopped) LLTA: KILL(SIG0) Thread 0x7ffff7fcb700 (LWP 29305) (OK) LLW: Delayed SIGSTOP caught for Thread 0x7ffff7fcb700 (LWP 29305). LLW: PTRACE_SINGLESTEP Thread 0x7ffff7fcb700 (LWP 29305), 0, 0 (discard SIGSTOP) LNW: waitpid(-1, ...) returned 29305, ERRNO-OK LLW: waitpid 29305 received Trafce/breakpoint trap (stopped) LLTA: KILL(SIG0) Thread 0x7ffff7fcb700 (LWP 29305) (OK) LLW: Candidate event Trace/breakpoint trap (stopped) in Thread 0x7ffff7fcb700 (LWP 29305). SEL: Select single-step Thread 0x7ffff7fcb700 (LWP 29305) LLW: trap ptid is Thread 0x7ffff7fcb700 (LWP 29305). LLW: exit sigchld infrun: target_wait (-1, status) = infrun: 29301 [Thread 0x7ffff7fcb700 (LWP 29305)], infrun: status->kind = stopped, signal = SIGTRAP infrun: infwait_normal_state infrun: TARGET_WAITKIND_STOPPED infrun: stop_pc = 0x3d25a130a5 infrun: no stepping, continue infrun: resume (step=0, signal=0), trap_expected=0, current thread [Thread 0x7ffff7fcb700 (LWP 29305)] at 0x3d25a130a5 LLR: Preparing to resume process 29301, 0, inferior_ptid Thread 0x7ffff7fcb700 (LWP 29305) RC: Not resuming sibling Thread 0x7ffff77ca700 (LWP 29306) (has pending) RC: Not resuming sibling Thread 0x7ffff7fcb700 (LWP 29305) (not stopped) RC: Resuming sibling Thread 0x7ffff7fcc740 (LWP 29301), 0, resume LLR: PTRACE_CONT process 29305, 0 (resume event thread) sigchld infrun: prepare_to_wait linux_nat_wait: [process -1], [] LLW: enter LLW: Using pending wait status Trace/breakpoint trap (stopped) for Thread 0x7ffff77ca700 (LWP 29306). LLW: Candidate event Trace/breakpoint trap (stopped) in Thread 0x7ffff77ca700 (LWP 29306). SC: kill Thread 0x7ffff7fcb700 (LWP 29305) **<SIGSTOP>** SC: lwp kill 0 ERRNO-OK SC: kill Thread 0x7ffff7fcc740 (LWP 29301) **<SIGSTOP>** SC: lwp kill 0 ERRNO-OK WL: waitpid Thread 0x7ffff7fcb700 (LWP 29305) received Trace/breakpoint trap (stopped) SWC: Pending event Trace/breakpoint trap (stopped) in Thread 0x7ffff7fcb700 (LWP 29305) WL: waitpid Thread 0x7ffff7fcc740 (LWP 29301) received Stopped (signal) (stopped) SWC: Delayed SIGSTOP caught for Thread 0x7ffff7fcc740 (LWP 29301). SEL: Found 2 SIGTRAP events, selecting #0 CB: Push back breakpoint for Thread 0x7ffff7fcb700 (LWP 29305) LLW: trap ptid is Thread 0x7ffff77ca700 (LWP 29306). LLW: exit sigchld infrun: target_wait (-1, status) = infrun: 29301 [Thread 0x7ffff77ca700 (LWP 29306)], infrun: status->kind = stopped, signal = SIGTRAP infrun: infwait_normal_state infrun: TARGET_WAITKIND_STOPPED infrun: stop_pc = 0x400b71 infrun: stopped by watchpoint infrun: stopped data address = 0x6012e4 infrun: context switch infrun: Switching context from Thread 0x7ffff7fcb700 (LWP 29305) to Thread 0x7ffff77ca700 (LWP 29306) breakpoint: nothing changed. Old=5, New=5 So we can now see from the above that the watchpoint is ignored because Old=5 and New=5. But why does GDB think the old value of the watchpoint is 5? Something must have forced the watchpoint's value to be refetched without informing the user. And indeed, extra logging in breakpoint.c shows: breakpoint: forced reparse breakpoint: value reparsed. New=5 The patch that triggers that is re_set_watchpoint. Okay, so why do we have watchpoint re-sets going on? The log shows threads stopping at 0x3d25a0f680, which is, (gdb) info symbol 0x3d25a0f680 _dl_debug_state in section .text of /lib64/ld-linux-x86-64.so.2 ahhhhhhhhhh. So to program is stopping at DSO events (though the user doesn't see this). With "set stop-on-solib-events 1", we see: (gdb) bt #0 __GI__dl_debug_state () at dl-debug.c:76 #1 0x0000003d25a068d2 in _dl_map_object_from_fd (name=name@entry=0x3d26a10acf "libgcc_s.so.1", fd=fd@entry=12, fbp=fbp@entry=0x7ffff77ca5f0, realname=0x7ffff00008c0 "/lib64/libgcc_s.so.1", loader=loader@entry=0x0, l_type=l_type@entry=2, mode=mode@entry=-1879048191, stack_endp=stack_endp@entry=0x7ffff77ca5e8, nsid=nsid@entry=0) at dl-load.c:1044 #2 0x0000003d25a082f3 in _dl_map_object (loader=0x0, name=name@entry=0x3d26a10acf "libgcc_s.so.1", type=type@entry=2, trace_mode=trace_mode@entry=0, mode=mode@entry=-1879048191, nsid=nsid@entry=0) at dl-load.c:2355 #3 0x0000003d25a12fec in dl_open_worker (a=a@entry=0x7ffff77cab90) at dl-open.c:226 #4 0x0000003d25a0eca6 in _dl_catch_error (objname=objname@entry=0x7ffff77cab80, errstring=errstring@entry=0x7ffff77cab88, mallocedp=mallocedp@entry=0x7ffff77cab70, operate=operate@entry=0x3d25a12ec0 <dl_open_worker>, args=args@entry=0x7ffff77cab90) at dl-error.c:178 #5 0x0000003d25a12b1c in _dl_open (file=0x3d26a10acf "libgcc_s.so.1", mode=-2147483647, caller_dlopen=<optimized out>, nsid=-2, argc=1, argv=0x7fffffffdc08, env=0x7fffffffdc18) at dl-open.c:652 #6 0x0000003d25f2d212 in do_dlopen () from /lib64/libc.so.6 #7 0x0000003d25a0eca6 in _dl_catch_error (objname=0x7ffff77cad80, errstring=0x7ffff77cad90, mallocedp=0x7ffff77cad70, operate=0x3d25f2d1d0 <do_dlopen>, args=0x7ffff77cada0) at dl-error.c:178 #8 0x0000003d25f2d2d2 in __libc_dlopen_mode () from /lib64/libc.so.6 #9 0x0000003d26a0f704 in pthread_cancel_init () at ../nptl/sysdeps/pthread/unwind-forcedunwind.c:53 #10 0x0000003d26a0f8dc in _Unwind_ForcedUnwind (exc=<optimized out>, stop=stop@entry=0x3d26a0da60 <unwind_stop>, stop_argument=<optimized out>) at ../nptl/sysdeps/pthread/unwind-forcedunwind.c:130 #11 0x0000003d26a0dbf0 in __GI___pthread_unwind (buf=<optimized out>) at unwind.c:130 #12 0x0000003d26a08d35 in __do_cancel () at pthreadP.h:265 #13 __pthread_exit (value=<optimized out>) at pthread_exit.c:30 #14 0x0000000000400bab in thread_function (arg=0x1) at ../../../src/gdb/testsuite/gdb.threads/wp-replication.c:146 #15 0x0000003d26a07d14 in start_thread (arg=0x7ffff77cb700) at pthread_create.c:309 #16 0x0000003d25ef168d in clone () from /lib64/libc.so.6 (gdb) That's a thread exiting normally. (Notice #13). IOW, when the first thread exits, pthread_cancel_init does: handle = __libc_dlopen (LIBGCC_S_SO); and GDB catches that and forces a watchpoint re-set, losing the watchpoint's old value... So GDB is to blame. Fixing this, however, would be a different story, and doesn't look that simple. So the test could work around this by making sure that threads don't exit until after all watchpoints have been tested. -------- diff --git c/gdb/breakpoint.c w/gdb/breakpoint.c index 2757c6b..35d3411 100644 --- c/gdb/breakpoint.c +++ w/gdb/breakpoint.c @@ -106,6 +106,9 @@ static void map_breakpoint_numbers (char *, void (*) (struct breakpoint *, void *), void *); +static void +watchpoint_value_print (struct value *val, struct ui_file *stream); + static void ignore_command (char *, int); static int breakpoint_re_set_one (void *); @@ -1788,6 +1791,8 @@ update_watchpoint (struct watchpoint *b, int reparse) b->val = NULL; b->val_valid = 0; + fprintf_unfiltered (gdb_stdlog, "breakpoint: forced reparse\n"); + /* Note that unlike with breakpoints, the watchpoint's condition expression is stored in the breakpoint object, not in the locations (re)created below. */ @@ -1831,6 +1836,18 @@ update_watchpoint (struct watchpoint *b, int reparse) watchpoints. */ if (!b->val_valid && !is_masked_watchpoint (&b->base)) { + struct cleanup *old_chain; + struct ui_file *new_stb = mem_fileopen (); + long len; + + old_chain = make_cleanup_ui_file_delete (new_stb); + + watchpoint_value_print (v, new_stb); + + fprintf_unfiltered (gdb_stdlog, "breakpoint: value reparsed. New=%s\n", + ui_file_xstrdup (new_stb, &len)); + do_cleanups (old_chain); + b->val = v; b->val_valid = 1; } @@ -4800,6 +4817,27 @@ watchpoint_check (void *p) release_value (new_val); value_free_to_mark (mark); } + + + + { + struct cleanup *old_chain; + struct ui_file *old_stb = mem_fileopen (); + struct ui_file *new_stb = mem_fileopen (); + long len; + + old_chain = make_cleanup_ui_file_delete (old_stb); + make_cleanup_ui_file_delete (new_stb); + + watchpoint_value_print (b->val, old_stb); + watchpoint_value_print (new_val, new_stb); + + fprintf_unfiltered (gdb_stdlog, "breakpoint: value changed. Old=%s, New=%s\n", + ui_file_xstrdup (old_stb, &len), + ui_file_xstrdup (new_stb, &len)); + do_cleanups (old_chain); + } + bs->old_val = b->val; b->val = new_val; b->val_valid = 1; @@ -4807,6 +4845,22 @@ watchpoint_check (void *p) } else { + struct cleanup *old_chain; + struct ui_file *old_stb = mem_fileopen (); + struct ui_file *new_stb = mem_fileopen (); + long len; + + old_chain = make_cleanup_ui_file_delete (old_stb); + make_cleanup_ui_file_delete (new_stb); + + watchpoint_value_print (b->val, old_stb); + watchpoint_value_print (new_val, new_stb); + + fprintf_unfiltered (gdb_stdlog, "breakpoint: nothing changed. Old=%s, New=%s\n", + ui_file_xstrdup (old_stb, &len), + ui_file_xstrdup (new_stb, &len)); + do_cleanups (old_chain); + /* Nothing changed. */ value_free_to_mark (mark); return WP_VALUE_NOT_CHANGED; @@ -14722,6 +14776,8 @@ invalidate_bp_value_on_memory_change (struct inferior *inferior, value_free (wp->val); wp->val = NULL; wp->val_valid = 0; + + fprintf_unfiltered (gdb_stdlog, "breakpoint: on memory change\n"); } } } diff --git c/gdb/testsuite/gdb.threads/wp-replication.c w/gdb/testsuite/gdb.threads/wp-replication.c index 4d79d56..0543b67 100644 --- c/gdb/testsuite/gdb.threads/wp-replication.c +++ w/gdb/testsuite/gdb.threads/wp-replication.c @@ -44,7 +44,7 @@ int test_ready = 0; int watch_count_done = 0; /* Array with elements we can create watchpoints for. */ -static int watched_data[NR_BYTES]; +static int watched_data[NR_TRIGGERS_PER_THREAD * NR_THREADS]; pthread_mutex_t data_mutex; /* Wait function to keep threads busy while the testcase does @@ -109,6 +109,9 @@ thread_started () { } +#include <sys/syscall.h> +#define gettid() syscall (__NR_gettid) + void * thread_function (void *arg) { @@ -121,24 +124,24 @@ thread_function (void *arg) while (!test_ready) usleep (1); + pthread_mutex_lock (&data_mutex); for (i = 0; i < NR_TRIGGERS_PER_THREAD; ++i) { for (j = 0; j < NR_THREADS; j++) { - pthread_mutex_lock (&data_mutex); /* For debugging. */ - printf ("Thread %ld changing watch_thread[%d] data" - " from %d -> %d\n", thread_number, j, + printf ("Thread %ld [0x%x (LWP %d)] changing watch_thread[%d] data" + " from %d -> %d\n", thread_number, pthread_self (), gettid (), j, watched_data[j], watched_data[j] + 1); /* The call to usleep is so that when the watchpoint triggers, the pc is still on the same line. */ /* Increment the watched data field. */ ++watched_data[j]; - usleep (1); + usleep (5); - pthread_mutex_unlock (&data_mutex); } } + pthread_mutex_unlock (&data_mutex); pthread_exit (NULL); } diff --git c/gdb/testsuite/gdb.threads/wp-replication.exp w/gdb/testsuite/gdb.threads/wp-replication.exp index 449423f..937c9e6 100644 --- c/gdb/testsuite/gdb.threads/wp-replication.exp +++ w/gdb/testsuite/gdb.threads/wp-replication.exp @@ -19,8 +19,8 @@ # threads when the hardware watchpoint is created. -set NR_THREADS 4 -set NR_TRIGGERS_PER_THREAD 10 +set NR_THREADS 2 +set NR_TRIGGERS_PER_THREAD 4 set NR_BYTES 100 # This test verifies that a hardware watchpoint gets replicated to @@ -105,6 +105,9 @@ gdb_test "break thread_started" \ "Breakpoint \[0-9\]+ at .*: file .*${srcfile}, line .*" \ "Breakpoint on thread_started" +verbose -log "hwatch_count = $hwatch_count" +verbose -log "NR_THREADS = $NR_THREADS" + # Move all threads to where they're supposed to be for testing. for { set i 0 } { $i < $NR_THREADS } { incr i} { @@ -117,6 +120,8 @@ for { set i 0 } { $i < $NR_THREADS } { incr i} { gdb_test "watch watched_data\[$i\]" \ "Hardware watchpoint .*" \ "watch watched_data\[$i\]" + } else { + verbose -log "not setting watchpoint for watched_data\[$i\]\n" } gdb_test continue "Continuing\\..*Breakpoint \[0-9\]+, thread_started \\(\\) at .*$srcfile.*" \ @@ -131,6 +136,9 @@ gdb_test_no_output "set var test_ready=1" \ # Set the number of expected watchpoint triggers. set TRIGGERS [expr "$NR_THREADS * $NR_THREADS * $NR_TRIGGERS_PER_THREAD"] +gdb_test_no_output "set debug infrun 1" +gdb_test_no_output "set debug lin-lwp 1" + # Move the threads and hit the watchpoints # TRIGGERS times. for { set i 0 } { $i < $TRIGGERS } { incr i} { ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment 2013-04-23 1:15 ` Pedro Alves @ 2013-04-23 20:25 ` Luis Machado 2013-04-23 23:18 ` Luis Machado 1 sibling, 0 replies; 24+ messages in thread From: Luis Machado @ 2013-04-23 20:25 UTC (permalink / raw) To: Pedro Alves; +Cc: 'gdb-patches@sourceware.org' Hi, On 04/22/2013 09:02 PM, Pedro Alves wrote: > I hacked GDB some more, and I have further insight. > GDB _is_ to blame. Updated GDB/test hack patch at the bottom. > So GDB is to blame. Fixing this, however, would be a different > story, and doesn't look that simple. > > So the test could work around this by making sure that threads > don't exit until after all watchpoints have been tested. Thanks for the analysis! I modified the testcase to prevent those threads from exitting and fixed the weird identation (i messed it up when copying from another source probably). But, there still seems to be something odd here. When the number of threads is greater than the number of available hardware watchpoints, GDB still seems to miss watchpoint hits. I'm currently trying to narrow this down. Luis ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment 2013-04-23 1:15 ` Pedro Alves 2013-04-23 20:25 ` Luis Machado @ 2013-04-23 23:18 ` Luis Machado 2013-04-24 3:19 ` Pedro Alves 2013-04-24 4:36 ` Pedro Alves 1 sibling, 2 replies; 24+ messages in thread From: Luis Machado @ 2013-04-23 23:18 UTC (permalink / raw) To: Pedro Alves; +Cc: 'gdb-patches@sourceware.org' [-- Attachment #1: Type: text/plain, Size: 1126 bytes --] On 04/22/2013 09:02 PM, Pedro Alves wrote: > I hacked GDB some more, and I have further insight. > GDB _is_ to blame. Updated GDB/test hack patch at the bottom. > So GDB is to blame. Fixing this, however, would be a different > story, and doesn't look that simple. > > So the test could work around this by making sure that threads > don't exit until after all watchpoints have been tested. I did one more fix to the testcase to allow it to run properly when the number of threads is greater than the number of available hardware watchpoints. I also cleaned up, adjusted and added some more comments to the expect file. NR_BYTES was removed (it was useless), so now we use NR_THREADS to allocate the static array. One more internal variable was added to the testcase to allow GDB to share its knowledge on the number of available hardware watchpoints. That way the testcase never expects more triggers than what is supposed to come. The question here is how many threads we should spawn. I went with 10 since that is often greater than the number of hardware watchpoints in a target. How does it look? Luis [-- Attachment #2: hw_watch.diff --] [-- Type: text/x-patch, Size: 11811 bytes --] 2013-04-23 Luis Machado <lgustavo@codesourcery.com> * ppc-linux-nat.c (ppc_linux_new_thread): Clear the new thread's debug state prior to replicating existing hardware watchpoints or breakpoints. * gdb/testsuite/gdb.threads/wp-replication.c: New file. * gdb/testsuite/gdb.threads/wp-replication.exp: New file. Index: gdb-head/gdb/ppc-linux-nat.c =================================================================== --- gdb-head.orig/gdb/ppc-linux-nat.c 2013-04-23 14:40:07.418560514 +0200 +++ gdb-head/gdb/ppc-linux-nat.c 2013-04-23 14:40:48.262559788 +0200 @@ -2178,7 +2178,21 @@ ppc_linux_new_thread (struct lwp_info *l /* Copy that thread's breakpoints and watchpoints to the new thread. */ for (i = 0; i < max_slots_number; i++) if (hw_breaks[i].hw_break) - booke_insert_point (hw_breaks[i].hw_break, tid); + { + /* The ppc Linux kernel causes a thread to inherit its parent + thread's debug state, and that includes any hardware + watchpoints or breakpoints that the parent thread may have set. + + For this reason, the debug state of the new thread is cleared + before trying to replicate any hardware watchpoints or + breakpoints contained in other threads. */ + + /* The ppc debug resource accounting is done through "slots". + Ask the kernel the deallocate this specific *point's slot. */ + ptrace (PPC_PTRACE_DELHWDEBUG, tid, 0, hw_breaks[i].slot); + + booke_insert_point (hw_breaks[i].hw_break, tid); + } } else ptrace (PTRACE_SET_DEBUGREG, tid, 0, saved_dabr_value); Index: gdb-head/gdb/testsuite/gdb.threads/wp-replication.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gdb-head/gdb/testsuite/gdb.threads/wp-replication.c 2013-04-23 15:29:10.518508221 +0200 @@ -0,0 +1,160 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2013 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + Check that hardware watchpoints get propagated to all existing + threads when the hardware watchpoint is created. +*/ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdint.h> +#include <pthread.h> + +#ifndef NR_THREADS +#define NR_THREADS 4 /* Set by the testcase. */ +#endif + +#ifndef X_INCR_COUNT +#define X_INCR_COUNT 10 /* Set by the testcase. */ +#endif + +void *thread_function (void *arg); /* Function executed by each thread. */ + +/* Used to hold threads back until wp-replication.exp is ready. */ +int test_ready = 0; + +/* Used to hold threads back until every thread has had a chance of causing + a watchpoint trigger. This prevents a situation in GDB where it may miss + watchpoint triggers when threads exit while other threads are causing + watchpoint triggers. */ +int can_terminate = 0; + +/* Used to push the program out of the waiting loop after the + testcase is done counting the number of hardware watchpoints + available for our target. */ +int watch_count_done = 0; + +/* Number of watchpoints GDB is capable of using (this is provided + by GDB during the test run). */ +int hw_watch_count = 0; + +/* Array with elements we can create watchpoints for. */ +static int watched_data[NR_THREADS]; +pthread_mutex_t data_mutex; + +/* Wait function to keep threads busy while the testcase does + what it needs to do. */ +void empty_cycle (void) +{ + usleep (1); +} + +int +main () +{ + int res; + pthread_t threads[NR_THREADS]; + int i; + + while (watch_count_done == 0) + { + /* GDB will modify the value of "i" at runtime and we will + get past this point. */ + empty_cycle (); + } + + pthread_mutex_init (&data_mutex, NULL); + + for (i = 0; i < NR_THREADS; i++) + { + res = pthread_create (&threads[i], + NULL, thread_function, + (void *) (intptr_t) i); + if (res != 0) + { + fprintf (stderr, "error in thread %d create\n", i); + abort (); + } + } + + for (i = 0; i < NR_THREADS; ++i) + { + res = pthread_join (threads[i], NULL); + if (res != 0) + { + fprintf (stderr, "error in thread %d join\n", i); + abort (); + } + } + + exit (EXIT_SUCCESS); +} + +/* Easy place for a breakpoint. + wp-replication.exp uses this to track when all threads are running + instead of, for example, the program keeping track + because we don't need the program to know when all threads are running, + instead we need gdb to know when all threads are running. + There is a delay between when a thread has started and when the thread + has been registered with gdb. */ + +void +thread_started () +{ +} + +void * +thread_function (void *arg) +{ + int i, j; + long thread_number = (long) arg; + + thread_started (); + + /* Don't start incrementing X until wp-replication.exp is ready. */ + while (!test_ready) + usleep (1); + + pthread_mutex_lock (&data_mutex); + + for (i = 0; i < NR_TRIGGERS_PER_THREAD; i++) + { + for (j = 0; j < hw_watch_count; j++) + { + /* For debugging. */ + printf ("Thread %ld changing watch_thread[%d] data" + " from %d -> %d\n", thread_number, j, + watched_data[j], watched_data[j] + 1); + /* The call to usleep is so that when the watchpoint triggers, + the pc is still on the same line. */ + /* Increment the watched data field. */ + watched_data[j]++; + usleep (1); + } + } + + pthread_mutex_unlock (&data_mutex); + + /* Hold the threads here to work around a problem GDB has evaluating + watchpoints right when a DSO event shows up. Sleep a little longer + to avoid consuming lots of cycles. */ + while (!can_terminate) + usleep (100); + + pthread_exit (NULL); +} Index: gdb-head/gdb/testsuite/gdb.threads/wp-replication.exp =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gdb-head/gdb/testsuite/gdb.threads/wp-replication.exp 2013-04-23 15:13:16.230525175 +0200 @@ -0,0 +1,148 @@ +# This testcase is part of GDB, the GNU debugger. + +# Copyright 2013 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Check that hardware watchpoints get replicated to all existing +# threads when the hardware watchpoint is created. + +set NR_THREADS 10 +set NR_TRIGGERS_PER_THREAD 2 + +# This test verifies that a hardware watchpoint gets replicated to +# every existing thread and is detected properly. This test is +# only meaningful on a target with hardware watchpoint support. +if {[skip_hw_watchpoint_tests]} { + return 0 +} + +standard_testfile +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "additional_flags=-DNR_THREADS=$NR_THREADS -DNR_TRIGGERS_PER_THREAD=$NR_TRIGGERS_PER_THREAD"]] != "" } { + return -1 +} + +clean_restart ${binfile} + +# Force hardware watchpoints to be used. +gdb_test_no_output "set can-use-hw-watchpoints 1" "" + +# Run to `main' where we begin our tests. +if ![runto_main] then { + gdb_suppress_tests +} + +# First, break at empty_cycle. +gdb_test "break empty_cycle" \ + "Breakpoint 2 at .*: file .*${srcfile}, line .*" \ + "breakpoint on empty_cycle" + +# Set some default values. +set hwatch_count 0 +set done 0 + +# Count the number of hardware watchpoints available on +# this target. +while { $done == 0 } { + + gdb_test "continue" \ + ".*Breakpoint 2, empty_cycle \\(\\) at .*${srcfile}.*" \ + "continue to empty_cycle" + + # Some targets do resource counting as we insert watchpoints. + # Such targets won't cause a watchpoint insertion failure, but + # will switch to software watchpoints silently. We check for + # both cases here. + gdb_test_multiple "watch watched_data\[$hwatch_count\]" \ + "watch watched_data\[$hwatch_count\]" { + -re "Hardware watchpoint .*$gdb_prompt $" { + } + -re "Watchpoint .*$gdb_prompt $" { + set done 1 + break + } + } + + gdb_test_multiple "continue" "watchpoint created successfully" { + -re ".*Breakpoint 2, empty_cycle \\(\\).*$gdb_prompt $" { + incr hwatch_count + } + -re ".*Could not insert hardware watchpoint.*$gdb_prompt $" { + set done 1 + break + } + } +} + +# Target cannot insert hardware watchpoints. Maybe it should have reported +# it does not supported them in the first place. +if { $hwatch_count == 0} { + gdb_exit; +} + +# Set the testcase's internal variable indicating the number of +# hardware watchpoints the target supports. +gdb_test_no_output "set var hw_watch_count=${hwatch_count}" \ + "set var hw_watch_count=${hwatch_count}" + +# At this point, we know how many hardware watchpoints +# the target supports. Use that to do further testing. +delete_breakpoints + +# Break out of the empty_cycle loop by changing the +# controlling variable. +gdb_test_no_output "set var watch_count_done=1" \ + "set var watch_count_done=1" + +# Prepare to create all the threads. +gdb_test "break thread_started" \ + "Breakpoint \[0-9\]+ at .*: file .*${srcfile}, line .*" \ + "Breakpoint on thread_started" + +# Move all threads to where they're supposed to be for testing. +for { set i 0 } { $i < $NR_THREADS } { incr i } { + + # We want to set the maximum number of hardware watchpoints + # and make sure the target can handle that without an error. + # That will show us the watchpoints got replicated to all the + # threads correctly, and that no new watchpoints got created + # in the background for a specific thread. + if {$i < $hwatch_count} { + gdb_test "watch watched_data\[$i\]" \ + "Hardware watchpoint .*" \ + "watch watched_data\[$i\]" + } else { + verbose -log "Not setting watchpoint for watched_data\[$i\]\n" + } + + gdb_test continue "Continuing\\..*Breakpoint \[0-9\]+, thread_started \\(\\) at .*$srcfile.*" \ + "Break at thread_started" +} + +# Let the threads run and change the watched data, leading +# to watchpoint triggers. +gdb_test_no_output "set var test_ready=1" \ + "set var test_ready=1" + +# Set the number of expected watchpoint triggers. +set TRIGGERS [expr "$NR_THREADS * $hwatch_count * $NR_TRIGGERS_PER_THREAD"] + +# Move the threads and hit the watchpoints +# TRIGGERS times. +for { set i 0 } { $i < $TRIGGERS } { incr i} { + gdb_test continue "Continuing\\..*Hardware watchpoint \[0-9\]+: watched_data\[\[0-9\]+\].*Old value = \[0-9\]+.*New value = \[0-9\]+.*thread_function \\(arg=$hex\\) at .*$srcfile.*" \ + "Continue to watchpoint trigger ${i} out of ${TRIGGERS} on watched_data" +} + +gdb_exit ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment 2013-04-23 23:18 ` Luis Machado @ 2013-04-24 3:19 ` Pedro Alves 2013-04-24 6:28 ` Luis Machado 2013-04-24 4:36 ` Pedro Alves 1 sibling, 1 reply; 24+ messages in thread From: Pedro Alves @ 2013-04-24 3:19 UTC (permalink / raw) To: lgustavo; +Cc: 'gdb-patches@sourceware.org' On 04/23/2013 02:30 PM, Luis Machado wrote: > /* Copy that thread's breakpoints and watchpoints to the new thread. */ > for (i = 0; i < max_slots_number; i++) > if (hw_breaks[i].hw_break) > - booke_insert_point (hw_breaks[i].hw_break, tid); > + { > + /* The ppc Linux kernel causes a thread to inherit its parent > + thread's debug state, and that includes any hardware > + watchpoints or breakpoints that the parent thread may have set. ISTR there was a point when the kernel changed behavior, right? It'd be good to mention the kernel version here. I _think_ you wanted to retain compatibility with older kernels, but, alas, the comment doesn't mention that. (Also, I'm left wondering if we couldn't detect the need for this just once, and skip several ptrace calls if we find the kernel does this for us already.) > + > + For this reason, the debug state of the new thread is cleared > + before trying to replicate any hardware watchpoints or > + breakpoints contained in other threads. */ > + > + /* The ppc debug resource accounting is done through "slots". > + Ask the kernel the deallocate this specific *point's slot. */ > + ptrace (PPC_PTRACE_DELHWDEBUG, tid, 0, hw_breaks[i].slot); > + > + booke_insert_point (hw_breaks[i].hw_break, tid); > + } > Index: gdb-head/gdb/testsuite/gdb.threads/wp-replication.c > =================================================================== > --- /dev/null 1970-01-01 00:00:00.000000000 +0000 > +++ gdb-head/gdb/testsuite/gdb.threads/wp-replication.c 2013-04-23 15:29:10.518508221 +0200 > @@ -0,0 +1,160 @@ > +/* This testcase is part of GDB, the GNU debugger. > + > + Copyright 2013 Free Software Foundation, Inc. I now notice this was largely based on watchthreads2.c/exp. Please retain the copyright years. > + > + This program is free software; you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 3 of the License, or > + (at your option) any later version. > + > + This program is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + GNU General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with this program. If not, see <http://www.gnu.org/licenses/>. > + > + Check that hardware watchpoints get propagated to all existing > + threads when the hardware watchpoint is created. Hmm. watchthreads2.exp has the exact same comment. Can we have some more info here on what is supposed to be different between this and watchthreads2.exp? > +*/ > + > +#include <stdio.h> > +#include <unistd.h> > +#include <stdlib.h> > +#include <stdint.h> > +#include <pthread.h> > + > +#ifndef NR_THREADS > +#define NR_THREADS 4 /* Set by the testcase. */ > +#endif > + > +#ifndef X_INCR_COUNT > +#define X_INCR_COUNT 10 /* Set by the testcase. */ > +#endif > + > +void *thread_function (void *arg); /* Function executed by each thread. */ > + > +/* Used to hold threads back until wp-replication.exp is ready. */ > +int test_ready = 0; > + > +/* Used to hold threads back until every thread has had a chance of causing > + a watchpoint trigger. This prevents a situation in GDB where it may miss > + watchpoint triggers when threads exit while other threads are causing > + watchpoint triggers. */ > +int can_terminate = 0; > + > +/* Used to push the program out of the waiting loop after the > + testcase is done counting the number of hardware watchpoints > + available for our target. */ > +int watch_count_done = 0; > + > +/* Number of watchpoints GDB is capable of using (this is provided > + by GDB during the test run). */ > +int hw_watch_count = 0; > + > +/* Array with elements we can create watchpoints for. */ > +static int watched_data[NR_THREADS]; > +pthread_mutex_t data_mutex; > + > +/* Wait function to keep threads busy while the testcase does > + what it needs to do. */ > +void empty_cycle (void) > +{ > + usleep (1); > +} > + > +int > +main () > +{ > + int res; > + pthread_t threads[NR_THREADS]; > + int i; > + > + while (watch_count_done == 0) > + { > + /* GDB will modify the value of "i" at runtime and we will > + get past this point. */ > + empty_cycle (); > + } > + > + pthread_mutex_init (&data_mutex, NULL); > + > + for (i = 0; i < NR_THREADS; i++) > + { > + res = pthread_create (&threads[i], > + NULL, thread_function, > + (void *) (intptr_t) i); > + if (res != 0) > + { > + fprintf (stderr, "error in thread %d create\n", i); > + abort (); > + } > + } > + > + for (i = 0; i < NR_THREADS; ++i) > + { > + res = pthread_join (threads[i], NULL); > + if (res != 0) > + { > + fprintf (stderr, "error in thread %d join\n", i); > + abort (); > + } > + } > + > + exit (EXIT_SUCCESS); > +} > + > +/* Easy place for a breakpoint. > + wp-replication.exp uses this to track when all threads are running > + instead of, for example, the program keeping track > + because we don't need the program to know when all threads are running, > + instead we need gdb to know when all threads are running. > + There is a delay between when a thread has started and when the thread > + has been registered with gdb. */ > + > +void > +thread_started () (void) > +{ > +} > + > +void * > +thread_function (void *arg) > +{ > + int i, j; > + long thread_number = (long) arg; > + > + thread_started (); > + > + /* Don't start incrementing X until wp-replication.exp is ready. */ > + while (!test_ready) > + usleep (1); > + > + pthread_mutex_lock (&data_mutex); > + > + for (i = 0; i < NR_TRIGGERS_PER_THREAD; i++) > + { > + for (j = 0; j < hw_watch_count; j++) > + { > + /* For debugging. */ > + printf ("Thread %ld changing watch_thread[%d] data" > + " from %d -> %d\n", thread_number, j, > + watched_data[j], watched_data[j] + 1); > + /* The call to usleep is so that when the watchpoint triggers, > + the pc is still on the same line. */ This comment made sense in watchthreads2.c, which reads: printf ("Thread %ld changing x %d -> %d\n", (long) arg, x, x + 1); /* The call to usleep is so that when the watchpoint triggers, the pc is still on the same line. */ ++x; usleep (1); /* X increment. */ but the usleep is no longer on the same line... Do we still need it, even? > + /* Increment the watched data field. */ > + watched_data[j]++; > + usleep (1); > + } > + } > + > + pthread_mutex_unlock (&data_mutex); > + > + /* Hold the threads here to work around a problem GDB has evaluating > + watchpoints right when a DSO event shows up. Sleep a little longer s/shows up/shows up (PR breakpoints/10116)/ I'd s/longer// ("longer than what?") > + to avoid consuming lots of cycles. */ > + while (!can_terminate) > + usleep (100); > + > + pthread_exit (NULL); > +} > Index: gdb-head/gdb/testsuite/gdb.threads/wp-replication.exp > =================================================================== > --- /dev/null 1970-01-01 00:00:00.000000000 +0000 > +++ gdb-head/gdb/testsuite/gdb.threads/wp-replication.exp 2013-04-23 15:13:16.230525175 +0200 > @@ -0,0 +1,148 @@ > +# This testcase is part of GDB, the GNU debugger. > + > +# Copyright 2013 Free Software Foundation, Inc. > + > +# This program is free software; you can redistribute it and/or modify > +# it under the terms of the GNU General Public License as published by > +# the Free Software Foundation; either version 3 of the License, or > +# (at your option) any later version. > +# > +# This program is distributed in the hope that it will be useful, > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +# GNU General Public License for more details. > +# > +# You should have received a copy of the GNU General Public License > +# along with this program. If not, see <http://www.gnu.org/licenses/>. > + > +# Check that hardware watchpoints get replicated to all existing > +# threads when the hardware watchpoint is created. Ditto. > + > +set NR_THREADS 10 > +set NR_TRIGGERS_PER_THREAD 2 > + > +# This test verifies that a hardware watchpoint gets replicated to > +# every existing thread and is detected properly. This test is > +# only meaningful on a target with hardware watchpoint support. > +if {[skip_hw_watchpoint_tests]} { > + return 0 > +} > + > +standard_testfile > +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "additional_flags=-DNR_THREADS=$NR_THREADS -DNR_TRIGGERS_PER_THREAD=$NR_TRIGGERS_PER_THREAD"]] != "" } { > + return -1 > +} > + > +clean_restart ${binfile} > + > +# Force hardware watchpoints to be used. > +gdb_test_no_output "set can-use-hw-watchpoints 1" "" > + > +# Run to `main' where we begin our tests. > +if ![runto_main] then { > + gdb_suppress_tests Avoid gdb_suppress_tests. Just fail/return as usual. > +} > + > +# First, break at empty_cycle. > +gdb_test "break empty_cycle" \ > + "Breakpoint 2 at .*: file .*${srcfile}, line .*" \ > + "breakpoint on empty_cycle" > + > +# Set some default values. > +set hwatch_count 0 > +set done 0 > + > +# Count the number of hardware watchpoints available on > +# this target. > +while { $done == 0 } { > + > + gdb_test "continue" \ > + ".*Breakpoint 2, empty_cycle \\(\\) at .*${srcfile}.*" \ > + "continue to empty_cycle" > + > + # Some targets do resource counting as we insert watchpoints. > + # Such targets won't cause a watchpoint insertion failure, but > + # will switch to software watchpoints silently. We check for > + # both cases here. > + gdb_test_multiple "watch watched_data\[$hwatch_count\]" \ > + "watch watched_data\[$hwatch_count\]" { > + -re "Hardware watchpoint .*$gdb_prompt $" { > + } > + -re "Watchpoint .*$gdb_prompt $" { > + set done 1 > + break > + } > + } > + > + gdb_test_multiple "continue" "watchpoint created successfully" { > + -re ".*Breakpoint 2, empty_cycle \\(\\).*$gdb_prompt $" { > + incr hwatch_count > + } > + -re ".*Could not insert hardware watchpoint.*$gdb_prompt $" { > + set done 1 > + break > + } > + } > +} > + > +# Target cannot insert hardware watchpoints. Maybe it should have reported > +# it does not supported them in the first place. "does not support them". What does does this "maybe" note mean though? A bug? Where? > +if { $hwatch_count == 0} { > + gdb_exit; > +} I don't understand this. Exit gdb, but carry on? > + > +# Set the testcase's internal variable indicating the number of > +# hardware watchpoints the target supports. > +gdb_test_no_output "set var hw_watch_count=${hwatch_count}" \ > + "set var hw_watch_count=${hwatch_count}" > + > +# At this point, we know how many hardware watchpoints > +# the target supports. Use that to do further testing. > +delete_breakpoints > + > +# Break out of the empty_cycle loop by changing the > +# controlling variable. > +gdb_test_no_output "set var watch_count_done=1" \ > + "set var watch_count_done=1" > + > +# Prepare to create all the threads. > +gdb_test "break thread_started" \ > + "Breakpoint \[0-9\]+ at .*: file .*${srcfile}, line .*" \ > + "Breakpoint on thread_started" > + > +# Move all threads to where they're supposed to be for testing. > +for { set i 0 } { $i < $NR_THREADS } { incr i } { > + > + # We want to set the maximum number of hardware watchpoints > + # and make sure the target can handle that without an error. > + # That will show us the watchpoints got replicated to all the > + # threads correctly, and that no new watchpoints got created > + # in the background for a specific thread. > + if {$i < $hwatch_count} { > + gdb_test "watch watched_data\[$i\]" \ > + "Hardware watchpoint .*" \ > + "watch watched_data\[$i\]" > + } else { > + verbose -log "Not setting watchpoint for watched_data\[$i\]\n" > + } > + > + gdb_test continue "Continuing\\..*Breakpoint \[0-9\]+, thread_started \\(\\) at .*$srcfile.*" \ > + "Break at thread_started" > +} > + > +# Let the threads run and change the watched data, leading > +# to watchpoint triggers. > +gdb_test_no_output "set var test_ready=1" \ > + "set var test_ready=1" > + > +# Set the number of expected watchpoint triggers. > +set TRIGGERS [expr "$NR_THREADS * $hwatch_count * $NR_TRIGGERS_PER_THREAD"] > + > +# Move the threads and hit the watchpoints > +# TRIGGERS times. > +for { set i 0 } { $i < $TRIGGERS } { incr i} { > + gdb_test continue "Continuing\\..*Hardware watchpoint \[0-9\]+: watched_data\[\[0-9\]+\].*Old value = \[0-9\]+.*New value = \[0-9\]+.*thread_function \\(arg=$hex\\) at .*$srcfile.*" \ > + "Continue to watchpoint trigger ${i} out of ${TRIGGERS} on watched_data" > +} > + > +gdb_exit Not necessary. The test has repeated messages in gdb.sum: http://sourceware.org/gdb/wiki/GDBTestcaseCookbook#Make_sure_test_messages_are_unique Otherwise looks fine, and I confirm I no longer see racy FAILs either. Thanks, -- Pedro Alves ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment 2013-04-24 3:19 ` Pedro Alves @ 2013-04-24 6:28 ` Luis Machado 2013-04-24 19:04 ` Pedro Alves 0 siblings, 1 reply; 24+ messages in thread From: Luis Machado @ 2013-04-24 6:28 UTC (permalink / raw) To: Pedro Alves; +Cc: 'gdb-patches@sourceware.org' [-- Attachment #1: Type: text/plain, Size: 15304 bytes --] On 04/23/2013 06:16 PM, Pedro Alves wrote: > On 04/23/2013 02:30 PM, Luis Machado wrote: >> /* Copy that thread's breakpoints and watchpoints to the new thread. */ >> for (i = 0; i < max_slots_number; i++) >> if (hw_breaks[i].hw_break) >> - booke_insert_point (hw_breaks[i].hw_break, tid); >> + { >> + /* The ppc Linux kernel causes a thread to inherit its parent >> + thread's debug state, and that includes any hardware >> + watchpoints or breakpoints that the parent thread may have set. > > ISTR there was a point when the kernel changed behavior, right? > It'd be good to mention the kernel version here. I _think_ you wanted > to retain compatibility with older kernels, but, alas, the comment > doesn't mention that. I can't state what version of the kernel had the behavior changed. I cc-ed the kernel folks in the original mail, but we received no answers back. > > (Also, I'm left wondering if we couldn't detect the need for this > just once, and skip several ptrace calls if we find the kernel > does this for us already.) We probably could do that. The question is whether it brings us a great benefit compared to what we do now. Ideally the kernel developers would fix what is broken in my opinion. > >> + >> + For this reason, the debug state of the new thread is cleared >> + before trying to replicate any hardware watchpoints or >> + breakpoints contained in other threads. */ >> + >> + /* The ppc debug resource accounting is done through "slots". >> + Ask the kernel the deallocate this specific *point's slot. */ >> + ptrace (PPC_PTRACE_DELHWDEBUG, tid, 0, hw_breaks[i].slot); >> + >> + booke_insert_point (hw_breaks[i].hw_break, tid); >> + } > >> Index: gdb-head/gdb/testsuite/gdb.threads/wp-replication.c >> =================================================================== >> --- /dev/null 1970-01-01 00:00:00.000000000 +0000 >> +++ gdb-head/gdb/testsuite/gdb.threads/wp-replication.c 2013-04-23 15:29:10.518508221 +0200 >> @@ -0,0 +1,160 @@ >> +/* This testcase is part of GDB, the GNU debugger. >> + >> + Copyright 2013 Free Software Foundation, Inc. > > I now notice this was largely based on watchthreads2.c/exp. Please > retain the copyright years. Done. > >> + >> + This program is free software; you can redistribute it and/or modify >> + it under the terms of the GNU General Public License as published by >> + the Free Software Foundation; either version 3 of the License, or >> + (at your option) any later version. >> + >> + This program is distributed in the hope that it will be useful, >> + but WITHOUT ANY WARRANTY; without even the implied warranty of >> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + GNU General Public License for more details. >> + >> + You should have received a copy of the GNU General Public License >> + along with this program. If not, see <http://www.gnu.org/licenses/>. >> + >> + Check that hardware watchpoints get propagated to all existing >> + threads when the hardware watchpoint is created. > > Hmm. watchthreads2.exp has the exact same comment. Can we have some more > info here on what is supposed to be different between this and > watchthreads2.exp? Not a lot of difference here, except that we test for the specific scenario of adding one watchpoint per thread and checking if that succeeds until we reach the maximum count (something related to per-slot hw *points for powerpc). The testcase actually tests more than that. Maybe it is a more reliable hardware watchpoint test for targets, as it properly finds out the number of hardware watchpoints a target supports. I could probably expand it to test other kinds of watchpoints and variations. But maybe another day. :-) > >> +*/ >> + >> +#include <stdio.h> >> +#include <unistd.h> >> +#include <stdlib.h> >> +#include <stdint.h> >> +#include <pthread.h> >> + >> +#ifndef NR_THREADS >> +#define NR_THREADS 4 /* Set by the testcase. */ >> +#endif >> + >> +#ifndef X_INCR_COUNT >> +#define X_INCR_COUNT 10 /* Set by the testcase. */ >> +#endif >> + >> +void *thread_function (void *arg); /* Function executed by each thread. */ >> + >> +/* Used to hold threads back until wp-replication.exp is ready. */ >> +int test_ready = 0; >> + >> +/* Used to hold threads back until every thread has had a chance of causing >> + a watchpoint trigger. This prevents a situation in GDB where it may miss >> + watchpoint triggers when threads exit while other threads are causing >> + watchpoint triggers. */ >> +int can_terminate = 0; >> + >> +/* Used to push the program out of the waiting loop after the >> + testcase is done counting the number of hardware watchpoints >> + available for our target. */ >> +int watch_count_done = 0; >> + >> +/* Number of watchpoints GDB is capable of using (this is provided >> + by GDB during the test run). */ >> +int hw_watch_count = 0; >> + >> +/* Array with elements we can create watchpoints for. */ >> +static int watched_data[NR_THREADS]; >> +pthread_mutex_t data_mutex; >> + >> +/* Wait function to keep threads busy while the testcase does >> + what it needs to do. */ >> +void empty_cycle (void) >> +{ >> + usleep (1); >> +} >> + >> +int >> +main () >> +{ >> + int res; >> + pthread_t threads[NR_THREADS]; >> + int i; >> + >> + while (watch_count_done == 0) >> + { >> + /* GDB will modify the value of "i" at runtime and we will >> + get past this point. */ >> + empty_cycle (); >> + } >> + >> + pthread_mutex_init (&data_mutex, NULL); >> + >> + for (i = 0; i < NR_THREADS; i++) >> + { >> + res = pthread_create (&threads[i], >> + NULL, thread_function, >> + (void *) (intptr_t) i); >> + if (res != 0) >> + { >> + fprintf (stderr, "error in thread %d create\n", i); >> + abort (); >> + } >> + } >> + >> + for (i = 0; i < NR_THREADS; ++i) >> + { >> + res = pthread_join (threads[i], NULL); >> + if (res != 0) >> + { >> + fprintf (stderr, "error in thread %d join\n", i); >> + abort (); >> + } >> + } >> + >> + exit (EXIT_SUCCESS); >> +} >> + >> +/* Easy place for a breakpoint. >> + wp-replication.exp uses this to track when all threads are running >> + instead of, for example, the program keeping track >> + because we don't need the program to know when all threads are running, >> + instead we need gdb to know when all threads are running. >> + There is a delay between when a thread has started and when the thread >> + has been registered with gdb. */ >> + >> +void >> +thread_started () > > (void) Done. > >> +{ >> +} >> + >> +void * >> +thread_function (void *arg) >> +{ >> + int i, j; >> + long thread_number = (long) arg; >> + >> + thread_started (); >> + >> + /* Don't start incrementing X until wp-replication.exp is ready. */ >> + while (!test_ready) >> + usleep (1); >> + >> + pthread_mutex_lock (&data_mutex); >> + >> + for (i = 0; i < NR_TRIGGERS_PER_THREAD; i++) >> + { >> + for (j = 0; j < hw_watch_count; j++) >> + { >> + /* For debugging. */ >> + printf ("Thread %ld changing watch_thread[%d] data" >> + " from %d -> %d\n", thread_number, j, >> + watched_data[j], watched_data[j] + 1); >> + /* The call to usleep is so that when the watchpoint triggers, >> + the pc is still on the same line. */ > > This comment made sense in watchthreads2.c, which reads: > > printf ("Thread %ld changing x %d -> %d\n", (long) arg, x, x + 1); > /* The call to usleep is so that when the watchpoint triggers, > the pc is still on the same line. */ > ++x; usleep (1); /* X increment. */ > > but the usleep is no longer on the same line... Do we still need it, > even? No. Removed from the code. > >> + /* Increment the watched data field. */ >> + watched_data[j]++; >> + usleep (1); >> + } >> + } >> + >> + pthread_mutex_unlock (&data_mutex); >> + >> + /* Hold the threads here to work around a problem GDB has evaluating >> + watchpoints right when a DSO event shows up. Sleep a little longer > > s/shows up/shows up (PR breakpoints/10116)/ > > I'd s/longer// ("longer than what?") I've added more context on this. > >> + to avoid consuming lots of cycles. */ >> + while (!can_terminate) >> + usleep (100); >> + >> + pthread_exit (NULL); >> +} >> Index: gdb-head/gdb/testsuite/gdb.threads/wp-replication.exp >> =================================================================== >> --- /dev/null 1970-01-01 00:00:00.000000000 +0000 >> +++ gdb-head/gdb/testsuite/gdb.threads/wp-replication.exp 2013-04-23 15:13:16.230525175 +0200 >> @@ -0,0 +1,148 @@ >> +# This testcase is part of GDB, the GNU debugger. >> + >> +# Copyright 2013 Free Software Foundation, Inc. >> + >> +# This program is free software; you can redistribute it and/or modify >> +# it under the terms of the GNU General Public License as published by >> +# the Free Software Foundation; either version 3 of the License, or >> +# (at your option) any later version. >> +# >> +# This program is distributed in the hope that it will be useful, >> +# but WITHOUT ANY WARRANTY; without even the implied warranty of >> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> +# GNU General Public License for more details. >> +# >> +# You should have received a copy of the GNU General Public License >> +# along with this program. If not, see <http://www.gnu.org/licenses/>. >> + >> +# Check that hardware watchpoints get replicated to all existing >> +# threads when the hardware watchpoint is created. > > Ditto. > Done. >> + >> +set NR_THREADS 10 >> +set NR_TRIGGERS_PER_THREAD 2 >> + >> +# This test verifies that a hardware watchpoint gets replicated to >> +# every existing thread and is detected properly. This test is >> +# only meaningful on a target with hardware watchpoint support. >> +if {[skip_hw_watchpoint_tests]} { >> + return 0 >> +} >> + >> +standard_testfile >> +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "additional_flags=-DNR_THREADS=$NR_THREADS -DNR_TRIGGERS_PER_THREAD=$NR_TRIGGERS_PER_THREAD"]] != "" } { >> + return -1 >> +} >> + >> +clean_restart ${binfile} >> + >> +# Force hardware watchpoints to be used. >> +gdb_test_no_output "set can-use-hw-watchpoints 1" "" >> + >> +# Run to `main' where we begin our tests. >> +if ![runto_main] then { >> + gdb_suppress_tests > > Avoid gdb_suppress_tests. Just fail/return as usual. > Done. It just returns 0 now. >> +} >> + >> +# First, break at empty_cycle. >> +gdb_test "break empty_cycle" \ >> + "Breakpoint 2 at .*: file .*${srcfile}, line .*" \ >> + "breakpoint on empty_cycle" >> + >> +# Set some default values. >> +set hwatch_count 0 >> +set done 0 >> + >> +# Count the number of hardware watchpoints available on >> +# this target. >> +while { $done == 0 } { >> + >> + gdb_test "continue" \ >> + ".*Breakpoint 2, empty_cycle \\(\\) at .*${srcfile}.*" \ >> + "continue to empty_cycle" >> + >> + # Some targets do resource counting as we insert watchpoints. >> + # Such targets won't cause a watchpoint insertion failure, but >> + # will switch to software watchpoints silently. We check for >> + # both cases here. >> + gdb_test_multiple "watch watched_data\[$hwatch_count\]" \ >> + "watch watched_data\[$hwatch_count\]" { >> + -re "Hardware watchpoint .*$gdb_prompt $" { >> + } >> + -re "Watchpoint .*$gdb_prompt $" { >> + set done 1 >> + break >> + } >> + } >> + >> + gdb_test_multiple "continue" "watchpoint created successfully" { >> + -re ".*Breakpoint 2, empty_cycle \\(\\).*$gdb_prompt $" { >> + incr hwatch_count >> + } >> + -re ".*Could not insert hardware watchpoint.*$gdb_prompt $" { >> + set done 1 >> + break >> + } >> + } >> +} >> + >> +# Target cannot insert hardware watchpoints. Maybe it should have reported >> +# it does not supported them in the first place. > > "does not support them". What does does this "maybe" note mean though? > A bug? Where? > It means that whoever has configured the testsuite for this target did not clearly specify it does not support hardware watchpoints (in gdbserver, for example). In practice, it means we will succeed in executing the first part of the test, but we will exit due to the number of available hardware watchpoints being 0. >> +if { $hwatch_count == 0} { >> + gdb_exit; >> +} > > I don't understand this. Exit gdb, but carry on? > Thinko, this should just return 0. >> + >> +# Set the testcase's internal variable indicating the number of >> +# hardware watchpoints the target supports. >> +gdb_test_no_output "set var hw_watch_count=${hwatch_count}" \ >> + "set var hw_watch_count=${hwatch_count}" >> + >> +# At this point, we know how many hardware watchpoints >> +# the target supports. Use that to do further testing. >> +delete_breakpoints >> + >> +# Break out of the empty_cycle loop by changing the >> +# controlling variable. >> +gdb_test_no_output "set var watch_count_done=1" \ >> + "set var watch_count_done=1" >> + >> +# Prepare to create all the threads. >> +gdb_test "break thread_started" \ >> + "Breakpoint \[0-9\]+ at .*: file .*${srcfile}, line .*" \ >> + "Breakpoint on thread_started" >> + >> +# Move all threads to where they're supposed to be for testing. >> +for { set i 0 } { $i < $NR_THREADS } { incr i } { >> + >> + # We want to set the maximum number of hardware watchpoints >> + # and make sure the target can handle that without an error. >> + # That will show us the watchpoints got replicated to all the >> + # threads correctly, and that no new watchpoints got created >> + # in the background for a specific thread. >> + if {$i < $hwatch_count} { >> + gdb_test "watch watched_data\[$i\]" \ >> + "Hardware watchpoint .*" \ >> + "watch watched_data\[$i\]" >> + } else { >> + verbose -log "Not setting watchpoint for watched_data\[$i\]\n" >> + } >> + >> + gdb_test continue "Continuing\\..*Breakpoint \[0-9\]+, thread_started \\(\\) at .*$srcfile.*" \ >> + "Break at thread_started" >> +} >> + >> +# Let the threads run and change the watched data, leading >> +# to watchpoint triggers. >> +gdb_test_no_output "set var test_ready=1" \ >> + "set var test_ready=1" >> + >> +# Set the number of expected watchpoint triggers. >> +set TRIGGERS [expr "$NR_THREADS * $hwatch_count * $NR_TRIGGERS_PER_THREAD"] >> + >> +# Move the threads and hit the watchpoints >> +# TRIGGERS times. >> +for { set i 0 } { $i < $TRIGGERS } { incr i} { >> + gdb_test continue "Continuing\\..*Hardware watchpoint \[0-9\]+: watched_data\[\[0-9\]+\].*Old value = \[0-9\]+.*New value = \[0-9\]+.*thread_function \\(arg=$hex\\) at .*$srcfile.*" \ >> + "Continue to watchpoint trigger ${i} out of ${TRIGGERS} on watched_data" >> +} >> + > > >> +gdb_exit > > Not necessary. Done. > > > The test has repeated messages in gdb.sum: > > http://sourceware.org/gdb/wiki/GDBTestcaseCookbook#Make_sure_test_messages_are_unique > > > Otherwise looks fine, and I confirm I no longer see racy FAILs either. > > Thanks, > Seems to be fixed now with unique messages and more numbers to make them unique. Thanks! [-- Attachment #2: hw_watch.diff --] [-- Type: text/x-patch, Size: 12314 bytes --] 2013-04-23 Luis Machado <lgustavo@codesourcery.com> * ppc-linux-nat.c (ppc_linux_new_thread): Clear the new thread's debug state prior to replicating existing hardware watchpoints or breakpoints. * gdb/testsuite/gdb.threads/wp-replication.c: New file. * gdb/testsuite/gdb.threads/wp-replication.exp: New file. Index: gdb-head/gdb/ppc-linux-nat.c =================================================================== --- gdb-head.orig/gdb/ppc-linux-nat.c 2013-04-23 16:34:19.726438757 +0200 +++ gdb-head/gdb/ppc-linux-nat.c 2013-04-23 16:34:28.314438605 +0200 @@ -2178,7 +2178,21 @@ ppc_linux_new_thread (struct lwp_info *l /* Copy that thread's breakpoints and watchpoints to the new thread. */ for (i = 0; i < max_slots_number; i++) if (hw_breaks[i].hw_break) - booke_insert_point (hw_breaks[i].hw_break, tid); + { + /* The ppc Linux kernel causes a thread to inherit its parent + thread's debug state, and that includes any hardware + watchpoints or breakpoints that the parent thread may have set. + + For this reason, the debug state of the new thread is cleared + before trying to replicate any hardware watchpoints or + breakpoints contained in other threads. */ + + /* The ppc debug resource accounting is done through "slots". + Ask the kernel the deallocate this specific *point's slot. */ + ptrace (PPC_PTRACE_DELHWDEBUG, tid, 0, hw_breaks[i].slot); + + booke_insert_point (hw_breaks[i].hw_break, tid); + } } else ptrace (PTRACE_SET_DEBUGREG, tid, 0, saved_dabr_value); Index: gdb-head/gdb/testsuite/gdb.threads/wp-replication.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gdb-head/gdb/testsuite/gdb.threads/wp-replication.c 2013-04-23 19:38:03.330242882 +0200 @@ -0,0 +1,162 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2009-2013 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + Check that hardware watchpoints get correctly replicated to all + existing threads when hardware watchpoints are created. This test + creates one hardware watchpoint per thread until a maximum is + reached. It originally addresses a deficiency seen on embedded + powerpc targets with slotted hardware *point designs. +*/ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdint.h> +#include <pthread.h> + +#ifndef NR_THREADS +#define NR_THREADS 4 /* Set by the testcase. */ +#endif + +#ifndef X_INCR_COUNT +#define X_INCR_COUNT 10 /* Set by the testcase. */ +#endif + +void *thread_function (void *arg); /* Function executed by each thread. */ + +/* Used to hold threads back until wp-replication.exp is ready. */ +int test_ready = 0; + +/* Used to hold threads back until every thread has had a chance of causing + a watchpoint trigger. This prevents a situation in GDB where it may miss + watchpoint triggers when threads exit while other threads are causing + watchpoint triggers. */ +int can_terminate = 0; + +/* Used to push the program out of the waiting loop after the + testcase is done counting the number of hardware watchpoints + available for our target. */ +int watch_count_done = 0; + +/* Number of watchpoints GDB is capable of using (this is provided + by GDB during the test run). */ +int hw_watch_count = 0; + +/* Array with elements we can create watchpoints for. */ +static int watched_data[NR_THREADS]; +pthread_mutex_t data_mutex; + +/* Wait function to keep threads busy while the testcase does + what it needs to do. */ +void empty_cycle (void) +{ + usleep (1); +} + +int +main () +{ + int res; + pthread_t threads[NR_THREADS]; + int i; + + while (watch_count_done == 0) + { + /* GDB will modify the value of "i" at runtime and we will + get past this point. */ + empty_cycle (); + } + + pthread_mutex_init (&data_mutex, NULL); + + for (i = 0; i < NR_THREADS; i++) + { + res = pthread_create (&threads[i], + NULL, thread_function, + (void *) (intptr_t) i); + if (res != 0) + { + fprintf (stderr, "error in thread %d create\n", i); + abort (); + } + } + + for (i = 0; i < NR_THREADS; ++i) + { + res = pthread_join (threads[i], NULL); + if (res != 0) + { + fprintf (stderr, "error in thread %d join\n", i); + abort (); + } + } + + exit (EXIT_SUCCESS); +} + +/* Easy place for a breakpoint. + wp-replication.exp uses this to track when all threads are running + instead of, for example, the program keeping track + because we don't need the program to know when all threads are running, + instead we need gdb to know when all threads are running. + There is a delay between when a thread has started and when the thread + has been registered with gdb. */ + +void +thread_started (void) +{ +} + +void * +thread_function (void *arg) +{ + int i, j; + long thread_number = (long) arg; + + thread_started (); + + /* Don't start incrementing X until wp-replication.exp is ready. */ + while (!test_ready) + usleep (1); + + pthread_mutex_lock (&data_mutex); + + for (i = 0; i < NR_TRIGGERS_PER_THREAD; i++) + { + for (j = 0; j < hw_watch_count; j++) + { + /* For debugging. */ + printf ("Thread %ld changing watch_thread[%d] data" + " from %d -> %d\n", thread_number, j, + watched_data[j], watched_data[j] + 1); + /* Increment the watched data field. */ + watched_data[j]++; + } + } + + pthread_mutex_unlock (&data_mutex); + + /* Hold the threads here to work around a problem GDB has evaluating + watchpoints right when a DSO event shows up (PR breakpoints/10116). + Sleep a little longer (than, say, 1, 5 or 10) to avoid consuming + lots of cycles while the other threads are trying to execute the + loop. */ + while (!can_terminate) + usleep (100); + + pthread_exit (NULL); +} Index: gdb-head/gdb/testsuite/gdb.threads/wp-replication.exp =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gdb-head/gdb/testsuite/gdb.threads/wp-replication.exp 2013-04-23 19:59:56.506219548 +0200 @@ -0,0 +1,150 @@ +# This testcase is part of GDB, the GNU debugger. + +# Copyright 2009-2013 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Check that hardware watchpoints get correctly replicated to all +# existing threads when hardware watchpoints are created. This test +# creates one hardware watchpoint per thread until a maximum is +# reached. It originally addresses a deficiency seen on embedded +# powerpc targets with slotted hardware *point designs. + +set NR_THREADS 10 +set NR_TRIGGERS_PER_THREAD 2 + +# This test verifies that a hardware watchpoint gets replicated to +# every existing thread and is detected properly. This test is +# only meaningful on a target with hardware watchpoint support. +if {[skip_hw_watchpoint_tests]} { + return 0 +} + +standard_testfile +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "additional_flags=-DNR_THREADS=$NR_THREADS -DNR_TRIGGERS_PER_THREAD=$NR_TRIGGERS_PER_THREAD"]] != "" } { + return -1 +} + +clean_restart ${binfile} + +# Force hardware watchpoints to be used. +gdb_test_no_output "set can-use-hw-watchpoints 1" "" + +# Run to `main' where we begin our tests. +if ![runto_main] then { + fail "Failed to run to main" +} + +# First, break at empty_cycle. +gdb_test "break empty_cycle" \ + "Breakpoint 2 at .*: file .*${srcfile}, line .*" \ + "Breakpoint on empty_cycle" + +# Set some default values. +set hwatch_count 0 +set done 0 + +# Count the number of hardware watchpoints available on +# this target. +while { $done == 0 } { + + gdb_test "continue" \ + ".*Breakpoint 2, empty_cycle \\(\\) at .*${srcfile}.*" \ + "Continue to empty_cycle to insert watchpoint $hwatch_count" + + # Some targets do resource counting as we insert watchpoints. + # Such targets won't cause a watchpoint insertion failure, but + # will switch to software watchpoints silently. We check for + # both cases here. + gdb_test_multiple "watch watched_data\[$hwatch_count\]" \ + "watch watched_data\[$hwatch_count\]" { + -re "Hardware watchpoint .*$gdb_prompt $" { + } + -re "Watchpoint .*$gdb_prompt $" { + set done 1 + break + } + } + + gdb_test_multiple "continue" "watchpoint created successfully" { + -re ".*Breakpoint 2, empty_cycle \\(\\).*$gdb_prompt $" { + incr hwatch_count + } + -re ".*Could not insert hardware watchpoint.*$gdb_prompt $" { + set done 1 + break + } + } +} + +# Target cannot insert hardware watchpoints. It should have reported +# (through board settings) that it did not support them in the first place. +# Just exit. +if { $hwatch_count == 0} { + return 0; +} + +# Set the testcase's internal variable indicating the number of +# hardware watchpoints the target supports. +gdb_test_no_output "set var hw_watch_count=${hwatch_count}" \ + "set var hw_watch_count=${hwatch_count}" + +# At this point, we know how many hardware watchpoints +# the target supports. Use that to do further testing. +delete_breakpoints + +# Break out of the empty_cycle loop by changing the +# controlling variable. +gdb_test_no_output "set var watch_count_done=1" \ + "set var watch_count_done=1" + +# Prepare to create all the threads. +gdb_test "break thread_started" \ + "Breakpoint \[0-9\]+ at .*: file .*${srcfile}, line .*" \ + "Breakpoint on thread_started" + +# Move all threads to where they're supposed to be for testing. +for { set i 0 } { $i < $NR_THREADS } { incr i } { + + # We want to set the maximum number of hardware watchpoints + # and make sure the target can handle that without an error. + # That will show us the watchpoints got replicated to all the + # threads correctly, and that no new watchpoints got created + # in the background for a specific thread. + if {$i < $hwatch_count} { + gdb_test "watch watched_data\[$i\]" \ + "Hardware watchpoint .*" \ + "watch watched_data\[$i\]" + } else { + verbose -log "Not setting watchpoint for watched_data\[$i\]\n" + } + + gdb_test continue "Continuing\\..*Breakpoint \[0-9\]+, thread_started \\(\\) at .*$srcfile.*" \ + "Thread $i hit breakpoint at thread_started" +} + +# Let the threads run and change the watched data, leading +# to watchpoint triggers. +gdb_test_no_output "set var test_ready=1" \ + "set var test_ready=1" + +# Set the number of expected watchpoint triggers. +set TRIGGERS [expr "$NR_THREADS * $hwatch_count * $NR_TRIGGERS_PER_THREAD"] + +# Move the threads and hit the watchpoints +# TRIGGERS times. +for { set i 1 } { $i <= $TRIGGERS} { incr i} { + gdb_test continue "Continuing\\..*Hardware watchpoint \[0-9\]+: watched_data\[\[0-9\]+\].*Old value = \[0-9\]+.*New value = \[0-9\]+.*thread_function \\(arg=$hex\\) at .*$srcfile.*" \ + "Continue to watchpoint trigger $i out of ${TRIGGERS} on watched_data" +} ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment 2013-04-24 6:28 ` Luis Machado @ 2013-04-24 19:04 ` Pedro Alves 2013-04-25 14:13 ` Luis Machado 0 siblings, 1 reply; 24+ messages in thread From: Pedro Alves @ 2013-04-24 19:04 UTC (permalink / raw) To: lgustavo; +Cc: 'gdb-patches@sourceware.org' On 04/23/2013 07:03 PM, Luis Machado wrote: > On 04/23/2013 06:16 PM, Pedro Alves wrote: >> On 04/23/2013 02:30 PM, Luis Machado wrote: >>> /* Copy that thread's breakpoints and watchpoints to the new thread. */ >>> for (i = 0; i < max_slots_number; i++) >>> if (hw_breaks[i].hw_break) >>> - booke_insert_point (hw_breaks[i].hw_break, tid); >>> + { >>> + /* The ppc Linux kernel causes a thread to inherit its parent >>> + thread's debug state, and that includes any hardware >>> + watchpoints or breakpoints that the parent thread may have set. >> >> ISTR there was a point when the kernel changed behavior, right? >> It'd be good to mention the kernel version here. I _think_ you wanted >> to retain compatibility with older kernels, but, alas, the comment >> doesn't mention that. > > I can't state what version of the kernel had the behavior changed. I cc-ed the kernel folks in the original mail, but we received no answers back. > >> >> (Also, I'm left wondering if we couldn't detect the need for this >> just once, and skip several ptrace calls if we find the kernel >> does this for us already.) > > We probably could do that. The question is whether it brings us a great benefit compared to what we do now. Ideally the kernel developers would fix what is broken in my opinion. One idea for less intrusive debugging would be to make it so the kernel doesn't notified of new threads/clones at all, IOW, not force parent/child clones to stop to report the child's existence to a ptracer (unless it wants to). Having the kernel auto-copy debug resources in the new child is a requirement for that, and given ptrace options and other things are copied as well, I can't really call it broken outright. I'd suggest just mixing something like Older kernels did not make new threads inherit their parent thread's debug state, so we always clear the slot and replicate the debug state ourselves, ensuring compatibility with all kernels. into the existing comment. >>> +# Run to `main' where we begin our tests. >>> +if ![runto_main] then { >>> + gdb_suppress_tests >> >> Avoid gdb_suppress_tests. Just fail/return as usual. >> > > Done. It just returns 0 now. It does not: +# Run to `main' where we begin our tests. +if ![runto_main] then { + fail "Failed to run to main" +} + >>> +# Target cannot insert hardware watchpoints. Maybe it should have reported >>> +# it does not supported them in the first place. >> >> "does not support them". What does does this "maybe" note mean though? >> A bug? Where? >> > > It means that whoever has configured the testsuite for this target did not clearly specify it does not support hardware watchpoints (in gdbserver, for example). Let's call "unsupported" or even FAIL then, so it can draw attention. We could also end up in that situation due to a bug somewhere in the test or gdb. Something like 'fail "no hardware watchpoints"'. > 2013-04-23 Luis Machado <lgustavo@codesourcery.com> > > * ppc-linux-nat.c (ppc_linux_new_thread): Clear the new thread's > debug state prior to replicating existing hardware watchpoints or > breakpoints. > > * gdb/testsuite/gdb.threads/wp-replication.c: New file. > * gdb/testsuite/gdb.threads/wp-replication.exp: New file. Recall that these go to gdb/testsuite/ChangeLog. To indicate to the reviewer that was not a mistake, I suggest posting the entry like: 2013-04-23 Luis Machado <lgustavo@codesourcery.com> gdb/ * ppc-linux-nat.c (ppc_linux_new_thread): Clear the new thread's debug state prior to replicating existing hardware watchpoints or breakpoints. gdb/testsuite/ * gdb.threads/wp-replication.c: New file. * gdb.threads/wp-replication.exp: New file. or: gdb/ 2013-04-23 Luis Machado <lgustavo@codesourcery.com> * ppc-linux-nat.c (ppc_linux_new_thread): Clear the new thread's debug state prior to replicating existing hardware watchpoints or breakpoints. gdb/testsuite/ 2013-04-23 Luis Machado <lgustavo@codesourcery.com> * gdb.threads/wp-replication.c: New file. * gdb.threads/wp-replication.exp: New file. > +void empty_cycle (void) '\n' after first void. > +for { set i 1 } { $i <= $TRIGGERS} { incr i} { -------^ -----^ Missing spaces. > +# Move the threads and hit the watchpoints > +# TRIGGERS times. Nit, that fits in a single line. Otherwise OK. Thanks, -- Pedro Alves ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment 2013-04-24 19:04 ` Pedro Alves @ 2013-04-25 14:13 ` Luis Machado 2013-05-07 7:44 ` Luis Machado 0 siblings, 1 reply; 24+ messages in thread From: Luis Machado @ 2013-04-25 14:13 UTC (permalink / raw) To: Pedro Alves; +Cc: 'gdb-patches@sourceware.org' [-- Attachment #1: Type: text/plain, Size: 1514 bytes --] > One idea for less intrusive debugging would be to make it so > the kernel doesn't notified of new threads/clones at all, IOW, not > force parent/child clones to stop to report the child's existence to > a ptracer (unless it wants to). Having the kernel auto-copy debug > resources in the new child is a requirement for that, and given > ptrace options and other things are copied as well, I can't > really call it broken outright. > > I'd suggest just mixing something like > > Older kernels did not make new threads inherit their parent thread's > debug state, so we always clear the slot and replicate the debug state > ourselves, ensuring compatibility with all kernels. > > into the existing comment. > The comment looked thorough enough that i went with it. > It does not: > > +# Run to `main' where we begin our tests. > +if ![runto_main] then { > + fail "Failed to run to main" > +} > + Really done now. > Let's call "unsupported" or even FAIL then, so it can draw attention. > We could also end up in that situation due to a bug somewhere in the > test or gdb. Something like 'fail "no hardware watchpoints"'. Done. >> +void empty_cycle (void) > > '\n' after first void. Done. > >> +for { set i 1 } { $i <= $TRIGGERS} { incr i} { > -------^ -----^ > Missing spaces. > Done. >> +# Move the threads and hit the watchpoints >> +# TRIGGERS times. > > Nit, that fits in a single line. Done. > > Otherwise OK. Thanks! I'll check it in later today. Luis [-- Attachment #2: hw_watch.diff --] [-- Type: text/x-patch, Size: 12272 bytes --] gdb/ 2013-04-25 Luis Machado <lgustavo@codesourcery.com> * ppc-linux-nat.c (ppc_linux_new_thread): Clear the new thread's debug state prior to replicating existing hardware watchpoints or breakpoints. gdb/testsuite/ 2013-04-25 Luis Machado <lgustavo@codesourcery.com> gdb/testsuite * gdb.threads/wp-replication.c: New file. * gdb.threads/wp-replication.exp: New file. Index: gdb-head/gdb/ppc-linux-nat.c =================================================================== --- gdb-head.orig/gdb/ppc-linux-nat.c 2013-04-23 16:34:19.726438757 +0200 +++ gdb-head/gdb/ppc-linux-nat.c 2013-04-25 07:42:30.325296537 +0200 @@ -2178,7 +2178,18 @@ ppc_linux_new_thread (struct lwp_info *l /* Copy that thread's breakpoints and watchpoints to the new thread. */ for (i = 0; i < max_slots_number; i++) if (hw_breaks[i].hw_break) - booke_insert_point (hw_breaks[i].hw_break, tid); + { + /* Older kernels did not make new threads inherit their parent + thread's debug state, so we always clear the slot and replicate + the debug state ourselves, ensuring compatibility with all + kernels. */ + + /* The ppc debug resource accounting is done through "slots". + Ask the kernel the deallocate this specific *point's slot. */ + ptrace (PPC_PTRACE_DELHWDEBUG, tid, 0, hw_breaks[i].slot); + + booke_insert_point (hw_breaks[i].hw_break, tid); + } } else ptrace (PTRACE_SET_DEBUGREG, tid, 0, saved_dabr_value); Index: gdb-head/gdb/testsuite/gdb.threads/wp-replication.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gdb-head/gdb/testsuite/gdb.threads/wp-replication.c 2013-04-25 07:23:24.281316900 +0200 @@ -0,0 +1,163 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2009-2013 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + Check that hardware watchpoints get correctly replicated to all + existing threads when hardware watchpoints are created. This test + creates one hardware watchpoint per thread until a maximum is + reached. It originally addresses a deficiency seen on embedded + powerpc targets with slotted hardware *point designs. +*/ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdint.h> +#include <pthread.h> + +#ifndef NR_THREADS +#define NR_THREADS 4 /* Set by the testcase. */ +#endif + +#ifndef X_INCR_COUNT +#define X_INCR_COUNT 10 /* Set by the testcase. */ +#endif + +void *thread_function (void *arg); /* Function executed by each thread. */ + +/* Used to hold threads back until wp-replication.exp is ready. */ +int test_ready = 0; + +/* Used to hold threads back until every thread has had a chance of causing + a watchpoint trigger. This prevents a situation in GDB where it may miss + watchpoint triggers when threads exit while other threads are causing + watchpoint triggers. */ +int can_terminate = 0; + +/* Used to push the program out of the waiting loop after the + testcase is done counting the number of hardware watchpoints + available for our target. */ +int watch_count_done = 0; + +/* Number of watchpoints GDB is capable of using (this is provided + by GDB during the test run). */ +int hw_watch_count = 0; + +/* Array with elements we can create watchpoints for. */ +static int watched_data[NR_THREADS]; +pthread_mutex_t data_mutex; + +/* Wait function to keep threads busy while the testcase does + what it needs to do. */ +void +empty_cycle (void) +{ + usleep (1); +} + +int +main () +{ + int res; + pthread_t threads[NR_THREADS]; + int i; + + while (watch_count_done == 0) + { + /* GDB will modify the value of "i" at runtime and we will + get past this point. */ + empty_cycle (); + } + + pthread_mutex_init (&data_mutex, NULL); + + for (i = 0; i < NR_THREADS; i++) + { + res = pthread_create (&threads[i], + NULL, thread_function, + (void *) (intptr_t) i); + if (res != 0) + { + fprintf (stderr, "error in thread %d create\n", i); + abort (); + } + } + + for (i = 0; i < NR_THREADS; ++i) + { + res = pthread_join (threads[i], NULL); + if (res != 0) + { + fprintf (stderr, "error in thread %d join\n", i); + abort (); + } + } + + exit (EXIT_SUCCESS); +} + +/* Easy place for a breakpoint. + wp-replication.exp uses this to track when all threads are running + instead of, for example, the program keeping track + because we don't need the program to know when all threads are running, + instead we need gdb to know when all threads are running. + There is a delay between when a thread has started and when the thread + has been registered with gdb. */ + +void +thread_started (void) +{ +} + +void * +thread_function (void *arg) +{ + int i, j; + long thread_number = (long) arg; + + thread_started (); + + /* Don't start incrementing X until wp-replication.exp is ready. */ + while (!test_ready) + usleep (1); + + pthread_mutex_lock (&data_mutex); + + for (i = 0; i < NR_TRIGGERS_PER_THREAD; i++) + { + for (j = 0; j < hw_watch_count; j++) + { + /* For debugging. */ + printf ("Thread %ld changing watch_thread[%d] data" + " from %d -> %d\n", thread_number, j, + watched_data[j], watched_data[j] + 1); + /* Increment the watched data field. */ + watched_data[j]++; + } + } + + pthread_mutex_unlock (&data_mutex); + + /* Hold the threads here to work around a problem GDB has evaluating + watchpoints right when a DSO event shows up (PR breakpoints/10116). + Sleep a little longer (than, say, 1, 5 or 10) to avoid consuming + lots of cycles while the other threads are trying to execute the + loop. */ + while (!can_terminate) + usleep (100); + + pthread_exit (NULL); +} Index: gdb-head/gdb/testsuite/gdb.threads/wp-replication.exp =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gdb-head/gdb/testsuite/gdb.threads/wp-replication.exp 2013-04-25 07:24:16.245315977 +0200 @@ -0,0 +1,151 @@ +# This testcase is part of GDB, the GNU debugger. + +# Copyright 2009-2013 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Check that hardware watchpoints get correctly replicated to all +# existing threads when hardware watchpoints are created. This test +# creates one hardware watchpoint per thread until a maximum is +# reached. It originally addresses a deficiency seen on embedded +# powerpc targets with slotted hardware *point designs. + +set NR_THREADS 10 +set NR_TRIGGERS_PER_THREAD 2 + +# This test verifies that a hardware watchpoint gets replicated to +# every existing thread and is detected properly. This test is +# only meaningful on a target with hardware watchpoint support. +if {[skip_hw_watchpoint_tests]} { + return 0 +} + +standard_testfile +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "additional_flags=-DNR_THREADS=$NR_THREADS -DNR_TRIGGERS_PER_THREAD=$NR_TRIGGERS_PER_THREAD"]] != "" } { + return -1 +} + +clean_restart ${binfile} + +# Force hardware watchpoints to be used. +gdb_test_no_output "set can-use-hw-watchpoints 1" "" + +# Run to `main' where we begin our tests. +if ![runto_main] then { + fail "Failed to run to main" + return 0 +} + +# First, break at empty_cycle. +gdb_test "break empty_cycle" \ + "Breakpoint 2 at .*: file .*${srcfile}, line .*" \ + "Breakpoint on empty_cycle" + +# Set some default values. +set hwatch_count 0 +set done 0 + +# Count the number of hardware watchpoints available on +# this target. +while { $done == 0 } { + + gdb_test "continue" \ + ".*Breakpoint 2, empty_cycle \\(\\) at .*${srcfile}.*" \ + "Continue to empty_cycle to insert watchpoint $hwatch_count" + + # Some targets do resource counting as we insert watchpoints. + # Such targets won't cause a watchpoint insertion failure, but + # will switch to software watchpoints silently. We check for + # both cases here. + gdb_test_multiple "watch watched_data\[$hwatch_count\]" \ + "watch watched_data\[$hwatch_count\]" { + -re "Hardware watchpoint .*$gdb_prompt $" { + } + -re "Watchpoint .*$gdb_prompt $" { + set done 1 + break + } + } + + gdb_test_multiple "continue" "watchpoint created successfully" { + -re ".*Breakpoint 2, empty_cycle \\(\\).*$gdb_prompt $" { + incr hwatch_count + } + -re ".*Could not insert hardware watchpoint.*$gdb_prompt $" { + set done 1 + break + } + } +} + +# Target cannot insert hardware watchpoints. It should have reported +# (through board settings) that it did not support them in the first place. +# Just exit. +if { $hwatch_count == 0} { + fail "No hardware watchpoints available" + return 0 +} + +# Set the testcase's internal variable indicating the number of +# hardware watchpoints the target supports. +gdb_test_no_output "set var hw_watch_count=${hwatch_count}" \ + "set var hw_watch_count=${hwatch_count}" + +# At this point, we know how many hardware watchpoints +# the target supports. Use that to do further testing. +delete_breakpoints + +# Break out of the empty_cycle loop by changing the +# controlling variable. +gdb_test_no_output "set var watch_count_done=1" \ + "set var watch_count_done=1" + +# Prepare to create all the threads. +gdb_test "break thread_started" \ + "Breakpoint \[0-9\]+ at .*: file .*${srcfile}, line .*" \ + "Breakpoint on thread_started" + +# Move all threads to where they're supposed to be for testing. +for { set i 0 } { $i < $NR_THREADS } { incr i } { + + # We want to set the maximum number of hardware watchpoints + # and make sure the target can handle that without an error. + # That will show us the watchpoints got replicated to all the + # threads correctly, and that no new watchpoints got created + # in the background for a specific thread. + if {$i < $hwatch_count} { + gdb_test "watch watched_data\[$i\]" \ + "Hardware watchpoint .*" \ + "watch watched_data\[$i\]" + } else { + verbose -log "Not setting watchpoint for watched_data\[$i\]\n" + } + + gdb_test continue "Continuing\\..*Breakpoint \[0-9\]+, thread_started \\(\\) at .*$srcfile.*" \ + "Thread $i hit breakpoint at thread_started" +} + +# Let the threads run and change the watched data, leading +# to watchpoint triggers. +gdb_test_no_output "set var test_ready=1" \ + "set var test_ready=1" + +# Set the number of expected watchpoint triggers. +set TRIGGERS [expr "$NR_THREADS * $hwatch_count * $NR_TRIGGERS_PER_THREAD"] + +# Move the threads and hit the watchpoints TRIGGERS times. +for { set i 1 } { $i <= $TRIGGERS } { incr i } { + gdb_test continue "Continuing\\..*Hardware watchpoint \[0-9\]+: watched_data\[\[0-9\]+\].*Old value = \[0-9\]+.*New value = \[0-9\]+.*thread_function \\(arg=$hex\\) at .*$srcfile.*" \ + "Continue to watchpoint trigger $i out of ${TRIGGERS} on watched_data" +} ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment 2013-04-25 14:13 ` Luis Machado @ 2013-05-07 7:44 ` Luis Machado 0 siblings, 0 replies; 24+ messages in thread From: Luis Machado @ 2013-05-07 7:44 UTC (permalink / raw) Cc: Pedro Alves, 'gdb-patches@sourceware.org' On 04/25/2013 07:48 AM, Luis Machado wrote: > gdb/ > 2013-04-25 Luis Machado<lgustavo@codesourcery.com> > > * ppc-linux-nat.c (ppc_linux_new_thread): Clear the new thread's > debug state prior to replicating existing hardware watchpoints or > breakpoints. > > gdb/testsuite/ > 2013-04-25 Luis Machado<lgustavo@codesourcery.com> > > * gdb.threads/wp-replication.c: New file. > * gdb.threads/wp-replication.exp: New file. I've checked this in now. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment 2013-04-23 23:18 ` Luis Machado 2013-04-24 3:19 ` Pedro Alves @ 2013-04-24 4:36 ` Pedro Alves 1 sibling, 0 replies; 24+ messages in thread From: Pedro Alves @ 2013-04-24 4:36 UTC (permalink / raw) To: lgustavo; +Cc: 'gdb-patches@sourceware.org' Whoops, looks like I forgot to paste this bit of the reply into the other mail. On 04/23/2013 02:30 PM, Luis Machado wrote: > On 04/22/2013 09:02 PM, Pedro Alves wrote: >> I hacked GDB some more, and I have further insight. >> GDB _is_ to blame. Updated GDB/test hack patch at the bottom. > >> So GDB is to blame. Fixing this, however, would be a different >> story, and doesn't look that simple. I found a PR already covering this, btw. breakpoints/10116. > The question here is how many threads we should spawn. I went with 10 since that is often greater than the number of hardware watchpoints in a target. Sounds fine to me. -- Pedro Alves ^ permalink raw reply [flat|nested] 24+ messages in thread
end of thread, other threads:[~2013-05-07 7:44 UTC | newest] Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2012-08-06 14:33 [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment Luis Gustavo 2012-08-06 18:40 ` Jan Kratochvil 2012-08-06 19:02 ` Luis Gustavo 2012-08-06 20:28 ` Jan Kratochvil 2012-08-07 14:55 ` Luis Gustavo 2012-08-07 15:00 ` Jan Kratochvil 2012-08-07 15:02 ` Luis Gustavo 2012-12-27 19:50 ` Luis Machado 2013-01-22 12:12 ` Pedro Alves 2013-04-17 20:33 Luis Machado 2013-04-18 0:19 ` Sergio Durigan Junior 2013-04-18 0:51 ` Luis Machado 2013-04-22 21:09 ` Luis Machado 2013-04-22 21:09 ` Pedro Alves 2013-04-23 0:05 ` Pedro Alves 2013-04-23 1:15 ` Pedro Alves 2013-04-23 20:25 ` Luis Machado 2013-04-23 23:18 ` Luis Machado 2013-04-24 3:19 ` Pedro Alves 2013-04-24 6:28 ` Luis Machado 2013-04-24 19:04 ` Pedro Alves 2013-04-25 14:13 ` Luis Machado 2013-05-07 7:44 ` Luis Machado 2013-04-24 4:36 ` Pedro Alves
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox