xref: /openbmc/linux/tools/bpf/bpftool/btf.c (revision 3180449e)
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 	[BTF_KIND_ENUM64]	= "ENUM64",
44 };
45 
46 static 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 
62 static 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 
76 static 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 
90 static 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 
97 static int btf_kind_safe(int kind)
98 {
99 	return kind <= BTF_KIND_MAX ? kind : BTF_KIND_UNKN;
100 }
101 
102 static 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 
418 static 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 
457 static void __printf(2, 0) btf_dump_printf(void *ctx,
458 					   const char *fmt, va_list args)
459 {
460 	vfprintf(stdout, fmt, args);
461 }
462 
463 static 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 
502 done:
503 	btf_dump__free(d);
504 	return err;
505 }
506 
507 static const char sysfs_vmlinux[] = "/sys/kernel/btf/vmlinux";
508 
509 static 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 
523 static 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 
550 static 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 
699 done:
700 	close(fd);
701 	btf__free(btf);
702 	btf__free(base);
703 	return err;
704 }
705 
706 static 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 
733 static int
734 build_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 
828 err_free:
829 	hashmap__free(tab);
830 	return err;
831 }
832 
833 static int
834 build_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 
858 static void
859 show_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 
891 static void
892 show_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 
927 static int
928 show_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 
964 static 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 
1045 exit_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 
1053 static 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 
1077 static const struct cmd cmds[] = {
1078 	{ "show",	do_show },
1079 	{ "list",	do_show },
1080 	{ "help",	do_help },
1081 	{ "dump",	do_dump },
1082 	{ 0 }
1083 };
1084 
1085 int do_btf(int argc, char **argv)
1086 {
1087 	return cmd_select(cmds, argc, argv, do_help);
1088 }
1089