xref: /aosp_15_r20/external/bcc/libbpf-tools/btf_helpers.c (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
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