1 /*
2 * Copyright (C) 2023 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 <BpfSyscallWrappers.h>
20 #include <android-base/file.h>
21 #include <android-base/logging.h>
22 #include <linux/perf_event.h>
23
24 #include <string>
25
26 #include "bpf/BpfRingbuf.h"
27
28 namespace android {
29 namespace uprobestats {
30 namespace bpf {
31
32 const char *PMU_TYPE_FILE = "/sys/bus/event_source/devices/uprobe/type";
33
bpfPerfEventOpen(const char * filename,int offset,int pid,const char * bpfProgramPath)34 int bpfPerfEventOpen(const char *filename, int offset, int pid,
35 const char *bpfProgramPath) {
36 android::base::unique_fd bpfProgramFd(
37 android::bpf::retrieveProgram(bpfProgramPath));
38 if (bpfProgramFd < 0) {
39 LOG(ERROR) << "retrieveProgram failed";
40 return -1;
41 }
42
43 std::string typeStr;
44 if (!android::base::ReadFileToString(PMU_TYPE_FILE, &typeStr)) {
45 LOG(ERROR) << "Failed to open pmu type file";
46 return -1;
47 }
48 int pmu_type = (int)strtol(typeStr.c_str(), NULL, 10);
49
50 struct perf_event_attr attr = {};
51 attr.sample_period = 1;
52 attr.wakeup_events = 1;
53 attr.config2 = offset;
54 attr.size = sizeof(attr);
55 attr.type = pmu_type;
56 attr.config1 = android::bpf::ptr_to_u64((void *)filename);
57 attr.exclude_kernel = true;
58
59 int perfEventFd = syscall(__NR_perf_event_open, &attr, pid, /*cpu=*/-1,
60 /* group_fd=*/-1, PERF_FLAG_FD_CLOEXEC);
61 if (perfEventFd < 0) {
62 LOG(ERROR) << "syscall(__NR_perf_event_open) failed. "
63 << "perfEventFd: " << perfEventFd << " "
64 << "error: " << strerror(errno);
65 return -1;
66 }
67 if (ioctl(perfEventFd, PERF_EVENT_IOC_SET_BPF, int(bpfProgramFd)) < 0) {
68 LOG(ERROR) << "PERF_EVENT_IOC_SET_BPF failed. " << strerror(errno);
69 return -1;
70 }
71 if (ioctl(perfEventFd, PERF_EVENT_IOC_ENABLE, 0) < 0) {
72 LOG(ERROR) << "PERF_EVENT_IOC_ENABLE failed. " << strerror(errno);
73 return -1;
74 }
75 return 0;
76 }
77
pollRingBuf(const char * map_path,int timeout_ms)78 std::vector<int32_t> pollRingBuf(const char *map_path, int timeout_ms) {
79 auto result = android::bpf::BpfRingbuf<uint64_t>::Create(map_path);
80 std::vector<int32_t> vec;
81 if (!result.value()->wait(timeout_ms)) {
82 return vec;
83 }
84 auto callback = [&](const uint64_t &value) { vec.push_back(value); };
85 result.value()->ConsumeAll(callback);
86 return vec;
87 }
88
consumeRingBuf(const char * map_path)89 std::vector<int32_t> consumeRingBuf(const char *map_path) {
90 auto result = android::bpf::BpfRingbuf<uint64_t>::Create(map_path);
91 std::vector<int32_t> vec;
92 auto callback = [&](const uint64_t &value) { vec.push_back(value); };
93 result.value()->ConsumeAll(callback);
94 return vec;
95 }
96
printRingBuf(const char * map_path)97 void printRingBuf(const char *map_path) {
98 auto result = android::bpf::BpfRingbuf<uint64_t>::Create(map_path);
99 auto callback = [&](const uint64_t &value) {
100 LOG(INFO) << "ringbuf result callback. value: " << value
101 << " map_path: " << map_path;
102 };
103 int num_consumed = result.value()->ConsumeAll(callback).value_or(-1);
104 LOG(INFO) << "ring buffer size: " << num_consumed
105 << " map_path: " << map_path;
106 }
107
108 } // namespace bpf
109 } // namespace uprobestats
110 } // namespace android
111