162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 262306a36Sopenharmony_ci/* Copyright (c) 2018 Facebook */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <ctype.h> 562306a36Sopenharmony_ci#include <stdio.h> /* for (FILE *) used by json_writer */ 662306a36Sopenharmony_ci#include <string.h> 762306a36Sopenharmony_ci#include <unistd.h> 862306a36Sopenharmony_ci#include <asm/byteorder.h> 962306a36Sopenharmony_ci#include <linux/bitops.h> 1062306a36Sopenharmony_ci#include <linux/btf.h> 1162306a36Sopenharmony_ci#include <linux/err.h> 1262306a36Sopenharmony_ci#include <bpf/btf.h> 1362306a36Sopenharmony_ci#include <bpf/bpf.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "json_writer.h" 1662306a36Sopenharmony_ci#include "main.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define BITS_PER_BYTE_MASK (BITS_PER_BYTE - 1) 1962306a36Sopenharmony_ci#define BITS_PER_BYTE_MASKED(bits) ((bits) & BITS_PER_BYTE_MASK) 2062306a36Sopenharmony_ci#define BITS_ROUNDDOWN_BYTES(bits) ((bits) >> 3) 2162306a36Sopenharmony_ci#define BITS_ROUNDUP_BYTES(bits) \ 2262306a36Sopenharmony_ci (BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits)) 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id, 2562306a36Sopenharmony_ci __u8 bit_offset, const void *data); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic int btf_dump_func(const struct btf *btf, char *func_sig, 2862306a36Sopenharmony_ci const struct btf_type *func_proto, 2962306a36Sopenharmony_ci const struct btf_type *func, int pos, int size); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic int dump_prog_id_as_func_ptr(const struct btf_dumper *d, 3262306a36Sopenharmony_ci const struct btf_type *func_proto, 3362306a36Sopenharmony_ci __u32 prog_id) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci const struct btf_type *func_type; 3662306a36Sopenharmony_ci int prog_fd = -1, func_sig_len; 3762306a36Sopenharmony_ci struct bpf_prog_info info = {}; 3862306a36Sopenharmony_ci __u32 info_len = sizeof(info); 3962306a36Sopenharmony_ci const char *prog_name = NULL; 4062306a36Sopenharmony_ci struct btf *prog_btf = NULL; 4162306a36Sopenharmony_ci struct bpf_func_info finfo; 4262306a36Sopenharmony_ci __u32 finfo_rec_size; 4362306a36Sopenharmony_ci char prog_str[1024]; 4462306a36Sopenharmony_ci int err; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci /* Get the ptr's func_proto */ 4762306a36Sopenharmony_ci func_sig_len = btf_dump_func(d->btf, prog_str, func_proto, NULL, 0, 4862306a36Sopenharmony_ci sizeof(prog_str)); 4962306a36Sopenharmony_ci if (func_sig_len == -1) 5062306a36Sopenharmony_ci return -1; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (!prog_id) 5362306a36Sopenharmony_ci goto print; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci /* Get the bpf_prog's name. Obtain from func_info. */ 5662306a36Sopenharmony_ci prog_fd = bpf_prog_get_fd_by_id(prog_id); 5762306a36Sopenharmony_ci if (prog_fd < 0) 5862306a36Sopenharmony_ci goto print; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len); 6162306a36Sopenharmony_ci if (err) 6262306a36Sopenharmony_ci goto print; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (!info.btf_id || !info.nr_func_info) 6562306a36Sopenharmony_ci goto print; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci finfo_rec_size = info.func_info_rec_size; 6862306a36Sopenharmony_ci memset(&info, 0, sizeof(info)); 6962306a36Sopenharmony_ci info.nr_func_info = 1; 7062306a36Sopenharmony_ci info.func_info_rec_size = finfo_rec_size; 7162306a36Sopenharmony_ci info.func_info = ptr_to_u64(&finfo); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len); 7462306a36Sopenharmony_ci if (err) 7562306a36Sopenharmony_ci goto print; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci prog_btf = btf__load_from_kernel_by_id(info.btf_id); 7862306a36Sopenharmony_ci if (!prog_btf) 7962306a36Sopenharmony_ci goto print; 8062306a36Sopenharmony_ci func_type = btf__type_by_id(prog_btf, finfo.type_id); 8162306a36Sopenharmony_ci if (!func_type || !btf_is_func(func_type)) 8262306a36Sopenharmony_ci goto print; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci prog_name = btf__name_by_offset(prog_btf, func_type->name_off); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ciprint: 8762306a36Sopenharmony_ci if (!prog_id) 8862306a36Sopenharmony_ci snprintf(&prog_str[func_sig_len], 8962306a36Sopenharmony_ci sizeof(prog_str) - func_sig_len, " 0"); 9062306a36Sopenharmony_ci else if (prog_name) 9162306a36Sopenharmony_ci snprintf(&prog_str[func_sig_len], 9262306a36Sopenharmony_ci sizeof(prog_str) - func_sig_len, 9362306a36Sopenharmony_ci " %s/prog_id:%u", prog_name, prog_id); 9462306a36Sopenharmony_ci else 9562306a36Sopenharmony_ci snprintf(&prog_str[func_sig_len], 9662306a36Sopenharmony_ci sizeof(prog_str) - func_sig_len, 9762306a36Sopenharmony_ci " <unknown_prog_name>/prog_id:%u", prog_id); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci prog_str[sizeof(prog_str) - 1] = '\0'; 10062306a36Sopenharmony_ci jsonw_string(d->jw, prog_str); 10162306a36Sopenharmony_ci btf__free(prog_btf); 10262306a36Sopenharmony_ci if (prog_fd >= 0) 10362306a36Sopenharmony_ci close(prog_fd); 10462306a36Sopenharmony_ci return 0; 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic void btf_dumper_ptr(const struct btf_dumper *d, 10862306a36Sopenharmony_ci const struct btf_type *t, 10962306a36Sopenharmony_ci const void *data) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci unsigned long value = *(unsigned long *)data; 11262306a36Sopenharmony_ci const struct btf_type *ptr_type; 11362306a36Sopenharmony_ci __s32 ptr_type_id; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci if (!d->prog_id_as_func_ptr || value > UINT32_MAX) 11662306a36Sopenharmony_ci goto print_ptr_value; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci ptr_type_id = btf__resolve_type(d->btf, t->type); 11962306a36Sopenharmony_ci if (ptr_type_id < 0) 12062306a36Sopenharmony_ci goto print_ptr_value; 12162306a36Sopenharmony_ci ptr_type = btf__type_by_id(d->btf, ptr_type_id); 12262306a36Sopenharmony_ci if (!ptr_type || !btf_is_func_proto(ptr_type)) 12362306a36Sopenharmony_ci goto print_ptr_value; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (!dump_prog_id_as_func_ptr(d, ptr_type, value)) 12662306a36Sopenharmony_ci return; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ciprint_ptr_value: 12962306a36Sopenharmony_ci if (d->is_plain_text) 13062306a36Sopenharmony_ci jsonw_printf(d->jw, "%p", (void *)value); 13162306a36Sopenharmony_ci else 13262306a36Sopenharmony_ci jsonw_printf(d->jw, "%lu", value); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic int btf_dumper_modifier(const struct btf_dumper *d, __u32 type_id, 13662306a36Sopenharmony_ci __u8 bit_offset, const void *data) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci int actual_type_id; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci actual_type_id = btf__resolve_type(d->btf, type_id); 14162306a36Sopenharmony_ci if (actual_type_id < 0) 14262306a36Sopenharmony_ci return actual_type_id; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci return btf_dumper_do_type(d, actual_type_id, bit_offset, data); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic int btf_dumper_enum(const struct btf_dumper *d, 14862306a36Sopenharmony_ci const struct btf_type *t, 14962306a36Sopenharmony_ci const void *data) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci const struct btf_enum *enums = btf_enum(t); 15262306a36Sopenharmony_ci __s64 value; 15362306a36Sopenharmony_ci __u16 i; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci switch (t->size) { 15662306a36Sopenharmony_ci case 8: 15762306a36Sopenharmony_ci value = *(__s64 *)data; 15862306a36Sopenharmony_ci break; 15962306a36Sopenharmony_ci case 4: 16062306a36Sopenharmony_ci value = *(__s32 *)data; 16162306a36Sopenharmony_ci break; 16262306a36Sopenharmony_ci case 2: 16362306a36Sopenharmony_ci value = *(__s16 *)data; 16462306a36Sopenharmony_ci break; 16562306a36Sopenharmony_ci case 1: 16662306a36Sopenharmony_ci value = *(__s8 *)data; 16762306a36Sopenharmony_ci break; 16862306a36Sopenharmony_ci default: 16962306a36Sopenharmony_ci return -EINVAL; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci for (i = 0; i < btf_vlen(t); i++) { 17362306a36Sopenharmony_ci if (value == enums[i].val) { 17462306a36Sopenharmony_ci jsonw_string(d->jw, 17562306a36Sopenharmony_ci btf__name_by_offset(d->btf, 17662306a36Sopenharmony_ci enums[i].name_off)); 17762306a36Sopenharmony_ci return 0; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci jsonw_int(d->jw, value); 18262306a36Sopenharmony_ci return 0; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic int btf_dumper_enum64(const struct btf_dumper *d, 18662306a36Sopenharmony_ci const struct btf_type *t, 18762306a36Sopenharmony_ci const void *data) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci const struct btf_enum64 *enums = btf_enum64(t); 19062306a36Sopenharmony_ci __u32 val_lo32, val_hi32; 19162306a36Sopenharmony_ci __u64 value; 19262306a36Sopenharmony_ci __u16 i; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci value = *(__u64 *)data; 19562306a36Sopenharmony_ci val_lo32 = (__u32)value; 19662306a36Sopenharmony_ci val_hi32 = value >> 32; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci for (i = 0; i < btf_vlen(t); i++) { 19962306a36Sopenharmony_ci if (val_lo32 == enums[i].val_lo32 && val_hi32 == enums[i].val_hi32) { 20062306a36Sopenharmony_ci jsonw_string(d->jw, 20162306a36Sopenharmony_ci btf__name_by_offset(d->btf, 20262306a36Sopenharmony_ci enums[i].name_off)); 20362306a36Sopenharmony_ci return 0; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci jsonw_int(d->jw, value); 20862306a36Sopenharmony_ci return 0; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic bool is_str_array(const struct btf *btf, const struct btf_array *arr, 21262306a36Sopenharmony_ci const char *s) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci const struct btf_type *elem_type; 21562306a36Sopenharmony_ci const char *end_s; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (!arr->nelems) 21862306a36Sopenharmony_ci return false; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci elem_type = btf__type_by_id(btf, arr->type); 22162306a36Sopenharmony_ci /* Not skipping typedef. typedef to char does not count as 22262306a36Sopenharmony_ci * a string now. 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_ci while (elem_type && btf_is_mod(elem_type)) 22562306a36Sopenharmony_ci elem_type = btf__type_by_id(btf, elem_type->type); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (!elem_type || !btf_is_int(elem_type) || elem_type->size != 1) 22862306a36Sopenharmony_ci return false; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (btf_int_encoding(elem_type) != BTF_INT_CHAR && 23162306a36Sopenharmony_ci strcmp("char", btf__name_by_offset(btf, elem_type->name_off))) 23262306a36Sopenharmony_ci return false; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci end_s = s + arr->nelems; 23562306a36Sopenharmony_ci while (s < end_s) { 23662306a36Sopenharmony_ci if (!*s) 23762306a36Sopenharmony_ci return true; 23862306a36Sopenharmony_ci if (*s <= 0x1f || *s >= 0x7f) 23962306a36Sopenharmony_ci return false; 24062306a36Sopenharmony_ci s++; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* '\0' is not found */ 24462306a36Sopenharmony_ci return false; 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic int btf_dumper_array(const struct btf_dumper *d, __u32 type_id, 24862306a36Sopenharmony_ci const void *data) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci const struct btf_type *t = btf__type_by_id(d->btf, type_id); 25162306a36Sopenharmony_ci struct btf_array *arr = (struct btf_array *)(t + 1); 25262306a36Sopenharmony_ci long long elem_size; 25362306a36Sopenharmony_ci int ret = 0; 25462306a36Sopenharmony_ci __u32 i; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (is_str_array(d->btf, arr, data)) { 25762306a36Sopenharmony_ci jsonw_string(d->jw, data); 25862306a36Sopenharmony_ci return 0; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci elem_size = btf__resolve_size(d->btf, arr->type); 26262306a36Sopenharmony_ci if (elem_size < 0) 26362306a36Sopenharmony_ci return elem_size; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci jsonw_start_array(d->jw); 26662306a36Sopenharmony_ci for (i = 0; i < arr->nelems; i++) { 26762306a36Sopenharmony_ci ret = btf_dumper_do_type(d, arr->type, 0, 26862306a36Sopenharmony_ci data + i * elem_size); 26962306a36Sopenharmony_ci if (ret) 27062306a36Sopenharmony_ci break; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci jsonw_end_array(d->jw); 27462306a36Sopenharmony_ci return ret; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic void btf_int128_print(json_writer_t *jw, const void *data, 27862306a36Sopenharmony_ci bool is_plain_text) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci /* data points to a __int128 number. 28162306a36Sopenharmony_ci * Suppose 28262306a36Sopenharmony_ci * int128_num = *(__int128 *)data; 28362306a36Sopenharmony_ci * The below formulas shows what upper_num and lower_num represents: 28462306a36Sopenharmony_ci * upper_num = int128_num >> 64; 28562306a36Sopenharmony_ci * lower_num = int128_num & 0xffffffffFFFFFFFFULL; 28662306a36Sopenharmony_ci */ 28762306a36Sopenharmony_ci __u64 upper_num, lower_num; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci#ifdef __BIG_ENDIAN_BITFIELD 29062306a36Sopenharmony_ci upper_num = *(__u64 *)data; 29162306a36Sopenharmony_ci lower_num = *(__u64 *)(data + 8); 29262306a36Sopenharmony_ci#else 29362306a36Sopenharmony_ci upper_num = *(__u64 *)(data + 8); 29462306a36Sopenharmony_ci lower_num = *(__u64 *)data; 29562306a36Sopenharmony_ci#endif 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (is_plain_text) { 29862306a36Sopenharmony_ci if (upper_num == 0) 29962306a36Sopenharmony_ci jsonw_printf(jw, "0x%llx", lower_num); 30062306a36Sopenharmony_ci else 30162306a36Sopenharmony_ci jsonw_printf(jw, "0x%llx%016llx", upper_num, lower_num); 30262306a36Sopenharmony_ci } else { 30362306a36Sopenharmony_ci if (upper_num == 0) 30462306a36Sopenharmony_ci jsonw_printf(jw, "\"0x%llx\"", lower_num); 30562306a36Sopenharmony_ci else 30662306a36Sopenharmony_ci jsonw_printf(jw, "\"0x%llx%016llx\"", upper_num, lower_num); 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic void btf_int128_shift(__u64 *print_num, __u16 left_shift_bits, 31162306a36Sopenharmony_ci __u16 right_shift_bits) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci __u64 upper_num, lower_num; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci#ifdef __BIG_ENDIAN_BITFIELD 31662306a36Sopenharmony_ci upper_num = print_num[0]; 31762306a36Sopenharmony_ci lower_num = print_num[1]; 31862306a36Sopenharmony_ci#else 31962306a36Sopenharmony_ci upper_num = print_num[1]; 32062306a36Sopenharmony_ci lower_num = print_num[0]; 32162306a36Sopenharmony_ci#endif 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* shake out un-needed bits by shift/or operations */ 32462306a36Sopenharmony_ci if (left_shift_bits >= 64) { 32562306a36Sopenharmony_ci upper_num = lower_num << (left_shift_bits - 64); 32662306a36Sopenharmony_ci lower_num = 0; 32762306a36Sopenharmony_ci } else { 32862306a36Sopenharmony_ci upper_num = (upper_num << left_shift_bits) | 32962306a36Sopenharmony_ci (lower_num >> (64 - left_shift_bits)); 33062306a36Sopenharmony_ci lower_num = lower_num << left_shift_bits; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (right_shift_bits >= 64) { 33462306a36Sopenharmony_ci lower_num = upper_num >> (right_shift_bits - 64); 33562306a36Sopenharmony_ci upper_num = 0; 33662306a36Sopenharmony_ci } else { 33762306a36Sopenharmony_ci lower_num = (lower_num >> right_shift_bits) | 33862306a36Sopenharmony_ci (upper_num << (64 - right_shift_bits)); 33962306a36Sopenharmony_ci upper_num = upper_num >> right_shift_bits; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci#ifdef __BIG_ENDIAN_BITFIELD 34362306a36Sopenharmony_ci print_num[0] = upper_num; 34462306a36Sopenharmony_ci print_num[1] = lower_num; 34562306a36Sopenharmony_ci#else 34662306a36Sopenharmony_ci print_num[0] = lower_num; 34762306a36Sopenharmony_ci print_num[1] = upper_num; 34862306a36Sopenharmony_ci#endif 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic void btf_dumper_bitfield(__u32 nr_bits, __u8 bit_offset, 35262306a36Sopenharmony_ci const void *data, json_writer_t *jw, 35362306a36Sopenharmony_ci bool is_plain_text) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci int left_shift_bits, right_shift_bits; 35662306a36Sopenharmony_ci __u64 print_num[2] = {}; 35762306a36Sopenharmony_ci int bytes_to_copy; 35862306a36Sopenharmony_ci int bits_to_copy; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci bits_to_copy = bit_offset + nr_bits; 36162306a36Sopenharmony_ci bytes_to_copy = BITS_ROUNDUP_BYTES(bits_to_copy); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci memcpy(print_num, data, bytes_to_copy); 36462306a36Sopenharmony_ci#if defined(__BIG_ENDIAN_BITFIELD) 36562306a36Sopenharmony_ci left_shift_bits = bit_offset; 36662306a36Sopenharmony_ci#elif defined(__LITTLE_ENDIAN_BITFIELD) 36762306a36Sopenharmony_ci left_shift_bits = 128 - bits_to_copy; 36862306a36Sopenharmony_ci#else 36962306a36Sopenharmony_ci#error neither big nor little endian 37062306a36Sopenharmony_ci#endif 37162306a36Sopenharmony_ci right_shift_bits = 128 - nr_bits; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci btf_int128_shift(print_num, left_shift_bits, right_shift_bits); 37462306a36Sopenharmony_ci btf_int128_print(jw, print_num, is_plain_text); 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic void btf_dumper_int_bits(__u32 int_type, __u8 bit_offset, 37962306a36Sopenharmony_ci const void *data, json_writer_t *jw, 38062306a36Sopenharmony_ci bool is_plain_text) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci int nr_bits = BTF_INT_BITS(int_type); 38362306a36Sopenharmony_ci int total_bits_offset; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* bits_offset is at most 7. 38662306a36Sopenharmony_ci * BTF_INT_OFFSET() cannot exceed 128 bits. 38762306a36Sopenharmony_ci */ 38862306a36Sopenharmony_ci total_bits_offset = bit_offset + BTF_INT_OFFSET(int_type); 38962306a36Sopenharmony_ci data += BITS_ROUNDDOWN_BYTES(total_bits_offset); 39062306a36Sopenharmony_ci bit_offset = BITS_PER_BYTE_MASKED(total_bits_offset); 39162306a36Sopenharmony_ci btf_dumper_bitfield(nr_bits, bit_offset, data, jw, 39262306a36Sopenharmony_ci is_plain_text); 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic int btf_dumper_int(const struct btf_type *t, __u8 bit_offset, 39662306a36Sopenharmony_ci const void *data, json_writer_t *jw, 39762306a36Sopenharmony_ci bool is_plain_text) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci __u32 *int_type; 40062306a36Sopenharmony_ci __u32 nr_bits; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci int_type = (__u32 *)(t + 1); 40362306a36Sopenharmony_ci nr_bits = BTF_INT_BITS(*int_type); 40462306a36Sopenharmony_ci /* if this is bit field */ 40562306a36Sopenharmony_ci if (bit_offset || BTF_INT_OFFSET(*int_type) || 40662306a36Sopenharmony_ci BITS_PER_BYTE_MASKED(nr_bits)) { 40762306a36Sopenharmony_ci btf_dumper_int_bits(*int_type, bit_offset, data, jw, 40862306a36Sopenharmony_ci is_plain_text); 40962306a36Sopenharmony_ci return 0; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (nr_bits == 128) { 41362306a36Sopenharmony_ci btf_int128_print(jw, data, is_plain_text); 41462306a36Sopenharmony_ci return 0; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci switch (BTF_INT_ENCODING(*int_type)) { 41862306a36Sopenharmony_ci case 0: 41962306a36Sopenharmony_ci if (BTF_INT_BITS(*int_type) == 64) 42062306a36Sopenharmony_ci jsonw_printf(jw, "%llu", *(__u64 *)data); 42162306a36Sopenharmony_ci else if (BTF_INT_BITS(*int_type) == 32) 42262306a36Sopenharmony_ci jsonw_printf(jw, "%u", *(__u32 *)data); 42362306a36Sopenharmony_ci else if (BTF_INT_BITS(*int_type) == 16) 42462306a36Sopenharmony_ci jsonw_printf(jw, "%hu", *(__u16 *)data); 42562306a36Sopenharmony_ci else if (BTF_INT_BITS(*int_type) == 8) 42662306a36Sopenharmony_ci jsonw_printf(jw, "%hhu", *(__u8 *)data); 42762306a36Sopenharmony_ci else 42862306a36Sopenharmony_ci btf_dumper_int_bits(*int_type, bit_offset, data, jw, 42962306a36Sopenharmony_ci is_plain_text); 43062306a36Sopenharmony_ci break; 43162306a36Sopenharmony_ci case BTF_INT_SIGNED: 43262306a36Sopenharmony_ci if (BTF_INT_BITS(*int_type) == 64) 43362306a36Sopenharmony_ci jsonw_printf(jw, "%lld", *(long long *)data); 43462306a36Sopenharmony_ci else if (BTF_INT_BITS(*int_type) == 32) 43562306a36Sopenharmony_ci jsonw_printf(jw, "%d", *(int *)data); 43662306a36Sopenharmony_ci else if (BTF_INT_BITS(*int_type) == 16) 43762306a36Sopenharmony_ci jsonw_printf(jw, "%hd", *(short *)data); 43862306a36Sopenharmony_ci else if (BTF_INT_BITS(*int_type) == 8) 43962306a36Sopenharmony_ci jsonw_printf(jw, "%hhd", *(char *)data); 44062306a36Sopenharmony_ci else 44162306a36Sopenharmony_ci btf_dumper_int_bits(*int_type, bit_offset, data, jw, 44262306a36Sopenharmony_ci is_plain_text); 44362306a36Sopenharmony_ci break; 44462306a36Sopenharmony_ci case BTF_INT_CHAR: 44562306a36Sopenharmony_ci if (isprint(*(char *)data)) 44662306a36Sopenharmony_ci jsonw_printf(jw, "\"%c\"", *(char *)data); 44762306a36Sopenharmony_ci else 44862306a36Sopenharmony_ci if (is_plain_text) 44962306a36Sopenharmony_ci jsonw_printf(jw, "0x%hhx", *(char *)data); 45062306a36Sopenharmony_ci else 45162306a36Sopenharmony_ci jsonw_printf(jw, "\"\\u00%02hhx\"", 45262306a36Sopenharmony_ci *(char *)data); 45362306a36Sopenharmony_ci break; 45462306a36Sopenharmony_ci case BTF_INT_BOOL: 45562306a36Sopenharmony_ci jsonw_bool(jw, *(bool *)data); 45662306a36Sopenharmony_ci break; 45762306a36Sopenharmony_ci default: 45862306a36Sopenharmony_ci /* shouldn't happen */ 45962306a36Sopenharmony_ci return -EINVAL; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci return 0; 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic int btf_dumper_struct(const struct btf_dumper *d, __u32 type_id, 46662306a36Sopenharmony_ci const void *data) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci const struct btf_type *t; 46962306a36Sopenharmony_ci struct btf_member *m; 47062306a36Sopenharmony_ci const void *data_off; 47162306a36Sopenharmony_ci int kind_flag; 47262306a36Sopenharmony_ci int ret = 0; 47362306a36Sopenharmony_ci int i, vlen; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci t = btf__type_by_id(d->btf, type_id); 47662306a36Sopenharmony_ci if (!t) 47762306a36Sopenharmony_ci return -EINVAL; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci kind_flag = BTF_INFO_KFLAG(t->info); 48062306a36Sopenharmony_ci vlen = BTF_INFO_VLEN(t->info); 48162306a36Sopenharmony_ci jsonw_start_object(d->jw); 48262306a36Sopenharmony_ci m = (struct btf_member *)(t + 1); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci for (i = 0; i < vlen; i++) { 48562306a36Sopenharmony_ci __u32 bit_offset = m[i].offset; 48662306a36Sopenharmony_ci __u32 bitfield_size = 0; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci if (kind_flag) { 48962306a36Sopenharmony_ci bitfield_size = BTF_MEMBER_BITFIELD_SIZE(bit_offset); 49062306a36Sopenharmony_ci bit_offset = BTF_MEMBER_BIT_OFFSET(bit_offset); 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci jsonw_name(d->jw, btf__name_by_offset(d->btf, m[i].name_off)); 49462306a36Sopenharmony_ci data_off = data + BITS_ROUNDDOWN_BYTES(bit_offset); 49562306a36Sopenharmony_ci if (bitfield_size) { 49662306a36Sopenharmony_ci btf_dumper_bitfield(bitfield_size, 49762306a36Sopenharmony_ci BITS_PER_BYTE_MASKED(bit_offset), 49862306a36Sopenharmony_ci data_off, d->jw, d->is_plain_text); 49962306a36Sopenharmony_ci } else { 50062306a36Sopenharmony_ci ret = btf_dumper_do_type(d, m[i].type, 50162306a36Sopenharmony_ci BITS_PER_BYTE_MASKED(bit_offset), 50262306a36Sopenharmony_ci data_off); 50362306a36Sopenharmony_ci if (ret) 50462306a36Sopenharmony_ci break; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci jsonw_end_object(d->jw); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci return ret; 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cistatic int btf_dumper_var(const struct btf_dumper *d, __u32 type_id, 51462306a36Sopenharmony_ci __u8 bit_offset, const void *data) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci const struct btf_type *t = btf__type_by_id(d->btf, type_id); 51762306a36Sopenharmony_ci int ret; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci jsonw_start_object(d->jw); 52062306a36Sopenharmony_ci jsonw_name(d->jw, btf__name_by_offset(d->btf, t->name_off)); 52162306a36Sopenharmony_ci ret = btf_dumper_do_type(d, t->type, bit_offset, data); 52262306a36Sopenharmony_ci jsonw_end_object(d->jw); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci return ret; 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic int btf_dumper_datasec(const struct btf_dumper *d, __u32 type_id, 52862306a36Sopenharmony_ci const void *data) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci struct btf_var_secinfo *vsi; 53162306a36Sopenharmony_ci const struct btf_type *t; 53262306a36Sopenharmony_ci int ret = 0, i, vlen; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci t = btf__type_by_id(d->btf, type_id); 53562306a36Sopenharmony_ci if (!t) 53662306a36Sopenharmony_ci return -EINVAL; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci vlen = BTF_INFO_VLEN(t->info); 53962306a36Sopenharmony_ci vsi = (struct btf_var_secinfo *)(t + 1); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci jsonw_start_object(d->jw); 54262306a36Sopenharmony_ci jsonw_name(d->jw, btf__name_by_offset(d->btf, t->name_off)); 54362306a36Sopenharmony_ci jsonw_start_array(d->jw); 54462306a36Sopenharmony_ci for (i = 0; i < vlen; i++) { 54562306a36Sopenharmony_ci ret = btf_dumper_do_type(d, vsi[i].type, 0, data + vsi[i].offset); 54662306a36Sopenharmony_ci if (ret) 54762306a36Sopenharmony_ci break; 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci jsonw_end_array(d->jw); 55062306a36Sopenharmony_ci jsonw_end_object(d->jw); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci return ret; 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id, 55662306a36Sopenharmony_ci __u8 bit_offset, const void *data) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci const struct btf_type *t = btf__type_by_id(d->btf, type_id); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci switch (BTF_INFO_KIND(t->info)) { 56162306a36Sopenharmony_ci case BTF_KIND_INT: 56262306a36Sopenharmony_ci return btf_dumper_int(t, bit_offset, data, d->jw, 56362306a36Sopenharmony_ci d->is_plain_text); 56462306a36Sopenharmony_ci case BTF_KIND_STRUCT: 56562306a36Sopenharmony_ci case BTF_KIND_UNION: 56662306a36Sopenharmony_ci return btf_dumper_struct(d, type_id, data); 56762306a36Sopenharmony_ci case BTF_KIND_ARRAY: 56862306a36Sopenharmony_ci return btf_dumper_array(d, type_id, data); 56962306a36Sopenharmony_ci case BTF_KIND_ENUM: 57062306a36Sopenharmony_ci return btf_dumper_enum(d, t, data); 57162306a36Sopenharmony_ci case BTF_KIND_ENUM64: 57262306a36Sopenharmony_ci return btf_dumper_enum64(d, t, data); 57362306a36Sopenharmony_ci case BTF_KIND_PTR: 57462306a36Sopenharmony_ci btf_dumper_ptr(d, t, data); 57562306a36Sopenharmony_ci return 0; 57662306a36Sopenharmony_ci case BTF_KIND_UNKN: 57762306a36Sopenharmony_ci jsonw_printf(d->jw, "(unknown)"); 57862306a36Sopenharmony_ci return 0; 57962306a36Sopenharmony_ci case BTF_KIND_FWD: 58062306a36Sopenharmony_ci /* map key or value can't be forward */ 58162306a36Sopenharmony_ci jsonw_printf(d->jw, "(fwd-kind-invalid)"); 58262306a36Sopenharmony_ci return -EINVAL; 58362306a36Sopenharmony_ci case BTF_KIND_TYPEDEF: 58462306a36Sopenharmony_ci case BTF_KIND_VOLATILE: 58562306a36Sopenharmony_ci case BTF_KIND_CONST: 58662306a36Sopenharmony_ci case BTF_KIND_RESTRICT: 58762306a36Sopenharmony_ci return btf_dumper_modifier(d, type_id, bit_offset, data); 58862306a36Sopenharmony_ci case BTF_KIND_VAR: 58962306a36Sopenharmony_ci return btf_dumper_var(d, type_id, bit_offset, data); 59062306a36Sopenharmony_ci case BTF_KIND_DATASEC: 59162306a36Sopenharmony_ci return btf_dumper_datasec(d, type_id, data); 59262306a36Sopenharmony_ci default: 59362306a36Sopenharmony_ci jsonw_printf(d->jw, "(unsupported-kind"); 59462306a36Sopenharmony_ci return -EINVAL; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ciint btf_dumper_type(const struct btf_dumper *d, __u32 type_id, 59962306a36Sopenharmony_ci const void *data) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci return btf_dumper_do_type(d, type_id, 0, data); 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci#define BTF_PRINT_ARG(...) \ 60562306a36Sopenharmony_ci do { \ 60662306a36Sopenharmony_ci pos += snprintf(func_sig + pos, size - pos, \ 60762306a36Sopenharmony_ci __VA_ARGS__); \ 60862306a36Sopenharmony_ci if (pos >= size) \ 60962306a36Sopenharmony_ci return -1; \ 61062306a36Sopenharmony_ci } while (0) 61162306a36Sopenharmony_ci#define BTF_PRINT_TYPE(type) \ 61262306a36Sopenharmony_ci do { \ 61362306a36Sopenharmony_ci pos = __btf_dumper_type_only(btf, type, func_sig, \ 61462306a36Sopenharmony_ci pos, size); \ 61562306a36Sopenharmony_ci if (pos == -1) \ 61662306a36Sopenharmony_ci return -1; \ 61762306a36Sopenharmony_ci } while (0) 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_cistatic int __btf_dumper_type_only(const struct btf *btf, __u32 type_id, 62062306a36Sopenharmony_ci char *func_sig, int pos, int size) 62162306a36Sopenharmony_ci{ 62262306a36Sopenharmony_ci const struct btf_type *proto_type; 62362306a36Sopenharmony_ci const struct btf_array *array; 62462306a36Sopenharmony_ci const struct btf_var *var; 62562306a36Sopenharmony_ci const struct btf_type *t; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci if (!type_id) { 62862306a36Sopenharmony_ci BTF_PRINT_ARG("void "); 62962306a36Sopenharmony_ci return pos; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci t = btf__type_by_id(btf, type_id); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci switch (BTF_INFO_KIND(t->info)) { 63562306a36Sopenharmony_ci case BTF_KIND_INT: 63662306a36Sopenharmony_ci case BTF_KIND_TYPEDEF: 63762306a36Sopenharmony_ci case BTF_KIND_FLOAT: 63862306a36Sopenharmony_ci BTF_PRINT_ARG("%s ", btf__name_by_offset(btf, t->name_off)); 63962306a36Sopenharmony_ci break; 64062306a36Sopenharmony_ci case BTF_KIND_STRUCT: 64162306a36Sopenharmony_ci BTF_PRINT_ARG("struct %s ", 64262306a36Sopenharmony_ci btf__name_by_offset(btf, t->name_off)); 64362306a36Sopenharmony_ci break; 64462306a36Sopenharmony_ci case BTF_KIND_UNION: 64562306a36Sopenharmony_ci BTF_PRINT_ARG("union %s ", 64662306a36Sopenharmony_ci btf__name_by_offset(btf, t->name_off)); 64762306a36Sopenharmony_ci break; 64862306a36Sopenharmony_ci case BTF_KIND_ENUM: 64962306a36Sopenharmony_ci case BTF_KIND_ENUM64: 65062306a36Sopenharmony_ci BTF_PRINT_ARG("enum %s ", 65162306a36Sopenharmony_ci btf__name_by_offset(btf, t->name_off)); 65262306a36Sopenharmony_ci break; 65362306a36Sopenharmony_ci case BTF_KIND_ARRAY: 65462306a36Sopenharmony_ci array = (struct btf_array *)(t + 1); 65562306a36Sopenharmony_ci BTF_PRINT_TYPE(array->type); 65662306a36Sopenharmony_ci BTF_PRINT_ARG("[%d]", array->nelems); 65762306a36Sopenharmony_ci break; 65862306a36Sopenharmony_ci case BTF_KIND_PTR: 65962306a36Sopenharmony_ci BTF_PRINT_TYPE(t->type); 66062306a36Sopenharmony_ci BTF_PRINT_ARG("* "); 66162306a36Sopenharmony_ci break; 66262306a36Sopenharmony_ci case BTF_KIND_FWD: 66362306a36Sopenharmony_ci BTF_PRINT_ARG("%s %s ", 66462306a36Sopenharmony_ci BTF_INFO_KFLAG(t->info) ? "union" : "struct", 66562306a36Sopenharmony_ci btf__name_by_offset(btf, t->name_off)); 66662306a36Sopenharmony_ci break; 66762306a36Sopenharmony_ci case BTF_KIND_VOLATILE: 66862306a36Sopenharmony_ci BTF_PRINT_ARG("volatile "); 66962306a36Sopenharmony_ci BTF_PRINT_TYPE(t->type); 67062306a36Sopenharmony_ci break; 67162306a36Sopenharmony_ci case BTF_KIND_CONST: 67262306a36Sopenharmony_ci BTF_PRINT_ARG("const "); 67362306a36Sopenharmony_ci BTF_PRINT_TYPE(t->type); 67462306a36Sopenharmony_ci break; 67562306a36Sopenharmony_ci case BTF_KIND_RESTRICT: 67662306a36Sopenharmony_ci BTF_PRINT_ARG("restrict "); 67762306a36Sopenharmony_ci BTF_PRINT_TYPE(t->type); 67862306a36Sopenharmony_ci break; 67962306a36Sopenharmony_ci case BTF_KIND_FUNC_PROTO: 68062306a36Sopenharmony_ci pos = btf_dump_func(btf, func_sig, t, NULL, pos, size); 68162306a36Sopenharmony_ci if (pos == -1) 68262306a36Sopenharmony_ci return -1; 68362306a36Sopenharmony_ci break; 68462306a36Sopenharmony_ci case BTF_KIND_FUNC: 68562306a36Sopenharmony_ci proto_type = btf__type_by_id(btf, t->type); 68662306a36Sopenharmony_ci pos = btf_dump_func(btf, func_sig, proto_type, t, pos, size); 68762306a36Sopenharmony_ci if (pos == -1) 68862306a36Sopenharmony_ci return -1; 68962306a36Sopenharmony_ci break; 69062306a36Sopenharmony_ci case BTF_KIND_VAR: 69162306a36Sopenharmony_ci var = (struct btf_var *)(t + 1); 69262306a36Sopenharmony_ci if (var->linkage == BTF_VAR_STATIC) 69362306a36Sopenharmony_ci BTF_PRINT_ARG("static "); 69462306a36Sopenharmony_ci BTF_PRINT_TYPE(t->type); 69562306a36Sopenharmony_ci BTF_PRINT_ARG(" %s", 69662306a36Sopenharmony_ci btf__name_by_offset(btf, t->name_off)); 69762306a36Sopenharmony_ci break; 69862306a36Sopenharmony_ci case BTF_KIND_DATASEC: 69962306a36Sopenharmony_ci BTF_PRINT_ARG("section (\"%s\") ", 70062306a36Sopenharmony_ci btf__name_by_offset(btf, t->name_off)); 70162306a36Sopenharmony_ci break; 70262306a36Sopenharmony_ci case BTF_KIND_UNKN: 70362306a36Sopenharmony_ci default: 70462306a36Sopenharmony_ci return -1; 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci return pos; 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cistatic int btf_dump_func(const struct btf *btf, char *func_sig, 71162306a36Sopenharmony_ci const struct btf_type *func_proto, 71262306a36Sopenharmony_ci const struct btf_type *func, int pos, int size) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci int i, vlen; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci BTF_PRINT_TYPE(func_proto->type); 71762306a36Sopenharmony_ci if (func) 71862306a36Sopenharmony_ci BTF_PRINT_ARG("%s(", btf__name_by_offset(btf, func->name_off)); 71962306a36Sopenharmony_ci else 72062306a36Sopenharmony_ci BTF_PRINT_ARG("("); 72162306a36Sopenharmony_ci vlen = BTF_INFO_VLEN(func_proto->info); 72262306a36Sopenharmony_ci for (i = 0; i < vlen; i++) { 72362306a36Sopenharmony_ci struct btf_param *arg = &((struct btf_param *)(func_proto + 1))[i]; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci if (i) 72662306a36Sopenharmony_ci BTF_PRINT_ARG(", "); 72762306a36Sopenharmony_ci if (arg->type) { 72862306a36Sopenharmony_ci BTF_PRINT_TYPE(arg->type); 72962306a36Sopenharmony_ci if (arg->name_off) 73062306a36Sopenharmony_ci BTF_PRINT_ARG("%s", 73162306a36Sopenharmony_ci btf__name_by_offset(btf, arg->name_off)); 73262306a36Sopenharmony_ci else if (pos && func_sig[pos - 1] == ' ') 73362306a36Sopenharmony_ci /* Remove unnecessary space for 73462306a36Sopenharmony_ci * FUNC_PROTO that does not have 73562306a36Sopenharmony_ci * arg->name_off 73662306a36Sopenharmony_ci */ 73762306a36Sopenharmony_ci func_sig[--pos] = '\0'; 73862306a36Sopenharmony_ci } else { 73962306a36Sopenharmony_ci BTF_PRINT_ARG("..."); 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci BTF_PRINT_ARG(")"); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci return pos; 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_civoid btf_dumper_type_only(const struct btf *btf, __u32 type_id, char *func_sig, 74862306a36Sopenharmony_ci int size) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci int err; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci func_sig[0] = '\0'; 75362306a36Sopenharmony_ci if (!btf) 75462306a36Sopenharmony_ci return; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci err = __btf_dumper_type_only(btf, type_id, func_sig, 0, size); 75762306a36Sopenharmony_ci if (err < 0) 75862306a36Sopenharmony_ci func_sig[0] = '\0'; 75962306a36Sopenharmony_ci} 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_cistatic const char *ltrim(const char *s) 76262306a36Sopenharmony_ci{ 76362306a36Sopenharmony_ci while (isspace(*s)) 76462306a36Sopenharmony_ci s++; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci return s; 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_civoid btf_dump_linfo_plain(const struct btf *btf, 77062306a36Sopenharmony_ci const struct bpf_line_info *linfo, 77162306a36Sopenharmony_ci const char *prefix, bool linum) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci const char *line = btf__name_by_offset(btf, linfo->line_off); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci if (!line) 77662306a36Sopenharmony_ci return; 77762306a36Sopenharmony_ci line = ltrim(line); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci if (!prefix) 78062306a36Sopenharmony_ci prefix = ""; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci if (linum) { 78362306a36Sopenharmony_ci const char *file = btf__name_by_offset(btf, linfo->file_name_off); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci /* More forgiving on file because linum option is 78662306a36Sopenharmony_ci * expected to provide more info than the already 78762306a36Sopenharmony_ci * available src line. 78862306a36Sopenharmony_ci */ 78962306a36Sopenharmony_ci if (!file) 79062306a36Sopenharmony_ci file = ""; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci printf("%s%s [file:%s line_num:%u line_col:%u]\n", 79362306a36Sopenharmony_ci prefix, line, file, 79462306a36Sopenharmony_ci BPF_LINE_INFO_LINE_NUM(linfo->line_col), 79562306a36Sopenharmony_ci BPF_LINE_INFO_LINE_COL(linfo->line_col)); 79662306a36Sopenharmony_ci } else { 79762306a36Sopenharmony_ci printf("%s%s\n", prefix, line); 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_civoid btf_dump_linfo_json(const struct btf *btf, 80262306a36Sopenharmony_ci const struct bpf_line_info *linfo, bool linum) 80362306a36Sopenharmony_ci{ 80462306a36Sopenharmony_ci const char *line = btf__name_by_offset(btf, linfo->line_off); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci if (line) 80762306a36Sopenharmony_ci jsonw_string_field(json_wtr, "src", ltrim(line)); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci if (linum) { 81062306a36Sopenharmony_ci const char *file = btf__name_by_offset(btf, linfo->file_name_off); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci if (file) 81362306a36Sopenharmony_ci jsonw_string_field(json_wtr, "file", file); 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci if (BPF_LINE_INFO_LINE_NUM(linfo->line_col)) 81662306a36Sopenharmony_ci jsonw_int_field(json_wtr, "line_num", 81762306a36Sopenharmony_ci BPF_LINE_INFO_LINE_NUM(linfo->line_col)); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci if (BPF_LINE_INFO_LINE_COL(linfo->line_col)) 82062306a36Sopenharmony_ci jsonw_int_field(json_wtr, "line_col", 82162306a36Sopenharmony_ci BPF_LINE_INFO_LINE_COL(linfo->line_col)); 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cistatic void dotlabel_puts(const char *s) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci for (; *s; ++s) { 82862306a36Sopenharmony_ci switch (*s) { 82962306a36Sopenharmony_ci case '\\': 83062306a36Sopenharmony_ci case '"': 83162306a36Sopenharmony_ci case '{': 83262306a36Sopenharmony_ci case '}': 83362306a36Sopenharmony_ci case '<': 83462306a36Sopenharmony_ci case '>': 83562306a36Sopenharmony_ci case '|': 83662306a36Sopenharmony_ci case ' ': 83762306a36Sopenharmony_ci putchar('\\'); 83862306a36Sopenharmony_ci fallthrough; 83962306a36Sopenharmony_ci default: 84062306a36Sopenharmony_ci putchar(*s); 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci} 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_cistatic const char *shorten_path(const char *path) 84662306a36Sopenharmony_ci{ 84762306a36Sopenharmony_ci const unsigned int MAX_PATH_LEN = 32; 84862306a36Sopenharmony_ci size_t len = strlen(path); 84962306a36Sopenharmony_ci const char *shortpath; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci if (len <= MAX_PATH_LEN) 85262306a36Sopenharmony_ci return path; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci /* Search for last '/' under the MAX_PATH_LEN limit */ 85562306a36Sopenharmony_ci shortpath = strchr(path + len - MAX_PATH_LEN, '/'); 85662306a36Sopenharmony_ci if (shortpath) { 85762306a36Sopenharmony_ci if (shortpath < path + strlen("...")) 85862306a36Sopenharmony_ci /* We removed a very short prefix, e.g. "/w", and we'll 85962306a36Sopenharmony_ci * make the path longer by prefixing with the ellipsis. 86062306a36Sopenharmony_ci * Not worth it, keep initial path. 86162306a36Sopenharmony_ci */ 86262306a36Sopenharmony_ci return path; 86362306a36Sopenharmony_ci return shortpath; 86462306a36Sopenharmony_ci } 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci /* File base name length is > MAX_PATH_LEN, search for last '/' */ 86762306a36Sopenharmony_ci shortpath = strrchr(path, '/'); 86862306a36Sopenharmony_ci if (shortpath) 86962306a36Sopenharmony_ci return shortpath; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci return path; 87262306a36Sopenharmony_ci} 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_civoid btf_dump_linfo_dotlabel(const struct btf *btf, 87562306a36Sopenharmony_ci const struct bpf_line_info *linfo, bool linum) 87662306a36Sopenharmony_ci{ 87762306a36Sopenharmony_ci const char *line = btf__name_by_offset(btf, linfo->line_off); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci if (!line || !strlen(line)) 88062306a36Sopenharmony_ci return; 88162306a36Sopenharmony_ci line = ltrim(line); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci if (linum) { 88462306a36Sopenharmony_ci const char *file = btf__name_by_offset(btf, linfo->file_name_off); 88562306a36Sopenharmony_ci const char *shortfile; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci /* More forgiving on file because linum option is 88862306a36Sopenharmony_ci * expected to provide more info than the already 88962306a36Sopenharmony_ci * available src line. 89062306a36Sopenharmony_ci */ 89162306a36Sopenharmony_ci if (!file) 89262306a36Sopenharmony_ci shortfile = ""; 89362306a36Sopenharmony_ci else 89462306a36Sopenharmony_ci shortfile = shorten_path(file); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci printf("; [%s", shortfile > file ? "..." : ""); 89762306a36Sopenharmony_ci dotlabel_puts(shortfile); 89862306a36Sopenharmony_ci printf(" line:%u col:%u]\\l\\\n", 89962306a36Sopenharmony_ci BPF_LINE_INFO_LINE_NUM(linfo->line_col), 90062306a36Sopenharmony_ci BPF_LINE_INFO_LINE_COL(linfo->line_col)); 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci printf("; "); 90462306a36Sopenharmony_ci dotlabel_puts(line); 90562306a36Sopenharmony_ci printf("\\l\\\n"); 90662306a36Sopenharmony_ci} 907