All of lore.kernel.org
 help / color / mirror / Atom feed
From: Okash Khawaja <osk@fb.com>
To: Quentin Monnet <quentin.monnet@netronome.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>,
	Martin KaFai Lau <kafai@fb.com>,
	Alexei Starovoitov <ast@kernel.org>, Yonghong Song <yhs@fb.com>,
	Jakub Kicinski <jakub.kicinski@netronome.com>,
	"David S. Miller" <davem@davemloft.net>, <netdev@vger.kernel.org>,
	<kernel-team@fb.com>, <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH bpf-next 2/3] bpf: btf: add btf json print functionality
Date: Fri, 22 Jun 2018 11:24:29 +0100	[thread overview]
Message-ID: <20180622102428.GA3050@w1t1fb> (raw)
In-Reply-To: <3db6047a-101a-2ed1-9ca3-9e90b45ea00f@netronome.com>

On Thu, Jun 21, 2018 at 11:42:59AM +0100, Quentin Monnet wrote:
> Hi Okash,
hi and sorry about delay in responding. the email got routed to
incorrect folder.
> 
> 2018-06-20 13:30 UTC-0700 ~ Okash Khawaja <osk@fb.com>
> > 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 -p 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": 0x7ffff6f70568,
> 
> Hexadecimal values, without quotes, are not valid JSON. Please stick to
> decimal values.
ah sorry, i used a buggy json validator. this should be a quick fix.
which would be better:  pointers be output hex strings or integers?

> 
> >             "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>
> > 
> > ---
> >  tools/bpf/bpftool/btf_dumper.c |  247 +++++++++++++++++++++++++++++++++++++++++
> >  tools/bpf/bpftool/btf_dumper.h |   18 ++
> >  2 files changed, 265 insertions(+)
> > 
> > --- /dev/null
> > +++ b/tools/bpf/bpftool/btf_dumper.c
> > @@ -0,0 +1,247 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/* Copyright (c) 2018 Facebook */
> > +
> > +#include <linux/btf.h>
> > +#include <linux/err.h>
> > +#include <stdio.h> /* for (FILE *) used by json_writer */
> > +#include <linux/bitops.h>
> > +#include <string.h>
> > +#include <ctype.h>
> > +
> > +#include "btf.h"
> > +#include "json_writer.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 *btf, uint32_t type_id,
> > +		uint8_t bit_offset, const void *data, json_writer_t *jw);
> > +
> > +static void btf_dumper_ptr(const void *data, json_writer_t *jw)
> > +{
> > +	jsonw_printf(jw, "%p", *((uintptr_t *)data));
> > +}
> > +
> > +static int btf_dumper_modifier(const struct btf *btf, uint32_t type_id,
> > +		const void *data, json_writer_t *jw)
> > +{
> > +	int32_t actual_type_id = btf__resolve_type(btf, type_id);
> > +	int ret;
> > +
> > +	if (actual_type_id < 0)
> > +		return actual_type_id;
> > +
> > +	ret = btf_dumper_do_type(btf, actual_type_id, 0, data, jw);
> > +
> > +	return ret;
> > +}
> > +
> > +static void btf_dumper_enum(const void *data, json_writer_t *jw)
> > +{
> > +	jsonw_printf(jw, "%d", *((int32_t *)data));
> > +}
> > +
> > +static int btf_dumper_array(const struct btf *btf, uint32_t type_id,
> > +		const void *data, json_writer_t *jw)
> > +{
> > +	const struct btf_type *t = btf__type_by_id(btf, type_id);
> > +	struct btf_array *arr = (struct btf_array *)(t + 1);
> > +	int64_t elem_size;
> > +	uint32_t i;
> > +	int ret;
> > +
> > +	elem_size = btf__resolve_size(btf, arr->type);
> > +	if (elem_size < 0)
> > +		return elem_size;
> > +
> > +	jsonw_start_array(jw);
> > +	for (i = 0; i < arr->nelems; i++) {
> > +		ret = btf_dumper_do_type(btf, arr->type, 0,
> > +				data + (i * elem_size), jw);
> > +		if (ret)
> > +			return ret;
> > +	}
> > +
> > +	jsonw_end_array(jw);
> > +
> > +	return 0;
> > +}
> > +
> > +static void btf_dumper_int_bits(uint32_t int_type, uint8_t bit_offset,
> > +		const void *data, json_writer_t *jw)
> > +{
> > +	uint16_t total_bits_offset;
> > +	uint32_t bits = BTF_INT_BITS(int_type);
> 
> Nit: Please use reverse-Christmas-tree here.
> 
> As for patch 3 you also have a number of continuation lines not aligned
> on the opening parenthesis from the first line, throughout the patch
> (please consider running checkpatch in "--strict" mode for the list).
i didn't use "--strict". that would explain style mismatch. will fix
that in v2.

> 
> > +	uint16_t bytes_to_copy;
> > +	uint16_t bits_to_copy;
> > +	uint8_t upper_bits;
> > +	union {
> > +		uint64_t u64_num;
> > +		uint8_t u8_nums[8];
> > +	} print_num;
> > +
> > +	total_bits_offset = bit_offset + BTF_INT_OFFSET(int_type);
> > +	data += BITS_ROUNDDOWN_BYTES(total_bits_offset);
> > +	bit_offset = BITS_PER_BYTE_MASKED(total_bits_offset);
> > +	bits_to_copy = bits + bit_offset;
> > +	bytes_to_copy = BITS_ROUNDUP_BYTES(bits_to_copy);
> > +
> > +	print_num.u64_num = 0;
> > +	memcpy(&print_num.u64_num, data, bytes_to_copy);
> > +
> > +	upper_bits = BITS_PER_BYTE_MASKED(bits_to_copy);
> > +	if (upper_bits) {
> > +		uint8_t mask = (1 << upper_bits) - 1;
> > +
> > +		print_num.u8_nums[bytes_to_copy - 1] &= mask;
> > +	}
> > +
> > +	print_num.u64_num >>= bit_offset;
> > +
> > +	jsonw_printf(jw, "0x%llx", print_num.u64_num);
> > +}
> > +
> > +static int btf_dumper_int(const struct btf_type *t, uint8_t bit_offset,
> > +		const void *data, json_writer_t *jw)
> > +{
> > +	uint32_t *int_type = (uint32_t *)(t + 1);
> > +	uint32_t bits = BTF_INT_BITS(*int_type);
> > +	int ret = 0;
> > +
> > +	/* if this is bit field */
> > +	if (bit_offset || BTF_INT_OFFSET(*int_type) ||
> > +			BITS_PER_BYTE_MASKED(bits)) {
> > +		btf_dumper_int_bits(*int_type, bit_offset, data, jw);
> > +		return ret;
> > +	}
> > +
> > +	switch (BTF_INT_ENCODING(*int_type)) {
> > +	case 0:
> > +		if (BTF_INT_BITS(*int_type) == 64)
> > +			jsonw_printf(jw, "%lu", *((uint64_t *)data));
> > +		else if (BTF_INT_BITS(*int_type) == 32)
> > +			jsonw_printf(jw, "%u", *((uint32_t *)data));
> > +		else if (BTF_INT_BITS(*int_type) == 16)
> > +			jsonw_printf(jw, "%hu", *((uint16_t *)data));
> > +		else if (BTF_INT_BITS(*int_type) == 8)
> > +			jsonw_printf(jw, "%hhu", *((uint8_t *)data));
> > +		else
> > +			btf_dumper_int_bits(*int_type, bit_offset, data, jw);
> > +		break;
> > +	case BTF_INT_SIGNED:
> > +		if (BTF_INT_BITS(*int_type) == 64)
> > +			jsonw_printf(jw, "%ld", *((int64_t *)data));
> > +		else if (BTF_INT_BITS(*int_type) == 32)
> > +			jsonw_printf(jw, "%d", *((int32_t *)data));
> > +		else if (BTF_INT_BITS(*int_type) ==  16)
> > +			jsonw_printf(jw, "%hd", *((int16_t *)data));
> > +		else if (BTF_INT_BITS(*int_type) ==  8)
> > +			jsonw_printf(jw, "%hhd", *((int8_t *)data));
> > +		else
> > +			btf_dumper_int_bits(*int_type, bit_offset, data, jw);
> > +		break;
> > +	case BTF_INT_CHAR:
> > +		if (*((char *)data) == '\0')
> > +			jsonw_null(jw);
> > +		else if (isprint(*((char *)data)))
> > +			jsonw_printf(jw, "\"%c\"", *((char *)data));
> > +		else
> > +			jsonw_printf(jw, "%hhx", *((char *)data));
> > +		break;
> > +	case BTF_INT_BOOL:
> > +		jsonw_bool(jw, *((int *)data));
> > +		break;
> > +	default:
> > +		/* shouldn't happen */
> > +		ret = -EINVAL;
> > +		break;
> > +	}
> > +
> > +	return ret;
> > +}
> > +
> > +static int btf_dumper_struct(const struct btf *btf, uint32_t type_id,
> > +		const void *data, json_writer_t *jw)
> > +{
> > +	const struct btf_type *t = btf__type_by_id(btf, type_id);
> > +	struct btf_member *m;
> > +	int ret = 0;
> > +	int i, vlen;
> > +
> > +	if (t == NULL)
> > +		return -EINVAL;
> > +
> > +	vlen = BTF_INFO_VLEN(t->info);
> > +	jsonw_start_object(jw);
> > +	m = (struct btf_member *)(t + 1);
> > +
> > +	for (i = 0; i < vlen; i++) {
> > +		jsonw_name(jw, btf__name_by_offset(btf, m[i].name_off));
> > +		ret = btf_dumper_do_type(btf, m[i].type,
> > +				BITS_PER_BYTE_MASKED(m[i].offset),
> > +				data + BITS_ROUNDDOWN_BYTES(m[i].offset), jw);
> > +		if (ret)
> > +			return ret;
> > +	}
> > +
> > +	jsonw_end_object(jw);
> > +
> > +	return 0;
> > +}
> > +
> > +static int btf_dumper_do_type(const struct btf *btf, uint32_t type_id,
> > +		uint8_t bit_offset, const void *data, json_writer_t *jw)
> > +{
> > +	const struct btf_type *t = btf__type_by_id(btf, type_id);
> > +	int ret = 0;
> > +
> > +	switch (BTF_INFO_KIND(t->info)) {
> > +	case BTF_KIND_INT:
> > +		ret = btf_dumper_int(t, bit_offset, data, jw);
> > +		break;
> > +	case BTF_KIND_STRUCT:
> > +	case BTF_KIND_UNION:
> > +		ret = btf_dumper_struct(btf, type_id, data, jw);
> > +		break;
> > +	case BTF_KIND_ARRAY:
> > +		ret = btf_dumper_array(btf, type_id, data, jw);
> > +		break;
> > +	case BTF_KIND_ENUM:
> > +		btf_dumper_enum(data, jw);
> > +		break;
> > +	case BTF_KIND_PTR:
> > +		btf_dumper_ptr(data, jw);
> > +		break;
> > +	case BTF_KIND_UNKN:
> > +		jsonw_printf(jw, "(unknown)");
> > +		break;
> > +	case BTF_KIND_FWD:
> > +		/* map key or value can't be forward */
> > +		ret = -EINVAL;
> > +		break;
> > +	case BTF_KIND_TYPEDEF:
> > +	case BTF_KIND_VOLATILE:
> > +	case BTF_KIND_CONST:
> > +	case BTF_KIND_RESTRICT:
> > +		ret = btf_dumper_modifier(btf, type_id, data, jw);
> > +		break;
> > +	default:
> > +		jsonw_printf(jw, "(unsupported-kind");
> > +		ret = -EINVAL;
> > +		break;
> > +	}
> > +
> > +	return ret;
> > +}
> > +
> > +int32_t btf_dumper_type(const struct btf *btf, json_writer_t *jw,
> > +		uint32_t type_id, const void *data)
> > +{
> > +	if (!jw)
> > +		return -EINVAL;
> > +
> > +	return btf_dumper_do_type(btf, type_id, 0, data, jw);
> > +}
> > --- /dev/null
> > +++ b/tools/bpf/bpftool/btf_dumper.h
> > @@ -0,0 +1,18 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> 
> I believe SPDX tag in header files should use C++ style comments (//)?
okay i will verify and fix that.

> 
> > +/* Copyright (c) 2018 Facebook */
> > +
> > +#ifndef BTF_DUMPER_H
> > +#define BTF_DUMPER_H
> > +
> > +/* btf_dumper_type - json print data along with type information
> > + * @btf: btf instance initialised via btf__new()
> > + * @jw: json writer used for printing
> > + * @type_id: index in btf->types array. this points to the type to be dumped
> > + * @data: pointer the actual data, i.e. the values to be printed
> > + *
> > + * Returns zero on success and negative error code otherwise
> > + */
> > +int32_t btf_dumper_type(const struct btf *btf, json_writer_t *jw,
> > +		uint32_t type_id, void *data);
> > +
> > +#endif
> > 
> 
> Thanks,
> Quentin

  reply	other threads:[~2018-06-22 10:25 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-06-20 20:30 [PATCH bpf-next 0/3] bpf: btf: json print btf info with bpftool map dump Okash Khawaja
2018-06-20 20:30 ` [PATCH bpf-next 1/3] bpf: btf: export btf types and name by offset from lib Okash Khawaja
2018-06-20 22:40   ` Song Liu
2018-06-20 22:48     ` Okash Khawaja
2018-06-20 23:24       ` Song Liu
2018-06-20 20:30 ` [PATCH bpf-next 2/3] bpf: btf: add btf json print functionality Okash Khawaja
2018-06-20 23:14   ` Song Liu
2018-06-21 10:31     ` Okash Khawaja
2018-06-21 10:42   ` Quentin Monnet
2018-06-22 10:24     ` Okash Khawaja [this message]
2018-06-22 10:39       ` Quentin Monnet
2018-06-22 18:44         ` Jakub Kicinski
2018-06-21 21:59   ` Jakub Kicinski
2018-06-21 22:51     ` Martin KaFai Lau
2018-06-21 23:07       ` Jakub Kicinski
2018-06-21 23:58         ` Martin KaFai Lau
2018-06-22  0:25           ` Jakub Kicinski
2018-06-22  1:20             ` Martin KaFai Lau
2018-06-22 11:17               ` Okash Khawaja
2018-06-22 18:43                 ` Jakub Kicinski
2018-06-22 18:40               ` Jakub Kicinski
2018-06-22 20:58                 ` Martin KaFai Lau
2018-06-22 21:27                   ` Jakub Kicinski
2018-06-22 21:49                     ` Jakub Kicinski
2018-06-22 23:19                       ` Martin KaFai Lau
2018-06-22 23:40                         ` Jakub Kicinski
2018-06-22 23:58                           ` Martin KaFai Lau
2018-06-22 22:48                     ` Okash Khawaja
2018-06-22 22:54                     ` Martin KaFai Lau
2018-06-22 23:32                       ` Jakub Kicinski
2018-06-23  0:26                         ` Martin KaFai Lau
2018-06-26 16:48                           ` Okash Khawaja
2018-06-26 20:31                             ` Jakub Kicinski
2018-06-26 22:27                               ` Martin KaFai Lau
2018-06-26 22:35                                 ` Jakub Kicinski
2018-06-27 10:34                                   ` Daniel Borkmann
2018-06-27 11:47                                     ` Okash Khawaja
2018-06-27 12:56                                       ` Daniel Borkmann
2018-07-01 10:31                                         ` Okash Khawaja
2018-07-02 17:19                                           ` Jakub Kicinski
2018-06-20 20:30 ` [PATCH bpf-next 3/3] bpf: btf: json print map dump with btf info Okash Khawaja
2018-06-20 23:22   ` Song Liu
2018-06-21 10:05     ` Okash Khawaja
2018-06-21 10:24   ` Quentin Monnet
2018-06-21 14:26     ` Okash Khawaja

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180622102428.GA3050@w1t1fb \
    --to=osk@fb.com \
    --cc=ast@kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=davem@davemloft.net \
    --cc=jakub.kicinski@netronome.com \
    --cc=kafai@fb.com \
    --cc=kernel-team@fb.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=quentin.monnet@netronome.com \
    --cc=yhs@fb.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.