bpftool: Translate prog_id to its bpf prog_name
The kernel struct_ops obj has kernel's func ptrs implemented by bpf_progs. The bpf prog_id is stored as the value of the func ptr for introspection purpose. In the latter patch, a struct_ops dump subcmd will be added to introspect these func ptrs. It is desired to print the actual bpf prog_name instead of only printing the prog_id. Since struct_ops is the only usecase storing prog_id in the func ptr, this patch adds a prog_id_as_func_ptr bool (default is false) to "struct btf_dumper" in order not to mis-interpret the ptr value for the other existing use-cases. While printing a func_ptr as a bpf prog_name, this patch also prefix the bpf prog_name with the ptr's func_proto. [ Note that it is the ptr's func_proto instead of the bpf prog's func_proto ] It reuses the current btf_dump_func() to obtain the ptr's func_proto string. Here is an example from the bpf_cubic.c: "void (struct sock *, u32, u32) bictcp_cong_avoid/prog_id:140" Signed-off-by: Martin KaFai Lau <kafai@fb.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Quentin Monnet <quentin@isovalent.com> Link: https://lore.kernel.org/bpf/20200318171650.129252-1-kafai@fb.com
This commit is contained in:
parent
30255d3175
commit
d5ae04da34
@ -4,11 +4,13 @@
|
||||
#include <ctype.h>
|
||||
#include <stdio.h> /* for (FILE *) used by json_writer */
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/btf.h>
|
||||
#include <linux/err.h>
|
||||
#include <bpf/btf.h>
|
||||
#include <bpf/bpf.h>
|
||||
|
||||
#include "json_writer.h"
|
||||
#include "main.h"
|
||||
@ -22,13 +24,102 @@
|
||||
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)
|
||||
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 dump_prog_id_as_func_ptr(const struct btf_dumper *d,
|
||||
const struct btf_type *func_proto,
|
||||
__u32 prog_id)
|
||||
{
|
||||
if (is_plain_text)
|
||||
jsonw_printf(jw, "%p", *(void **)data);
|
||||
struct bpf_prog_info_linear *prog_info = NULL;
|
||||
const struct btf_type *func_type;
|
||||
const char *prog_name = NULL;
|
||||
struct bpf_func_info *finfo;
|
||||
struct btf *prog_btf = NULL;
|
||||
struct bpf_prog_info *info;
|
||||
int prog_fd, func_sig_len;
|
||||
char prog_str[1024];
|
||||
|
||||
/* Get the ptr's func_proto */
|
||||
func_sig_len = btf_dump_func(d->btf, prog_str, func_proto, NULL, 0,
|
||||
sizeof(prog_str));
|
||||
if (func_sig_len == -1)
|
||||
return -1;
|
||||
|
||||
if (!prog_id)
|
||||
goto print;
|
||||
|
||||
/* Get the bpf_prog's name. Obtain from func_info. */
|
||||
prog_fd = bpf_prog_get_fd_by_id(prog_id);
|
||||
if (prog_fd == -1)
|
||||
goto print;
|
||||
|
||||
prog_info = bpf_program__get_prog_info_linear(prog_fd,
|
||||
1UL << BPF_PROG_INFO_FUNC_INFO);
|
||||
close(prog_fd);
|
||||
if (IS_ERR(prog_info)) {
|
||||
prog_info = NULL;
|
||||
goto print;
|
||||
}
|
||||
info = &prog_info->info;
|
||||
|
||||
if (!info->btf_id || !info->nr_func_info ||
|
||||
btf__get_from_id(info->btf_id, &prog_btf))
|
||||
goto print;
|
||||
finfo = (struct bpf_func_info *)info->func_info;
|
||||
func_type = btf__type_by_id(prog_btf, finfo->type_id);
|
||||
if (!func_type || !btf_is_func(func_type))
|
||||
goto print;
|
||||
|
||||
prog_name = btf__name_by_offset(prog_btf, func_type->name_off);
|
||||
|
||||
print:
|
||||
if (!prog_id)
|
||||
snprintf(&prog_str[func_sig_len],
|
||||
sizeof(prog_str) - func_sig_len, " 0");
|
||||
else if (prog_name)
|
||||
snprintf(&prog_str[func_sig_len],
|
||||
sizeof(prog_str) - func_sig_len,
|
||||
" %s/prog_id:%u", prog_name, prog_id);
|
||||
else
|
||||
jsonw_printf(jw, "%lu", *(unsigned long *)data);
|
||||
snprintf(&prog_str[func_sig_len],
|
||||
sizeof(prog_str) - func_sig_len,
|
||||
" <unknown_prog_name>/prog_id:%u", prog_id);
|
||||
|
||||
prog_str[sizeof(prog_str) - 1] = '\0';
|
||||
jsonw_string(d->jw, prog_str);
|
||||
btf__free(prog_btf);
|
||||
free(prog_info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void btf_dumper_ptr(const struct btf_dumper *d,
|
||||
const struct btf_type *t,
|
||||
const void *data)
|
||||
{
|
||||
unsigned long value = *(unsigned long *)data;
|
||||
const struct btf_type *ptr_type;
|
||||
__s32 ptr_type_id;
|
||||
|
||||
if (!d->prog_id_as_func_ptr || value > UINT32_MAX)
|
||||
goto print_ptr_value;
|
||||
|
||||
ptr_type_id = btf__resolve_type(d->btf, t->type);
|
||||
if (ptr_type_id < 0)
|
||||
goto print_ptr_value;
|
||||
ptr_type = btf__type_by_id(d->btf, ptr_type_id);
|
||||
if (!ptr_type || !btf_is_func_proto(ptr_type))
|
||||
goto print_ptr_value;
|
||||
|
||||
if (!dump_prog_id_as_func_ptr(d, ptr_type, value))
|
||||
return;
|
||||
|
||||
print_ptr_value:
|
||||
if (d->is_plain_text)
|
||||
jsonw_printf(d->jw, "%p", (void *)value);
|
||||
else
|
||||
jsonw_printf(d->jw, "%lu", value);
|
||||
}
|
||||
|
||||
static int btf_dumper_modifier(const struct btf_dumper *d, __u32 type_id,
|
||||
@ -442,7 +533,7 @@ static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id,
|
||||
case BTF_KIND_ENUM:
|
||||
return btf_dumper_enum(d, t, data);
|
||||
case BTF_KIND_PTR:
|
||||
btf_dumper_ptr(data, d->jw, d->is_plain_text);
|
||||
btf_dumper_ptr(d, t, data);
|
||||
return 0;
|
||||
case BTF_KIND_UNKN:
|
||||
jsonw_printf(d->jw, "(unknown)");
|
||||
@ -487,10 +578,6 @@ int btf_dumper_type(const struct btf_dumper *d, __u32 type_id,
|
||||
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)
|
||||
{
|
||||
@ -599,8 +686,15 @@ static int btf_dump_func(const struct btf *btf, char *func_sig,
|
||||
BTF_PRINT_ARG(", ");
|
||||
if (arg->type) {
|
||||
BTF_PRINT_TYPE(arg->type);
|
||||
BTF_PRINT_ARG("%s",
|
||||
btf__name_by_offset(btf, arg->name_off));
|
||||
if (arg->name_off)
|
||||
BTF_PRINT_ARG("%s",
|
||||
btf__name_by_offset(btf, arg->name_off));
|
||||
else if (pos && func_sig[pos - 1] == ' ')
|
||||
/* Remove unnecessary space for
|
||||
* FUNC_PROTO that does not have
|
||||
* arg->name_off
|
||||
*/
|
||||
func_sig[--pos] = '\0';
|
||||
} else {
|
||||
BTF_PRINT_ARG("...");
|
||||
}
|
||||
|
@ -205,6 +205,7 @@ struct btf_dumper {
|
||||
const struct btf *btf;
|
||||
json_writer_t *jw;
|
||||
bool is_plain_text;
|
||||
bool prog_id_as_func_ptr;
|
||||
};
|
||||
|
||||
/* btf_dumper_type - print data along with type information
|
||||
|
Loading…
Reference in New Issue
Block a user