From 459c4ec68e8f266bcd15fac9a5d8619b277560b1 Mon Sep 17 00:00:00 2001 From: jhb Date: Thu, 6 Sep 2018 22:23:39 +0000 Subject: [PATCH] MFC 332906,332907,332976,333679,336053: Expand testing of breakpoints. 332906: Extend support for ptrace() tests using breakpoints. - Use a single list of platforms to define HAVE_BREAKPOINT for platforms that expose a functional breakpoint() inline to userland. Replace existing lists of platform tests with HAVE_BREAKPOINT instead. - Add support for advancing PC past a breakpoint inserted via breakpoint() to support the existing ptrace__PT_CONTINUE_different_thread test on non-x86 platforms (x86 advances the PC past the breakpoint instruction, but other platforms do not). This is implemented by defining a new SKIP_BREAK macro which accepts a pointer to a 'struct reg' as its sole argument and modifies the contents to advance the PC. The intention is to use it in between PT_GETREGS and PT_SETREGS. 332907: Expose breakpoint() to userland from on MIPS. Enable ptrace() tests using breakpoint on MIPS as well. 332976: Shorten some recently-added lines that are an extra indent over 80 columns. 333679: Export a breakpoint() function to userland for riscv. As a result, enable tests using breakpoint() on riscv. 336053: Export a breakpoint() function to userland for arm and arm64. Enable ptrace() tests using breakpoint() on these architectures. --- sys/arm/include/cpufunc.h | 15 +++++++++- sys/arm64/include/cpufunc.h | 12 ++++---- sys/mips/include/cpufunc.h | 12 ++++---- sys/riscv/include/cpufunc.h | 8 ++--- tests/sys/kern/ptrace_test.c | 58 ++++++++++++++++++++++++++++-------- 5 files changed, 75 insertions(+), 30 deletions(-) diff --git a/sys/arm/include/cpufunc.h b/sys/arm/include/cpufunc.h index 13c0eddd53d..3a774d2f4dd 100644 --- a/sys/arm/include/cpufunc.h +++ b/sys/arm/include/cpufunc.h @@ -52,7 +52,7 @@ static __inline void breakpoint(void) { - __asm(".word 0xe7ffffff"); + __asm("udf 0xffff"); } struct cpu_functions { @@ -526,6 +526,19 @@ extern u_int arm_cache_level; extern u_int arm_cache_loc; extern u_int arm_cache_type[14]; +#else /* !_KERNEL */ + +static __inline void +breakpoint(void) +{ + + /* + * This matches the instruction used by GDB for software + * breakpoints. + */ + __asm("udf 0xfdee"); +} + #endif /* _KERNEL */ #endif /* _MACHINE_CPUFUNC_H_ */ diff --git a/sys/arm64/include/cpufunc.h b/sys/arm64/include/cpufunc.h index 35e54068469..e69d3623832 100644 --- a/sys/arm64/include/cpufunc.h +++ b/sys/arm64/include/cpufunc.h @@ -29,12 +29,6 @@ #ifndef _MACHINE_CPUFUNC_H_ #define _MACHINE_CPUFUNC_H_ -#ifdef _KERNEL - -#include - -void pan_enable(void); - static __inline void breakpoint(void) { @@ -42,6 +36,12 @@ breakpoint(void) __asm("brk #0"); } +#ifdef _KERNEL + +#include + +void pan_enable(void); + static __inline register_t dbg_disable(void) { diff --git a/sys/mips/include/cpufunc.h b/sys/mips/include/cpufunc.h index 3ebb8c14b44..d67062f61a6 100644 --- a/sys/mips/include/cpufunc.h +++ b/sys/mips/include/cpufunc.h @@ -106,6 +106,12 @@ mips_wbflush(void) #endif } +static __inline void +breakpoint(void) +{ + __asm __volatile ("break"); +} + #ifdef _KERNEL /* * XXX @@ -341,12 +347,6 @@ get_intr_mask(void) return (mips_rd_status() & MIPS_SR_INT_MASK); } -static __inline void -breakpoint(void) -{ - __asm __volatile ("break"); -} - #if defined(__GNUC__) && !defined(__mips_o32) #define mips3_ld(a) (*(const volatile uint64_t *)(a)) #define mips3_sd(a, v) (*(volatile uint64_t *)(a) = (v)) diff --git a/sys/riscv/include/cpufunc.h b/sys/riscv/include/cpufunc.h index 4ee68dcfccb..f7a4957feea 100644 --- a/sys/riscv/include/cpufunc.h +++ b/sys/riscv/include/cpufunc.h @@ -37,10 +37,6 @@ #ifndef _MACHINE_CPUFUNC_H_ #define _MACHINE_CPUFUNC_H_ -#ifdef _KERNEL - -#include - static __inline void breakpoint(void) { @@ -48,6 +44,10 @@ breakpoint(void) __asm("ebreak"); } +#ifdef _KERNEL + +#include + static __inline register_t intr_disable(void) { diff --git a/tests/sys/kern/ptrace_test.c b/tests/sys/kern/ptrace_test.c index 5c1b66d054f..5e4c56ad786 100644 --- a/tests/sys/kern/ptrace_test.c +++ b/tests/sys/kern/ptrace_test.c @@ -51,6 +51,37 @@ __FBSDID("$FreeBSD$"); #include #include +/* + * Architectures with a user-visible breakpoint(). + */ +#if defined(__aarch64__) || defined(__amd64__) || defined(__arm__) || \ + defined(__i386__) || defined(__mips__) || defined(__riscv) || \ + defined(__sparc64__) +#define HAVE_BREAKPOINT +#endif + +/* + * Adjust PC to skip over a breakpoint when stopped for a breakpoint trap. + */ +#ifdef HAVE_BREAKPOINT +#if defined(__aarch64__) +#define SKIP_BREAK(reg) ((reg)->elr += 4) +#elif defined(__amd64__) || defined(__i386__) +#define SKIP_BREAK(reg) +#elif defined(__arm__) +#define SKIP_BREAK(reg) ((reg)->r_pc += 4) +#elif defined(__mips__) +#define SKIP_BREAK(reg) ((reg)->r_regs[PC] += 4) +#elif defined(__riscv) +#define SKIP_BREAK(reg) ((reg)->sepc += 4) +#elif defined(__sparc64__) +#define SKIP_BREAK(reg) do { \ + (reg)->r_tpc = (reg)->r_tnpc + 4; \ + (reg)->r_tnpc += 8; \ +} while (0) +#endif +#endif + /* * A variant of ATF_REQUIRE that is suitable for use in child * processes. This only works if the parent process is tripped up by @@ -1688,11 +1719,7 @@ ATF_TC_BODY(ptrace__ptrace_vfork_follow, tc) ATF_REQUIRE(errno == ECHILD); } -/* - * XXX: There's nothing inherently platform specific about this test, however a - * userspace visible breakpoint() is a prerequisite. - */ - #if defined(__amd64__) || defined(__i386__) || defined(__sparc64__) +#ifdef HAVE_BREAKPOINT /* * Verify that no more events are reported after PT_KILL except for the * process exit when stopped due to a breakpoint trap. @@ -1738,7 +1765,7 @@ ATF_TC_BODY(ptrace__PT_KILL_breakpoint, tc) ATF_REQUIRE(wpid == -1); ATF_REQUIRE(errno == ECHILD); } -#endif /* defined(__amd64__) || defined(__i386__) || defined(__sparc64__) */ +#endif /* HAVE_BREAKPOINT */ /* * Verify that no more events are reported after PT_KILL except for the @@ -3468,11 +3495,7 @@ ATF_TC_BODY(ptrace__PT_STEP_with_signal, tc) ATF_REQUIRE(errno == ECHILD); } -#if defined(__amd64__) || defined(__i386__) -/* - * Only x86 both define breakpoint() and have a PC after breakpoint so - * that restarting doesn't retrigger the breakpoint. - */ +#if defined(HAVE_BREAKPOINT) && defined(SKIP_BREAK) static void * continue_thread(void *arg __unused) { @@ -3506,6 +3529,7 @@ ATF_TC_BODY(ptrace__PT_CONTINUE_different_thread, tc) pid_t fpid, wpid; lwpid_t lwps[2]; bool hit_break[2]; + struct reg reg; int i, j, status; ATF_REQUIRE((fpid = fork()) != -1); @@ -3579,6 +3603,9 @@ ATF_TC_BODY(ptrace__PT_CONTINUE_different_thread, tc) else i = 1; hit_break[i] = true; + ATF_REQUIRE(ptrace(PT_GETREGS, pl.pl_lwpid, (caddr_t)®, 0) != -1); + SKIP_BREAK(®); + ATF_REQUIRE(ptrace(PT_SETREGS, pl.pl_lwpid, (caddr_t)®, 0) != -1); /* * Resume both threads but pass the other thread's LWPID to @@ -3616,6 +3643,11 @@ ATF_TC_BODY(ptrace__PT_CONTINUE_different_thread, tc) ATF_REQUIRE_MSG(!hit_break[i], "double breakpoint event"); hit_break[i] = true; + ATF_REQUIRE(ptrace(PT_GETREGS, pl.pl_lwpid, (caddr_t)®, + 0) != -1); + SKIP_BREAK(®); + ATF_REQUIRE(ptrace(PT_SETREGS, pl.pl_lwpid, (caddr_t)®, + 0) != -1); } ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); @@ -3663,7 +3695,7 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, ptrace__event_mask); ATF_TP_ADD_TC(tp, ptrace__ptrace_vfork); ATF_TP_ADD_TC(tp, ptrace__ptrace_vfork_follow); -#if defined(__amd64__) || defined(__i386__) || defined(__sparc64__) +#ifdef HAVE_BREAKPOINT ATF_TP_ADD_TC(tp, ptrace__PT_KILL_breakpoint); #endif ATF_TP_ADD_TC(tp, ptrace__PT_KILL_system_call); @@ -3688,7 +3720,7 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, ptrace__event_mask_sigkill_discard); ATF_TP_ADD_TC(tp, ptrace__PT_ATTACH_with_SBDRY_thread); ATF_TP_ADD_TC(tp, ptrace__PT_STEP_with_signal); -#if defined(__amd64__) || defined(__i386__) +#if defined(HAVE_BREAKPOINT) && defined(SKIP_BREAK) ATF_TP_ADD_TC(tp, ptrace__PT_CONTINUE_different_thread); #endif -- 2.45.0