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