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