Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2020 Facebook */
  3#include <stdio.h>
  4#include <errno.h>
  5#include <bpf/btf.h>
  6#include <bpf/libbpf.h>
  7#include "test_progs.h"
  8
  9static const char * const btf_kind_str_mapping[] = {
 10	[BTF_KIND_UNKN]		= "UNKNOWN",
 11	[BTF_KIND_INT]		= "INT",
 12	[BTF_KIND_PTR]		= "PTR",
 13	[BTF_KIND_ARRAY]	= "ARRAY",
 14	[BTF_KIND_STRUCT]	= "STRUCT",
 15	[BTF_KIND_UNION]	= "UNION",
 16	[BTF_KIND_ENUM]		= "ENUM",
 17	[BTF_KIND_FWD]		= "FWD",
 18	[BTF_KIND_TYPEDEF]	= "TYPEDEF",
 19	[BTF_KIND_VOLATILE]	= "VOLATILE",
 20	[BTF_KIND_CONST]	= "CONST",
 21	[BTF_KIND_RESTRICT]	= "RESTRICT",
 22	[BTF_KIND_FUNC]		= "FUNC",
 23	[BTF_KIND_FUNC_PROTO]	= "FUNC_PROTO",
 24	[BTF_KIND_VAR]		= "VAR",
 25	[BTF_KIND_DATASEC]	= "DATASEC",
 26	[BTF_KIND_FLOAT]	= "FLOAT",
 27};
 28
 29static const char *btf_kind_str(__u16 kind)
 30{
 31	if (kind > BTF_KIND_DATASEC)
 32		return "UNKNOWN";
 33	return btf_kind_str_mapping[kind];
 34}
 35
 36static const char *btf_int_enc_str(__u8 encoding)
 37{
 38	switch (encoding) {
 39	case 0:
 40		return "(none)";
 41	case BTF_INT_SIGNED:
 42		return "SIGNED";
 43	case BTF_INT_CHAR:
 44		return "CHAR";
 45	case BTF_INT_BOOL:
 46		return "BOOL";
 47	default:
 48		return "UNKN";
 49	}
 50}
 51
 52static const char *btf_var_linkage_str(__u32 linkage)
 53{
 54	switch (linkage) {
 55	case BTF_VAR_STATIC:
 56		return "static";
 57	case BTF_VAR_GLOBAL_ALLOCATED:
 58		return "global-alloc";
 59	default:
 60		return "(unknown)";
 61	}
 62}
 63
 64static const char *btf_func_linkage_str(const struct btf_type *t)
 65{
 66	switch (btf_vlen(t)) {
 67	case BTF_FUNC_STATIC:
 68		return "static";
 69	case BTF_FUNC_GLOBAL:
 70		return "global";
 71	case BTF_FUNC_EXTERN:
 72		return "extern";
 73	default:
 74		return "(unknown)";
 75	}
 76}
 77
 78static const char *btf_str(const struct btf *btf, __u32 off)
 79{
 80	if (!off)
 81		return "(anon)";
 82	return btf__str_by_offset(btf, off) ?: "(invalid)";
 83}
 84
 85int fprintf_btf_type_raw(FILE *out, const struct btf *btf, __u32 id)
 86{
 87	const struct btf_type *t;
 88	int kind, i;
 89	__u32 vlen;
 90
 91	t = btf__type_by_id(btf, id);
 92	if (!t)
 93		return -EINVAL;
 94
 95	vlen = btf_vlen(t);
 96	kind = btf_kind(t);
 97
 98	fprintf(out, "[%u] %s '%s'", id, btf_kind_str(kind), btf_str(btf, t->name_off));
 99
100	switch (kind) {
101	case BTF_KIND_INT:
102		fprintf(out, " size=%u bits_offset=%u nr_bits=%u encoding=%s",
103			t->size, btf_int_offset(t), btf_int_bits(t),
104			btf_int_enc_str(btf_int_encoding(t)));
105		break;
106	case BTF_KIND_PTR:
107	case BTF_KIND_CONST:
108	case BTF_KIND_VOLATILE:
109	case BTF_KIND_RESTRICT:
110	case BTF_KIND_TYPEDEF:
111		fprintf(out, " type_id=%u", t->type);
112		break;
113	case BTF_KIND_ARRAY: {
114		const struct btf_array *arr = btf_array(t);
115
116		fprintf(out, " type_id=%u index_type_id=%u nr_elems=%u",
117			arr->type, arr->index_type, arr->nelems);
118		break;
119	}
120	case BTF_KIND_STRUCT:
121	case BTF_KIND_UNION: {
122		const struct btf_member *m = btf_members(t);
123
124		fprintf(out, " size=%u vlen=%u", t->size, vlen);
125		for (i = 0; i < vlen; i++, m++) {
126			__u32 bit_off, bit_sz;
127
128			bit_off = btf_member_bit_offset(t, i);
129			bit_sz = btf_member_bitfield_size(t, i);
130			fprintf(out, "\n\t'%s' type_id=%u bits_offset=%u",
131				btf_str(btf, m->name_off), m->type, bit_off);
132			if (bit_sz)
133				fprintf(out, " bitfield_size=%u", bit_sz);
134		}
135		break;
136	}
137	case BTF_KIND_ENUM: {
138		const struct btf_enum *v = btf_enum(t);
139
140		fprintf(out, " size=%u vlen=%u", t->size, vlen);
141		for (i = 0; i < vlen; i++, v++) {
142			fprintf(out, "\n\t'%s' val=%u",
143				btf_str(btf, v->name_off), v->val);
144		}
145		break;
146	}
147	case BTF_KIND_FWD:
148		fprintf(out, " fwd_kind=%s", btf_kflag(t) ? "union" : "struct");
149		break;
150	case BTF_KIND_FUNC:
151		fprintf(out, " type_id=%u linkage=%s", t->type, btf_func_linkage_str(t));
152		break;
153	case BTF_KIND_FUNC_PROTO: {
154		const struct btf_param *p = btf_params(t);
155
156		fprintf(out, " ret_type_id=%u vlen=%u", t->type, vlen);
157		for (i = 0; i < vlen; i++, p++) {
158			fprintf(out, "\n\t'%s' type_id=%u",
159				btf_str(btf, p->name_off), p->type);
160		}
161		break;
162	}
163	case BTF_KIND_VAR:
164		fprintf(out, " type_id=%u, linkage=%s",
165			t->type, btf_var_linkage_str(btf_var(t)->linkage));
166		break;
167	case BTF_KIND_DATASEC: {
168		const struct btf_var_secinfo *v = btf_var_secinfos(t);
169
170		fprintf(out, " size=%u vlen=%u", t->size, vlen);
171		for (i = 0; i < vlen; i++, v++) {
172			fprintf(out, "\n\ttype_id=%u offset=%u size=%u",
173				v->type, v->offset, v->size);
174		}
175		break;
176	}
177	case BTF_KIND_FLOAT:
178		fprintf(out, " size=%u", t->size);
179		break;
180	default:
181		break;
182	}
183
184	return 0;
185}
186
187/* Print raw BTF type dump into a local buffer and return string pointer back.
188 * Buffer *will* be overwritten by subsequent btf_type_raw_dump() calls
189 */
190const char *btf_type_raw_dump(const struct btf *btf, int type_id)
191{
192	static char buf[16 * 1024];
193	FILE *buf_file;
194
195	buf_file = fmemopen(buf, sizeof(buf) - 1, "w");
196	if (!buf_file) {
197		fprintf(stderr, "Failed to open memstream: %d\n", errno);
198		return NULL;
199	}
200
201	fprintf_btf_type_raw(buf_file, btf, type_id);
202	fflush(buf_file);
203	fclose(buf_file);
204
205	return buf;
206}
207
208int btf_validate_raw(struct btf *btf, int nr_types, const char *exp_types[])
209{
210	int i;
211	bool ok = true;
212
213	ASSERT_EQ(btf__get_nr_types(btf), nr_types, "btf_nr_types");
214
215	for (i = 1; i <= nr_types; i++) {
216		if (!ASSERT_STREQ(btf_type_raw_dump(btf, i), exp_types[i - 1], "raw_dump"))
217			ok = false;
218	}
219
220	return ok;
221}
222
223static void btf_dump_printf(void *ctx, const char *fmt, va_list args)
224{
225	vfprintf(ctx, fmt, args);
226}
227
228/* Print BTF-to-C dump into a local buffer and return string pointer back.
229 * Buffer *will* be overwritten by subsequent btf_type_raw_dump() calls
230 */
231const char *btf_type_c_dump(const struct btf *btf)
232{
233	static char buf[16 * 1024];
234	FILE *buf_file;
235	struct btf_dump *d = NULL;
236	struct btf_dump_opts opts = {};
237	int err, i;
238
239	buf_file = fmemopen(buf, sizeof(buf) - 1, "w");
240	if (!buf_file) {
241		fprintf(stderr, "Failed to open memstream: %d\n", errno);
242		return NULL;
243	}
244
245	opts.ctx = buf_file;
246	d = btf_dump__new(btf, NULL, &opts, btf_dump_printf);
247	if (libbpf_get_error(d)) {
248		fprintf(stderr, "Failed to create btf_dump instance: %ld\n", libbpf_get_error(d));
249		return NULL;
250	}
251
252	for (i = 1; i <= btf__get_nr_types(btf); i++) {
253		err = btf_dump__dump_type(d, i);
254		if (err) {
255			fprintf(stderr, "Failed to dump type [%d]: %d\n", i, err);
256			return NULL;
257		}
258	}
259
260	fflush(buf_file);
261	fclose(buf_file);
262	return buf;
263}