xref: /openbmc/linux/tools/bpf/bpftool/btf.c (revision e7f127b2)
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 	err = libbpf_get_error(d);
425 	if (err)
426 		return err;
427 
428 	printf("#ifndef __VMLINUX_H__\n");
429 	printf("#define __VMLINUX_H__\n");
430 	printf("\n");
431 	printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");
432 	printf("#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)\n");
433 	printf("#endif\n\n");
434 
435 	if (root_type_cnt) {
436 		for (i = 0; i < root_type_cnt; i++) {
437 			err = btf_dump__dump_type(d, root_type_ids[i]);
438 			if (err)
439 				goto done;
440 		}
441 	} else {
442 		int cnt = btf__type_cnt(btf);
443 
444 		for (i = 1; i < cnt; i++) {
445 			err = btf_dump__dump_type(d, i);
446 			if (err)
447 				goto done;
448 		}
449 	}
450 
451 	printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");
452 	printf("#pragma clang attribute pop\n");
453 	printf("#endif\n");
454 	printf("\n");
455 	printf("#endif /* __VMLINUX_H__ */\n");
456 
457 done:
458 	btf_dump__free(d);
459 	return err;
460 }
461 
462 static int do_dump(int argc, char **argv)
463 {
464 	struct btf *btf = NULL, *base = NULL;
465 	__u32 root_type_ids[2];
466 	int root_type_cnt = 0;
467 	bool dump_c = false;
468 	__u32 btf_id = -1;
469 	const char *src;
470 	int fd = -1;
471 	int err;
472 
473 	if (!REQ_ARGS(2)) {
474 		usage();
475 		return -1;
476 	}
477 	src = GET_ARG();
478 	if (is_prefix(src, "map")) {
479 		struct bpf_map_info info = {};
480 		__u32 len = sizeof(info);
481 
482 		if (!REQ_ARGS(2)) {
483 			usage();
484 			return -1;
485 		}
486 
487 		fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
488 		if (fd < 0)
489 			return -1;
490 
491 		btf_id = info.btf_id;
492 		if (argc && is_prefix(*argv, "key")) {
493 			root_type_ids[root_type_cnt++] = info.btf_key_type_id;
494 			NEXT_ARG();
495 		} else if (argc && is_prefix(*argv, "value")) {
496 			root_type_ids[root_type_cnt++] = info.btf_value_type_id;
497 			NEXT_ARG();
498 		} else if (argc && is_prefix(*argv, "all")) {
499 			NEXT_ARG();
500 		} else if (argc && is_prefix(*argv, "kv")) {
501 			root_type_ids[root_type_cnt++] = info.btf_key_type_id;
502 			root_type_ids[root_type_cnt++] = info.btf_value_type_id;
503 			NEXT_ARG();
504 		} else {
505 			root_type_ids[root_type_cnt++] = info.btf_key_type_id;
506 			root_type_ids[root_type_cnt++] = info.btf_value_type_id;
507 		}
508 	} else if (is_prefix(src, "prog")) {
509 		struct bpf_prog_info info = {};
510 		__u32 len = sizeof(info);
511 
512 		if (!REQ_ARGS(2)) {
513 			usage();
514 			return -1;
515 		}
516 
517 		fd = prog_parse_fd(&argc, &argv);
518 		if (fd < 0)
519 			return -1;
520 
521 		err = bpf_obj_get_info_by_fd(fd, &info, &len);
522 		if (err) {
523 			p_err("can't get prog info: %s", strerror(errno));
524 			goto done;
525 		}
526 
527 		btf_id = info.btf_id;
528 	} else if (is_prefix(src, "id")) {
529 		char *endptr;
530 
531 		btf_id = strtoul(*argv, &endptr, 0);
532 		if (*endptr) {
533 			p_err("can't parse %s as ID", *argv);
534 			return -1;
535 		}
536 		NEXT_ARG();
537 	} else if (is_prefix(src, "file")) {
538 		const char sysfs_prefix[] = "/sys/kernel/btf/";
539 		const char sysfs_vmlinux[] = "/sys/kernel/btf/vmlinux";
540 
541 		if (!base_btf &&
542 		    strncmp(*argv, sysfs_prefix, sizeof(sysfs_prefix) - 1) == 0 &&
543 		    strcmp(*argv, sysfs_vmlinux) != 0) {
544 			base = btf__parse(sysfs_vmlinux, NULL);
545 			if (libbpf_get_error(base)) {
546 				p_err("failed to parse vmlinux BTF at '%s': %ld\n",
547 				      sysfs_vmlinux, libbpf_get_error(base));
548 				base = NULL;
549 			}
550 		}
551 
552 		btf = btf__parse_split(*argv, base ?: base_btf);
553 		err = libbpf_get_error(btf);
554 		if (err) {
555 			btf = NULL;
556 			p_err("failed to load BTF from %s: %s",
557 			      *argv, strerror(err));
558 			goto done;
559 		}
560 		NEXT_ARG();
561 	} else {
562 		err = -1;
563 		p_err("unrecognized BTF source specifier: '%s'", src);
564 		goto done;
565 	}
566 
567 	while (argc) {
568 		if (is_prefix(*argv, "format")) {
569 			NEXT_ARG();
570 			if (argc < 1) {
571 				p_err("expecting value for 'format' option\n");
572 				err = -EINVAL;
573 				goto done;
574 			}
575 			if (strcmp(*argv, "c") == 0) {
576 				dump_c = true;
577 			} else if (strcmp(*argv, "raw") == 0) {
578 				dump_c = false;
579 			} else {
580 				p_err("unrecognized format specifier: '%s', possible values: raw, c",
581 				      *argv);
582 				err = -EINVAL;
583 				goto done;
584 			}
585 			NEXT_ARG();
586 		} else {
587 			p_err("unrecognized option: '%s'", *argv);
588 			err = -EINVAL;
589 			goto done;
590 		}
591 	}
592 
593 	if (!btf) {
594 		btf = btf__load_from_kernel_by_id_split(btf_id, base_btf);
595 		err = libbpf_get_error(btf);
596 		if (err) {
597 			p_err("get btf by id (%u): %s", btf_id, strerror(err));
598 			goto done;
599 		}
600 	}
601 
602 	if (dump_c) {
603 		if (json_output) {
604 			p_err("JSON output for C-syntax dump is not supported");
605 			err = -ENOTSUP;
606 			goto done;
607 		}
608 		err = dump_btf_c(btf, root_type_ids, root_type_cnt);
609 	} else {
610 		err = dump_btf_raw(btf, root_type_ids, root_type_cnt);
611 	}
612 
613 done:
614 	close(fd);
615 	btf__free(btf);
616 	btf__free(base);
617 	return err;
618 }
619 
620 static int btf_parse_fd(int *argc, char ***argv)
621 {
622 	unsigned int id;
623 	char *endptr;
624 	int fd;
625 
626 	if (!is_prefix(*argv[0], "id")) {
627 		p_err("expected 'id', got: '%s'?", **argv);
628 		return -1;
629 	}
630 	NEXT_ARGP();
631 
632 	id = strtoul(**argv, &endptr, 0);
633 	if (*endptr) {
634 		p_err("can't parse %s as ID", **argv);
635 		return -1;
636 	}
637 	NEXT_ARGP();
638 
639 	fd = bpf_btf_get_fd_by_id(id);
640 	if (fd < 0)
641 		p_err("can't get BTF object by id (%u): %s",
642 		      id, strerror(errno));
643 
644 	return fd;
645 }
646 
647 static int
648 build_btf_type_table(struct hashmap *tab, enum bpf_obj_type type,
649 		     void *info, __u32 *len)
650 {
651 	static const char * const names[] = {
652 		[BPF_OBJ_UNKNOWN]	= "unknown",
653 		[BPF_OBJ_PROG]		= "prog",
654 		[BPF_OBJ_MAP]		= "map",
655 	};
656 	__u32 btf_id, id = 0;
657 	int err;
658 	int fd;
659 
660 	while (true) {
661 		switch (type) {
662 		case BPF_OBJ_PROG:
663 			err = bpf_prog_get_next_id(id, &id);
664 			break;
665 		case BPF_OBJ_MAP:
666 			err = bpf_map_get_next_id(id, &id);
667 			break;
668 		default:
669 			err = -1;
670 			p_err("unexpected object type: %d", type);
671 			goto err_free;
672 		}
673 		if (err) {
674 			if (errno == ENOENT) {
675 				err = 0;
676 				break;
677 			}
678 			p_err("can't get next %s: %s%s", names[type],
679 			      strerror(errno),
680 			      errno == EINVAL ? " -- kernel too old?" : "");
681 			goto err_free;
682 		}
683 
684 		switch (type) {
685 		case BPF_OBJ_PROG:
686 			fd = bpf_prog_get_fd_by_id(id);
687 			break;
688 		case BPF_OBJ_MAP:
689 			fd = bpf_map_get_fd_by_id(id);
690 			break;
691 		default:
692 			err = -1;
693 			p_err("unexpected object type: %d", type);
694 			goto err_free;
695 		}
696 		if (fd < 0) {
697 			if (errno == ENOENT)
698 				continue;
699 			p_err("can't get %s by id (%u): %s", names[type], id,
700 			      strerror(errno));
701 			err = -1;
702 			goto err_free;
703 		}
704 
705 		memset(info, 0, *len);
706 		err = bpf_obj_get_info_by_fd(fd, info, len);
707 		close(fd);
708 		if (err) {
709 			p_err("can't get %s info: %s", names[type],
710 			      strerror(errno));
711 			goto err_free;
712 		}
713 
714 		switch (type) {
715 		case BPF_OBJ_PROG:
716 			btf_id = ((struct bpf_prog_info *)info)->btf_id;
717 			break;
718 		case BPF_OBJ_MAP:
719 			btf_id = ((struct bpf_map_info *)info)->btf_id;
720 			break;
721 		default:
722 			err = -1;
723 			p_err("unexpected object type: %d", type);
724 			goto err_free;
725 		}
726 		if (!btf_id)
727 			continue;
728 
729 		err = hashmap__append(tab, u32_as_hash_field(btf_id),
730 				      u32_as_hash_field(id));
731 		if (err) {
732 			p_err("failed to append entry to hashmap for BTF ID %u, object ID %u: %s",
733 			      btf_id, id, strerror(errno));
734 			goto err_free;
735 		}
736 	}
737 
738 	return 0;
739 
740 err_free:
741 	hashmap__free(tab);
742 	return err;
743 }
744 
745 static int
746 build_btf_tables(struct hashmap *btf_prog_table,
747 		 struct hashmap *btf_map_table)
748 {
749 	struct bpf_prog_info prog_info;
750 	__u32 prog_len = sizeof(prog_info);
751 	struct bpf_map_info map_info;
752 	__u32 map_len = sizeof(map_info);
753 	int err = 0;
754 
755 	err = build_btf_type_table(btf_prog_table, BPF_OBJ_PROG, &prog_info,
756 				   &prog_len);
757 	if (err)
758 		return err;
759 
760 	err = build_btf_type_table(btf_map_table, BPF_OBJ_MAP, &map_info,
761 				   &map_len);
762 	if (err) {
763 		hashmap__free(btf_prog_table);
764 		return err;
765 	}
766 
767 	return 0;
768 }
769 
770 static void
771 show_btf_plain(struct bpf_btf_info *info, int fd,
772 	       struct hashmap *btf_prog_table,
773 	       struct hashmap *btf_map_table)
774 {
775 	struct hashmap_entry *entry;
776 	const char *name = u64_to_ptr(info->name);
777 	int n;
778 
779 	printf("%u: ", info->id);
780 	if (info->kernel_btf)
781 		printf("name [%s]  ", name);
782 	else if (name && name[0])
783 		printf("name %s  ", name);
784 	else
785 		printf("name <anon>  ");
786 	printf("size %uB", info->btf_size);
787 
788 	n = 0;
789 	hashmap__for_each_key_entry(btf_prog_table, entry,
790 				    u32_as_hash_field(info->id)) {
791 		printf("%s%u", n++ == 0 ? "  prog_ids " : ",",
792 		       hash_field_as_u32(entry->value));
793 	}
794 
795 	n = 0;
796 	hashmap__for_each_key_entry(btf_map_table, entry,
797 				    u32_as_hash_field(info->id)) {
798 		printf("%s%u", n++ == 0 ? "  map_ids " : ",",
799 		       hash_field_as_u32(entry->value));
800 	}
801 
802 	emit_obj_refs_plain(refs_table, info->id, "\n\tpids ");
803 
804 	printf("\n");
805 }
806 
807 static void
808 show_btf_json(struct bpf_btf_info *info, int fd,
809 	      struct hashmap *btf_prog_table,
810 	      struct hashmap *btf_map_table)
811 {
812 	struct hashmap_entry *entry;
813 	const char *name = u64_to_ptr(info->name);
814 
815 	jsonw_start_object(json_wtr);	/* btf object */
816 	jsonw_uint_field(json_wtr, "id", info->id);
817 	jsonw_uint_field(json_wtr, "size", info->btf_size);
818 
819 	jsonw_name(json_wtr, "prog_ids");
820 	jsonw_start_array(json_wtr);	/* prog_ids */
821 	hashmap__for_each_key_entry(btf_prog_table, entry,
822 				    u32_as_hash_field(info->id)) {
823 		jsonw_uint(json_wtr, hash_field_as_u32(entry->value));
824 	}
825 	jsonw_end_array(json_wtr);	/* prog_ids */
826 
827 	jsonw_name(json_wtr, "map_ids");
828 	jsonw_start_array(json_wtr);	/* map_ids */
829 	hashmap__for_each_key_entry(btf_map_table, entry,
830 				    u32_as_hash_field(info->id)) {
831 		jsonw_uint(json_wtr, hash_field_as_u32(entry->value));
832 	}
833 	jsonw_end_array(json_wtr);	/* map_ids */
834 
835 	emit_obj_refs_json(refs_table, info->id, json_wtr); /* pids */
836 
837 	jsonw_bool_field(json_wtr, "kernel", info->kernel_btf);
838 
839 	if (name && name[0])
840 		jsonw_string_field(json_wtr, "name", name);
841 
842 	jsonw_end_object(json_wtr);	/* btf object */
843 }
844 
845 static int
846 show_btf(int fd, struct hashmap *btf_prog_table,
847 	 struct hashmap *btf_map_table)
848 {
849 	struct bpf_btf_info info;
850 	__u32 len = sizeof(info);
851 	char name[64];
852 	int err;
853 
854 	memset(&info, 0, sizeof(info));
855 	err = bpf_obj_get_info_by_fd(fd, &info, &len);
856 	if (err) {
857 		p_err("can't get BTF object info: %s", strerror(errno));
858 		return -1;
859 	}
860 	/* if kernel support emitting BTF object name, pass name pointer */
861 	if (info.name_len) {
862 		memset(&info, 0, sizeof(info));
863 		info.name_len = sizeof(name);
864 		info.name = ptr_to_u64(name);
865 		len = sizeof(info);
866 
867 		err = bpf_obj_get_info_by_fd(fd, &info, &len);
868 		if (err) {
869 			p_err("can't get BTF object info: %s", strerror(errno));
870 			return -1;
871 		}
872 	}
873 
874 	if (json_output)
875 		show_btf_json(&info, fd, btf_prog_table, btf_map_table);
876 	else
877 		show_btf_plain(&info, fd, btf_prog_table, btf_map_table);
878 
879 	return 0;
880 }
881 
882 static int do_show(int argc, char **argv)
883 {
884 	struct hashmap *btf_prog_table;
885 	struct hashmap *btf_map_table;
886 	int err, fd = -1;
887 	__u32 id = 0;
888 
889 	if (argc == 2) {
890 		fd = btf_parse_fd(&argc, &argv);
891 		if (fd < 0)
892 			return -1;
893 	}
894 
895 	if (argc) {
896 		if (fd >= 0)
897 			close(fd);
898 		return BAD_ARG();
899 	}
900 
901 	btf_prog_table = hashmap__new(hash_fn_for_key_as_id,
902 				      equal_fn_for_key_as_id, NULL);
903 	btf_map_table = hashmap__new(hash_fn_for_key_as_id,
904 				     equal_fn_for_key_as_id, NULL);
905 	if (!btf_prog_table || !btf_map_table) {
906 		hashmap__free(btf_prog_table);
907 		hashmap__free(btf_map_table);
908 		if (fd >= 0)
909 			close(fd);
910 		p_err("failed to create hashmap for object references");
911 		return -1;
912 	}
913 	err = build_btf_tables(btf_prog_table, btf_map_table);
914 	if (err) {
915 		if (fd >= 0)
916 			close(fd);
917 		return err;
918 	}
919 	build_obj_refs_table(&refs_table, BPF_OBJ_BTF);
920 
921 	if (fd >= 0) {
922 		err = show_btf(fd, btf_prog_table, btf_map_table);
923 		close(fd);
924 		goto exit_free;
925 	}
926 
927 	if (json_output)
928 		jsonw_start_array(json_wtr);	/* root array */
929 
930 	while (true) {
931 		err = bpf_btf_get_next_id(id, &id);
932 		if (err) {
933 			if (errno == ENOENT) {
934 				err = 0;
935 				break;
936 			}
937 			p_err("can't get next BTF object: %s%s",
938 			      strerror(errno),
939 			      errno == EINVAL ? " -- kernel too old?" : "");
940 			err = -1;
941 			break;
942 		}
943 
944 		fd = bpf_btf_get_fd_by_id(id);
945 		if (fd < 0) {
946 			if (errno == ENOENT)
947 				continue;
948 			p_err("can't get BTF object by id (%u): %s",
949 			      id, strerror(errno));
950 			err = -1;
951 			break;
952 		}
953 
954 		err = show_btf(fd, btf_prog_table, btf_map_table);
955 		close(fd);
956 		if (err)
957 			break;
958 	}
959 
960 	if (json_output)
961 		jsonw_end_array(json_wtr);	/* root array */
962 
963 exit_free:
964 	hashmap__free(btf_prog_table);
965 	hashmap__free(btf_map_table);
966 	delete_obj_refs_table(refs_table);
967 
968 	return err;
969 }
970 
971 static int do_help(int argc, char **argv)
972 {
973 	if (json_output) {
974 		jsonw_null(json_wtr);
975 		return 0;
976 	}
977 
978 	fprintf(stderr,
979 		"Usage: %1$s %2$s { show | list } [id BTF_ID]\n"
980 		"       %1$s %2$s dump BTF_SRC [format FORMAT]\n"
981 		"       %1$s %2$s help\n"
982 		"\n"
983 		"       BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n"
984 		"       FORMAT  := { raw | c }\n"
985 		"       " HELP_SPEC_MAP "\n"
986 		"       " HELP_SPEC_PROGRAM "\n"
987 		"       " HELP_SPEC_OPTIONS " |\n"
988 		"                    {-B|--base-btf} }\n"
989 		"",
990 		bin_name, "btf");
991 
992 	return 0;
993 }
994 
995 static const struct cmd cmds[] = {
996 	{ "show",	do_show },
997 	{ "list",	do_show },
998 	{ "help",	do_help },
999 	{ "dump",	do_dump },
1000 	{ 0 }
1001 };
1002 
1003 int do_btf(int argc, char **argv)
1004 {
1005 	return cmd_select(cmds, argc, argv, do_help);
1006 }
1007