aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYonghong Song <yhs@fb.com>2018-11-19 15:29:21 -0800
committerAlexei Starovoitov <ast@kernel.org>2018-11-20 10:54:39 -0800
commit254471e57a86b8dc1a2cc19848e99f5d7c0558f4 (patch)
tree1892de2dc8c361322df68d459f0e63e59d901450
parenttools/bpf: enhance test_btf file testing to test func info (diff)
downloadlinux-dev-254471e57a86b8dc1a2cc19848e99f5d7c0558f4.tar.xz
linux-dev-254471e57a86b8dc1a2cc19848e99f5d7c0558f4.zip
tools/bpf: bpftool: add support for func types
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 for translated insns and jited insns respectively. $ bpftool prog dump xlated id 1 int _dummy_tracepoint(struct dummy_tracepoint_args * arg): 0: (85) call pc+2#bpf_prog_2dcecc18072623fc_test_long_fname_1 1: (b7) r0 = 0 2: (95) exit int test_long_fname_1(struct dummy_tracepoint_args * arg): 3: (85) call pc+1#bpf_prog_89d64e4abf0f0126_test_long_fname_2 4: (95) exit int test_long_fname_2(struct dummy_tracepoint_args * arg): 5: (b7) r2 = 0 6: (63) *(u32 *)(r10 -4) = r2 7: (79) r1 = *(u64 *)(r1 +8) ... 22: (07) r1 += 1 23: (63) *(u32 *)(r0 +4) = r1 24: (95) exit $ bpftool prog dump jited id 1 int _dummy_tracepoint(struct dummy_tracepoint_args * arg): 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 * arg): 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 * arg): 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 <yhs@fb.com> Signed-off-by: Martin KaFai Lau <kafai@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
-rw-r--r--tools/bpf/bpftool/btf_dumper.c136
-rw-r--r--tools/bpf/bpftool/main.h2
-rw-r--r--tools/bpf/bpftool/prog.c56
-rw-r--r--tools/bpf/bpftool/xlated_dumper.c33
-rw-r--r--tools/bpf/bpftool/xlated_dumper.h3
5 files changed, 230 insertions, 0 deletions
diff --git a/tools/bpf/bpftool/btf_dumper.c b/tools/bpf/bpftool/btf_dumper.c
index 55bc512a1831..c3fd3a7cb787 100644
--- a/tools/bpf/bpftool/btf_dumper.c
+++ b/tools/bpf/bpftool/btf_dumper.c
@@ -249,3 +249,139 @@ 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_ARG(...) \
+ do { \
+ pos += snprintf(func_sig + pos, size - pos, \
+ __VA_ARGS__); \
+ if (pos >= size) \
+ return -1; \
+ } while (0)
+#define BTF_PRINT_TYPE(type) \
+ do { \
+ pos = __btf_dumper_type_only(btf, type, func_sig, \
+ pos, size); \
+ if (pos == -1) \
+ 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)
+{
+ const struct btf_type *proto_type;
+ const struct btf_array *array;
+ const struct btf_type *t;
+
+ if (!type_id) {
+ BTF_PRINT_ARG("void ");
+ return pos;
+ }
+
+ t = btf__type_by_id(btf, type_id);
+
+ switch (BTF_INFO_KIND(t->info)) {
+ case BTF_KIND_INT:
+ BTF_PRINT_ARG("%s ", btf__name_by_offset(btf, t->name_off));
+ break;
+ case BTF_KIND_STRUCT:
+ BTF_PRINT_ARG("struct %s ",
+ btf__name_by_offset(btf, t->name_off));
+ break;
+ case BTF_KIND_UNION:
+ BTF_PRINT_ARG("union %s ",
+ btf__name_by_offset(btf, t->name_off));
+ break;
+ case BTF_KIND_ENUM:
+ BTF_PRINT_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(array->type);
+ BTF_PRINT_ARG("[%d]", array->nelems);
+ break;
+ case BTF_KIND_PTR:
+ BTF_PRINT_TYPE(t->type);
+ BTF_PRINT_ARG("* ");
+ break;
+ case BTF_KIND_UNKN:
+ case BTF_KIND_FWD:
+ case BTF_KIND_TYPEDEF:
+ return -1;
+ case BTF_KIND_VOLATILE:
+ BTF_PRINT_ARG("volatile ");
+ BTF_PRINT_TYPE(t->type);
+ break;
+ case BTF_KIND_CONST:
+ BTF_PRINT_ARG("const ");
+ BTF_PRINT_TYPE(t->type);
+ break;
+ case BTF_KIND_RESTRICT:
+ BTF_PRINT_ARG("restrict ");
+ BTF_PRINT_TYPE(t->type);
+ break;
+ case BTF_KIND_FUNC_PROTO:
+ pos = btf_dump_func(btf, func_sig, t, NULL, pos, size);
+ if (pos == -1)
+ return -1;
+ break;
+ case BTF_KIND_FUNC:
+ proto_type = btf__type_by_id(btf, t->type);
+ pos = btf_dump_func(btf, func_sig, proto_type, t, pos, size);
+ if (pos == -1)
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+
+ return pos;
+}
+
+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)
+{
+ int i, vlen;
+
+ BTF_PRINT_TYPE(func_proto->type);
+ if (func)
+ BTF_PRINT_ARG("%s(", btf__name_by_offset(btf, func->name_off));
+ else
+ BTF_PRINT_ARG("(");
+ vlen = BTF_INFO_VLEN(func_proto->info);
+ for (i = 0; i < vlen; i++) {
+ struct btf_param *arg = &((struct btf_param *)(func_proto + 1))[i];
+
+ if (i)
+ BTF_PRINT_ARG(", ");
+ if (arg->type) {
+ BTF_PRINT_TYPE(arg->type);
+ BTF_PRINT_ARG("%s",
+ btf__name_by_offset(btf, arg->name_off));
+ } else {
+ BTF_PRINT_ARG("...");
+ }
+ }
+ BTF_PRINT_ARG(")");
+
+ return pos;
+}
+
+void btf_dumper_type_only(const struct btf *btf, __u32 type_id, char *func_sig,
+ int size)
+{
+ int err;
+
+ func_sig[0] = '\0';
+ if (!btf)
+ return;
+
+ err = __btf_dumper_type_only(btf, type_id, func_sig, 0, size);
+ if (err < 0)
+ func_sig[0] = '\0';
+}
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 10c6c16fae29..3e8979567cf1 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -187,6 +187,8 @@ struct btf_dumper {
*/
int btf_dumper_type(const struct btf_dumper *d, __u32 type_id,
const void *data);
+void btf_dumper_type_only(const 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 c176e1aa66fe..37b1daf19da6 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"
@@ -451,14 +452,19 @@ static int do_dump(int argc, char **argv)
struct bpf_prog_info info = {};
unsigned int *func_lens = NULL;
const char *disasm_opt = NULL;
+ unsigned int finfo_rec_size;
unsigned int nr_func_ksyms;
unsigned int nr_func_lens;
struct dump_data dd = {};
__u32 len = sizeof(info);
+ struct btf *btf = NULL;
+ void *func_info = NULL;
+ unsigned int finfo_cnt;
unsigned int buf_size;
char *filepath = NULL;
bool opcodes = false;
bool visual = false;
+ char func_sig[1024];
unsigned char *buf;
__u32 *member_len;
__u64 *member_ptr;
@@ -551,6 +557,17 @@ static int do_dump(int argc, char **argv)
}
}
+ finfo_cnt = info.func_info_cnt;
+ finfo_rec_size = info.func_info_rec_size;
+ if (finfo_cnt && finfo_rec_size) {
+ func_info = malloc(finfo_cnt * finfo_rec_size);
+ if (!func_info) {
+ p_err("mem alloc failed");
+ close(fd);
+ goto err_free;
+ }
+ }
+
memset(&info, 0, sizeof(info));
*member_ptr = ptr_to_u64(buf);
@@ -559,6 +576,9 @@ 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.func_info_cnt = finfo_cnt;
+ info.func_info_rec_size = finfo_rec_size;
+ info.func_info = ptr_to_u64(func_info);
err = bpf_obj_get_info_by_fd(fd, &info, &len);
close(fd);
@@ -582,6 +602,18 @@ static int do_dump(int argc, char **argv)
goto err_free;
}
+ if (info.func_info_cnt != finfo_cnt) {
+ p_err("incorrect func_info_cnt %d vs. expected %d",
+ info.func_info_cnt, finfo_cnt);
+ goto err_free;
+ }
+
+ if (info.func_info_rec_size != finfo_rec_size) {
+ p_err("incorrect func_info_rec_size %d vs. expected %d",
+ info.func_info_rec_size, finfo_rec_size);
+ goto err_free;
+ }
+
if ((member_len == &info.jited_prog_len &&
info.jited_prog_insns == 0) ||
(member_len == &info.xlated_prog_len &&
@@ -590,6 +622,11 @@ static int do_dump(int argc, char **argv)
goto err_free;
}
+ if (info.btf_id && btf_get_from_id(info.btf_id, &btf)) {
+ p_err("failed to get btf");
+ goto err_free;
+ }
+
if (filepath) {
fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd < 0) {
@@ -622,6 +659,7 @@ static int do_dump(int argc, char **argv)
if (info.nr_jited_func_lens && info.jited_func_lens) {
struct kernel_sym *sym = NULL;
+ struct bpf_func_info *record;
char sym_name[SYM_MAX_NAME];
unsigned char *img = buf;
__u64 *ksyms = NULL;
@@ -648,12 +686,25 @@ static int do_dump(int argc, char **argv)
strcpy(sym_name, "unknown");
}
+ if (func_info) {
+ record = func_info + i * finfo_rec_size;
+ btf_dumper_type_only(btf, record->type_id,
+ func_sig,
+ sizeof(func_sig));
+ }
+
if (json_output) {
jsonw_start_object(json_wtr);
+ if (func_info && 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_info && func_sig[0] != '\0')
+ printf("%s:\n", func_sig);
printf("%s:\n", sym_name);
}
@@ -682,6 +733,9 @@ static int do_dump(int argc, char **argv)
kernel_syms_load(&dd);
dd.nr_jited_ksyms = info.nr_jited_ksyms;
dd.jited_ksyms = (__u64 *) info.jited_ksyms;
+ dd.btf = btf;
+ dd.func_info = func_info;
+ dd.finfo_rec_size = finfo_rec_size;
if (json_output)
dump_xlated_json(&dd, buf, *member_len, opcodes);
@@ -693,12 +747,14 @@ static int do_dump(int argc, char **argv)
free(buf);
free(func_ksyms);
free(func_lens);
+ free(func_info);
return 0;
err_free:
free(buf);
free(func_ksyms);
free(func_lens);
+ free(func_info);
return -1;
}
diff --git a/tools/bpf/bpftool/xlated_dumper.c b/tools/bpf/bpftool/xlated_dumper.c
index 3284759df98a..e06ac0286a75 100644
--- a/tools/bpf/bpftool/xlated_dumper.c
+++ b/tools/bpf/bpftool/xlated_dumper.c
@@ -242,11 +242,15 @@ void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len,
.cb_imm = print_imm,
.private_data = dd,
};
+ struct bpf_func_info *record;
struct bpf_insn *insn = buf;
+ struct btf *btf = dd->btf;
bool double_insn = false;
+ char func_sig[1024];
unsigned int i;
jsonw_start_array(json_wtr);
+ record = dd->func_info;
for (i = 0; i < len / sizeof(*insn); i++) {
if (double_insn) {
double_insn = false;
@@ -255,6 +259,20 @@ void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len,
double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW);
jsonw_start_object(json_wtr);
+
+ if (btf && record) {
+ if (record->insn_offset == i) {
+ btf_dumper_type_only(btf, record->type_id,
+ func_sig,
+ sizeof(func_sig));
+ if (func_sig[0] != '\0') {
+ jsonw_name(json_wtr, "proto");
+ jsonw_string(json_wtr, func_sig);
+ }
+ record = (void *)record + dd->finfo_rec_size;
+ }
+ }
+
jsonw_name(json_wtr, "disasm");
print_bpf_insn(&cbs, insn + i, true);
@@ -297,16 +315,31 @@ void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len,
.cb_imm = print_imm,
.private_data = dd,
};
+ struct bpf_func_info *record;
struct bpf_insn *insn = buf;
+ struct btf *btf = dd->btf;
bool double_insn = false;
+ char func_sig[1024];
unsigned int i;
+ record = dd->func_info;
for (i = 0; i < len / sizeof(*insn); i++) {
if (double_insn) {
double_insn = false;
continue;
}
+ if (btf && record) {
+ if (record->insn_offset == i) {
+ btf_dumper_type_only(btf, record->type_id,
+ func_sig,
+ sizeof(func_sig));
+ if (func_sig[0] != '\0')
+ printf("%s:\n", func_sig);
+ record = (void *)record + dd->finfo_rec_size;
+ }
+ }
+
double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW);
printf("% 4d: ", i);
diff --git a/tools/bpf/bpftool/xlated_dumper.h b/tools/bpf/bpftool/xlated_dumper.h
index 33d86e2b369b..aec31723e1e5 100644
--- a/tools/bpf/bpftool/xlated_dumper.h
+++ b/tools/bpf/bpftool/xlated_dumper.h
@@ -51,6 +51,9 @@ struct dump_data {
__u32 sym_count;
__u64 *jited_ksyms;
__u32 nr_jited_ksyms;
+ struct btf *btf;
+ void *func_info;
+ __u32 finfo_rec_size;
char scratch_buff[SYM_MAX_NAME + 8];
};