aboutsummaryrefslogtreecommitdiff
path: root/android/btfloader.cpp
blob: cd8226220b8fdfb228a6f04975e2898b2810b623 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#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;
}