brintos

brintos / linux-shallow public Read only

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