Skip to content

Commit b00b8da

Browse files
iamkafaiborkmann
authored andcommitted
bpf: btf: Add pretty print capability for data with BTF type info
This patch adds pretty print capability for data with BTF type info. The current usage is to allow pretty print for a BPF map. The next few patches will allow a read() on a pinned map with BTF type info for its key and value. This patch uses the seq_printf() infra. Signed-off-by: Martin KaFai Lau <[email protected]> Acked-by: Alexei Starovoitov <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]>
1 parent 179cde8 commit b00b8da

File tree

2 files changed

+200
-0
lines changed

2 files changed

+200
-0
lines changed

include/linux/btf.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,7 @@ struct btf_type;
3333
const struct btf_type *btf_type_id_size(const struct btf *btf,
3434
u32 *type_id,
3535
u32 *ret_size);
36+
void btf_type_seq_show(const struct btf *btf, u32 type_id, void *obj,
37+
struct seq_file *m);
3638

3739
#endif

kernel/bpf/btf.c

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include <uapi/linux/btf.h>
55
#include <uapi/linux/types.h>
6+
#include <linux/seq_file.h>
67
#include <linux/compiler.h>
78
#include <linux/errno.h>
89
#include <linux/slab.h>
@@ -256,6 +257,9 @@ struct btf_kind_operations {
256257
const struct btf_type *member_type);
257258
void (*log_details)(struct btf_verifier_env *env,
258259
const struct btf_type *t);
260+
void (*seq_show)(const struct btf *btf, const struct btf_type *t,
261+
u32 type_id, void *data, u8 bits_offsets,
262+
struct seq_file *m);
259263
};
260264

261265
static const struct btf_kind_operations * const kind_ops[NR_BTF_KINDS];
@@ -781,6 +785,13 @@ static int btf_df_resolve(struct btf_verifier_env *env,
781785
return -EINVAL;
782786
}
783787

788+
static void btf_df_seq_show(const struct btf *btf, const struct btf_type *t,
789+
u32 type_id, void *data, u8 bits_offsets,
790+
struct seq_file *m)
791+
{
792+
seq_printf(m, "<unsupported kind:%u>", BTF_INFO_KIND(t->info));
793+
}
794+
784795
static int btf_int_check_member(struct btf_verifier_env *env,
785796
const struct btf_type *struct_type,
786797
const struct btf_member *member,
@@ -879,11 +890,96 @@ static void btf_int_log(struct btf_verifier_env *env,
879890
btf_int_encoding_str(BTF_INT_ENCODING(int_data)));
880891
}
881892

893+
static void btf_int_bits_seq_show(const struct btf *btf,
894+
const struct btf_type *t,
895+
void *data, u8 bits_offset,
896+
struct seq_file *m)
897+
{
898+
u32 int_data = btf_type_int(t);
899+
u16 nr_bits = BTF_INT_BITS(int_data);
900+
u16 total_bits_offset;
901+
u16 nr_copy_bytes;
902+
u16 nr_copy_bits;
903+
u8 nr_upper_bits;
904+
union {
905+
u64 u64_num;
906+
u8 u8_nums[8];
907+
} print_num;
908+
909+
total_bits_offset = bits_offset + BTF_INT_OFFSET(int_data);
910+
data += BITS_ROUNDDOWN_BYTES(total_bits_offset);
911+
bits_offset = BITS_PER_BYTE_MASKED(total_bits_offset);
912+
nr_copy_bits = nr_bits + bits_offset;
913+
nr_copy_bytes = BITS_ROUNDUP_BYTES(nr_copy_bits);
914+
915+
print_num.u64_num = 0;
916+
memcpy(&print_num.u64_num, data, nr_copy_bytes);
917+
918+
/* Ditch the higher order bits */
919+
nr_upper_bits = BITS_PER_BYTE_MASKED(nr_copy_bits);
920+
if (nr_upper_bits) {
921+
/* We need to mask out some bits of the upper byte. */
922+
u8 mask = (1 << nr_upper_bits) - 1;
923+
924+
print_num.u8_nums[nr_copy_bytes - 1] &= mask;
925+
}
926+
927+
print_num.u64_num >>= bits_offset;
928+
929+
seq_printf(m, "0x%llx", print_num.u64_num);
930+
}
931+
932+
static void btf_int_seq_show(const struct btf *btf, const struct btf_type *t,
933+
u32 type_id, void *data, u8 bits_offset,
934+
struct seq_file *m)
935+
{
936+
u32 int_data = btf_type_int(t);
937+
u8 encoding = BTF_INT_ENCODING(int_data);
938+
bool sign = encoding & BTF_INT_SIGNED;
939+
u32 nr_bits = BTF_INT_BITS(int_data);
940+
941+
if (bits_offset || BTF_INT_OFFSET(int_data) ||
942+
BITS_PER_BYTE_MASKED(nr_bits)) {
943+
btf_int_bits_seq_show(btf, t, data, bits_offset, m);
944+
return;
945+
}
946+
947+
switch (nr_bits) {
948+
case 64:
949+
if (sign)
950+
seq_printf(m, "%lld", *(s64 *)data);
951+
else
952+
seq_printf(m, "%llu", *(u64 *)data);
953+
break;
954+
case 32:
955+
if (sign)
956+
seq_printf(m, "%d", *(s32 *)data);
957+
else
958+
seq_printf(m, "%u", *(u32 *)data);
959+
break;
960+
case 16:
961+
if (sign)
962+
seq_printf(m, "%d", *(s16 *)data);
963+
else
964+
seq_printf(m, "%u", *(u16 *)data);
965+
break;
966+
case 8:
967+
if (sign)
968+
seq_printf(m, "%d", *(s8 *)data);
969+
else
970+
seq_printf(m, "%u", *(u8 *)data);
971+
break;
972+
default:
973+
btf_int_bits_seq_show(btf, t, data, bits_offset, m);
974+
}
975+
}
976+
882977
static const struct btf_kind_operations int_ops = {
883978
.check_meta = btf_int_check_meta,
884979
.resolve = btf_df_resolve,
885980
.check_member = btf_int_check_member,
886981
.log_details = btf_int_log,
982+
.seq_show = btf_int_seq_show,
887983
};
888984

889985
static int btf_modifier_check_member(struct btf_verifier_env *env,
@@ -1054,6 +1150,24 @@ static int btf_ptr_resolve(struct btf_verifier_env *env,
10541150
return 0;
10551151
}
10561152

1153+
static void btf_modifier_seq_show(const struct btf *btf,
1154+
const struct btf_type *t,
1155+
u32 type_id, void *data,
1156+
u8 bits_offset, struct seq_file *m)
1157+
{
1158+
t = btf_type_id_resolve(btf, &type_id);
1159+
1160+
btf_type_ops(t)->seq_show(btf, t, type_id, data, bits_offset, m);
1161+
}
1162+
1163+
static void btf_ptr_seq_show(const struct btf *btf, const struct btf_type *t,
1164+
u32 type_id, void *data, u8 bits_offset,
1165+
struct seq_file *m)
1166+
{
1167+
/* It is a hashed value */
1168+
seq_printf(m, "%p", *(void **)data);
1169+
}
1170+
10571171
static void btf_ref_type_log(struct btf_verifier_env *env,
10581172
const struct btf_type *t)
10591173
{
@@ -1065,20 +1179,23 @@ static struct btf_kind_operations modifier_ops = {
10651179
.resolve = btf_modifier_resolve,
10661180
.check_member = btf_modifier_check_member,
10671181
.log_details = btf_ref_type_log,
1182+
.seq_show = btf_modifier_seq_show,
10681183
};
10691184

10701185
static struct btf_kind_operations ptr_ops = {
10711186
.check_meta = btf_ref_type_check_meta,
10721187
.resolve = btf_ptr_resolve,
10731188
.check_member = btf_ptr_check_member,
10741189
.log_details = btf_ref_type_log,
1190+
.seq_show = btf_ptr_seq_show,
10751191
};
10761192

10771193
static struct btf_kind_operations fwd_ops = {
10781194
.check_meta = btf_ref_type_check_meta,
10791195
.resolve = btf_df_resolve,
10801196
.check_member = btf_df_check_member,
10811197
.log_details = btf_ref_type_log,
1198+
.seq_show = btf_df_seq_show,
10821199
};
10831200

10841201
static int btf_array_check_member(struct btf_verifier_env *env,
@@ -1209,11 +1326,36 @@ static void btf_array_log(struct btf_verifier_env *env,
12091326
array->type, array->index_type, array->nelems);
12101327
}
12111328

1329+
static void btf_array_seq_show(const struct btf *btf, const struct btf_type *t,
1330+
u32 type_id, void *data, u8 bits_offset,
1331+
struct seq_file *m)
1332+
{
1333+
const struct btf_array *array = btf_type_array(t);
1334+
const struct btf_kind_operations *elem_ops;
1335+
const struct btf_type *elem_type;
1336+
u32 i, elem_size, elem_type_id;
1337+
1338+
elem_type_id = array->type;
1339+
elem_type = btf_type_id_size(btf, &elem_type_id, &elem_size);
1340+
elem_ops = btf_type_ops(elem_type);
1341+
seq_puts(m, "[");
1342+
for (i = 0; i < array->nelems; i++) {
1343+
if (i)
1344+
seq_puts(m, ",");
1345+
1346+
elem_ops->seq_show(btf, elem_type, elem_type_id, data,
1347+
bits_offset, m);
1348+
data += elem_size;
1349+
}
1350+
seq_puts(m, "]");
1351+
}
1352+
12121353
static struct btf_kind_operations array_ops = {
12131354
.check_meta = btf_array_check_meta,
12141355
.resolve = btf_array_resolve,
12151356
.check_member = btf_array_check_member,
12161357
.log_details = btf_array_log,
1358+
.seq_show = btf_array_seq_show,
12171359
};
12181360

12191361
static int btf_struct_check_member(struct btf_verifier_env *env,
@@ -1361,11 +1503,39 @@ static void btf_struct_log(struct btf_verifier_env *env,
13611503
btf_verifier_log(env, "size=%u vlen=%u", t->size, btf_type_vlen(t));
13621504
}
13631505

1506+
static void btf_struct_seq_show(const struct btf *btf, const struct btf_type *t,
1507+
u32 type_id, void *data, u8 bits_offset,
1508+
struct seq_file *m)
1509+
{
1510+
const char *seq = BTF_INFO_KIND(t->info) == BTF_KIND_UNION ? "|" : ",";
1511+
const struct btf_member *member;
1512+
u32 i;
1513+
1514+
seq_puts(m, "{");
1515+
for_each_member(i, t, member) {
1516+
const struct btf_type *member_type = btf_type_by_id(btf,
1517+
member->type);
1518+
u32 member_offset = member->offset;
1519+
u32 bytes_offset = BITS_ROUNDDOWN_BYTES(member_offset);
1520+
u8 bits8_offset = BITS_PER_BYTE_MASKED(member_offset);
1521+
const struct btf_kind_operations *ops;
1522+
1523+
if (i)
1524+
seq_puts(m, seq);
1525+
1526+
ops = btf_type_ops(member_type);
1527+
ops->seq_show(btf, member_type, member->type,
1528+
data + bytes_offset, bits8_offset, m);
1529+
}
1530+
seq_puts(m, "}");
1531+
}
1532+
13641533
static struct btf_kind_operations struct_ops = {
13651534
.check_meta = btf_struct_check_meta,
13661535
.resolve = btf_struct_resolve,
13671536
.check_member = btf_struct_check_member,
13681537
.log_details = btf_struct_log,
1538+
.seq_show = btf_struct_seq_show,
13691539
};
13701540

13711541
static int btf_enum_check_member(struct btf_verifier_env *env,
@@ -1441,11 +1611,31 @@ static void btf_enum_log(struct btf_verifier_env *env,
14411611
btf_verifier_log(env, "size=%u vlen=%u", t->size, btf_type_vlen(t));
14421612
}
14431613

1614+
static void btf_enum_seq_show(const struct btf *btf, const struct btf_type *t,
1615+
u32 type_id, void *data, u8 bits_offset,
1616+
struct seq_file *m)
1617+
{
1618+
const struct btf_enum *enums = btf_type_enum(t);
1619+
u32 i, nr_enums = btf_type_vlen(t);
1620+
int v = *(int *)data;
1621+
1622+
for (i = 0; i < nr_enums; i++) {
1623+
if (v == enums[i].val) {
1624+
seq_printf(m, "%s",
1625+
btf_name_by_offset(btf, enums[i].name));
1626+
return;
1627+
}
1628+
}
1629+
1630+
seq_printf(m, "%d", v);
1631+
}
1632+
14441633
static struct btf_kind_operations enum_ops = {
14451634
.check_meta = btf_enum_check_meta,
14461635
.resolve = btf_df_resolve,
14471636
.check_member = btf_enum_check_member,
14481637
.log_details = btf_enum_log,
1638+
.seq_show = btf_enum_seq_show,
14491639
};
14501640

14511641
static const struct btf_kind_operations * const kind_ops[NR_BTF_KINDS] = {
@@ -1782,3 +1972,11 @@ static struct btf *btf_parse(void __user *btf_data, u32 btf_data_size,
17821972
btf_free(btf);
17831973
return ERR_PTR(err);
17841974
}
1975+
1976+
void btf_type_seq_show(const struct btf *btf, u32 type_id, void *obj,
1977+
struct seq_file *m)
1978+
{
1979+
const struct btf_type *t = btf_type_by_id(btf, type_id);
1980+
1981+
btf_type_ops(t)->seq_show(btf, t, type_id, obj, 0, m);
1982+
}

0 commit comments

Comments
 (0)