#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; static void *breakpoint_addr = NULL; void signal_handler(int signum, siginfo_t *info, void *context) { ioctl(info->si_fd, PERF_EVENT_IOC_DISABLE, 0); close(info->si_fd); ucontext_t *ucontext = (ucontext_t *)context; uintptr_t pc = (uintptr_t)ucontext->uc_mcontext.pc; if (pc != (uintptr_t)breakpoint_addr) printf("Warning: PC (0x%lx) does not match breakpoint address (0x%lx) signum: %d\n", pc, (uintptr_t)breakpoint_addr, signum); } static int set_hw_breakpoint(void *addr) { struct perf_event_attr pe; int fd; memset(&pe, 0, sizeof(struct perf_event_attr)); pe.type = PERF_TYPE_BREAKPOINT; pe.size = sizeof(struct perf_event_attr); pe.config = 0; pe.bp_type = HW_BREAKPOINT_X; pe.bp_addr = (uintptr_t)addr; pe.bp_len = 4; pe.sample_period = 1; pe.disabled = 1; pe.exclude_kernel = 1; // perf_event_open syscall fd = syscall(__NR_perf_event_open, &pe, syscall(SYS_gettid), -1, -1, 0); if (fd < 0) { perror("perf_event_open"); return -1; } struct f_owner_ex owner; owner.type = F_OWNER_TID; owner.pid = syscall(SYS_gettid); if (fcntl(fd, F_SETOWN_EX, &owner) == -1) { perror("F_SETSIG"); exit(EXIT_FAILURE); } if (fcntl(fd, F_SETSIG, SIGRTMIN+4) == -1) { perror("F_SETSIG"); close(fd); exit(EXIT_FAILURE); } int flags = fcntl(fd, F_GETFL, 0); if (flags == -1) { perror("F_GETFL"); close(fd); exit(EXIT_FAILURE); } if (fcntl(fd, F_SETFL, flags | O_ASYNC) == -1) { perror("F_SETFL"); close(fd); exit(EXIT_FAILURE); } // enable breakpoint if (ioctl(fd, PERF_EVENT_IOC_RESET, 0) < 0) { perror("PERF_EVENT_IOC_RESET"); close(fd); return -1; } if (ioctl(fd, PERF_EVENT_IOC_ENABLE, 0) < 0) { perror("PERF_EVENT_IOC_ENABLE"); close(fd); return -1; } return fd; } // function where breakpoints get set void target_function() { int i = 0; i++; } int main() { int breakpoint_fd; // set breakpoint breakpoint_addr = (void *)target_function; printf("Breakpoint address: %p, target_function address: %p\n", breakpoint_addr, target_function); // set sig handler struct sigaction sa; memset(&sa, 0, sizeof(struct sigaction)); sa.sa_sigaction = signal_handler; sa.sa_flags = SA_SIGINFO | SA_RESTART; sigfillset(&sa.sa_mask); if (sigaction(SIGRTMIN+4, &sa, NULL) == -1) { perror("sigaction"); close(breakpoint_fd); return EXIT_FAILURE; } // test breakpoint printf("Calling target function...\n"); while (1) { breakpoint_fd = set_hw_breakpoint(breakpoint_addr); if (breakpoint_fd < 0) { fprintf(stderr, "Failed to set hardware breakpoint\n"); return 1; } target_function(); // disable breakpoint ioctl(breakpoint_fd, PERF_EVENT_IOC_DISABLE, 0); close(breakpoint_fd); } return 0; }