95 lines
2.8 KiB
C++
95 lines
2.8 KiB
C++
#include <sys/socket.h>
|
|
#include <sysexits.h>
|
|
#include <unistd.h>
|
|
|
|
#include <bpf/btf.h>
|
|
#include <bpf/libbpf.h>
|
|
|
|
#include <cstdlib>
|
|
#include <sstream>
|
|
|
|
constexpr int kERROR_BPF_OBJECT_OPEN = 1;
|
|
constexpr int kERROR_BTF_NOT_FOUND = 2;
|
|
constexpr int kERROR_LOAD_BTF = 3;
|
|
constexpr int kERROR_SEND_BTF_FD = 4;
|
|
constexpr int kERROR_BTF_TYPE_IDS = 5;
|
|
|
|
static int no_print(enum libbpf_print_level , const char *, va_list ) {
|
|
return 0;
|
|
}
|
|
|
|
int sendBtfFd(int socket, int fd) {
|
|
char buf[CMSG_SPACE(sizeof(fd))];
|
|
|
|
struct msghdr msg;
|
|
memset(&msg, 0, sizeof(msg));
|
|
msg.msg_control = buf;
|
|
msg.msg_controllen = sizeof(buf);
|
|
|
|
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
|
|
cmsg->cmsg_level = SOL_SOCKET;
|
|
cmsg->cmsg_type = SCM_RIGHTS;
|
|
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
|
|
|
|
*(int*)CMSG_DATA(cmsg) = fd;
|
|
return sendmsg(socket, &msg, 0);
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
int ret = 0, socketFd, pipeFd, btfFd;
|
|
if (argc != 4) return EX_USAGE;
|
|
|
|
socketFd = atoi(argv[1]);
|
|
pipeFd = atoi(argv[2]);
|
|
|
|
auto path(argv[3]);
|
|
ret = libbpf_set_strict_mode(LIBBPF_STRICT_CLEAN_PTRS);
|
|
if (ret) return EX_SOFTWARE;
|
|
|
|
libbpf_set_print(no_print);
|
|
|
|
struct bpf_object_open_opts opts = {
|
|
.relaxed_maps = true,
|
|
.sz = sizeof(struct bpf_object_open_opts),
|
|
};
|
|
struct bpf_object *obj = bpf_object__open_file(path, &opts);
|
|
if (!obj) return kERROR_BPF_OBJECT_OPEN;
|
|
|
|
struct btf *btf = bpf_object__btf(obj);
|
|
if (!btf) return kERROR_BTF_NOT_FOUND;
|
|
|
|
ret = btf__load_into_kernel(btf);
|
|
if (ret) {
|
|
if (errno != EINVAL) return kERROR_LOAD_BTF;
|
|
// For BTF_KIND_FUNC, newer kernels can read the BTF_INFO_VLEN bits of
|
|
// struct btf_type to distinguish static vs. global vs. extern
|
|
// functions, but older kernels enforce that only the BTF_INFO_KIND bits
|
|
// can be set. Retry with non-BTF_INFO_KIND bits zeroed out to handle
|
|
// this case.
|
|
for (unsigned int i = 1; i < btf__type_cnt(btf); ++i) {
|
|
struct btf_type *bt = (struct btf_type *)btf__type_by_id(btf, i);
|
|
if (btf_is_func(bt)) {
|
|
bt->info = (BTF_INFO_KIND(bt->info)) << 24;
|
|
}
|
|
}
|
|
if (btf__load_into_kernel(btf)) return kERROR_LOAD_BTF;
|
|
}
|
|
|
|
btfFd = btf__fd(btf);
|
|
if (sendBtfFd(socketFd, btf__fd(btf))) return kERROR_SEND_BTF_FD;
|
|
|
|
std::ostringstream oss;
|
|
struct bpf_map *m;
|
|
bpf_object__for_each_map(m, obj) {
|
|
unsigned kTid, vTid;
|
|
auto mapName = bpf_map__name(m);
|
|
if (btf__get_map_kv_tids(btf, mapName, bpf_map__key_size(m),
|
|
bpf_map__value_size(m), &kTid, &vTid))
|
|
return kERROR_BTF_TYPE_IDS;
|
|
oss << mapName << ' ' << kTid << ' ' << vTid << '\n';
|
|
}
|
|
write(pipeFd, oss.str().c_str(), oss.str().size());
|
|
|
|
return EX_OK;
|
|
}
|