root/tools/perf/arch/x86/tests/bp-modify.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bp_1
  2. bp_2
  3. spawn_child
  4. bp_modify1
  5. bp_modify2
  6. test__bp_modify

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <linux/compiler.h>
   3 #include <sys/types.h>
   4 #include <sys/wait.h>
   5 #include <sys/user.h>
   6 #include <syscall.h>
   7 #include <unistd.h>
   8 #include <stdio.h>
   9 #include <stdlib.h>
  10 #include <string.h>
  11 #include <sys/ptrace.h>
  12 #include <asm/ptrace.h>
  13 #include <errno.h>
  14 #include "debug.h"
  15 #include "tests/tests.h"
  16 #include "arch-tests.h"
  17 
  18 static noinline int bp_1(void)
  19 {
  20         pr_debug("in %s\n", __func__);
  21         return 0;
  22 }
  23 
  24 static noinline int bp_2(void)
  25 {
  26         pr_debug("in %s\n", __func__);
  27         return 0;
  28 }
  29 
  30 static int spawn_child(void)
  31 {
  32         int child = fork();
  33 
  34         if (child == 0) {
  35                 /*
  36                  * The child sets itself for as tracee and
  37                  * waits in signal for parent to trace it,
  38                  * then it calls bp_1 and quits.
  39                  */
  40                 int err = ptrace(PTRACE_TRACEME, 0, NULL, NULL);
  41 
  42                 if (err) {
  43                         pr_debug("failed to PTRACE_TRACEME\n");
  44                         exit(1);
  45                 }
  46 
  47                 raise(SIGCONT);
  48                 bp_1();
  49                 exit(0);
  50         }
  51 
  52         return child;
  53 }
  54 
  55 /*
  56  * This tests creates HW breakpoint, tries to
  57  * change it and checks it was properly changed.
  58  */
  59 static int bp_modify1(void)
  60 {
  61         pid_t child;
  62         int status;
  63         unsigned long rip = 0, dr7 = 1;
  64 
  65         child = spawn_child();
  66 
  67         waitpid(child, &status, 0);
  68         if (WIFEXITED(status)) {
  69                 pr_debug("tracee exited prematurely 1\n");
  70                 return TEST_FAIL;
  71         }
  72 
  73         /*
  74          * The parent does following steps:
  75          *  - creates a new breakpoint (id 0) for bp_2 function
  76          *  - changes that breakponit to bp_1 function
  77          *  - waits for the breakpoint to hit and checks
  78          *    it has proper rip of bp_1 function
  79          *  - detaches the child
  80          */
  81         if (ptrace(PTRACE_POKEUSER, child,
  82                    offsetof(struct user, u_debugreg[0]), bp_2)) {
  83                 pr_debug("failed to set breakpoint, 1st time: %s\n",
  84                          strerror(errno));
  85                 goto out;
  86         }
  87 
  88         if (ptrace(PTRACE_POKEUSER, child,
  89                    offsetof(struct user, u_debugreg[0]), bp_1)) {
  90                 pr_debug("failed to set breakpoint, 2nd time: %s\n",
  91                          strerror(errno));
  92                 goto out;
  93         }
  94 
  95         if (ptrace(PTRACE_POKEUSER, child,
  96                    offsetof(struct user, u_debugreg[7]), dr7)) {
  97                 pr_debug("failed to set dr7: %s\n", strerror(errno));
  98                 goto out;
  99         }
 100 
 101         if (ptrace(PTRACE_CONT, child, NULL, NULL)) {
 102                 pr_debug("failed to PTRACE_CONT: %s\n", strerror(errno));
 103                 goto out;
 104         }
 105 
 106         waitpid(child, &status, 0);
 107         if (WIFEXITED(status)) {
 108                 pr_debug("tracee exited prematurely 2\n");
 109                 return TEST_FAIL;
 110         }
 111 
 112         rip = ptrace(PTRACE_PEEKUSER, child,
 113                      offsetof(struct user_regs_struct, rip), NULL);
 114         if (rip == (unsigned long) -1) {
 115                 pr_debug("failed to PTRACE_PEEKUSER: %s\n",
 116                          strerror(errno));
 117                 goto out;
 118         }
 119 
 120         pr_debug("rip %lx, bp_1 %p\n", rip, bp_1);
 121 
 122 out:
 123         if (ptrace(PTRACE_DETACH, child, NULL, NULL)) {
 124                 pr_debug("failed to PTRACE_DETACH: %s", strerror(errno));
 125                 return TEST_FAIL;
 126         }
 127 
 128         return rip == (unsigned long) bp_1 ? TEST_OK : TEST_FAIL;
 129 }
 130 
 131 /*
 132  * This tests creates HW breakpoint, tries to
 133  * change it to bogus value and checks the original
 134  * breakpoint is hit.
 135  */
 136 static int bp_modify2(void)
 137 {
 138         pid_t child;
 139         int status;
 140         unsigned long rip = 0, dr7 = 1;
 141 
 142         child = spawn_child();
 143 
 144         waitpid(child, &status, 0);
 145         if (WIFEXITED(status)) {
 146                 pr_debug("tracee exited prematurely 1\n");
 147                 return TEST_FAIL;
 148         }
 149 
 150         /*
 151          * The parent does following steps:
 152          *  - creates a new breakpoint (id 0) for bp_1 function
 153          *  - tries to change that breakpoint to (-1) address
 154          *  - waits for the breakpoint to hit and checks
 155          *    it has proper rip of bp_1 function
 156          *  - detaches the child
 157          */
 158         if (ptrace(PTRACE_POKEUSER, child,
 159                    offsetof(struct user, u_debugreg[0]), bp_1)) {
 160                 pr_debug("failed to set breakpoint: %s\n",
 161                          strerror(errno));
 162                 goto out;
 163         }
 164 
 165         if (ptrace(PTRACE_POKEUSER, child,
 166                    offsetof(struct user, u_debugreg[7]), dr7)) {
 167                 pr_debug("failed to set dr7: %s\n", strerror(errno));
 168                 goto out;
 169         }
 170 
 171         if (!ptrace(PTRACE_POKEUSER, child,
 172                    offsetof(struct user, u_debugreg[0]), (unsigned long) (-1))) {
 173                 pr_debug("failed, breakpoint set to bogus address\n");
 174                 goto out;
 175         }
 176 
 177         if (ptrace(PTRACE_CONT, child, NULL, NULL)) {
 178                 pr_debug("failed to PTRACE_CONT: %s\n", strerror(errno));
 179                 goto out;
 180         }
 181 
 182         waitpid(child, &status, 0);
 183         if (WIFEXITED(status)) {
 184                 pr_debug("tracee exited prematurely 2\n");
 185                 return TEST_FAIL;
 186         }
 187 
 188         rip = ptrace(PTRACE_PEEKUSER, child,
 189                      offsetof(struct user_regs_struct, rip), NULL);
 190         if (rip == (unsigned long) -1) {
 191                 pr_debug("failed to PTRACE_PEEKUSER: %s\n",
 192                          strerror(errno));
 193                 goto out;
 194         }
 195 
 196         pr_debug("rip %lx, bp_1 %p\n", rip, bp_1);
 197 
 198 out:
 199         if (ptrace(PTRACE_DETACH, child, NULL, NULL)) {
 200                 pr_debug("failed to PTRACE_DETACH: %s", strerror(errno));
 201                 return TEST_FAIL;
 202         }
 203 
 204         return rip == (unsigned long) bp_1 ? TEST_OK : TEST_FAIL;
 205 }
 206 
 207 int test__bp_modify(struct test *test __maybe_unused,
 208                     int subtest __maybe_unused)
 209 {
 210         TEST_ASSERT_VAL("modify test 1 failed\n", !bp_modify1());
 211         TEST_ASSERT_VAL("modify test 2 failed\n", !bp_modify2());
 212 
 213         return 0;
 214 }

/* [<][>][^][v][top][bottom][index][help] */