Add a test case for fast tracepoints' locking mechanism

When installing a fast tracepoint, we create a jump pad with a
spin-lock.  This way, only one thread can collect a given tracepoint at
any time.  This test case checks that this lock actually works as
expected.

This test works by creating a function which overrides the in-process
agent library's gdb_collect function.  On start up, GDBserver will ask
GDB with the 'qSymbol' packet about symbols present in the inferior.
GDB will reply with the gdb_agent_gdb_collect function from the test
case instead of the one from the agent.

gdb/testsuite/ChangeLog:

	* gdb.trace/ftrace-lock.c: New file.
	* gdb.trace/ftrace-lock.exp: New file.
This commit is contained in:
Pierre Langlois 2015-09-21 15:01:05 +01:00 committed by Yao Qi
parent 4f51c22aca
commit 06da0f77c2
3 changed files with 199 additions and 0 deletions

View File

@ -1,3 +1,8 @@
2015-09-21 Pierre Langlois <pierre.langlois@arm.com>
* gdb.trace/ftrace-lock.c: New file.
* gdb.trace/ftrace-lock.exp: New file.
2015-09-21 Pierre Langlois <pierre.langlois@arm.com>
* gdb.arch/insn-reloc.c: New file.

View File

@ -0,0 +1,106 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2015 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/>. */
#include <pthread.h>
#ifdef SYMBOL_PREFIX
#define SYMBOL(str) SYMBOL_PREFIX #str
#else
#define SYMBOL(str) #str
#endif
/* Called if the testcase failed. */
static void
fail (void)
{
}
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
/* This function overrides gdb_collect in the in-process agent library.
See gdbserver/tracepoint.c (gdb_collect). We want this function to
be ran instead of the one from the library to easily check that only
one thread is tracing at a time.
This works as expected because GDBserver will ask GDB about symbols
present in the inferior with the 'qSymbol' packet. And GDB will
reply with the address of this function instead of the one from the
in-process agent library. */
void
gdb_agent_gdb_collect (void *tpoint, unsigned char *regs)
{
/* If we cannot acquire a lock, then this means another thread is
tracing and the lock implemented by the jump pad is not working! */
if (pthread_mutex_trylock (&mutex) != 0)
{
fail ();
return;
}
sleep (1);
if (pthread_mutex_unlock (&mutex) != 0)
{
fail ();
return;
}
}
/* Called from asm. */
static void __attribute__((used))
func (void)
{
}
static void *
thread_function (void *arg)
{
/* `set_point' is the label at which to set a fast tracepoint. The
insn at the label must be large enough to fit a fast tracepoint
jump. */
asm (" .global " SYMBOL (set_point) "\n"
SYMBOL (set_point) ":\n"
#if (defined __x86_64__ || defined __i386__)
" call " SYMBOL (func) "\n"
#elif (defined __aarch64__)
" nop\n"
#endif
);
}
static void
end (void)
{
}
int
main (int argc, char *argv[], char *envp[])
{
pthread_t threads[NUM_THREADS];
int i;
for (i = 0; i < NUM_THREADS; i++)
pthread_create (&threads[i], NULL, thread_function, NULL);
for (i = 0; i < NUM_THREADS; i++)
pthread_join (threads[i], NULL);
end ();
return 0;
}

View File

@ -0,0 +1,88 @@
# Copyright 2015 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/>.
load_lib "trace-support.exp"
standard_testfile
set executable $testfile
set expfile $testfile.exp
# make check RUNTESTFLAGS='gdb.trace/ftrace-lock.exp NUM_THREADS=2'
if ![info exists NUM_THREADS] {
set NUM_THREADS 2
}
# Some targets have leading underscores on assembly symbols.
set additional_flags [gdb_target_symbol_prefix_flags]
set options [list debug [gdb_target_symbol_prefix_flags] \
additional_flags=-DNUM_THREADS=$NUM_THREADS]
# Check that the target supports trace.
if { [gdb_compile_pthreads "$srcdir/$subdir/$srcfile" $binfile executable $options] != "" } {
untested "Couldn't compile test program"
return -1
}
clean_restart ${testfile}
if ![runto_main] {
fail "Can't run to main to check for trace support"
return -1
}
if ![gdb_target_supports_trace] {
unsupported "target does not support trace"
return -1
}
# Compile the test case with the in-process agent library.
set libipa [get_in_proc_agent]
gdb_load_shlibs $libipa
lappend options shlib=$libipa
if { [gdb_compile_pthreads "$srcdir/$subdir/$srcfile" $binfile executable $options] != "" } {
untested "Couldn't compile test program with in-process agent library"
return -1
}
clean_restart ${executable}
if ![runto_main] {
fail "Can't run to main to check for trace support"
return -1
}
if { [gdb_test "info sharedlibrary" ".*${libipa}.*" "IPA loaded"] != 0 } {
untested "Could not find IPA lib loaded"
return 1
}
gdb_test "break end" ""
gdb_test "break fail" ""
gdb_test "ftrace set_point" "Fast tracepoint .*" \
"fast tracepoint at a long insn"
gdb_test "tstart" ""
# If NUM_THREADS is high then this test case may timeout. Increase the
# timeout temporarily.
with_timeout_factor $NUM_THREADS {
# If the fail function is hit, then the testcase will fail.
gdb_test "continue" ".*Breakpoint \[0-9\]+, end \(\).*" \
"do not hit the fail function"
}
gdb_test "tstop" ""