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.
This commit is contained in:
parent
0c01335354
commit
aacbb8a556
|
@ -1,3 +1,9 @@
|
|||
2013-05-07 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.
|
||||
|
||||
2013-05-07 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
* gcore.c (gcore_create_callback): Ignore sections with
|
||||
|
|
|
@ -2178,7 +2178,18 @@ ppc_linux_new_thread (struct lwp_info *lp)
|
|||
/* 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);
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2013-05-07 Luis Machado <lgustavo@codesourcery.com>
|
||||
|
||||
* gdb.threads/wp-replication.c: New file.
|
||||
* gdb.threads/wp-replication.exp: New file.
|
||||
|
||||
2013-05-06 Sandra Loosemore <sandra@codesourcery.com>
|
||||
|
||||
* gdb.xml/tdesc-regs.exp: Add case for nios2.
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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"
|
||||
}
|
Loading…
Reference in New Issue