1*387f9dfdSAndroid Build Coastguard Worker /*
2*387f9dfdSAndroid Build Coastguard Worker * Copyright (c) 2016 Facebook, Inc.
3*387f9dfdSAndroid Build Coastguard Worker *
4*387f9dfdSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*387f9dfdSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*387f9dfdSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*387f9dfdSAndroid Build Coastguard Worker *
8*387f9dfdSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*387f9dfdSAndroid Build Coastguard Worker *
10*387f9dfdSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*387f9dfdSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*387f9dfdSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*387f9dfdSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*387f9dfdSAndroid Build Coastguard Worker * limitations under the License.
15*387f9dfdSAndroid Build Coastguard Worker */
16*387f9dfdSAndroid Build Coastguard Worker
17*387f9dfdSAndroid Build Coastguard Worker #include <fcntl.h>
18*387f9dfdSAndroid Build Coastguard Worker #include <linux/elf.h>
19*387f9dfdSAndroid Build Coastguard Worker #include <linux/perf_event.h>
20*387f9dfdSAndroid Build Coastguard Worker #include <sys/epoll.h>
21*387f9dfdSAndroid Build Coastguard Worker #include <unistd.h>
22*387f9dfdSAndroid Build Coastguard Worker #include <cerrno>
23*387f9dfdSAndroid Build Coastguard Worker #include <cinttypes>
24*387f9dfdSAndroid Build Coastguard Worker #include <cstdint>
25*387f9dfdSAndroid Build Coastguard Worker #include <cstring>
26*387f9dfdSAndroid Build Coastguard Worker #include <iostream>
27*387f9dfdSAndroid Build Coastguard Worker #include <memory>
28*387f9dfdSAndroid Build Coastguard Worker
29*387f9dfdSAndroid Build Coastguard Worker #include "BPFTable.h"
30*387f9dfdSAndroid Build Coastguard Worker
31*387f9dfdSAndroid Build Coastguard Worker #include "bcc_exception.h"
32*387f9dfdSAndroid Build Coastguard Worker #include "bcc_syms.h"
33*387f9dfdSAndroid Build Coastguard Worker #include "common.h"
34*387f9dfdSAndroid Build Coastguard Worker #include "file_desc.h"
35*387f9dfdSAndroid Build Coastguard Worker #include "libbpf.h"
36*387f9dfdSAndroid Build Coastguard Worker #include "perf_reader.h"
37*387f9dfdSAndroid Build Coastguard Worker
38*387f9dfdSAndroid Build Coastguard Worker namespace ebpf {
39*387f9dfdSAndroid Build Coastguard Worker
BPFTable(const TableDesc & desc)40*387f9dfdSAndroid Build Coastguard Worker BPFTable::BPFTable(const TableDesc& desc) : BPFTableBase<void, void>(desc) {}
41*387f9dfdSAndroid Build Coastguard Worker
get_value(const std::string & key_str,std::string & value_str)42*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFTable::get_value(const std::string& key_str,
43*387f9dfdSAndroid Build Coastguard Worker std::string& value_str) {
44*387f9dfdSAndroid Build Coastguard Worker char key[desc.key_size];
45*387f9dfdSAndroid Build Coastguard Worker char value[desc.leaf_size];
46*387f9dfdSAndroid Build Coastguard Worker
47*387f9dfdSAndroid Build Coastguard Worker StatusTuple r(0);
48*387f9dfdSAndroid Build Coastguard Worker
49*387f9dfdSAndroid Build Coastguard Worker r = string_to_key(key_str, key);
50*387f9dfdSAndroid Build Coastguard Worker if (!r.ok())
51*387f9dfdSAndroid Build Coastguard Worker return r;
52*387f9dfdSAndroid Build Coastguard Worker
53*387f9dfdSAndroid Build Coastguard Worker if (!lookup(key, value))
54*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "error getting value");
55*387f9dfdSAndroid Build Coastguard Worker
56*387f9dfdSAndroid Build Coastguard Worker return leaf_to_string(value, value_str);
57*387f9dfdSAndroid Build Coastguard Worker }
58*387f9dfdSAndroid Build Coastguard Worker
get_value(const std::string & key_str,std::vector<std::string> & value_str)59*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFTable::get_value(const std::string& key_str,
60*387f9dfdSAndroid Build Coastguard Worker std::vector<std::string>& value_str) {
61*387f9dfdSAndroid Build Coastguard Worker size_t ncpus = get_possible_cpus().size();
62*387f9dfdSAndroid Build Coastguard Worker char key[desc.key_size];
63*387f9dfdSAndroid Build Coastguard Worker char value[desc.leaf_size * ncpus];
64*387f9dfdSAndroid Build Coastguard Worker
65*387f9dfdSAndroid Build Coastguard Worker StatusTuple r(0);
66*387f9dfdSAndroid Build Coastguard Worker
67*387f9dfdSAndroid Build Coastguard Worker r = string_to_key(key_str, key);
68*387f9dfdSAndroid Build Coastguard Worker if (!r.ok())
69*387f9dfdSAndroid Build Coastguard Worker return r;
70*387f9dfdSAndroid Build Coastguard Worker
71*387f9dfdSAndroid Build Coastguard Worker if (!lookup(key, value))
72*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "error getting value");
73*387f9dfdSAndroid Build Coastguard Worker
74*387f9dfdSAndroid Build Coastguard Worker value_str.resize(ncpus);
75*387f9dfdSAndroid Build Coastguard Worker
76*387f9dfdSAndroid Build Coastguard Worker for (size_t i = 0; i < ncpus; i++) {
77*387f9dfdSAndroid Build Coastguard Worker r = leaf_to_string(value + i * desc.leaf_size, value_str.at(i));
78*387f9dfdSAndroid Build Coastguard Worker if (!r.ok())
79*387f9dfdSAndroid Build Coastguard Worker return r;
80*387f9dfdSAndroid Build Coastguard Worker }
81*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
82*387f9dfdSAndroid Build Coastguard Worker }
83*387f9dfdSAndroid Build Coastguard Worker
update_value(const std::string & key_str,const std::string & value_str)84*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFTable::update_value(const std::string& key_str,
85*387f9dfdSAndroid Build Coastguard Worker const std::string& value_str) {
86*387f9dfdSAndroid Build Coastguard Worker char key[desc.key_size];
87*387f9dfdSAndroid Build Coastguard Worker char value[desc.leaf_size];
88*387f9dfdSAndroid Build Coastguard Worker
89*387f9dfdSAndroid Build Coastguard Worker StatusTuple r(0);
90*387f9dfdSAndroid Build Coastguard Worker
91*387f9dfdSAndroid Build Coastguard Worker r = string_to_key(key_str, key);
92*387f9dfdSAndroid Build Coastguard Worker if (!r.ok())
93*387f9dfdSAndroid Build Coastguard Worker return r;
94*387f9dfdSAndroid Build Coastguard Worker
95*387f9dfdSAndroid Build Coastguard Worker r = string_to_leaf(value_str, value);
96*387f9dfdSAndroid Build Coastguard Worker if (!r.ok())
97*387f9dfdSAndroid Build Coastguard Worker return r;
98*387f9dfdSAndroid Build Coastguard Worker
99*387f9dfdSAndroid Build Coastguard Worker if (!update(key, value))
100*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "error updating element");
101*387f9dfdSAndroid Build Coastguard Worker
102*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
103*387f9dfdSAndroid Build Coastguard Worker }
104*387f9dfdSAndroid Build Coastguard Worker
update_value(const std::string & key_str,const std::vector<std::string> & value_str)105*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFTable::update_value(const std::string& key_str,
106*387f9dfdSAndroid Build Coastguard Worker const std::vector<std::string>& value_str) {
107*387f9dfdSAndroid Build Coastguard Worker size_t ncpus = get_possible_cpus().size();
108*387f9dfdSAndroid Build Coastguard Worker char key[desc.key_size];
109*387f9dfdSAndroid Build Coastguard Worker char value[desc.leaf_size * ncpus];
110*387f9dfdSAndroid Build Coastguard Worker
111*387f9dfdSAndroid Build Coastguard Worker StatusTuple r(0);
112*387f9dfdSAndroid Build Coastguard Worker
113*387f9dfdSAndroid Build Coastguard Worker r = string_to_key(key_str, key);
114*387f9dfdSAndroid Build Coastguard Worker if (!r.ok())
115*387f9dfdSAndroid Build Coastguard Worker return r;
116*387f9dfdSAndroid Build Coastguard Worker
117*387f9dfdSAndroid Build Coastguard Worker if (value_str.size() != ncpus)
118*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "bad value size");
119*387f9dfdSAndroid Build Coastguard Worker
120*387f9dfdSAndroid Build Coastguard Worker for (size_t i = 0; i < ncpus; i++) {
121*387f9dfdSAndroid Build Coastguard Worker r = string_to_leaf(value_str.at(i), value + i * desc.leaf_size);
122*387f9dfdSAndroid Build Coastguard Worker if (!r.ok())
123*387f9dfdSAndroid Build Coastguard Worker return r;
124*387f9dfdSAndroid Build Coastguard Worker }
125*387f9dfdSAndroid Build Coastguard Worker
126*387f9dfdSAndroid Build Coastguard Worker if (!update(key, value))
127*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "error updating element");
128*387f9dfdSAndroid Build Coastguard Worker
129*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
130*387f9dfdSAndroid Build Coastguard Worker }
131*387f9dfdSAndroid Build Coastguard Worker
remove_value(const std::string & key_str)132*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFTable::remove_value(const std::string& key_str) {
133*387f9dfdSAndroid Build Coastguard Worker char key[desc.key_size];
134*387f9dfdSAndroid Build Coastguard Worker
135*387f9dfdSAndroid Build Coastguard Worker StatusTuple r(0);
136*387f9dfdSAndroid Build Coastguard Worker
137*387f9dfdSAndroid Build Coastguard Worker r = string_to_key(key_str, key);
138*387f9dfdSAndroid Build Coastguard Worker if (!r.ok())
139*387f9dfdSAndroid Build Coastguard Worker return r;
140*387f9dfdSAndroid Build Coastguard Worker
141*387f9dfdSAndroid Build Coastguard Worker if (!remove(key))
142*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "error removing element");
143*387f9dfdSAndroid Build Coastguard Worker
144*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
145*387f9dfdSAndroid Build Coastguard Worker }
146*387f9dfdSAndroid Build Coastguard Worker
clear_table_non_atomic()147*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFTable::clear_table_non_atomic() {
148*387f9dfdSAndroid Build Coastguard Worker if (desc.type == BPF_MAP_TYPE_HASH ||
149*387f9dfdSAndroid Build Coastguard Worker desc.type == BPF_MAP_TYPE_LRU_HASH ||
150*387f9dfdSAndroid Build Coastguard Worker desc.type == BPF_MAP_TYPE_PERCPU_HASH ||
151*387f9dfdSAndroid Build Coastguard Worker desc.type == BPF_MAP_TYPE_HASH_OF_MAPS) {
152*387f9dfdSAndroid Build Coastguard Worker // For hash maps, use the first() interface (which uses get_next_key) to
153*387f9dfdSAndroid Build Coastguard Worker // iterate through the map and clear elements
154*387f9dfdSAndroid Build Coastguard Worker auto key = std::unique_ptr<void, decltype(::free)*>(::malloc(desc.key_size),
155*387f9dfdSAndroid Build Coastguard Worker ::free);
156*387f9dfdSAndroid Build Coastguard Worker
157*387f9dfdSAndroid Build Coastguard Worker while (this->first(key.get()))
158*387f9dfdSAndroid Build Coastguard Worker if (!this->remove(key.get())) {
159*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1,
160*387f9dfdSAndroid Build Coastguard Worker "Failed to delete element when clearing table %s",
161*387f9dfdSAndroid Build Coastguard Worker desc.name.c_str());
162*387f9dfdSAndroid Build Coastguard Worker }
163*387f9dfdSAndroid Build Coastguard Worker } else if (desc.type == BPF_MAP_TYPE_ARRAY ||
164*387f9dfdSAndroid Build Coastguard Worker desc.type == BPF_MAP_TYPE_PERCPU_ARRAY) {
165*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Array map %s do not support clearing elements",
166*387f9dfdSAndroid Build Coastguard Worker desc.name.c_str());
167*387f9dfdSAndroid Build Coastguard Worker } else if (desc.type == BPF_MAP_TYPE_PROG_ARRAY ||
168*387f9dfdSAndroid Build Coastguard Worker desc.type == BPF_MAP_TYPE_PERF_EVENT_ARRAY ||
169*387f9dfdSAndroid Build Coastguard Worker desc.type == BPF_MAP_TYPE_STACK_TRACE ||
170*387f9dfdSAndroid Build Coastguard Worker desc.type == BPF_MAP_TYPE_ARRAY_OF_MAPS) {
171*387f9dfdSAndroid Build Coastguard Worker // For Stack-trace and FD arrays, just iterate over all indices
172*387f9dfdSAndroid Build Coastguard Worker for (size_t i = 0; i < desc.max_entries; i++) {
173*387f9dfdSAndroid Build Coastguard Worker this->remove(&i);
174*387f9dfdSAndroid Build Coastguard Worker }
175*387f9dfdSAndroid Build Coastguard Worker } else {
176*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Clearing for map type of %s not supported yet",
177*387f9dfdSAndroid Build Coastguard Worker desc.name.c_str());
178*387f9dfdSAndroid Build Coastguard Worker }
179*387f9dfdSAndroid Build Coastguard Worker
180*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
181*387f9dfdSAndroid Build Coastguard Worker }
182*387f9dfdSAndroid Build Coastguard Worker
get_table_offline(std::vector<std::pair<std::string,std::string>> & res)183*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFTable::get_table_offline(
184*387f9dfdSAndroid Build Coastguard Worker std::vector<std::pair<std::string, std::string>> &res) {
185*387f9dfdSAndroid Build Coastguard Worker StatusTuple r(0);
186*387f9dfdSAndroid Build Coastguard Worker int err;
187*387f9dfdSAndroid Build Coastguard Worker
188*387f9dfdSAndroid Build Coastguard Worker auto key = std::unique_ptr<void, decltype(::free)*>(::malloc(desc.key_size),
189*387f9dfdSAndroid Build Coastguard Worker ::free);
190*387f9dfdSAndroid Build Coastguard Worker auto value = std::unique_ptr<void, decltype(::free)*>(::malloc(desc.leaf_size),
191*387f9dfdSAndroid Build Coastguard Worker ::free);
192*387f9dfdSAndroid Build Coastguard Worker std::string key_str;
193*387f9dfdSAndroid Build Coastguard Worker std::string value_str;
194*387f9dfdSAndroid Build Coastguard Worker
195*387f9dfdSAndroid Build Coastguard Worker if (desc.type == BPF_MAP_TYPE_ARRAY ||
196*387f9dfdSAndroid Build Coastguard Worker desc.type == BPF_MAP_TYPE_PROG_ARRAY ||
197*387f9dfdSAndroid Build Coastguard Worker desc.type == BPF_MAP_TYPE_PERF_EVENT_ARRAY ||
198*387f9dfdSAndroid Build Coastguard Worker desc.type == BPF_MAP_TYPE_PERCPU_ARRAY ||
199*387f9dfdSAndroid Build Coastguard Worker desc.type == BPF_MAP_TYPE_CGROUP_ARRAY ||
200*387f9dfdSAndroid Build Coastguard Worker desc.type == BPF_MAP_TYPE_ARRAY_OF_MAPS ||
201*387f9dfdSAndroid Build Coastguard Worker desc.type == BPF_MAP_TYPE_DEVMAP ||
202*387f9dfdSAndroid Build Coastguard Worker desc.type == BPF_MAP_TYPE_CPUMAP ||
203*387f9dfdSAndroid Build Coastguard Worker desc.type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) {
204*387f9dfdSAndroid Build Coastguard Worker // For arrays, just iterate over all indices
205*387f9dfdSAndroid Build Coastguard Worker for (size_t i = 0; i < desc.max_entries; i++) {
206*387f9dfdSAndroid Build Coastguard Worker err = bpf_lookup_elem(desc.fd, &i, value.get());
207*387f9dfdSAndroid Build Coastguard Worker if (err < 0 && errno == ENOENT) {
208*387f9dfdSAndroid Build Coastguard Worker // Element is not present, skip it
209*387f9dfdSAndroid Build Coastguard Worker continue;
210*387f9dfdSAndroid Build Coastguard Worker } else if (err < 0) {
211*387f9dfdSAndroid Build Coastguard Worker // Other error, abort
212*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Error looking up value: %s", std::strerror(errno));
213*387f9dfdSAndroid Build Coastguard Worker }
214*387f9dfdSAndroid Build Coastguard Worker
215*387f9dfdSAndroid Build Coastguard Worker r = key_to_string(&i, key_str);
216*387f9dfdSAndroid Build Coastguard Worker if (!r.ok())
217*387f9dfdSAndroid Build Coastguard Worker return r;
218*387f9dfdSAndroid Build Coastguard Worker
219*387f9dfdSAndroid Build Coastguard Worker r = leaf_to_string(value.get(), value_str);
220*387f9dfdSAndroid Build Coastguard Worker if (!r.ok())
221*387f9dfdSAndroid Build Coastguard Worker return r;
222*387f9dfdSAndroid Build Coastguard Worker res.emplace_back(key_str, value_str);
223*387f9dfdSAndroid Build Coastguard Worker }
224*387f9dfdSAndroid Build Coastguard Worker } else {
225*387f9dfdSAndroid Build Coastguard Worker res.clear();
226*387f9dfdSAndroid Build Coastguard Worker // For other maps, try to use the first() and next() interfaces
227*387f9dfdSAndroid Build Coastguard Worker if (!this->first(key.get()))
228*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
229*387f9dfdSAndroid Build Coastguard Worker
230*387f9dfdSAndroid Build Coastguard Worker while (true) {
231*387f9dfdSAndroid Build Coastguard Worker if (!this->lookup(key.get(), value.get()))
232*387f9dfdSAndroid Build Coastguard Worker break;
233*387f9dfdSAndroid Build Coastguard Worker r = key_to_string(key.get(), key_str);
234*387f9dfdSAndroid Build Coastguard Worker if (!r.ok())
235*387f9dfdSAndroid Build Coastguard Worker return r;
236*387f9dfdSAndroid Build Coastguard Worker
237*387f9dfdSAndroid Build Coastguard Worker r = leaf_to_string(value.get(), value_str);
238*387f9dfdSAndroid Build Coastguard Worker if (!r.ok())
239*387f9dfdSAndroid Build Coastguard Worker return r;
240*387f9dfdSAndroid Build Coastguard Worker res.emplace_back(key_str, value_str);
241*387f9dfdSAndroid Build Coastguard Worker if (!this->next(key.get(), key.get()))
242*387f9dfdSAndroid Build Coastguard Worker break;
243*387f9dfdSAndroid Build Coastguard Worker }
244*387f9dfdSAndroid Build Coastguard Worker }
245*387f9dfdSAndroid Build Coastguard Worker
246*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
247*387f9dfdSAndroid Build Coastguard Worker }
248*387f9dfdSAndroid Build Coastguard Worker
get_possible_cpu_count()249*387f9dfdSAndroid Build Coastguard Worker size_t BPFTable::get_possible_cpu_count() { return get_possible_cpus().size(); }
250*387f9dfdSAndroid Build Coastguard Worker
BPFStackTable(const TableDesc & desc,bool use_debug_file,bool check_debug_file_crc)251*387f9dfdSAndroid Build Coastguard Worker BPFStackTable::BPFStackTable(const TableDesc& desc, bool use_debug_file,
252*387f9dfdSAndroid Build Coastguard Worker bool check_debug_file_crc)
253*387f9dfdSAndroid Build Coastguard Worker : BPFTableBase<int, stacktrace_t>(desc) {
254*387f9dfdSAndroid Build Coastguard Worker if (desc.type != BPF_MAP_TYPE_STACK_TRACE)
255*387f9dfdSAndroid Build Coastguard Worker throw std::invalid_argument("Table '" + desc.name +
256*387f9dfdSAndroid Build Coastguard Worker "' is not a stack table");
257*387f9dfdSAndroid Build Coastguard Worker
258*387f9dfdSAndroid Build Coastguard Worker uint32_t use_symbol_type = (1 << STT_FUNC) | (1 << STT_GNU_IFUNC);
259*387f9dfdSAndroid Build Coastguard Worker symbol_option_ = {.use_debug_file = use_debug_file,
260*387f9dfdSAndroid Build Coastguard Worker .check_debug_file_crc = check_debug_file_crc,
261*387f9dfdSAndroid Build Coastguard Worker .lazy_symbolize = 1,
262*387f9dfdSAndroid Build Coastguard Worker .use_symbol_type = use_symbol_type};
263*387f9dfdSAndroid Build Coastguard Worker }
264*387f9dfdSAndroid Build Coastguard Worker
BPFStackTable(BPFStackTable && that)265*387f9dfdSAndroid Build Coastguard Worker BPFStackTable::BPFStackTable(BPFStackTable&& that)
266*387f9dfdSAndroid Build Coastguard Worker : BPFTableBase<int, stacktrace_t>(that.desc),
267*387f9dfdSAndroid Build Coastguard Worker symbol_option_(std::move(that.symbol_option_)),
268*387f9dfdSAndroid Build Coastguard Worker pid_sym_(std::move(that.pid_sym_)) {
269*387f9dfdSAndroid Build Coastguard Worker that.pid_sym_.clear();
270*387f9dfdSAndroid Build Coastguard Worker }
271*387f9dfdSAndroid Build Coastguard Worker
~BPFStackTable()272*387f9dfdSAndroid Build Coastguard Worker BPFStackTable::~BPFStackTable() {
273*387f9dfdSAndroid Build Coastguard Worker for (auto it : pid_sym_)
274*387f9dfdSAndroid Build Coastguard Worker bcc_free_symcache(it.second, it.first);
275*387f9dfdSAndroid Build Coastguard Worker }
276*387f9dfdSAndroid Build Coastguard Worker
free_symcache(int pid)277*387f9dfdSAndroid Build Coastguard Worker void BPFStackTable::free_symcache(int pid) {
278*387f9dfdSAndroid Build Coastguard Worker auto iter = pid_sym_.find(pid);
279*387f9dfdSAndroid Build Coastguard Worker if (iter != pid_sym_.end()) {
280*387f9dfdSAndroid Build Coastguard Worker bcc_free_symcache(iter->second, iter->first);
281*387f9dfdSAndroid Build Coastguard Worker pid_sym_.erase(iter);
282*387f9dfdSAndroid Build Coastguard Worker }
283*387f9dfdSAndroid Build Coastguard Worker }
284*387f9dfdSAndroid Build Coastguard Worker
clear_table_non_atomic()285*387f9dfdSAndroid Build Coastguard Worker void BPFStackTable::clear_table_non_atomic() {
286*387f9dfdSAndroid Build Coastguard Worker for (int i = 0; size_t(i) < capacity(); i++) {
287*387f9dfdSAndroid Build Coastguard Worker remove(&i);
288*387f9dfdSAndroid Build Coastguard Worker }
289*387f9dfdSAndroid Build Coastguard Worker }
290*387f9dfdSAndroid Build Coastguard Worker
get_stack_addr(int stack_id)291*387f9dfdSAndroid Build Coastguard Worker std::vector<uintptr_t> BPFStackTable::get_stack_addr(int stack_id) {
292*387f9dfdSAndroid Build Coastguard Worker std::vector<uintptr_t> res;
293*387f9dfdSAndroid Build Coastguard Worker stacktrace_t stack;
294*387f9dfdSAndroid Build Coastguard Worker if (stack_id < 0)
295*387f9dfdSAndroid Build Coastguard Worker return res;
296*387f9dfdSAndroid Build Coastguard Worker if (!lookup(&stack_id, &stack))
297*387f9dfdSAndroid Build Coastguard Worker return res;
298*387f9dfdSAndroid Build Coastguard Worker for (int i = 0; (i < BPF_MAX_STACK_DEPTH) && (stack.ip[i] != 0); i++)
299*387f9dfdSAndroid Build Coastguard Worker res.push_back(stack.ip[i]);
300*387f9dfdSAndroid Build Coastguard Worker return res;
301*387f9dfdSAndroid Build Coastguard Worker }
302*387f9dfdSAndroid Build Coastguard Worker
get_stack_symbol(int stack_id,int pid)303*387f9dfdSAndroid Build Coastguard Worker std::vector<std::string> BPFStackTable::get_stack_symbol(int stack_id,
304*387f9dfdSAndroid Build Coastguard Worker int pid) {
305*387f9dfdSAndroid Build Coastguard Worker auto addresses = get_stack_addr(stack_id);
306*387f9dfdSAndroid Build Coastguard Worker std::vector<std::string> res;
307*387f9dfdSAndroid Build Coastguard Worker if (addresses.empty())
308*387f9dfdSAndroid Build Coastguard Worker return res;
309*387f9dfdSAndroid Build Coastguard Worker res.reserve(addresses.size());
310*387f9dfdSAndroid Build Coastguard Worker
311*387f9dfdSAndroid Build Coastguard Worker if (pid < 0)
312*387f9dfdSAndroid Build Coastguard Worker pid = -1;
313*387f9dfdSAndroid Build Coastguard Worker if (pid_sym_.find(pid) == pid_sym_.end())
314*387f9dfdSAndroid Build Coastguard Worker pid_sym_[pid] = bcc_symcache_new(pid, &symbol_option_);
315*387f9dfdSAndroid Build Coastguard Worker void* cache = pid_sym_[pid];
316*387f9dfdSAndroid Build Coastguard Worker
317*387f9dfdSAndroid Build Coastguard Worker bcc_symbol symbol;
318*387f9dfdSAndroid Build Coastguard Worker for (auto addr : addresses)
319*387f9dfdSAndroid Build Coastguard Worker if (bcc_symcache_resolve(cache, addr, &symbol) != 0)
320*387f9dfdSAndroid Build Coastguard Worker res.emplace_back("[UNKNOWN]");
321*387f9dfdSAndroid Build Coastguard Worker else {
322*387f9dfdSAndroid Build Coastguard Worker res.push_back(symbol.demangle_name);
323*387f9dfdSAndroid Build Coastguard Worker bcc_symbol_free_demangle_name(&symbol);
324*387f9dfdSAndroid Build Coastguard Worker }
325*387f9dfdSAndroid Build Coastguard Worker
326*387f9dfdSAndroid Build Coastguard Worker return res;
327*387f9dfdSAndroid Build Coastguard Worker }
328*387f9dfdSAndroid Build Coastguard Worker
BPFStackBuildIdTable(const TableDesc & desc,bool use_debug_file,bool check_debug_file_crc,void * bsymcache)329*387f9dfdSAndroid Build Coastguard Worker BPFStackBuildIdTable::BPFStackBuildIdTable(const TableDesc& desc, bool use_debug_file,
330*387f9dfdSAndroid Build Coastguard Worker bool check_debug_file_crc,
331*387f9dfdSAndroid Build Coastguard Worker void *bsymcache)
332*387f9dfdSAndroid Build Coastguard Worker : BPFTableBase<int, stacktrace_buildid_t>(desc),
333*387f9dfdSAndroid Build Coastguard Worker bsymcache_(bsymcache) {
334*387f9dfdSAndroid Build Coastguard Worker if (desc.type != BPF_MAP_TYPE_STACK_TRACE)
335*387f9dfdSAndroid Build Coastguard Worker throw std::invalid_argument("Table '" + desc.name +
336*387f9dfdSAndroid Build Coastguard Worker "' is not a stack table");
337*387f9dfdSAndroid Build Coastguard Worker
338*387f9dfdSAndroid Build Coastguard Worker symbol_option_ = {.use_debug_file = use_debug_file,
339*387f9dfdSAndroid Build Coastguard Worker .check_debug_file_crc = check_debug_file_crc,
340*387f9dfdSAndroid Build Coastguard Worker .lazy_symbolize = 1,
341*387f9dfdSAndroid Build Coastguard Worker .use_symbol_type = (1 << STT_FUNC) | (1 << STT_GNU_IFUNC)};
342*387f9dfdSAndroid Build Coastguard Worker }
343*387f9dfdSAndroid Build Coastguard Worker
clear_table_non_atomic()344*387f9dfdSAndroid Build Coastguard Worker void BPFStackBuildIdTable::clear_table_non_atomic() {
345*387f9dfdSAndroid Build Coastguard Worker for (int i = 0; size_t(i) < capacity(); i++) {
346*387f9dfdSAndroid Build Coastguard Worker remove(&i);
347*387f9dfdSAndroid Build Coastguard Worker }
348*387f9dfdSAndroid Build Coastguard Worker }
349*387f9dfdSAndroid Build Coastguard Worker
get_stack_addr(int stack_id)350*387f9dfdSAndroid Build Coastguard Worker std::vector<bpf_stack_build_id> BPFStackBuildIdTable::get_stack_addr(int stack_id) {
351*387f9dfdSAndroid Build Coastguard Worker std::vector<bpf_stack_build_id> res;
352*387f9dfdSAndroid Build Coastguard Worker struct stacktrace_buildid_t stack;
353*387f9dfdSAndroid Build Coastguard Worker if (stack_id < 0)
354*387f9dfdSAndroid Build Coastguard Worker return res;
355*387f9dfdSAndroid Build Coastguard Worker if (!lookup(&stack_id, &stack))
356*387f9dfdSAndroid Build Coastguard Worker return res;
357*387f9dfdSAndroid Build Coastguard Worker for (int i = 0; (i < BPF_MAX_STACK_DEPTH) && \
358*387f9dfdSAndroid Build Coastguard Worker (stack.trace[i].status == BPF_STACK_BUILD_ID_VALID);
359*387f9dfdSAndroid Build Coastguard Worker i++) {
360*387f9dfdSAndroid Build Coastguard Worker /* End of stack marker is BCC_STACK_BUILD_ID_EMPTY or
361*387f9dfdSAndroid Build Coastguard Worker * BCC_STACK_BUILD_IP(fallback) mechanism.
362*387f9dfdSAndroid Build Coastguard Worker * We do not support fallback mechanism
363*387f9dfdSAndroid Build Coastguard Worker */
364*387f9dfdSAndroid Build Coastguard Worker res.push_back(stack.trace[i]);
365*387f9dfdSAndroid Build Coastguard Worker }
366*387f9dfdSAndroid Build Coastguard Worker return res;
367*387f9dfdSAndroid Build Coastguard Worker }
368*387f9dfdSAndroid Build Coastguard Worker
get_stack_symbol(int stack_id)369*387f9dfdSAndroid Build Coastguard Worker std::vector<std::string> BPFStackBuildIdTable::get_stack_symbol(int stack_id)
370*387f9dfdSAndroid Build Coastguard Worker {
371*387f9dfdSAndroid Build Coastguard Worker auto addresses = get_stack_addr(stack_id);
372*387f9dfdSAndroid Build Coastguard Worker std::vector<std::string> res;
373*387f9dfdSAndroid Build Coastguard Worker if (addresses.empty())
374*387f9dfdSAndroid Build Coastguard Worker return res;
375*387f9dfdSAndroid Build Coastguard Worker res.reserve(addresses.size());
376*387f9dfdSAndroid Build Coastguard Worker
377*387f9dfdSAndroid Build Coastguard Worker bcc_symbol symbol;
378*387f9dfdSAndroid Build Coastguard Worker struct bpf_stack_build_id trace;
379*387f9dfdSAndroid Build Coastguard Worker for (auto addr : addresses) {
380*387f9dfdSAndroid Build Coastguard Worker memcpy(trace.build_id, addr.build_id, sizeof(trace.build_id));
381*387f9dfdSAndroid Build Coastguard Worker trace.status = addr.status;
382*387f9dfdSAndroid Build Coastguard Worker trace.offset = addr.offset;
383*387f9dfdSAndroid Build Coastguard Worker if (bcc_buildsymcache_resolve(bsymcache_,&trace,&symbol) != 0) {
384*387f9dfdSAndroid Build Coastguard Worker res.emplace_back("[UNKNOWN]");
385*387f9dfdSAndroid Build Coastguard Worker } else {
386*387f9dfdSAndroid Build Coastguard Worker res.push_back(symbol.name);
387*387f9dfdSAndroid Build Coastguard Worker bcc_symbol_free_demangle_name(&symbol);
388*387f9dfdSAndroid Build Coastguard Worker }
389*387f9dfdSAndroid Build Coastguard Worker }
390*387f9dfdSAndroid Build Coastguard Worker return res;
391*387f9dfdSAndroid Build Coastguard Worker }
392*387f9dfdSAndroid Build Coastguard Worker
BPFPerfBuffer(const TableDesc & desc)393*387f9dfdSAndroid Build Coastguard Worker BPFPerfBuffer::BPFPerfBuffer(const TableDesc& desc)
394*387f9dfdSAndroid Build Coastguard Worker : BPFTableBase<int, int>(desc), epfd_(-1) {
395*387f9dfdSAndroid Build Coastguard Worker if (desc.type != BPF_MAP_TYPE_PERF_EVENT_ARRAY)
396*387f9dfdSAndroid Build Coastguard Worker throw std::invalid_argument("Table '" + desc.name +
397*387f9dfdSAndroid Build Coastguard Worker "' is not a perf buffer");
398*387f9dfdSAndroid Build Coastguard Worker }
399*387f9dfdSAndroid Build Coastguard Worker
open_on_cpu(perf_reader_raw_cb cb,perf_reader_lost_cb lost_cb,void * cb_cookie,int page_cnt,struct bcc_perf_buffer_opts & opts)400*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFPerfBuffer::open_on_cpu(perf_reader_raw_cb cb, perf_reader_lost_cb lost_cb,
401*387f9dfdSAndroid Build Coastguard Worker void* cb_cookie, int page_cnt,
402*387f9dfdSAndroid Build Coastguard Worker struct bcc_perf_buffer_opts& opts) {
403*387f9dfdSAndroid Build Coastguard Worker if (cpu_readers_.find(opts.cpu) != cpu_readers_.end())
404*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Perf buffer already open on CPU %d", opts.cpu);
405*387f9dfdSAndroid Build Coastguard Worker
406*387f9dfdSAndroid Build Coastguard Worker auto reader = static_cast<perf_reader*>(
407*387f9dfdSAndroid Build Coastguard Worker bpf_open_perf_buffer_opts(cb, lost_cb, cb_cookie, page_cnt, &opts));
408*387f9dfdSAndroid Build Coastguard Worker if (reader == nullptr)
409*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Unable to construct perf reader");
410*387f9dfdSAndroid Build Coastguard Worker
411*387f9dfdSAndroid Build Coastguard Worker int reader_fd = perf_reader_fd(reader);
412*387f9dfdSAndroid Build Coastguard Worker if (!update(&opts.cpu, &reader_fd)) {
413*387f9dfdSAndroid Build Coastguard Worker perf_reader_free(static_cast<void*>(reader));
414*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Unable to open perf buffer on CPU %d: %s", opts.cpu,
415*387f9dfdSAndroid Build Coastguard Worker std::strerror(errno));
416*387f9dfdSAndroid Build Coastguard Worker }
417*387f9dfdSAndroid Build Coastguard Worker
418*387f9dfdSAndroid Build Coastguard Worker struct epoll_event event = {};
419*387f9dfdSAndroid Build Coastguard Worker event.events = EPOLLIN;
420*387f9dfdSAndroid Build Coastguard Worker event.data.ptr = static_cast<void*>(reader);
421*387f9dfdSAndroid Build Coastguard Worker if (epoll_ctl(epfd_, EPOLL_CTL_ADD, reader_fd, &event) != 0) {
422*387f9dfdSAndroid Build Coastguard Worker perf_reader_free(static_cast<void*>(reader));
423*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Unable to add perf_reader FD to epoll: %s",
424*387f9dfdSAndroid Build Coastguard Worker std::strerror(errno));
425*387f9dfdSAndroid Build Coastguard Worker }
426*387f9dfdSAndroid Build Coastguard Worker
427*387f9dfdSAndroid Build Coastguard Worker cpu_readers_[opts.cpu] = reader;
428*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
429*387f9dfdSAndroid Build Coastguard Worker }
430*387f9dfdSAndroid Build Coastguard Worker
open_all_cpu(perf_reader_raw_cb cb,perf_reader_lost_cb lost_cb,void * cb_cookie,int page_cnt)431*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFPerfBuffer::open_all_cpu(perf_reader_raw_cb cb,
432*387f9dfdSAndroid Build Coastguard Worker perf_reader_lost_cb lost_cb,
433*387f9dfdSAndroid Build Coastguard Worker void* cb_cookie, int page_cnt) {
434*387f9dfdSAndroid Build Coastguard Worker return open_all_cpu(cb, lost_cb, cb_cookie, page_cnt, 1);
435*387f9dfdSAndroid Build Coastguard Worker }
436*387f9dfdSAndroid Build Coastguard Worker
open_all_cpu(perf_reader_raw_cb cb,perf_reader_lost_cb lost_cb,void * cb_cookie,int page_cnt,int wakeup_events)437*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFPerfBuffer::open_all_cpu(perf_reader_raw_cb cb,
438*387f9dfdSAndroid Build Coastguard Worker perf_reader_lost_cb lost_cb,
439*387f9dfdSAndroid Build Coastguard Worker void* cb_cookie, int page_cnt,
440*387f9dfdSAndroid Build Coastguard Worker int wakeup_events)
441*387f9dfdSAndroid Build Coastguard Worker {
442*387f9dfdSAndroid Build Coastguard Worker if (cpu_readers_.size() != 0 || epfd_ != -1)
443*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Previously opened perf buffer not cleaned");
444*387f9dfdSAndroid Build Coastguard Worker
445*387f9dfdSAndroid Build Coastguard Worker std::vector<int> cpus = get_online_cpus();
446*387f9dfdSAndroid Build Coastguard Worker ep_events_.reset(new epoll_event[cpus.size()]);
447*387f9dfdSAndroid Build Coastguard Worker epfd_ = epoll_create1(EPOLL_CLOEXEC);
448*387f9dfdSAndroid Build Coastguard Worker
449*387f9dfdSAndroid Build Coastguard Worker for (int i : cpus) {
450*387f9dfdSAndroid Build Coastguard Worker struct bcc_perf_buffer_opts opts = {
451*387f9dfdSAndroid Build Coastguard Worker .pid = -1,
452*387f9dfdSAndroid Build Coastguard Worker .cpu = i,
453*387f9dfdSAndroid Build Coastguard Worker .wakeup_events = wakeup_events,
454*387f9dfdSAndroid Build Coastguard Worker };
455*387f9dfdSAndroid Build Coastguard Worker auto res = open_on_cpu(cb, lost_cb, cb_cookie, page_cnt, opts);
456*387f9dfdSAndroid Build Coastguard Worker if (!res.ok()) {
457*387f9dfdSAndroid Build Coastguard Worker TRY2(close_all_cpu());
458*387f9dfdSAndroid Build Coastguard Worker return res;
459*387f9dfdSAndroid Build Coastguard Worker }
460*387f9dfdSAndroid Build Coastguard Worker }
461*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
462*387f9dfdSAndroid Build Coastguard Worker }
463*387f9dfdSAndroid Build Coastguard Worker
close_on_cpu(int cpu)464*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFPerfBuffer::close_on_cpu(int cpu) {
465*387f9dfdSAndroid Build Coastguard Worker auto it = cpu_readers_.find(cpu);
466*387f9dfdSAndroid Build Coastguard Worker if (it == cpu_readers_.end())
467*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
468*387f9dfdSAndroid Build Coastguard Worker perf_reader_free(static_cast<void*>(it->second));
469*387f9dfdSAndroid Build Coastguard Worker if (!remove(const_cast<int*>(&(it->first))))
470*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Unable to close perf buffer on CPU %d", it->first);
471*387f9dfdSAndroid Build Coastguard Worker cpu_readers_.erase(it);
472*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
473*387f9dfdSAndroid Build Coastguard Worker }
474*387f9dfdSAndroid Build Coastguard Worker
close_all_cpu()475*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFPerfBuffer::close_all_cpu() {
476*387f9dfdSAndroid Build Coastguard Worker std::string errors;
477*387f9dfdSAndroid Build Coastguard Worker bool has_error = false;
478*387f9dfdSAndroid Build Coastguard Worker
479*387f9dfdSAndroid Build Coastguard Worker if (epfd_ >= 0) {
480*387f9dfdSAndroid Build Coastguard Worker int close_res = close(epfd_);
481*387f9dfdSAndroid Build Coastguard Worker epfd_ = -1;
482*387f9dfdSAndroid Build Coastguard Worker ep_events_.reset();
483*387f9dfdSAndroid Build Coastguard Worker if (close_res != 0) {
484*387f9dfdSAndroid Build Coastguard Worker has_error = true;
485*387f9dfdSAndroid Build Coastguard Worker errors += std::string(std::strerror(errno)) + "\n";
486*387f9dfdSAndroid Build Coastguard Worker }
487*387f9dfdSAndroid Build Coastguard Worker }
488*387f9dfdSAndroid Build Coastguard Worker
489*387f9dfdSAndroid Build Coastguard Worker std::vector<int> opened_cpus;
490*387f9dfdSAndroid Build Coastguard Worker for (auto it : cpu_readers_)
491*387f9dfdSAndroid Build Coastguard Worker opened_cpus.push_back(it.first);
492*387f9dfdSAndroid Build Coastguard Worker for (int i : opened_cpus) {
493*387f9dfdSAndroid Build Coastguard Worker auto res = close_on_cpu(i);
494*387f9dfdSAndroid Build Coastguard Worker if (!res.ok()) {
495*387f9dfdSAndroid Build Coastguard Worker errors += "Failed to close CPU" + std::to_string(i) + " perf buffer: ";
496*387f9dfdSAndroid Build Coastguard Worker errors += res.msg() + "\n";
497*387f9dfdSAndroid Build Coastguard Worker has_error = true;
498*387f9dfdSAndroid Build Coastguard Worker }
499*387f9dfdSAndroid Build Coastguard Worker }
500*387f9dfdSAndroid Build Coastguard Worker
501*387f9dfdSAndroid Build Coastguard Worker if (has_error)
502*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, errors);
503*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
504*387f9dfdSAndroid Build Coastguard Worker }
505*387f9dfdSAndroid Build Coastguard Worker
poll(int timeout_ms)506*387f9dfdSAndroid Build Coastguard Worker int BPFPerfBuffer::poll(int timeout_ms) {
507*387f9dfdSAndroid Build Coastguard Worker if (epfd_ < 0)
508*387f9dfdSAndroid Build Coastguard Worker return -1;
509*387f9dfdSAndroid Build Coastguard Worker int cnt =
510*387f9dfdSAndroid Build Coastguard Worker epoll_wait(epfd_, ep_events_.get(), cpu_readers_.size(), timeout_ms);
511*387f9dfdSAndroid Build Coastguard Worker for (int i = 0; i < cnt; i++)
512*387f9dfdSAndroid Build Coastguard Worker perf_reader_event_read(static_cast<perf_reader*>(ep_events_[i].data.ptr));
513*387f9dfdSAndroid Build Coastguard Worker return cnt;
514*387f9dfdSAndroid Build Coastguard Worker }
515*387f9dfdSAndroid Build Coastguard Worker
consume()516*387f9dfdSAndroid Build Coastguard Worker int BPFPerfBuffer::consume() {
517*387f9dfdSAndroid Build Coastguard Worker if (epfd_ < 0)
518*387f9dfdSAndroid Build Coastguard Worker return -1;
519*387f9dfdSAndroid Build Coastguard Worker for (auto it : cpu_readers_)
520*387f9dfdSAndroid Build Coastguard Worker perf_reader_event_read(it.second);
521*387f9dfdSAndroid Build Coastguard Worker return 0;
522*387f9dfdSAndroid Build Coastguard Worker }
523*387f9dfdSAndroid Build Coastguard Worker
~BPFPerfBuffer()524*387f9dfdSAndroid Build Coastguard Worker BPFPerfBuffer::~BPFPerfBuffer() {
525*387f9dfdSAndroid Build Coastguard Worker auto res = close_all_cpu();
526*387f9dfdSAndroid Build Coastguard Worker if (!res.ok())
527*387f9dfdSAndroid Build Coastguard Worker std::cerr << "Failed to close all perf buffer on destruction: " << res.msg()
528*387f9dfdSAndroid Build Coastguard Worker << std::endl;
529*387f9dfdSAndroid Build Coastguard Worker }
530*387f9dfdSAndroid Build Coastguard Worker
BPFPerfEventArray(const TableDesc & desc)531*387f9dfdSAndroid Build Coastguard Worker BPFPerfEventArray::BPFPerfEventArray(const TableDesc& desc)
532*387f9dfdSAndroid Build Coastguard Worker : BPFTableBase<int, int>(desc) {
533*387f9dfdSAndroid Build Coastguard Worker if (desc.type != BPF_MAP_TYPE_PERF_EVENT_ARRAY)
534*387f9dfdSAndroid Build Coastguard Worker throw std::invalid_argument("Table '" + desc.name +
535*387f9dfdSAndroid Build Coastguard Worker "' is not a perf event array");
536*387f9dfdSAndroid Build Coastguard Worker }
537*387f9dfdSAndroid Build Coastguard Worker
open_all_cpu(uint32_t type,uint64_t config,int pid)538*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFPerfEventArray::open_all_cpu(uint32_t type, uint64_t config,
539*387f9dfdSAndroid Build Coastguard Worker int pid) {
540*387f9dfdSAndroid Build Coastguard Worker if (cpu_fds_.size() != 0)
541*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Previously opened perf event not cleaned");
542*387f9dfdSAndroid Build Coastguard Worker
543*387f9dfdSAndroid Build Coastguard Worker std::vector<int> cpus = get_online_cpus();
544*387f9dfdSAndroid Build Coastguard Worker
545*387f9dfdSAndroid Build Coastguard Worker for (int i : cpus) {
546*387f9dfdSAndroid Build Coastguard Worker auto res = open_on_cpu(i, type, config, pid);
547*387f9dfdSAndroid Build Coastguard Worker if (!res.ok()) {
548*387f9dfdSAndroid Build Coastguard Worker TRY2(close_all_cpu());
549*387f9dfdSAndroid Build Coastguard Worker return res;
550*387f9dfdSAndroid Build Coastguard Worker }
551*387f9dfdSAndroid Build Coastguard Worker }
552*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
553*387f9dfdSAndroid Build Coastguard Worker }
554*387f9dfdSAndroid Build Coastguard Worker
close_all_cpu()555*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFPerfEventArray::close_all_cpu() {
556*387f9dfdSAndroid Build Coastguard Worker std::string errors;
557*387f9dfdSAndroid Build Coastguard Worker bool has_error = false;
558*387f9dfdSAndroid Build Coastguard Worker
559*387f9dfdSAndroid Build Coastguard Worker std::vector<int> opened_cpus;
560*387f9dfdSAndroid Build Coastguard Worker for (auto it : cpu_fds_)
561*387f9dfdSAndroid Build Coastguard Worker opened_cpus.push_back(it.first);
562*387f9dfdSAndroid Build Coastguard Worker for (int i : opened_cpus) {
563*387f9dfdSAndroid Build Coastguard Worker auto res = close_on_cpu(i);
564*387f9dfdSAndroid Build Coastguard Worker if (!res.ok()) {
565*387f9dfdSAndroid Build Coastguard Worker errors += "Failed to close CPU" + std::to_string(i) + " perf event: ";
566*387f9dfdSAndroid Build Coastguard Worker errors += res.msg() + "\n";
567*387f9dfdSAndroid Build Coastguard Worker has_error = true;
568*387f9dfdSAndroid Build Coastguard Worker }
569*387f9dfdSAndroid Build Coastguard Worker }
570*387f9dfdSAndroid Build Coastguard Worker
571*387f9dfdSAndroid Build Coastguard Worker if (has_error)
572*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, errors);
573*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
574*387f9dfdSAndroid Build Coastguard Worker }
575*387f9dfdSAndroid Build Coastguard Worker
open_on_cpu(int cpu,uint32_t type,uint64_t config,int pid)576*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFPerfEventArray::open_on_cpu(int cpu, uint32_t type,
577*387f9dfdSAndroid Build Coastguard Worker uint64_t config, int pid) {
578*387f9dfdSAndroid Build Coastguard Worker if (cpu_fds_.find(cpu) != cpu_fds_.end())
579*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Perf event already open on CPU %d", cpu);
580*387f9dfdSAndroid Build Coastguard Worker int fd = bpf_open_perf_event(type, config, pid, cpu);
581*387f9dfdSAndroid Build Coastguard Worker if (fd < 0) {
582*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Error constructing perf event %" PRIu32 ":%" PRIu64,
583*387f9dfdSAndroid Build Coastguard Worker type, config);
584*387f9dfdSAndroid Build Coastguard Worker }
585*387f9dfdSAndroid Build Coastguard Worker if (!update(&cpu, &fd)) {
586*387f9dfdSAndroid Build Coastguard Worker bpf_close_perf_event_fd(fd);
587*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Unable to open perf event on CPU %d: %s", cpu,
588*387f9dfdSAndroid Build Coastguard Worker std::strerror(errno));
589*387f9dfdSAndroid Build Coastguard Worker }
590*387f9dfdSAndroid Build Coastguard Worker cpu_fds_[cpu] = fd;
591*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
592*387f9dfdSAndroid Build Coastguard Worker }
593*387f9dfdSAndroid Build Coastguard Worker
close_on_cpu(int cpu)594*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFPerfEventArray::close_on_cpu(int cpu) {
595*387f9dfdSAndroid Build Coastguard Worker auto it = cpu_fds_.find(cpu);
596*387f9dfdSAndroid Build Coastguard Worker if (it == cpu_fds_.end()) {
597*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
598*387f9dfdSAndroid Build Coastguard Worker }
599*387f9dfdSAndroid Build Coastguard Worker bpf_close_perf_event_fd(it->second);
600*387f9dfdSAndroid Build Coastguard Worker cpu_fds_.erase(it);
601*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
602*387f9dfdSAndroid Build Coastguard Worker }
603*387f9dfdSAndroid Build Coastguard Worker
~BPFPerfEventArray()604*387f9dfdSAndroid Build Coastguard Worker BPFPerfEventArray::~BPFPerfEventArray() {
605*387f9dfdSAndroid Build Coastguard Worker auto res = close_all_cpu();
606*387f9dfdSAndroid Build Coastguard Worker if (!res.ok()) {
607*387f9dfdSAndroid Build Coastguard Worker std::cerr << "Failed to close all perf buffer on destruction: " << res.msg()
608*387f9dfdSAndroid Build Coastguard Worker << std::endl;
609*387f9dfdSAndroid Build Coastguard Worker }
610*387f9dfdSAndroid Build Coastguard Worker }
611*387f9dfdSAndroid Build Coastguard Worker
BPFProgTable(const TableDesc & desc)612*387f9dfdSAndroid Build Coastguard Worker BPFProgTable::BPFProgTable(const TableDesc& desc)
613*387f9dfdSAndroid Build Coastguard Worker : BPFTableBase<int, int>(desc) {
614*387f9dfdSAndroid Build Coastguard Worker if (desc.type != BPF_MAP_TYPE_PROG_ARRAY)
615*387f9dfdSAndroid Build Coastguard Worker throw std::invalid_argument("Table '" + desc.name +
616*387f9dfdSAndroid Build Coastguard Worker "' is not a prog table");
617*387f9dfdSAndroid Build Coastguard Worker }
618*387f9dfdSAndroid Build Coastguard Worker
update_value(const int & index,const int & prog_fd)619*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFProgTable::update_value(const int& index, const int& prog_fd) {
620*387f9dfdSAndroid Build Coastguard Worker if (!this->update(const_cast<int*>(&index), const_cast<int*>(&prog_fd)))
621*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
622*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
623*387f9dfdSAndroid Build Coastguard Worker }
624*387f9dfdSAndroid Build Coastguard Worker
remove_value(const int & index)625*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFProgTable::remove_value(const int& index) {
626*387f9dfdSAndroid Build Coastguard Worker if (!this->remove(const_cast<int*>(&index)))
627*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
628*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
629*387f9dfdSAndroid Build Coastguard Worker }
630*387f9dfdSAndroid Build Coastguard Worker
BPFCgroupArray(const TableDesc & desc)631*387f9dfdSAndroid Build Coastguard Worker BPFCgroupArray::BPFCgroupArray(const TableDesc& desc)
632*387f9dfdSAndroid Build Coastguard Worker : BPFTableBase<int, int>(desc) {
633*387f9dfdSAndroid Build Coastguard Worker if (desc.type != BPF_MAP_TYPE_CGROUP_ARRAY)
634*387f9dfdSAndroid Build Coastguard Worker throw std::invalid_argument("Table '" + desc.name +
635*387f9dfdSAndroid Build Coastguard Worker "' is not a cgroup array");
636*387f9dfdSAndroid Build Coastguard Worker }
637*387f9dfdSAndroid Build Coastguard Worker
update_value(const int & index,const int & cgroup2_fd)638*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFCgroupArray::update_value(const int& index,
639*387f9dfdSAndroid Build Coastguard Worker const int& cgroup2_fd) {
640*387f9dfdSAndroid Build Coastguard Worker if (!this->update(const_cast<int*>(&index), const_cast<int*>(&cgroup2_fd)))
641*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
642*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
643*387f9dfdSAndroid Build Coastguard Worker }
644*387f9dfdSAndroid Build Coastguard Worker
update_value(const int & index,const std::string & cgroup2_path)645*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFCgroupArray::update_value(const int& index,
646*387f9dfdSAndroid Build Coastguard Worker const std::string& cgroup2_path) {
647*387f9dfdSAndroid Build Coastguard Worker FileDesc f(::open(cgroup2_path.c_str(), O_RDONLY | O_CLOEXEC));
648*387f9dfdSAndroid Build Coastguard Worker if ((int)f < 0)
649*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Unable to open %s", cgroup2_path.c_str());
650*387f9dfdSAndroid Build Coastguard Worker TRY2(update_value(index, (int)f));
651*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
652*387f9dfdSAndroid Build Coastguard Worker }
653*387f9dfdSAndroid Build Coastguard Worker
remove_value(const int & index)654*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFCgroupArray::remove_value(const int& index) {
655*387f9dfdSAndroid Build Coastguard Worker if (!this->remove(const_cast<int*>(&index)))
656*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
657*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
658*387f9dfdSAndroid Build Coastguard Worker }
659*387f9dfdSAndroid Build Coastguard Worker
BPFDevmapTable(const TableDesc & desc)660*387f9dfdSAndroid Build Coastguard Worker BPFDevmapTable::BPFDevmapTable(const TableDesc& desc)
661*387f9dfdSAndroid Build Coastguard Worker : BPFTableBase<int, int>(desc) {
662*387f9dfdSAndroid Build Coastguard Worker if(desc.type != BPF_MAP_TYPE_DEVMAP)
663*387f9dfdSAndroid Build Coastguard Worker throw std::invalid_argument("Table '" + desc.name +
664*387f9dfdSAndroid Build Coastguard Worker "' is not a devmap table");
665*387f9dfdSAndroid Build Coastguard Worker }
666*387f9dfdSAndroid Build Coastguard Worker
update_value(const int & index,const int & value)667*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFDevmapTable::update_value(const int& index,
668*387f9dfdSAndroid Build Coastguard Worker const int& value) {
669*387f9dfdSAndroid Build Coastguard Worker if (!this->update(const_cast<int*>(&index), const_cast<int*>(&value)))
670*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
671*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
672*387f9dfdSAndroid Build Coastguard Worker }
673*387f9dfdSAndroid Build Coastguard Worker
get_value(const int & index,int & value)674*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFDevmapTable::get_value(const int& index,
675*387f9dfdSAndroid Build Coastguard Worker int& value) {
676*387f9dfdSAndroid Build Coastguard Worker if (!this->lookup(const_cast<int*>(&index), &value))
677*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Error getting value: %s", std::strerror(errno));
678*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
679*387f9dfdSAndroid Build Coastguard Worker }
680*387f9dfdSAndroid Build Coastguard Worker
remove_value(const int & index)681*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFDevmapTable::remove_value(const int& index) {
682*387f9dfdSAndroid Build Coastguard Worker if (!this->remove(const_cast<int*>(&index)))
683*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
684*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
685*387f9dfdSAndroid Build Coastguard Worker }
686*387f9dfdSAndroid Build Coastguard Worker
BPFXskmapTable(const TableDesc & desc)687*387f9dfdSAndroid Build Coastguard Worker BPFXskmapTable::BPFXskmapTable(const TableDesc& desc)
688*387f9dfdSAndroid Build Coastguard Worker : BPFTableBase<int, int>(desc) {
689*387f9dfdSAndroid Build Coastguard Worker if(desc.type != BPF_MAP_TYPE_XSKMAP)
690*387f9dfdSAndroid Build Coastguard Worker throw std::invalid_argument("Table '" + desc.name +
691*387f9dfdSAndroid Build Coastguard Worker "' is not a xskmap table");
692*387f9dfdSAndroid Build Coastguard Worker }
693*387f9dfdSAndroid Build Coastguard Worker
update_value(const int & index,const int & value)694*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFXskmapTable::update_value(const int& index,
695*387f9dfdSAndroid Build Coastguard Worker const int& value) {
696*387f9dfdSAndroid Build Coastguard Worker if (!this->update(const_cast<int*>(&index), const_cast<int*>(&value)))
697*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
698*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
699*387f9dfdSAndroid Build Coastguard Worker }
700*387f9dfdSAndroid Build Coastguard Worker
get_value(const int & index,int & value)701*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFXskmapTable::get_value(const int& index,
702*387f9dfdSAndroid Build Coastguard Worker int& value) {
703*387f9dfdSAndroid Build Coastguard Worker if (!this->lookup(const_cast<int*>(&index), &value))
704*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Error getting value: %s", std::strerror(errno));
705*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
706*387f9dfdSAndroid Build Coastguard Worker }
707*387f9dfdSAndroid Build Coastguard Worker
remove_value(const int & index)708*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFXskmapTable::remove_value(const int& index) {
709*387f9dfdSAndroid Build Coastguard Worker if (!this->remove(const_cast<int*>(&index)))
710*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
711*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
712*387f9dfdSAndroid Build Coastguard Worker }
713*387f9dfdSAndroid Build Coastguard Worker
BPFSockmapTable(const TableDesc & desc)714*387f9dfdSAndroid Build Coastguard Worker BPFSockmapTable::BPFSockmapTable(const TableDesc& desc)
715*387f9dfdSAndroid Build Coastguard Worker : BPFTableBase<int, int>(desc) {
716*387f9dfdSAndroid Build Coastguard Worker if(desc.type != BPF_MAP_TYPE_SOCKMAP)
717*387f9dfdSAndroid Build Coastguard Worker throw std::invalid_argument("Table '" + desc.name +
718*387f9dfdSAndroid Build Coastguard Worker "' is not a sockmap table");
719*387f9dfdSAndroid Build Coastguard Worker }
720*387f9dfdSAndroid Build Coastguard Worker
update_value(const int & index,const int & value)721*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFSockmapTable::update_value(const int& index,
722*387f9dfdSAndroid Build Coastguard Worker const int& value) {
723*387f9dfdSAndroid Build Coastguard Worker if (!this->update(const_cast<int*>(&index), const_cast<int*>(&value)))
724*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
725*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
726*387f9dfdSAndroid Build Coastguard Worker }
727*387f9dfdSAndroid Build Coastguard Worker
remove_value(const int & index)728*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFSockmapTable::remove_value(const int& index) {
729*387f9dfdSAndroid Build Coastguard Worker if (!this->remove(const_cast<int*>(&index)))
730*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
731*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
732*387f9dfdSAndroid Build Coastguard Worker }
733*387f9dfdSAndroid Build Coastguard Worker
BPFSockhashTable(const TableDesc & desc)734*387f9dfdSAndroid Build Coastguard Worker BPFSockhashTable::BPFSockhashTable(const TableDesc& desc)
735*387f9dfdSAndroid Build Coastguard Worker : BPFTableBase<int, int>(desc) {
736*387f9dfdSAndroid Build Coastguard Worker if(desc.type != BPF_MAP_TYPE_SOCKHASH)
737*387f9dfdSAndroid Build Coastguard Worker throw std::invalid_argument("Table '" + desc.name +
738*387f9dfdSAndroid Build Coastguard Worker "' is not a sockhash table");
739*387f9dfdSAndroid Build Coastguard Worker }
740*387f9dfdSAndroid Build Coastguard Worker
update_value(const int & key,const int & value)741*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFSockhashTable::update_value(const int& key,
742*387f9dfdSAndroid Build Coastguard Worker const int& value) {
743*387f9dfdSAndroid Build Coastguard Worker if (!this->update(const_cast<int*>(&key), const_cast<int*>(&value)))
744*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
745*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
746*387f9dfdSAndroid Build Coastguard Worker }
747*387f9dfdSAndroid Build Coastguard Worker
remove_value(const int & key)748*387f9dfdSAndroid Build Coastguard Worker StatusTuple BPFSockhashTable::remove_value(const int& key) {
749*387f9dfdSAndroid Build Coastguard Worker if (!this->remove(const_cast<int*>(&key)))
750*387f9dfdSAndroid Build Coastguard Worker return StatusTuple(-1, "Error removing value: %s", std::strerror(errno));
751*387f9dfdSAndroid Build Coastguard Worker return StatusTuple::OK();
752*387f9dfdSAndroid Build Coastguard Worker }
753*387f9dfdSAndroid Build Coastguard Worker
754*387f9dfdSAndroid Build Coastguard Worker } // namespace ebpf
755