bpftool: Adding support for BTF program names

`bpftool prog list` and other bpftool subcommands that show
BPF program names currently get them from bpf_prog_info.name.
That field is limited to 16 (BPF_OBJ_NAME_LEN) chars which leads
to truncated names since many progs have much longer names.

The idea of this change is to improve all bpftool commands that
output prog name so that bpftool uses info from BTF to print
program names if available.

It tries bpf_prog_info.name first and fall back to btf only if
the name is suspected to be truncated (has 15 chars length).

Right now `bpftool p show id <id>` returns capped prog name

<id>: kprobe  name example_cap_cap  tag 712e...
...

With this change it would return

<id>: kprobe  name example_cap_capable  tag 712e...
...

Note, other commands that print prog names (e.g. "bpftool
cgroup tree") are also addressed in this change.

Signed-off-by: Raman Shukhau <ramasha@fb.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20220119100255.1068997-1-ramasha@fb.com
This commit is contained in:
Raman Shukhau 2022-01-19 02:02:55 -08:00 committed by Andrii Nakryiko
parent eaa266d83a
commit b662000aff
4 changed files with 70 additions and 12 deletions

View File

@ -50,6 +50,7 @@ static int show_bpf_prog(int id, enum bpf_attach_type attach_type,
const char *attach_flags_str, const char *attach_flags_str,
int level) int level)
{ {
char prog_name[MAX_PROG_FULL_NAME];
struct bpf_prog_info info = {}; struct bpf_prog_info info = {};
__u32 info_len = sizeof(info); __u32 info_len = sizeof(info);
int prog_fd; int prog_fd;
@ -63,6 +64,7 @@ static int show_bpf_prog(int id, enum bpf_attach_type attach_type,
return -1; return -1;
} }
get_prog_full_name(&info, prog_fd, prog_name, sizeof(prog_name));
if (json_output) { if (json_output) {
jsonw_start_object(json_wtr); jsonw_start_object(json_wtr);
jsonw_uint_field(json_wtr, "id", info.id); jsonw_uint_field(json_wtr, "id", info.id);
@ -73,7 +75,7 @@ static int show_bpf_prog(int id, enum bpf_attach_type attach_type,
jsonw_uint_field(json_wtr, "attach_type", attach_type); jsonw_uint_field(json_wtr, "attach_type", attach_type);
jsonw_string_field(json_wtr, "attach_flags", jsonw_string_field(json_wtr, "attach_flags",
attach_flags_str); attach_flags_str);
jsonw_string_field(json_wtr, "name", info.name); jsonw_string_field(json_wtr, "name", prog_name);
jsonw_end_object(json_wtr); jsonw_end_object(json_wtr);
} else { } else {
printf("%s%-8u ", level ? " " : "", info.id); printf("%s%-8u ", level ? " " : "", info.id);
@ -81,7 +83,7 @@ static int show_bpf_prog(int id, enum bpf_attach_type attach_type,
printf("%-15s", attach_type_name[attach_type]); printf("%-15s", attach_type_name[attach_type]);
else else
printf("type %-10u", attach_type); printf("type %-10u", attach_type);
printf(" %-15s %-15s\n", attach_flags_str, info.name); printf(" %-15s %-15s\n", attach_flags_str, prog_name);
} }
close(prog_fd); close(prog_fd);

View File

@ -24,6 +24,7 @@
#include <bpf/bpf.h> #include <bpf/bpf.h>
#include <bpf/hashmap.h> #include <bpf/hashmap.h>
#include <bpf/libbpf.h> /* libbpf_num_possible_cpus */ #include <bpf/libbpf.h> /* libbpf_num_possible_cpus */
#include <bpf/btf.h>
#include "main.h" #include "main.h"
@ -304,6 +305,49 @@ const char *get_fd_type_name(enum bpf_obj_type type)
return names[type]; return names[type];
} }
void get_prog_full_name(const struct bpf_prog_info *prog_info, int prog_fd,
char *name_buff, size_t buff_len)
{
const char *prog_name = prog_info->name;
const struct btf_type *func_type;
const struct bpf_func_info finfo;
struct bpf_prog_info info = {};
__u32 info_len = sizeof(info);
struct btf *prog_btf = NULL;
if (buff_len <= BPF_OBJ_NAME_LEN ||
strlen(prog_info->name) < BPF_OBJ_NAME_LEN - 1)
goto copy_name;
if (!prog_info->btf_id || prog_info->nr_func_info == 0)
goto copy_name;
info.nr_func_info = 1;
info.func_info_rec_size = prog_info->func_info_rec_size;
if (info.func_info_rec_size > sizeof(finfo))
info.func_info_rec_size = sizeof(finfo);
info.func_info = ptr_to_u64(&finfo);
if (bpf_obj_get_info_by_fd(prog_fd, &info, &info_len))
goto copy_name;
prog_btf = btf__load_from_kernel_by_id(info.btf_id);
if (!prog_btf)
goto copy_name;
func_type = btf__type_by_id(prog_btf, finfo.type_id);
if (!func_type || !btf_is_func(func_type))
goto copy_name;
prog_name = btf__name_by_offset(prog_btf, func_type->name_off);
copy_name:
snprintf(name_buff, buff_len, "%s", prog_name);
if (prog_btf)
btf__free(prog_btf);
}
int get_fd_type(int fd) int get_fd_type(int fd)
{ {
char path[PATH_MAX]; char path[PATH_MAX];

View File

@ -140,6 +140,10 @@ struct cmd {
int cmd_select(const struct cmd *cmds, int argc, char **argv, int cmd_select(const struct cmd *cmds, int argc, char **argv,
int (*help)(int argc, char **argv)); int (*help)(int argc, char **argv));
#define MAX_PROG_FULL_NAME 128
void get_prog_full_name(const struct bpf_prog_info *prog_info, int prog_fd,
char *name_buff, size_t buff_len);
int get_fd_type(int fd); int get_fd_type(int fd);
const char *get_fd_type_name(enum bpf_obj_type type); const char *get_fd_type_name(enum bpf_obj_type type);
char *get_fdinfo(int fd, const char *key); char *get_fdinfo(int fd, const char *key);

View File

@ -424,8 +424,10 @@ out_free:
free(value); free(value);
} }
static void print_prog_header_json(struct bpf_prog_info *info) static void print_prog_header_json(struct bpf_prog_info *info, int fd)
{ {
char prog_name[MAX_PROG_FULL_NAME];
jsonw_uint_field(json_wtr, "id", info->id); jsonw_uint_field(json_wtr, "id", info->id);
if (info->type < ARRAY_SIZE(prog_type_name)) if (info->type < ARRAY_SIZE(prog_type_name))
jsonw_string_field(json_wtr, "type", jsonw_string_field(json_wtr, "type",
@ -433,8 +435,10 @@ static void print_prog_header_json(struct bpf_prog_info *info)
else else
jsonw_uint_field(json_wtr, "type", info->type); jsonw_uint_field(json_wtr, "type", info->type);
if (*info->name) if (*info->name) {
jsonw_string_field(json_wtr, "name", info->name); get_prog_full_name(info, fd, prog_name, sizeof(prog_name));
jsonw_string_field(json_wtr, "name", prog_name);
}
jsonw_name(json_wtr, "tag"); jsonw_name(json_wtr, "tag");
jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"",
@ -455,7 +459,7 @@ static void print_prog_json(struct bpf_prog_info *info, int fd)
char *memlock; char *memlock;
jsonw_start_object(json_wtr); jsonw_start_object(json_wtr);
print_prog_header_json(info); print_prog_header_json(info, fd);
print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); print_dev_json(info->ifindex, info->netns_dev, info->netns_ino);
if (info->load_time) { if (info->load_time) {
@ -507,16 +511,20 @@ static void print_prog_json(struct bpf_prog_info *info, int fd)
jsonw_end_object(json_wtr); jsonw_end_object(json_wtr);
} }
static void print_prog_header_plain(struct bpf_prog_info *info) static void print_prog_header_plain(struct bpf_prog_info *info, int fd)
{ {
char prog_name[MAX_PROG_FULL_NAME];
printf("%u: ", info->id); printf("%u: ", info->id);
if (info->type < ARRAY_SIZE(prog_type_name)) if (info->type < ARRAY_SIZE(prog_type_name))
printf("%s ", prog_type_name[info->type]); printf("%s ", prog_type_name[info->type]);
else else
printf("type %u ", info->type); printf("type %u ", info->type);
if (*info->name) if (*info->name) {
printf("name %s ", info->name); get_prog_full_name(info, fd, prog_name, sizeof(prog_name));
printf("name %s ", prog_name);
}
printf("tag "); printf("tag ");
fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); fprint_hex(stdout, info->tag, BPF_TAG_SIZE, "");
@ -534,7 +542,7 @@ static void print_prog_plain(struct bpf_prog_info *info, int fd)
{ {
char *memlock; char *memlock;
print_prog_header_plain(info); print_prog_header_plain(info, fd);
if (info->load_time) { if (info->load_time) {
char buf[32]; char buf[32];
@ -972,10 +980,10 @@ static int do_dump(int argc, char **argv)
if (json_output && nb_fds > 1) { if (json_output && nb_fds > 1) {
jsonw_start_object(json_wtr); /* prog object */ jsonw_start_object(json_wtr); /* prog object */
print_prog_header_json(&info); print_prog_header_json(&info, fds[i]);
jsonw_name(json_wtr, "insns"); jsonw_name(json_wtr, "insns");
} else if (nb_fds > 1) { } else if (nb_fds > 1) {
print_prog_header_plain(&info); print_prog_header_plain(&info, fds[i]);
} }
err = prog_dump(&info, mode, filepath, opcodes, visual, linum); err = prog_dump(&info, mode, filepath, opcodes, visual, linum);