[PATCH bpf-next v2 13/13] tools/bpf: bpftool: add support for jited func types
From: Yonghong Song <hidden>
Date: 2018-10-17 15:18:58
Subsystem:
bpf [general] (safe dynamic programs and tools), bpf [tooling] (bpftool), the rest · Maintainers:
Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi, Quentin Monnet, Linus Torvalds
This patch added support to print function signature
if btf func_info is available. Note that ksym
now uses function name instead of prog_name as
prog_name has a limit of 16 bytes including
ending '\0'.
The following is a sample output for selftests
test_btf with file test_btf_haskv.o:
$ bpftool prog dump jited id 1
int _dummy_tracepoint(struct dummy_tracepoint_args * ):
bpf_prog_b07ccb89267cf242__dummy_tracepoint:
0: push %rbp
1: mov %rsp,%rbp
......
3c: add $0x28,%rbp
40: leaveq
41: retq
int test_long_fname_1(struct dummy_tracepoint_args * ):
bpf_prog_2dcecc18072623fc_test_long_fname_1:
0: push %rbp
1: mov %rsp,%rbp
......
3a: add $0x28,%rbp
3e: leaveq
3f: retq
int test_long_fname_2(struct dummy_tracepoint_args * ):
bpf_prog_89d64e4abf0f0126_test_long_fname_2:
0: push %rbp
1: mov %rsp,%rbp
......
80: add $0x28,%rbp
84: leaveq
85: retq
Signed-off-by: Yonghong Song <redacted>
---
tools/bpf/bpftool/btf_dumper.c | 96 ++++++++++++++++++++++++++++++++++
tools/bpf/bpftool/main.h | 2 +
tools/bpf/bpftool/prog.c | 54 +++++++++++++++++++
3 files changed, 152 insertions(+)
diff --git a/tools/bpf/bpftool/btf_dumper.c b/tools/bpf/bpftool/btf_dumper.c
index 55bc512a1831..a31df4202335 100644
--- a/tools/bpf/bpftool/btf_dumper.c
+++ b/tools/bpf/bpftool/btf_dumper.c@@ -249,3 +249,99 @@ int btf_dumper_type(const struct btf_dumper *d, __u32 type_id, { return btf_dumper_do_type(d, type_id, 0, data); } + +#define BTF_PRINT_STRING(str) \ + { \ + pos += snprintf(func_sig + pos, size - pos, str); \ + if (pos >= size) \ + return -1; \ + } +#define BTF_PRINT_ONE_ARG(fmt, arg) \ + { \ + pos += snprintf(func_sig + pos, size - pos, fmt, arg); \ + if (pos >= size) \ + return -1; \ + } +#define BTF_PRINT_TYPE_ONLY(type) \ + { \ + pos = __btf_dumper_type_only(btf, type, func_sig, \ + pos, size); \ + if (pos == -1) \ + return -1; \ + } + +static int __btf_dumper_type_only(struct btf *btf, __u32 type_id, + char *func_sig, int pos, int size) +{ + const struct btf_type *t = btf__type_by_id(btf, type_id); + const struct btf_array *array; + int i, vlen; + + switch (BTF_INFO_KIND(t->info)) { + case BTF_KIND_INT: + BTF_PRINT_ONE_ARG("%s ", + btf__name_by_offset(btf, t->name_off)); + break; + case BTF_KIND_STRUCT: + BTF_PRINT_ONE_ARG("struct %s ", + btf__name_by_offset(btf, t->name_off)); + break; + case BTF_KIND_UNION: + BTF_PRINT_ONE_ARG("union %s ", + btf__name_by_offset(btf, t->name_off)); + break; + case BTF_KIND_ENUM: + BTF_PRINT_ONE_ARG("enum %s ", + btf__name_by_offset(btf, t->name_off)); + break; + case BTF_KIND_ARRAY: + array = (struct btf_array *)(t + 1); + BTF_PRINT_TYPE_ONLY(array->type); + BTF_PRINT_ONE_ARG("[%d]", array->nelems); + break; + case BTF_KIND_PTR: + BTF_PRINT_TYPE_ONLY(t->type); + BTF_PRINT_STRING("* "); + break; + case BTF_KIND_UNKN: + case BTF_KIND_FWD: + case BTF_KIND_TYPEDEF: + return -1; + case BTF_KIND_VOLATILE: + BTF_PRINT_STRING("volatile "); + BTF_PRINT_TYPE_ONLY(t->type); + break; + case BTF_KIND_CONST: + BTF_PRINT_STRING("const "); + BTF_PRINT_TYPE_ONLY(t->type); + break; + case BTF_KIND_RESTRICT: + BTF_PRINT_STRING("restrict "); + BTF_PRINT_TYPE_ONLY(t->type); + break; + case BTF_KIND_FUNC: + case BTF_KIND_FUNC_PROTO: + BTF_PRINT_TYPE_ONLY(t->type); + BTF_PRINT_ONE_ARG("%s(", btf__name_by_offset(btf, t->name_off)); + vlen = BTF_INFO_VLEN(t->info); + for (i = 0; i < vlen; i++) { + __u32 arg_type = ((__u32 *)(t + 1))[i]; + + BTF_PRINT_TYPE_ONLY(arg_type); + if (i != (vlen - 1)) + BTF_PRINT_STRING(", "); + } + BTF_PRINT_STRING(")"); + break; + default: + return -1; + } + + return pos; +} + +int btf_dumper_type_only(struct btf *btf, __u32 type_id, char *func_sig, + int size) +{ + return __btf_dumper_type_only(btf, type_id, func_sig, 0, size); +}
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 28ee769bd11b..f887564476dc 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h@@ -168,6 +168,8 @@ struct btf_dumper { */ int btf_dumper_type(const struct btf_dumper *d, __u32 type_id, const void *data); +int btf_dumper_type_only(struct btf *btf, __u32 func_type_id, char *func_only, + int size); struct nlattr; struct ifinfomsg;
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index 335028968dfb..e78632a30ea3 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c@@ -47,6 +47,7 @@ #include <linux/err.h> #include <bpf.h> +#include <btf.h> #include <libbpf.h> #include "cfg.h"
@@ -447,9 +448,11 @@ static int do_show(int argc, char **argv) static int do_dump(int argc, char **argv) { unsigned long *func_ksyms = NULL; + unsigned int *func_types = NULL; struct bpf_prog_info info = {}; unsigned int *func_lens = NULL; unsigned int nr_func_ksyms; + unsigned int nr_func_types; unsigned int nr_func_lens; struct dump_data dd = {}; __u32 len = sizeof(info);
@@ -546,6 +549,16 @@ static int do_dump(int argc, char **argv) } } + nr_func_types = info.nr_jited_func_types; + if (nr_func_types) { + func_types = malloc(nr_func_types * sizeof(__u32)); + if (!func_types) { + p_err("mem alloc failed"); + close(fd); + goto err_free; + } + } + memset(&info, 0, sizeof(info)); *member_ptr = ptr_to_u64(buf);
@@ -554,6 +567,8 @@ static int do_dump(int argc, char **argv) info.nr_jited_ksyms = nr_func_ksyms; info.jited_func_lens = ptr_to_u64(func_lens); info.nr_jited_func_lens = nr_func_lens; + info.jited_func_types = ptr_to_u64(func_types); + info.nr_jited_func_types = nr_func_types; err = bpf_obj_get_info_by_fd(fd, &info, &len); close(fd);
@@ -577,6 +592,11 @@ static int do_dump(int argc, char **argv) goto err_free; } + if (info.nr_jited_func_types > nr_func_types) { + p_err("too many types returned"); + goto err_free; + } + if ((member_len == &info.jited_prog_len && info.jited_prog_insns == 0) || (member_len == &info.xlated_prog_len &&
@@ -585,6 +605,12 @@ static int do_dump(int argc, char **argv) goto err_free; } + if (info.btf_id && + info.nr_jited_func_lens != info.nr_jited_func_types) { + p_err("unequal jited func lens and types"); + goto err_free; + } + if (filepath) { fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fd < 0) {
@@ -618,7 +644,9 @@ static int do_dump(int argc, char **argv) struct kernel_sym *sym = NULL; char sym_name[SYM_MAX_NAME]; unsigned char *img = buf; + struct btf *btf = NULL; __u64 *ksyms = NULL; + char func_sig[1024]; __u32 *lens; __u32 i;
@@ -627,6 +655,14 @@ static int do_dump(int argc, char **argv) ksyms = (__u64 *) info.jited_ksyms; } + if (info.btf_id) { + err = btf_get_from_id(info.btf_id, &btf); + if (err) { + p_err("failed to get btf"); + goto err_free; + } + } + if (json_output) jsonw_start_array(json_wtr);
@@ -642,12 +678,28 @@ static int do_dump(int argc, char **argv) strcpy(sym_name, "unknown"); } + func_sig[0] = '\0'; + if (btf) { + err = btf_dumper_type_only(btf, + func_types[i], + func_sig, + sizeof(func_sig)); + if (err < 0) + func_sig[0] = '\0'; + } + if (json_output) { jsonw_start_object(json_wtr); + if (func_sig[0] != '\0') { + jsonw_name(json_wtr, "proto"); + jsonw_string(json_wtr, func_sig); + } jsonw_name(json_wtr, "name"); jsonw_string(json_wtr, sym_name); jsonw_name(json_wtr, "insns"); } else { + if (func_sig[0] != '\0') + printf("%s:\n", func_sig); printf("%s:\n", sym_name); }
@@ -685,12 +737,14 @@ static int do_dump(int argc, char **argv) free(buf); free(func_ksyms); free(func_lens); + free(func_types); return 0; err_free: free(buf); free(func_ksyms); free(func_lens); + free(func_types); return -1; }
--
2.17.1