1 /*
2 * Copyright (C) 2025 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "uprobestats"
18
19 #include "bpf.h"
20
21 #include <BpfSyscallWrappers.h>
22 #include <android-base/file.h>
23 #include <android-base/logging.h>
24 #include <linux/perf_event.h>
25
26 #include <string>
27
28 #include "bpf/BpfRingbuf.h"
29
pollRingBuf(const char * mapPath,int timeoutMs,size_t valueSize,void (* callback)(const void *,void *),void * cookie)30 int pollRingBuf(const char *mapPath, int timeoutMs, size_t valueSize,
31 void (*callback)(const void *, void *), void *cookie) {
32 auto result = android::bpf::BpfRingbufSized::Create(mapPath, valueSize);
33 if (!result.ok()) {
34 return -1;
35 }
36 if (!result.value()->wait(timeoutMs)) {
37 return 0;
38 }
39 auto count = result.value()->ConsumeAll(
40 [&](const void *value) { callback(value, cookie); });
41 if (!count.ok()) {
42 LOG(ERROR) << "Failed to consume events from ring buffer. Error: "
43 << count.error().message();
44 return -2;
45 }
46 return count.value();
47 }
48
49 const char *PMU_TYPE_FILE = "/sys/bus/event_source/devices/uprobe/type";
50
bpfPerfEventOpen(const char * filename,int offset,int pid,const char * bpfProgramPath)51 int bpfPerfEventOpen(const char *filename, int offset, int pid,
52 const char *bpfProgramPath) {
53 android::base::unique_fd bpfProgramFd(
54 android::bpf::retrieveProgram(bpfProgramPath));
55 if (bpfProgramFd < 0) {
56 LOG(ERROR) << "retrieveProgram failed";
57 return -1;
58 }
59 std::string typeStr;
60 if (!android::base::ReadFileToString(PMU_TYPE_FILE, &typeStr)) {
61 LOG(ERROR) << "Failed to open pmu type file";
62 return -1;
63 }
64 int pmu_type = (int)strtol(typeStr.c_str(), NULL, 10);
65 struct perf_event_attr attr = {};
66 attr.sample_period = 1;
67 attr.wakeup_events = 1;
68 attr.config2 = offset;
69 attr.size = sizeof(attr);
70 attr.type = pmu_type;
71 attr.config1 = android::bpf::ptr_to_u64((void *)filename);
72 attr.exclude_kernel = true;
73 int perfEventFd = syscall(__NR_perf_event_open, &attr, pid, /*cpu=*/-1,
74 /* group_fd=*/-1, PERF_FLAG_FD_CLOEXEC);
75 if (perfEventFd < 0) {
76 LOG(ERROR) << "syscall(__NR_perf_event_open) failed. "
77 << "perfEventFd: " << perfEventFd << " "
78 << "error: " << strerror(errno);
79 return -1;
80 }
81 if (ioctl(perfEventFd, PERF_EVENT_IOC_SET_BPF, int(bpfProgramFd)) < 0) {
82 LOG(ERROR) << "PERF_EVENT_IOC_SET_BPF failed. " << strerror(errno);
83 return -1;
84 }
85 if (ioctl(perfEventFd, PERF_EVENT_IOC_ENABLE, 0) < 0) {
86 LOG(ERROR) << "PERF_EVENT_IOC_ENABLE failed. " << strerror(errno);
87 return -1;
88 }
89 return 0;
90 }
91