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