Commit b77915df authored by 4ast's avatar 4ast Committed by GitHub

Merge pull request #918 from derek0883/mybcc

Handling multiple concurrent probe users.
parents 199b341a 227b5b99
...@@ -147,7 +147,7 @@ StatusTuple BPF::detach_all() { ...@@ -147,7 +147,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_attach_type attach_type, bpf_probe_attach_type attach_type,
pid_t pid, int cpu, int group_fd, pid_t pid, int cpu, int group_fd,
perf_reader_cb cb, void* cb_cookie) { 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);
...@@ -157,11 +157,8 @@ StatusTuple BPF::attach_kprobe(const std::string& kernel_func, ...@@ -157,11 +157,8 @@ 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));
std::string probe_event_desc = attach_type_prefix(attach_type);
probe_event_desc += ":kprobes/" + probe_event + " " + kernel_func;
void* res = void* res =
bpf_attach_kprobe(probe_fd, probe_event.c_str(), probe_event_desc.c_str(), bpf_attach_kprobe(probe_fd, attach_type, probe_event.c_str(), kernel_func.c_str(),
pid, cpu, group_fd, cb, cb_cookie); pid, cpu, group_fd, cb, cb_cookie);
if (!res) { if (!res) {
...@@ -182,7 +179,7 @@ StatusTuple BPF::attach_uprobe(const std::string& binary_path, ...@@ -182,7 +179,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_attach_type attach_type, bpf_probe_attach_type attach_type,
pid_t pid, int cpu, int group_fd, pid_t pid, int cpu, int group_fd,
perf_reader_cb cb, void* cb_cookie) { perf_reader_cb cb, void* cb_cookie) {
bcc_symbol sym = bcc_symbol(); bcc_symbol sym = bcc_symbol();
...@@ -196,13 +193,9 @@ StatusTuple BPF::attach_uprobe(const std::string& binary_path, ...@@ -196,13 +193,9 @@ 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));
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 = void* res =
bpf_attach_uprobe(probe_fd, probe_event.c_str(), probe_event_desc.c_str(), bpf_attach_uprobe(probe_fd, attach_type, probe_event.c_str(), binary_path.c_str(),
pid, cpu, group_fd, cb, cb_cookie); sym.offset, pid, cpu, group_fd, cb, cb_cookie);
if (!res) { if (!res) {
TRY2(unload_func(probe_func)); TRY2(unload_func(probe_func));
...@@ -325,7 +318,7 @@ StatusTuple BPF::attach_perf_event(uint32_t ev_type, uint32_t ev_config, ...@@ -325,7 +318,7 @@ StatusTuple BPF::attach_perf_event(uint32_t ev_type, uint32_t ev_config,
} }
StatusTuple BPF::detach_kprobe(const std::string& kernel_func, StatusTuple BPF::detach_kprobe(const std::string& kernel_func,
bpf_attach_type attach_type) { bpf_probe_attach_type attach_type) {
std::string event = get_kprobe_event(kernel_func, attach_type); std::string event = get_kprobe_event(kernel_func, attach_type);
auto it = kprobes_.find(event); auto it = kprobes_.find(event);
...@@ -341,7 +334,7 @@ StatusTuple BPF::detach_kprobe(const std::string& kernel_func, ...@@ -341,7 +334,7 @@ StatusTuple BPF::detach_kprobe(const std::string& kernel_func,
StatusTuple BPF::detach_uprobe(const std::string& binary_path, StatusTuple BPF::detach_uprobe(const std::string& binary_path,
const std::string& symbol, uint64_t symbol_addr, const std::string& symbol, uint64_t symbol_addr,
bpf_attach_type attach_type) { bpf_probe_attach_type attach_type) {
bcc_symbol sym = bcc_symbol(); bcc_symbol sym = bcc_symbol();
TRY2(check_binary_symbol(binary_path, symbol, symbol_addr, &sym)); TRY2(check_binary_symbol(binary_path, symbol, symbol_addr, &sym));
...@@ -423,7 +416,7 @@ void BPF::poll_perf_buffer(const std::string& name, int timeout) { ...@@ -423,7 +416,7 @@ void BPF::poll_perf_buffer(const std::string& name, int timeout) {
} }
StatusTuple BPF::load_func(const std::string& func_name, StatusTuple BPF::load_func(const std::string& func_name,
enum bpf_prog_type type, int& fd) { bpf_prog_type type, int& fd) {
if (funcs_.find(func_name) != funcs_.end()) { if (funcs_.find(func_name) != funcs_.end()) {
fd = funcs_[func_name]; fd = funcs_[func_name];
return StatusTuple(0); return StatusTuple(0);
...@@ -473,14 +466,14 @@ StatusTuple BPF::check_binary_symbol(const std::string& binary_path, ...@@ -473,14 +466,14 @@ StatusTuple BPF::check_binary_symbol(const std::string& binary_path,
} }
std::string BPF::get_kprobe_event(const std::string& kernel_func, std::string BPF::get_kprobe_event(const std::string& kernel_func,
bpf_attach_type type) { bpf_probe_attach_type type) {
std::string res = attach_type_prefix(type) + "_"; std::string res = attach_type_prefix(type) + "_";
res += sanitize_str(kernel_func, &BPF::kprobe_event_validator); res += sanitize_str(kernel_func, &BPF::kprobe_event_validator);
return res; return res;
} }
std::string BPF::get_uprobe_event(const std::string& binary_path, std::string BPF::get_uprobe_event(const std::string& binary_path,
uint64_t offset, bpf_attach_type type) { uint64_t offset, bpf_probe_attach_type type) {
std::string res = attach_type_prefix(type) + "_"; std::string res = attach_type_prefix(type) + "_";
res += sanitize_str(binary_path, &BPF::uprobe_path_validator); res += sanitize_str(binary_path, &BPF::uprobe_path_validator);
res += "_0x" + uint_to_hex(offset); res += "_0x" + uint_to_hex(offset);
...@@ -494,8 +487,7 @@ StatusTuple BPF::detach_kprobe_event(const std::string& event, ...@@ -494,8 +487,7 @@ StatusTuple BPF::detach_kprobe_event(const std::string& event,
attr.reader_ptr = nullptr; attr.reader_ptr = nullptr;
} }
TRY2(unload_func(attr.func)); TRY2(unload_func(attr.func));
std::string detach_event = "-:kprobes/" + event; if (bpf_detach_kprobe(event.c_str()) < 0)
if (bpf_detach_kprobe(detach_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());
return StatusTuple(0); return StatusTuple(0);
} }
...@@ -507,8 +499,7 @@ StatusTuple BPF::detach_uprobe_event(const std::string& event, ...@@ -507,8 +499,7 @@ StatusTuple BPF::detach_uprobe_event(const std::string& event,
attr.reader_ptr = nullptr; attr.reader_ptr = nullptr;
} }
TRY2(unload_func(attr.func)); TRY2(unload_func(attr.func));
std::string detach_event = "-:uprobes/" + event; if (bpf_detach_uprobe(event.c_str()) < 0)
if (bpf_detach_uprobe(detach_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());
return StatusTuple(0); return StatusTuple(0);
} }
......
...@@ -29,11 +29,6 @@ ...@@ -29,11 +29,6 @@
namespace ebpf { namespace ebpf {
enum class bpf_attach_type {
probe_entry,
probe_return
};
struct open_probe_t { struct open_probe_t {
void* reader_ptr; void* reader_ptr;
std::string func; std::string func;
...@@ -56,23 +51,23 @@ public: ...@@ -56,23 +51,23 @@ public:
StatusTuple attach_kprobe( StatusTuple attach_kprobe(
const std::string& kernel_func, const std::string& probe_func, const std::string& kernel_func, const std::string& probe_func,
bpf_attach_type attach_type = bpf_attach_type::probe_entry, bpf_probe_attach_type = BPF_PROBE_ENTRY,
pid_t pid = -1, int cpu = 0, int group_fd = -1, pid_t pid = -1, int cpu = 0, int group_fd = -1,
perf_reader_cb cb = nullptr, void* cb_cookie = nullptr); 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_attach_type attach_type = bpf_attach_type::probe_entry); bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY);
StatusTuple attach_uprobe( StatusTuple attach_uprobe(
const std::string& binary_path, const std::string& symbol, const std::string& binary_path, const std::string& symbol,
const std::string& probe_func, uint64_t symbol_addr = 0, const std::string& probe_func, uint64_t symbol_addr = 0,
bpf_attach_type attach_type = bpf_attach_type::probe_entry, bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY,
pid_t pid = -1, int cpu = 0, int group_fd = -1, pid_t pid = -1, int cpu = 0, int group_fd = -1,
perf_reader_cb cb = nullptr, void* cb_cookie = nullptr); perf_reader_cb cb = nullptr, void* cb_cookie = nullptr);
StatusTuple detach_uprobe( StatusTuple detach_uprobe(
const std::string& binary_path, const std::string& symbol, const std::string& binary_path, const std::string& symbol,
uint64_t symbol_addr = 0, uint64_t symbol_addr = 0,
bpf_attach_type attach_type = bpf_attach_type::probe_entry); bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY);
StatusTuple attach_usdt(const USDT& usdt, pid_t pid = -1, int cpu = 0, StatusTuple attach_usdt(const USDT& usdt, pid_t pid = -1, int cpu = 0,
int group_fd = -1); int group_fd = -1);
StatusTuple detach_usdt(const USDT& usdt); StatusTuple detach_usdt(const USDT& usdt);
...@@ -111,9 +106,9 @@ private: ...@@ -111,9 +106,9 @@ private:
StatusTuple unload_func(const std::string& func_name); StatusTuple unload_func(const std::string& func_name);
std::string get_kprobe_event(const std::string& kernel_func, std::string get_kprobe_event(const std::string& kernel_func,
bpf_attach_type type); bpf_probe_attach_type type);
std::string get_uprobe_event(const std::string& binary_path, uint64_t offset, std::string get_uprobe_event(const std::string& binary_path, uint64_t offset,
bpf_attach_type type); bpf_probe_attach_type type);
StatusTuple detach_kprobe_event(const std::string& event, open_probe_t& attr); 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_uprobe_event(const std::string& event, open_probe_t& attr);
...@@ -121,21 +116,21 @@ private: ...@@ -121,21 +116,21 @@ private:
open_probe_t& attr); open_probe_t& attr);
StatusTuple detach_perf_event_all_cpu(open_probe_t& attr); StatusTuple detach_perf_event_all_cpu(open_probe_t& attr);
std::string attach_type_debug(bpf_attach_type type) { std::string attach_type_debug(bpf_probe_attach_type type) {
switch (type) { switch (type) {
case bpf_attach_type::probe_entry: case BPF_PROBE_ENTRY:
return ""; return "";
case bpf_attach_type::probe_return: case BPF_PROBE_RETURN:
return "return "; return "return ";
} }
return "ERROR"; return "ERROR";
} }
std::string attach_type_prefix(bpf_attach_type type) { std::string attach_type_prefix(bpf_probe_attach_type type) {
switch (type) { switch (type) {
case bpf_attach_type::probe_entry: case BPF_PROBE_ENTRY:
return "p"; return "p";
case bpf_attach_type::probe_return: case BPF_PROBE_RETURN:
return "r"; return "r";
} }
return "ERROR"; return "ERROR";
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
#include <sys/resource.h> #include <sys/resource.h>
#include <unistd.h> #include <unistd.h>
#include <stdbool.h> #include <stdbool.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "libbpf.h" #include "libbpf.h"
#include "perf_reader.h" #include "perf_reader.h"
...@@ -336,14 +338,19 @@ static int bpf_attach_tracing_event(int progfd, const char *event_path, ...@@ -336,14 +338,19 @@ static int bpf_attach_tracing_event(int progfd, const char *event_path,
return 0; return 0;
} }
static void * bpf_attach_probe(int progfd, const char *event, void * bpf_attach_kprobe(int progfd, enum bpf_probe_attach_type attach_type, const char *ev_name,
const char *event_desc, const char *event_type, const char *fn_name,
pid_t pid, int cpu, int group_fd, pid_t pid, int cpu, int group_fd,
perf_reader_cb cb, void *cb_cookie) { perf_reader_cb cb, void *cb_cookie)
{
int kfd; int kfd;
char buf[256]; char buf[256];
char new_name[128];
struct perf_reader *reader = NULL; struct perf_reader *reader = NULL;
static char *event_type = "kprobe";
int n;
snprintf(new_name, sizeof(new_name), "%s_bcc_%d", ev_name, getpid());
reader = perf_reader_new(cb, NULL, cb_cookie); reader = perf_reader_new(cb, NULL, cb_cookie);
if (!reader) if (!reader)
goto error; goto error;
...@@ -355,8 +362,9 @@ static void * bpf_attach_probe(int progfd, const char *event, ...@@ -355,8 +362,9 @@ static void * bpf_attach_probe(int progfd, const char *event,
goto error; goto error;
} }
if (write(kfd, event_desc, strlen(event_desc)) < 0) { snprintf(buf, sizeof(buf), "%c:%ss/%s %s", attach_type==BPF_PROBE_ENTRY ? 'p' : 'r',
fprintf(stderr, "write(%s, \"%s\") failed: %s\n", buf, event_desc, strerror(errno)); event_type, new_name, fn_name);
if (write(kfd, buf, strlen(buf)) < 0) {
if (errno == EINVAL) if (errno == EINVAL)
fprintf(stderr, "check dmesg output for possible cause\n"); fprintf(stderr, "check dmesg output for possible cause\n");
close(kfd); close(kfd);
...@@ -364,34 +372,82 @@ static void * bpf_attach_probe(int progfd, const char *event, ...@@ -364,34 +372,82 @@ static void * bpf_attach_probe(int progfd, const char *event,
} }
close(kfd); close(kfd);
snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%ss/%s", event_type, event); if (access("/sys/kernel/debug/tracing/instances", F_OK) != -1) {
snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/instances/%s", new_name);
if (mkdir(buf, 0755) == -1)
goto retry;
n = snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/instances/%s/events/%ss/%s",
new_name, event_type, new_name);
if (n < sizeof(buf) && bpf_attach_tracing_event(progfd, buf, reader, pid, cpu, group_fd) == 0)
goto out;
snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/instances/%s", new_name);
rmdir(buf);
}
retry:
snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%ss/%s", event_type, new_name);
if (bpf_attach_tracing_event(progfd, buf, reader, pid, cpu, group_fd) < 0) if (bpf_attach_tracing_event(progfd, buf, reader, pid, cpu, group_fd) < 0)
goto error; goto error;
out:
return reader; return reader;
error: error:
perf_reader_free(reader); perf_reader_free(reader);
return NULL; return NULL;
}
void * bpf_attach_kprobe(int progfd, const char *event,
const char *event_desc,
pid_t pid, int cpu, int group_fd,
perf_reader_cb cb, void *cb_cookie) {
return bpf_attach_probe(progfd, event, event_desc, "kprobe", pid, cpu, group_fd, cb, cb_cookie);
} }
void * bpf_attach_uprobe(int progfd, const char *event, void * bpf_attach_uprobe(int progfd, enum bpf_probe_attach_type attach_type, const char *ev_name,
const char *event_desc, const char *binary_path, uint64_t offset,
pid_t pid, int cpu, int group_fd, pid_t pid, int cpu, int group_fd,
perf_reader_cb cb, void *cb_cookie) { perf_reader_cb cb, void *cb_cookie)
return bpf_attach_probe(progfd, event, event_desc, "uprobe", pid, cpu, group_fd, cb, cb_cookie); {
int kfd;
char buf[PATH_MAX];
char new_name[128];
struct perf_reader *reader = NULL;
static char *event_type = "uprobe";
int n;
snprintf(new_name, sizeof(new_name), "%s_bcc_%d", ev_name, getpid());
reader = perf_reader_new(cb, NULL, cb_cookie);
if (!reader)
goto error;
snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/%s_events", event_type);
kfd = open(buf, O_WRONLY | O_APPEND, 0);
if (kfd < 0) {
fprintf(stderr, "open(%s): %s\n", buf, strerror(errno));
goto error;
}
n = snprintf(buf, sizeof(buf), "%c:%ss/%s %s:0x%lx", attach_type==BPF_PROBE_ENTRY ? 'p' : 'r',
event_type, new_name, binary_path, offset);
if (n >= sizeof(buf)) {
close(kfd);
goto error;
}
if (write(kfd, buf, strlen(buf)) < 0) {
if (errno == EINVAL)
fprintf(stderr, "check dmesg output for possible cause\n");
close(kfd);
goto error;
}
close(kfd);
snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%ss/%s", event_type, new_name);
if (bpf_attach_tracing_event(progfd, buf, reader, pid, cpu, group_fd) < 0)
goto error;
return reader;
error:
perf_reader_free(reader);
return NULL;
} }
static int bpf_detach_probe(const char *event_desc, const char *event_type) { static int bpf_detach_probe(const char *ev_name, const char *event_type)
{
int kfd; int kfd;
char buf[256]; char buf[256];
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);
...@@ -400,7 +456,8 @@ static int bpf_detach_probe(const char *event_desc, const char *event_type) { ...@@ -400,7 +456,8 @@ static int bpf_detach_probe(const char *event_desc, const char *event_type) {
return -1; return -1;
} }
if (write(kfd, event_desc, strlen(event_desc)) < 0) { snprintf(buf, sizeof(buf), "-:%ss/%s_bcc_%d", event_type, ev_name, getpid());
if (write(kfd, buf, strlen(buf)) < 0) {
fprintf(stderr, "write(%s): %s\n", buf, strerror(errno)); fprintf(stderr, "write(%s): %s\n", buf, strerror(errno));
close(kfd); close(kfd);
return -1; return -1;
...@@ -410,14 +467,24 @@ static int bpf_detach_probe(const char *event_desc, const char *event_type) { ...@@ -410,14 +467,24 @@ static int bpf_detach_probe(const char *event_desc, const char *event_type) {
return 0; return 0;
} }
int bpf_detach_kprobe(const char *event_desc) { int bpf_detach_kprobe(const char *ev_name)
return bpf_detach_probe(event_desc, "kprobe"); {
char buf[256];
int ret = bpf_detach_probe(ev_name, "kprobe");
snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/instances/%s_bcc_%d", ev_name, getpid());
if (access(buf, F_OK) != -1) {
rmdir(buf);
}
return ret;
} }
int bpf_detach_uprobe(const char *event_desc) { int bpf_detach_uprobe(const char *ev_name)
return bpf_detach_probe(event_desc, "uprobe"); {
return bpf_detach_probe(ev_name, "uprobe");
} }
void * bpf_attach_tracepoint(int progfd, const char *tp_category, void * bpf_attach_tracepoint(int progfd, const char *tp_category,
const char *tp_name, int pid, int cpu, const char *tp_name, int pid, int cpu,
int group_fd, perf_reader_cb cb, void *cb_cookie) { int group_fd, perf_reader_cb cb, void *cb_cookie) {
......
...@@ -24,6 +24,11 @@ ...@@ -24,6 +24,11 @@
extern "C" { extern "C" {
#endif #endif
enum bpf_probe_attach_type {
BPF_PROBE_ENTRY,
BPF_PROBE_RETURN
};
int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,
int max_entries, int map_flags); int max_entries, int map_flags);
int bpf_update_elem(int fd, void *key, void *value, unsigned long long flags); int bpf_update_elem(int fd, void *key, void *value, unsigned long long flags);
...@@ -44,15 +49,19 @@ typedef void (*perf_reader_cb)(void *cb_cookie, int pid, uint64_t callchain_num, ...@@ -44,15 +49,19 @@ typedef void (*perf_reader_cb)(void *cb_cookie, int pid, uint64_t callchain_num,
void *callchain); 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);
void * bpf_attach_kprobe(int progfd, const char *event, const char *event_desc, void * bpf_attach_kprobe(int progfd, enum bpf_probe_attach_type attach_type,
int pid, int cpu, int group_fd, perf_reader_cb cb, const char *ev_name, const char *fn_name,
void *cb_cookie); pid_t pid, int cpu, int group_fd,
int bpf_detach_kprobe(const char *event_desc); perf_reader_cb cb, void *cb_cookie);
int bpf_detach_kprobe(const char *ev_name);
void * bpf_attach_uprobe(int progfd, enum bpf_probe_attach_type attach_type,
const char *ev_name, const char *binary_path, uint64_t offset,
pid_t pid, int cpu, int group_fd,
perf_reader_cb cb, void *cb_cookie);
void * bpf_attach_uprobe(int progfd, const char *event, const char *event_desc, int bpf_detach_uprobe(const char *ev_name);
int pid, int cpu, int group_fd, perf_reader_cb cb,
void *cb_cookie);
int bpf_detach_uprobe(const char *event_desc);
void * bpf_attach_tracepoint(int progfd, const char *tp_category, void * bpf_attach_tracepoint(int progfd, const char *tp_category,
const char *tp_name, int pid, int cpu, const char *tp_name, int pid, int cpu,
......
...@@ -43,13 +43,10 @@ function Bpf.static.cleanup() ...@@ -43,13 +43,10 @@ function Bpf.static.cleanup()
libbcc.perf_reader_free(probe) libbcc.perf_reader_free(probe)
-- skip bcc-specific kprobes -- skip bcc-specific kprobes
if not key:starts("bcc:") then if not key:starts("bcc:") then
local desc = string.format("-:%s/%s", probe_type, key)
log.info("detaching %s", desc)
if probe_type == "kprobes" then if probe_type == "kprobes" then
libbcc.bpf_detach_kprobe(desc) libbcc.bpf_detach_kprobe(key)
elseif probe_type == "uprobes" then elseif probe_type == "uprobes" then
libbcc.bpf_detach_uprobe(desc) libbcc.bpf_detach_uprobe(key)
end end
end end
all_probes[key] = nil all_probes[key] = nil
...@@ -187,11 +184,9 @@ function Bpf:attach_uprobe(args) ...@@ -187,11 +184,9 @@ function Bpf:attach_uprobe(args)
local fn = self:load_func(args.fn_name, 'BPF_PROG_TYPE_KPROBE') local fn = self:load_func(args.fn_name, 'BPF_PROG_TYPE_KPROBE')
local ptype = args.retprobe and "r" or "p" local ptype = args.retprobe and "r" or "p"
local ev_name = string.format("%s_%s_0x%p", ptype, path:gsub("[^%a%d]", "_"), addr) local ev_name = string.format("%s_%s_0x%p", ptype, path:gsub("[^%a%d]", "_"), addr)
local desc = string.format("%s:uprobes/%s %s:0x%p", ptype, ev_name, path, addr) local retprobe = args.retprobe and 1 or 0
log.info(desc)
local res = libbcc.bpf_attach_uprobe(fn.fd, ev_name, desc, local res = libbcc.bpf_attach_uprobe(fn.fd, retprobe, ev_name, path, addr,
args.pid or -1, args.pid or -1,
args.cpu or 0, args.cpu or 0,
args.group_fd or -1, nil, nil) -- TODO; reader callback args.group_fd or -1, nil, nil) -- TODO; reader callback
...@@ -209,11 +204,9 @@ function Bpf:attach_kprobe(args) ...@@ -209,11 +204,9 @@ function Bpf:attach_kprobe(args)
local event = args.event or "" local event = args.event or ""
local ptype = args.retprobe and "r" or "p" local ptype = args.retprobe and "r" or "p"
local ev_name = string.format("%s_%s", ptype, event:gsub("[%+%.]", "_")) local ev_name = string.format("%s_%s", ptype, event:gsub("[%+%.]", "_"))
local desc = string.format("%s:kprobes/%s %s", ptype, ev_name, event) local retprobe = args.retprobe and 1 or 0
log.info(desc)
local res = libbcc.bpf_attach_kprobe(fn.fd, ev_name, desc, local res = libbcc.bpf_attach_kprobe(fn.fd, retprobe, ev_name, event,
args.pid or -1, args.pid or -1,
args.cpu or 0, args.cpu or 0,
args.group_fd or -1, nil, nil) -- TODO; reader callback args.group_fd or -1, nil, nil) -- TODO; reader callback
......
...@@ -40,13 +40,19 @@ int bpf_open_raw_sock(const char *name); ...@@ -40,13 +40,19 @@ 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_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);
void * bpf_attach_kprobe(int progfd, const char *event, const char *event_desc, void * bpf_attach_kprobe(int progfd, int attach_type, const char *ev_name,
int pid, int cpu, int group_fd, perf_reader_cb cb, void *cb_cookie); const char *fn_name,
int bpf_detach_kprobe(const char *event_desc); int pid, int cpu, int group_fd,
perf_reader_cb cb, void *cb_cookie);
void * bpf_attach_uprobe(int progfd, const char *event, const char *event_desc, int bpf_detach_kprobe(const char *ev_name);
int pid, int cpu, int group_fd, perf_reader_cb cb, void *cb_cookie);
int bpf_detach_uprobe(const char *event_desc); void * bpf_attach_uprobe(int progfd, int attach_type, const char *ev_name,
const char *binary_path, uint64_t offset,
int pid, int cpu, int group_fd,
perf_reader_cb cb, void *cb_cookie);
int bpf_detach_uprobe(const char *ev_name);
void * bpf_open_perf_buffer(perf_reader_raw_cb raw_cb, void *cb_cookie, int pid, int cpu); void * bpf_open_perf_buffer(perf_reader_raw_cb raw_cb, void *cb_cookie, int pid, int cpu);
]] ]]
......
...@@ -459,9 +459,8 @@ class BPF(object): ...@@ -459,9 +459,8 @@ class BPF(object):
self._check_probe_quota(1) self._check_probe_quota(1)
fn = self.load_func(fn_name, BPF.KPROBE) fn = self.load_func(fn_name, BPF.KPROBE)
ev_name = "p_" + event.replace("+", "_").replace(".", "_") ev_name = "p_" + event.replace("+", "_").replace(".", "_")
desc = "p:kprobes/%s %s" % (ev_name, event) res = lib.bpf_attach_kprobe(fn.fd, 0, ev_name.encode("ascii"),
res = lib.bpf_attach_kprobe(fn.fd, ev_name.encode("ascii"), event.encode("ascii"), pid, cpu, group_fd,
desc.encode("ascii"), pid, cpu, group_fd,
self._reader_cb_impl, ct.cast(id(self), ct.py_object)) self._reader_cb_impl, ct.cast(id(self), ct.py_object))
res = ct.cast(res, ct.c_void_p) res = ct.cast(res, ct.c_void_p)
if not res: if not res:
...@@ -475,8 +474,7 @@ class BPF(object): ...@@ -475,8 +474,7 @@ class BPF(object):
if ev_name not in self.open_kprobes: if ev_name not in self.open_kprobes:
raise Exception("Kprobe %s is not attached" % event) raise Exception("Kprobe %s is not attached" % event)
lib.perf_reader_free(self.open_kprobes[ev_name]) lib.perf_reader_free(self.open_kprobes[ev_name])
desc = "-:kprobes/%s" % ev_name res = lib.bpf_detach_kprobe(ev_name.encode("ascii"))
res = lib.bpf_detach_kprobe(desc.encode("ascii"))
if res < 0: if res < 0:
raise Exception("Failed to detach BPF from kprobe") raise Exception("Failed to detach BPF from kprobe")
self._del_kprobe(ev_name) self._del_kprobe(ev_name)
...@@ -498,9 +496,8 @@ class BPF(object): ...@@ -498,9 +496,8 @@ class BPF(object):
self._check_probe_quota(1) self._check_probe_quota(1)
fn = self.load_func(fn_name, BPF.KPROBE) fn = self.load_func(fn_name, BPF.KPROBE)
ev_name = "r_" + event.replace("+", "_").replace(".", "_") ev_name = "r_" + event.replace("+", "_").replace(".", "_")
desc = "r:kprobes/%s %s" % (ev_name, event) res = lib.bpf_attach_kprobe(fn.fd, 1, ev_name.encode("ascii"),
res = lib.bpf_attach_kprobe(fn.fd, ev_name.encode("ascii"), event.encode("ascii"), pid, cpu, group_fd,
desc.encode("ascii"), pid, cpu, group_fd,
self._reader_cb_impl, ct.cast(id(self), ct.py_object)) self._reader_cb_impl, ct.cast(id(self), ct.py_object))
res = ct.cast(res, ct.c_void_p) res = ct.cast(res, ct.c_void_p)
if not res: if not res:
...@@ -514,8 +511,7 @@ class BPF(object): ...@@ -514,8 +511,7 @@ class BPF(object):
if ev_name not in self.open_kprobes: if ev_name not in self.open_kprobes:
raise Exception("Kretprobe %s is not attached" % event) raise Exception("Kretprobe %s is not attached" % event)
lib.perf_reader_free(self.open_kprobes[ev_name]) lib.perf_reader_free(self.open_kprobes[ev_name])
desc = "-:kprobes/%s" % ev_name res = lib.bpf_detach_kprobe(ev_name.encode("ascii"))
res = lib.bpf_detach_kprobe(desc.encode("ascii"))
if res < 0: if res < 0:
raise Exception("Failed to detach BPF from kprobe") raise Exception("Failed to detach BPF from kprobe")
self._del_kprobe(ev_name) self._del_kprobe(ev_name)
...@@ -767,9 +763,8 @@ class BPF(object): ...@@ -767,9 +763,8 @@ class BPF(object):
self._check_probe_quota(1) self._check_probe_quota(1)
fn = self.load_func(fn_name, BPF.KPROBE) fn = self.load_func(fn_name, BPF.KPROBE)
ev_name = "p_%s_0x%x" % (self._probe_repl.sub("_", path), addr) ev_name = "p_%s_0x%x" % (self._probe_repl.sub("_", path), addr)
desc = "p:uprobes/%s %s:0x%x" % (ev_name, path, addr) res = lib.bpf_attach_uprobe(fn.fd, 0, ev_name.encode("ascii"),
res = lib.bpf_attach_uprobe(fn.fd, ev_name.encode("ascii"), path, addr, pid, cpu, group_fd,
desc.encode("ascii"), pid, cpu, group_fd,
self._reader_cb_impl, ct.cast(id(self), ct.py_object)) self._reader_cb_impl, ct.cast(id(self), ct.py_object))
res = ct.cast(res, ct.c_void_p) res = ct.cast(res, ct.c_void_p)
if not res: if not res:
...@@ -790,8 +785,7 @@ class BPF(object): ...@@ -790,8 +785,7 @@ class BPF(object):
if ev_name not in self.open_uprobes: if ev_name not in self.open_uprobes:
raise Exception("Uprobe %s is not attached" % ev_name) raise Exception("Uprobe %s is not attached" % ev_name)
lib.perf_reader_free(self.open_uprobes[ev_name]) lib.perf_reader_free(self.open_uprobes[ev_name])
desc = "-:uprobes/%s" % ev_name res = lib.bpf_detach_uprobe(ev_name.encode("ascii"))
res = lib.bpf_detach_uprobe(desc.encode("ascii"))
if res < 0: if res < 0:
raise Exception("Failed to detach BPF from uprobe") raise Exception("Failed to detach BPF from uprobe")
self._del_uprobe(ev_name) self._del_uprobe(ev_name)
...@@ -819,9 +813,8 @@ class BPF(object): ...@@ -819,9 +813,8 @@ class BPF(object):
self._check_probe_quota(1) self._check_probe_quota(1)
fn = self.load_func(fn_name, BPF.KPROBE) fn = self.load_func(fn_name, BPF.KPROBE)
ev_name = "r_%s_0x%x" % (self._probe_repl.sub("_", path), addr) ev_name = "r_%s_0x%x" % (self._probe_repl.sub("_", path), addr)
desc = "r:uprobes/%s %s:0x%x" % (ev_name, path, addr) res = lib.bpf_attach_uprobe(fn.fd, 1, ev_name.encode("ascii"),
res = lib.bpf_attach_uprobe(fn.fd, ev_name.encode("ascii"), path, addr, pid, cpu, group_fd,
desc.encode("ascii"), pid, cpu, group_fd,
self._reader_cb_impl, ct.cast(id(self), ct.py_object)) self._reader_cb_impl, ct.cast(id(self), ct.py_object))
res = ct.cast(res, ct.c_void_p) res = ct.cast(res, ct.c_void_p)
if not res: if not res:
...@@ -842,8 +835,7 @@ class BPF(object): ...@@ -842,8 +835,7 @@ class BPF(object):
if ev_name not in self.open_uprobes: if ev_name not in self.open_uprobes:
raise Exception("Uretprobe %s is not attached" % ev_name) raise Exception("Uretprobe %s is not attached" % ev_name)
lib.perf_reader_free(self.open_uprobes[ev_name]) lib.perf_reader_free(self.open_uprobes[ev_name])
desc = "-:uprobes/%s" % ev_name res = lib.bpf_detach_uprobe(ev_name.encode("ascii"))
res = lib.bpf_detach_uprobe(desc.encode("ascii"))
if res < 0: if res < 0:
raise Exception("Failed to detach BPF from uprobe") raise Exception("Failed to detach BPF from uprobe")
self._del_uprobe(ev_name) self._del_uprobe(ev_name)
...@@ -1045,13 +1037,11 @@ class BPF(object): ...@@ -1045,13 +1037,11 @@ class BPF(object):
lib.perf_reader_free(v) lib.perf_reader_free(v)
# non-string keys here include the perf_events reader # non-string keys here include the perf_events reader
if isinstance(k, str): if isinstance(k, str):
desc = "-:kprobes/%s" % k lib.bpf_detach_kprobe(str(k).encode("ascii"))
lib.bpf_detach_kprobe(desc.encode("ascii"))
self._del_kprobe(k) self._del_kprobe(k)
for k, v in list(self.open_uprobes.items()): for k, v in list(self.open_uprobes.items()):
lib.perf_reader_free(v) lib.perf_reader_free(v)
desc = "-:uprobes/%s" % k lib.bpf_detach_uprobe(str(k).encode("ascii"))
lib.bpf_detach_uprobe(desc.encode("ascii"))
self._del_uprobe(k) self._del_uprobe(k)
for k, v in self.open_tracepoints.items(): for k, v in self.open_tracepoints.items():
lib.perf_reader_free(v) lib.perf_reader_free(v)
......
...@@ -87,13 +87,13 @@ lib.bpf_attach_kprobe.restype = ct.c_void_p ...@@ -87,13 +87,13 @@ lib.bpf_attach_kprobe.restype = ct.c_void_p
_CB_TYPE = ct.CFUNCTYPE(None, ct.py_object, ct.c_int, _CB_TYPE = ct.CFUNCTYPE(None, ct.py_object, ct.c_int,
ct.c_ulonglong, ct.POINTER(ct.c_ulonglong)) 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)
lib.bpf_attach_kprobe.argtypes = [ct.c_int, ct.c_char_p, ct.c_char_p, ct.c_int, lib.bpf_attach_kprobe.argtypes = [ct.c_int, ct.c_int, ct.c_char_p, ct.c_char_p, ct.c_int,
ct.c_int, ct.c_int, _CB_TYPE, ct.py_object] ct.c_int, ct.c_int, _CB_TYPE, ct.py_object]
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_void_p
lib.bpf_attach_uprobe.argtypes = [ct.c_int, ct.c_char_p, ct.c_char_p, ct.c_int, lib.bpf_attach_uprobe.argtypes = [ct.c_int, ct.c_int, ct.c_char_p, ct.c_char_p,
ct.c_int, ct.c_int, _CB_TYPE, ct.py_object] ct.c_ulonglong, ct.c_int, ct.c_int, ct.c_int, _CB_TYPE, ct.py_object]
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_void_p
......
...@@ -20,7 +20,7 @@ import sys ...@@ -20,7 +20,7 @@ import sys
class Probe(object): class Probe(object):
next_probe_index = 0 next_probe_index = 0
streq_index = 0 streq_index = 0
aliases = {"$PID": "(bpf_get_current_pid_tgid() >> 32)"} aliases = {"$PID": "bpf_get_current_pid_tgid()"}
def _substitute_aliases(self, expr): def _substitute_aliases(self, expr):
if expr is None: if expr is None:
...@@ -47,9 +47,7 @@ class Probe(object): ...@@ -47,9 +47,7 @@ class Probe(object):
text = """ text = """
int PROBENAME(struct pt_regs *ctx SIGNATURE) int PROBENAME(struct pt_regs *ctx SIGNATURE)
{ {
u64 __pid_tgid = bpf_get_current_pid_tgid(); u32 pid = bpf_get_current_pid_tgid();
u32 __pid = __pid_tgid; // lower 32 bits
u32 __tgid = __pid_tgid >> 32; // upper 32 bits
PID_FILTER PID_FILTER
COLLECT COLLECT
return 0; return 0;
...@@ -58,17 +56,19 @@ int PROBENAME(struct pt_regs *ctx SIGNATURE) ...@@ -58,17 +56,19 @@ int PROBENAME(struct pt_regs *ctx SIGNATURE)
text = text.replace("PROBENAME", self.entry_probe_func) text = text.replace("PROBENAME", self.entry_probe_func)
text = text.replace("SIGNATURE", text = text.replace("SIGNATURE",
"" if len(self.signature) == 0 else ", " + self.signature) "" if len(self.signature) == 0 else ", " + self.signature)
text = text.replace("PID_FILTER", self._generate_pid_filter()) pid_filter = "" if self.is_user or self.pid is None \
else "if (pid != %d) { return 0; }" % self.pid
text = text.replace("PID_FILTER", pid_filter)
collect = "" collect = ""
for pname in self.args_to_probe: for pname in self.args_to_probe:
param_hash = self.hashname_prefix + pname param_hash = self.hashname_prefix + pname
if pname == "__latency": if pname == "__latency":
collect += """ collect += """
u64 __time = bpf_ktime_get_ns(); u64 __time = bpf_ktime_get_ns();
%s.update(&__pid, &__time); %s.update(&pid, &__time);
""" % param_hash """ % param_hash
else: else:
collect += "%s.update(&__pid, &%s);\n" % \ collect += "%s.update(&pid, &%s);\n" % \
(param_hash, pname) (param_hash, pname)
text = text.replace("COLLECT", collect) text = text.replace("COLLECT", collect)
return text return text
...@@ -108,7 +108,7 @@ u64 __time = bpf_ktime_get_ns(); ...@@ -108,7 +108,7 @@ u64 __time = bpf_ktime_get_ns();
# argument we needed to probe using $entry(name), and they all # argument we needed to probe using $entry(name), and they all
# have values (which isn't necessarily the case if we missed # have values (which isn't necessarily the case if we missed
# the method entry probe). # the method entry probe).
text = "" text = "u32 __pid = bpf_get_current_pid_tgid();\n"
self.param_val_names = {} self.param_val_names = {}
for pname in self.args_to_probe: for pname in self.args_to_probe:
val_name = "__%s_val" % pname val_name = "__%s_val" % pname
...@@ -345,7 +345,8 @@ static inline bool %s(char const *ignored, char const *str) { ...@@ -345,7 +345,8 @@ static inline bool %s(char const *ignored, char const *str) {
# Kernel probes need to explicitly filter pid, because the # Kernel probes need to explicitly filter pid, because the
# attach interface doesn't support pid filtering # attach interface doesn't support pid filtering
if self.pid is not None and not self.is_user: if self.pid is not None and not self.is_user:
return "if (__tgid != %d) { return 0; }" % self.pid return "u32 pid = bpf_get_current_pid_tgid();\n" + \
"if (pid != %d) { return 0; }" % self.pid
else: else:
return "" return ""
...@@ -359,9 +360,6 @@ DATA_DECL ...@@ -359,9 +360,6 @@ DATA_DECL
if self.probe_type == "t" if self.probe_type == "t"
else "int PROBENAME(struct pt_regs *ctx SIGNATURE)") + """ else "int PROBENAME(struct pt_regs *ctx SIGNATURE)") + """
{ {
u64 __pid_tgid = bpf_get_current_pid_tgid();
u32 __pid = __pid_tgid; // lower 32 bits
u32 __tgid = __pid_tgid >> 32; // upper 32 bits
PID_FILTER PID_FILTER
PREFIX PREFIX
if (!(FILTER)) return 0; if (!(FILTER)) return 0;
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
# Licensed under the Apache License, Version 2.0 (the "License") # Licensed under the Apache License, Version 2.0 (the "License")
from __future__ import print_function from __future__ import print_function
from bcc import BPF from bcc import BPF, Tracepoint
from time import sleep, strftime from time import sleep, strftime
import argparse import argparse
......
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