diff options
-rw-r--r-- | gdb/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/testsuite/gdb.arch/ftrace-insn-reloc.exp | 114 | ||||
-rw-r--r-- | gdb/testsuite/gdb.arch/insn-reloc.c | 508 |
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; +} |