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_dumper.c (19534B)


      1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
      2/* Copyright (c) 2018 Facebook */
      3
      4#include <ctype.h>
      5#include <stdio.h> /* for (FILE *) used by json_writer */
      6#include <string.h>
      7#include <unistd.h>
      8#include <asm/byteorder.h>
      9#include <linux/bitops.h>
     10#include <linux/btf.h>
     11#include <linux/err.h>
     12#include <bpf/btf.h>
     13#include <bpf/bpf.h>
     14
     15#include "json_writer.h"
     16#include "main.h"
     17
     18#define BITS_PER_BYTE_MASK (BITS_PER_BYTE - 1)
     19#define BITS_PER_BYTE_MASKED(bits) ((bits) & BITS_PER_BYTE_MASK)
     20#define BITS_ROUNDDOWN_BYTES(bits) ((bits) >> 3)
     21#define BITS_ROUNDUP_BYTES(bits) \
     22	(BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits))
     23
     24static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id,
     25			      __u8 bit_offset, const void *data);
     26
     27static int btf_dump_func(const struct btf *btf, char *func_sig,
     28			 const struct btf_type *func_proto,
     29			 const struct btf_type *func, int pos, int size);
     30
     31static int dump_prog_id_as_func_ptr(const struct btf_dumper *d,
     32				    const struct btf_type *func_proto,
     33				    __u32 prog_id)
     34{
     35	const struct btf_type *func_type;
     36	int prog_fd = -1, func_sig_len;
     37	struct bpf_prog_info info = {};
     38	__u32 info_len = sizeof(info);
     39	const char *prog_name = NULL;
     40	struct btf *prog_btf = NULL;
     41	struct bpf_func_info finfo;
     42	__u32 finfo_rec_size;
     43	char prog_str[1024];
     44	int err;
     45
     46	/* Get the ptr's func_proto */
     47	func_sig_len = btf_dump_func(d->btf, prog_str, func_proto, NULL, 0,
     48				     sizeof(prog_str));
     49	if (func_sig_len == -1)
     50		return -1;
     51
     52	if (!prog_id)
     53		goto print;
     54
     55	/* Get the bpf_prog's name.  Obtain from func_info. */
     56	prog_fd = bpf_prog_get_fd_by_id(prog_id);
     57	if (prog_fd < 0)
     58		goto print;
     59
     60	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);
     61	if (err)
     62		goto print;
     63
     64	if (!info.btf_id || !info.nr_func_info)
     65		goto print;
     66
     67	finfo_rec_size = info.func_info_rec_size;
     68	memset(&info, 0, sizeof(info));
     69	info.nr_func_info = 1;
     70	info.func_info_rec_size = finfo_rec_size;
     71	info.func_info = ptr_to_u64(&finfo);
     72
     73	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);
     74	if (err)
     75		goto print;
     76
     77	prog_btf = btf__load_from_kernel_by_id(info.btf_id);
     78	if (libbpf_get_error(prog_btf))
     79		goto print;
     80	func_type = btf__type_by_id(prog_btf, finfo.type_id);
     81	if (!func_type || !btf_is_func(func_type))
     82		goto print;
     83
     84	prog_name = btf__name_by_offset(prog_btf, func_type->name_off);
     85
     86print:
     87	if (!prog_id)
     88		snprintf(&prog_str[func_sig_len],
     89			 sizeof(prog_str) - func_sig_len, " 0");
     90	else if (prog_name)
     91		snprintf(&prog_str[func_sig_len],
     92			 sizeof(prog_str) - func_sig_len,
     93			 " %s/prog_id:%u", prog_name, prog_id);
     94	else
     95		snprintf(&prog_str[func_sig_len],
     96			 sizeof(prog_str) - func_sig_len,
     97			 " <unknown_prog_name>/prog_id:%u", prog_id);
     98
     99	prog_str[sizeof(prog_str) - 1] = '\0';
    100	jsonw_string(d->jw, prog_str);
    101	btf__free(prog_btf);
    102	if (prog_fd >= 0)
    103		close(prog_fd);
    104	return 0;
    105}
    106
    107static void btf_dumper_ptr(const struct btf_dumper *d,
    108			   const struct btf_type *t,
    109			   const void *data)
    110{
    111	unsigned long value = *(unsigned long *)data;
    112	const struct btf_type *ptr_type;
    113	__s32 ptr_type_id;
    114
    115	if (!d->prog_id_as_func_ptr || value > UINT32_MAX)
    116		goto print_ptr_value;
    117
    118	ptr_type_id = btf__resolve_type(d->btf, t->type);
    119	if (ptr_type_id < 0)
    120		goto print_ptr_value;
    121	ptr_type = btf__type_by_id(d->btf, ptr_type_id);
    122	if (!ptr_type || !btf_is_func_proto(ptr_type))
    123		goto print_ptr_value;
    124
    125	if (!dump_prog_id_as_func_ptr(d, ptr_type, value))
    126		return;
    127
    128print_ptr_value:
    129	if (d->is_plain_text)
    130		jsonw_printf(d->jw, "%p", (void *)value);
    131	else
    132		jsonw_printf(d->jw, "%lu", value);
    133}
    134
    135static int btf_dumper_modifier(const struct btf_dumper *d, __u32 type_id,
    136			       __u8 bit_offset, const void *data)
    137{
    138	int actual_type_id;
    139
    140	actual_type_id = btf__resolve_type(d->btf, type_id);
    141	if (actual_type_id < 0)
    142		return actual_type_id;
    143
    144	return btf_dumper_do_type(d, actual_type_id, bit_offset, data);
    145}
    146
    147static int btf_dumper_enum(const struct btf_dumper *d,
    148			    const struct btf_type *t,
    149			    const void *data)
    150{
    151	const struct btf_enum *enums = btf_enum(t);
    152	__s64 value;
    153	__u16 i;
    154
    155	switch (t->size) {
    156	case 8:
    157		value = *(__s64 *)data;
    158		break;
    159	case 4:
    160		value = *(__s32 *)data;
    161		break;
    162	case 2:
    163		value = *(__s16 *)data;
    164		break;
    165	case 1:
    166		value = *(__s8 *)data;
    167		break;
    168	default:
    169		return -EINVAL;
    170	}
    171
    172	for (i = 0; i < btf_vlen(t); i++) {
    173		if (value == enums[i].val) {
    174			jsonw_string(d->jw,
    175				     btf__name_by_offset(d->btf,
    176							 enums[i].name_off));
    177			return 0;
    178		}
    179	}
    180
    181	jsonw_int(d->jw, value);
    182	return 0;
    183}
    184
    185static bool is_str_array(const struct btf *btf, const struct btf_array *arr,
    186			 const char *s)
    187{
    188	const struct btf_type *elem_type;
    189	const char *end_s;
    190
    191	if (!arr->nelems)
    192		return false;
    193
    194	elem_type = btf__type_by_id(btf, arr->type);
    195	/* Not skipping typedef.  typedef to char does not count as
    196	 * a string now.
    197	 */
    198	while (elem_type && btf_is_mod(elem_type))
    199		elem_type = btf__type_by_id(btf, elem_type->type);
    200
    201	if (!elem_type || !btf_is_int(elem_type) || elem_type->size != 1)
    202		return false;
    203
    204	if (btf_int_encoding(elem_type) != BTF_INT_CHAR &&
    205	    strcmp("char", btf__name_by_offset(btf, elem_type->name_off)))
    206		return false;
    207
    208	end_s = s + arr->nelems;
    209	while (s < end_s) {
    210		if (!*s)
    211			return true;
    212		if (*s <= 0x1f || *s >= 0x7f)
    213			return false;
    214		s++;
    215	}
    216
    217	/* '\0' is not found */
    218	return false;
    219}
    220
    221static int btf_dumper_array(const struct btf_dumper *d, __u32 type_id,
    222			    const void *data)
    223{
    224	const struct btf_type *t = btf__type_by_id(d->btf, type_id);
    225	struct btf_array *arr = (struct btf_array *)(t + 1);
    226	long long elem_size;
    227	int ret = 0;
    228	__u32 i;
    229
    230	if (is_str_array(d->btf, arr, data)) {
    231		jsonw_string(d->jw, data);
    232		return 0;
    233	}
    234
    235	elem_size = btf__resolve_size(d->btf, arr->type);
    236	if (elem_size < 0)
    237		return elem_size;
    238
    239	jsonw_start_array(d->jw);
    240	for (i = 0; i < arr->nelems; i++) {
    241		ret = btf_dumper_do_type(d, arr->type, 0,
    242					 data + i * elem_size);
    243		if (ret)
    244			break;
    245	}
    246
    247	jsonw_end_array(d->jw);
    248	return ret;
    249}
    250
    251static void btf_int128_print(json_writer_t *jw, const void *data,
    252			     bool is_plain_text)
    253{
    254	/* data points to a __int128 number.
    255	 * Suppose
    256	 *     int128_num = *(__int128 *)data;
    257	 * The below formulas shows what upper_num and lower_num represents:
    258	 *     upper_num = int128_num >> 64;
    259	 *     lower_num = int128_num & 0xffffffffFFFFFFFFULL;
    260	 */
    261	__u64 upper_num, lower_num;
    262
    263#ifdef __BIG_ENDIAN_BITFIELD
    264	upper_num = *(__u64 *)data;
    265	lower_num = *(__u64 *)(data + 8);
    266#else
    267	upper_num = *(__u64 *)(data + 8);
    268	lower_num = *(__u64 *)data;
    269#endif
    270
    271	if (is_plain_text) {
    272		if (upper_num == 0)
    273			jsonw_printf(jw, "0x%llx", lower_num);
    274		else
    275			jsonw_printf(jw, "0x%llx%016llx", upper_num, lower_num);
    276	} else {
    277		if (upper_num == 0)
    278			jsonw_printf(jw, "\"0x%llx\"", lower_num);
    279		else
    280			jsonw_printf(jw, "\"0x%llx%016llx\"", upper_num, lower_num);
    281	}
    282}
    283
    284static void btf_int128_shift(__u64 *print_num, __u16 left_shift_bits,
    285			     __u16 right_shift_bits)
    286{
    287	__u64 upper_num, lower_num;
    288
    289#ifdef __BIG_ENDIAN_BITFIELD
    290	upper_num = print_num[0];
    291	lower_num = print_num[1];
    292#else
    293	upper_num = print_num[1];
    294	lower_num = print_num[0];
    295#endif
    296
    297	/* shake out un-needed bits by shift/or operations */
    298	if (left_shift_bits >= 64) {
    299		upper_num = lower_num << (left_shift_bits - 64);
    300		lower_num = 0;
    301	} else {
    302		upper_num = (upper_num << left_shift_bits) |
    303			    (lower_num >> (64 - left_shift_bits));
    304		lower_num = lower_num << left_shift_bits;
    305	}
    306
    307	if (right_shift_bits >= 64) {
    308		lower_num = upper_num >> (right_shift_bits - 64);
    309		upper_num = 0;
    310	} else {
    311		lower_num = (lower_num >> right_shift_bits) |
    312			    (upper_num << (64 - right_shift_bits));
    313		upper_num = upper_num >> right_shift_bits;
    314	}
    315
    316#ifdef __BIG_ENDIAN_BITFIELD
    317	print_num[0] = upper_num;
    318	print_num[1] = lower_num;
    319#else
    320	print_num[0] = lower_num;
    321	print_num[1] = upper_num;
    322#endif
    323}
    324
    325static void btf_dumper_bitfield(__u32 nr_bits, __u8 bit_offset,
    326				const void *data, json_writer_t *jw,
    327				bool is_plain_text)
    328{
    329	int left_shift_bits, right_shift_bits;
    330	__u64 print_num[2] = {};
    331	int bytes_to_copy;
    332	int bits_to_copy;
    333
    334	bits_to_copy = bit_offset + nr_bits;
    335	bytes_to_copy = BITS_ROUNDUP_BYTES(bits_to_copy);
    336
    337	memcpy(print_num, data, bytes_to_copy);
    338#if defined(__BIG_ENDIAN_BITFIELD)
    339	left_shift_bits = bit_offset;
    340#elif defined(__LITTLE_ENDIAN_BITFIELD)
    341	left_shift_bits = 128 - bits_to_copy;
    342#else
    343#error neither big nor little endian
    344#endif
    345	right_shift_bits = 128 - nr_bits;
    346
    347	btf_int128_shift(print_num, left_shift_bits, right_shift_bits);
    348	btf_int128_print(jw, print_num, is_plain_text);
    349}
    350
    351
    352static void btf_dumper_int_bits(__u32 int_type, __u8 bit_offset,
    353				const void *data, json_writer_t *jw,
    354				bool is_plain_text)
    355{
    356	int nr_bits = BTF_INT_BITS(int_type);
    357	int total_bits_offset;
    358
    359	/* bits_offset is at most 7.
    360	 * BTF_INT_OFFSET() cannot exceed 128 bits.
    361	 */
    362	total_bits_offset = bit_offset + BTF_INT_OFFSET(int_type);
    363	data += BITS_ROUNDDOWN_BYTES(total_bits_offset);
    364	bit_offset = BITS_PER_BYTE_MASKED(total_bits_offset);
    365	btf_dumper_bitfield(nr_bits, bit_offset, data, jw,
    366			    is_plain_text);
    367}
    368
    369static int btf_dumper_int(const struct btf_type *t, __u8 bit_offset,
    370			  const void *data, json_writer_t *jw,
    371			  bool is_plain_text)
    372{
    373	__u32 *int_type;
    374	__u32 nr_bits;
    375
    376	int_type = (__u32 *)(t + 1);
    377	nr_bits = BTF_INT_BITS(*int_type);
    378	/* if this is bit field */
    379	if (bit_offset || BTF_INT_OFFSET(*int_type) ||
    380	    BITS_PER_BYTE_MASKED(nr_bits)) {
    381		btf_dumper_int_bits(*int_type, bit_offset, data, jw,
    382				    is_plain_text);
    383		return 0;
    384	}
    385
    386	if (nr_bits == 128) {
    387		btf_int128_print(jw, data, is_plain_text);
    388		return 0;
    389	}
    390
    391	switch (BTF_INT_ENCODING(*int_type)) {
    392	case 0:
    393		if (BTF_INT_BITS(*int_type) == 64)
    394			jsonw_printf(jw, "%llu", *(__u64 *)data);
    395		else if (BTF_INT_BITS(*int_type) == 32)
    396			jsonw_printf(jw, "%u", *(__u32 *)data);
    397		else if (BTF_INT_BITS(*int_type) == 16)
    398			jsonw_printf(jw, "%hu", *(__u16 *)data);
    399		else if (BTF_INT_BITS(*int_type) == 8)
    400			jsonw_printf(jw, "%hhu", *(__u8 *)data);
    401		else
    402			btf_dumper_int_bits(*int_type, bit_offset, data, jw,
    403					    is_plain_text);
    404		break;
    405	case BTF_INT_SIGNED:
    406		if (BTF_INT_BITS(*int_type) == 64)
    407			jsonw_printf(jw, "%lld", *(long long *)data);
    408		else if (BTF_INT_BITS(*int_type) == 32)
    409			jsonw_printf(jw, "%d", *(int *)data);
    410		else if (BTF_INT_BITS(*int_type) == 16)
    411			jsonw_printf(jw, "%hd", *(short *)data);
    412		else if (BTF_INT_BITS(*int_type) == 8)
    413			jsonw_printf(jw, "%hhd", *(char *)data);
    414		else
    415			btf_dumper_int_bits(*int_type, bit_offset, data, jw,
    416					    is_plain_text);
    417		break;
    418	case BTF_INT_CHAR:
    419		if (isprint(*(char *)data))
    420			jsonw_printf(jw, "\"%c\"", *(char *)data);
    421		else
    422			if (is_plain_text)
    423				jsonw_printf(jw, "0x%hhx", *(char *)data);
    424			else
    425				jsonw_printf(jw, "\"\\u00%02hhx\"",
    426					     *(char *)data);
    427		break;
    428	case BTF_INT_BOOL:
    429		jsonw_bool(jw, *(int *)data);
    430		break;
    431	default:
    432		/* shouldn't happen */
    433		return -EINVAL;
    434	}
    435
    436	return 0;
    437}
    438
    439static int btf_dumper_struct(const struct btf_dumper *d, __u32 type_id,
    440			     const void *data)
    441{
    442	const struct btf_type *t;
    443	struct btf_member *m;
    444	const void *data_off;
    445	int kind_flag;
    446	int ret = 0;
    447	int i, vlen;
    448
    449	t = btf__type_by_id(d->btf, type_id);
    450	if (!t)
    451		return -EINVAL;
    452
    453	kind_flag = BTF_INFO_KFLAG(t->info);
    454	vlen = BTF_INFO_VLEN(t->info);
    455	jsonw_start_object(d->jw);
    456	m = (struct btf_member *)(t + 1);
    457
    458	for (i = 0; i < vlen; i++) {
    459		__u32 bit_offset = m[i].offset;
    460		__u32 bitfield_size = 0;
    461
    462		if (kind_flag) {
    463			bitfield_size = BTF_MEMBER_BITFIELD_SIZE(bit_offset);
    464			bit_offset = BTF_MEMBER_BIT_OFFSET(bit_offset);
    465		}
    466
    467		jsonw_name(d->jw, btf__name_by_offset(d->btf, m[i].name_off));
    468		data_off = data + BITS_ROUNDDOWN_BYTES(bit_offset);
    469		if (bitfield_size) {
    470			btf_dumper_bitfield(bitfield_size,
    471					    BITS_PER_BYTE_MASKED(bit_offset),
    472					    data_off, d->jw, d->is_plain_text);
    473		} else {
    474			ret = btf_dumper_do_type(d, m[i].type,
    475						 BITS_PER_BYTE_MASKED(bit_offset),
    476						 data_off);
    477			if (ret)
    478				break;
    479		}
    480	}
    481
    482	jsonw_end_object(d->jw);
    483
    484	return ret;
    485}
    486
    487static int btf_dumper_var(const struct btf_dumper *d, __u32 type_id,
    488			  __u8 bit_offset, const void *data)
    489{
    490	const struct btf_type *t = btf__type_by_id(d->btf, type_id);
    491	int ret;
    492
    493	jsonw_start_object(d->jw);
    494	jsonw_name(d->jw, btf__name_by_offset(d->btf, t->name_off));
    495	ret = btf_dumper_do_type(d, t->type, bit_offset, data);
    496	jsonw_end_object(d->jw);
    497
    498	return ret;
    499}
    500
    501static int btf_dumper_datasec(const struct btf_dumper *d, __u32 type_id,
    502			      const void *data)
    503{
    504	struct btf_var_secinfo *vsi;
    505	const struct btf_type *t;
    506	int ret = 0, i, vlen;
    507
    508	t = btf__type_by_id(d->btf, type_id);
    509	if (!t)
    510		return -EINVAL;
    511
    512	vlen = BTF_INFO_VLEN(t->info);
    513	vsi = (struct btf_var_secinfo *)(t + 1);
    514
    515	jsonw_start_object(d->jw);
    516	jsonw_name(d->jw, btf__name_by_offset(d->btf, t->name_off));
    517	jsonw_start_array(d->jw);
    518	for (i = 0; i < vlen; i++) {
    519		ret = btf_dumper_do_type(d, vsi[i].type, 0, data + vsi[i].offset);
    520		if (ret)
    521			break;
    522	}
    523	jsonw_end_array(d->jw);
    524	jsonw_end_object(d->jw);
    525
    526	return ret;
    527}
    528
    529static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id,
    530			      __u8 bit_offset, const void *data)
    531{
    532	const struct btf_type *t = btf__type_by_id(d->btf, type_id);
    533
    534	switch (BTF_INFO_KIND(t->info)) {
    535	case BTF_KIND_INT:
    536		return btf_dumper_int(t, bit_offset, data, d->jw,
    537				     d->is_plain_text);
    538	case BTF_KIND_STRUCT:
    539	case BTF_KIND_UNION:
    540		return btf_dumper_struct(d, type_id, data);
    541	case BTF_KIND_ARRAY:
    542		return btf_dumper_array(d, type_id, data);
    543	case BTF_KIND_ENUM:
    544		return btf_dumper_enum(d, t, data);
    545	case BTF_KIND_PTR:
    546		btf_dumper_ptr(d, t, data);
    547		return 0;
    548	case BTF_KIND_UNKN:
    549		jsonw_printf(d->jw, "(unknown)");
    550		return 0;
    551	case BTF_KIND_FWD:
    552		/* map key or value can't be forward */
    553		jsonw_printf(d->jw, "(fwd-kind-invalid)");
    554		return -EINVAL;
    555	case BTF_KIND_TYPEDEF:
    556	case BTF_KIND_VOLATILE:
    557	case BTF_KIND_CONST:
    558	case BTF_KIND_RESTRICT:
    559		return btf_dumper_modifier(d, type_id, bit_offset, data);
    560	case BTF_KIND_VAR:
    561		return btf_dumper_var(d, type_id, bit_offset, data);
    562	case BTF_KIND_DATASEC:
    563		return btf_dumper_datasec(d, type_id, data);
    564	default:
    565		jsonw_printf(d->jw, "(unsupported-kind");
    566		return -EINVAL;
    567	}
    568}
    569
    570int btf_dumper_type(const struct btf_dumper *d, __u32 type_id,
    571		    const void *data)
    572{
    573	return btf_dumper_do_type(d, type_id, 0, data);
    574}
    575
    576#define BTF_PRINT_ARG(...)						\
    577	do {								\
    578		pos += snprintf(func_sig + pos, size - pos,		\
    579				__VA_ARGS__);				\
    580		if (pos >= size)					\
    581			return -1;					\
    582	} while (0)
    583#define BTF_PRINT_TYPE(type)					\
    584	do {								\
    585		pos = __btf_dumper_type_only(btf, type, func_sig,	\
    586					     pos, size);		\
    587		if (pos == -1)						\
    588			return -1;					\
    589	} while (0)
    590
    591static int __btf_dumper_type_only(const struct btf *btf, __u32 type_id,
    592				  char *func_sig, int pos, int size)
    593{
    594	const struct btf_type *proto_type;
    595	const struct btf_array *array;
    596	const struct btf_var *var;
    597	const struct btf_type *t;
    598
    599	if (!type_id) {
    600		BTF_PRINT_ARG("void ");
    601		return pos;
    602	}
    603
    604	t = btf__type_by_id(btf, type_id);
    605
    606	switch (BTF_INFO_KIND(t->info)) {
    607	case BTF_KIND_INT:
    608	case BTF_KIND_TYPEDEF:
    609	case BTF_KIND_FLOAT:
    610		BTF_PRINT_ARG("%s ", btf__name_by_offset(btf, t->name_off));
    611		break;
    612	case BTF_KIND_STRUCT:
    613		BTF_PRINT_ARG("struct %s ",
    614			      btf__name_by_offset(btf, t->name_off));
    615		break;
    616	case BTF_KIND_UNION:
    617		BTF_PRINT_ARG("union %s ",
    618			      btf__name_by_offset(btf, t->name_off));
    619		break;
    620	case BTF_KIND_ENUM:
    621		BTF_PRINT_ARG("enum %s ",
    622			      btf__name_by_offset(btf, t->name_off));
    623		break;
    624	case BTF_KIND_ARRAY:
    625		array = (struct btf_array *)(t + 1);
    626		BTF_PRINT_TYPE(array->type);
    627		BTF_PRINT_ARG("[%d]", array->nelems);
    628		break;
    629	case BTF_KIND_PTR:
    630		BTF_PRINT_TYPE(t->type);
    631		BTF_PRINT_ARG("* ");
    632		break;
    633	case BTF_KIND_FWD:
    634		BTF_PRINT_ARG("%s %s ",
    635			      BTF_INFO_KFLAG(t->info) ? "union" : "struct",
    636			      btf__name_by_offset(btf, t->name_off));
    637		break;
    638	case BTF_KIND_VOLATILE:
    639		BTF_PRINT_ARG("volatile ");
    640		BTF_PRINT_TYPE(t->type);
    641		break;
    642	case BTF_KIND_CONST:
    643		BTF_PRINT_ARG("const ");
    644		BTF_PRINT_TYPE(t->type);
    645		break;
    646	case BTF_KIND_RESTRICT:
    647		BTF_PRINT_ARG("restrict ");
    648		BTF_PRINT_TYPE(t->type);
    649		break;
    650	case BTF_KIND_FUNC_PROTO:
    651		pos = btf_dump_func(btf, func_sig, t, NULL, pos, size);
    652		if (pos == -1)
    653			return -1;
    654		break;
    655	case BTF_KIND_FUNC:
    656		proto_type = btf__type_by_id(btf, t->type);
    657		pos = btf_dump_func(btf, func_sig, proto_type, t, pos, size);
    658		if (pos == -1)
    659			return -1;
    660		break;
    661	case BTF_KIND_VAR:
    662		var = (struct btf_var *)(t + 1);
    663		if (var->linkage == BTF_VAR_STATIC)
    664			BTF_PRINT_ARG("static ");
    665		BTF_PRINT_TYPE(t->type);
    666		BTF_PRINT_ARG(" %s",
    667			      btf__name_by_offset(btf, t->name_off));
    668		break;
    669	case BTF_KIND_DATASEC:
    670		BTF_PRINT_ARG("section (\"%s\") ",
    671			      btf__name_by_offset(btf, t->name_off));
    672		break;
    673	case BTF_KIND_UNKN:
    674	default:
    675		return -1;
    676	}
    677
    678	return pos;
    679}
    680
    681static int btf_dump_func(const struct btf *btf, char *func_sig,
    682			 const struct btf_type *func_proto,
    683			 const struct btf_type *func, int pos, int size)
    684{
    685	int i, vlen;
    686
    687	BTF_PRINT_TYPE(func_proto->type);
    688	if (func)
    689		BTF_PRINT_ARG("%s(", btf__name_by_offset(btf, func->name_off));
    690	else
    691		BTF_PRINT_ARG("(");
    692	vlen = BTF_INFO_VLEN(func_proto->info);
    693	for (i = 0; i < vlen; i++) {
    694		struct btf_param *arg = &((struct btf_param *)(func_proto + 1))[i];
    695
    696		if (i)
    697			BTF_PRINT_ARG(", ");
    698		if (arg->type) {
    699			BTF_PRINT_TYPE(arg->type);
    700			if (arg->name_off)
    701				BTF_PRINT_ARG("%s",
    702					      btf__name_by_offset(btf, arg->name_off));
    703			else if (pos && func_sig[pos - 1] == ' ')
    704				/* Remove unnecessary space for
    705				 * FUNC_PROTO that does not have
    706				 * arg->name_off
    707				 */
    708				func_sig[--pos] = '\0';
    709		} else {
    710			BTF_PRINT_ARG("...");
    711		}
    712	}
    713	BTF_PRINT_ARG(")");
    714
    715	return pos;
    716}
    717
    718void btf_dumper_type_only(const struct btf *btf, __u32 type_id, char *func_sig,
    719			  int size)
    720{
    721	int err;
    722
    723	func_sig[0] = '\0';
    724	if (!btf)
    725		return;
    726
    727	err = __btf_dumper_type_only(btf, type_id, func_sig, 0, size);
    728	if (err < 0)
    729		func_sig[0] = '\0';
    730}
    731
    732static const char *ltrim(const char *s)
    733{
    734	while (isspace(*s))
    735		s++;
    736
    737	return s;
    738}
    739
    740void btf_dump_linfo_plain(const struct btf *btf,
    741			  const struct bpf_line_info *linfo,
    742			  const char *prefix, bool linum)
    743{
    744	const char *line = btf__name_by_offset(btf, linfo->line_off);
    745
    746	if (!line)
    747		return;
    748	line = ltrim(line);
    749
    750	if (!prefix)
    751		prefix = "";
    752
    753	if (linum) {
    754		const char *file = btf__name_by_offset(btf, linfo->file_name_off);
    755
    756		/* More forgiving on file because linum option is
    757		 * expected to provide more info than the already
    758		 * available src line.
    759		 */
    760		if (!file)
    761			file = "";
    762
    763		printf("%s%s [file:%s line_num:%u line_col:%u]\n",
    764		       prefix, line, file,
    765		       BPF_LINE_INFO_LINE_NUM(linfo->line_col),
    766		       BPF_LINE_INFO_LINE_COL(linfo->line_col));
    767	} else {
    768		printf("%s%s\n", prefix, line);
    769	}
    770}
    771
    772void btf_dump_linfo_json(const struct btf *btf,
    773			 const struct bpf_line_info *linfo, bool linum)
    774{
    775	const char *line = btf__name_by_offset(btf, linfo->line_off);
    776
    777	if (line)
    778		jsonw_string_field(json_wtr, "src", ltrim(line));
    779
    780	if (linum) {
    781		const char *file = btf__name_by_offset(btf, linfo->file_name_off);
    782
    783		if (file)
    784			jsonw_string_field(json_wtr, "file", file);
    785
    786		if (BPF_LINE_INFO_LINE_NUM(linfo->line_col))
    787			jsonw_int_field(json_wtr, "line_num",
    788					BPF_LINE_INFO_LINE_NUM(linfo->line_col));
    789
    790		if (BPF_LINE_INFO_LINE_COL(linfo->line_col))
    791			jsonw_int_field(json_wtr, "line_col",
    792					BPF_LINE_INFO_LINE_COL(linfo->line_col));
    793	}
    794}