aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/testsuite/ChangeLog5
-rw-r--r--gdb/testsuite/gdb.arch/ftrace-insn-reloc.exp114
-rw-r--r--gdb/testsuite/gdb.arch/insn-reloc.c508
3 files changed, 627 insertions, 0 deletions
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 596f2fa..b4ee375 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,10 @@
2015-09-21 Pierre Langlois <pierre.langlois@arm.com>
+ * gdb.arch/insn-reloc.c: New file.
+ * gdb.arch/ftrace-insn-reloc.exp: New file.
+
+2015-09-21 Pierre Langlois <pierre.langlois@arm.com>
+
* gdb.trace/change-loc.h (func4) [__aarch64__]: Add a nop
instruction.
* gdb.trace/pendshr1.c (pendfunc): Likewise.
diff --git a/gdb/testsuite/gdb.arch/ftrace-insn-reloc.exp b/gdb/testsuite/gdb.arch/ftrace-insn-reloc.exp
new file mode 100644
index 0000000..bdd71e6
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/ftrace-insn-reloc.exp
@@ -0,0 +1,114 @@
+# 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 insn-reloc.c
+set executable $testfile
+set expfile $testfile.exp
+
+# Some targets have leading underscores on assembly symbols.
+set additional_flags [gdb_target_symbol_prefix_flags]
+
+if [prepare_for_testing $expfile $executable $srcfile \
+ [list debug $additional_flags]] {
+ untested "failed to prepare for trace tests"
+ return -1
+}
+
+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
+}
+
+set libipa [get_in_proc_agent]
+gdb_load_shlibs $libipa
+
+# Can't use prepare_for_testing, because that splits compiling into
+# building objects and then linking, and we'd fail with "linker input
+# file unused because linking not done" when building the object.
+
+if { [gdb_compile "$srcdir/$subdir/$srcfile" $binfile \
+ executable [list debug $additional_flags shlib=$libipa] ] != "" } {
+ untested "failed to compile ftrace tests"
+ return -1
+}
+clean_restart ${executable}
+
+if ![runto_main] {
+ fail "Can't run to main for ftrace tests"
+ return 0
+}
+
+gdb_reinitialize_dir $srcdir/$subdir
+
+if { [gdb_test "info sharedlibrary" ".*${libipa}.*" "IPA loaded"] != 0 } {
+ untested "Could not find IPA lib loaded"
+ return 1
+}
+
+# Read function name from testcases[N].
+
+proc read_testcase { n } {
+ global gdb_prompt
+
+ set result -1
+ gdb_test_multiple "print testcases\[${n}\]" "read name of test case ${n}" {
+ -re "\[$\].*= .*<(.*)>.*$gdb_prompt $" {
+ set result $expect_out(1,string)
+ }
+ -re "$gdb_prompt $" { }
+ }
+
+ return $result
+}
+
+set n_testcases [gdb_readexpr "n_testcases"]
+
+if { ${n_testcases} == 0 } {
+ untested "No instruction relocation to test"
+ return 1
+}
+
+# Set a fast tracepoint on each set_point${i} symbol. There is one for
+# each testcase.
+for { set i 0 } { ${i} < ${n_testcases} } { incr i } {
+ set testcase [read_testcase $i]
+
+ gdb_test "ftrace *set_point$i" "Fast tracepoint .*" \
+ "fast tracepoint on ${testcase}"
+}
+
+gdb_test "break pass" ".*" ""
+gdb_test "break fail" ".*" ""
+
+gdb_test_no_output "tstart" "start trace experiment"
+
+# Make sure we have hit the pass breakpoint for each testcase.
+for { set i 0 } { ${i} < ${n_testcases} } { incr i } {
+ set testcase [read_testcase $i]
+
+ gdb_test "continue" \
+ ".*Breakpoint \[0-9\]+, pass \(\).*" \
+ "relocated instruction at ${testcase}"
+}
+
+gdb_test "tstatus" ".*Collected ${n_testcases} trace frames.*" "check on trace status"
+
+gdb_test "tstop" "" ""
diff --git a/gdb/testsuite/gdb.arch/insn-reloc.c b/gdb/testsuite/gdb.arch/insn-reloc.c
new file mode 100644
index 0000000..c7148a2
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/insn-reloc.c
@@ -0,0 +1,508 @@
+/* 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 <stddef.h>
+#include <stdint.h>
+
+typedef void (*testcase_ftype)(void);
+
+/* Each function checks the correctness of the instruction being
+ relocated due to a fast tracepoint. Call function pass if it is
+ correct, otherwise call function fail. GDB sets a breakpoints on
+ pass and fail in order to check the correctness. */
+
+static void
+pass (void)
+{
+}
+
+static void
+fail (void)
+{
+}
+
+#if (defined __x86_64__ || defined __i386__)
+
+#ifdef SYMBOL_PREFIX
+#define SYMBOL(str) SYMBOL_PREFIX #str
+#else
+#define SYMBOL(str) #str
+#endif
+
+/* Make sure we can relocate a CALL instruction. CALL instructions are
+ 5 bytes long so we can always set a fast tracepoints on them.
+
+ JMP set_point0
+ f:
+ MOV $1, %[ok]
+ JMP end
+ set_point0:
+ CALL f ; tracepoint here.
+ end:
+
+ */
+
+static void
+can_relocate_call (void)
+{
+ int ok = 0;
+
+ asm (" .global " SYMBOL (set_point0) "\n"
+ " jmp " SYMBOL (set_point0) "\n"
+ "0:\n"
+ " mov $1, %[ok]\n"
+ " jmp 1f\n"
+ SYMBOL (set_point0) ":\n"
+ " call 0b\n"
+ "1:\n"
+ : [ok] "=r" (ok));
+
+ if (ok == 1)
+ pass ();
+ else
+ fail ();
+}
+
+/* Make sure we can relocate a JMP instruction. We need the JMP
+ instruction to be 5 bytes long in order to set a fast tracepoint on
+ it. To do this, we emit the opcode directly.
+
+ JMP next ; tracepoint here.
+ next:
+ MOV $1, %[ok]
+
+ */
+
+static void
+can_relocate_jump (void)
+{
+ int ok = 0;
+
+ asm (" .global " SYMBOL (set_point1) "\n"
+ SYMBOL (set_point1) ":\n"
+ ".byte 0xe9\n" /* jmp */
+ ".byte 0x00\n"
+ ".byte 0x00\n"
+ ".byte 0x00\n"
+ ".byte 0x00\n"
+ " mov $1, %[ok]\n"
+ : [ok] "=r" (ok));
+
+ if (ok == 1)
+ pass ();
+ else
+ fail ();
+}
+#elif (defined __aarch64__)
+
+/* Make sure we can relocate a B instruction.
+
+ B set_point0
+ set_ok:
+ MOV %[ok], #1
+ B end
+ set_point0:
+ B set_ok ; tracepoint here.
+ MOV %[ok], #0
+ end
+
+ */
+
+static void
+can_relocate_b (void)
+{
+ int ok = 0;
+
+ asm (" b set_point0\n"
+ "0:\n"
+ " mov %[ok], #1\n"
+ " b 1f\n"
+ "set_point0:\n"
+ " b 0b\n"
+ " mov %[ok], #0\n"
+ "1:\n"
+ : [ok] "=r" (ok));
+
+ if (ok == 1)
+ pass ();
+ else
+ fail ();
+}
+
+/* Make sure we can relocate a B.cond instruction.
+
+ MOV x0, #8
+ TST x0, #8 ; Clear the Z flag.
+ B set_point1
+ set_ok:
+ MOV %[ok], #1
+ B end
+ set_point1:
+ B.NE set_ok ; tracepoint here.
+ MOV %[ok], #0
+ end
+
+ */
+
+static void
+can_relocate_bcond (void)
+{
+ int ok = 0;
+
+ asm (" mov x0, #8\n"
+ " tst x0, #8\n"
+ " b set_point1\n"
+ "0:\n"
+ " mov %[ok], #1\n"
+ " b 1f\n"
+ "set_point1:\n"
+ " b.ne 0b\n"
+ " mov %[ok], #0\n"
+ "1:\n"
+ : [ok] "=r" (ok)
+ :
+ : "0", "cc");
+
+ if (ok == 1)
+ pass ();
+ else
+ fail ();
+}
+
+/* Make sure we can relocate a CBZ instruction.
+
+ MOV x0, #0
+ B set_point2
+ set_ok:
+ MOV %[ok], #1
+ B end
+ set_point2:
+ CBZ x0, set_ok ; tracepoint here.
+ MOV %[ok], #0
+ end
+
+ */
+
+static void
+can_relocate_cbz (void)
+{
+ int ok = 0;
+
+ asm (" mov x0, #0\n"
+ " b set_point2\n"
+ "0:\n"
+ " mov %[ok], #1\n"
+ " b 1f\n"
+ "set_point2:\n"
+ " cbz x0, 0b\n"
+ " mov %[ok], #0\n"
+ "1:\n"
+ : [ok] "=r" (ok)
+ :
+ : "0");
+
+ if (ok == 1)
+ pass ();
+ else
+ fail ();
+}
+
+/* Make sure we can relocate a CBNZ instruction.
+
+ MOV x0, #8
+ B set_point3
+ set_ok:
+ MOV %[ok], #1
+ B end
+ set_point3:
+ CBNZ x0, set_ok ; tracepoint here.
+ MOV %[ok], #0
+ end
+
+ */
+
+static void
+can_relocate_cbnz (void)
+{
+ int ok = 0;
+
+ asm (" mov x0, #8\n"
+ " b set_point3\n"
+ "0:\n"
+ " mov %[ok], #1\n"
+ " b 1f\n"
+ "set_point3:\n"
+ " cbnz x0, 0b\n"
+ " mov %[ok], #0\n"
+ "1:\n"
+ : [ok] "=r" (ok)
+ :
+ : "0");
+
+ if (ok == 1)
+ pass ();
+ else
+ fail ();
+}
+
+/* Make sure we can relocate a TBZ instruction.
+
+ MOV x0, #8
+ MVN x0, x0 ; Clear bit 3.
+ B set_point4
+ set_ok:
+ MOV %[ok], #1
+ B end
+ set_point4:
+ TBZ x0, #3, set_ok ; tracepoint here.
+ MOV %[ok], #0
+ end
+
+ */
+
+static void
+can_relocate_tbz (void)
+{
+ int ok = 0;
+
+ asm (" mov x0, #8\n"
+ " mvn x0, x0\n"
+ " b set_point4\n"
+ "0:\n"
+ " mov %[ok], #1\n"
+ " b 1f\n"
+ "set_point4:\n"
+ " tbz x0, #3, 0b\n"
+ " mov %[ok], #0\n"
+ "1:\n"
+ : [ok] "=r" (ok)
+ :
+ : "0");
+
+ if (ok == 1)
+ pass ();
+ else
+ fail ();
+}
+
+/* Make sure we can relocate a TBNZ instruction.
+
+ MOV x0, #8 ; Set bit 3.
+ B set_point5
+ set_ok:
+ MOV %[ok], #1
+ B end
+ set_point5:
+ TBNZ x0, #3, set_ok ; tracepoint here.
+ MOV %[ok], #0
+ end
+
+ */
+
+static void
+can_relocate_tbnz (void)
+{
+ int ok = 0;
+
+ asm (" mov x0, #8\n"
+ " b set_point5\n"
+ "0:\n"
+ " mov %[ok], #1\n"
+ " b 1f\n"
+ "set_point5:\n"
+ " tbnz x0, #3, 0b\n"
+ " mov %[ok], #0\n"
+ "1:\n"
+ : [ok] "=r" (ok)
+ :
+ : "0");
+
+ if (ok == 1)
+ pass ();
+ else
+ fail ();
+}
+
+/* Make sure we can relocate an ADR instruction with a positive offset.
+
+ set_point6:
+ ADR x0, target ; tracepoint here.
+ BR x0 ; jump to target
+ MOV %[ok], #0
+ B end
+ target:
+ MOV %[ok], #1
+ end
+
+ */
+
+static void
+can_relocate_adr_forward (void)
+{
+ int ok = 0;
+
+ asm ("set_point6:\n"
+ " adr x0, 0f\n"
+ " br x0\n"
+ " mov %[ok], #0\n"
+ " b 1f\n"
+ "0:\n"
+ " mov %[ok], #1\n"
+ "1:\n"
+ : [ok] "=r" (ok)
+ :
+ : "0");
+
+ if (ok == 1)
+ pass ();
+ else
+ fail ();
+}
+
+/* Make sure we can relocate an ADR instruction with a negative offset.
+
+ B set_point7
+ target:
+ MOV %[ok], #1
+ B end
+ set_point7:
+ ADR x0, target ; tracepoint here.
+ BR x0 ; jump to target
+ MOV %[ok], #0
+ end
+
+ */
+
+static void
+can_relocate_adr_backward (void)
+{
+ int ok = 0;
+
+ asm ("b set_point7\n"
+ "0:\n"
+ " mov %[ok], #1\n"
+ " b 1f\n"
+ "set_point7:\n"
+ " adr x0, 0b\n"
+ " br x0\n"
+ " mov %[ok], #0\n"
+ "1:\n"
+ : [ok] "=r" (ok)
+ :
+ : "0");
+
+ if (ok == 1)
+ pass ();
+ else
+ fail ();
+}
+
+/* Make sure we can relocate an ADRP instruction.
+
+ set_point8:
+ ADRP %[addr], set_point8 ; tracepoint here.
+ ADR %[pc], set_point8
+
+ ADR computes the address of the given label. While ADRP gives us its
+ page, on a 4K boundary. We can check ADRP executed normally by
+ making sure the result of ADR and ADRP are equivalent, except for the
+ 12 lowest bits which should be cleared.
+
+ */
+
+static void
+can_relocate_adrp (void)
+{
+ uintptr_t page;
+ uintptr_t pc;
+
+ asm ("set_point8:\n"
+ " adrp %[page], set_point8\n"
+ " adr %[pc], set_point8\n"
+ : [page] "=r" (page), [pc] "=r" (pc));
+
+ if (page == (pc & ~0xfff))
+ pass ();
+ else
+ fail ();
+}
+
+/* Make sure we can relocate an LDR instruction, where the memory to
+ read is an offset from the current PC.
+
+ B set_point9
+ data:
+ .word 0x0cabba9e
+ set_point9:
+ LDR %[result], data ; tracepoint here.
+
+ */
+
+static void
+can_relocate_ldr (void)
+{
+ uint32_t result = 0;
+
+ asm ("b set_point9\n"
+ "0:\n"
+ " .word 0x0cabba9e\n"
+ "set_point9:\n"
+ " ldr %w[result], 0b\n"
+ : [result] "=r" (result));
+
+ if (result == 0x0cabba9e)
+ pass ();
+ else
+ fail ();
+}
+#endif
+
+/* Functions testing relocations need to be placed here. GDB will read
+ n_testcases to know how many fast tracepoints to place. It will look
+ for symbols in the form of 'set_point\[0-9\]+' so each functions
+ needs one, starting at 0. */
+
+static testcase_ftype testcases[] = {
+#if (defined __x86_64__ || defined __i386__)
+ can_relocate_call,
+ can_relocate_jump
+#elif (defined __aarch64__)
+ can_relocate_b,
+ can_relocate_bcond,
+ can_relocate_cbz,
+ can_relocate_cbnz,
+ can_relocate_tbz,
+ can_relocate_tbnz,
+ can_relocate_adr_forward,
+ can_relocate_adr_backward,
+ can_relocate_adrp,
+ can_relocate_ldr
+#endif
+};
+
+static size_t n_testcases = (sizeof (testcases) / sizeof (testcase_ftype));
+
+int
+main ()
+{
+ int i = 0;
+
+ for (i = 0; i < n_testcases; i++)
+ testcases[i] ();
+
+ return 0;
+}