diff options
Diffstat (limited to 'tools/testing/selftests/powerpc/ptrace')
17 files changed, 402 insertions, 582 deletions
diff --git a/tools/testing/selftests/powerpc/ptrace/Makefile b/tools/testing/selftests/powerpc/ptrace/Makefile index cbeeaeae8837..1b39b86849da 100644 --- a/tools/testing/selftests/powerpc/ptrace/Makefile +++ b/tools/testing/selftests/powerpc/ptrace/Makefile @@ -36,6 +36,7 @@ $(TM_TESTS): CFLAGS += -I../tm -mhtm CFLAGS += $(KHDR_INCLUDES) -fno-pie $(OUTPUT)/ptrace-gpr: ptrace-gpr.S +$(OUTPUT)/ptrace-perf-hwbreak: ptrace-perf-asm.S $(OUTPUT)/ptrace-pkey $(OUTPUT)/core-pkey: LDLIBS += -pthread $(TEST_GEN_PROGS): ../harness.c ../utils.c ../lib/reg.S diff --git a/tools/testing/selftests/powerpc/ptrace/child.h b/tools/testing/selftests/powerpc/ptrace/child.h index d7275b7b33dc..df62ff0735f7 100644 --- a/tools/testing/selftests/powerpc/ptrace/child.h +++ b/tools/testing/selftests/powerpc/ptrace/child.h @@ -48,12 +48,12 @@ struct child_sync { } \ } while (0) -#define PARENT_SKIP_IF_UNSUPPORTED(x, sync) \ +#define PARENT_SKIP_IF_UNSUPPORTED(x, sync, msg) \ do { \ if ((x) == -1 && (errno == ENODEV || errno == EINVAL)) { \ (sync)->parent_gave_up = true; \ prod_child(sync); \ - SKIP_IF(1); \ + SKIP_IF_MSG(1, msg); \ } \ } while (0) diff --git a/tools/testing/selftests/powerpc/ptrace/core-pkey.c b/tools/testing/selftests/powerpc/ptrace/core-pkey.c index f6f8596ce8e1..f6da4cb30cd6 100644 --- a/tools/testing/selftests/powerpc/ptrace/core-pkey.c +++ b/tools/testing/selftests/powerpc/ptrace/core-pkey.c @@ -266,7 +266,7 @@ static int parent(struct shared_info *info, pid_t pid) * to the child. */ ret = ptrace_read_regs(pid, NT_PPC_PKEY, regs, 3); - PARENT_SKIP_IF_UNSUPPORTED(ret, &info->child_sync); + PARENT_SKIP_IF_UNSUPPORTED(ret, &info->child_sync, "PKEYs not supported"); PARENT_FAIL_IF(ret, &info->child_sync); info->amr = regs[0]; diff --git a/tools/testing/selftests/powerpc/ptrace/perf-hwbreak.c b/tools/testing/selftests/powerpc/ptrace/perf-hwbreak.c index f75739bbad28..e374c6b7ace6 100644 --- a/tools/testing/selftests/powerpc/ptrace/perf-hwbreak.c +++ b/tools/testing/selftests/powerpc/ptrace/perf-hwbreak.c @@ -884,7 +884,7 @@ static int perf_hwbreak(void) { srand ( time(NULL) ); - SKIP_IF(!perf_breakpoint_supported()); + SKIP_IF_MSG(!perf_breakpoint_supported(), "Perf breakpoints not supported"); return runtest(); } diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-hwbreak.c b/tools/testing/selftests/powerpc/ptrace/ptrace-hwbreak.c index 1345e9b9af0f..75d30d61ab0e 100644 --- a/tools/testing/selftests/powerpc/ptrace/ptrace-hwbreak.c +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-hwbreak.c @@ -64,26 +64,26 @@ static bool dawr_present(struct ppc_debug_info *dbginfo) static void write_var(int len) { - __u8 *pcvar; - __u16 *psvar; - __u32 *pivar; - __u64 *plvar; + volatile __u8 *pcvar; + volatile __u16 *psvar; + volatile __u32 *pivar; + volatile __u64 *plvar; switch (len) { case 1: - pcvar = (__u8 *)&glvar; + pcvar = (volatile __u8 *)&glvar; *pcvar = 0xff; break; case 2: - psvar = (__u16 *)&glvar; + psvar = (volatile __u16 *)&glvar; *psvar = 0xffff; break; case 4: - pivar = (__u32 *)&glvar; + pivar = (volatile __u32 *)&glvar; *pivar = 0xffffffff; break; case 8: - plvar = (__u64 *)&glvar; + plvar = (volatile __u64 *)&glvar; *plvar = 0xffffffffffffffffLL; break; } @@ -98,16 +98,16 @@ static void read_var(int len) switch (len) { case 1: - cvar = (__u8)glvar; + cvar = (volatile __u8)glvar; break; case 2: - svar = (__u16)glvar; + svar = (volatile __u16)glvar; break; case 4: - ivar = (__u32)glvar; + ivar = (volatile __u32)glvar; break; case 8: - lvar = (__u64)glvar; + lvar = (volatile __u64)glvar; break; } } @@ -603,7 +603,7 @@ static int ptrace_hwbreak(void) wait(NULL); get_dbginfo(child_pid, &dbginfo); - SKIP_IF(dbginfo.num_data_bps == 0); + SKIP_IF_MSG(dbginfo.num_data_bps == 0, "No data breakpoints present"); dawr = dawr_present(&dbginfo); run_tests(child_pid, &dbginfo, dawr); diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-perf-asm.S b/tools/testing/selftests/powerpc/ptrace/ptrace-perf-asm.S new file mode 100644 index 000000000000..9aa2e58f3189 --- /dev/null +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-perf-asm.S @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <ppc-asm.h> + +.global same_watch_addr_load +.global same_watch_addr_trap + +FUNC_START(same_watch_addr_child) + nop +same_watch_addr_load: + ld 0,0(3) + nop +same_watch_addr_trap: + trap + blr +FUNC_END(same_watch_addr_child) + + +.global perf_then_ptrace_load1 +.global perf_then_ptrace_load2 +.global perf_then_ptrace_trap + +FUNC_START(perf_then_ptrace_child) + nop +perf_then_ptrace_load1: + ld 0,0(3) +perf_then_ptrace_load2: + ld 0,0(4) + nop +perf_then_ptrace_trap: + trap + blr +FUNC_END(perf_then_ptrace_child) diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-perf-hwbreak.c b/tools/testing/selftests/powerpc/ptrace/ptrace-perf-hwbreak.c index 3344e74a97b4..a0a0b9bb5854 100644 --- a/tools/testing/selftests/powerpc/ptrace/ptrace-perf-hwbreak.c +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-perf-hwbreak.c @@ -1,659 +1,445 @@ // SPDX-License-Identifier: GPL-2.0+ -#include <stdio.h> -#include <string.h> -#include <signal.h> -#include <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <linux/hw_breakpoint.h> -#include <linux/perf_event.h> + #include <asm/unistd.h> -#include <sys/ptrace.h> +#include <linux/hw_breakpoint.h> +#include <linux/ptrace.h> +#include <memory.h> +#include <stdlib.h> #include <sys/wait.h> -#include "ptrace.h" -char data[16]; +#include "utils.h" -/* Overlapping address range */ -volatile __u64 *ptrace_data1 = (__u64 *)&data[0]; -volatile __u64 *perf_data1 = (__u64 *)&data[4]; +/* + * Child subroutine that performs a load on the address, then traps + */ +void same_watch_addr_child(unsigned long *addr); -/* Non-overlapping address range */ -volatile __u64 *ptrace_data2 = (__u64 *)&data[0]; -volatile __u64 *perf_data2 = (__u64 *)&data[8]; +/* Address of the ld instruction in same_watch_addr_child() */ +extern char same_watch_addr_load[]; -static unsigned long pid_max_addr(void) -{ - FILE *fp; - char *line, *c; - char addr[100]; - size_t len = 0; - - fp = fopen("/proc/kallsyms", "r"); - if (!fp) { - printf("Failed to read /proc/kallsyms. Exiting..\n"); - exit(EXIT_FAILURE); - } +/* Address of the end trap instruction in same_watch_addr_child() */ +extern char same_watch_addr_trap[]; - while (getline(&line, &len, fp) != -1) { - if (!strstr(line, "pid_max") || strstr(line, "pid_max_max") || - strstr(line, "pid_max_min")) - continue; +/* + * Child subroutine that performs a load on the first address, then a load on + * the second address (with no instructions separating this from the first + * load), then traps. + */ +void perf_then_ptrace_child(unsigned long *first_addr, unsigned long *second_addr); - strncpy(addr, line, len < 100 ? len : 100); - c = strchr(addr, ' '); - *c = '\0'; - return strtoul(addr, &c, 16); - } - fclose(fp); - printf("Could not find pix_max. Exiting..\n"); - exit(EXIT_FAILURE); - return -1; -} +/* Address of the first ld instruction in perf_then_ptrace_child() */ +extern char perf_then_ptrace_load1[]; -static void perf_user_event_attr_set(struct perf_event_attr *attr, __u64 addr, __u64 len) -{ - memset(attr, 0, sizeof(struct perf_event_attr)); - attr->type = PERF_TYPE_BREAKPOINT; - attr->size = sizeof(struct perf_event_attr); - attr->bp_type = HW_BREAKPOINT_R; - attr->bp_addr = addr; - attr->bp_len = len; - attr->exclude_kernel = 1; - attr->exclude_hv = 1; -} +/* Address of the second ld instruction in perf_then_ptrace_child() */ +extern char perf_then_ptrace_load2[]; -static void perf_kernel_event_attr_set(struct perf_event_attr *attr) +/* Address of the end trap instruction in perf_then_ptrace_child() */ +extern char perf_then_ptrace_trap[]; + +static inline long sys_ptrace(long request, pid_t pid, unsigned long addr, unsigned long data) { - memset(attr, 0, sizeof(struct perf_event_attr)); - attr->type = PERF_TYPE_BREAKPOINT; - attr->size = sizeof(struct perf_event_attr); - attr->bp_type = HW_BREAKPOINT_R; - attr->bp_addr = pid_max_addr(); - attr->bp_len = sizeof(unsigned long); - attr->exclude_user = 1; - attr->exclude_hv = 1; + return syscall(__NR_ptrace, request, pid, addr, data); } -static int perf_cpu_event_open(int cpu, __u64 addr, __u64 len) +static long ptrace_traceme(void) { - struct perf_event_attr attr; - - perf_user_event_attr_set(&attr, addr, len); - return syscall(__NR_perf_event_open, &attr, -1, cpu, -1, 0); + return sys_ptrace(PTRACE_TRACEME, 0, 0, 0); } -static int perf_thread_event_open(pid_t child_pid, __u64 addr, __u64 len) +static long ptrace_getregs(pid_t pid, struct pt_regs *result) { - struct perf_event_attr attr; - - perf_user_event_attr_set(&attr, addr, len); - return syscall(__NR_perf_event_open, &attr, child_pid, -1, -1, 0); + return sys_ptrace(PTRACE_GETREGS, pid, 0, (unsigned long)result); } -static int perf_thread_cpu_event_open(pid_t child_pid, int cpu, __u64 addr, __u64 len) +static long ptrace_setregs(pid_t pid, struct pt_regs *result) { - struct perf_event_attr attr; - - perf_user_event_attr_set(&attr, addr, len); - return syscall(__NR_perf_event_open, &attr, child_pid, cpu, -1, 0); + return sys_ptrace(PTRACE_SETREGS, pid, 0, (unsigned long)result); } -static int perf_thread_kernel_event_open(pid_t child_pid) +static long ptrace_cont(pid_t pid, long signal) { - struct perf_event_attr attr; - - perf_kernel_event_attr_set(&attr); - return syscall(__NR_perf_event_open, &attr, child_pid, -1, -1, 0); + return sys_ptrace(PTRACE_CONT, pid, 0, signal); } -static int perf_cpu_kernel_event_open(int cpu) +static long ptrace_singlestep(pid_t pid, long signal) { - struct perf_event_attr attr; - - perf_kernel_event_attr_set(&attr); - return syscall(__NR_perf_event_open, &attr, -1, cpu, -1, 0); + return sys_ptrace(PTRACE_SINGLESTEP, pid, 0, signal); } -static int child(void) +static long ppc_ptrace_gethwdbginfo(pid_t pid, struct ppc_debug_info *dbginfo) { - int ret; - - ret = ptrace(PTRACE_TRACEME, 0, NULL, 0); - if (ret) { - printf("Error: PTRACE_TRACEME failed\n"); - return 0; - } - kill(getpid(), SIGUSR1); /* --> parent (SIGUSR1) */ - - return 0; + return sys_ptrace(PPC_PTRACE_GETHWDBGINFO, pid, 0, (unsigned long)dbginfo); } -static void ptrace_ppc_hw_breakpoint(struct ppc_hw_breakpoint *info, int type, - __u64 addr, int len) +static long ppc_ptrace_sethwdbg(pid_t pid, struct ppc_hw_breakpoint *bp_info) { - info->version = 1; - info->trigger_type = type; - info->condition_mode = PPC_BREAKPOINT_CONDITION_NONE; - info->addr = addr; - info->addr2 = addr + len; - info->condition_value = 0; - if (!len) - info->addr_mode = PPC_BREAKPOINT_MODE_EXACT; - else - info->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE; + return sys_ptrace(PPC_PTRACE_SETHWDEBUG, pid, 0, (unsigned long)bp_info); } -static int ptrace_open(pid_t child_pid, __u64 wp_addr, int len) +static long ppc_ptrace_delhwdbg(pid_t pid, int bp_id) { - struct ppc_hw_breakpoint info; - - ptrace_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len); - return ptrace(PPC_PTRACE_SETHWDEBUG, child_pid, 0, &info); + return sys_ptrace(PPC_PTRACE_DELHWDEBUG, pid, 0L, bp_id); } -static int test1(pid_t child_pid) +static long ptrace_getreg_pc(pid_t pid, void **pc) { - int perf_fd; - int ptrace_fd; - int ret = 0; - - /* Test: - * if (new per thread event by ptrace) - * if (existing cpu event by perf) - * if (addr range overlaps) - * fail; - */ + struct pt_regs regs; + long err; - perf_fd = perf_cpu_event_open(0, (__u64)perf_data1, sizeof(*perf_data1)); - if (perf_fd < 0) - return -1; + err = ptrace_getregs(pid, ®s); + if (err) + return err; - ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); - if (ptrace_fd > 0 || errno != ENOSPC) - ret = -1; + *pc = (void *)regs.nip; - close(perf_fd); - return ret; + return 0; } -static int test2(pid_t child_pid) +static long ptrace_setreg_pc(pid_t pid, void *pc) { - int perf_fd; - int ptrace_fd; - int ret = 0; - - /* Test: - * if (new per thread event by ptrace) - * if (existing cpu event by perf) - * if (addr range does not overlaps) - * allow; - */ + struct pt_regs regs; + long err; - perf_fd = perf_cpu_event_open(0, (__u64)perf_data2, sizeof(*perf_data2)); - if (perf_fd < 0) - return -1; - - ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2)); - if (ptrace_fd < 0) { - ret = -1; - goto perf_close; - } - ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); - -perf_close: - close(perf_fd); - return ret; -} + err = ptrace_getregs(pid, ®s); + if (err) + return err; -static int test3(pid_t child_pid) -{ - int perf_fd; - int ptrace_fd; - int ret = 0; - - /* Test: - * if (new per thread event by ptrace) - * if (existing thread event by perf on the same thread) - * if (addr range overlaps) - * fail; - */ - perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data1, - sizeof(*perf_data1)); - if (perf_fd < 0) - return -1; + regs.nip = (unsigned long)pc; - ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); - if (ptrace_fd > 0 || errno != ENOSPC) - ret = -1; + err = ptrace_setregs(pid, ®s); + if (err) + return err; - close(perf_fd); - return ret; + return 0; } -static int test4(pid_t child_pid) +static int perf_event_open(struct perf_event_attr *attr, pid_t pid, int cpu, + int group_fd, unsigned long flags) { - int perf_fd; - int ptrace_fd; - int ret = 0; - - /* Test: - * if (new per thread event by ptrace) - * if (existing thread event by perf on the same thread) - * if (addr range does not overlaps) - * fail; - */ - perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data2, - sizeof(*perf_data2)); - if (perf_fd < 0) - return -1; - - ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2)); - if (ptrace_fd < 0) { - ret = -1; - goto perf_close; - } - ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); - -perf_close: - close(perf_fd); - return ret; + return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags); } -static int test5(pid_t child_pid) +static void perf_user_event_attr_set(struct perf_event_attr *attr, void *addr, u64 len) { - int perf_fd; - int ptrace_fd; - int cpid; - int ret = 0; - - /* Test: - * if (new per thread event by ptrace) - * if (existing thread event by perf on the different thread) - * allow; - */ - cpid = fork(); - if (!cpid) { - /* Temporary Child */ - pause(); - exit(EXIT_SUCCESS); - } - - perf_fd = perf_thread_event_open(cpid, (__u64)perf_data1, sizeof(*perf_data1)); - if (perf_fd < 0) { - ret = -1; - goto kill_child; - } - - ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); - if (ptrace_fd < 0) { - ret = -1; - goto perf_close; - } + memset(attr, 0, sizeof(struct perf_event_attr)); - ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); -perf_close: - close(perf_fd); -kill_child: - kill(cpid, SIGINT); - return ret; + attr->type = PERF_TYPE_BREAKPOINT; + attr->size = sizeof(struct perf_event_attr); + attr->bp_type = HW_BREAKPOINT_R; + attr->bp_addr = (u64)addr; + attr->bp_len = len; + attr->exclude_kernel = 1; + attr->exclude_hv = 1; } -static int test6(pid_t child_pid) +static int perf_watchpoint_open(pid_t child_pid, void *addr, u64 len) { - int perf_fd; - int ptrace_fd; - int ret = 0; - - /* Test: - * if (new per thread kernel event by perf) - * if (existing thread event by ptrace on the same thread) - * allow; - * -- OR -- - * if (new per cpu kernel event by perf) - * if (existing thread event by ptrace) - * allow; - */ - ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); - if (ptrace_fd < 0) - return -1; - - perf_fd = perf_thread_kernel_event_open(child_pid); - if (perf_fd < 0) { - ret = -1; - goto ptrace_close; - } - close(perf_fd); - - perf_fd = perf_cpu_kernel_event_open(0); - if (perf_fd < 0) { - ret = -1; - goto ptrace_close; - } - close(perf_fd); + struct perf_event_attr attr; -ptrace_close: - ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); - return ret; + perf_user_event_attr_set(&attr, addr, len); + return perf_event_open(&attr, child_pid, -1, -1, 0); } -static int test7(pid_t child_pid) +static int perf_read_counter(int perf_fd, u64 *count) { - int perf_fd; - int ptrace_fd; - int ret = 0; - - /* Test: - * if (new per thread event by perf) - * if (existing thread event by ptrace on the same thread) - * if (addr range overlaps) - * fail; + /* + * A perf counter is retrieved by the read() syscall. It contains + * the current count as 8 bytes that are interpreted as a u64 */ - ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); - if (ptrace_fd < 0) - return -1; + ssize_t len = read(perf_fd, count, sizeof(*count)); - perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data1, - sizeof(*perf_data1)); - if (perf_fd > 0 || errno != ENOSPC) - ret = -1; + if (len != sizeof(*count)) + return -1; - ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); - return ret; + return 0; } -static int test8(pid_t child_pid) +static void ppc_ptrace_init_breakpoint(struct ppc_hw_breakpoint *info, + int type, void *addr, int len) { - int perf_fd; - int ptrace_fd; - int ret = 0; - - /* Test: - * if (new per thread event by perf) - * if (existing thread event by ptrace on the same thread) - * if (addr range does not overlaps) - * allow; - */ - ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2)); - if (ptrace_fd < 0) - return -1; - - perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data2, - sizeof(*perf_data2)); - if (perf_fd < 0) { - ret = -1; - goto ptrace_close; - } - close(perf_fd); - -ptrace_close: - ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); - return ret; + info->version = 1; + info->trigger_type = type; + info->condition_mode = PPC_BREAKPOINT_CONDITION_NONE; + info->addr = (u64)addr; + info->addr2 = (u64)addr + len; + info->condition_value = 0; + if (!len) + info->addr_mode = PPC_BREAKPOINT_MODE_EXACT; + else + info->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE; } -static int test9(pid_t child_pid) +/* + * Checks if we can place at least 2 watchpoints on the child process + */ +static int check_watchpoints(pid_t pid) { - int perf_fd; - int ptrace_fd; - int cpid; - int ret = 0; - - /* Test: - * if (new per thread event by perf) - * if (existing thread event by ptrace on the other thread) - * allow; - */ - ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); - if (ptrace_fd < 0) - return -1; - - cpid = fork(); - if (!cpid) { - /* Temporary Child */ - pause(); - exit(EXIT_SUCCESS); - } + struct ppc_debug_info dbginfo; - perf_fd = perf_thread_event_open(cpid, (__u64)perf_data1, sizeof(*perf_data1)); - if (perf_fd < 0) { - ret = -1; - goto kill_child; - } - close(perf_fd); + FAIL_IF_MSG(ppc_ptrace_gethwdbginfo(pid, &dbginfo), "PPC_PTRACE_GETHWDBGINFO failed"); + SKIP_IF_MSG(dbginfo.num_data_bps <= 1, "Not enough data watchpoints (need at least 2)"); -kill_child: - kill(cpid, SIGINT); - ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); - return ret; + return 0; } -static int test10(pid_t child_pid) +/* + * Wrapper around a plain fork() call that sets up the child for + * ptrace-ing. Both the parent and child return from this, though + * the child is stopped until ptrace_cont(pid) is run by the parent. + */ +static int ptrace_fork_child(pid_t *pid) { - int perf_fd; - int ptrace_fd; - int ret = 0; - - /* Test: - * if (new per cpu event by perf) - * if (existing thread event by ptrace on the same thread) - * if (addr range overlaps) - * fail; - */ - ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); - if (ptrace_fd < 0) - return -1; + int status; - perf_fd = perf_cpu_event_open(0, (__u64)perf_data1, sizeof(*perf_data1)); - if (perf_fd > 0 || errno != ENOSPC) - ret = -1; - - ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); - return ret; -} + *pid = fork(); -static int test11(pid_t child_pid) -{ - int perf_fd; - int ptrace_fd; - int ret = 0; - - /* Test: - * if (new per cpu event by perf) - * if (existing thread event by ptrace on the same thread) - * if (addr range does not overlap) - * allow; - */ - ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2)); - if (ptrace_fd < 0) - return -1; + if (*pid < 0) + FAIL_IF_MSG(1, "Failed to fork child"); - perf_fd = perf_cpu_event_open(0, (__u64)perf_data2, sizeof(*perf_data2)); - if (perf_fd < 0) { - ret = -1; - goto ptrace_close; + if (!*pid) { + FAIL_IF_EXIT_MSG(ptrace_traceme(), "PTRACE_TRACEME failed"); + FAIL_IF_EXIT_MSG(raise(SIGSTOP), "Child failed to raise SIGSTOP"); + } else { + /* Synchronise on child SIGSTOP */ + FAIL_IF_MSG(waitpid(*pid, &status, 0) == -1, "Failed to wait for child"); + FAIL_IF_MSG(!WIFSTOPPED(status), "Child is not stopped"); } - close(perf_fd); -ptrace_close: - ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); - return ret; + return 0; } -static int test12(pid_t child_pid) +/* + * Tests the interaction between ptrace and perf watching the same data. + * + * We expect ptrace to take 'priority', as it is has before-execute + * semantics. + * + * The perf counter should not be incremented yet because perf has after-execute + * semantics. E.g., if ptrace changes the child PC, we don't even execute the + * instruction at all. + * + * When the child is stopped for ptrace, we test both continue and single step. + * Both should increment the perf counter. We also test changing the PC somewhere + * different and stepping, which should not increment the perf counter. + */ +int same_watch_addr_test(void) { - int perf_fd; - int ptrace_fd; - int ret = 0; - - /* Test: - * if (new per thread and per cpu event by perf) - * if (existing thread event by ptrace on the same thread) - * if (addr range overlaps) - * fail; - */ - ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); - if (ptrace_fd < 0) - return -1; + struct ppc_hw_breakpoint bp_info; /* ptrace breakpoint info */ + int bp_id; /* Breakpoint handle of ptrace watchpoint */ + int perf_fd; /* File descriptor of perf performance counter */ + u64 perf_count; /* Most recently fetched perf performance counter value */ + pid_t pid; /* PID of child process */ + void *pc; /* Most recently fetched child PC value */ + int status; /* Stop status of child after waitpid */ + unsigned long value; /* Dummy value to be read/written to by child */ + int err; + + err = ptrace_fork_child(&pid); + if (err) + return err; + + if (!pid) { + same_watch_addr_child(&value); + exit(1); + } - perf_fd = perf_thread_cpu_event_open(child_pid, 0, (__u64)perf_data1, sizeof(*perf_data1)); - if (perf_fd > 0 || errno != ENOSPC) - ret = -1; + err = check_watchpoints(pid); + if (err) + return err; - ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); - return ret; -} + /* Place a perf watchpoint counter on value */ + perf_fd = perf_watchpoint_open(pid, &value, sizeof(value)); + FAIL_IF_MSG(perf_fd < 0, "Failed to open perf performance counter"); -static int test13(pid_t child_pid) -{ - int perf_fd; - int ptrace_fd; - int ret = 0; - - /* Test: - * if (new per thread and per cpu event by perf) - * if (existing thread event by ptrace on the same thread) - * if (addr range does not overlap) - * allow; - */ - ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2)); - if (ptrace_fd < 0) - return -1; + /* Place a ptrace watchpoint on value */ + ppc_ptrace_init_breakpoint(&bp_info, PPC_BREAKPOINT_TRIGGER_READ, &value, sizeof(value)); + bp_id = ppc_ptrace_sethwdbg(pid, &bp_info); + FAIL_IF_MSG(bp_id < 0, "Failed to set ptrace watchpoint"); - perf_fd = perf_thread_cpu_event_open(child_pid, 0, (__u64)perf_data2, sizeof(*perf_data2)); - if (perf_fd < 0) { - ret = -1; - goto ptrace_close; - } - close(perf_fd); + /* Let the child run. It should stop on the ptrace watchpoint */ + FAIL_IF_MSG(ptrace_cont(pid, 0), "Failed to continue child"); -ptrace_close: - ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); - return ret; -} + FAIL_IF_MSG(waitpid(pid, &status, 0) == -1, "Failed to wait for child"); + FAIL_IF_MSG(!WIFSTOPPED(status), "Child is not stopped"); + FAIL_IF_MSG(ptrace_getreg_pc(pid, &pc), "Failed to get child PC"); + FAIL_IF_MSG(pc != same_watch_addr_load, "Child did not stop on load instruction"); -static int test14(pid_t child_pid) -{ - int perf_fd; - int ptrace_fd; - int cpid; - int ret = 0; - - /* Test: - * if (new per thread and per cpu event by perf) - * if (existing thread event by ptrace on the other thread) - * allow; + /* + * We stopped before executing the load, so perf should not have + * recorded any events yet */ - ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1)); - if (ptrace_fd < 0) - return -1; - - cpid = fork(); - if (!cpid) { - /* Temporary Child */ - pause(); - exit(EXIT_SUCCESS); - } - - perf_fd = perf_thread_cpu_event_open(cpid, 0, (__u64)perf_data1, - sizeof(*perf_data1)); - if (perf_fd < 0) { - ret = -1; - goto kill_child; - } - close(perf_fd); - -kill_child: - kill(cpid, SIGINT); - ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd); - return ret; -} + FAIL_IF_MSG(perf_read_counter(perf_fd, &perf_count), "Failed to read perf counter"); + FAIL_IF_MSG(perf_count != 0, "perf recorded unexpected event"); + + /* Single stepping over the load should increment the perf counter */ + FAIL_IF_MSG(ptrace_singlestep(pid, 0), "Failed to single step child"); + + FAIL_IF_MSG(waitpid(pid, &status, 0) == -1, "Failed to wait for child"); + FAIL_IF_MSG(!WIFSTOPPED(status), "Child is not stopped"); + FAIL_IF_MSG(ptrace_getreg_pc(pid, &pc), "Failed to get child PC"); + FAIL_IF_MSG(pc != same_watch_addr_load + 4, "Failed to single step load instruction"); + FAIL_IF_MSG(perf_read_counter(perf_fd, &perf_count), "Failed to read perf counter"); + FAIL_IF_MSG(perf_count != 1, "perf counter did not increment"); + + /* + * Set up a ptrace watchpoint on the value again and trigger it. + * The perf counter should not have incremented because we do not + * execute the load yet. + */ + FAIL_IF_MSG(ppc_ptrace_delhwdbg(pid, bp_id), "Failed to remove old ptrace watchpoint"); + bp_id = ppc_ptrace_sethwdbg(pid, &bp_info); + FAIL_IF_MSG(bp_id < 0, "Failed to set ptrace watchpoint"); + FAIL_IF_MSG(ptrace_setreg_pc(pid, same_watch_addr_load), "Failed to set child PC"); + FAIL_IF_MSG(ptrace_cont(pid, 0), "Failed to continue child"); + + FAIL_IF_MSG(waitpid(pid, &status, 0) == -1, "Failed to wait for child"); + FAIL_IF_MSG(!WIFSTOPPED(status), "Child is not stopped"); + FAIL_IF_MSG(ptrace_getreg_pc(pid, &pc), "Failed to get child PC"); + FAIL_IF_MSG(pc != same_watch_addr_load, "Child did not stop on load trap"); + FAIL_IF_MSG(perf_read_counter(perf_fd, &perf_count), "Failed to read perf counter"); + FAIL_IF_MSG(perf_count != 1, "perf counter should not have changed"); + + /* Continuing over the load should increment the perf counter */ + FAIL_IF_MSG(ptrace_cont(pid, 0), "Failed to continue child"); + + FAIL_IF_MSG(waitpid(pid, &status, 0) == -1, "Failed to wait for child"); + FAIL_IF_MSG(!WIFSTOPPED(status), "Child is not stopped"); + FAIL_IF_MSG(ptrace_getreg_pc(pid, &pc), "Failed to get child PC"); + FAIL_IF_MSG(pc != same_watch_addr_trap, "Child did not stop on end trap"); + FAIL_IF_MSG(perf_read_counter(perf_fd, &perf_count), "Failed to read perf counter"); + FAIL_IF_MSG(perf_count != 2, "perf counter did not increment"); + + /* + * If we set the child PC back to the load instruction, then continue, + * we should reach the end trap (because ptrace is one-shot) and have + * another perf event. + */ + FAIL_IF_MSG(ptrace_setreg_pc(pid, same_watch_addr_load), "Failed to set child PC"); + FAIL_IF_MSG(ptrace_cont(pid, 0), "Failed to continue child"); + + FAIL_IF_MSG(waitpid(pid, &status, 0) == -1, "Failed to wait for child"); + FAIL_IF_MSG(!WIFSTOPPED(status), "Child is not stopped"); + FAIL_IF_MSG(ptrace_getreg_pc(pid, &pc), "Failed to get child PC"); + FAIL_IF_MSG(pc != same_watch_addr_trap, "Child did not stop on end trap"); + FAIL_IF_MSG(perf_read_counter(perf_fd, &perf_count), "Failed to read perf counter"); + FAIL_IF_MSG(perf_count != 3, "perf counter did not increment"); + + /* + * If we set the child PC back to the load instruction, set a ptrace + * watchpoint on the load, then continue, we should immediately get + * the ptrace trap without incrementing the perf counter + */ + FAIL_IF_MSG(ppc_ptrace_delhwdbg(pid, bp_id), "Failed to remove old ptrace watchpoint"); + bp_id = ppc_ptrace_sethwdbg(pid, &bp_info); + FAIL_IF_MSG(bp_id < 0, "Failed to set ptrace watchpoint"); + FAIL_IF_MSG(ptrace_setreg_pc(pid, same_watch_addr_load), "Failed to set child PC"); + FAIL_IF_MSG(ptrace_cont(pid, 0), "Failed to continue child"); + + FAIL_IF_MSG(waitpid(pid, &status, 0) == -1, "Failed to wait for child"); + FAIL_IF_MSG(!WIFSTOPPED(status), "Child is not stopped"); + FAIL_IF_MSG(ptrace_getreg_pc(pid, &pc), "Failed to get child PC"); + FAIL_IF_MSG(pc != same_watch_addr_load, "Child did not stop on load instruction"); + FAIL_IF_MSG(perf_read_counter(perf_fd, &perf_count), "Failed to read perf counter"); + FAIL_IF_MSG(perf_count != 3, "perf counter should not have changed"); + + /* + * If we change the PC while stopped on the load instruction, we should + * not increment the perf counter (because ptrace is before-execute, + * perf is after-execute). + */ + FAIL_IF_MSG(ptrace_setreg_pc(pid, same_watch_addr_load + 4), "Failed to set child PC"); + FAIL_IF_MSG(ptrace_cont(pid, 0), "Failed to continue child"); -static int do_test(const char *msg, int (*fun)(pid_t arg), pid_t arg) -{ - int ret; + FAIL_IF_MSG(waitpid(pid, &status, 0) == -1, "Failed to wait for child"); + FAIL_IF_MSG(!WIFSTOPPED(status), "Child is not stopped"); + FAIL_IF_MSG(ptrace_getreg_pc(pid, &pc), "Failed to get child PC"); + FAIL_IF_MSG(pc != same_watch_addr_trap, "Child did not stop on end trap"); + FAIL_IF_MSG(perf_read_counter(perf_fd, &perf_count), "Failed to read perf counter"); + FAIL_IF_MSG(perf_count != 3, "perf counter should not have changed"); - ret = fun(arg); - if (ret) - printf("%s: Error\n", msg); - else - printf("%s: Ok\n", msg); - return ret; -} + /* Clean up child */ + FAIL_IF_MSG(kill(pid, SIGKILL) != 0, "Failed to kill child"); -char *desc[14] = { - "perf cpu event -> ptrace thread event (Overlapping)", - "perf cpu event -> ptrace thread event (Non-overlapping)", - "perf thread event -> ptrace same thread event (Overlapping)", - "perf thread event -> ptrace same thread event (Non-overlapping)", - "perf thread event -> ptrace other thread event", - "ptrace thread event -> perf kernel event", - "ptrace thread event -> perf same thread event (Overlapping)", - "ptrace thread event -> perf same thread event (Non-overlapping)", - "ptrace thread event -> perf other thread event", - "ptrace thread event -> perf cpu event (Overlapping)", - "ptrace thread event -> perf cpu event (Non-overlapping)", - "ptrace thread event -> perf same thread & cpu event (Overlapping)", - "ptrace thread event -> perf same thread & cpu event (Non-overlapping)", - "ptrace thread event -> perf other thread & cpu event", -}; - -static int test(pid_t child_pid) -{ - int ret = TEST_PASS; - - ret |= do_test(desc[0], test1, child_pid); - ret |= do_test(desc[1], test2, child_pid); - ret |= do_test(desc[2], test3, child_pid); - ret |= do_test(desc[3], test4, child_pid); - ret |= do_test(desc[4], test5, child_pid); - ret |= do_test(desc[5], test6, child_pid); - ret |= do_test(desc[6], test7, child_pid); - ret |= do_test(desc[7], test8, child_pid); - ret |= do_test(desc[8], test9, child_pid); - ret |= do_test(desc[9], test10, child_pid); - ret |= do_test(desc[10], test11, child_pid); - ret |= do_test(desc[11], test12, child_pid); - ret |= do_test(desc[12], test13, child_pid); - ret |= do_test(desc[13], test14, child_pid); - - return ret; + return 0; } -static void get_dbginfo(pid_t child_pid, struct ppc_debug_info *dbginfo) +/* + * Tests the interaction between ptrace and perf when: + * 1. perf watches a value + * 2. ptrace watches a different value + * 3. The perf value is read, then the ptrace value is read immediately after + * + * A breakpoint implementation may accidentally misattribute/skip one of + * the ptrace or perf handlers, as interrupt based work is done after perf + * and before ptrace. + * + * We expect the perf counter to increment before the ptrace watchpoint + * triggers. + */ +int perf_then_ptrace_test(void) { - if (ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, dbginfo)) { - perror("Can't get breakpoint info"); - exit(-1); + struct ppc_hw_breakpoint bp_info; /* ptrace breakpoint info */ + int bp_id; /* Breakpoint handle of ptrace watchpoint */ + int perf_fd; /* File descriptor of perf performance counter */ + u64 perf_count; /* Most recently fetched perf performance counter value */ + pid_t pid; /* PID of child process */ + void *pc; /* Most recently fetched child PC value */ + int status; /* Stop status of child after waitpid */ + unsigned long perf_value; /* Dummy value to be watched by perf */ + unsigned long ptrace_value; /* Dummy value to be watched by ptrace */ + int err; + + err = ptrace_fork_child(&pid); + if (err) + return err; + + /* + * If we are the child, run a subroutine that reads the perf value, + * then reads the ptrace value with consecutive load instructions + */ + if (!pid) { + perf_then_ptrace_child(&perf_value, &ptrace_value); + exit(0); } -} -static int ptrace_perf_hwbreak(void) -{ - int ret; - pid_t child_pid; - struct ppc_debug_info dbginfo; + err = check_watchpoints(pid); + if (err) + return err; - child_pid = fork(); - if (!child_pid) - return child(); + /* Place a perf watchpoint counter */ + perf_fd = perf_watchpoint_open(pid, &perf_value, sizeof(perf_value)); + FAIL_IF_MSG(perf_fd < 0, "Failed to open perf performance counter"); - /* parent */ - wait(NULL); /* <-- child (SIGUSR1) */ + /* Place a ptrace watchpoint */ + ppc_ptrace_init_breakpoint(&bp_info, PPC_BREAKPOINT_TRIGGER_READ, + &ptrace_value, sizeof(ptrace_value)); + bp_id = ppc_ptrace_sethwdbg(pid, &bp_info); + FAIL_IF_MSG(bp_id < 0, "Failed to set ptrace watchpoint"); - get_dbginfo(child_pid, &dbginfo); - SKIP_IF(dbginfo.num_data_bps <= 1); + /* Let the child run. It should stop on the ptrace watchpoint */ + FAIL_IF_MSG(ptrace_cont(pid, 0), "Failed to continue child"); - ret = perf_cpu_event_open(0, (__u64)perf_data1, sizeof(*perf_data1)); - SKIP_IF(ret < 0); - close(ret); + FAIL_IF_MSG(waitpid(pid, &status, 0) == -1, "Failed to wait for child"); + FAIL_IF_MSG(!WIFSTOPPED(status), "Child is not stopped"); + FAIL_IF_MSG(ptrace_getreg_pc(pid, &pc), "Failed to get child PC"); + FAIL_IF_MSG(pc != perf_then_ptrace_load2, "Child did not stop on ptrace load"); - ret = test(child_pid); + /* perf should have recorded the first load */ + FAIL_IF_MSG(perf_read_counter(perf_fd, &perf_count), "Failed to read perf counter"); + FAIL_IF_MSG(perf_count != 1, "perf counter did not increment"); - ptrace(PTRACE_CONT, child_pid, NULL, 0); - return ret; + /* Clean up child */ + FAIL_IF_MSG(kill(pid, SIGKILL) != 0, "Failed to kill child"); + + return 0; } int main(int argc, char *argv[]) { - return test_harness(ptrace_perf_hwbreak, "ptrace-perf-hwbreak"); + int err = 0; + + err |= test_harness(same_watch_addr_test, "same_watch_addr"); + err |= test_harness(perf_then_ptrace_test, "perf_then_ptrace"); + + return err; } diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c b/tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c index bc454f899124..d89474377f11 100644 --- a/tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c @@ -192,7 +192,7 @@ static int parent(struct shared_info *info, pid_t pid) * to the child. */ ret = ptrace_read_regs(pid, NT_PPC_PKEY, regs, 3); - PARENT_SKIP_IF_UNSUPPORTED(ret, &info->child_sync); + PARENT_SKIP_IF_UNSUPPORTED(ret, &info->child_sync, "PKEYs not supported"); PARENT_FAIL_IF(ret, &info->child_sync); info->amr1 = info->amr2 = regs[0]; diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-tar.c b/tools/testing/selftests/powerpc/ptrace/ptrace-tar.c index 4436ca9d3caf..14726c77a6ce 100644 --- a/tools/testing/selftests/powerpc/ptrace/ptrace-tar.c +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-tar.c @@ -79,7 +79,7 @@ int ptrace_tar(void) int ret, status; // TAR was added in v2.07 - SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_2_07)); + SKIP_IF_MSG(!have_hwcap2(PPC_FEATURE2_ARCH_2_07), "TAR requires ISA 2.07 compatible hardware"); shm_id = shmget(IPC_PRIVATE, sizeof(int) * 3, 0777|IPC_CREAT); pid = fork(); diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-tm-gpr.c b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-gpr.c index 5dc152b162df..7c70d62587c2 100644 --- a/tools/testing/selftests/powerpc/ptrace/ptrace-tm-gpr.c +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-gpr.c @@ -112,8 +112,8 @@ int ptrace_tm_gpr(void) pid_t pid; int ret, status; - SKIP_IF(!have_htm()); - SKIP_IF(htm_is_synthetic()); + SKIP_IF_MSG(!have_htm(), "Don't have transactional memory"); + SKIP_IF_MSG(htm_is_synthetic(), "Transactional memory is synthetic"); shm_id = shmget(IPC_PRIVATE, sizeof(int) * 2, 0777|IPC_CREAT); pid = fork(); if (pid < 0) { diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spd-gpr.c b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spd-gpr.c index 458cc1a70ccf..6c17ed099969 100644 --- a/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spd-gpr.c +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spd-gpr.c @@ -118,8 +118,8 @@ int ptrace_tm_spd_gpr(void) pid_t pid; int ret, status; - SKIP_IF(!have_htm()); - SKIP_IF(htm_is_synthetic()); + SKIP_IF_MSG(!have_htm(), "Don't have transactional memory"); + SKIP_IF_MSG(htm_is_synthetic(), "Transactional memory is synthetic"); shm_id = shmget(IPC_PRIVATE, sizeof(int) * 3, 0777|IPC_CREAT); pid = fork(); if (pid < 0) { diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spd-tar.c b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spd-tar.c index e112a34fbe59..afd8dc2e2097 100644 --- a/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spd-tar.c +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spd-tar.c @@ -128,8 +128,8 @@ int ptrace_tm_spd_tar(void) pid_t pid; int ret, status; - SKIP_IF(!have_htm()); - SKIP_IF(htm_is_synthetic()); + SKIP_IF_MSG(!have_htm(), "Don't have transactional memory"); + SKIP_IF_MSG(htm_is_synthetic(), "Transactional memory is synthetic"); shm_id = shmget(IPC_PRIVATE, sizeof(int) * 3, 0777|IPC_CREAT); pid = fork(); if (pid == 0) diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spd-vsx.c b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spd-vsx.c index 40133d49fe39..14d2fac8f237 100644 --- a/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spd-vsx.c +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spd-vsx.c @@ -128,8 +128,8 @@ int ptrace_tm_spd_vsx(void) pid_t pid; int ret, status, i; - SKIP_IF(!have_htm()); - SKIP_IF(htm_is_synthetic()); + SKIP_IF_MSG(!have_htm(), "Don't have transactional memory"); + SKIP_IF_MSG(htm_is_synthetic(), "Transactional memory is synthetic"); shm_id = shmget(IPC_PRIVATE, sizeof(int) * 3, 0777|IPC_CREAT); for (i = 0; i < 128; i++) { diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spr.c b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spr.c index 880ba6a29a48..e64cdb04cecf 100644 --- a/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spr.c +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-spr.c @@ -113,8 +113,8 @@ int ptrace_tm_spr(void) pid_t pid; int ret, status; - SKIP_IF(!have_htm()); - SKIP_IF(htm_is_synthetic()); + SKIP_IF_MSG(!have_htm(), "Don't have transactional memory"); + SKIP_IF_MSG(htm_is_synthetic(), "Transactional memory is synthetic"); shm_id = shmget(IPC_PRIVATE, sizeof(struct shared), 0777|IPC_CREAT); shm_id1 = shmget(IPC_PRIVATE, sizeof(int), 0777|IPC_CREAT); pid = fork(); diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-tm-tar.c b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-tar.c index d0db6df0f0ea..3963d4b0429f 100644 --- a/tools/testing/selftests/powerpc/ptrace/ptrace-tm-tar.c +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-tar.c @@ -116,8 +116,8 @@ int ptrace_tm_tar(void) pid_t pid; int ret, status; - SKIP_IF(!have_htm()); - SKIP_IF(htm_is_synthetic()); + SKIP_IF_MSG(!have_htm(), "Don't have transactional memory"); + SKIP_IF_MSG(htm_is_synthetic(), "Transactional memory is synthetic"); shm_id = shmget(IPC_PRIVATE, sizeof(int) * 2, 0777|IPC_CREAT); pid = fork(); if (pid == 0) diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-tm-vsx.c b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-vsx.c index 4f05ce4fd282..8c925d734a72 100644 --- a/tools/testing/selftests/powerpc/ptrace/ptrace-tm-vsx.c +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-tm-vsx.c @@ -112,8 +112,8 @@ int ptrace_tm_vsx(void) pid_t pid; int ret, status, i; - SKIP_IF(!have_htm()); - SKIP_IF(htm_is_synthetic()); + SKIP_IF_MSG(!have_htm(), "Don't have transactional memory"); + SKIP_IF_MSG(htm_is_synthetic(), "Transactional memory is synthetic"); shm_id = shmget(IPC_PRIVATE, sizeof(int) * 2, 0777|IPC_CREAT); for (i = 0; i < 128; i++) { diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-vsx.c b/tools/testing/selftests/powerpc/ptrace/ptrace-vsx.c index cb9875f764ca..11bc624574fe 100644 --- a/tools/testing/selftests/powerpc/ptrace/ptrace-vsx.c +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-vsx.c @@ -61,7 +61,7 @@ int ptrace_vsx(void) pid_t pid; int ret, status, i; - SKIP_IF(!have_hwcap(PPC_FEATURE_HAS_VSX)); + SKIP_IF_MSG(!have_hwcap(PPC_FEATURE_HAS_VSX), "Don't have VSX"); shm_id = shmget(IPC_PRIVATE, sizeof(int) * 2, 0777|IPC_CREAT); |