cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

btf.c (23792B)


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