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