From: Andrey Ignatov <rdna@fb.com>
To: Quentin Monnet <quentin@isovalent.com>
Cc: <bpf@vger.kernel.org>, <ast@kernel.org>, <daniel@iogearbox.net>,
<osandov@fb.com>, <kernel-team@fb.com>
Subject: Re: [PATCH bpf-next] bpf: Add drgn script to list progs/maps
Date: Fri, 28 Feb 2020 12:15:14 -0800 [thread overview]
Message-ID: <20200228201514.GB51456@rdna-mbp> (raw)
In-Reply-To: <42af50cc-acde-d7a9-19da-8e2fb87bce48@isovalent.com>
Quentin Monnet <quentin@isovalent.com> [Fri, 2020-02-28 04:51 -0800]:
> 2020-02-26 18:32 UTC-0800 ~ Andrey Ignatov <rdna@fb.com>
> > drgn is a debugger that reads kernel memory and uses DWARF to get types
> > and symbols. See [1], [2] and [3] for more details on drgn.
> >
> > Since drgn operates on kernel memory it has access to kernel internals
> > that user space doesn't. It allows to get extended info about various
> > kernel data structures.
> >
> > Introduce bpf.py drgn script to list BPF programs and maps and their
> > properties unavailable to user space via kernel API.
> >
> > The main use-case bpf.py covers is to show BPF programs attached to
> > other BPF programs via freplace/fentry/fexit mechanisms introduced
> > recently. There is no user-space API to get this info and e.g. bpftool
> > can only show all BPF programs but can't show if program A replaces a
> > function in program B.
> >
>
> [...]
>
> >
> > Signed-off-by: Andrey Ignatov <rdna@fb.com>
> > ---
> > tools/bpf/bpf.py | 149 +++++++++++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 149 insertions(+)
> > create mode 100755 tools/bpf/bpf.py
> >
> > diff --git a/tools/bpf/bpf.py b/tools/bpf/bpf.py
> > new file mode 100755
> > index 000000000000..a00d112c0486
> > --- /dev/null
> > +++ b/tools/bpf/bpf.py
> > @@ -0,0 +1,149 @@
> > +#!/usr/bin/env drgn
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +#
> > +# Copyright (c) 2020 Facebook
> > +
> > +DESCRIPTION = """
> > +drgn script to list BPF programs or maps and their properties
> > +unavailable via kernel API.
> > +
> > +See https://github.com/osandov/drgn/ for more details on drgn.
> > +"""
> > +
> > +import argparse
> > +import sys
> > +
> > +from drgn.helpers import enum_type_to_class
> > +from drgn.helpers.linux import (
> > + bpf_map_for_each,
> > + bpf_prog_for_each,
> > + hlist_for_each_entry,
> > +)
> > +
> > +
> > +BpfMapType = enum_type_to_class(prog.type("enum bpf_map_type"), "BpfMapType")
> > +BpfProgType = enum_type_to_class(prog.type("enum bpf_prog_type"), "BpfProgType")
> > +BpfProgTrampType = enum_type_to_class(
> > + prog.type("enum bpf_tramp_prog_type"), "BpfProgTrampType"
> > +)
> > +BpfAttachType = enum_type_to_class(
> > + prog.type("enum bpf_attach_type"), "BpfAttachType"
> > +)
>
> Hi Andrey, the script looks neat, thanks for this work!
>
> I tried to run it on my system. Because my kernel is 5.3 and does not have
> "enum bpf_tramp_prog_type", the script crashes on the above assignments. But
> even without that enum, it could be possible to print program and map ids
> and types (even if we don't show the trampolines).
>
> Do you think it would be worth adding error handling on that block,
> something like:
>
> try:
> BpfMapType = ...
> BpfProgType = ...
> BpfProgTrampType = ...
> BpfAttachType = ...
> except LookupError as e:
> print(e) # Possibly add a hint as kernel being too old?
>
> I understand that printing the BPF extensions is the main interest of the
> script, I'm just thinking it would be nice to use it / tweak it even if not
> on the latest kernel. What do you think?
Hi Quentin,
Thanks for feedback. That's a nice usability improvement indeed.
I'll add something like this and tag you on the github PR (since we're
coming to the conclusion that drgn repo is a better place for it).
> > +
> > +
> > +def get_btf_name(btf, btf_id):
> > + type_ = btf.types[btf_id]
> > + if type_.name_off < btf.hdr.str_len:
> > + return btf.strings[type_.name_off].address_of_().string_().decode()
> > + return ""
> > +
> > +
> > +def get_prog_btf_name(bpf_prog):
> > + aux = bpf_prog.aux
> > + if aux.btf:
> > + # func_info[0] points to BPF program function itself.
> > + return get_btf_name(aux.btf, aux.func_info[0].type_id)
> > + return ""
> > +
> > +
> > +def get_prog_name(bpf_prog):
> > + return get_prog_btf_name(bpf_prog) or bpf_prog.aux.name.string_().decode()
> > +
> > +
> > +def attach_type_to_tramp(attach_type):
> > + at = BpfAttachType(attach_type)
> > +
> > + if at == BpfAttachType.BPF_TRACE_FENTRY:
> > + return BpfProgTrampType.BPF_TRAMP_FENTRY
> > +
> > + if at == BpfAttachType.BPF_TRACE_FEXIT:
> > + return BpfProgTrampType.BPF_TRAMP_FEXIT
> > +
> > + return BpfProgTrampType.BPF_TRAMP_REPLACE
> > +
> > +
> > +def get_linked_func(bpf_prog):
> > + kind = attach_type_to_tramp(bpf_prog.expected_attach_type)
> > +
> > + linked_prog = bpf_prog.aux.linked_prog
> > + linked_btf_id = bpf_prog.aux.attach_btf_id
> > +
> > + linked_prog_id = linked_prog.aux.id.value_()
> > + linked_name = "{}->{}()".format(
> > + get_prog_name(linked_prog),
> > + get_btf_name(linked_prog.aux.btf, linked_btf_id),
> > + )
> > +
> > + return "{}->{}: {} {}".format(
> > + linked_prog_id, linked_btf_id.value_(), kind.name, linked_name
> > + )
> > +
> > +
> > +def get_tramp_progs(bpf_prog):
> > + tr = bpf_prog.aux.trampoline
> > + if not tr:
> > + return
>
> Same observation here, I solved it with
>
> try:
> tr = bpf_prog.aux.trampoline
> if not tr:
> return
> except AttributeError as e:
> print(e)
> return
Yep, sounds good. Will address in v2 on github as well. Thanks!
--
Andrey Ignatov
prev parent reply other threads:[~2020-02-28 20:15 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-02-27 2:32 [PATCH bpf-next] bpf: Add drgn script to list progs/maps Andrey Ignatov
2020-02-27 5:45 ` Song Liu
2020-02-27 17:01 ` Andrey Ignatov
2020-02-27 6:27 ` Andrii Nakryiko
2020-02-27 17:38 ` Andrey Ignatov
2020-02-27 18:01 ` Stanislav Fomichev
2020-02-27 18:26 ` Andrey Ignatov
2020-02-27 21:11 ` Daniel Borkmann
2020-02-27 21:32 ` Daniel Borkmann
2020-02-27 22:19 ` Omar Sandoval
2020-02-28 20:11 ` Andrey Ignatov
2020-02-28 21:29 ` Andrey Ignatov
2020-02-28 12:51 ` Quentin Monnet
2020-02-28 20:15 ` Andrey Ignatov [this message]
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=20200228201514.GB51456@rdna-mbp \
--to=rdna@fb.com \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=kernel-team@fb.com \
--cc=osandov@fb.com \
--cc=quentin@isovalent.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).