Commit 1fe85d07 authored by yonghong-song's avatar yonghong-song Committed by GitHub

Merge pull request #1607 from palmtenor/no_reader

Remove PERF_SAMPLE_CALLCHAIN logic from TRACEPOINT events
parents abef8350 d0e48edb
...@@ -159,8 +159,7 @@ StatusTuple BPF::detach_all() { ...@@ -159,8 +159,7 @@ StatusTuple BPF::detach_all() {
StatusTuple BPF::attach_kprobe(const std::string& kernel_func, StatusTuple BPF::attach_kprobe(const std::string& kernel_func,
const std::string& probe_func, const std::string& probe_func,
bpf_probe_attach_type attach_type, bpf_probe_attach_type attach_type) {
perf_reader_cb cb, void* cb_cookie) {
std::string probe_event = get_kprobe_event(kernel_func, attach_type); std::string probe_event = get_kprobe_event(kernel_func, attach_type);
if (kprobes_.find(probe_event) != kprobes_.end()) if (kprobes_.find(probe_event) != kprobes_.end())
return StatusTuple(-1, "kprobe %s already attached", probe_event.c_str()); return StatusTuple(-1, "kprobe %s already attached", probe_event.c_str());
...@@ -168,10 +167,10 @@ StatusTuple BPF::attach_kprobe(const std::string& kernel_func, ...@@ -168,10 +167,10 @@ StatusTuple BPF::attach_kprobe(const std::string& kernel_func,
int probe_fd; int probe_fd;
TRY2(load_func(probe_func, BPF_PROG_TYPE_KPROBE, probe_fd)); TRY2(load_func(probe_func, BPF_PROG_TYPE_KPROBE, probe_fd));
void* res = bpf_attach_kprobe(probe_fd, attach_type, probe_event.c_str(), int res_fd = bpf_attach_kprobe(probe_fd, attach_type, probe_event.c_str(),
kernel_func.c_str(), cb, cb_cookie); kernel_func.c_str());
if (!res) { if (res_fd < 0) {
TRY2(unload_func(probe_func)); TRY2(unload_func(probe_func));
return StatusTuple(-1, "Unable to attach %skprobe for %s using %s", return StatusTuple(-1, "Unable to attach %skprobe for %s using %s",
attach_type_debug(attach_type).c_str(), attach_type_debug(attach_type).c_str(),
...@@ -179,7 +178,7 @@ StatusTuple BPF::attach_kprobe(const std::string& kernel_func, ...@@ -179,7 +178,7 @@ StatusTuple BPF::attach_kprobe(const std::string& kernel_func,
} }
open_probe_t p = {}; open_probe_t p = {};
p.reader_ptr = res; p.perf_event_fd = res_fd;
p.func = probe_func; p.func = probe_func;
kprobes_[probe_event] = std::move(p); kprobes_[probe_event] = std::move(p);
return StatusTuple(0); return StatusTuple(0);
...@@ -189,8 +188,7 @@ StatusTuple BPF::attach_uprobe(const std::string& binary_path, ...@@ -189,8 +188,7 @@ StatusTuple BPF::attach_uprobe(const std::string& binary_path,
const std::string& symbol, const std::string& symbol,
const std::string& probe_func, const std::string& probe_func,
uint64_t symbol_addr, uint64_t symbol_addr,
bpf_probe_attach_type attach_type, pid_t pid, bpf_probe_attach_type attach_type, pid_t pid) {
perf_reader_cb cb, void* cb_cookie) {
std::string module; std::string module;
uint64_t offset; uint64_t offset;
TRY2(check_binary_symbol(binary_path, symbol, symbol_addr, module, offset)); TRY2(check_binary_symbol(binary_path, symbol, symbol_addr, module, offset));
...@@ -202,11 +200,10 @@ StatusTuple BPF::attach_uprobe(const std::string& binary_path, ...@@ -202,11 +200,10 @@ StatusTuple BPF::attach_uprobe(const std::string& binary_path,
int probe_fd; int probe_fd;
TRY2(load_func(probe_func, BPF_PROG_TYPE_KPROBE, probe_fd)); TRY2(load_func(probe_func, BPF_PROG_TYPE_KPROBE, probe_fd));
void* res = int res_fd = bpf_attach_uprobe(probe_fd, attach_type, probe_event.c_str(),
bpf_attach_uprobe(probe_fd, attach_type, probe_event.c_str(), binary_path.c_str(), offset, pid);
binary_path.c_str(), offset, pid, cb, cb_cookie);
if (!res) { if (res_fd < 0) {
TRY2(unload_func(probe_func)); TRY2(unload_func(probe_func));
return StatusTuple( return StatusTuple(
-1, -1,
...@@ -216,7 +213,7 @@ StatusTuple BPF::attach_uprobe(const std::string& binary_path, ...@@ -216,7 +213,7 @@ StatusTuple BPF::attach_uprobe(const std::string& binary_path,
} }
open_probe_t p = {}; open_probe_t p = {};
p.reader_ptr = res; p.perf_event_fd = res_fd;
p.func = probe_func; p.func = probe_func;
uprobes_[probe_event] = std::move(p); uprobes_[probe_event] = std::move(p);
return StatusTuple(0); return StatusTuple(0);
...@@ -253,8 +250,7 @@ StatusTuple BPF::attach_usdt(const USDT& usdt, pid_t pid) { ...@@ -253,8 +250,7 @@ StatusTuple BPF::attach_usdt(const USDT& usdt, pid_t pid) {
} }
StatusTuple BPF::attach_tracepoint(const std::string& tracepoint, StatusTuple BPF::attach_tracepoint(const std::string& tracepoint,
const std::string& probe_func, const std::string& probe_func) {
perf_reader_cb cb, void* cb_cookie) {
if (tracepoints_.find(tracepoint) != tracepoints_.end()) if (tracepoints_.find(tracepoint) != tracepoints_.end())
return StatusTuple(-1, "Tracepoint %s already attached", return StatusTuple(-1, "Tracepoint %s already attached",
tracepoint.c_str()); tracepoint.c_str());
...@@ -268,17 +264,17 @@ StatusTuple BPF::attach_tracepoint(const std::string& tracepoint, ...@@ -268,17 +264,17 @@ StatusTuple BPF::attach_tracepoint(const std::string& tracepoint,
int probe_fd; int probe_fd;
TRY2(load_func(probe_func, BPF_PROG_TYPE_TRACEPOINT, probe_fd)); TRY2(load_func(probe_func, BPF_PROG_TYPE_TRACEPOINT, probe_fd));
void* res = bpf_attach_tracepoint(probe_fd, tp_category.c_str(), int res_fd = bpf_attach_tracepoint(probe_fd, tp_category.c_str(),
tp_name.c_str(), cb, cb_cookie); tp_name.c_str());
if (!res) { if (res_fd < 0) {
TRY2(unload_func(probe_func)); TRY2(unload_func(probe_func));
return StatusTuple(-1, "Unable to attach Tracepoint %s using %s", return StatusTuple(-1, "Unable to attach Tracepoint %s using %s",
tracepoint.c_str(), probe_func.c_str()); tracepoint.c_str(), probe_func.c_str());
} }
open_probe_t p = {}; open_probe_t p = {};
p.reader_ptr = res; p.perf_event_fd = res_fd;
p.func = probe_func; p.func = probe_func;
tracepoints_[tracepoint] = std::move(p); tracepoints_[tracepoint] = std::move(p);
return StatusTuple(0); return StatusTuple(0);
...@@ -558,10 +554,7 @@ std::string BPF::get_uprobe_event(const std::string& binary_path, ...@@ -558,10 +554,7 @@ std::string BPF::get_uprobe_event(const std::string& binary_path,
StatusTuple BPF::detach_kprobe_event(const std::string& event, StatusTuple BPF::detach_kprobe_event(const std::string& event,
open_probe_t& attr) { open_probe_t& attr) {
if (attr.reader_ptr) { bpf_close_perf_event_fd(attr.perf_event_fd);
perf_reader_free(attr.reader_ptr);
attr.reader_ptr = nullptr;
}
TRY2(unload_func(attr.func)); TRY2(unload_func(attr.func));
if (bpf_detach_kprobe(event.c_str()) < 0) if (bpf_detach_kprobe(event.c_str()) < 0)
return StatusTuple(-1, "Unable to detach kprobe %s", event.c_str()); return StatusTuple(-1, "Unable to detach kprobe %s", event.c_str());
...@@ -570,10 +563,7 @@ StatusTuple BPF::detach_kprobe_event(const std::string& event, ...@@ -570,10 +563,7 @@ StatusTuple BPF::detach_kprobe_event(const std::string& event,
StatusTuple BPF::detach_uprobe_event(const std::string& event, StatusTuple BPF::detach_uprobe_event(const std::string& event,
open_probe_t& attr) { open_probe_t& attr) {
if (attr.reader_ptr) { bpf_close_perf_event_fd(attr.perf_event_fd);
perf_reader_free(attr.reader_ptr);
attr.reader_ptr = nullptr;
}
TRY2(unload_func(attr.func)); TRY2(unload_func(attr.func));
if (bpf_detach_uprobe(event.c_str()) < 0) if (bpf_detach_uprobe(event.c_str()) < 0)
return StatusTuple(-1, "Unable to detach uprobe %s", event.c_str()); return StatusTuple(-1, "Unable to detach uprobe %s", event.c_str());
...@@ -582,10 +572,7 @@ StatusTuple BPF::detach_uprobe_event(const std::string& event, ...@@ -582,10 +572,7 @@ StatusTuple BPF::detach_uprobe_event(const std::string& event,
StatusTuple BPF::detach_tracepoint_event(const std::string& tracepoint, StatusTuple BPF::detach_tracepoint_event(const std::string& tracepoint,
open_probe_t& attr) { open_probe_t& attr) {
if (attr.reader_ptr) { bpf_close_perf_event_fd(attr.perf_event_fd);
perf_reader_free(attr.reader_ptr);
attr.reader_ptr = nullptr;
}
TRY2(unload_func(attr.func)); TRY2(unload_func(attr.func));
// TODO: bpf_detach_tracepoint currently does nothing. // TODO: bpf_detach_tracepoint currently does nothing.
......
...@@ -34,7 +34,7 @@ static const int DEFAULT_PERF_BUFFER_PAGE_CNT = 8; ...@@ -34,7 +34,7 @@ static const int DEFAULT_PERF_BUFFER_PAGE_CNT = 8;
namespace ebpf { namespace ebpf {
struct open_probe_t { struct open_probe_t {
void* reader_ptr; int perf_event_fd;
std::string func; std::string func;
std::map<int, int>* per_cpu_fd; std::map<int, int>* per_cpu_fd;
}; };
...@@ -57,9 +57,7 @@ class BPF { ...@@ -57,9 +57,7 @@ class BPF {
StatusTuple attach_kprobe(const std::string& kernel_func, StatusTuple attach_kprobe(const std::string& kernel_func,
const std::string& probe_func, const std::string& probe_func,
bpf_probe_attach_type = BPF_PROBE_ENTRY, bpf_probe_attach_type = BPF_PROBE_ENTRY);
perf_reader_cb cb = nullptr,
void* cb_cookie = nullptr);
StatusTuple detach_kprobe( StatusTuple detach_kprobe(
const std::string& kernel_func, const std::string& kernel_func,
bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY); bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY);
...@@ -69,8 +67,7 @@ class BPF { ...@@ -69,8 +67,7 @@ class BPF {
const std::string& probe_func, const std::string& probe_func,
uint64_t symbol_addr = 0, uint64_t symbol_addr = 0,
bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY, bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY,
pid_t pid = -1, perf_reader_cb cb = nullptr, pid_t pid = -1);
void* cb_cookie = nullptr);
StatusTuple detach_uprobe(const std::string& binary_path, StatusTuple detach_uprobe(const std::string& binary_path,
const std::string& symbol, uint64_t symbol_addr = 0, const std::string& symbol, uint64_t symbol_addr = 0,
bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY, bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY,
...@@ -79,9 +76,7 @@ class BPF { ...@@ -79,9 +76,7 @@ class BPF {
StatusTuple detach_usdt(const USDT& usdt); StatusTuple detach_usdt(const USDT& usdt);
StatusTuple attach_tracepoint(const std::string& tracepoint, StatusTuple attach_tracepoint(const std::string& tracepoint,
const std::string& probe_func, const std::string& probe_func);
perf_reader_cb cb = nullptr,
void* cb_cookie = nullptr);
StatusTuple detach_tracepoint(const std::string& tracepoint); StatusTuple detach_tracepoint(const std::string& tracepoint);
StatusTuple attach_perf_event(uint32_t ev_type, uint32_t ev_config, StatusTuple attach_perf_event(uint32_t ev_type, uint32_t ev_config,
......
...@@ -151,8 +151,6 @@ static struct bpf_helper helpers[] = { ...@@ -151,8 +151,6 @@ static struct bpf_helper helpers[] = {
{"sock_ops_cb_flags_set", "4.16"}, {"sock_ops_cb_flags_set", "4.16"},
}; };
static int probe_perf_reader_page_cnt = 8;
static uint64_t ptr_to_u64(void *ptr) static uint64_t ptr_to_u64(void *ptr)
{ {
return (uint64_t) (unsigned long) ptr; return (uint64_t) (unsigned long) ptr;
...@@ -682,7 +680,6 @@ static int bpf_try_perf_event_open_with_probe(const char *name, uint64_t offs, ...@@ -682,7 +680,6 @@ static int bpf_try_perf_event_open_with_probe(const char *name, uint64_t offs,
if (type < 0 || is_return_bit < 0) if (type < 0 || is_return_bit < 0)
return -1; return -1;
attr.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_CALLCHAIN;
attr.sample_period = 1; attr.sample_period = 1;
attr.wakeup_events = 1; attr.wakeup_events = 1;
if (is_return) if (is_return)
...@@ -724,16 +721,23 @@ static int bpf_try_perf_event_open_with_probe(const char *name, uint64_t offs, ...@@ -724,16 +721,23 @@ static int bpf_try_perf_event_open_with_probe(const char *name, uint64_t offs,
PERF_FLAG_FD_CLOEXEC); PERF_FLAG_FD_CLOEXEC);
} }
static int bpf_attach_tracing_event(int progfd, const char *event_path, // When a valid Perf Event FD provided through pfd, it will be used to enable
struct perf_reader *reader, int pid, // and attach BPF program to the event, and event_path will be ignored.
int pfd) // Otherwise, event_path is expected to contain the path to the event in debugfs
// and it will be used to open the Perf Event FD.
// In either case, if the attach partially failed (such as issue with the
// ioctl operations), the **caller** need to clean up the Perf Event FD, either
// provided by the caller or opened here.
static int bpf_attach_tracing_event(int progfd, const char *event_path, int pid,
int *pfd)
{ {
int efd, cpu = 0; int efd, cpu = 0;
ssize_t bytes; ssize_t bytes;
char buf[PATH_MAX]; char buf[PATH_MAX];
struct perf_event_attr attr = {}; struct perf_event_attr attr = {};
// Caller did not provided a valid Perf Event FD. Create one with the debugfs
if (pfd < 0) { // event path provided.
if (*pfd < 0) {
snprintf(buf, sizeof(buf), "%s/id", event_path); snprintf(buf, sizeof(buf), "%s/id", event_path);
efd = open(buf, O_RDONLY, 0); efd = open(buf, O_RDONLY, 0);
if (efd < 0) { if (efd < 0) {
...@@ -751,7 +755,6 @@ static int bpf_attach_tracing_event(int progfd, const char *event_path, ...@@ -751,7 +755,6 @@ static int bpf_attach_tracing_event(int progfd, const char *event_path,
buf[bytes] = '\0'; buf[bytes] = '\0';
attr.config = strtol(buf, NULL, 0); attr.config = strtol(buf, NULL, 0);
attr.type = PERF_TYPE_TRACEPOINT; attr.type = PERF_TYPE_TRACEPOINT;
attr.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_CALLCHAIN;
attr.sample_period = 1; attr.sample_period = 1;
attr.wakeup_events = 1; attr.wakeup_events = 1;
// PID filter is only possible for uprobe events. // PID filter is only possible for uprobe events.
...@@ -762,22 +765,18 @@ static int bpf_attach_tracing_event(int progfd, const char *event_path, ...@@ -762,22 +765,18 @@ static int bpf_attach_tracing_event(int progfd, const char *event_path,
// Tracing events do not do CPU filtering in any cases. // Tracing events do not do CPU filtering in any cases.
if (pid != -1) if (pid != -1)
cpu = -1; cpu = -1;
pfd = syscall(__NR_perf_event_open, &attr, pid, cpu, -1 /* group_fd */, PERF_FLAG_FD_CLOEXEC); *pfd = syscall(__NR_perf_event_open, &attr, pid, cpu, -1 /* group_fd */, PERF_FLAG_FD_CLOEXEC);
if (pfd < 0) { if (*pfd < 0) {
fprintf(stderr, "perf_event_open(%s/id): %s\n", event_path, strerror(errno)); fprintf(stderr, "perf_event_open(%s/id): %s\n", event_path, strerror(errno));
return -1; return -1;
} }
} }
perf_reader_set_fd(reader, pfd);
if (perf_reader_mmap(reader, attr.type, attr.sample_type) < 0)
return -1;
if (ioctl(pfd, PERF_EVENT_IOC_SET_BPF, progfd) < 0) { if (ioctl(*pfd, PERF_EVENT_IOC_SET_BPF, progfd) < 0) {
perror("ioctl(PERF_EVENT_IOC_SET_BPF)"); perror("ioctl(PERF_EVENT_IOC_SET_BPF)");
return -1; return -1;
} }
if (ioctl(pfd, PERF_EVENT_IOC_ENABLE, 0) < 0) { if (ioctl(*pfd, PERF_EVENT_IOC_ENABLE, 0) < 0) {
perror("ioctl(PERF_EVENT_IOC_ENABLE)"); perror("ioctl(PERF_EVENT_IOC_ENABLE)");
return -1; return -1;
} }
...@@ -785,24 +784,19 @@ static int bpf_attach_tracing_event(int progfd, const char *event_path, ...@@ -785,24 +784,19 @@ static int bpf_attach_tracing_event(int progfd, const char *event_path,
return 0; return 0;
} }
void *bpf_attach_kprobe(int progfd, enum bpf_probe_attach_type attach_type, int bpf_attach_kprobe(int progfd, enum bpf_probe_attach_type attach_type,
const char *ev_name, const char *fn_name, const char *ev_name, const char *fn_name)
perf_reader_cb cb, void *cb_cookie)
{ {
int kfd; int kfd, pfd = -1;
int pfd;
char buf[256]; char buf[256];
char event_alias[128]; char event_alias[128];
struct perf_reader *reader = NULL;
static char *event_type = "kprobe"; static char *event_type = "kprobe";
reader = perf_reader_new(cb, NULL, NULL, cb_cookie, probe_perf_reader_page_cnt); // Try create the kprobe Perf Event with perf_event_open API.
if (!reader)
goto error;
pfd = bpf_try_perf_event_open_with_probe(fn_name, 0, -1, event_type, pfd = bpf_try_perf_event_open_with_probe(fn_name, 0, -1, event_type,
attach_type != BPF_PROBE_ENTRY); attach_type != BPF_PROBE_ENTRY);
// If failed, most likely Kernel doesn't support the new perf_event_open API
// yet. Try create the event using debugfs.
if (pfd < 0) { if (pfd < 0) {
snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/%s_events", event_type); snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/%s_events", event_type);
kfd = open(buf, O_WRONLY | O_APPEND, 0); kfd = open(buf, O_WRONLY | O_APPEND, 0);
...@@ -823,15 +817,16 @@ void *bpf_attach_kprobe(int progfd, enum bpf_probe_attach_type attach_type, ...@@ -823,15 +817,16 @@ void *bpf_attach_kprobe(int progfd, enum bpf_probe_attach_type attach_type,
close(kfd); close(kfd);
snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%ss/%s", event_type, event_alias); snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%ss/%s", event_type, event_alias);
} }
if (bpf_attach_tracing_event(progfd, buf, reader, -1 /* PID */, pfd) < 0) // If perf_event_open succeeded, bpf_attach_tracing_event will use the created
goto error; // Perf Event FD directly and buf would be empty and unused.
// Otherwise it will read the event ID from the path in buf, create the
return reader; // Perf Event event using that ID, and updated value of pfd.
if (bpf_attach_tracing_event(progfd, buf, -1 /* PID */, &pfd) == 0)
return pfd;
error: error:
perf_reader_free(reader); bpf_close_perf_event_fd(pfd);
return NULL; return -1;
} }
static int enter_mount_ns(int pid) { static int enter_mount_ns(int pid) {
...@@ -895,24 +890,19 @@ static void exit_mount_ns(int fd) { ...@@ -895,24 +890,19 @@ static void exit_mount_ns(int fd) {
perror("setns"); perror("setns");
} }
void *bpf_attach_uprobe(int progfd, enum bpf_probe_attach_type attach_type, int bpf_attach_uprobe(int progfd, enum bpf_probe_attach_type attach_type,
const char *ev_name, const char *binary_path, const char *ev_name, const char *binary_path,
uint64_t offset, pid_t pid, perf_reader_cb cb, uint64_t offset, pid_t pid)
void *cb_cookie)
{ {
char buf[PATH_MAX]; char buf[PATH_MAX];
char event_alias[PATH_MAX]; char event_alias[PATH_MAX];
struct perf_reader *reader = NULL;
static char *event_type = "uprobe"; static char *event_type = "uprobe";
int res, kfd = -1, ns_fd = -1; int res, kfd = -1, pfd = -1, ns_fd = -1;
int pfd; // Try create the uprobe Perf Event with perf_event_open API.
reader = perf_reader_new(cb, NULL, NULL, cb_cookie, probe_perf_reader_page_cnt);
if (!reader)
goto error;
pfd = bpf_try_perf_event_open_with_probe(binary_path, offset, pid, event_type, pfd = bpf_try_perf_event_open_with_probe(binary_path, offset, pid, event_type,
attach_type != BPF_PROBE_ENTRY); attach_type != BPF_PROBE_ENTRY);
// If failed, most likely Kernel doesn't support the new perf_event_open API
// yet. Try create the event using debugfs.
if (pfd < 0) { if (pfd < 0) {
snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/%s_events", event_type); snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/%s_events", event_type);
kfd = open(buf, O_WRONLY | O_APPEND, 0); kfd = open(buf, O_WRONLY | O_APPEND, 0);
...@@ -940,22 +930,25 @@ void *bpf_attach_uprobe(int progfd, enum bpf_probe_attach_type attach_type, ...@@ -940,22 +930,25 @@ void *bpf_attach_uprobe(int progfd, enum bpf_probe_attach_type attach_type,
goto error; goto error;
} }
close(kfd); close(kfd);
kfd = -1;
exit_mount_ns(ns_fd); exit_mount_ns(ns_fd);
ns_fd = -1; ns_fd = -1;
snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%ss/%s", event_type, event_alias); snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%ss/%s", event_type, event_alias);
} }
if (bpf_attach_tracing_event(progfd, buf, reader, pid, pfd) < 0) // If perf_event_open succeeded, bpf_attach_tracing_event will use the created
goto error; // Perf Event FD directly and buf would be empty and unused.
// Otherwise it will read the event ID from the path in buf, create the
return reader; // Perf Event event using that ID, and updated value of pfd.
if (bpf_attach_tracing_event(progfd, buf, pid, &pfd) == 0)
return pfd;
error: error:
if (kfd >= 0) if (kfd >= 0)
close(kfd); close(kfd);
exit_mount_ns(ns_fd); exit_mount_ns(ns_fd);
perf_reader_free(reader); bpf_close_perf_event_fd(pfd);
return NULL; return -1;
} }
static int bpf_detach_probe(const char *ev_name, const char *event_type) static int bpf_detach_probe(const char *ev_name, const char *event_type)
...@@ -1036,26 +1029,19 @@ int bpf_detach_uprobe(const char *ev_name) ...@@ -1036,26 +1029,19 @@ int bpf_detach_uprobe(const char *ev_name)
} }
void *bpf_attach_tracepoint(int progfd, const char *tp_category, int bpf_attach_tracepoint(int progfd, const char *tp_category,
const char *tp_name, perf_reader_cb cb, const char *tp_name)
void *cb_cookie) { {
char buf[256]; char buf[256];
struct perf_reader *reader = NULL; int pfd = -1;
reader = perf_reader_new(cb, NULL, NULL, cb_cookie, probe_perf_reader_page_cnt);
if (!reader)
goto error;
snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/%s", snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/%s",
tp_category, tp_name); tp_category, tp_name);
if (bpf_attach_tracing_event(progfd, buf, reader, -1 /* PID */, -1 /* pfd */) < 0) if (bpf_attach_tracing_event(progfd, buf, -1 /* PID */, &pfd) == 0)
goto error; return pfd;
return reader; bpf_close_perf_event_fd(pfd);
return -1;
error:
perf_reader_free(reader);
return NULL;
} }
int bpf_detach_tracepoint(const char *tp_category, const char *tp_name) { int bpf_detach_tracepoint(const char *tp_category, const char *tp_name) {
...@@ -1071,7 +1057,7 @@ void * bpf_open_perf_buffer(perf_reader_raw_cb raw_cb, ...@@ -1071,7 +1057,7 @@ void * bpf_open_perf_buffer(perf_reader_raw_cb raw_cb,
struct perf_event_attr attr = {}; struct perf_event_attr attr = {};
struct perf_reader *reader = NULL; struct perf_reader *reader = NULL;
reader = perf_reader_new(NULL, raw_cb, lost_cb, cb_cookie, page_cnt); reader = perf_reader_new(raw_cb, lost_cb, cb_cookie, page_cnt);
if (!reader) if (!reader)
goto error; goto error;
...@@ -1088,7 +1074,7 @@ void * bpf_open_perf_buffer(perf_reader_raw_cb raw_cb, ...@@ -1088,7 +1074,7 @@ void * bpf_open_perf_buffer(perf_reader_raw_cb raw_cb,
} }
perf_reader_set_fd(reader, pfd); perf_reader_set_fd(reader, pfd);
if (perf_reader_mmap(reader, attr.type, attr.sample_type) < 0) if (perf_reader_mmap(reader) < 0)
goto error; goto error;
if (ioctl(pfd, PERF_EVENT_IOC_ENABLE, 0) < 0) { if (ioctl(pfd, PERF_EVENT_IOC_ENABLE, 0) < 0) {
......
...@@ -65,27 +65,20 @@ int bpf_attach_socket(int sockfd, int progfd); ...@@ -65,27 +65,20 @@ int bpf_attach_socket(int sockfd, int progfd);
* bind the raw socket to the interface 'name' */ * bind the raw socket to the interface 'name' */
int bpf_open_raw_sock(const char *name); int bpf_open_raw_sock(const char *name);
typedef void (*perf_reader_cb)(void *cb_cookie, int pid, uint64_t callchain_num,
void *callchain);
typedef void (*perf_reader_raw_cb)(void *cb_cookie, void *raw, int raw_size); typedef void (*perf_reader_raw_cb)(void *cb_cookie, void *raw, int raw_size);
typedef void (*perf_reader_lost_cb)(void *cb_cookie, uint64_t lost); typedef void (*perf_reader_lost_cb)(void *cb_cookie, uint64_t lost);
void *bpf_attach_kprobe(int progfd, enum bpf_probe_attach_type attach_type, int bpf_attach_kprobe(int progfd, enum bpf_probe_attach_type attach_type,
const char *ev_name, const char *fn_name, const char *ev_name, const char *fn_name);
perf_reader_cb cb, void *cb_cookie);
int bpf_detach_kprobe(const char *ev_name); int bpf_detach_kprobe(const char *ev_name);
void *bpf_attach_uprobe(int progfd, enum bpf_probe_attach_type attach_type, int bpf_attach_uprobe(int progfd, enum bpf_probe_attach_type attach_type,
const char *ev_name, const char *binary_path, const char *ev_name, const char *binary_path,
uint64_t offset, pid_t pid, perf_reader_cb cb, uint64_t offset, pid_t pid);
void *cb_cookie);
int bpf_detach_uprobe(const char *ev_name); int bpf_detach_uprobe(const char *ev_name);
void *bpf_attach_tracepoint(int progfd, const char *tp_category, int bpf_attach_tracepoint(int progfd, const char *tp_category,
const char *tp_name, perf_reader_cb cb, const char *tp_name);
void *cb_cookie);
int bpf_detach_tracepoint(const char *tp_category, const char *tp_name); int bpf_detach_tracepoint(const char *tp_category, const char *tp_name);
void * bpf_open_perf_buffer(perf_reader_raw_cb raw_cb, void * bpf_open_perf_buffer(perf_reader_raw_cb raw_cb,
......
...@@ -37,7 +37,6 @@ enum { ...@@ -37,7 +37,6 @@ enum {
}; };
struct perf_reader { struct perf_reader {
perf_reader_cb cb;
perf_reader_raw_cb raw_cb; perf_reader_raw_cb raw_cb;
perf_reader_lost_cb lost_cb; perf_reader_lost_cb lost_cb;
void *cb_cookie; // to be returned in the cb void *cb_cookie; // to be returned in the cb
...@@ -49,18 +48,14 @@ struct perf_reader { ...@@ -49,18 +48,14 @@ struct perf_reader {
int page_size; int page_size;
int page_cnt; int page_cnt;
int fd; int fd;
uint32_t type;
uint64_t sample_type;
}; };
struct perf_reader * perf_reader_new(perf_reader_cb cb, struct perf_reader * perf_reader_new(perf_reader_raw_cb raw_cb,
perf_reader_raw_cb raw_cb,
perf_reader_lost_cb lost_cb, perf_reader_lost_cb lost_cb,
void *cb_cookie, int page_cnt) { void *cb_cookie, int page_cnt) {
struct perf_reader *reader = calloc(1, sizeof(struct perf_reader)); struct perf_reader *reader = calloc(1, sizeof(struct perf_reader));
if (!reader) if (!reader)
return NULL; return NULL;
reader->cb = cb;
reader->raw_cb = raw_cb; reader->raw_cb = raw_cb;
reader->lost_cb = lost_cb; reader->lost_cb = lost_cb;
reader->cb_cookie = cb_cookie; reader->cb_cookie = cb_cookie;
...@@ -89,7 +84,7 @@ void perf_reader_free(void *ptr) { ...@@ -89,7 +84,7 @@ void perf_reader_free(void *ptr) {
} }
} }
int perf_reader_mmap(struct perf_reader *reader, unsigned type, unsigned long sample_type) { int perf_reader_mmap(struct perf_reader *reader) {
int mmap_size = reader->page_size * (reader->page_cnt + 1); int mmap_size = reader->page_size * (reader->page_cnt + 1);
if (reader->fd < 0) { if (reader->fd < 0) {
...@@ -102,8 +97,6 @@ int perf_reader_mmap(struct perf_reader *reader, unsigned type, unsigned long sa ...@@ -102,8 +97,6 @@ int perf_reader_mmap(struct perf_reader *reader, unsigned type, unsigned long sa
perror("mmap"); perror("mmap");
return -1; return -1;
} }
reader->type = type;
reader->sample_type = sample_type;
return 0; return 0;
} }
...@@ -120,69 +113,6 @@ struct perf_sample_trace_kprobe { ...@@ -120,69 +113,6 @@ struct perf_sample_trace_kprobe {
uint64_t ip; uint64_t ip;
}; };
static void parse_tracepoint(struct perf_reader *reader, void *data, int size) {
uint8_t *ptr = data;
struct perf_event_header *header = (void *)data;
struct perf_sample_trace_kprobe *tk = NULL;
uint64_t *callchain = NULL;
uint64_t num_callchain = 0;
ptr += sizeof(*header);
if (ptr > (uint8_t *)data + size) {
fprintf(stderr, "%s: corrupt sample header\n", __FUNCTION__);
return;
}
if (reader->sample_type & PERF_SAMPLE_CALLCHAIN) {
struct {
uint64_t nr;
uint64_t ips[0];
} *cc = (void *)ptr;
ptr += sizeof(cc->nr) + sizeof(*cc->ips) * cc->nr;
// size sanity check
if (ptr > (uint8_t *)data + size) {
fprintf(stderr, "%s: corrupt callchain sample\n", __FUNCTION__);
return;
}
int i;
// don't include magic numbers in the call chain
for (i = 0; i < cc->nr; ++i) {
if (cc->ips[i] == PERF_CONTEXT_USER)
break;
if (cc->ips[i] >= PERF_CONTEXT_MAX)
continue;
if (!callchain)
callchain = &cc->ips[i];
++num_callchain;
}
}
// for kprobes, raw samples just include the common data structure and the
// instruction pointer
if (reader->sample_type & PERF_SAMPLE_RAW) {
struct {
uint32_t size;
char data[0];
} *raw = (void *)ptr;
ptr += sizeof(raw->size) + raw->size;
if (ptr > (uint8_t *)data + size) {
fprintf(stderr, "%s: corrupt raw sample\n", __FUNCTION__);
return;
}
tk = (void *)raw->data;
}
// sanity check
if (ptr != (uint8_t *)data + size) {
fprintf(stderr, "%s: extra data at end of sample\n", __FUNCTION__);
return;
}
// call out to the user with the parsed data
if (reader->cb)
reader->cb(reader->cb_cookie, tk ? tk->common.pid : -1, num_callchain, callchain);
}
static void parse_sw(struct perf_reader *reader, void *data, int size) { static void parse_sw(struct perf_reader *reader, void *data, int size) {
uint8_t *ptr = data; uint8_t *ptr = data;
struct perf_event_header *header = (void *)data; struct perf_event_header *header = (void *)data;
...@@ -198,13 +128,11 @@ static void parse_sw(struct perf_reader *reader, void *data, int size) { ...@@ -198,13 +128,11 @@ static void parse_sw(struct perf_reader *reader, void *data, int size) {
return; return;
} }
if (reader->sample_type & PERF_SAMPLE_RAW) { raw = (void *)ptr;
raw = (void *)ptr; ptr += sizeof(raw->size) + raw->size;
ptr += sizeof(raw->size) + raw->size; if (ptr > (uint8_t *)data + size) {
if (ptr > (uint8_t *)data + size) { fprintf(stderr, "%s: corrupt raw sample\n", __FUNCTION__);
fprintf(stderr, "%s: corrupt raw sample\n", __FUNCTION__); return;
return;
}
} }
// sanity check // sanity check
...@@ -278,10 +206,7 @@ void perf_reader_event_read(struct perf_reader *reader) { ...@@ -278,10 +206,7 @@ void perf_reader_event_read(struct perf_reader *reader) {
fprintf(stderr, "Possibly lost %" PRIu64 " samples\n", lost); fprintf(stderr, "Possibly lost %" PRIu64 " samples\n", lost);
} }
} else if (e->type == PERF_RECORD_SAMPLE) { } else if (e->type == PERF_RECORD_SAMPLE) {
if (reader->type == PERF_TYPE_TRACEPOINT) parse_sw(reader, ptr, e->size);
parse_tracepoint(reader, ptr, e->size);
else if (reader->type == PERF_TYPE_SOFTWARE)
parse_sw(reader, ptr, e->size);
} else { } else {
fprintf(stderr, "%s: unknown sample type %d\n", __FUNCTION__, e->type); fprintf(stderr, "%s: unknown sample type %d\n", __FUNCTION__, e->type);
} }
......
...@@ -25,12 +25,11 @@ extern "C" { ...@@ -25,12 +25,11 @@ extern "C" {
struct perf_reader; struct perf_reader;
struct perf_reader * perf_reader_new(perf_reader_cb cb, struct perf_reader * perf_reader_new(perf_reader_raw_cb raw_cb,
perf_reader_raw_cb raw_cb,
perf_reader_lost_cb lost_cb, perf_reader_lost_cb lost_cb,
void *cb_cookie, int page_cnt); void *cb_cookie, int page_cnt);
void perf_reader_free(void *ptr); void perf_reader_free(void *ptr);
int perf_reader_mmap(struct perf_reader *reader, unsigned type, unsigned long sample_type); int perf_reader_mmap(struct perf_reader *reader);
void perf_reader_event_read(struct perf_reader *reader); void perf_reader_event_read(struct perf_reader *reader);
int perf_reader_poll(int num_readers, struct perf_reader **readers, int timeout); int perf_reader_poll(int num_readers, struct perf_reader **readers, int timeout);
int perf_reader_fd(struct perf_reader *reader); int perf_reader_fd(struct perf_reader *reader);
......
...@@ -24,6 +24,7 @@ local Bpf = class("BPF") ...@@ -24,6 +24,7 @@ local Bpf = class("BPF")
Bpf.static.open_kprobes = {} Bpf.static.open_kprobes = {}
Bpf.static.open_uprobes = {} Bpf.static.open_uprobes = {}
Bpf.static.perf_buffers = {}
Bpf.static.KPROBE_LIMIT = 1000 Bpf.static.KPROBE_LIMIT = 1000
Bpf.static.tracer_pipe = nil Bpf.static.tracer_pipe = nil
Bpf.static.DEFAULT_CFLAGS = { Bpf.static.DEFAULT_CFLAGS = {
...@@ -39,8 +40,8 @@ end ...@@ -39,8 +40,8 @@ end
function Bpf.static.cleanup() function Bpf.static.cleanup()
local function detach_all(probe_type, all_probes) local function detach_all(probe_type, all_probes)
for key, probe in pairs(all_probes) do for key, fd in pairs(all_probes) do
libbcc.perf_reader_free(probe) libbcc.bpf_close_perf_event_fd(fd)
-- skip bcc-specific kprobes -- skip bcc-specific kprobes
if not key:starts("bcc:") then if not key:starts("bcc:") then
if probe_type == "kprobes" then if probe_type == "kprobes" then
...@@ -55,6 +56,12 @@ function Bpf.static.cleanup() ...@@ -55,6 +56,12 @@ function Bpf.static.cleanup()
detach_all("kprobes", Bpf.static.open_kprobes) detach_all("kprobes", Bpf.static.open_kprobes)
detach_all("uprobes", Bpf.static.open_uprobes) detach_all("uprobes", Bpf.static.open_uprobes)
for key, perf_buffer in pairs(Bpf.static.perf_buffers) do
libbcc.perf_reader_free(perf_buffer)
Bpf.static.perf_buffers[key] = nil
end
if Bpf.static.tracer_pipe ~= nil then if Bpf.static.tracer_pipe ~= nil then
Bpf.static.tracer_pipe:close() Bpf.static.tracer_pipe:close()
end end
...@@ -189,9 +196,9 @@ function Bpf:attach_uprobe(args) ...@@ -189,9 +196,9 @@ function Bpf:attach_uprobe(args)
local retprobe = args.retprobe and 1 or 0 local retprobe = args.retprobe and 1 or 0
local res = libbcc.bpf_attach_uprobe(fn.fd, retprobe, ev_name, path, addr, local res = libbcc.bpf_attach_uprobe(fn.fd, retprobe, ev_name, path, addr,
args.pid or -1, nil, nil) -- TODO; reader callback args.pid or -1)
assert(res ~= nil, "failed to attach BPF to uprobe") assert(res >= 0, "failed to attach BPF to uprobe")
self:probe_store("uprobe", ev_name, res) self:probe_store("uprobe", ev_name, res)
return self return self
end end
...@@ -206,10 +213,9 @@ function Bpf:attach_kprobe(args) ...@@ -206,10 +213,9 @@ function Bpf:attach_kprobe(args)
local ev_name = string.format("%s_%s", ptype, event:gsub("[%+%.]", "_")) local ev_name = string.format("%s_%s", ptype, event:gsub("[%+%.]", "_"))
local retprobe = args.retprobe and 1 or 0 local retprobe = args.retprobe and 1 or 0
local res = libbcc.bpf_attach_kprobe(fn.fd, retprobe, ev_name, event, local res = libbcc.bpf_attach_kprobe(fn.fd, retprobe, ev_name, event)
nil, nil) -- TODO; reader callback
assert(res ~= nil, "failed to attach BPF to kprobe") assert(res >= 0, "failed to attach BPF to kprobe")
self:probe_store("kprobe", ev_name, res) self:probe_store("kprobe", ev_name, res)
return self return self
end end
...@@ -228,16 +234,22 @@ function Bpf:get_table(name, key_type, leaf_type) ...@@ -228,16 +234,22 @@ function Bpf:get_table(name, key_type, leaf_type)
return self.tables[name] return self.tables[name]
end end
function Bpf:probe_store(t, id, reader) function Bpf:probe_store(t, id, fd)
if t == "kprobe" then if t == "kprobe" then
Bpf.open_kprobes[id] = reader Bpf.open_kprobes[id] = fd
elseif t == "uprobe" then elseif t == "uprobe" then
Bpf.open_uprobes[id] = reader Bpf.open_uprobes[id] = fd
else else
error("unknown probe type '%s'" % t) error("unknown probe type '%s'" % t)
end end
log.info("%s -> %s", id, reader) log.info("%s -> %s", id, fd)
end
function Bpf:perf_buffer_store(t, id, reader)
Bpf.perf_buffers[id] = reader
log.info("%s -> %s", id, fd)
end end
function Bpf:probe_lookup(t, id) function Bpf:probe_lookup(t, id)
...@@ -250,32 +262,32 @@ function Bpf:probe_lookup(t, id) ...@@ -250,32 +262,32 @@ function Bpf:probe_lookup(t, id)
end end
end end
function Bpf:_kprobe_array() function Bpf:_perf_buffer_array()
local kprobe_count = table.count(Bpf.open_kprobes) local perf_buffer_count = table.count(Bpf.perf_buffers)
local readers = ffi.new("struct perf_reader*[?]", kprobe_count) local readers = ffi.new("struct perf_reader*[?]", perf_buffer_count)
local n = 0 local n = 0
for _, r in pairs(Bpf.open_kprobes) do for _, r in pairs(Bpf.perf_buffers) do
readers[n] = r readers[n] = r
n = n + 1 n = n + 1
end end
assert(n == kprobe_count) assert(n == perf_buffer_count)
return readers, n return readers, n
end end
function Bpf:kprobe_poll_loop() function Bpf:kprobe_poll_loop()
local probes, probe_count = self:_kprobe_array() local perf_buffer, perf_buffer_count = self:_perf_buffer_array()
return pcall(function() return pcall(function()
while true do while true do
libbcc.perf_reader_poll(probe_count, probes, -1) libbcc.perf_reader_poll(perf_buffer_count, perf_buffers, -1)
end end
end) end)
end end
function Bpf:kprobe_poll(timeout) function Bpf:kprobe_poll(timeout)
local probes, probe_count = self:_kprobe_array() local perf_buffer, perf_buffer_count = self:_perf_buffer_array()
libbcc.perf_reader_poll(probe_count, probes, timeout or -1) libbcc.perf_reader_poll(perf_buffer_count, perf_buffers, timeout or -1)
end end
return Bpf return Bpf
...@@ -39,23 +39,22 @@ int bpf_attach_socket(int sockfd, int progfd); ...@@ -39,23 +39,22 @@ int bpf_attach_socket(int sockfd, int progfd);
/* create RAW socket and bind to interface 'name' */ /* create RAW socket and bind to interface 'name' */
int bpf_open_raw_sock(const char *name); int bpf_open_raw_sock(const char *name);
typedef void (*perf_reader_cb)(void *cb_cookie, int pid, uint64_t callchain_num, void *callchain);
typedef void (*perf_reader_raw_cb)(void *cb_cookie, void *raw, int raw_size); typedef void (*perf_reader_raw_cb)(void *cb_cookie, void *raw, int raw_size);
typedef void (*perf_reader_lost_cb)(void *cb_cookie, uint64_t lost); typedef void (*perf_reader_lost_cb)(void *cb_cookie, uint64_t lost);
void *bpf_attach_kprobe(int progfd, int attach_type, const char *ev_name, int bpf_attach_kprobe(int progfd, int attach_type, const char *ev_name,
const char *fn_name, perf_reader_cb cb, const char *fn_name);
void *cb_cookie);
int bpf_detach_kprobe(const char *ev_name); int bpf_detach_kprobe(const char *ev_name);
void *bpf_attach_uprobe(int progfd, int attach_type, const char *ev_name, int bpf_attach_uprobe(int progfd, int attach_type, const char *ev_name,
const char *binary_path, uint64_t offset, int pid, const char *binary_path, uint64_t offset, int pid);
perf_reader_cb cb, void *cb_cookie);
int bpf_detach_uprobe(const char *ev_name); int bpf_detach_uprobe(const char *ev_name);
void * bpf_open_perf_buffer(perf_reader_raw_cb raw_cb, perf_reader_lost_cb lost_cb, void *cb_cookie, int pid, int cpu, int page_cnt); void * bpf_open_perf_buffer(perf_reader_raw_cb raw_cb, perf_reader_lost_cb lost_cb, void *cb_cookie, int pid, int cpu, int page_cnt);
int bpf_close_perf_event_fd(int fd);
]] ]]
ffi.cdef[[ ffi.cdef[[
...@@ -100,7 +99,7 @@ ffi.cdef[[ ...@@ -100,7 +99,7 @@ ffi.cdef[[
struct perf_reader; struct perf_reader;
void perf_reader_free(void *ptr); void perf_reader_free(void *ptr);
int perf_reader_mmap(struct perf_reader *reader, unsigned type, unsigned long sample_type); int perf_reader_mmap(struct perf_reader *reader);
int perf_reader_poll(int num_readers, struct perf_reader **readers, int timeout); int perf_reader_poll(int num_readers, struct perf_reader **readers, int timeout);
int perf_reader_fd(struct perf_reader *reader); int perf_reader_fd(struct perf_reader *reader);
void perf_reader_set_fd(struct perf_reader *reader, int fd); void perf_reader_set_fd(struct perf_reader *reader, int fd);
......
...@@ -263,7 +263,7 @@ function PerfEventArray:_open_perf_buffer(cpu, callback, ctype, page_cnt, lost_c ...@@ -263,7 +263,7 @@ function PerfEventArray:_open_perf_buffer(cpu, callback, ctype, page_cnt, lost_c
local fd = libbcc.perf_reader_fd(reader) local fd = libbcc.perf_reader_fd(reader)
self:set(cpu, fd) self:set(cpu, fd)
self.bpf:probe_store("kprobe", _perf_id(self.map_id, cpu), reader) self.bpf:perf_buffer_store(_perf_id(self.map_id, cpu), reader)
self._callbacks[cpu] = _cb self._callbacks[cpu] = _cb
end end
......
This diff is collapsed.
...@@ -85,23 +85,19 @@ lib.bpf_attach_socket.argtypes = [ct.c_int, ct.c_int] ...@@ -85,23 +85,19 @@ lib.bpf_attach_socket.argtypes = [ct.c_int, ct.c_int]
lib.bpf_prog_load.restype = ct.c_int lib.bpf_prog_load.restype = ct.c_int
lib.bpf_prog_load.argtypes = [ct.c_int, ct.c_char_p, ct.c_void_p, lib.bpf_prog_load.argtypes = [ct.c_int, ct.c_char_p, ct.c_void_p,
ct.c_size_t, ct.c_char_p, ct.c_uint, ct.c_int, ct.c_char_p, ct.c_uint] ct.c_size_t, ct.c_char_p, ct.c_uint, ct.c_int, ct.c_char_p, ct.c_uint]
lib.bpf_attach_kprobe.restype = ct.c_void_p
_CB_TYPE = ct.CFUNCTYPE(None, ct.py_object, ct.c_int,
ct.c_ulonglong, ct.POINTER(ct.c_ulonglong))
_RAW_CB_TYPE = ct.CFUNCTYPE(None, ct.py_object, ct.c_void_p, ct.c_int) _RAW_CB_TYPE = ct.CFUNCTYPE(None, ct.py_object, ct.c_void_p, ct.c_int)
_LOST_CB_TYPE = ct.CFUNCTYPE(None, ct.py_object, ct.c_ulonglong) _LOST_CB_TYPE = ct.CFUNCTYPE(None, ct.py_object, ct.c_ulonglong)
lib.bpf_attach_kprobe.argtypes = [ct.c_int, ct.c_int, ct.c_char_p, ct.c_char_p, lib.bpf_attach_kprobe.restype = ct.c_int
_CB_TYPE, ct.py_object] lib.bpf_attach_kprobe.argtypes = [ct.c_int, ct.c_int, ct.c_char_p, ct.c_char_p]
lib.bpf_detach_kprobe.restype = ct.c_int lib.bpf_detach_kprobe.restype = ct.c_int
lib.bpf_detach_kprobe.argtypes = [ct.c_char_p] lib.bpf_detach_kprobe.argtypes = [ct.c_char_p]
lib.bpf_attach_uprobe.restype = ct.c_void_p lib.bpf_attach_uprobe.restype = ct.c_int
lib.bpf_attach_uprobe.argtypes = [ct.c_int, ct.c_int, ct.c_char_p, ct.c_char_p, lib.bpf_attach_uprobe.argtypes = [ct.c_int, ct.c_int, ct.c_char_p, ct.c_char_p,
ct.c_ulonglong, ct.c_int, _CB_TYPE, ct.py_object] ct.c_ulonglong, ct.c_int]
lib.bpf_detach_uprobe.restype = ct.c_int lib.bpf_detach_uprobe.restype = ct.c_int
lib.bpf_detach_uprobe.argtypes = [ct.c_char_p] lib.bpf_detach_uprobe.argtypes = [ct.c_char_p]
lib.bpf_attach_tracepoint.restype = ct.c_void_p lib.bpf_attach_tracepoint.restype = ct.c_int
lib.bpf_attach_tracepoint.argtypes = [ct.c_int, ct.c_char_p, ct.c_char_p, lib.bpf_attach_tracepoint.argtypes = [ct.c_int, ct.c_char_p, ct.c_char_p]
_CB_TYPE, ct.py_object]
lib.bpf_detach_tracepoint.restype = ct.c_int lib.bpf_detach_tracepoint.restype = ct.c_int
lib.bpf_detach_tracepoint.argtypes = [ct.c_char_p, ct.c_char_p] lib.bpf_detach_tracepoint.argtypes = [ct.c_char_p, ct.c_char_p]
lib.bpf_open_perf_buffer.restype = ct.c_void_p lib.bpf_open_perf_buffer.restype = ct.c_void_p
......
...@@ -494,10 +494,10 @@ class PerfEventArray(ArrayBase): ...@@ -494,10 +494,10 @@ class PerfEventArray(ArrayBase):
# Delete entry from the array # Delete entry from the array
super(PerfEventArray, self).__delitem__(key) super(PerfEventArray, self).__delitem__(key)
key_id = (id(self), key) key_id = (id(self), key)
if key_id in self.bpf.open_kprobes: if key_id in self.bpf.perf_buffers:
# The key is opened for perf ring buffer # The key is opened for perf ring buffer
lib.perf_reader_free(self.bpf.open_kprobes[key_id]) lib.perf_reader_free(self.bpf.perf_buffers[key_id])
self.bpf._del_kprobe(key_id) del self.bpf.perf_buffers[key_id]
del self._cbs[key] del self._cbs[key]
else: else:
# The key is opened for perf event read # The key is opened for perf event read
...@@ -544,7 +544,7 @@ class PerfEventArray(ArrayBase): ...@@ -544,7 +544,7 @@ class PerfEventArray(ArrayBase):
raise Exception("Could not open perf buffer") raise Exception("Could not open perf buffer")
fd = lib.perf_reader_fd(reader) fd = lib.perf_reader_fd(reader)
self[self.Key(cpu)] = self.Leaf(fd) self[self.Key(cpu)] = self.Leaf(fd)
self.bpf._add_kprobe((id(self), cpu), reader) self.bpf.perf_buffers[(id(self), cpu)] = reader
# keep a refcnt # keep a refcnt
self._cbs[cpu] = (fn, lost_fn) self._cbs[cpu] = (fn, lost_fn)
# The actual fd is held by the perf reader, add to track opened keys # The actual fd is held by the perf reader, add to track opened keys
......
...@@ -46,8 +46,6 @@ add_test(NAME py_test_clang WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ...@@ -46,8 +46,6 @@ add_test(NAME py_test_clang WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${TEST_WRAPPER} py_clang sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_clang.py) COMMAND ${TEST_WRAPPER} py_clang sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_clang.py)
add_test(NAME py_test_histogram WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} add_test(NAME py_test_histogram WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${TEST_WRAPPER} py_histogram sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_histogram.py) COMMAND ${TEST_WRAPPER} py_histogram sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_histogram.py)
add_test(NAME py_test_callchain WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${TEST_WRAPPER} py_callchain sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_callchain.py)
add_test(NAME py_array WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} add_test(NAME py_array WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${TEST_WRAPPER} py_array sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_array.py) COMMAND ${TEST_WRAPPER} py_array sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_array.py)
add_test(NAME py_uprobes WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} add_test(NAME py_uprobes WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
......
#!/usr/bin/env python
# Copyright (c) PLUMgrid, Inc.
# Licensed under the Apache License, Version 2.0 (the "License")
from bcc import BPF
import time
from unittest import main, TestCase
class TestCallchain(TestCase):
def test_callchain1(self):
hist = {}
def cb(pid, callchain):
counter = hist.get(callchain, 0)
counter += 1
hist[callchain] = counter
b = BPF(text="""
#include <linux/ptrace.h>
int kprobe__finish_task_switch(struct pt_regs *ctx) {
return 1;
}
""", cb=cb)
start = time.time()
while time.time() < start + 1:
b.kprobe_poll()
for k, v in hist.items():
syms = [b.ksym(addr) for addr in k]
print("%-08d:" % v, syms)
if __name__ == "__main__":
main()
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