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