1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/compiler.h>
10 #include <sys/ptrace.h>
11 #include <asm/ptrace.h>
14 #include "tests/tests.h"
15 #include "arch-tests.h"
17 static noinline int bp_1(void)
19 pr_debug("in %s\n", __func__);
23 static noinline int bp_2(void)
25 pr_debug("in %s\n", __func__);
29 static int spawn_child(void)
35 * The child sets itself for as tracee and
36 * waits in signal for parent to trace it,
37 * then it calls bp_1 and quits.
39 int err = ptrace(PTRACE_TRACEME, 0, NULL, NULL);
42 pr_debug("failed to PTRACE_TRACEME\n");
55 * This tests creates HW breakpoint, tries to
56 * change it and checks it was properly changed.
58 static int bp_modify1(void)
62 unsigned long rip = 0, dr7 = 1;
64 child = spawn_child();
66 waitpid(child, &status, 0);
67 if (WIFEXITED(status)) {
68 pr_debug("tracee exited prematurely 1\n");
73 * The parent does following steps:
74 * - creates a new breakpoint (id 0) for bp_2 function
75 * - changes that breakponit to bp_1 function
76 * - waits for the breakpoint to hit and checks
77 * it has proper rip of bp_1 function
78 * - detaches the child
80 if (ptrace(PTRACE_POKEUSER, child,
81 offsetof(struct user, u_debugreg[0]), bp_2)) {
82 pr_debug("failed to set breakpoint, 1st time: %s\n",
87 if (ptrace(PTRACE_POKEUSER, child,
88 offsetof(struct user, u_debugreg[0]), bp_1)) {
89 pr_debug("failed to set breakpoint, 2nd time: %s\n",
94 if (ptrace(PTRACE_POKEUSER, child,
95 offsetof(struct user, u_debugreg[7]), dr7)) {
96 pr_debug("failed to set dr7: %s\n", strerror(errno));
100 if (ptrace(PTRACE_CONT, child, NULL, NULL)) {
101 pr_debug("failed to PTRACE_CONT: %s\n", strerror(errno));
105 waitpid(child, &status, 0);
106 if (WIFEXITED(status)) {
107 pr_debug("tracee exited prematurely 2\n");
111 rip = ptrace(PTRACE_PEEKUSER, child,
112 offsetof(struct user_regs_struct, rip), NULL);
113 if (rip == (unsigned long) -1) {
114 pr_debug("failed to PTRACE_PEEKUSER: %s\n",
119 pr_debug("rip %lx, bp_1 %p\n", rip, bp_1);
122 if (ptrace(PTRACE_DETACH, child, NULL, NULL)) {
123 pr_debug("failed to PTRACE_DETACH: %s", strerror(errno));
127 return rip == (unsigned long) bp_1 ? TEST_OK : TEST_FAIL;
131 * This tests creates HW breakpoint, tries to
132 * change it to bogus value and checks the original
135 static int bp_modify2(void)
139 unsigned long rip = 0, dr7 = 1;
141 child = spawn_child();
143 waitpid(child, &status, 0);
144 if (WIFEXITED(status)) {
145 pr_debug("tracee exited prematurely 1\n");
150 * The parent does following steps:
151 * - creates a new breakpoint (id 0) for bp_1 function
152 * - tries to change that breakpoint to (-1) address
153 * - waits for the breakpoint to hit and checks
154 * it has proper rip of bp_1 function
155 * - detaches the child
157 if (ptrace(PTRACE_POKEUSER, child,
158 offsetof(struct user, u_debugreg[0]), bp_1)) {
159 pr_debug("failed to set breakpoint: %s\n",
164 if (ptrace(PTRACE_POKEUSER, child,
165 offsetof(struct user, u_debugreg[7]), dr7)) {
166 pr_debug("failed to set dr7: %s\n", strerror(errno));
170 if (!ptrace(PTRACE_POKEUSER, child,
171 offsetof(struct user, u_debugreg[0]), (unsigned long) (-1))) {
172 pr_debug("failed, breakpoint set to bogus address\n");
176 if (ptrace(PTRACE_CONT, child, NULL, NULL)) {
177 pr_debug("failed to PTRACE_CONT: %s\n", strerror(errno));
181 waitpid(child, &status, 0);
182 if (WIFEXITED(status)) {
183 pr_debug("tracee exited prematurely 2\n");
187 rip = ptrace(PTRACE_PEEKUSER, child,
188 offsetof(struct user_regs_struct, rip), NULL);
189 if (rip == (unsigned long) -1) {
190 pr_debug("failed to PTRACE_PEEKUSER: %s\n",
195 pr_debug("rip %lx, bp_1 %p\n", rip, bp_1);
198 if (ptrace(PTRACE_DETACH, child, NULL, NULL)) {
199 pr_debug("failed to PTRACE_DETACH: %s", strerror(errno));
203 return rip == (unsigned long) bp_1 ? TEST_OK : TEST_FAIL;
206 int test__bp_modify(struct test *test __maybe_unused,
207 int subtest __maybe_unused)
209 TEST_ASSERT_VAL("modify test 1 failed\n", !bp_modify1());
210 TEST_ASSERT_VAL("modify test 2 failed\n", !bp_modify2());