1*387f9dfdSAndroid Build Coastguard Worker /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2*387f9dfdSAndroid Build Coastguard Worker
3*387f9dfdSAndroid Build Coastguard Worker #include <errno.h>
4*387f9dfdSAndroid Build Coastguard Worker #include <stdio.h>
5*387f9dfdSAndroid Build Coastguard Worker #include <stdlib.h>
6*387f9dfdSAndroid Build Coastguard Worker #include <string.h>
7*387f9dfdSAndroid Build Coastguard Worker #include <sys/utsname.h>
8*387f9dfdSAndroid Build Coastguard Worker #include <zlib.h>
9*387f9dfdSAndroid Build Coastguard Worker
10*387f9dfdSAndroid Build Coastguard Worker #include "trace_helpers.h"
11*387f9dfdSAndroid Build Coastguard Worker #include "btf_helpers.h"
12*387f9dfdSAndroid Build Coastguard Worker
13*387f9dfdSAndroid Build Coastguard Worker extern unsigned char _binary_min_core_btfs_tar_gz_start[] __attribute__((weak));
14*387f9dfdSAndroid Build Coastguard Worker extern unsigned char _binary_min_core_btfs_tar_gz_end[] __attribute__((weak));
15*387f9dfdSAndroid Build Coastguard Worker
16*387f9dfdSAndroid Build Coastguard Worker #define FIELD_LEN 65
17*387f9dfdSAndroid Build Coastguard Worker #define ID_FMT "ID=%64s"
18*387f9dfdSAndroid Build Coastguard Worker #define VERSION_FMT "VERSION_ID=\"%64s"
19*387f9dfdSAndroid Build Coastguard Worker
20*387f9dfdSAndroid Build Coastguard Worker struct os_info {
21*387f9dfdSAndroid Build Coastguard Worker char id[FIELD_LEN];
22*387f9dfdSAndroid Build Coastguard Worker char version[FIELD_LEN];
23*387f9dfdSAndroid Build Coastguard Worker char arch[FIELD_LEN];
24*387f9dfdSAndroid Build Coastguard Worker char kernel_release[FIELD_LEN];
25*387f9dfdSAndroid Build Coastguard Worker };
26*387f9dfdSAndroid Build Coastguard Worker
get_os_info()27*387f9dfdSAndroid Build Coastguard Worker static struct os_info * get_os_info()
28*387f9dfdSAndroid Build Coastguard Worker {
29*387f9dfdSAndroid Build Coastguard Worker struct os_info *info = NULL;
30*387f9dfdSAndroid Build Coastguard Worker struct utsname u;
31*387f9dfdSAndroid Build Coastguard Worker size_t len = 0;
32*387f9dfdSAndroid Build Coastguard Worker ssize_t read;
33*387f9dfdSAndroid Build Coastguard Worker char *line = NULL;
34*387f9dfdSAndroid Build Coastguard Worker FILE *f;
35*387f9dfdSAndroid Build Coastguard Worker
36*387f9dfdSAndroid Build Coastguard Worker if (uname(&u) == -1)
37*387f9dfdSAndroid Build Coastguard Worker return NULL;
38*387f9dfdSAndroid Build Coastguard Worker
39*387f9dfdSAndroid Build Coastguard Worker f = fopen("/etc/os-release", "r");
40*387f9dfdSAndroid Build Coastguard Worker if (!f)
41*387f9dfdSAndroid Build Coastguard Worker return NULL;
42*387f9dfdSAndroid Build Coastguard Worker
43*387f9dfdSAndroid Build Coastguard Worker info = calloc(1, sizeof(*info));
44*387f9dfdSAndroid Build Coastguard Worker if (!info)
45*387f9dfdSAndroid Build Coastguard Worker goto out;
46*387f9dfdSAndroid Build Coastguard Worker
47*387f9dfdSAndroid Build Coastguard Worker strncpy(info->kernel_release, u.release, FIELD_LEN);
48*387f9dfdSAndroid Build Coastguard Worker strncpy(info->arch, u.machine, FIELD_LEN);
49*387f9dfdSAndroid Build Coastguard Worker
50*387f9dfdSAndroid Build Coastguard Worker while ((read = getline(&line, &len, f)) != -1) {
51*387f9dfdSAndroid Build Coastguard Worker if (sscanf(line, ID_FMT, info->id) == 1)
52*387f9dfdSAndroid Build Coastguard Worker continue;
53*387f9dfdSAndroid Build Coastguard Worker
54*387f9dfdSAndroid Build Coastguard Worker if (sscanf(line, VERSION_FMT, info->version) == 1) {
55*387f9dfdSAndroid Build Coastguard Worker /* remove '"' suffix */
56*387f9dfdSAndroid Build Coastguard Worker info->version[strlen(info->version) - 1] = 0;
57*387f9dfdSAndroid Build Coastguard Worker continue;
58*387f9dfdSAndroid Build Coastguard Worker }
59*387f9dfdSAndroid Build Coastguard Worker }
60*387f9dfdSAndroid Build Coastguard Worker
61*387f9dfdSAndroid Build Coastguard Worker out:
62*387f9dfdSAndroid Build Coastguard Worker free(line);
63*387f9dfdSAndroid Build Coastguard Worker fclose(f);
64*387f9dfdSAndroid Build Coastguard Worker
65*387f9dfdSAndroid Build Coastguard Worker return info;
66*387f9dfdSAndroid Build Coastguard Worker }
67*387f9dfdSAndroid Build Coastguard Worker
68*387f9dfdSAndroid Build Coastguard Worker #define INITIAL_BUF_SIZE (1024 * 1024 * 4) /* 4MB */
69*387f9dfdSAndroid Build Coastguard Worker
70*387f9dfdSAndroid Build Coastguard Worker /* adapted from https://zlib.net/zlib_how.html */
71*387f9dfdSAndroid Build Coastguard Worker static int
inflate_gz(unsigned char * src,int src_size,unsigned char ** dst,int * dst_size)72*387f9dfdSAndroid Build Coastguard Worker inflate_gz(unsigned char *src, int src_size, unsigned char **dst, int *dst_size)
73*387f9dfdSAndroid Build Coastguard Worker {
74*387f9dfdSAndroid Build Coastguard Worker size_t size = INITIAL_BUF_SIZE;
75*387f9dfdSAndroid Build Coastguard Worker size_t next_size = size;
76*387f9dfdSAndroid Build Coastguard Worker z_stream strm;
77*387f9dfdSAndroid Build Coastguard Worker void *tmp;
78*387f9dfdSAndroid Build Coastguard Worker int ret;
79*387f9dfdSAndroid Build Coastguard Worker
80*387f9dfdSAndroid Build Coastguard Worker strm.zalloc = Z_NULL;
81*387f9dfdSAndroid Build Coastguard Worker strm.zfree = Z_NULL;
82*387f9dfdSAndroid Build Coastguard Worker strm.opaque = Z_NULL;
83*387f9dfdSAndroid Build Coastguard Worker strm.avail_in = 0;
84*387f9dfdSAndroid Build Coastguard Worker strm.next_in = Z_NULL;
85*387f9dfdSAndroid Build Coastguard Worker
86*387f9dfdSAndroid Build Coastguard Worker ret = inflateInit2(&strm, 16 + MAX_WBITS);
87*387f9dfdSAndroid Build Coastguard Worker if (ret != Z_OK)
88*387f9dfdSAndroid Build Coastguard Worker return -EINVAL;
89*387f9dfdSAndroid Build Coastguard Worker
90*387f9dfdSAndroid Build Coastguard Worker *dst = malloc(size);
91*387f9dfdSAndroid Build Coastguard Worker if (!*dst)
92*387f9dfdSAndroid Build Coastguard Worker return -ENOMEM;
93*387f9dfdSAndroid Build Coastguard Worker
94*387f9dfdSAndroid Build Coastguard Worker strm.next_in = src;
95*387f9dfdSAndroid Build Coastguard Worker strm.avail_in = src_size;
96*387f9dfdSAndroid Build Coastguard Worker
97*387f9dfdSAndroid Build Coastguard Worker /* run inflate() on input until it returns Z_STREAM_END */
98*387f9dfdSAndroid Build Coastguard Worker do {
99*387f9dfdSAndroid Build Coastguard Worker strm.next_out = *dst + strm.total_out;
100*387f9dfdSAndroid Build Coastguard Worker strm.avail_out = next_size;
101*387f9dfdSAndroid Build Coastguard Worker ret = inflate(&strm, Z_NO_FLUSH);
102*387f9dfdSAndroid Build Coastguard Worker if (ret != Z_OK && ret != Z_STREAM_END)
103*387f9dfdSAndroid Build Coastguard Worker goto out_err;
104*387f9dfdSAndroid Build Coastguard Worker /* we need more space */
105*387f9dfdSAndroid Build Coastguard Worker if (strm.avail_out == 0) {
106*387f9dfdSAndroid Build Coastguard Worker next_size = size;
107*387f9dfdSAndroid Build Coastguard Worker size *= 2;
108*387f9dfdSAndroid Build Coastguard Worker tmp = realloc(*dst, size);
109*387f9dfdSAndroid Build Coastguard Worker if (!tmp) {
110*387f9dfdSAndroid Build Coastguard Worker ret = -ENOMEM;
111*387f9dfdSAndroid Build Coastguard Worker goto out_err;
112*387f9dfdSAndroid Build Coastguard Worker }
113*387f9dfdSAndroid Build Coastguard Worker *dst = tmp;
114*387f9dfdSAndroid Build Coastguard Worker }
115*387f9dfdSAndroid Build Coastguard Worker } while (ret != Z_STREAM_END);
116*387f9dfdSAndroid Build Coastguard Worker
117*387f9dfdSAndroid Build Coastguard Worker *dst_size = strm.total_out;
118*387f9dfdSAndroid Build Coastguard Worker
119*387f9dfdSAndroid Build Coastguard Worker /* clean up and return */
120*387f9dfdSAndroid Build Coastguard Worker ret = inflateEnd(&strm);
121*387f9dfdSAndroid Build Coastguard Worker if (ret != Z_OK) {
122*387f9dfdSAndroid Build Coastguard Worker ret = -EINVAL;
123*387f9dfdSAndroid Build Coastguard Worker goto out_err;
124*387f9dfdSAndroid Build Coastguard Worker }
125*387f9dfdSAndroid Build Coastguard Worker return 0;
126*387f9dfdSAndroid Build Coastguard Worker
127*387f9dfdSAndroid Build Coastguard Worker out_err:
128*387f9dfdSAndroid Build Coastguard Worker free(*dst);
129*387f9dfdSAndroid Build Coastguard Worker *dst = NULL;
130*387f9dfdSAndroid Build Coastguard Worker return ret;
131*387f9dfdSAndroid Build Coastguard Worker }
132*387f9dfdSAndroid Build Coastguard Worker
133*387f9dfdSAndroid Build Coastguard Worker /* tar header from https://github.com/tklauser/libtar/blob/v1.2.20/lib/libtar.h#L39-L60 */
134*387f9dfdSAndroid Build Coastguard Worker struct tar_header {
135*387f9dfdSAndroid Build Coastguard Worker char name[100];
136*387f9dfdSAndroid Build Coastguard Worker char mode[8];
137*387f9dfdSAndroid Build Coastguard Worker char uid[8];
138*387f9dfdSAndroid Build Coastguard Worker char gid[8];
139*387f9dfdSAndroid Build Coastguard Worker char size[12];
140*387f9dfdSAndroid Build Coastguard Worker char mtime[12];
141*387f9dfdSAndroid Build Coastguard Worker char chksum[8];
142*387f9dfdSAndroid Build Coastguard Worker char typeflag;
143*387f9dfdSAndroid Build Coastguard Worker char linkname[100];
144*387f9dfdSAndroid Build Coastguard Worker char magic[6];
145*387f9dfdSAndroid Build Coastguard Worker char version[2];
146*387f9dfdSAndroid Build Coastguard Worker char uname[32];
147*387f9dfdSAndroid Build Coastguard Worker char gname[32];
148*387f9dfdSAndroid Build Coastguard Worker char devmajor[8];
149*387f9dfdSAndroid Build Coastguard Worker char devminor[8];
150*387f9dfdSAndroid Build Coastguard Worker char prefix[155];
151*387f9dfdSAndroid Build Coastguard Worker char padding[12];
152*387f9dfdSAndroid Build Coastguard Worker };
153*387f9dfdSAndroid Build Coastguard Worker
tar_file_start(struct tar_header * tar,const char * name,int * length)154*387f9dfdSAndroid Build Coastguard Worker static char *tar_file_start(struct tar_header *tar, const char *name, int *length)
155*387f9dfdSAndroid Build Coastguard Worker {
156*387f9dfdSAndroid Build Coastguard Worker while (tar->name[0]) {
157*387f9dfdSAndroid Build Coastguard Worker sscanf(tar->size, "%o", length);
158*387f9dfdSAndroid Build Coastguard Worker if (!strcmp(tar->name, name))
159*387f9dfdSAndroid Build Coastguard Worker return (char *)(tar + 1);
160*387f9dfdSAndroid Build Coastguard Worker tar += 1 + (*length + 511)/512;
161*387f9dfdSAndroid Build Coastguard Worker }
162*387f9dfdSAndroid Build Coastguard Worker return NULL;
163*387f9dfdSAndroid Build Coastguard Worker }
164*387f9dfdSAndroid Build Coastguard Worker
ensure_core_btf(struct bpf_object_open_opts * opts)165*387f9dfdSAndroid Build Coastguard Worker int ensure_core_btf(struct bpf_object_open_opts *opts)
166*387f9dfdSAndroid Build Coastguard Worker {
167*387f9dfdSAndroid Build Coastguard Worker char name_fmt[] = "./%s/%s/%s/%s.btf";
168*387f9dfdSAndroid Build Coastguard Worker char btf_path[] = "/tmp/bcc-libbpf-tools.btf.XXXXXX";
169*387f9dfdSAndroid Build Coastguard Worker struct os_info *info = NULL;
170*387f9dfdSAndroid Build Coastguard Worker unsigned char *dst_buf = NULL;
171*387f9dfdSAndroid Build Coastguard Worker char *file_start;
172*387f9dfdSAndroid Build Coastguard Worker int dst_size = 0;
173*387f9dfdSAndroid Build Coastguard Worker char name[100];
174*387f9dfdSAndroid Build Coastguard Worker FILE *dst = NULL;
175*387f9dfdSAndroid Build Coastguard Worker int ret;
176*387f9dfdSAndroid Build Coastguard Worker
177*387f9dfdSAndroid Build Coastguard Worker /* do nothing if the system provides BTF */
178*387f9dfdSAndroid Build Coastguard Worker if (vmlinux_btf_exists())
179*387f9dfdSAndroid Build Coastguard Worker return 0;
180*387f9dfdSAndroid Build Coastguard Worker
181*387f9dfdSAndroid Build Coastguard Worker /* compiled without min core btfs */
182*387f9dfdSAndroid Build Coastguard Worker if (!_binary_min_core_btfs_tar_gz_start)
183*387f9dfdSAndroid Build Coastguard Worker return -EOPNOTSUPP;
184*387f9dfdSAndroid Build Coastguard Worker
185*387f9dfdSAndroid Build Coastguard Worker info = get_os_info();
186*387f9dfdSAndroid Build Coastguard Worker if (!info)
187*387f9dfdSAndroid Build Coastguard Worker return -errno;
188*387f9dfdSAndroid Build Coastguard Worker
189*387f9dfdSAndroid Build Coastguard Worker ret = mkstemp(btf_path);
190*387f9dfdSAndroid Build Coastguard Worker if (ret < 0) {
191*387f9dfdSAndroid Build Coastguard Worker ret = -errno;
192*387f9dfdSAndroid Build Coastguard Worker goto out;
193*387f9dfdSAndroid Build Coastguard Worker }
194*387f9dfdSAndroid Build Coastguard Worker
195*387f9dfdSAndroid Build Coastguard Worker dst = fdopen(ret, "wb");
196*387f9dfdSAndroid Build Coastguard Worker if (!dst) {
197*387f9dfdSAndroid Build Coastguard Worker ret = -errno;
198*387f9dfdSAndroid Build Coastguard Worker goto out;
199*387f9dfdSAndroid Build Coastguard Worker }
200*387f9dfdSAndroid Build Coastguard Worker
201*387f9dfdSAndroid Build Coastguard Worker ret = snprintf(name, sizeof(name), name_fmt, info->id, info->version,
202*387f9dfdSAndroid Build Coastguard Worker info->arch, info->kernel_release);
203*387f9dfdSAndroid Build Coastguard Worker if (ret < 0 || ret == sizeof(name)) {
204*387f9dfdSAndroid Build Coastguard Worker ret = -EINVAL;
205*387f9dfdSAndroid Build Coastguard Worker goto out;
206*387f9dfdSAndroid Build Coastguard Worker }
207*387f9dfdSAndroid Build Coastguard Worker
208*387f9dfdSAndroid Build Coastguard Worker ret = inflate_gz(_binary_min_core_btfs_tar_gz_start,
209*387f9dfdSAndroid Build Coastguard Worker _binary_min_core_btfs_tar_gz_end - _binary_min_core_btfs_tar_gz_start,
210*387f9dfdSAndroid Build Coastguard Worker &dst_buf, &dst_size);
211*387f9dfdSAndroid Build Coastguard Worker if (ret < 0)
212*387f9dfdSAndroid Build Coastguard Worker goto out;
213*387f9dfdSAndroid Build Coastguard Worker
214*387f9dfdSAndroid Build Coastguard Worker ret = 0;
215*387f9dfdSAndroid Build Coastguard Worker file_start = tar_file_start((struct tar_header *)dst_buf, name, &dst_size);
216*387f9dfdSAndroid Build Coastguard Worker if (!file_start) {
217*387f9dfdSAndroid Build Coastguard Worker ret = -EINVAL;
218*387f9dfdSAndroid Build Coastguard Worker goto out;
219*387f9dfdSAndroid Build Coastguard Worker }
220*387f9dfdSAndroid Build Coastguard Worker
221*387f9dfdSAndroid Build Coastguard Worker if (fwrite(file_start, 1, dst_size, dst) != dst_size) {
222*387f9dfdSAndroid Build Coastguard Worker ret = -ferror(dst);
223*387f9dfdSAndroid Build Coastguard Worker goto out;
224*387f9dfdSAndroid Build Coastguard Worker }
225*387f9dfdSAndroid Build Coastguard Worker
226*387f9dfdSAndroid Build Coastguard Worker opts->btf_custom_path = strdup(btf_path);
227*387f9dfdSAndroid Build Coastguard Worker if (!opts->btf_custom_path)
228*387f9dfdSAndroid Build Coastguard Worker ret = -ENOMEM;
229*387f9dfdSAndroid Build Coastguard Worker
230*387f9dfdSAndroid Build Coastguard Worker out:
231*387f9dfdSAndroid Build Coastguard Worker free(info);
232*387f9dfdSAndroid Build Coastguard Worker fclose(dst);
233*387f9dfdSAndroid Build Coastguard Worker free(dst_buf);
234*387f9dfdSAndroid Build Coastguard Worker
235*387f9dfdSAndroid Build Coastguard Worker return ret;
236*387f9dfdSAndroid Build Coastguard Worker }
237*387f9dfdSAndroid Build Coastguard Worker
cleanup_core_btf(struct bpf_object_open_opts * opts)238*387f9dfdSAndroid Build Coastguard Worker void cleanup_core_btf(struct bpf_object_open_opts *opts) {
239*387f9dfdSAndroid Build Coastguard Worker if (!opts)
240*387f9dfdSAndroid Build Coastguard Worker return;
241*387f9dfdSAndroid Build Coastguard Worker
242*387f9dfdSAndroid Build Coastguard Worker if (!opts->btf_custom_path)
243*387f9dfdSAndroid Build Coastguard Worker return;
244*387f9dfdSAndroid Build Coastguard Worker
245*387f9dfdSAndroid Build Coastguard Worker unlink(opts->btf_custom_path);
246*387f9dfdSAndroid Build Coastguard Worker free((void *)opts->btf_custom_path);
247*387f9dfdSAndroid Build Coastguard Worker }
248