From 06da0f77c2a447348127e072e34bf541597154a2 Mon Sep 17 00:00:00 2001 From: Pierre Langlois Date: Mon, 21 Sep 2015 15:01:05 +0100 Subject: [PATCH] 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. --- gdb/testsuite/ChangeLog | 5 ++ gdb/testsuite/gdb.trace/ftrace-lock.c | 106 ++++++++++++++++++++++++++++++++ gdb/testsuite/gdb.trace/ftrace-lock.exp | 88 ++++++++++++++++++++++++++ 3 files changed, 199 insertions(+) create mode 100644 gdb/testsuite/gdb.trace/ftrace-lock.c create mode 100644 gdb/testsuite/gdb.trace/ftrace-lock.exp diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index b4ee375..8cb1b7f 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,5 +1,10 @@ 2015-09-21 Pierre Langlois + * gdb.trace/ftrace-lock.c: New file. + * gdb.trace/ftrace-lock.exp: New file. + +2015-09-21 Pierre Langlois + * gdb.arch/insn-reloc.c: New file. * gdb.arch/ftrace-insn-reloc.exp: New file. diff --git a/gdb/testsuite/gdb.trace/ftrace-lock.c b/gdb/testsuite/gdb.trace/ftrace-lock.c new file mode 100644 index 0000000..8ed45f4 --- /dev/null +++ b/gdb/testsuite/gdb.trace/ftrace-lock.c @@ -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 . */ + +#include + +#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; +} diff --git a/gdb/testsuite/gdb.trace/ftrace-lock.exp b/gdb/testsuite/gdb.trace/ftrace-lock.exp new file mode 100644 index 0000000..c67739d --- /dev/null +++ b/gdb/testsuite/gdb.trace/ftrace-lock.exp @@ -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 . + +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" "" -- 2.7.4