Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Luis Machado <lgustavo@codesourcery.com>
To: Pedro Alves <palves@redhat.com>
Cc: "'gdb-patches@sourceware.org'" <gdb-patches@sourceware.org>
Subject: Re: [PATCH, ppc] Fix hw *points for embedded ppc in a threaded environment
Date: Thu, 25 Apr 2013 14:13:00 -0000	[thread overview]
Message-ID: <5178C3A6.7010302@codesourcery.com> (raw)
In-Reply-To: <5177F7D6.6070908@redhat.com>

[-- 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"
+}

  reply	other threads:[~2013-04-25  5:48 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
2013-05-07  7:44                   ` Luis Machado
2013-04-24  4:36           ` Pedro Alves
  -- strict thread matches above, loose matches on Subject: below --
2012-08-06 14:33 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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5178C3A6.7010302@codesourcery.com \
    --to=lgustavo@codesourcery.com \
    --cc=gdb-patches@sourceware.org \
    --cc=palves@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox