Commit 335cbe4f authored by Teng Qin's avatar Teng Qin

Basic BCC C++ API

parent 1c89ff5d
/*
* Copyright (c) 2016 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <linux/bpf.h>
#include <unistd.h>
#include <cstdio>
#include <exception>
#include <iostream>
#include <memory>
#include <sstream>
#include <vector>
#include "bcc_syms.h"
#include "bpf_module.h"
#include "common.h"
#include "exception.h"
#include "libbpf.h"
#include "perf_reader.h"
#include "BPF.h"
namespace ebpf {
std::string uint_to_hex(uint64_t value) {
std::stringstream ss;
ss << std::hex << value;
return ss.str();
}
std::string sanitize_str(std::string str, bool (*validator)(char),
char replacement = '_') {
for (size_t i = 0; i < str.length(); i++)
if (!validator(str[i]))
str[i] = replacement;
return str;
}
StatusTuple BPF::init(const std::string& bpf_program,
std::vector<std::string> cflags) {
auto flags_len = cflags.size();
const char* flags[flags_len];
for (size_t i = 0; i < flags_len; i++)
flags[i] = cflags[i].c_str();
if (bpf_module_->load_string(bpf_program, flags, flags_len) != 0)
return mkstatus(-1, "Unable to initialize BPF program");
return mkstatus(0);
};
BPF::~BPF() {
auto res = detach_all();
if (std::get<0>(res) != 0)
std::cerr << "Failed to detach all probes on destruction: " << std::endl
<< std::get<1>(res) << std::endl;
}
StatusTuple BPF::detach_all() {
bool has_error = false;
std::string error_msg;
for (auto it : kprobes_) {
auto res = detach_kprobe_event(it.first, it.second);
if (std::get<0>(res) != 0) {
error_msg += "Failed to detach kprobe event " + it.first + ": ";
error_msg += std::get<1>(res) + "\n";
has_error = true;
}
}
for (auto it : uprobes_) {
auto res = detach_uprobe_event(it.first, it.second);
if (std::get<0>(res) != 0) {
error_msg += "Failed to detach uprobe event " + it.first + ": ";
error_msg += std::get<1>(res) + "\n";
has_error = true;
}
}
for (auto it : tracepoints_) {
auto res = detach_tracepoint_event(it.first, it.second);
if (std::get<0>(res) != 0) {
error_msg += "Failed to detach Tracepoint " + it.first + ": ";
error_msg += std::get<1>(res) + "\n";
has_error = true;
}
}
for (auto it : perf_buffers_) {
auto res = it.second->close();
if (std::get<0>(res) != 0) {
error_msg += "Failed to close perf buffer " + it.first + ": ";
error_msg += std::get<1>(res) + "\n";
has_error = true;
}
delete it.second;
}
if (has_error)
return mkstatus(-1, error_msg);
else
return mkstatus(0);
}
StatusTuple BPF::attach_kprobe(const std::string& kernel_func,
const std::string& probe_func,
bpf_attach_type attach_type,
pid_t pid, int cpu, int group_fd,
perf_reader_cb cb, void* cb_cookie) {
int probe_fd;
TRY2(load_func(probe_func, BPF_PROG_TYPE_KPROBE, probe_fd));
std::string probe_event = get_kprobe_event(kernel_func, attach_type);
if (kprobes_.find(probe_event) != kprobes_.end()) {
TRY2(unload_func(probe_func));
return mkstatus(-1, "kprobe %s already attached", probe_event.c_str());
}
std::string probe_event_desc = attach_type_prefix(attach_type);
probe_event_desc += ":kprobes/" + probe_event + " " + kernel_func;
void* res =
bpf_attach_kprobe(probe_fd, probe_event.c_str(), probe_event_desc.c_str(),
pid, cpu, group_fd, cb, cb_cookie);
if (!res) {
TRY2(unload_func(probe_func));
return mkstatus(-1, "Unable to attach %skprobe for %s using %s",
attach_type_debug(attach_type).c_str(), kernel_func.c_str(),
probe_func.c_str());
}
open_probe_t p = {};
p.reader_ptr = res;
p.func = probe_func;
kprobes_[probe_event] = std::move(p);
return mkstatus(0);
}
StatusTuple BPF::attach_uprobe(const std::string& binary_path,
const std::string& symbol,
const std::string& probe_func,
uint64_t symbol_addr,
bpf_attach_type attach_type,
pid_t pid, int cpu, int group_fd,
perf_reader_cb cb, void* cb_cookie) {
int probe_fd;
TRY2(load_func(probe_func, BPF_PROG_TYPE_KPROBE, probe_fd));
bcc_symbol sym = bcc_symbol();
TRY2(check_binary_symbol(binary_path, symbol, symbol_addr, &sym));
std::string probe_event =
get_uprobe_event(sym.module, sym.offset, attach_type);
if (uprobes_.find(probe_event) != uprobes_.end()) {
TRY2(unload_func(probe_func));
return mkstatus(-1, "uprobe %s already attached", probe_event.c_str());
}
std::string probe_event_desc = attach_type_prefix(attach_type);
probe_event_desc += ":uprobes/" + probe_event + " ";
probe_event_desc += binary_path + ":0x" + uint_to_hex(sym.offset);
void* res =
bpf_attach_uprobe(probe_fd, probe_event.c_str(), probe_event_desc.c_str(),
pid, cpu, group_fd, cb, cb_cookie);
if (!res) {
TRY2(unload_func(probe_func));
return mkstatus(
-1,
"Unable to attach %suprobe for binary %s symbol %s addr %lx using %s\n",
attach_type_debug(attach_type).c_str(), binary_path.c_str(),
symbol.c_str(), symbol_addr, probe_func.c_str());
}
open_probe_t p = {};
p.reader_ptr = res;
p.func = probe_func;
uprobes_[probe_event] = std::move(p);
return mkstatus(0);
}
StatusTuple BPF::attach_tracepoint(const std::string& tracepoint,
const std::string& probe_func,
pid_t pid, int cpu, int group_fd,
perf_reader_cb cb, void* cb_cookie) {
int probe_fd;
TRY2(load_func(probe_func, BPF_PROG_TYPE_TRACEPOINT, probe_fd));
if (tracepoints_.find(tracepoint) != tracepoints_.end())
return mkstatus(-1, "Tracepoint %s already attached", tracepoint.c_str());
auto pos = tracepoint.find(":");
if ((pos == std::string::npos) || (pos != tracepoint.rfind(":")))
return mkstatus(-1, "Unable to parse Tracepoint %s", tracepoint.c_str());
std::string tp_category = tracepoint.substr(0, pos);
std::string tp_name = tracepoint.substr(pos + 1);
void* res =
bpf_attach_tracepoint(probe_fd, tp_category.c_str(), tp_name.c_str(), pid,
cpu, group_fd, cb, cb_cookie);
if (!res) {
TRY2(unload_func(probe_func));
return mkstatus(-1, "Unable to attach Tracepoint %s using %s",
tracepoint.c_str(), probe_func.c_str());
}
open_probe_t p = {};
p.reader_ptr = res;
p.func = probe_func;
tracepoints_[tracepoint] = std::move(p);
return mkstatus(0);
}
StatusTuple BPF::detach_kprobe(const std::string& kernel_func,
bpf_attach_type attach_type) {
std::string event = get_kprobe_event(kernel_func, attach_type);
auto it = kprobes_.find(event);
if (it == kprobes_.end())
return mkstatus(-1, "No open %skprobe for %s",
attach_type_debug(attach_type).c_str(),
kernel_func.c_str());
TRY2(detach_kprobe_event(it->first, it->second));
kprobes_.erase(it);
return mkstatus(0);
}
StatusTuple BPF::detach_uprobe(const std::string& binary_path,
const std::string& symbol, uint64_t symbol_addr,
bpf_attach_type attach_type) {
bcc_symbol sym = bcc_symbol();
TRY2(check_binary_symbol(binary_path, symbol, symbol_addr, &sym));
std::string event = get_uprobe_event(sym.module, sym.offset, attach_type);
auto it = uprobes_.find(event);
if (it == uprobes_.end())
return mkstatus(-1, "No open %suprobe for binary %s symbol %s addr %lx",
attach_type_debug(attach_type).c_str(), binary_path.c_str(),
symbol.c_str(), symbol_addr);
TRY2(detach_uprobe_event(it->first, it->second));
uprobes_.erase(it);
return mkstatus(0);
}
StatusTuple BPF::detach_tracepoint(const std::string& tracepoint) {
auto it = tracepoints_.find(tracepoint);
if (it == tracepoints_.end())
return mkstatus(-1, "No open Tracepoint %s", tracepoint.c_str());
TRY2(detach_tracepoint_event(it->first, it->second));
tracepoints_.erase(it);
return mkstatus(0);
}
StatusTuple BPF::open_perf_buffer(const std::string& name,
perf_reader_raw_cb cb, void* cb_cookie) {
if (perf_buffers_.find(name) == perf_buffers_.end())
perf_buffers_[name] = new BPFPerfBuffer(bpf_module_.get(), name);
auto table = perf_buffers_[name];
TRY2(table->open(cb, cb_cookie));
return mkstatus(0);
}
StatusTuple BPF::close_perf_buffer(const std::string& name) {
auto it = perf_buffers_.find(name);
if (it == perf_buffers_.end())
return mkstatus(-1, "Perf buffer for %s not open", name.c_str());
TRY2(it->second->close());
return mkstatus(0);
}
void BPF::poll_perf_buffer(const std::string& name, int timeout) {
auto it = perf_buffers_.find(name);
if (it == perf_buffers_.end())
return;
it->second->poll(timeout);
}
StatusTuple BPF::load_func(const std::string& func_name,
enum bpf_prog_type type, int& fd) {
if (funcs_.find(func_name) != funcs_.end()) {
fd = funcs_[func_name];
return mkstatus(0);
}
uint8_t* func_start = bpf_module_->function_start(func_name);
if (!func_start)
return mkstatus(-1, "Can't find start of function %s", func_name.c_str());
size_t func_size = bpf_module_->function_size(func_name);
fd = bpf_prog_load(type, reinterpret_cast<struct bpf_insn*>(func_start),
func_size, bpf_module_->license(),
bpf_module_->kern_version(), nullptr,
0 // BPFModule will handle error printing
);
if (fd < 0)
return mkstatus(-1, "Failed to load %s: %d", func_name.c_str(), fd);
funcs_[func_name] = fd;
return mkstatus(0);
}
StatusTuple BPF::unload_func(const std::string& func_name) {
auto it = funcs_.find(func_name);
if (it == funcs_.end())
return mkstatus(-1, "Probe function %s not loaded", func_name.c_str());
int res = close(it->second);
if (res != 0)
return mkstatus(-1, "Can't close FD for %s: %d", it->first.c_str(), res);
funcs_.erase(it);
return mkstatus(0);
}
StatusTuple BPF::check_binary_symbol(const std::string& binary_path,
const std::string& symbol,
uint64_t symbol_addr, bcc_symbol* output) {
int res = bcc_resolve_symname(binary_path.c_str(), symbol.c_str(),
symbol_addr, output);
if (res < 0)
return mkstatus(-1,
"Unable to find offset for binary %s symbol %s address %lx",
binary_path.c_str(), symbol.c_str(), symbol_addr);
return mkstatus(0);
}
std::string BPF::get_kprobe_event(const std::string& kernel_func,
bpf_attach_type type) {
std::string res = attach_type_prefix(type) + "_";
res += sanitize_str(kernel_func, &BPF::kprobe_event_validator);
return res;
}
std::string BPF::get_uprobe_event(const std::string& binary_path,
uint64_t offset, bpf_attach_type type) {
std::string res = attach_type_prefix(type) + "_";
res += sanitize_str(binary_path, &BPF::uprobe_path_validator);
res += "_0x" + uint_to_hex(offset);
return res;
}
StatusTuple BPF::detach_kprobe_event(const std::string& event,
open_probe_t& attr) {
if (attr.reader_ptr) {
perf_reader_free(attr.reader_ptr);
attr.reader_ptr = nullptr;
}
TRY2(unload_func(attr.func));
std::string detach_event = "-:kprobes/" + event;
if (bpf_detach_kprobe(detach_event.c_str()) < 0)
return mkstatus(-1, "Unable to detach kprobe %s", event.c_str());
return mkstatus(0);
}
StatusTuple BPF::detach_uprobe_event(const std::string& event,
open_probe_t& attr) {
if (attr.reader_ptr) {
perf_reader_free(attr.reader_ptr);
attr.reader_ptr = nullptr;
}
TRY2(unload_func(attr.func));
std::string detach_event = "-:uprobes/" + event;
if (bpf_detach_uprobe(detach_event.c_str()) < 0)
return mkstatus(-1, "Unable to detach uprobe %s", event.c_str());
return mkstatus(0);
}
StatusTuple BPF::detach_tracepoint_event(const std::string& tracepoint,
open_probe_t& attr) {
if (attr.reader_ptr) {
perf_reader_free(attr.reader_ptr);
attr.reader_ptr = nullptr;
}
TRY2(unload_func(attr.func));
// TODO: bpf_detach_tracepoint currently does nothing.
return mkstatus(0);
}
} // namespace ebpf
/*
* Copyright (c) 2016 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <cctype>
#include <memory>
#include <string>
#include "BPFTable.h"
#include "bcc_syms.h"
#include "bpf_module.h"
#include "common.h"
#include "compat/linux/bpf.h"
#include "libbpf.h"
namespace ebpf {
enum class bpf_attach_type {
probe_entry,
probe_return
};
struct open_probe_t {
void* reader_ptr;
std::string func;
};
class BPF {
public:
static const int BPF_MAX_STACK_DEPTH = 127;
explicit BPF(unsigned int flag = 0) : bpf_module_(new BPFModule(flag)) {}
StatusTuple init(const std::string& bpf_program,
std::vector<std::string> cflags = {});
~BPF();
StatusTuple detach_all();
StatusTuple attach_kprobe(
const std::string& kernel_func, const std::string& probe_func,
bpf_attach_type attach_type = bpf_attach_type::probe_entry,
pid_t pid = -1, int cpu = 0, int group_fd = -1,
perf_reader_cb cb = nullptr, void* cb_cookie = nullptr);
StatusTuple detach_kprobe(
const std::string& kernel_func,
bpf_attach_type attach_type = bpf_attach_type::probe_entry);
StatusTuple attach_uprobe(
const std::string& binary_path, const std::string& symbol,
const std::string& probe_func, uint64_t symbol_addr = 0,
bpf_attach_type attach_type = bpf_attach_type::probe_entry,
pid_t pid = -1, int cpu = 0, int group_fd = -1,
perf_reader_cb cb = nullptr, void* cb_cookie = nullptr);
StatusTuple detach_uprobe(
const std::string& binary_path, const std::string& symbol,
uint64_t symbol_addr = 0,
bpf_attach_type attach_type = bpf_attach_type::probe_entry);
StatusTuple attach_tracepoint(const std::string& tracepoint,
const std::string& probe_func,
pid_t pid = -1, int cpu = 0, int group_fd = -1,
perf_reader_cb cb = nullptr,
void* cb_cookie = nullptr);
StatusTuple detach_tracepoint(const std::string& tracepoint);
template <class KeyType, class ValueType>
BPFHashTable<KeyType, ValueType> get_hash_table(const std::string& name) {
return BPFHashTable<KeyType, ValueType>(bpf_module_.get(), name);
}
BPFStackTable get_stack_table(const std::string& name) {
return BPFStackTable(bpf_module_.get(), name);
}
StatusTuple open_perf_buffer(const std::string& name, perf_reader_raw_cb cb,
void* cb_cookie = nullptr);
StatusTuple close_perf_buffer(const std::string& name);
void poll_perf_buffer(const std::string& name, int timeout = -1);
private:
StatusTuple load_func(const std::string& func_name, enum bpf_prog_type type,
int& fd);
StatusTuple unload_func(const std::string& func_name);
std::string get_kprobe_event(const std::string& kernel_func,
bpf_attach_type type);
std::string get_uprobe_event(const std::string& binary_path, uint64_t offset,
bpf_attach_type type);
StatusTuple detach_kprobe_event(const std::string& event, open_probe_t& attr);
StatusTuple detach_uprobe_event(const std::string& event, open_probe_t& attr);
StatusTuple detach_tracepoint_event(const std::string& tracepoint,
open_probe_t& attr);
std::string attach_type_debug(bpf_attach_type type) {
switch (type) {
case bpf_attach_type::probe_entry:
return "";
case bpf_attach_type::probe_return:
return "return ";
}
return "ERROR";
}
std::string attach_type_prefix(bpf_attach_type type) {
switch (type) {
case bpf_attach_type::probe_entry:
return "p";
case bpf_attach_type::probe_return:
return "r";
}
return "ERROR";
}
static bool kprobe_event_validator(char c) {
return (c != '+') && (c != '.');
}
static bool uprobe_path_validator(char c) {
return std::isalpha(c) || std::isdigit(c) || (c == '_');
}
StatusTuple check_binary_symbol(const std::string& binary_path,
const std::string& symbol,
uint64_t symbol_addr, bcc_symbol* output);
std::unique_ptr<BPFModule> bpf_module_;
std::map<std::string, int> funcs_;
std::map<std::string, open_probe_t> kprobes_;
std::map<std::string, open_probe_t> uprobes_;
std::map<std::string, open_probe_t> tracepoints_;
std::map<std::string, BPFPerfBuffer*> perf_buffers_;
};
} // namespace ebpf
/*
* Copyright (c) 2016 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <errno.h>
#include <unistd.h>
#include <cstring>
#include <iostream>
#include "BPFTable.h"
#include "bcc_syms.h"
#include "common.h"
#include "exception.h"
#include "libbpf.h"
#include "perf_reader.h"
namespace ebpf {
BPFStackTable::~BPFStackTable() {
for (auto it : pid_sym_)
bcc_free_symcache(it.second, it.first);
}
std::vector<intptr_t> BPFStackTable::get_stack_addr(int stack_id) {
std::vector<intptr_t> res;
stacktrace_t stack;
if (!lookup(&stack_id, &stack))
return res;
for (int i = 0; (i < BPF_MAX_STACK_DEPTH) && (stack.ip[i] != 0); i++)
res.push_back(stack.ip[i]);
return res;
}
std::vector<std::string> BPFStackTable::get_stack_symbol(int stack_id,
int pid) {
auto addresses = get_stack_addr(stack_id);
std::vector<std::string> res;
res.reserve(addresses.size());
if (pid < 0)
pid = -1;
if (pid_sym_.find(pid) == pid_sym_.end())
pid_sym_[pid] = bcc_symcache_new(pid);
void* cache = pid_sym_[pid];
bcc_symbol symbol;
for (auto addr : addresses)
if (bcc_symcache_resolve(cache, addr, &symbol) != 0)
res.push_back("[UNKNOWN]");
else
res.push_back(symbol.demangle_name);
return res;
}
StatusTuple BPFPerfBuffer::open_on_cpu(perf_reader_raw_cb cb, int cpu,
void* cb_cookie) {
if (cpu_readers_.find(cpu) != cpu_readers_.end())
return mkstatus(-1, "Perf buffer already open on CPU %d", cpu);
auto reader =
static_cast<perf_reader*>(bpf_open_perf_buffer(cb, cb_cookie, -1, cpu));
if (reader == nullptr)
return mkstatus(-1, "Unable to construct perf reader");
int reader_fd = perf_reader_fd(reader);
if (!update(&cpu, &reader_fd)) {
perf_reader_free(static_cast<void*>(reader));
return mkstatus(-1, "Unable to open perf buffer on CPU %d: %s", cpu,
strerror(errno));
}
cpu_readers_[cpu] = static_cast<perf_reader*>(reader);
return mkstatus(0);
}
StatusTuple BPFPerfBuffer::open(perf_reader_raw_cb cb, void* cb_cookie) {
for (int i = 0; i < sysconf(_SC_NPROCESSORS_ONLN); i++)
TRY2(open_on_cpu(cb, i, cb_cookie));
return mkstatus(0);
}
StatusTuple BPFPerfBuffer::close_on_cpu(int cpu) {
auto it = cpu_readers_.find(cpu);
if (it == cpu_readers_.end())
return mkstatus(0);
perf_reader_free(static_cast<void*>(it->second));
if (!remove(const_cast<int*>(&(it->first))))
return mkstatus(-1, "Unable to close perf buffer on CPU %d", it->first);
cpu_readers_.erase(it);
return mkstatus(0);
}
StatusTuple BPFPerfBuffer::close() {
std::string errors;
bool has_error = false;
for (int i = 0; i < sysconf(_SC_NPROCESSORS_ONLN); i++) {
auto res = close_on_cpu(i);
if (std::get<0>(res) != 0) {
errors += "Failed to close CPU" + std::to_string(i) + " perf buffer: ";
errors += std::get<1>(res) + "\n";
has_error = true;
}
}
if (has_error)
return mkstatus(-1, errors);
return mkstatus(0);
}
void BPFPerfBuffer::poll(int timeout) {
perf_reader* readers[cpu_readers_.size()];
int i = 0;
for (auto it : cpu_readers_)
readers[i++] = it.second;
perf_reader_poll(cpu_readers_.size(), readers, timeout);
}
BPFPerfBuffer::~BPFPerfBuffer() {
auto res = close();
if (std::get<0>(res) != 0)
std::cerr << "Failed to close all perf buffer on destruction: "
<< std::get<1>(res) << std::endl;
}
} // namespace ebpf
/*
* Copyright (c) 2016 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <exception>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "bpf_module.h"
#include "common.h"
#include "libbpf.h"
#include "perf_reader.h"
namespace ebpf {
template <class KeyType, class ValueType>
class BPFTableBase {
public:
size_t capacity() { return capacity_; }
protected:
BPFTableBase(BPFModule* bpf_module, const std::string& name) {
size_t id_ = bpf_module->table_id(name);
if (id_ >= bpf_module->num_tables())
throw std::invalid_argument("Table " + name + " does not exist");
fd_ = bpf_module->table_fd(id_);
capacity_ = bpf_module->table_max_entries(id_);
};
bool lookup(KeyType* key, ValueType* value) {
return bpf_lookup_elem(fd_, static_cast<void*>(key),
static_cast<void*>(value)) >= 0;
}
bool next(KeyType* key, KeyType* next_key) {
return bpf_get_next_key(fd_, static_cast<void*>(key),
static_cast<void*>(next_key)) >= 0;
}
bool update(KeyType* key, ValueType* value) {
return bpf_update_elem(fd_, static_cast<void*>(key),
static_cast<void*>(value), 0) >= 0;
}
bool remove(KeyType* key) {
return bpf_delete_elem(fd_, static_cast<void*>(key)) >= 0;
}
int fd_;
size_t capacity_;
};
template <class KeyType, class ValueType>
class BPFHashTable : protected BPFTableBase<KeyType, ValueType> {
public:
BPFHashTable(BPFModule* bpf_module, const std::string& name)
: BPFTableBase<KeyType, ValueType>(bpf_module, name) {}
ValueType get_value(const KeyType& key) {
ValueType res;
if (!this->lookup(const_cast<KeyType*>(&key), &res))
throw std::invalid_argument("Key does not exist in the table");
return res;
}
ValueType operator[](const KeyType& key) { return get_value(key); }
std::vector<std::pair<KeyType, ValueType>> get_table_offline() {
std::vector<std::pair<KeyType, ValueType>> res;
KeyType cur, nxt;
ValueType value;
while (true) {
if (!this->next(&cur, &nxt))
break;
if (!this->lookup(&nxt, &value))
break;
res.emplace_back(nxt, value);
std::swap(cur, nxt);
}
return res;
}
};
// From src/cc/export/helpers.h
static const int BPF_MAX_STACK_DEPTH = 127;
struct stacktrace_t {
intptr_t ip[BPF_MAX_STACK_DEPTH];
};
class BPFStackTable : protected BPFTableBase<int, stacktrace_t> {
public:
BPFStackTable(BPFModule* bpf_module, const std::string& name)
: BPFTableBase<int, stacktrace_t>(bpf_module, name) {}
~BPFStackTable();
std::vector<intptr_t> get_stack_addr(int stack_id);
std::vector<std::string> get_stack_symbol(int stack_id, int pid);
private:
std::map<int, void*> pid_sym_;
};
class BPFPerfBuffer : protected BPFTableBase<int, int> {
public:
BPFPerfBuffer(BPFModule* bpf_module, const std::string& name)
: BPFTableBase<int, int>(bpf_module, name) {}
~BPFPerfBuffer();
StatusTuple open(perf_reader_raw_cb cb, void* cb_cookie);
StatusTuple close();
void poll(int timeout);
private:
StatusTuple open_on_cpu(perf_reader_raw_cb cb, int cpu, void* cb_cookie);
StatusTuple close_on_cpu(int cpu);
std::map<int, perf_reader*> cpu_readers_;
};
} // namespace ebpf
......@@ -35,12 +35,12 @@ if (CMAKE_COMPILER_IS_GNUCC AND LIBCLANG_ISSTATIC)
endif()
endif()
add_library(bcc-shared SHARED bpf_common.cc bpf_module.cc libbpf.c perf_reader.c shared_table.cc exported_files.cc bcc_elf.c bcc_perf_map.c bcc_proc.c bcc_syms.cc usdt_args.cc usdt.cc)
add_library(bcc-shared SHARED bpf_common.cc bpf_module.cc libbpf.c perf_reader.c shared_table.cc exported_files.cc bcc_elf.c bcc_perf_map.c bcc_proc.c bcc_syms.cc usdt_args.cc usdt.cc BPF.cc BPFTable.cc)
set_target_properties(bcc-shared PROPERTIES VERSION ${REVISION_LAST} SOVERSION 0)
set_target_properties(bcc-shared PROPERTIES OUTPUT_NAME bcc)
add_library(bcc-loader-static libbpf.c perf_reader.c bcc_elf.c bcc_perf_map.c bcc_proc.c)
add_library(bcc-static STATIC bpf_common.cc bpf_module.cc shared_table.cc exported_files.cc bcc_syms.cc usdt_args.cc usdt.cc)
add_library(bcc-static STATIC bpf_common.cc bpf_module.cc shared_table.cc exported_files.cc bcc_syms.cc usdt_args.cc usdt.cc BPF.cc BPFTable.cc)
set_target_properties(bcc-static PROPERTIES OUTPUT_NAME bcc)
set(llvm_raw_libs bitwriter bpfcodegen irreader linker
......@@ -63,7 +63,7 @@ target_link_libraries(bcc-static b_frontend clang_frontend bcc-loader-static ${c
install(TARGETS bcc-shared LIBRARY COMPONENT libbcc
DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES bpf_common.h bpf_module.h bcc_syms.h common.h exception.h libbpf.h perf_reader.h COMPONENT libbcc
install(FILES bpf_common.h bpf_module.h bcc_syms.h common.h exception.h libbpf.h perf_reader.h BPF.h BPFTable.h COMPONENT libbcc
DESTINATION include/bcc)
install(DIRECTORY compat/linux/ COMPONENT libbcc
DESTINATION include/bcc/compat/linux
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment