Commit d5ae04da authored by Martin KaFai Lau's avatar Martin KaFai Lau Committed by Daniel Borkmann
Browse files

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: default avatarMartin KaFai Lau <kafai@fb.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Acked-by: default avatarQuentin Monnet <quentin@isovalent.com>
Link: https://lore.kernel.org/bpf/20200318171650.129252-1-kafai@fb.com
parent 30255d31
Loading
Loading
Loading
Loading
+106 −12
Original line number Diff line number Diff line
@@ -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
		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(jw, "%lu", *(unsigned long *)data);
		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);
			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("...");
		}
+1 −0
Original line number Diff line number Diff line
@@ -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