Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2016 Google, Inc.
0004  *
0005  * Original Code by Pavel Labath <labath@google.com>
0006  *
0007  * Code modified by Pratyush Anand <panand@redhat.com>
0008  * for testing different byte select for each access size.
0009  */
0010 
0011 #define _GNU_SOURCE
0012 
0013 #include <asm/ptrace.h>
0014 #include <sys/types.h>
0015 #include <sys/wait.h>
0016 #include <sys/ptrace.h>
0017 #include <sys/param.h>
0018 #include <sys/uio.h>
0019 #include <stdint.h>
0020 #include <stdbool.h>
0021 #include <stddef.h>
0022 #include <string.h>
0023 #include <stdio.h>
0024 #include <unistd.h>
0025 #include <elf.h>
0026 #include <errno.h>
0027 #include <signal.h>
0028 
0029 #include "../kselftest.h"
0030 
0031 static volatile uint8_t var[96] __attribute__((__aligned__(32)));
0032 
0033 static void child(int size, int wr)
0034 {
0035     volatile uint8_t *addr = &var[32 + wr];
0036 
0037     if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) != 0) {
0038         ksft_print_msg(
0039             "ptrace(PTRACE_TRACEME) failed: %s\n",
0040             strerror(errno));
0041         _exit(1);
0042     }
0043 
0044     if (raise(SIGSTOP) != 0) {
0045         ksft_print_msg(
0046             "raise(SIGSTOP) failed: %s\n", strerror(errno));
0047         _exit(1);
0048     }
0049 
0050     if ((uintptr_t) addr % size) {
0051         ksft_print_msg(
0052              "Wrong address write for the given size: %s\n",
0053              strerror(errno));
0054         _exit(1);
0055     }
0056 
0057     switch (size) {
0058     case 1:
0059         *addr = 47;
0060         break;
0061     case 2:
0062         *(uint16_t *)addr = 47;
0063         break;
0064     case 4:
0065         *(uint32_t *)addr = 47;
0066         break;
0067     case 8:
0068         *(uint64_t *)addr = 47;
0069         break;
0070     case 16:
0071         __asm__ volatile ("stp x29, x30, %0" : "=m" (addr[0]));
0072         break;
0073     case 32:
0074         __asm__ volatile ("stp q29, q30, %0" : "=m" (addr[0]));
0075         break;
0076     }
0077 
0078     _exit(0);
0079 }
0080 
0081 static bool set_watchpoint(pid_t pid, int size, int wp)
0082 {
0083     const volatile uint8_t *addr = &var[32 + wp];
0084     const int offset = (uintptr_t)addr % 8;
0085     const unsigned int byte_mask = ((1 << size) - 1) << offset;
0086     const unsigned int type = 2; /* Write */
0087     const unsigned int enable = 1;
0088     const unsigned int control = byte_mask << 5 | type << 3 | enable;
0089     struct user_hwdebug_state dreg_state;
0090     struct iovec iov;
0091 
0092     memset(&dreg_state, 0, sizeof(dreg_state));
0093     dreg_state.dbg_regs[0].addr = (uintptr_t)(addr - offset);
0094     dreg_state.dbg_regs[0].ctrl = control;
0095     iov.iov_base = &dreg_state;
0096     iov.iov_len = offsetof(struct user_hwdebug_state, dbg_regs) +
0097                 sizeof(dreg_state.dbg_regs[0]);
0098     if (ptrace(PTRACE_SETREGSET, pid, NT_ARM_HW_WATCH, &iov) == 0)
0099         return true;
0100 
0101     if (errno == EIO)
0102         ksft_print_msg(
0103             "ptrace(PTRACE_SETREGSET, NT_ARM_HW_WATCH) not supported on this hardware: %s\n",
0104             strerror(errno));
0105 
0106     ksft_print_msg(
0107         "ptrace(PTRACE_SETREGSET, NT_ARM_HW_WATCH) failed: %s\n",
0108         strerror(errno));
0109     return false;
0110 }
0111 
0112 static bool run_test(int wr_size, int wp_size, int wr, int wp)
0113 {
0114     int status;
0115     siginfo_t siginfo;
0116     pid_t pid = fork();
0117     pid_t wpid;
0118 
0119     if (pid < 0) {
0120         ksft_test_result_fail(
0121             "fork() failed: %s\n", strerror(errno));
0122         return false;
0123     }
0124     if (pid == 0)
0125         child(wr_size, wr);
0126 
0127     wpid = waitpid(pid, &status, __WALL);
0128     if (wpid != pid) {
0129         ksft_print_msg(
0130             "waitpid() failed: %s\n", strerror(errno));
0131         return false;
0132     }
0133     if (!WIFSTOPPED(status)) {
0134         ksft_print_msg(
0135             "child did not stop: %s\n", strerror(errno));
0136         return false;
0137     }
0138     if (WSTOPSIG(status) != SIGSTOP) {
0139         ksft_print_msg("child did not stop with SIGSTOP\n");
0140         return false;
0141     }
0142 
0143     if (!set_watchpoint(pid, wp_size, wp))
0144         return false;
0145 
0146     if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) {
0147         ksft_print_msg(
0148             "ptrace(PTRACE_CONT) failed: %s\n",
0149             strerror(errno));
0150         return false;
0151     }
0152 
0153     alarm(3);
0154     wpid = waitpid(pid, &status, __WALL);
0155     if (wpid != pid) {
0156         ksft_print_msg(
0157             "waitpid() failed: %s\n", strerror(errno));
0158         return false;
0159     }
0160     alarm(0);
0161     if (WIFEXITED(status)) {
0162         ksft_print_msg("child exited prematurely\n");
0163         return false;
0164     }
0165     if (!WIFSTOPPED(status)) {
0166         ksft_print_msg("child did not stop\n");
0167         return false;
0168     }
0169     if (WSTOPSIG(status) != SIGTRAP) {
0170         ksft_print_msg("child did not stop with SIGTRAP\n");
0171         return false;
0172     }
0173     if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo) != 0) {
0174         ksft_print_msg(
0175             "ptrace(PTRACE_GETSIGINFO): %s\n",
0176             strerror(errno));
0177         return false;
0178     }
0179     if (siginfo.si_code != TRAP_HWBKPT) {
0180         ksft_print_msg(
0181             "Unexpected si_code %d\n", siginfo.si_code);
0182         return false;
0183     }
0184 
0185     kill(pid, SIGKILL);
0186     wpid = waitpid(pid, &status, 0);
0187     if (wpid != pid) {
0188         ksft_print_msg(
0189             "waitpid() failed: %s\n", strerror(errno));
0190         return false;
0191     }
0192     return true;
0193 }
0194 
0195 static void sigalrm(int sig)
0196 {
0197 }
0198 
0199 int main(int argc, char **argv)
0200 {
0201     int opt;
0202     bool succeeded = true;
0203     struct sigaction act;
0204     int wr, wp, size;
0205     bool result;
0206 
0207     ksft_print_header();
0208     ksft_set_plan(213);
0209 
0210     act.sa_handler = sigalrm;
0211     sigemptyset(&act.sa_mask);
0212     act.sa_flags = 0;
0213     sigaction(SIGALRM, &act, NULL);
0214     for (size = 1; size <= 32; size = size*2) {
0215         for (wr = 0; wr <= 32; wr = wr + size) {
0216             for (wp = wr - size; wp <= wr + size; wp = wp + size) {
0217                 result = run_test(size, MIN(size, 8), wr, wp);
0218                 if ((result && wr == wp) ||
0219                     (!result && wr != wp))
0220                     ksft_test_result_pass(
0221                         "Test size = %d write offset = %d watchpoint offset = %d\n",
0222                         size, wr, wp);
0223                 else {
0224                     ksft_test_result_fail(
0225                         "Test size = %d write offset = %d watchpoint offset = %d\n",
0226                         size, wr, wp);
0227                     succeeded = false;
0228                 }
0229             }
0230         }
0231     }
0232 
0233     for (size = 1; size <= 32; size = size*2) {
0234         if (run_test(size, 8, -size, -8))
0235             ksft_test_result_pass(
0236                 "Test size = %d write offset = %d watchpoint offset = -8\n",
0237                 size, -size);
0238         else {
0239             ksft_test_result_fail(
0240                 "Test size = %d write offset = %d watchpoint offset = -8\n",
0241                 size, -size);
0242             succeeded = false;
0243         }
0244     }
0245 
0246     if (succeeded)
0247         ksft_exit_pass();
0248     else
0249         ksft_exit_fail();
0250 }