2018-12-13 10:59:26 +07:00
|
|
|
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
bpf: btf: add btf print functionality
This consumes functionality exported in the previous patch. It does the
main job of printing with BTF data. This is used in the following patch
to provide a more readable output of a map's dump. It relies on
json_writer to do json printing. Below is sample output where map keys
are ints and values are of type struct A:
typedef int int_type;
enum E {
E0,
E1,
};
struct B {
int x;
int y;
};
struct A {
int m;
unsigned long long n;
char o;
int p[8];
int q[4][8];
enum E r;
void *s;
struct B t;
const int u;
int_type v;
unsigned int w1: 3;
unsigned int w2: 3;
};
$ sudo bpftool map dump id 14
[{
"key": 0,
"value": {
"m": 1,
"n": 2,
"o": "c",
"p": [15,16,17,18,15,16,17,18
],
"q": [[25,26,27,28,25,26,27,28
],[35,36,37,38,35,36,37,38
],[45,46,47,48,45,46,47,48
],[55,56,57,58,55,56,57,58
]
],
"r": 1,
"s": 0x7ffd80531cf8,
"t": {
"x": 5,
"y": 10
},
"u": 100,
"v": 20,
"w1": 0x7,
"w2": 0x3
}
}
]
This patch uses json's {} and [] to imply struct/union and array. More
explicit information can be added later. For example, a command line
option can be introduced to print whether a key or value is struct
or union, name of a struct etc. This will however come at the expense
of duplicating info when, for example, printing an array of structs.
enums are printed as ints without their names.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 11:57:03 +07:00
|
|
|
/* Copyright (c) 2018 Facebook */
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdio.h> /* for (FILE *) used by json_writer */
|
|
|
|
#include <string.h>
|
|
|
|
#include <asm/byteorder.h>
|
|
|
|
#include <linux/bitops.h>
|
|
|
|
#include <linux/btf.h>
|
|
|
|
#include <linux/err.h>
|
|
|
|
|
|
|
|
#include "btf.h"
|
|
|
|
#include "json_writer.h"
|
|
|
|
#include "main.h"
|
|
|
|
|
|
|
|
#define BITS_PER_BYTE_MASK (BITS_PER_BYTE - 1)
|
|
|
|
#define BITS_PER_BYTE_MASKED(bits) ((bits) & BITS_PER_BYTE_MASK)
|
|
|
|
#define BITS_ROUNDDOWN_BYTES(bits) ((bits) >> 3)
|
|
|
|
#define BITS_ROUNDUP_BYTES(bits) \
|
|
|
|
(BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits))
|
|
|
|
|
|
|
|
static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id,
|
|
|
|
__u8 bit_offset, const void *data);
|
|
|
|
|
|
|
|
static void btf_dumper_ptr(const void *data, json_writer_t *jw,
|
|
|
|
bool is_plain_text)
|
|
|
|
{
|
|
|
|
if (is_plain_text)
|
|
|
|
jsonw_printf(jw, "%p", *(unsigned long *)data);
|
|
|
|
else
|
|
|
|
jsonw_printf(jw, "%u", *(unsigned long *)data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int btf_dumper_modifier(const struct btf_dumper *d, __u32 type_id,
|
tools: bpftool: fix a bitfield pretty print issue
Commit b12d6ec09730 ("bpf: btf: add btf print functionality")
added btf pretty print functionality to bpftool.
There is a problem though in printing a bitfield whose type
has modifiers.
For example, for a type like
typedef int ___int;
struct tmp_t {
int a:3;
___int b:3;
};
Suppose we have a map
struct bpf_map_def SEC("maps") tmpmap = {
.type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(__u32),
.value_size = sizeof(struct tmp_t),
.max_entries = 1,
};
and the hash table is populated with one element with
key 0 and value (.a = 1 and .b = 2).
In BTF, the struct member "b" will have a type "typedef" which
points to an int type. The current implementation does not
pass the bit offset during transition from typedef to int type,
hence incorrectly print the value as
$ bpftool m d id 79
[{
"key": 0,
"value": {
"a": 0x1,
"b": 0x1
}
}
]
This patch fixed the issue by carrying bit_offset along the type
chain during bit_field print. The correct result can be printed as
$ bpftool m d id 76
[{
"key": 0,
"value": {
"a": 0x1,
"b": 0x2
}
}
]
The kernel pretty print is implemented correctly and does not
have this issue.
Fixes: b12d6ec09730 ("bpf: btf: add btf print functionality")
Signed-off-by: Yonghong Song <yhs@fb.com>
Acked-by: Song Liu <songliubraving@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-11-29 00:38:23 +07:00
|
|
|
__u8 bit_offset, const void *data)
|
bpf: btf: add btf print functionality
This consumes functionality exported in the previous patch. It does the
main job of printing with BTF data. This is used in the following patch
to provide a more readable output of a map's dump. It relies on
json_writer to do json printing. Below is sample output where map keys
are ints and values are of type struct A:
typedef int int_type;
enum E {
E0,
E1,
};
struct B {
int x;
int y;
};
struct A {
int m;
unsigned long long n;
char o;
int p[8];
int q[4][8];
enum E r;
void *s;
struct B t;
const int u;
int_type v;
unsigned int w1: 3;
unsigned int w2: 3;
};
$ sudo bpftool map dump id 14
[{
"key": 0,
"value": {
"m": 1,
"n": 2,
"o": "c",
"p": [15,16,17,18,15,16,17,18
],
"q": [[25,26,27,28,25,26,27,28
],[35,36,37,38,35,36,37,38
],[45,46,47,48,45,46,47,48
],[55,56,57,58,55,56,57,58
]
],
"r": 1,
"s": 0x7ffd80531cf8,
"t": {
"x": 5,
"y": 10
},
"u": 100,
"v": 20,
"w1": 0x7,
"w2": 0x3
}
}
]
This patch uses json's {} and [] to imply struct/union and array. More
explicit information can be added later. For example, a command line
option can be introduced to print whether a key or value is struct
or union, name of a struct etc. This will however come at the expense
of duplicating info when, for example, printing an array of structs.
enums are printed as ints without their names.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 11:57:03 +07:00
|
|
|
{
|
|
|
|
int actual_type_id;
|
|
|
|
|
|
|
|
actual_type_id = btf__resolve_type(d->btf, type_id);
|
|
|
|
if (actual_type_id < 0)
|
|
|
|
return actual_type_id;
|
|
|
|
|
tools: bpftool: fix a bitfield pretty print issue
Commit b12d6ec09730 ("bpf: btf: add btf print functionality")
added btf pretty print functionality to bpftool.
There is a problem though in printing a bitfield whose type
has modifiers.
For example, for a type like
typedef int ___int;
struct tmp_t {
int a:3;
___int b:3;
};
Suppose we have a map
struct bpf_map_def SEC("maps") tmpmap = {
.type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(__u32),
.value_size = sizeof(struct tmp_t),
.max_entries = 1,
};
and the hash table is populated with one element with
key 0 and value (.a = 1 and .b = 2).
In BTF, the struct member "b" will have a type "typedef" which
points to an int type. The current implementation does not
pass the bit offset during transition from typedef to int type,
hence incorrectly print the value as
$ bpftool m d id 79
[{
"key": 0,
"value": {
"a": 0x1,
"b": 0x1
}
}
]
This patch fixed the issue by carrying bit_offset along the type
chain during bit_field print. The correct result can be printed as
$ bpftool m d id 76
[{
"key": 0,
"value": {
"a": 0x1,
"b": 0x2
}
}
]
The kernel pretty print is implemented correctly and does not
have this issue.
Fixes: b12d6ec09730 ("bpf: btf: add btf print functionality")
Signed-off-by: Yonghong Song <yhs@fb.com>
Acked-by: Song Liu <songliubraving@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-11-29 00:38:23 +07:00
|
|
|
return btf_dumper_do_type(d, actual_type_id, bit_offset, data);
|
bpf: btf: add btf print functionality
This consumes functionality exported in the previous patch. It does the
main job of printing with BTF data. This is used in the following patch
to provide a more readable output of a map's dump. It relies on
json_writer to do json printing. Below is sample output where map keys
are ints and values are of type struct A:
typedef int int_type;
enum E {
E0,
E1,
};
struct B {
int x;
int y;
};
struct A {
int m;
unsigned long long n;
char o;
int p[8];
int q[4][8];
enum E r;
void *s;
struct B t;
const int u;
int_type v;
unsigned int w1: 3;
unsigned int w2: 3;
};
$ sudo bpftool map dump id 14
[{
"key": 0,
"value": {
"m": 1,
"n": 2,
"o": "c",
"p": [15,16,17,18,15,16,17,18
],
"q": [[25,26,27,28,25,26,27,28
],[35,36,37,38,35,36,37,38
],[45,46,47,48,45,46,47,48
],[55,56,57,58,55,56,57,58
]
],
"r": 1,
"s": 0x7ffd80531cf8,
"t": {
"x": 5,
"y": 10
},
"u": 100,
"v": 20,
"w1": 0x7,
"w2": 0x3
}
}
]
This patch uses json's {} and [] to imply struct/union and array. More
explicit information can be added later. For example, a command line
option can be introduced to print whether a key or value is struct
or union, name of a struct etc. This will however come at the expense
of duplicating info when, for example, printing an array of structs.
enums are printed as ints without their names.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 11:57:03 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void btf_dumper_enum(const void *data, json_writer_t *jw)
|
|
|
|
{
|
|
|
|
jsonw_printf(jw, "%d", *(int *)data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int btf_dumper_array(const struct btf_dumper *d, __u32 type_id,
|
|
|
|
const void *data)
|
|
|
|
{
|
|
|
|
const struct btf_type *t = btf__type_by_id(d->btf, type_id);
|
|
|
|
struct btf_array *arr = (struct btf_array *)(t + 1);
|
|
|
|
long long elem_size;
|
|
|
|
int ret = 0;
|
|
|
|
__u32 i;
|
|
|
|
|
|
|
|
elem_size = btf__resolve_size(d->btf, arr->type);
|
|
|
|
if (elem_size < 0)
|
|
|
|
return elem_size;
|
|
|
|
|
|
|
|
jsonw_start_array(d->jw);
|
|
|
|
for (i = 0; i < arr->nelems; i++) {
|
|
|
|
ret = btf_dumper_do_type(d, arr->type, 0,
|
|
|
|
data + i * elem_size);
|
|
|
|
if (ret)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
jsonw_end_array(d->jw);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-12-16 13:13:57 +07:00
|
|
|
static void btf_dumper_bitfield(__u32 nr_bits, __u8 bit_offset,
|
bpf: btf: add btf print functionality
This consumes functionality exported in the previous patch. It does the
main job of printing with BTF data. This is used in the following patch
to provide a more readable output of a map's dump. It relies on
json_writer to do json printing. Below is sample output where map keys
are ints and values are of type struct A:
typedef int int_type;
enum E {
E0,
E1,
};
struct B {
int x;
int y;
};
struct A {
int m;
unsigned long long n;
char o;
int p[8];
int q[4][8];
enum E r;
void *s;
struct B t;
const int u;
int_type v;
unsigned int w1: 3;
unsigned int w2: 3;
};
$ sudo bpftool map dump id 14
[{
"key": 0,
"value": {
"m": 1,
"n": 2,
"o": "c",
"p": [15,16,17,18,15,16,17,18
],
"q": [[25,26,27,28,25,26,27,28
],[35,36,37,38,35,36,37,38
],[45,46,47,48,45,46,47,48
],[55,56,57,58,55,56,57,58
]
],
"r": 1,
"s": 0x7ffd80531cf8,
"t": {
"x": 5,
"y": 10
},
"u": 100,
"v": 20,
"w1": 0x7,
"w2": 0x3
}
}
]
This patch uses json's {} and [] to imply struct/union and array. More
explicit information can be added later. For example, a command line
option can be introduced to print whether a key or value is struct
or union, name of a struct etc. This will however come at the expense
of duplicating info when, for example, printing an array of structs.
enums are printed as ints without their names.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 11:57:03 +07:00
|
|
|
const void *data, json_writer_t *jw,
|
|
|
|
bool is_plain_text)
|
|
|
|
{
|
|
|
|
int left_shift_bits, right_shift_bits;
|
|
|
|
int bytes_to_copy;
|
|
|
|
int bits_to_copy;
|
|
|
|
__u64 print_num;
|
|
|
|
|
|
|
|
bits_to_copy = bit_offset + nr_bits;
|
|
|
|
bytes_to_copy = BITS_ROUNDUP_BYTES(bits_to_copy);
|
|
|
|
|
|
|
|
print_num = 0;
|
|
|
|
memcpy(&print_num, data, bytes_to_copy);
|
|
|
|
#if defined(__BIG_ENDIAN_BITFIELD)
|
|
|
|
left_shift_bits = bit_offset;
|
|
|
|
#elif defined(__LITTLE_ENDIAN_BITFIELD)
|
|
|
|
left_shift_bits = 64 - bits_to_copy;
|
|
|
|
#else
|
|
|
|
#error neither big nor little endian
|
|
|
|
#endif
|
|
|
|
right_shift_bits = 64 - nr_bits;
|
|
|
|
|
|
|
|
print_num <<= left_shift_bits;
|
|
|
|
print_num >>= right_shift_bits;
|
|
|
|
if (is_plain_text)
|
|
|
|
jsonw_printf(jw, "0x%llx", print_num);
|
|
|
|
else
|
|
|
|
jsonw_printf(jw, "%llu", print_num);
|
|
|
|
}
|
|
|
|
|
2018-12-16 13:13:57 +07:00
|
|
|
|
|
|
|
static void btf_dumper_int_bits(__u32 int_type, __u8 bit_offset,
|
|
|
|
const void *data, json_writer_t *jw,
|
|
|
|
bool is_plain_text)
|
|
|
|
{
|
|
|
|
int nr_bits = BTF_INT_BITS(int_type);
|
|
|
|
int total_bits_offset;
|
|
|
|
|
|
|
|
/* bits_offset is at most 7.
|
|
|
|
* BTF_INT_OFFSET() cannot exceed 64 bits.
|
|
|
|
*/
|
|
|
|
total_bits_offset = bit_offset + BTF_INT_OFFSET(int_type);
|
2019-01-11 02:14:02 +07:00
|
|
|
data += BITS_ROUNDDOWN_BYTES(total_bits_offset);
|
|
|
|
bit_offset = BITS_PER_BYTE_MASKED(total_bits_offset);
|
|
|
|
btf_dumper_bitfield(nr_bits, bit_offset, data, jw,
|
2018-12-16 13:13:57 +07:00
|
|
|
is_plain_text);
|
|
|
|
}
|
|
|
|
|
bpf: btf: add btf print functionality
This consumes functionality exported in the previous patch. It does the
main job of printing with BTF data. This is used in the following patch
to provide a more readable output of a map's dump. It relies on
json_writer to do json printing. Below is sample output where map keys
are ints and values are of type struct A:
typedef int int_type;
enum E {
E0,
E1,
};
struct B {
int x;
int y;
};
struct A {
int m;
unsigned long long n;
char o;
int p[8];
int q[4][8];
enum E r;
void *s;
struct B t;
const int u;
int_type v;
unsigned int w1: 3;
unsigned int w2: 3;
};
$ sudo bpftool map dump id 14
[{
"key": 0,
"value": {
"m": 1,
"n": 2,
"o": "c",
"p": [15,16,17,18,15,16,17,18
],
"q": [[25,26,27,28,25,26,27,28
],[35,36,37,38,35,36,37,38
],[45,46,47,48,45,46,47,48
],[55,56,57,58,55,56,57,58
]
],
"r": 1,
"s": 0x7ffd80531cf8,
"t": {
"x": 5,
"y": 10
},
"u": 100,
"v": 20,
"w1": 0x7,
"w2": 0x3
}
}
]
This patch uses json's {} and [] to imply struct/union and array. More
explicit information can be added later. For example, a command line
option can be introduced to print whether a key or value is struct
or union, name of a struct etc. This will however come at the expense
of duplicating info when, for example, printing an array of structs.
enums are printed as ints without their names.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 11:57:03 +07:00
|
|
|
static int btf_dumper_int(const struct btf_type *t, __u8 bit_offset,
|
|
|
|
const void *data, json_writer_t *jw,
|
|
|
|
bool is_plain_text)
|
|
|
|
{
|
|
|
|
__u32 *int_type;
|
|
|
|
__u32 nr_bits;
|
|
|
|
|
|
|
|
int_type = (__u32 *)(t + 1);
|
|
|
|
nr_bits = BTF_INT_BITS(*int_type);
|
|
|
|
/* if this is bit field */
|
|
|
|
if (bit_offset || BTF_INT_OFFSET(*int_type) ||
|
|
|
|
BITS_PER_BYTE_MASKED(nr_bits)) {
|
|
|
|
btf_dumper_int_bits(*int_type, bit_offset, data, jw,
|
|
|
|
is_plain_text);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (BTF_INT_ENCODING(*int_type)) {
|
|
|
|
case 0:
|
|
|
|
if (BTF_INT_BITS(*int_type) == 64)
|
|
|
|
jsonw_printf(jw, "%lu", *(__u64 *)data);
|
|
|
|
else if (BTF_INT_BITS(*int_type) == 32)
|
|
|
|
jsonw_printf(jw, "%u", *(__u32 *)data);
|
|
|
|
else if (BTF_INT_BITS(*int_type) == 16)
|
|
|
|
jsonw_printf(jw, "%hu", *(__u16 *)data);
|
|
|
|
else if (BTF_INT_BITS(*int_type) == 8)
|
|
|
|
jsonw_printf(jw, "%hhu", *(__u8 *)data);
|
|
|
|
else
|
|
|
|
btf_dumper_int_bits(*int_type, bit_offset, data, jw,
|
|
|
|
is_plain_text);
|
|
|
|
break;
|
|
|
|
case BTF_INT_SIGNED:
|
|
|
|
if (BTF_INT_BITS(*int_type) == 64)
|
|
|
|
jsonw_printf(jw, "%ld", *(long long *)data);
|
|
|
|
else if (BTF_INT_BITS(*int_type) == 32)
|
|
|
|
jsonw_printf(jw, "%d", *(int *)data);
|
|
|
|
else if (BTF_INT_BITS(*int_type) == 16)
|
|
|
|
jsonw_printf(jw, "%hd", *(short *)data);
|
|
|
|
else if (BTF_INT_BITS(*int_type) == 8)
|
|
|
|
jsonw_printf(jw, "%hhd", *(char *)data);
|
|
|
|
else
|
|
|
|
btf_dumper_int_bits(*int_type, bit_offset, data, jw,
|
|
|
|
is_plain_text);
|
|
|
|
break;
|
|
|
|
case BTF_INT_CHAR:
|
|
|
|
if (isprint(*(char *)data))
|
|
|
|
jsonw_printf(jw, "\"%c\"", *(char *)data);
|
|
|
|
else
|
|
|
|
if (is_plain_text)
|
|
|
|
jsonw_printf(jw, "0x%hhx", *(char *)data);
|
|
|
|
else
|
|
|
|
jsonw_printf(jw, "\"\\u00%02hhx\"",
|
|
|
|
*(char *)data);
|
|
|
|
break;
|
|
|
|
case BTF_INT_BOOL:
|
|
|
|
jsonw_bool(jw, *(int *)data);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* shouldn't happen */
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int btf_dumper_struct(const struct btf_dumper *d, __u32 type_id,
|
|
|
|
const void *data)
|
|
|
|
{
|
|
|
|
const struct btf_type *t;
|
|
|
|
struct btf_member *m;
|
|
|
|
const void *data_off;
|
tools: bpftool: support pretty print with kind_flag set
The following example shows map pretty print with structures
which include bitfield members.
enum A { A1, A2, A3, A4, A5 };
typedef enum A ___A;
struct tmp_t {
char a1:4;
int a2:4;
int :4;
__u32 a3:4;
int b;
___A b1:4;
enum A b2:4;
};
struct bpf_map_def SEC("maps") tmpmap = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(struct tmp_t),
.max_entries = 1,
};
BPF_ANNOTATE_KV_PAIR(tmpmap, int, struct tmp_t);
and the following map update in the bpf program:
key = 0;
struct tmp_t t = {};
t.a1 = 2;
t.a2 = 4;
t.a3 = 6;
t.b = 7;
t.b1 = 8;
t.b2 = 10;
bpf_map_update_elem(&tmpmap, &key, &t, 0);
With this patch, I am able to print out the map values
correctly with this patch:
bpftool map dump id 187
[{
"key": 0,
"value": {
"a1": 0x2,
"a2": 0x4,
"a3": 0x6,
"b": 7,
"b1": 0x8,
"b2": 0xa
}
}
]
Previously, if a function prototype argument has a typedef
type, the prototype is not printed since
function __btf_dumper_type_only() bailed out with error
if the type is a typedef. This commit corrected this
behavior by printing out typedef properly.
The following example shows forward type and
typedef type can be properly printed in function prototype
with modified test_btf_haskv.c.
struct t;
union u;
__attribute__((noinline))
static int test_long_fname_1(struct dummy_tracepoint_args *arg,
struct t *p1, union u *p2,
__u32 unused)
...
int _dummy_tracepoint(struct dummy_tracepoint_args *arg) {
return test_long_fname_1(arg, 0, 0, 0);
}
$ bpftool p d xlated id 24
...
int test_long_fname_1(struct dummy_tracepoint_args * arg,
struct t * p1, union u * p2,
__u32 unused)
...
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-12-16 13:13:58 +07:00
|
|
|
int kind_flag;
|
bpf: btf: add btf print functionality
This consumes functionality exported in the previous patch. It does the
main job of printing with BTF data. This is used in the following patch
to provide a more readable output of a map's dump. It relies on
json_writer to do json printing. Below is sample output where map keys
are ints and values are of type struct A:
typedef int int_type;
enum E {
E0,
E1,
};
struct B {
int x;
int y;
};
struct A {
int m;
unsigned long long n;
char o;
int p[8];
int q[4][8];
enum E r;
void *s;
struct B t;
const int u;
int_type v;
unsigned int w1: 3;
unsigned int w2: 3;
};
$ sudo bpftool map dump id 14
[{
"key": 0,
"value": {
"m": 1,
"n": 2,
"o": "c",
"p": [15,16,17,18,15,16,17,18
],
"q": [[25,26,27,28,25,26,27,28
],[35,36,37,38,35,36,37,38
],[45,46,47,48,45,46,47,48
],[55,56,57,58,55,56,57,58
]
],
"r": 1,
"s": 0x7ffd80531cf8,
"t": {
"x": 5,
"y": 10
},
"u": 100,
"v": 20,
"w1": 0x7,
"w2": 0x3
}
}
]
This patch uses json's {} and [] to imply struct/union and array. More
explicit information can be added later. For example, a command line
option can be introduced to print whether a key or value is struct
or union, name of a struct etc. This will however come at the expense
of duplicating info when, for example, printing an array of structs.
enums are printed as ints without their names.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 11:57:03 +07:00
|
|
|
int ret = 0;
|
|
|
|
int i, vlen;
|
|
|
|
|
|
|
|
t = btf__type_by_id(d->btf, type_id);
|
|
|
|
if (!t)
|
|
|
|
return -EINVAL;
|
|
|
|
|
tools: bpftool: support pretty print with kind_flag set
The following example shows map pretty print with structures
which include bitfield members.
enum A { A1, A2, A3, A4, A5 };
typedef enum A ___A;
struct tmp_t {
char a1:4;
int a2:4;
int :4;
__u32 a3:4;
int b;
___A b1:4;
enum A b2:4;
};
struct bpf_map_def SEC("maps") tmpmap = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(struct tmp_t),
.max_entries = 1,
};
BPF_ANNOTATE_KV_PAIR(tmpmap, int, struct tmp_t);
and the following map update in the bpf program:
key = 0;
struct tmp_t t = {};
t.a1 = 2;
t.a2 = 4;
t.a3 = 6;
t.b = 7;
t.b1 = 8;
t.b2 = 10;
bpf_map_update_elem(&tmpmap, &key, &t, 0);
With this patch, I am able to print out the map values
correctly with this patch:
bpftool map dump id 187
[{
"key": 0,
"value": {
"a1": 0x2,
"a2": 0x4,
"a3": 0x6,
"b": 7,
"b1": 0x8,
"b2": 0xa
}
}
]
Previously, if a function prototype argument has a typedef
type, the prototype is not printed since
function __btf_dumper_type_only() bailed out with error
if the type is a typedef. This commit corrected this
behavior by printing out typedef properly.
The following example shows forward type and
typedef type can be properly printed in function prototype
with modified test_btf_haskv.c.
struct t;
union u;
__attribute__((noinline))
static int test_long_fname_1(struct dummy_tracepoint_args *arg,
struct t *p1, union u *p2,
__u32 unused)
...
int _dummy_tracepoint(struct dummy_tracepoint_args *arg) {
return test_long_fname_1(arg, 0, 0, 0);
}
$ bpftool p d xlated id 24
...
int test_long_fname_1(struct dummy_tracepoint_args * arg,
struct t * p1, union u * p2,
__u32 unused)
...
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-12-16 13:13:58 +07:00
|
|
|
kind_flag = BTF_INFO_KFLAG(t->info);
|
bpf: btf: add btf print functionality
This consumes functionality exported in the previous patch. It does the
main job of printing with BTF data. This is used in the following patch
to provide a more readable output of a map's dump. It relies on
json_writer to do json printing. Below is sample output where map keys
are ints and values are of type struct A:
typedef int int_type;
enum E {
E0,
E1,
};
struct B {
int x;
int y;
};
struct A {
int m;
unsigned long long n;
char o;
int p[8];
int q[4][8];
enum E r;
void *s;
struct B t;
const int u;
int_type v;
unsigned int w1: 3;
unsigned int w2: 3;
};
$ sudo bpftool map dump id 14
[{
"key": 0,
"value": {
"m": 1,
"n": 2,
"o": "c",
"p": [15,16,17,18,15,16,17,18
],
"q": [[25,26,27,28,25,26,27,28
],[35,36,37,38,35,36,37,38
],[45,46,47,48,45,46,47,48
],[55,56,57,58,55,56,57,58
]
],
"r": 1,
"s": 0x7ffd80531cf8,
"t": {
"x": 5,
"y": 10
},
"u": 100,
"v": 20,
"w1": 0x7,
"w2": 0x3
}
}
]
This patch uses json's {} and [] to imply struct/union and array. More
explicit information can be added later. For example, a command line
option can be introduced to print whether a key or value is struct
or union, name of a struct etc. This will however come at the expense
of duplicating info when, for example, printing an array of structs.
enums are printed as ints without their names.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 11:57:03 +07:00
|
|
|
vlen = BTF_INFO_VLEN(t->info);
|
|
|
|
jsonw_start_object(d->jw);
|
|
|
|
m = (struct btf_member *)(t + 1);
|
|
|
|
|
|
|
|
for (i = 0; i < vlen; i++) {
|
tools: bpftool: support pretty print with kind_flag set
The following example shows map pretty print with structures
which include bitfield members.
enum A { A1, A2, A3, A4, A5 };
typedef enum A ___A;
struct tmp_t {
char a1:4;
int a2:4;
int :4;
__u32 a3:4;
int b;
___A b1:4;
enum A b2:4;
};
struct bpf_map_def SEC("maps") tmpmap = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(struct tmp_t),
.max_entries = 1,
};
BPF_ANNOTATE_KV_PAIR(tmpmap, int, struct tmp_t);
and the following map update in the bpf program:
key = 0;
struct tmp_t t = {};
t.a1 = 2;
t.a2 = 4;
t.a3 = 6;
t.b = 7;
t.b1 = 8;
t.b2 = 10;
bpf_map_update_elem(&tmpmap, &key, &t, 0);
With this patch, I am able to print out the map values
correctly with this patch:
bpftool map dump id 187
[{
"key": 0,
"value": {
"a1": 0x2,
"a2": 0x4,
"a3": 0x6,
"b": 7,
"b1": 0x8,
"b2": 0xa
}
}
]
Previously, if a function prototype argument has a typedef
type, the prototype is not printed since
function __btf_dumper_type_only() bailed out with error
if the type is a typedef. This commit corrected this
behavior by printing out typedef properly.
The following example shows forward type and
typedef type can be properly printed in function prototype
with modified test_btf_haskv.c.
struct t;
union u;
__attribute__((noinline))
static int test_long_fname_1(struct dummy_tracepoint_args *arg,
struct t *p1, union u *p2,
__u32 unused)
...
int _dummy_tracepoint(struct dummy_tracepoint_args *arg) {
return test_long_fname_1(arg, 0, 0, 0);
}
$ bpftool p d xlated id 24
...
int test_long_fname_1(struct dummy_tracepoint_args * arg,
struct t * p1, union u * p2,
__u32 unused)
...
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-12-16 13:13:58 +07:00
|
|
|
__u32 bit_offset = m[i].offset;
|
|
|
|
__u32 bitfield_size = 0;
|
|
|
|
|
|
|
|
if (kind_flag) {
|
|
|
|
bitfield_size = BTF_MEMBER_BITFIELD_SIZE(bit_offset);
|
|
|
|
bit_offset = BTF_MEMBER_BIT_OFFSET(bit_offset);
|
|
|
|
}
|
|
|
|
|
bpf: btf: add btf print functionality
This consumes functionality exported in the previous patch. It does the
main job of printing with BTF data. This is used in the following patch
to provide a more readable output of a map's dump. It relies on
json_writer to do json printing. Below is sample output where map keys
are ints and values are of type struct A:
typedef int int_type;
enum E {
E0,
E1,
};
struct B {
int x;
int y;
};
struct A {
int m;
unsigned long long n;
char o;
int p[8];
int q[4][8];
enum E r;
void *s;
struct B t;
const int u;
int_type v;
unsigned int w1: 3;
unsigned int w2: 3;
};
$ sudo bpftool map dump id 14
[{
"key": 0,
"value": {
"m": 1,
"n": 2,
"o": "c",
"p": [15,16,17,18,15,16,17,18
],
"q": [[25,26,27,28,25,26,27,28
],[35,36,37,38,35,36,37,38
],[45,46,47,48,45,46,47,48
],[55,56,57,58,55,56,57,58
]
],
"r": 1,
"s": 0x7ffd80531cf8,
"t": {
"x": 5,
"y": 10
},
"u": 100,
"v": 20,
"w1": 0x7,
"w2": 0x3
}
}
]
This patch uses json's {} and [] to imply struct/union and array. More
explicit information can be added later. For example, a command line
option can be introduced to print whether a key or value is struct
or union, name of a struct etc. This will however come at the expense
of duplicating info when, for example, printing an array of structs.
enums are printed as ints without their names.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 11:57:03 +07:00
|
|
|
jsonw_name(d->jw, btf__name_by_offset(d->btf, m[i].name_off));
|
2019-01-11 02:14:02 +07:00
|
|
|
data_off = data + BITS_ROUNDDOWN_BYTES(bit_offset);
|
tools: bpftool: support pretty print with kind_flag set
The following example shows map pretty print with structures
which include bitfield members.
enum A { A1, A2, A3, A4, A5 };
typedef enum A ___A;
struct tmp_t {
char a1:4;
int a2:4;
int :4;
__u32 a3:4;
int b;
___A b1:4;
enum A b2:4;
};
struct bpf_map_def SEC("maps") tmpmap = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(struct tmp_t),
.max_entries = 1,
};
BPF_ANNOTATE_KV_PAIR(tmpmap, int, struct tmp_t);
and the following map update in the bpf program:
key = 0;
struct tmp_t t = {};
t.a1 = 2;
t.a2 = 4;
t.a3 = 6;
t.b = 7;
t.b1 = 8;
t.b2 = 10;
bpf_map_update_elem(&tmpmap, &key, &t, 0);
With this patch, I am able to print out the map values
correctly with this patch:
bpftool map dump id 187
[{
"key": 0,
"value": {
"a1": 0x2,
"a2": 0x4,
"a3": 0x6,
"b": 7,
"b1": 0x8,
"b2": 0xa
}
}
]
Previously, if a function prototype argument has a typedef
type, the prototype is not printed since
function __btf_dumper_type_only() bailed out with error
if the type is a typedef. This commit corrected this
behavior by printing out typedef properly.
The following example shows forward type and
typedef type can be properly printed in function prototype
with modified test_btf_haskv.c.
struct t;
union u;
__attribute__((noinline))
static int test_long_fname_1(struct dummy_tracepoint_args *arg,
struct t *p1, union u *p2,
__u32 unused)
...
int _dummy_tracepoint(struct dummy_tracepoint_args *arg) {
return test_long_fname_1(arg, 0, 0, 0);
}
$ bpftool p d xlated id 24
...
int test_long_fname_1(struct dummy_tracepoint_args * arg,
struct t * p1, union u * p2,
__u32 unused)
...
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-12-16 13:13:58 +07:00
|
|
|
if (bitfield_size) {
|
2019-01-11 02:14:02 +07:00
|
|
|
btf_dumper_bitfield(bitfield_size,
|
|
|
|
BITS_PER_BYTE_MASKED(bit_offset),
|
|
|
|
data_off, d->jw, d->is_plain_text);
|
tools: bpftool: support pretty print with kind_flag set
The following example shows map pretty print with structures
which include bitfield members.
enum A { A1, A2, A3, A4, A5 };
typedef enum A ___A;
struct tmp_t {
char a1:4;
int a2:4;
int :4;
__u32 a3:4;
int b;
___A b1:4;
enum A b2:4;
};
struct bpf_map_def SEC("maps") tmpmap = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(struct tmp_t),
.max_entries = 1,
};
BPF_ANNOTATE_KV_PAIR(tmpmap, int, struct tmp_t);
and the following map update in the bpf program:
key = 0;
struct tmp_t t = {};
t.a1 = 2;
t.a2 = 4;
t.a3 = 6;
t.b = 7;
t.b1 = 8;
t.b2 = 10;
bpf_map_update_elem(&tmpmap, &key, &t, 0);
With this patch, I am able to print out the map values
correctly with this patch:
bpftool map dump id 187
[{
"key": 0,
"value": {
"a1": 0x2,
"a2": 0x4,
"a3": 0x6,
"b": 7,
"b1": 0x8,
"b2": 0xa
}
}
]
Previously, if a function prototype argument has a typedef
type, the prototype is not printed since
function __btf_dumper_type_only() bailed out with error
if the type is a typedef. This commit corrected this
behavior by printing out typedef properly.
The following example shows forward type and
typedef type can be properly printed in function prototype
with modified test_btf_haskv.c.
struct t;
union u;
__attribute__((noinline))
static int test_long_fname_1(struct dummy_tracepoint_args *arg,
struct t *p1, union u *p2,
__u32 unused)
...
int _dummy_tracepoint(struct dummy_tracepoint_args *arg) {
return test_long_fname_1(arg, 0, 0, 0);
}
$ bpftool p d xlated id 24
...
int test_long_fname_1(struct dummy_tracepoint_args * arg,
struct t * p1, union u * p2,
__u32 unused)
...
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-12-16 13:13:58 +07:00
|
|
|
} else {
|
|
|
|
ret = btf_dumper_do_type(d, m[i].type,
|
|
|
|
BITS_PER_BYTE_MASKED(bit_offset),
|
|
|
|
data_off);
|
|
|
|
if (ret)
|
|
|
|
break;
|
|
|
|
}
|
bpf: btf: add btf print functionality
This consumes functionality exported in the previous patch. It does the
main job of printing with BTF data. This is used in the following patch
to provide a more readable output of a map's dump. It relies on
json_writer to do json printing. Below is sample output where map keys
are ints and values are of type struct A:
typedef int int_type;
enum E {
E0,
E1,
};
struct B {
int x;
int y;
};
struct A {
int m;
unsigned long long n;
char o;
int p[8];
int q[4][8];
enum E r;
void *s;
struct B t;
const int u;
int_type v;
unsigned int w1: 3;
unsigned int w2: 3;
};
$ sudo bpftool map dump id 14
[{
"key": 0,
"value": {
"m": 1,
"n": 2,
"o": "c",
"p": [15,16,17,18,15,16,17,18
],
"q": [[25,26,27,28,25,26,27,28
],[35,36,37,38,35,36,37,38
],[45,46,47,48,45,46,47,48
],[55,56,57,58,55,56,57,58
]
],
"r": 1,
"s": 0x7ffd80531cf8,
"t": {
"x": 5,
"y": 10
},
"u": 100,
"v": 20,
"w1": 0x7,
"w2": 0x3
}
}
]
This patch uses json's {} and [] to imply struct/union and array. More
explicit information can be added later. For example, a command line
option can be introduced to print whether a key or value is struct
or union, name of a struct etc. This will however come at the expense
of duplicating info when, for example, printing an array of structs.
enums are printed as ints without their names.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 11:57:03 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
jsonw_end_object(d->jw);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id,
|
|
|
|
__u8 bit_offset, const void *data)
|
|
|
|
{
|
|
|
|
const struct btf_type *t = btf__type_by_id(d->btf, type_id);
|
|
|
|
|
|
|
|
switch (BTF_INFO_KIND(t->info)) {
|
|
|
|
case BTF_KIND_INT:
|
|
|
|
return btf_dumper_int(t, bit_offset, data, d->jw,
|
|
|
|
d->is_plain_text);
|
|
|
|
case BTF_KIND_STRUCT:
|
|
|
|
case BTF_KIND_UNION:
|
|
|
|
return btf_dumper_struct(d, type_id, data);
|
|
|
|
case BTF_KIND_ARRAY:
|
|
|
|
return btf_dumper_array(d, type_id, data);
|
|
|
|
case BTF_KIND_ENUM:
|
|
|
|
btf_dumper_enum(data, d->jw);
|
|
|
|
return 0;
|
|
|
|
case BTF_KIND_PTR:
|
|
|
|
btf_dumper_ptr(data, d->jw, d->is_plain_text);
|
|
|
|
return 0;
|
|
|
|
case BTF_KIND_UNKN:
|
|
|
|
jsonw_printf(d->jw, "(unknown)");
|
|
|
|
return 0;
|
|
|
|
case BTF_KIND_FWD:
|
|
|
|
/* map key or value can't be forward */
|
|
|
|
jsonw_printf(d->jw, "(fwd-kind-invalid)");
|
|
|
|
return -EINVAL;
|
|
|
|
case BTF_KIND_TYPEDEF:
|
|
|
|
case BTF_KIND_VOLATILE:
|
|
|
|
case BTF_KIND_CONST:
|
|
|
|
case BTF_KIND_RESTRICT:
|
tools: bpftool: fix a bitfield pretty print issue
Commit b12d6ec09730 ("bpf: btf: add btf print functionality")
added btf pretty print functionality to bpftool.
There is a problem though in printing a bitfield whose type
has modifiers.
For example, for a type like
typedef int ___int;
struct tmp_t {
int a:3;
___int b:3;
};
Suppose we have a map
struct bpf_map_def SEC("maps") tmpmap = {
.type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(__u32),
.value_size = sizeof(struct tmp_t),
.max_entries = 1,
};
and the hash table is populated with one element with
key 0 and value (.a = 1 and .b = 2).
In BTF, the struct member "b" will have a type "typedef" which
points to an int type. The current implementation does not
pass the bit offset during transition from typedef to int type,
hence incorrectly print the value as
$ bpftool m d id 79
[{
"key": 0,
"value": {
"a": 0x1,
"b": 0x1
}
}
]
This patch fixed the issue by carrying bit_offset along the type
chain during bit_field print. The correct result can be printed as
$ bpftool m d id 76
[{
"key": 0,
"value": {
"a": 0x1,
"b": 0x2
}
}
]
The kernel pretty print is implemented correctly and does not
have this issue.
Fixes: b12d6ec09730 ("bpf: btf: add btf print functionality")
Signed-off-by: Yonghong Song <yhs@fb.com>
Acked-by: Song Liu <songliubraving@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-11-29 00:38:23 +07:00
|
|
|
return btf_dumper_modifier(d, type_id, bit_offset, data);
|
bpf: btf: add btf print functionality
This consumes functionality exported in the previous patch. It does the
main job of printing with BTF data. This is used in the following patch
to provide a more readable output of a map's dump. It relies on
json_writer to do json printing. Below is sample output where map keys
are ints and values are of type struct A:
typedef int int_type;
enum E {
E0,
E1,
};
struct B {
int x;
int y;
};
struct A {
int m;
unsigned long long n;
char o;
int p[8];
int q[4][8];
enum E r;
void *s;
struct B t;
const int u;
int_type v;
unsigned int w1: 3;
unsigned int w2: 3;
};
$ sudo bpftool map dump id 14
[{
"key": 0,
"value": {
"m": 1,
"n": 2,
"o": "c",
"p": [15,16,17,18,15,16,17,18
],
"q": [[25,26,27,28,25,26,27,28
],[35,36,37,38,35,36,37,38
],[45,46,47,48,45,46,47,48
],[55,56,57,58,55,56,57,58
]
],
"r": 1,
"s": 0x7ffd80531cf8,
"t": {
"x": 5,
"y": 10
},
"u": 100,
"v": 20,
"w1": 0x7,
"w2": 0x3
}
}
]
This patch uses json's {} and [] to imply struct/union and array. More
explicit information can be added later. For example, a command line
option can be introduced to print whether a key or value is struct
or union, name of a struct etc. This will however come at the expense
of duplicating info when, for example, printing an array of structs.
enums are printed as ints without their names.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 11:57:03 +07:00
|
|
|
default:
|
|
|
|
jsonw_printf(d->jw, "(unsupported-kind");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int btf_dumper_type(const struct btf_dumper *d, __u32 type_id,
|
|
|
|
const void *data)
|
|
|
|
{
|
|
|
|
return btf_dumper_do_type(d, type_id, 0, data);
|
|
|
|
}
|
2018-11-20 06:29:21 +07:00
|
|
|
|
|
|
|
#define BTF_PRINT_ARG(...) \
|
|
|
|
do { \
|
|
|
|
pos += snprintf(func_sig + pos, size - pos, \
|
|
|
|
__VA_ARGS__); \
|
|
|
|
if (pos >= size) \
|
|
|
|
return -1; \
|
|
|
|
} while (0)
|
|
|
|
#define BTF_PRINT_TYPE(type) \
|
|
|
|
do { \
|
|
|
|
pos = __btf_dumper_type_only(btf, type, func_sig, \
|
|
|
|
pos, size); \
|
|
|
|
if (pos == -1) \
|
|
|
|
return -1; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
static int btf_dump_func(const struct btf *btf, char *func_sig,
|
|
|
|
const struct btf_type *func_proto,
|
|
|
|
const struct btf_type *func, int pos, int size);
|
|
|
|
|
|
|
|
static int __btf_dumper_type_only(const struct btf *btf, __u32 type_id,
|
|
|
|
char *func_sig, int pos, int size)
|
|
|
|
{
|
|
|
|
const struct btf_type *proto_type;
|
|
|
|
const struct btf_array *array;
|
|
|
|
const struct btf_type *t;
|
|
|
|
|
|
|
|
if (!type_id) {
|
|
|
|
BTF_PRINT_ARG("void ");
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
t = btf__type_by_id(btf, type_id);
|
|
|
|
|
|
|
|
switch (BTF_INFO_KIND(t->info)) {
|
|
|
|
case BTF_KIND_INT:
|
tools: bpftool: support pretty print with kind_flag set
The following example shows map pretty print with structures
which include bitfield members.
enum A { A1, A2, A3, A4, A5 };
typedef enum A ___A;
struct tmp_t {
char a1:4;
int a2:4;
int :4;
__u32 a3:4;
int b;
___A b1:4;
enum A b2:4;
};
struct bpf_map_def SEC("maps") tmpmap = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(struct tmp_t),
.max_entries = 1,
};
BPF_ANNOTATE_KV_PAIR(tmpmap, int, struct tmp_t);
and the following map update in the bpf program:
key = 0;
struct tmp_t t = {};
t.a1 = 2;
t.a2 = 4;
t.a3 = 6;
t.b = 7;
t.b1 = 8;
t.b2 = 10;
bpf_map_update_elem(&tmpmap, &key, &t, 0);
With this patch, I am able to print out the map values
correctly with this patch:
bpftool map dump id 187
[{
"key": 0,
"value": {
"a1": 0x2,
"a2": 0x4,
"a3": 0x6,
"b": 7,
"b1": 0x8,
"b2": 0xa
}
}
]
Previously, if a function prototype argument has a typedef
type, the prototype is not printed since
function __btf_dumper_type_only() bailed out with error
if the type is a typedef. This commit corrected this
behavior by printing out typedef properly.
The following example shows forward type and
typedef type can be properly printed in function prototype
with modified test_btf_haskv.c.
struct t;
union u;
__attribute__((noinline))
static int test_long_fname_1(struct dummy_tracepoint_args *arg,
struct t *p1, union u *p2,
__u32 unused)
...
int _dummy_tracepoint(struct dummy_tracepoint_args *arg) {
return test_long_fname_1(arg, 0, 0, 0);
}
$ bpftool p d xlated id 24
...
int test_long_fname_1(struct dummy_tracepoint_args * arg,
struct t * p1, union u * p2,
__u32 unused)
...
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-12-16 13:13:58 +07:00
|
|
|
case BTF_KIND_TYPEDEF:
|
2018-11-20 06:29:21 +07:00
|
|
|
BTF_PRINT_ARG("%s ", btf__name_by_offset(btf, t->name_off));
|
|
|
|
break;
|
|
|
|
case BTF_KIND_STRUCT:
|
|
|
|
BTF_PRINT_ARG("struct %s ",
|
|
|
|
btf__name_by_offset(btf, t->name_off));
|
|
|
|
break;
|
|
|
|
case BTF_KIND_UNION:
|
|
|
|
BTF_PRINT_ARG("union %s ",
|
|
|
|
btf__name_by_offset(btf, t->name_off));
|
|
|
|
break;
|
|
|
|
case BTF_KIND_ENUM:
|
|
|
|
BTF_PRINT_ARG("enum %s ",
|
|
|
|
btf__name_by_offset(btf, t->name_off));
|
|
|
|
break;
|
|
|
|
case BTF_KIND_ARRAY:
|
|
|
|
array = (struct btf_array *)(t + 1);
|
|
|
|
BTF_PRINT_TYPE(array->type);
|
|
|
|
BTF_PRINT_ARG("[%d]", array->nelems);
|
|
|
|
break;
|
|
|
|
case BTF_KIND_PTR:
|
|
|
|
BTF_PRINT_TYPE(t->type);
|
|
|
|
BTF_PRINT_ARG("* ");
|
|
|
|
break;
|
|
|
|
case BTF_KIND_FWD:
|
tools: bpftool: support pretty print with kind_flag set
The following example shows map pretty print with structures
which include bitfield members.
enum A { A1, A2, A3, A4, A5 };
typedef enum A ___A;
struct tmp_t {
char a1:4;
int a2:4;
int :4;
__u32 a3:4;
int b;
___A b1:4;
enum A b2:4;
};
struct bpf_map_def SEC("maps") tmpmap = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(struct tmp_t),
.max_entries = 1,
};
BPF_ANNOTATE_KV_PAIR(tmpmap, int, struct tmp_t);
and the following map update in the bpf program:
key = 0;
struct tmp_t t = {};
t.a1 = 2;
t.a2 = 4;
t.a3 = 6;
t.b = 7;
t.b1 = 8;
t.b2 = 10;
bpf_map_update_elem(&tmpmap, &key, &t, 0);
With this patch, I am able to print out the map values
correctly with this patch:
bpftool map dump id 187
[{
"key": 0,
"value": {
"a1": 0x2,
"a2": 0x4,
"a3": 0x6,
"b": 7,
"b1": 0x8,
"b2": 0xa
}
}
]
Previously, if a function prototype argument has a typedef
type, the prototype is not printed since
function __btf_dumper_type_only() bailed out with error
if the type is a typedef. This commit corrected this
behavior by printing out typedef properly.
The following example shows forward type and
typedef type can be properly printed in function prototype
with modified test_btf_haskv.c.
struct t;
union u;
__attribute__((noinline))
static int test_long_fname_1(struct dummy_tracepoint_args *arg,
struct t *p1, union u *p2,
__u32 unused)
...
int _dummy_tracepoint(struct dummy_tracepoint_args *arg) {
return test_long_fname_1(arg, 0, 0, 0);
}
$ bpftool p d xlated id 24
...
int test_long_fname_1(struct dummy_tracepoint_args * arg,
struct t * p1, union u * p2,
__u32 unused)
...
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-12-16 13:13:58 +07:00
|
|
|
BTF_PRINT_ARG("%s %s ",
|
|
|
|
BTF_INFO_KFLAG(t->info) ? "union" : "struct",
|
|
|
|
btf__name_by_offset(btf, t->name_off));
|
|
|
|
break;
|
2018-11-20 06:29:21 +07:00
|
|
|
case BTF_KIND_VOLATILE:
|
|
|
|
BTF_PRINT_ARG("volatile ");
|
|
|
|
BTF_PRINT_TYPE(t->type);
|
|
|
|
break;
|
|
|
|
case BTF_KIND_CONST:
|
|
|
|
BTF_PRINT_ARG("const ");
|
|
|
|
BTF_PRINT_TYPE(t->type);
|
|
|
|
break;
|
|
|
|
case BTF_KIND_RESTRICT:
|
|
|
|
BTF_PRINT_ARG("restrict ");
|
|
|
|
BTF_PRINT_TYPE(t->type);
|
|
|
|
break;
|
|
|
|
case BTF_KIND_FUNC_PROTO:
|
|
|
|
pos = btf_dump_func(btf, func_sig, t, NULL, pos, size);
|
|
|
|
if (pos == -1)
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
case BTF_KIND_FUNC:
|
|
|
|
proto_type = btf__type_by_id(btf, t->type);
|
|
|
|
pos = btf_dump_func(btf, func_sig, proto_type, t, pos, size);
|
|
|
|
if (pos == -1)
|
|
|
|
return -1;
|
|
|
|
break;
|
tools: bpftool: support pretty print with kind_flag set
The following example shows map pretty print with structures
which include bitfield members.
enum A { A1, A2, A3, A4, A5 };
typedef enum A ___A;
struct tmp_t {
char a1:4;
int a2:4;
int :4;
__u32 a3:4;
int b;
___A b1:4;
enum A b2:4;
};
struct bpf_map_def SEC("maps") tmpmap = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(struct tmp_t),
.max_entries = 1,
};
BPF_ANNOTATE_KV_PAIR(tmpmap, int, struct tmp_t);
and the following map update in the bpf program:
key = 0;
struct tmp_t t = {};
t.a1 = 2;
t.a2 = 4;
t.a3 = 6;
t.b = 7;
t.b1 = 8;
t.b2 = 10;
bpf_map_update_elem(&tmpmap, &key, &t, 0);
With this patch, I am able to print out the map values
correctly with this patch:
bpftool map dump id 187
[{
"key": 0,
"value": {
"a1": 0x2,
"a2": 0x4,
"a3": 0x6,
"b": 7,
"b1": 0x8,
"b2": 0xa
}
}
]
Previously, if a function prototype argument has a typedef
type, the prototype is not printed since
function __btf_dumper_type_only() bailed out with error
if the type is a typedef. This commit corrected this
behavior by printing out typedef properly.
The following example shows forward type and
typedef type can be properly printed in function prototype
with modified test_btf_haskv.c.
struct t;
union u;
__attribute__((noinline))
static int test_long_fname_1(struct dummy_tracepoint_args *arg,
struct t *p1, union u *p2,
__u32 unused)
...
int _dummy_tracepoint(struct dummy_tracepoint_args *arg) {
return test_long_fname_1(arg, 0, 0, 0);
}
$ bpftool p d xlated id 24
...
int test_long_fname_1(struct dummy_tracepoint_args * arg,
struct t * p1, union u * p2,
__u32 unused)
...
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-12-16 13:13:58 +07:00
|
|
|
case BTF_KIND_UNKN:
|
2018-11-20 06:29:21 +07:00
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int btf_dump_func(const struct btf *btf, char *func_sig,
|
|
|
|
const struct btf_type *func_proto,
|
|
|
|
const struct btf_type *func, int pos, int size)
|
|
|
|
{
|
|
|
|
int i, vlen;
|
|
|
|
|
|
|
|
BTF_PRINT_TYPE(func_proto->type);
|
|
|
|
if (func)
|
|
|
|
BTF_PRINT_ARG("%s(", btf__name_by_offset(btf, func->name_off));
|
|
|
|
else
|
|
|
|
BTF_PRINT_ARG("(");
|
|
|
|
vlen = BTF_INFO_VLEN(func_proto->info);
|
|
|
|
for (i = 0; i < vlen; i++) {
|
|
|
|
struct btf_param *arg = &((struct btf_param *)(func_proto + 1))[i];
|
|
|
|
|
|
|
|
if (i)
|
|
|
|
BTF_PRINT_ARG(", ");
|
|
|
|
if (arg->type) {
|
|
|
|
BTF_PRINT_TYPE(arg->type);
|
|
|
|
BTF_PRINT_ARG("%s",
|
|
|
|
btf__name_by_offset(btf, arg->name_off));
|
|
|
|
} else {
|
|
|
|
BTF_PRINT_ARG("...");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BTF_PRINT_ARG(")");
|
|
|
|
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
void btf_dumper_type_only(const struct btf *btf, __u32 type_id, char *func_sig,
|
|
|
|
int size)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
func_sig[0] = '\0';
|
|
|
|
if (!btf)
|
|
|
|
return;
|
|
|
|
|
|
|
|
err = __btf_dumper_type_only(btf, type_id, func_sig, 0, size);
|
|
|
|
if (err < 0)
|
|
|
|
func_sig[0] = '\0';
|
|
|
|
}
|
bpf: libbpf: bpftool: Print bpf_line_info during prog dump
This patch adds print bpf_line_info function in 'prog dump jitted'
and 'prog dump xlated':
[root@arch-fb-vm1 bpf]# ~/devshare/fb-kernel/linux/tools/bpf/bpftool/bpftool prog dump jited pinned /sys/fs/bpf/test_btf_haskv
[...]
int test_long_fname_2(struct dummy_tracepoint_args * arg):
bpf_prog_44a040bf25481309_test_long_fname_2:
; static int test_long_fname_2(struct dummy_tracepoint_args *arg)
0: push %rbp
1: mov %rsp,%rbp
4: sub $0x30,%rsp
b: sub $0x28,%rbp
f: mov %rbx,0x0(%rbp)
13: mov %r13,0x8(%rbp)
17: mov %r14,0x10(%rbp)
1b: mov %r15,0x18(%rbp)
1f: xor %eax,%eax
21: mov %rax,0x20(%rbp)
25: xor %esi,%esi
; int key = 0;
27: mov %esi,-0x4(%rbp)
; if (!arg->sock)
2a: mov 0x8(%rdi),%rdi
; if (!arg->sock)
2e: cmp $0x0,%rdi
32: je 0x0000000000000070
34: mov %rbp,%rsi
; counts = bpf_map_lookup_elem(&btf_map, &key);
37: add $0xfffffffffffffffc,%rsi
3b: movabs $0xffff8881139d7480,%rdi
45: add $0x110,%rdi
4c: mov 0x0(%rsi),%eax
4f: cmp $0x4,%rax
53: jae 0x000000000000005e
55: shl $0x3,%rax
59: add %rdi,%rax
5c: jmp 0x0000000000000060
5e: xor %eax,%eax
; if (!counts)
60: cmp $0x0,%rax
64: je 0x0000000000000070
; counts->v6++;
66: mov 0x4(%rax),%edi
69: add $0x1,%rdi
6d: mov %edi,0x4(%rax)
70: mov 0x0(%rbp),%rbx
74: mov 0x8(%rbp),%r13
78: mov 0x10(%rbp),%r14
7c: mov 0x18(%rbp),%r15
80: add $0x28,%rbp
84: leaveq
85: retq
[...]
With linum:
[root@arch-fb-vm1 bpf]# ~/devshare/fb-kernel/linux/tools/bpf/bpftool/bpftool prog dump jited pinned /sys/fs/bpf/test_btf_haskv linum
int _dummy_tracepoint(struct dummy_tracepoint_args * arg):
bpf_prog_b07ccb89267cf242__dummy_tracepoint:
; return test_long_fname_1(arg); [file:/data/users/kafai/fb-kernel/linux/tools/testing/selftests/bpf/test_btf_haskv.c line_num:54 line_col:9]
0: push %rbp
1: mov %rsp,%rbp
4: sub $0x28,%rsp
b: sub $0x28,%rbp
f: mov %rbx,0x0(%rbp)
13: mov %r13,0x8(%rbp)
17: mov %r14,0x10(%rbp)
1b: mov %r15,0x18(%rbp)
1f: xor %eax,%eax
21: mov %rax,0x20(%rbp)
25: callq 0x000000000000851e
; return test_long_fname_1(arg); [file:/data/users/kafai/fb-kernel/linux/tools/testing/selftests/bpf/test_btf_haskv.c line_num:54 line_col:2]
2a: xor %eax,%eax
2c: mov 0x0(%rbp),%rbx
30: mov 0x8(%rbp),%r13
34: mov 0x10(%rbp),%r14
38: mov 0x18(%rbp),%r15
3c: add $0x28,%rbp
40: leaveq
41: retq
[...]
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Acked-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-12-08 07:42:32 +07:00
|
|
|
|
|
|
|
static const char *ltrim(const char *s)
|
|
|
|
{
|
|
|
|
while (isspace(*s))
|
|
|
|
s++;
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
void btf_dump_linfo_plain(const struct btf *btf,
|
|
|
|
const struct bpf_line_info *linfo,
|
|
|
|
const char *prefix, bool linum)
|
|
|
|
{
|
|
|
|
const char *line = btf__name_by_offset(btf, linfo->line_off);
|
|
|
|
|
|
|
|
if (!line)
|
|
|
|
return;
|
|
|
|
line = ltrim(line);
|
|
|
|
|
|
|
|
if (!prefix)
|
|
|
|
prefix = "";
|
|
|
|
|
|
|
|
if (linum) {
|
|
|
|
const char *file = btf__name_by_offset(btf, linfo->file_name_off);
|
|
|
|
|
|
|
|
/* More forgiving on file because linum option is
|
|
|
|
* expected to provide more info than the already
|
|
|
|
* available src line.
|
|
|
|
*/
|
|
|
|
if (!file)
|
|
|
|
file = "";
|
|
|
|
|
|
|
|
printf("%s%s [file:%s line_num:%u line_col:%u]\n",
|
|
|
|
prefix, line, file,
|
|
|
|
BPF_LINE_INFO_LINE_NUM(linfo->line_col),
|
|
|
|
BPF_LINE_INFO_LINE_COL(linfo->line_col));
|
|
|
|
} else {
|
|
|
|
printf("%s%s\n", prefix, line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void btf_dump_linfo_json(const struct btf *btf,
|
|
|
|
const struct bpf_line_info *linfo, bool linum)
|
|
|
|
{
|
|
|
|
const char *line = btf__name_by_offset(btf, linfo->line_off);
|
|
|
|
|
|
|
|
if (line)
|
|
|
|
jsonw_string_field(json_wtr, "src", ltrim(line));
|
|
|
|
|
|
|
|
if (linum) {
|
|
|
|
const char *file = btf__name_by_offset(btf, linfo->file_name_off);
|
|
|
|
|
|
|
|
if (file)
|
|
|
|
jsonw_string_field(json_wtr, "file", file);
|
|
|
|
|
|
|
|
if (BPF_LINE_INFO_LINE_NUM(linfo->line_col))
|
|
|
|
jsonw_int_field(json_wtr, "line_num",
|
|
|
|
BPF_LINE_INFO_LINE_NUM(linfo->line_col));
|
|
|
|
|
|
|
|
if (BPF_LINE_INFO_LINE_COL(linfo->line_col))
|
|
|
|
jsonw_int_field(json_wtr, "line_col",
|
|
|
|
BPF_LINE_INFO_LINE_COL(linfo->line_col));
|
|
|
|
}
|
|
|
|
}
|