Path: blob/master/tools/perf/arch/x86/tests/bp-modify.c
26292 views
// SPDX-License-Identifier: GPL-2.01#include <linux/compiler.h>2#include <sys/types.h>3#include <sys/wait.h>4#include <sys/user.h>5#include <syscall.h>6#include <unistd.h>7#include <stdio.h>8#include <stdlib.h>9#include <string.h>10#include <sys/ptrace.h>11#include <asm/ptrace.h>12#include <errno.h>13#include "debug.h"14#include "tests/tests.h"15#include "arch-tests.h"1617static noinline int bp_1(void)18{19pr_debug("in %s\n", __func__);20return 0;21}2223static noinline int bp_2(void)24{25pr_debug("in %s\n", __func__);26return 0;27}2829static int spawn_child(void)30{31int child = fork();3233if (child == 0) {34/*35* The child sets itself for as tracee and36* waits in signal for parent to trace it,37* then it calls bp_1 and quits.38*/39int err = ptrace(PTRACE_TRACEME, 0, NULL, NULL);4041if (err) {42pr_debug("failed to PTRACE_TRACEME\n");43exit(1);44}4546raise(SIGCONT);47bp_1();48exit(0);49}5051return child;52}5354/*55* This tests creates HW breakpoint, tries to56* change it and checks it was properly changed.57*/58static int bp_modify1(void)59{60pid_t child;61int status;62unsigned long rip = 0, dr7 = 1;6364child = spawn_child();6566waitpid(child, &status, 0);67if (WIFEXITED(status)) {68pr_debug("tracee exited prematurely 1\n");69return TEST_FAIL;70}7172/*73* The parent does following steps:74* - creates a new breakpoint (id 0) for bp_2 function75* - changes that breakpoint to bp_1 function76* - waits for the breakpoint to hit and checks77* it has proper rip of bp_1 function78* - detaches the child79*/80if (ptrace(PTRACE_POKEUSER, child,81offsetof(struct user, u_debugreg[0]), bp_2)) {82pr_debug("failed to set breakpoint, 1st time: %s\n",83strerror(errno));84goto out;85}8687if (ptrace(PTRACE_POKEUSER, child,88offsetof(struct user, u_debugreg[0]), bp_1)) {89pr_debug("failed to set breakpoint, 2nd time: %s\n",90strerror(errno));91goto out;92}9394if (ptrace(PTRACE_POKEUSER, child,95offsetof(struct user, u_debugreg[7]), dr7)) {96pr_debug("failed to set dr7: %s\n", strerror(errno));97goto out;98}99100if (ptrace(PTRACE_CONT, child, NULL, NULL)) {101pr_debug("failed to PTRACE_CONT: %s\n", strerror(errno));102goto out;103}104105waitpid(child, &status, 0);106if (WIFEXITED(status)) {107pr_debug("tracee exited prematurely 2\n");108return TEST_FAIL;109}110111rip = ptrace(PTRACE_PEEKUSER, child,112offsetof(struct user_regs_struct, rip), NULL);113if (rip == (unsigned long) -1) {114pr_debug("failed to PTRACE_PEEKUSER: %s\n",115strerror(errno));116goto out;117}118119pr_debug("rip %lx, bp_1 %p\n", rip, bp_1);120121out:122if (ptrace(PTRACE_DETACH, child, NULL, NULL)) {123pr_debug("failed to PTRACE_DETACH: %s", strerror(errno));124return TEST_FAIL;125}126127return rip == (unsigned long) bp_1 ? TEST_OK : TEST_FAIL;128}129130/*131* This tests creates HW breakpoint, tries to132* change it to bogus value and checks the original133* breakpoint is hit.134*/135static int bp_modify2(void)136{137pid_t child;138int status;139unsigned long rip = 0, dr7 = 1;140141child = spawn_child();142143waitpid(child, &status, 0);144if (WIFEXITED(status)) {145pr_debug("tracee exited prematurely 1\n");146return TEST_FAIL;147}148149/*150* The parent does following steps:151* - creates a new breakpoint (id 0) for bp_1 function152* - tries to change that breakpoint to (-1) address153* - waits for the breakpoint to hit and checks154* it has proper rip of bp_1 function155* - detaches the child156*/157if (ptrace(PTRACE_POKEUSER, child,158offsetof(struct user, u_debugreg[0]), bp_1)) {159pr_debug("failed to set breakpoint: %s\n",160strerror(errno));161goto out;162}163164if (ptrace(PTRACE_POKEUSER, child,165offsetof(struct user, u_debugreg[7]), dr7)) {166pr_debug("failed to set dr7: %s\n", strerror(errno));167goto out;168}169170if (!ptrace(PTRACE_POKEUSER, child,171offsetof(struct user, u_debugreg[0]), (unsigned long) (-1))) {172pr_debug("failed, breakpoint set to bogus address\n");173goto out;174}175176if (ptrace(PTRACE_CONT, child, NULL, NULL)) {177pr_debug("failed to PTRACE_CONT: %s\n", strerror(errno));178goto out;179}180181waitpid(child, &status, 0);182if (WIFEXITED(status)) {183pr_debug("tracee exited prematurely 2\n");184return TEST_FAIL;185}186187rip = ptrace(PTRACE_PEEKUSER, child,188offsetof(struct user_regs_struct, rip), NULL);189if (rip == (unsigned long) -1) {190pr_debug("failed to PTRACE_PEEKUSER: %s\n",191strerror(errno));192goto out;193}194195pr_debug("rip %lx, bp_1 %p\n", rip, bp_1);196197out:198if (ptrace(PTRACE_DETACH, child, NULL, NULL)) {199pr_debug("failed to PTRACE_DETACH: %s", strerror(errno));200return TEST_FAIL;201}202203return rip == (unsigned long) bp_1 ? TEST_OK : TEST_FAIL;204}205206int test__bp_modify(struct test_suite *test __maybe_unused,207int subtest __maybe_unused)208{209TEST_ASSERT_VAL("modify test 1 failed\n", !bp_modify1());210TEST_ASSERT_VAL("modify test 2 failed\n", !bp_modify2());211212return 0;213}214215216