From: Yonghong Song <y...@fb.com>

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 <y...@fb.com>
Signed-off-by: Martin KaFai Lau <ka...@fb.com>
---
 tools/bpf/bpftool/btf_dumper.c    | 136 ++++++++++++++++++++++++++++++
 tools/bpf/bpftool/main.h          |   2 +
 tools/bpf/bpftool/prog.c          |  56 ++++++++++++
 tools/bpf/bpftool/xlated_dumper.c |  33 ++++++++
 tools/bpf/bpftool/xlated_dumper.h |   3 +
 5 files changed, 230 insertions(+)

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 61d82020af58..a6258e583bd7 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -173,6 +173,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 5ff5544596e7..fdc5e1b6556c 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;
@@ -548,6 +554,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);
@@ -556,6 +573,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);
@@ -579,6 +599,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 &&
@@ -587,6 +619,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) {
@@ -619,6 +656,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;
@@ -645,12 +683,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);
                                }
 
@@ -679,6 +730,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);
@@ -690,12 +744,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];
 };
 
-- 
2.17.1

Reply via email to