• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <sys/socket.h>
2 #include <sysexits.h>
3 #include <unistd.h>
4 
5 #include <bpf/btf.h>
6 #include <bpf/libbpf.h>
7 
8 #include <cstdlib>
9 #include <sstream>
10 
11 constexpr int kERROR_BPF_OBJECT_OPEN = 1;
12 constexpr int kERROR_BTF_NOT_FOUND = 2;
13 constexpr int kERROR_LOAD_BTF = 3;
14 constexpr int kERROR_SEND_BTF_FD = 4;
15 constexpr int kERROR_BTF_TYPE_IDS = 5;
16 
no_print(enum libbpf_print_level,const char *,va_list)17 static int no_print(enum libbpf_print_level , const char *, va_list ) {
18     return 0;
19 }
20 
sendBtfFd(int socket,int fd)21 int sendBtfFd(int socket, int fd) {
22     char buf[CMSG_SPACE(sizeof(fd))];
23 
24     struct msghdr msg;
25     memset(&msg, 0, sizeof(msg));
26     msg.msg_control = buf;
27     msg.msg_controllen = sizeof(buf);
28 
29     struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
30     cmsg->cmsg_level = SOL_SOCKET;
31     cmsg->cmsg_type = SCM_RIGHTS;
32     cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
33 
34     *(int*)CMSG_DATA(cmsg) = fd;
35     return sendmsg(socket, &msg, 0);
36 }
37 
main(int argc,char ** argv)38 int main(int argc, char **argv) {
39     int ret = 0, socketFd, pipeFd, btfFd;
40     if (argc != 4) return EX_USAGE;
41 
42     socketFd = atoi(argv[1]);
43     pipeFd = atoi(argv[2]);
44 
45     auto path(argv[3]);
46     ret = libbpf_set_strict_mode(LIBBPF_STRICT_CLEAN_PTRS);
47     if (ret) return EX_SOFTWARE;
48 
49     libbpf_set_print(no_print);
50 
51     struct bpf_object_open_opts opts = {
52         .relaxed_maps = true,
53         .sz = sizeof(struct bpf_object_open_opts),
54     };
55     struct bpf_object *obj = bpf_object__open_file(path, &opts);
56     if (!obj) return kERROR_BPF_OBJECT_OPEN;
57 
58     struct btf *btf = bpf_object__btf(obj);
59     if (!btf) return kERROR_BTF_NOT_FOUND;
60 
61     ret = btf__load_into_kernel(btf);
62     if (ret) {
63         if (errno != EINVAL) return kERROR_LOAD_BTF;
64         // For BTF_KIND_FUNC, newer kernels can read the BTF_INFO_VLEN bits of
65         // struct btf_type to distinguish static vs. global vs. extern
66         // functions, but older kernels enforce that only the BTF_INFO_KIND bits
67         // can be set. Retry with non-BTF_INFO_KIND bits zeroed out to handle
68         // this case.
69         for (unsigned int i = 1; i < btf__type_cnt(btf); ++i) {
70             struct btf_type *bt = (struct btf_type *)btf__type_by_id(btf, i);
71             if (btf_is_func(bt)) {
72                 bt->info = (BTF_INFO_KIND(bt->info)) << 24;
73             }
74         }
75         if (btf__load_into_kernel(btf)) return kERROR_LOAD_BTF;
76     }
77 
78     btfFd = btf__fd(btf);
79     if (sendBtfFd(socketFd, btf__fd(btf))) return kERROR_SEND_BTF_FD;
80 
81     std::ostringstream oss;
82     struct bpf_map *m;
83     bpf_object__for_each_map(m, obj) {
84         unsigned kTid, vTid;
85         auto mapName = bpf_map__name(m);
86         if (btf__get_map_kv_tids(btf, mapName, bpf_map__key_size(m),
87                                  bpf_map__value_size(m), &kTid, &vTid))
88             return kERROR_BTF_TYPE_IDS;
89         oss << mapName << ' ' << kTid << ' ' << vTid << '\n';
90     }
91     write(pipeFd, oss.str().c_str(), oss.str().size());
92 
93     return EX_OK;
94 }
95