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