| 1 | #include "KittyPerfEvent.hpp" |
| 2 | |
| 3 | bool KittyPerfWatch::add(pid_t tid, uintptr_t addr, KT_WATCH_TYPE bp_type, KT_WATCH_LEN bp_len) |
| 4 | { |
| 5 | #if defined(__arm__) || defined(__aarch64__) |
| 6 | addr &= ~3UL; |
| 7 | #endif |
| 8 | |
| 9 | perf_event_attr pe{}; |
| 10 | pe.type = PERF_TYPE_BREAKPOINT; |
| 11 | pe.config = 0; |
| 12 | pe.size = sizeof(pe); |
| 13 | |
| 14 | pe.bp_addr = addr; |
| 15 | pe.bp_len = bp_len; |
| 16 | pe.bp_type = bp_type; |
| 17 | |
| 18 | pe.sample_period = 1; |
| 19 | pe.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR; |
| 20 | |
| 21 | pe.exclude_kernel = 1; |
| 22 | pe.exclude_hv = 1; |
| 23 | pe.disabled = 1; |
| 24 | pe.wakeup_events = 1; |
| 25 | pe.precise_ip = 2; |
| 26 | |
| 27 | int fd = perf_event_open(&pe, tid, -1, -1, 0); |
| 28 | if (fd < 0) |
| 29 | return false; |
| 30 | |
| 31 | size_t page_sz = sysconf(_SC_PAGESIZE); |
| 32 | size_t mmap_sz = (1 + KT_WATCH_PAGES) * page_sz; |
| 33 | |
| 34 | void *base = mmap(nullptr, mmap_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); |
| 35 | if (!base || base == MAP_FAILED) |
| 36 | { |
| 37 | ioctl(fd, PERF_EVENT_IOC_RESET, 0); |
| 38 | ioctl(fd, PERF_EVENT_IOC_DISABLE, 0); |
| 39 | close(fd); |
| 40 | return false; |
| 41 | } |
| 42 | |
| 43 | auto *meta = reinterpret_cast<perf_event_mmap_page *>(base); |
| 44 | if (meta->data_size == 0) |
| 45 | { |
| 46 | ioctl(fd, PERF_EVENT_IOC_RESET, 0); |
| 47 | ioctl(fd, PERF_EVENT_IOC_DISABLE, 0); |
| 48 | munmap(base, mmap_sz); |
| 49 | close(fd); |
| 50 | return false; |
| 51 | } |
| 52 | |
| 53 | WatchInfo w{}; |
| 54 | w.fd = fd; |
| 55 | w.mmap = base; |
| 56 | w.mmap_sz = mmap_sz; |
| 57 | |
| 58 | _watches.push_back(w); |
| 59 | |
| 60 | return true; |
nothing calls this directly
no outgoing calls
no test coverage detected