All of lore.kernel.org
 help / color / mirror / Atom feed
From: Quentin Monnet <quentin@isovalent.com>
To: Andrey Ignatov <rdna@fb.com>, bpf@vger.kernel.org
Cc: 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:51:05 +0000	[thread overview]
Message-ID: <42af50cc-acde-d7a9-19da-8e2fb87bce48@isovalent.com> (raw)
In-Reply-To: <20200227023253.3445221-1-rdna@fb.com>

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?

> +
> +
> +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

Best regards,
Quentin

  parent reply	other threads:[~2020-02-28 12:51 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 [this message]
2020-02-28 20:15   ` Andrey Ignatov

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=42af50cc-acde-d7a9-19da-8e2fb87bce48@isovalent.com \
    --to=quentin@isovalent.com \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=kernel-team@fb.com \
    --cc=osandov@fb.com \
    --cc=rdna@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.