xref: /openbmc/linux/tools/bpf/bpftool/btf.c (revision f59a3ee6)
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2 /* Copyright (C) 2019 Facebook */
3 
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <linux/err.h>
7 #include <stdbool.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <linux/btf.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 
15 #include <bpf/bpf.h>
16 #include <bpf/btf.h>
17 #include <bpf/hashmap.h>
18 #include <bpf/libbpf.h>
19 
20 #include "json_writer.h"
21 #include "main.h"
22 
23 static const char * const btf_kind_str[NR_BTF_KINDS] = {
24 	[BTF_KIND_UNKN]		= "UNKNOWN",
25 	[BTF_KIND_INT]		= "INT",
26 	[BTF_KIND_PTR]		= "PTR",
27 	[BTF_KIND_ARRAY]	= "ARRAY",
28 	[BTF_KIND_STRUCT]	= "STRUCT",
29 	[BTF_KIND_UNION]	= "UNION",
30 	[BTF_KIND_ENUM]		= "ENUM",
31 	[BTF_KIND_FWD]		= "FWD",
32 	[BTF_KIND_TYPEDEF]	= "TYPEDEF",
33 	[BTF_KIND_VOLATILE]	= "VOLATILE",
34 	[BTF_KIND_CONST]	= "CONST",
35 	[BTF_KIND_RESTRICT]	= "RESTRICT",
36 	[BTF_KIND_FUNC]		= "FUNC",
37 	[BTF_KIND_FUNC_PROTO]	= "FUNC_PROTO",
38 	[BTF_KIND_VAR]		= "VAR",
39 	[BTF_KIND_DATASEC]	= "DATASEC",
40 	[BTF_KIND_FLOAT]	= "FLOAT",
41 	[BTF_KIND_DECL_TAG]	= "DECL_TAG",
42 	[BTF_KIND_TYPE_TAG]	= "TYPE_TAG",
43 	[BTF_KIND_ENUM64]	= "ENUM64",
44 };
45 
46 static const char *btf_int_enc_str(__u8 encoding)
47 {
48 	switch (encoding) {
49 	case 0:
50 		return "(none)";
51 	case BTF_INT_SIGNED:
52 		return "SIGNED";
53 	case BTF_INT_CHAR:
54 		return "CHAR";
55 	case BTF_INT_BOOL:
56 		return "BOOL";
57 	default:
58 		return "UNKN";
59 	}
60 }
61 
62 static const char *btf_var_linkage_str(__u32 linkage)
63 {
64 	switch (linkage) {
65 	case BTF_VAR_STATIC:
66 		return "static";
67 	case BTF_VAR_GLOBAL_ALLOCATED:
68 		return "global";
69 	case BTF_VAR_GLOBAL_EXTERN:
70 		return "extern";
71 	default:
72 		return "(unknown)";
73 	}
74 }
75 
76 static const char *btf_func_linkage_str(const struct btf_type *t)
77 {
78 	switch (btf_vlen(t)) {
79 	case BTF_FUNC_STATIC:
80 		return "static";
81 	case BTF_FUNC_GLOBAL:
82 		return "global";
83 	case BTF_FUNC_EXTERN:
84 		return "extern";
85 	default:
86 		return "(unknown)";
87 	}
88 }
89 
90 static const char *btf_str(const struct btf *btf, __u32 off)
91 {
92 	if (!off)
93 		return "(anon)";
94 	return btf__name_by_offset(btf, off) ? : "(invalid)";
95 }
96 
97 static int btf_kind_safe(int kind)
98 {
99 	return kind <= BTF_KIND_MAX ? kind : BTF_KIND_UNKN;
100 }
101 
102 static int dump_btf_type(const struct btf *btf, __u32 id,
103 			 const struct btf_type *t)
104 {
105 	json_writer_t *w = json_wtr;
106 	int kind = btf_kind(t);
107 
108 	if (json_output) {
109 		jsonw_start_object(w);
110 		jsonw_uint_field(w, "id", id);
111 		jsonw_string_field(w, "kind", btf_kind_str[btf_kind_safe(kind)]);
112 		jsonw_string_field(w, "name", btf_str(btf, t->name_off));
113 	} else {
114 		printf("[%u] %s '%s'", id, btf_kind_str[btf_kind_safe(kind)],
115 		       btf_str(btf, t->name_off));
116 	}
117 
118 	switch (kind) {
119 	case BTF_KIND_INT: {
120 		__u32 v = *(__u32 *)(t + 1);
121 		const char *enc;
122 
123 		enc = btf_int_enc_str(BTF_INT_ENCODING(v));
124 
125 		if (json_output) {
126 			jsonw_uint_field(w, "size", t->size);
127 			jsonw_uint_field(w, "bits_offset", BTF_INT_OFFSET(v));
128 			jsonw_uint_field(w, "nr_bits", BTF_INT_BITS(v));
129 			jsonw_string_field(w, "encoding", enc);
130 		} else {
131 			printf(" size=%u bits_offset=%u nr_bits=%u encoding=%s",
132 			       t->size, BTF_INT_OFFSET(v), BTF_INT_BITS(v),
133 			       enc);
134 		}
135 		break;
136 	}
137 	case BTF_KIND_PTR:
138 	case BTF_KIND_CONST:
139 	case BTF_KIND_VOLATILE:
140 	case BTF_KIND_RESTRICT:
141 	case BTF_KIND_TYPEDEF:
142 	case BTF_KIND_TYPE_TAG:
143 		if (json_output)
144 			jsonw_uint_field(w, "type_id", t->type);
145 		else
146 			printf(" type_id=%u", t->type);
147 		break;
148 	case BTF_KIND_ARRAY: {
149 		const struct btf_array *arr = (const void *)(t + 1);
150 
151 		if (json_output) {
152 			jsonw_uint_field(w, "type_id", arr->type);
153 			jsonw_uint_field(w, "index_type_id", arr->index_type);
154 			jsonw_uint_field(w, "nr_elems", arr->nelems);
155 		} else {
156 			printf(" type_id=%u index_type_id=%u nr_elems=%u",
157 			       arr->type, arr->index_type, arr->nelems);
158 		}
159 		break;
160 	}
161 	case BTF_KIND_STRUCT:
162 	case BTF_KIND_UNION: {
163 		const struct btf_member *m = (const void *)(t + 1);
164 		__u16 vlen = BTF_INFO_VLEN(t->info);
165 		int i;
166 
167 		if (json_output) {
168 			jsonw_uint_field(w, "size", t->size);
169 			jsonw_uint_field(w, "vlen", vlen);
170 			jsonw_name(w, "members");
171 			jsonw_start_array(w);
172 		} else {
173 			printf(" size=%u vlen=%u", t->size, vlen);
174 		}
175 		for (i = 0; i < vlen; i++, m++) {
176 			const char *name = btf_str(btf, m->name_off);
177 			__u32 bit_off, bit_sz;
178 
179 			if (BTF_INFO_KFLAG(t->info)) {
180 				bit_off = BTF_MEMBER_BIT_OFFSET(m->offset);
181 				bit_sz = BTF_MEMBER_BITFIELD_SIZE(m->offset);
182 			} else {
183 				bit_off = m->offset;
184 				bit_sz = 0;
185 			}
186 
187 			if (json_output) {
188 				jsonw_start_object(w);
189 				jsonw_string_field(w, "name", name);
190 				jsonw_uint_field(w, "type_id", m->type);
191 				jsonw_uint_field(w, "bits_offset", bit_off);
192 				if (bit_sz) {
193 					jsonw_uint_field(w, "bitfield_size",
194 							 bit_sz);
195 				}
196 				jsonw_end_object(w);
197 			} else {
198 				printf("\n\t'%s' type_id=%u bits_offset=%u",
199 				       name, m->type, bit_off);
200 				if (bit_sz)
201 					printf(" bitfield_size=%u", bit_sz);
202 			}
203 		}
204 		if (json_output)
205 			jsonw_end_array(w);
206 		break;
207 	}
208 	case BTF_KIND_ENUM: {
209 		const struct btf_enum *v = (const void *)(t + 1);
210 		__u16 vlen = BTF_INFO_VLEN(t->info);
211 		const char *encoding;
212 		int i;
213 
214 		encoding = btf_kflag(t) ? "SIGNED" : "UNSIGNED";
215 		if (json_output) {
216 			jsonw_string_field(w, "encoding", encoding);
217 			jsonw_uint_field(w, "size", t->size);
218 			jsonw_uint_field(w, "vlen", vlen);
219 			jsonw_name(w, "values");
220 			jsonw_start_array(w);
221 		} else {
222 			printf(" encoding=%s size=%u vlen=%u", encoding, t->size, vlen);
223 		}
224 		for (i = 0; i < vlen; i++, v++) {
225 			const char *name = btf_str(btf, v->name_off);
226 
227 			if (json_output) {
228 				jsonw_start_object(w);
229 				jsonw_string_field(w, "name", name);
230 				if (btf_kflag(t))
231 					jsonw_int_field(w, "val", v->val);
232 				else
233 					jsonw_uint_field(w, "val", v->val);
234 				jsonw_end_object(w);
235 			} else {
236 				if (btf_kflag(t))
237 					printf("\n\t'%s' val=%d", name, v->val);
238 				else
239 					printf("\n\t'%s' val=%u", name, v->val);
240 			}
241 		}
242 		if (json_output)
243 			jsonw_end_array(w);
244 		break;
245 	}
246 	case BTF_KIND_ENUM64: {
247 		const struct btf_enum64 *v = btf_enum64(t);
248 		__u16 vlen = btf_vlen(t);
249 		const char *encoding;
250 		int i;
251 
252 		encoding = btf_kflag(t) ? "SIGNED" : "UNSIGNED";
253 		if (json_output) {
254 			jsonw_string_field(w, "encoding", encoding);
255 			jsonw_uint_field(w, "size", t->size);
256 			jsonw_uint_field(w, "vlen", vlen);
257 			jsonw_name(w, "values");
258 			jsonw_start_array(w);
259 		} else {
260 			printf(" encoding=%s size=%u vlen=%u", encoding, t->size, vlen);
261 		}
262 		for (i = 0; i < vlen; i++, v++) {
263 			const char *name = btf_str(btf, v->name_off);
264 			__u64 val = ((__u64)v->val_hi32 << 32) | v->val_lo32;
265 
266 			if (json_output) {
267 				jsonw_start_object(w);
268 				jsonw_string_field(w, "name", name);
269 				if (btf_kflag(t))
270 					jsonw_int_field(w, "val", val);
271 				else
272 					jsonw_uint_field(w, "val", val);
273 				jsonw_end_object(w);
274 			} else {
275 				if (btf_kflag(t))
276 					printf("\n\t'%s' val=%lldLL", name,
277 					       (unsigned long long)val);
278 				else
279 					printf("\n\t'%s' val=%lluULL", name,
280 					       (unsigned long long)val);
281 			}
282 		}
283 		if (json_output)
284 			jsonw_end_array(w);
285 		break;
286 	}
287 	case BTF_KIND_FWD: {
288 		const char *fwd_kind = BTF_INFO_KFLAG(t->info) ? "union"
289 							       : "struct";
290 
291 		if (json_output)
292 			jsonw_string_field(w, "fwd_kind", fwd_kind);
293 		else
294 			printf(" fwd_kind=%s", fwd_kind);
295 		break;
296 	}
297 	case BTF_KIND_FUNC: {
298 		const char *linkage = btf_func_linkage_str(t);
299 
300 		if (json_output) {
301 			jsonw_uint_field(w, "type_id", t->type);
302 			jsonw_string_field(w, "linkage", linkage);
303 		} else {
304 			printf(" type_id=%u linkage=%s", t->type, linkage);
305 		}
306 		break;
307 	}
308 	case BTF_KIND_FUNC_PROTO: {
309 		const struct btf_param *p = (const void *)(t + 1);
310 		__u16 vlen = BTF_INFO_VLEN(t->info);
311 		int i;
312 
313 		if (json_output) {
314 			jsonw_uint_field(w, "ret_type_id", t->type);
315 			jsonw_uint_field(w, "vlen", vlen);
316 			jsonw_name(w, "params");
317 			jsonw_start_array(w);
318 		} else {
319 			printf(" ret_type_id=%u vlen=%u", t->type, vlen);
320 		}
321 		for (i = 0; i < vlen; i++, p++) {
322 			const char *name = btf_str(btf, p->name_off);
323 
324 			if (json_output) {
325 				jsonw_start_object(w);
326 				jsonw_string_field(w, "name", name);
327 				jsonw_uint_field(w, "type_id", p->type);
328 				jsonw_end_object(w);
329 			} else {
330 				printf("\n\t'%s' type_id=%u", name, p->type);
331 			}
332 		}
333 		if (json_output)
334 			jsonw_end_array(w);
335 		break;
336 	}
337 	case BTF_KIND_VAR: {
338 		const struct btf_var *v = (const void *)(t + 1);
339 		const char *linkage;
340 
341 		linkage = btf_var_linkage_str(v->linkage);
342 
343 		if (json_output) {
344 			jsonw_uint_field(w, "type_id", t->type);
345 			jsonw_string_field(w, "linkage", linkage);
346 		} else {
347 			printf(" type_id=%u, linkage=%s", t->type, linkage);
348 		}
349 		break;
350 	}
351 	case BTF_KIND_DATASEC: {
352 		const struct btf_var_secinfo *v = (const void *)(t + 1);
353 		const struct btf_type *vt;
354 		__u16 vlen = BTF_INFO_VLEN(t->info);
355 		int i;
356 
357 		if (json_output) {
358 			jsonw_uint_field(w, "size", t->size);
359 			jsonw_uint_field(w, "vlen", vlen);
360 			jsonw_name(w, "vars");
361 			jsonw_start_array(w);
362 		} else {
363 			printf(" size=%u vlen=%u", t->size, vlen);
364 		}
365 		for (i = 0; i < vlen; i++, v++) {
366 			if (json_output) {
367 				jsonw_start_object(w);
368 				jsonw_uint_field(w, "type_id", v->type);
369 				jsonw_uint_field(w, "offset", v->offset);
370 				jsonw_uint_field(w, "size", v->size);
371 				jsonw_end_object(w);
372 			} else {
373 				printf("\n\ttype_id=%u offset=%u size=%u",
374 				       v->type, v->offset, v->size);
375 
376 				if (v->type < btf__type_cnt(btf)) {
377 					vt = btf__type_by_id(btf, v->type);
378 					printf(" (%s '%s')",
379 					       btf_kind_str[btf_kind_safe(btf_kind(vt))],
380 					       btf_str(btf, vt->name_off));
381 				}
382 			}
383 		}
384 		if (json_output)
385 			jsonw_end_array(w);
386 		break;
387 	}
388 	case BTF_KIND_FLOAT: {
389 		if (json_output)
390 			jsonw_uint_field(w, "size", t->size);
391 		else
392 			printf(" size=%u", t->size);
393 		break;
394 	}
395 	case BTF_KIND_DECL_TAG: {
396 		const struct btf_decl_tag *tag = (const void *)(t + 1);
397 
398 		if (json_output) {
399 			jsonw_uint_field(w, "type_id", t->type);
400 			jsonw_int_field(w, "component_idx", tag->component_idx);
401 		} else {
402 			printf(" type_id=%u component_idx=%d", t->type, tag->component_idx);
403 		}
404 		break;
405 	}
406 	default:
407 		break;
408 	}
409 
410 	if (json_output)
411 		jsonw_end_object(json_wtr);
412 	else
413 		printf("\n");
414 
415 	return 0;
416 }
417 
418 static int dump_btf_raw(const struct btf *btf,
419 			__u32 *root_type_ids, int root_type_cnt)
420 {
421 	const struct btf_type *t;
422 	int i;
423 
424 	if (json_output) {
425 		jsonw_start_object(json_wtr);
426 		jsonw_name(json_wtr, "types");
427 		jsonw_start_array(json_wtr);
428 	}
429 
430 	if (root_type_cnt) {
431 		for (i = 0; i < root_type_cnt; i++) {
432 			t = btf__type_by_id(btf, root_type_ids[i]);
433 			dump_btf_type(btf, root_type_ids[i], t);
434 		}
435 	} else {
436 		const struct btf *base;
437 		int cnt = btf__type_cnt(btf);
438 		int start_id = 1;
439 
440 		base = btf__base_btf(btf);
441 		if (base)
442 			start_id = btf__type_cnt(base);
443 
444 		for (i = start_id; i < cnt; i++) {
445 			t = btf__type_by_id(btf, i);
446 			dump_btf_type(btf, i, t);
447 		}
448 	}
449 
450 	if (json_output) {
451 		jsonw_end_array(json_wtr);
452 		jsonw_end_object(json_wtr);
453 	}
454 	return 0;
455 }
456 
457 static void __printf(2, 0) btf_dump_printf(void *ctx,
458 					   const char *fmt, va_list args)
459 {
460 	vfprintf(stdout, fmt, args);
461 }
462 
463 static int dump_btf_c(const struct btf *btf,
464 		      __u32 *root_type_ids, int root_type_cnt)
465 {
466 	struct btf_dump *d;
467 	int err = 0, i;
468 
469 	d = btf_dump__new(btf, btf_dump_printf, NULL, NULL);
470 	err = libbpf_get_error(d);
471 	if (err)
472 		return err;
473 
474 	printf("#ifndef __VMLINUX_H__\n");
475 	printf("#define __VMLINUX_H__\n");
476 	printf("\n");
477 	printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");
478 	printf("#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)\n");
479 	printf("#endif\n\n");
480 
481 	if (root_type_cnt) {
482 		for (i = 0; i < root_type_cnt; i++) {
483 			err = btf_dump__dump_type(d, root_type_ids[i]);
484 			if (err)
485 				goto done;
486 		}
487 	} else {
488 		int cnt = btf__type_cnt(btf);
489 
490 		for (i = 1; i < cnt; i++) {
491 			err = btf_dump__dump_type(d, i);
492 			if (err)
493 				goto done;
494 		}
495 	}
496 
497 	printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");
498 	printf("#pragma clang attribute pop\n");
499 	printf("#endif\n");
500 	printf("\n");
501 	printf("#endif /* __VMLINUX_H__ */\n");
502 
503 done:
504 	btf_dump__free(d);
505 	return err;
506 }
507 
508 static const char sysfs_vmlinux[] = "/sys/kernel/btf/vmlinux";
509 
510 static struct btf *get_vmlinux_btf_from_sysfs(void)
511 {
512 	struct btf *base;
513 
514 	base = btf__parse(sysfs_vmlinux, NULL);
515 	if (libbpf_get_error(base)) {
516 		p_err("failed to parse vmlinux BTF at '%s': %ld\n",
517 		      sysfs_vmlinux, libbpf_get_error(base));
518 		base = NULL;
519 	}
520 
521 	return base;
522 }
523 
524 #define BTF_NAME_BUFF_LEN 64
525 
526 static bool btf_is_kernel_module(__u32 btf_id)
527 {
528 	struct bpf_btf_info btf_info = {};
529 	char btf_name[BTF_NAME_BUFF_LEN];
530 	int btf_fd;
531 	__u32 len;
532 	int err;
533 
534 	btf_fd = bpf_btf_get_fd_by_id(btf_id);
535 	if (btf_fd < 0) {
536 		p_err("can't get BTF object by id (%u): %s", btf_id, strerror(errno));
537 		return false;
538 	}
539 
540 	len = sizeof(btf_info);
541 	btf_info.name = ptr_to_u64(btf_name);
542 	btf_info.name_len = sizeof(btf_name);
543 	err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len);
544 	close(btf_fd);
545 	if (err) {
546 		p_err("can't get BTF (ID %u) object info: %s", btf_id, strerror(errno));
547 		return false;
548 	}
549 
550 	return btf_info.kernel_btf && strncmp(btf_name, "vmlinux", sizeof(btf_name)) != 0;
551 }
552 
553 static int do_dump(int argc, char **argv)
554 {
555 	struct btf *btf = NULL, *base = NULL;
556 	__u32 root_type_ids[2];
557 	int root_type_cnt = 0;
558 	bool dump_c = false;
559 	__u32 btf_id = -1;
560 	const char *src;
561 	int fd = -1;
562 	int err;
563 
564 	if (!REQ_ARGS(2)) {
565 		usage();
566 		return -1;
567 	}
568 	src = GET_ARG();
569 	if (is_prefix(src, "map")) {
570 		struct bpf_map_info info = {};
571 		__u32 len = sizeof(info);
572 
573 		if (!REQ_ARGS(2)) {
574 			usage();
575 			return -1;
576 		}
577 
578 		fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
579 		if (fd < 0)
580 			return -1;
581 
582 		btf_id = info.btf_id;
583 		if (argc && is_prefix(*argv, "key")) {
584 			root_type_ids[root_type_cnt++] = info.btf_key_type_id;
585 			NEXT_ARG();
586 		} else if (argc && is_prefix(*argv, "value")) {
587 			root_type_ids[root_type_cnt++] = info.btf_value_type_id;
588 			NEXT_ARG();
589 		} else if (argc && is_prefix(*argv, "all")) {
590 			NEXT_ARG();
591 		} else if (argc && is_prefix(*argv, "kv")) {
592 			root_type_ids[root_type_cnt++] = info.btf_key_type_id;
593 			root_type_ids[root_type_cnt++] = info.btf_value_type_id;
594 			NEXT_ARG();
595 		} else {
596 			root_type_ids[root_type_cnt++] = info.btf_key_type_id;
597 			root_type_ids[root_type_cnt++] = info.btf_value_type_id;
598 		}
599 	} else if (is_prefix(src, "prog")) {
600 		struct bpf_prog_info info = {};
601 		__u32 len = sizeof(info);
602 
603 		if (!REQ_ARGS(2)) {
604 			usage();
605 			return -1;
606 		}
607 
608 		fd = prog_parse_fd(&argc, &argv);
609 		if (fd < 0)
610 			return -1;
611 
612 		err = bpf_obj_get_info_by_fd(fd, &info, &len);
613 		if (err) {
614 			p_err("can't get prog info: %s", strerror(errno));
615 			goto done;
616 		}
617 
618 		btf_id = info.btf_id;
619 	} else if (is_prefix(src, "id")) {
620 		char *endptr;
621 
622 		btf_id = strtoul(*argv, &endptr, 0);
623 		if (*endptr) {
624 			p_err("can't parse %s as ID", *argv);
625 			return -1;
626 		}
627 		NEXT_ARG();
628 	} else if (is_prefix(src, "file")) {
629 		const char sysfs_prefix[] = "/sys/kernel/btf/";
630 
631 		if (!base_btf &&
632 		    strncmp(*argv, sysfs_prefix, sizeof(sysfs_prefix) - 1) == 0 &&
633 		    strcmp(*argv, sysfs_vmlinux) != 0)
634 			base = get_vmlinux_btf_from_sysfs();
635 
636 		btf = btf__parse_split(*argv, base ?: base_btf);
637 		err = libbpf_get_error(btf);
638 		if (!btf) {
639 			p_err("failed to load BTF from %s: %s",
640 			      *argv, strerror(errno));
641 			goto done;
642 		}
643 		NEXT_ARG();
644 	} else {
645 		err = -1;
646 		p_err("unrecognized BTF source specifier: '%s'", src);
647 		goto done;
648 	}
649 
650 	while (argc) {
651 		if (is_prefix(*argv, "format")) {
652 			NEXT_ARG();
653 			if (argc < 1) {
654 				p_err("expecting value for 'format' option\n");
655 				err = -EINVAL;
656 				goto done;
657 			}
658 			if (strcmp(*argv, "c") == 0) {
659 				dump_c = true;
660 			} else if (strcmp(*argv, "raw") == 0) {
661 				dump_c = false;
662 			} else {
663 				p_err("unrecognized format specifier: '%s', possible values: raw, c",
664 				      *argv);
665 				err = -EINVAL;
666 				goto done;
667 			}
668 			NEXT_ARG();
669 		} else {
670 			p_err("unrecognized option: '%s'", *argv);
671 			err = -EINVAL;
672 			goto done;
673 		}
674 	}
675 
676 	if (!btf) {
677 		if (!base_btf && btf_is_kernel_module(btf_id)) {
678 			p_info("Warning: valid base BTF was not specified with -B option, falling back to standard base BTF (%s)",
679 			       sysfs_vmlinux);
680 			base_btf = get_vmlinux_btf_from_sysfs();
681 		}
682 
683 		btf = btf__load_from_kernel_by_id_split(btf_id, base_btf);
684 		err = libbpf_get_error(btf);
685 		if (!btf) {
686 			p_err("get btf by id (%u): %s", btf_id, strerror(errno));
687 			goto done;
688 		}
689 	}
690 
691 	if (dump_c) {
692 		if (json_output) {
693 			p_err("JSON output for C-syntax dump is not supported");
694 			err = -ENOTSUP;
695 			goto done;
696 		}
697 		err = dump_btf_c(btf, root_type_ids, root_type_cnt);
698 	} else {
699 		err = dump_btf_raw(btf, root_type_ids, root_type_cnt);
700 	}
701 
702 done:
703 	close(fd);
704 	btf__free(btf);
705 	btf__free(base);
706 	return err;
707 }
708 
709 static int btf_parse_fd(int *argc, char ***argv)
710 {
711 	unsigned int id;
712 	char *endptr;
713 	int fd;
714 
715 	if (!is_prefix(*argv[0], "id")) {
716 		p_err("expected 'id', got: '%s'?", **argv);
717 		return -1;
718 	}
719 	NEXT_ARGP();
720 
721 	id = strtoul(**argv, &endptr, 0);
722 	if (*endptr) {
723 		p_err("can't parse %s as ID", **argv);
724 		return -1;
725 	}
726 	NEXT_ARGP();
727 
728 	fd = bpf_btf_get_fd_by_id(id);
729 	if (fd < 0)
730 		p_err("can't get BTF object by id (%u): %s",
731 		      id, strerror(errno));
732 
733 	return fd;
734 }
735 
736 static int
737 build_btf_type_table(struct hashmap *tab, enum bpf_obj_type type,
738 		     void *info, __u32 *len)
739 {
740 	static const char * const names[] = {
741 		[BPF_OBJ_UNKNOWN]	= "unknown",
742 		[BPF_OBJ_PROG]		= "prog",
743 		[BPF_OBJ_MAP]		= "map",
744 	};
745 	__u32 btf_id, id = 0;
746 	int err;
747 	int fd;
748 
749 	while (true) {
750 		switch (type) {
751 		case BPF_OBJ_PROG:
752 			err = bpf_prog_get_next_id(id, &id);
753 			break;
754 		case BPF_OBJ_MAP:
755 			err = bpf_map_get_next_id(id, &id);
756 			break;
757 		default:
758 			err = -1;
759 			p_err("unexpected object type: %d", type);
760 			goto err_free;
761 		}
762 		if (err) {
763 			if (errno == ENOENT) {
764 				err = 0;
765 				break;
766 			}
767 			p_err("can't get next %s: %s%s", names[type],
768 			      strerror(errno),
769 			      errno == EINVAL ? " -- kernel too old?" : "");
770 			goto err_free;
771 		}
772 
773 		switch (type) {
774 		case BPF_OBJ_PROG:
775 			fd = bpf_prog_get_fd_by_id(id);
776 			break;
777 		case BPF_OBJ_MAP:
778 			fd = bpf_map_get_fd_by_id(id);
779 			break;
780 		default:
781 			err = -1;
782 			p_err("unexpected object type: %d", type);
783 			goto err_free;
784 		}
785 		if (fd < 0) {
786 			if (errno == ENOENT)
787 				continue;
788 			p_err("can't get %s by id (%u): %s", names[type], id,
789 			      strerror(errno));
790 			err = -1;
791 			goto err_free;
792 		}
793 
794 		memset(info, 0, *len);
795 		err = bpf_obj_get_info_by_fd(fd, info, len);
796 		close(fd);
797 		if (err) {
798 			p_err("can't get %s info: %s", names[type],
799 			      strerror(errno));
800 			goto err_free;
801 		}
802 
803 		switch (type) {
804 		case BPF_OBJ_PROG:
805 			btf_id = ((struct bpf_prog_info *)info)->btf_id;
806 			break;
807 		case BPF_OBJ_MAP:
808 			btf_id = ((struct bpf_map_info *)info)->btf_id;
809 			break;
810 		default:
811 			err = -1;
812 			p_err("unexpected object type: %d", type);
813 			goto err_free;
814 		}
815 		if (!btf_id)
816 			continue;
817 
818 		err = hashmap__append(tab, u32_as_hash_field(btf_id),
819 				      u32_as_hash_field(id));
820 		if (err) {
821 			p_err("failed to append entry to hashmap for BTF ID %u, object ID %u: %s",
822 			      btf_id, id, strerror(-err));
823 			goto err_free;
824 		}
825 	}
826 
827 	return 0;
828 
829 err_free:
830 	hashmap__free(tab);
831 	return err;
832 }
833 
834 static int
835 build_btf_tables(struct hashmap *btf_prog_table,
836 		 struct hashmap *btf_map_table)
837 {
838 	struct bpf_prog_info prog_info;
839 	__u32 prog_len = sizeof(prog_info);
840 	struct bpf_map_info map_info;
841 	__u32 map_len = sizeof(map_info);
842 	int err = 0;
843 
844 	err = build_btf_type_table(btf_prog_table, BPF_OBJ_PROG, &prog_info,
845 				   &prog_len);
846 	if (err)
847 		return err;
848 
849 	err = build_btf_type_table(btf_map_table, BPF_OBJ_MAP, &map_info,
850 				   &map_len);
851 	if (err) {
852 		hashmap__free(btf_prog_table);
853 		return err;
854 	}
855 
856 	return 0;
857 }
858 
859 static void
860 show_btf_plain(struct bpf_btf_info *info, int fd,
861 	       struct hashmap *btf_prog_table,
862 	       struct hashmap *btf_map_table)
863 {
864 	struct hashmap_entry *entry;
865 	const char *name = u64_to_ptr(info->name);
866 	int n;
867 
868 	printf("%u: ", info->id);
869 	if (info->kernel_btf)
870 		printf("name [%s]  ", name);
871 	else if (name && name[0])
872 		printf("name %s  ", name);
873 	else
874 		printf("name <anon>  ");
875 	printf("size %uB", info->btf_size);
876 
877 	n = 0;
878 	hashmap__for_each_key_entry(btf_prog_table, entry,
879 				    u32_as_hash_field(info->id)) {
880 		printf("%s%u", n++ == 0 ? "  prog_ids " : ",",
881 		       hash_field_as_u32(entry->value));
882 	}
883 
884 	n = 0;
885 	hashmap__for_each_key_entry(btf_map_table, entry,
886 				    u32_as_hash_field(info->id)) {
887 		printf("%s%u", n++ == 0 ? "  map_ids " : ",",
888 		       hash_field_as_u32(entry->value));
889 	}
890 
891 	emit_obj_refs_plain(refs_table, info->id, "\n\tpids ");
892 
893 	printf("\n");
894 }
895 
896 static void
897 show_btf_json(struct bpf_btf_info *info, int fd,
898 	      struct hashmap *btf_prog_table,
899 	      struct hashmap *btf_map_table)
900 {
901 	struct hashmap_entry *entry;
902 	const char *name = u64_to_ptr(info->name);
903 
904 	jsonw_start_object(json_wtr);	/* btf object */
905 	jsonw_uint_field(json_wtr, "id", info->id);
906 	jsonw_uint_field(json_wtr, "size", info->btf_size);
907 
908 	jsonw_name(json_wtr, "prog_ids");
909 	jsonw_start_array(json_wtr);	/* prog_ids */
910 	hashmap__for_each_key_entry(btf_prog_table, entry,
911 				    u32_as_hash_field(info->id)) {
912 		jsonw_uint(json_wtr, hash_field_as_u32(entry->value));
913 	}
914 	jsonw_end_array(json_wtr);	/* prog_ids */
915 
916 	jsonw_name(json_wtr, "map_ids");
917 	jsonw_start_array(json_wtr);	/* map_ids */
918 	hashmap__for_each_key_entry(btf_map_table, entry,
919 				    u32_as_hash_field(info->id)) {
920 		jsonw_uint(json_wtr, hash_field_as_u32(entry->value));
921 	}
922 	jsonw_end_array(json_wtr);	/* map_ids */
923 
924 	emit_obj_refs_json(refs_table, info->id, json_wtr); /* pids */
925 
926 	jsonw_bool_field(json_wtr, "kernel", info->kernel_btf);
927 
928 	if (name && name[0])
929 		jsonw_string_field(json_wtr, "name", name);
930 
931 	jsonw_end_object(json_wtr);	/* btf object */
932 }
933 
934 static int
935 show_btf(int fd, struct hashmap *btf_prog_table,
936 	 struct hashmap *btf_map_table)
937 {
938 	struct bpf_btf_info info;
939 	__u32 len = sizeof(info);
940 	char name[64];
941 	int err;
942 
943 	memset(&info, 0, sizeof(info));
944 	err = bpf_obj_get_info_by_fd(fd, &info, &len);
945 	if (err) {
946 		p_err("can't get BTF object info: %s", strerror(errno));
947 		return -1;
948 	}
949 	/* if kernel support emitting BTF object name, pass name pointer */
950 	if (info.name_len) {
951 		memset(&info, 0, sizeof(info));
952 		info.name_len = sizeof(name);
953 		info.name = ptr_to_u64(name);
954 		len = sizeof(info);
955 
956 		err = bpf_obj_get_info_by_fd(fd, &info, &len);
957 		if (err) {
958 			p_err("can't get BTF object info: %s", strerror(errno));
959 			return -1;
960 		}
961 	}
962 
963 	if (json_output)
964 		show_btf_json(&info, fd, btf_prog_table, btf_map_table);
965 	else
966 		show_btf_plain(&info, fd, btf_prog_table, btf_map_table);
967 
968 	return 0;
969 }
970 
971 static int do_show(int argc, char **argv)
972 {
973 	struct hashmap *btf_prog_table;
974 	struct hashmap *btf_map_table;
975 	int err, fd = -1;
976 	__u32 id = 0;
977 
978 	if (argc == 2) {
979 		fd = btf_parse_fd(&argc, &argv);
980 		if (fd < 0)
981 			return -1;
982 	}
983 
984 	if (argc) {
985 		if (fd >= 0)
986 			close(fd);
987 		return BAD_ARG();
988 	}
989 
990 	btf_prog_table = hashmap__new(hash_fn_for_key_as_id,
991 				      equal_fn_for_key_as_id, NULL);
992 	btf_map_table = hashmap__new(hash_fn_for_key_as_id,
993 				     equal_fn_for_key_as_id, NULL);
994 	if (IS_ERR(btf_prog_table) || IS_ERR(btf_map_table)) {
995 		hashmap__free(btf_prog_table);
996 		hashmap__free(btf_map_table);
997 		if (fd >= 0)
998 			close(fd);
999 		p_err("failed to create hashmap for object references");
1000 		return -1;
1001 	}
1002 	err = build_btf_tables(btf_prog_table, btf_map_table);
1003 	if (err) {
1004 		if (fd >= 0)
1005 			close(fd);
1006 		return err;
1007 	}
1008 	build_obj_refs_table(&refs_table, BPF_OBJ_BTF);
1009 
1010 	if (fd >= 0) {
1011 		err = show_btf(fd, btf_prog_table, btf_map_table);
1012 		close(fd);
1013 		goto exit_free;
1014 	}
1015 
1016 	if (json_output)
1017 		jsonw_start_array(json_wtr);	/* root array */
1018 
1019 	while (true) {
1020 		err = bpf_btf_get_next_id(id, &id);
1021 		if (err) {
1022 			if (errno == ENOENT) {
1023 				err = 0;
1024 				break;
1025 			}
1026 			p_err("can't get next BTF object: %s%s",
1027 			      strerror(errno),
1028 			      errno == EINVAL ? " -- kernel too old?" : "");
1029 			err = -1;
1030 			break;
1031 		}
1032 
1033 		fd = bpf_btf_get_fd_by_id(id);
1034 		if (fd < 0) {
1035 			if (errno == ENOENT)
1036 				continue;
1037 			p_err("can't get BTF object by id (%u): %s",
1038 			      id, strerror(errno));
1039 			err = -1;
1040 			break;
1041 		}
1042 
1043 		err = show_btf(fd, btf_prog_table, btf_map_table);
1044 		close(fd);
1045 		if (err)
1046 			break;
1047 	}
1048 
1049 	if (json_output)
1050 		jsonw_end_array(json_wtr);	/* root array */
1051 
1052 exit_free:
1053 	hashmap__free(btf_prog_table);
1054 	hashmap__free(btf_map_table);
1055 	delete_obj_refs_table(refs_table);
1056 
1057 	return err;
1058 }
1059 
1060 static int do_help(int argc, char **argv)
1061 {
1062 	if (json_output) {
1063 		jsonw_null(json_wtr);
1064 		return 0;
1065 	}
1066 
1067 	fprintf(stderr,
1068 		"Usage: %1$s %2$s { show | list } [id BTF_ID]\n"
1069 		"       %1$s %2$s dump BTF_SRC [format FORMAT]\n"
1070 		"       %1$s %2$s help\n"
1071 		"\n"
1072 		"       BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n"
1073 		"       FORMAT  := { raw | c }\n"
1074 		"       " HELP_SPEC_MAP "\n"
1075 		"       " HELP_SPEC_PROGRAM "\n"
1076 		"       " HELP_SPEC_OPTIONS " |\n"
1077 		"                    {-B|--base-btf} }\n"
1078 		"",
1079 		bin_name, "btf");
1080 
1081 	return 0;
1082 }
1083 
1084 static const struct cmd cmds[] = {
1085 	{ "show",	do_show },
1086 	{ "list",	do_show },
1087 	{ "help",	do_help },
1088 	{ "dump",	do_dump },
1089 	{ 0 }
1090 };
1091 
1092 int do_btf(int argc, char **argv)
1093 {
1094 	return cmd_select(cmds, argc, argv, do_help);
1095 }
1096