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