Message ID | 20190312053051.2690567-13-songliubraving@fb.com |
---|---|
State | Awaiting Upstream |
Delegated to: | BPF Maintainers |
Headers | show |
Series | perf annotation of BPF programs | expand |
Em Mon, Mar 11, 2019 at 10:30:48PM -0700, Song Liu escreveu: > This patch enables the annotation of bpf program. > > A new dso type DSO_BINARY_TYPE__BPF_PROG_INFO is introduced to for BPF > programs. In symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso > calls into a new function symbol__disassemble_bpf(), where annotation > line information is filled based bpf_prog_info and btf saved in given > perf_env. > > symbol__disassemble_bpf() uses libbfd to disassemble bpf programs. > > Signed-off-by: Song Liu <songliubraving@fb.com> > --- > tools/build/Makefile.feature | 6 +- > tools/perf/Makefile.config | 4 + I see the changes to these two files, but I can't see the feature test that it triggers, forgot to do a git-add? Or is it in an upcoming patch in this series? After applying this test it "works": make: Entering directory '/home/acme/git/perf/tools/perf' BUILD: Doing 'make -j8' parallel build Auto-detecting system features: ... dwarf: [ on ] ... dwarf_getlocations: [ on ] <SNIP> ... bpf: [ on ] ... libaio: [ on ] ... disassembler-four-args: [ on ] Because you added it to FEATURE_TESTS_BASIC, and this means that if tools/build/feature/test-all.c builds, then what is in FEATURE_TESTS_BASIC is set to 'on', but you didn't add anything to tools/build/feature/test-all.c, so it works because all the other features are present. Take a look at: 2a07d814747b ("tools build feature: Check if libaio is available") To see what needs to be done. Either way, its interesting to break this patch in two, one adding the feature test and another to use it, i.e. the second patch out of this should have the commit log message in this patch. I've applied the patches up to before this one and will continue processing other patches while you address this. Thanks, - Arnaldo > tools/perf/util/annotate.c | 150 ++++++++++++++++++++++++++++++++++- > tools/perf/util/dso.c | 1 + > tools/perf/util/dso.h | 32 +++++--- > tools/perf/util/symbol.c | 1 + > 6 files changed, 180 insertions(+), 14 deletions(-) > > diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature > index 61e46d54a67c..8d3864b061f3 100644 > --- a/tools/build/Makefile.feature > +++ b/tools/build/Makefile.feature > @@ -66,7 +66,8 @@ FEATURE_TESTS_BASIC := \ > sched_getcpu \ > sdt \ > setns \ > - libaio > + libaio \ > + disassembler-four-args > > # FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list > # of all feature tests > @@ -118,7 +119,8 @@ FEATURE_DISPLAY ?= \ > lzma \ > get_cpuid \ > bpf \ > - libaio > + libaio \ > + disassembler-four-args > > # Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features. > # If in the future we need per-feature checks/flags for features not > diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config > index df4ad45599ca..c51b59e43dcc 100644 > --- a/tools/perf/Makefile.config > +++ b/tools/perf/Makefile.config > @@ -808,6 +808,10 @@ ifdef HAVE_KVM_STAT_SUPPORT > CFLAGS += -DHAVE_KVM_STAT_SUPPORT > endif > > +ifeq ($(feature-disassembler-four-args), 1) > + CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE > +endif > + > ifeq (${IS_64_BIT}, 1) > ifndef NO_PERF_READ_VDSO32 > $(call feature_check,compile-32) > diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c > index 5f6dbbf5d749..e492b19a157c 100644 > --- a/tools/perf/util/annotate.c > +++ b/tools/perf/util/annotate.c > @@ -10,6 +10,10 @@ > #include <errno.h> > #include <inttypes.h> > #include <libgen.h> > +#include <bpf/bpf.h> > +#include <bpf/btf.h> > +#include <bpf/libbpf.h> > +#include <linux/btf.h> > #include "util.h" > #include "ui/ui.h" > #include "sort.h" > @@ -24,6 +28,7 @@ > #include "annotate.h" > #include "evsel.h" > #include "evlist.h" > +#include "bpf-event.h" > #include "block-range.h" > #include "string2.h" > #include "arch/common.h" > @@ -31,6 +36,9 @@ > #include <pthread.h> > #include <linux/bitops.h> > #include <linux/kernel.h> > +#include <bfd.h> > +#include <dis-asm.h> > +#include <bpf/libbpf.h> > > /* FIXME: For the HE_COLORSET */ > #include "ui/browser.h" > @@ -1674,6 +1682,144 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil > return 0; > } > > +static int symbol__disassemble_bpf(struct symbol *sym, > + struct annotate_args *args) > +{ > + struct annotation *notes = symbol__annotation(sym); > + struct annotation_options *opts = args->options; > + struct bpf_prog_info_linear *info_linear; > + struct bpf_prog_linfo *prog_linfo = NULL; > + struct bpf_prog_info_node *info_node; > + int len = sym->end - sym->start; > + disassembler_ftype disassemble; > + struct map *map = args->ms.map; > + struct disassemble_info info; > + struct dso *dso = map->dso; > + int pc = 0, count, sub_id; > + struct btf *btf = NULL; > + char tpath[PATH_MAX]; > + size_t buf_size; > + int nr_skip = 0; > + int ret = -1; > + char *buf; > + bfd *bfdf; > + FILE *s; > + > + if (dso->binary_type != DSO_BINARY_TYPE__BPF_PROG_INFO) > + return -1; > + > + pr_debug("%s: handling sym %s addr %lx len %lx\n", __func__, > + sym->name, sym->start, sym->end - sym->start); > + > + memset(tpath, 0, sizeof(tpath)); > + perf_exe(tpath, sizeof(tpath)); > + > + bfdf = bfd_openr(tpath, NULL); > + assert(bfdf); > + assert(bfd_check_format(bfdf, bfd_object)); > + > + s = open_memstream(&buf, &buf_size); > + if (!s) > + goto out; > + init_disassemble_info(&info, s, > + (fprintf_ftype) fprintf); > + > + info.arch = bfd_get_arch(bfdf); > + info.mach = bfd_get_mach(bfdf); > + > + info_node = perf_env__find_bpf_prog_info(dso->bpf_prog.env, > + dso->bpf_prog.id); > + if (!info_node) > + goto out; > + info_linear = info_node->info_linear; > + sub_id = dso->bpf_prog.sub_id; > + > + info.buffer = (void *)(info_linear->info.jited_prog_insns); > + info.buffer_length = info_linear->info.jited_prog_len; > + > + if (info_linear->info.nr_line_info) > + prog_linfo = bpf_prog_linfo__new(&info_linear->info); > + > + if (info_linear->info.btf_id) { > + struct btf_node *node; > + > + node = perf_env__find_btf(dso->bpf_prog.env, > + info_linear->info.btf_id); > + if (node) > + btf = btf__new((__u8 *)(node->data), > + node->data_size); > + } > + > + disassemble_init_for_target(&info); > + > +#ifdef DISASM_FOUR_ARGS_SIGNATURE > + disassemble = disassembler(info.arch, > + bfd_big_endian(bfdf), > + info.mach, > + bfdf); > +#else > + disassemble = disassembler(bfdf); > +#endif > + assert(disassemble); > + > + fflush(s); > + do { > + const struct bpf_line_info *linfo = NULL; > + struct disasm_line *dl; > + size_t prev_buf_size; > + const char *srcline; > + u64 addr; > + > + addr = pc + ((u64 *)(info_linear->info.jited_ksyms))[sub_id]; > + count = disassemble(pc, &info); > + > + if (prog_linfo) > + linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo, > + addr, sub_id, > + nr_skip); > + > + if (linfo && btf) { > + srcline = btf__name_by_offset(btf, linfo->line_off); > + nr_skip++; > + } else > + srcline = NULL; > + > + fprintf(s, "\n"); > + prev_buf_size = buf_size; > + fflush(s); > + > + if (!opts->hide_src_code && srcline) { > + args->offset = -1; > + args->line = strdup(srcline); > + args->line_nr = 0; > + args->ms.sym = sym; > + dl = disasm_line__new(args); > + if (dl) { > + annotation_line__add(&dl->al, > + ¬es->src->source); > + } > + } > + > + args->offset = pc; > + args->line = buf + prev_buf_size; > + args->line_nr = 0; > + args->ms.sym = sym; > + dl = disasm_line__new(args); > + if (dl) > + annotation_line__add(&dl->al, ¬es->src->source); > + > + pc += count; > + } while (count > 0 && pc < len); > + > + ret = 0; > +out: > + free(prog_linfo); > + free(btf); > + fclose(s); > + bfd_close(bfdf); > + return ret; > +} > + > static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) > { > struct annotation_options *opts = args->options; > @@ -1701,7 +1847,9 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) > pr_debug("annotating [%p] %30s : [%p] %30s\n", > dso, dso->long_name, sym, sym->name); > > - if (dso__is_kcore(dso)) { > + if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) { > + return symbol__disassemble_bpf(sym, args); > + } else if (dso__is_kcore(dso)) { > kce.kcore_filename = symfs_filename; > kce.addr = map__rip_2objdump(map, sym->start); > kce.offs = sym->start; > diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c > index ba58ba603b69..58547c468c65 100644 > --- a/tools/perf/util/dso.c > +++ b/tools/perf/util/dso.c > @@ -184,6 +184,7 @@ int dso__read_binary_type_filename(const struct dso *dso, > case DSO_BINARY_TYPE__KALLSYMS: > case DSO_BINARY_TYPE__GUEST_KALLSYMS: > case DSO_BINARY_TYPE__JAVA_JIT: > + case DSO_BINARY_TYPE__BPF_PROG_INFO: > case DSO_BINARY_TYPE__NOT_FOUND: > ret = -1; > break; > diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h > index bb417c54c25a..c274b5aa839d 100644 > --- a/tools/perf/util/dso.h > +++ b/tools/perf/util/dso.h > @@ -14,6 +14,7 @@ > > struct machine; > struct map; > +struct perf_env; > > enum dso_binary_type { > DSO_BINARY_TYPE__KALLSYMS = 0, > @@ -35,6 +36,7 @@ enum dso_binary_type { > DSO_BINARY_TYPE__KCORE, > DSO_BINARY_TYPE__GUEST_KCORE, > DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, > + DSO_BINARY_TYPE__BPF_PROG_INFO, > DSO_BINARY_TYPE__NOT_FOUND, > }; > > @@ -178,17 +180,25 @@ struct dso { > struct auxtrace_cache *auxtrace_cache; > int comp; > > - /* dso data file */ > - struct { > - struct rb_root cache; > - int fd; > - int status; > - u32 status_seen; > - size_t file_size; > - struct list_head open_entry; > - u64 debug_frame_offset; > - u64 eh_frame_hdr_offset; > - } data; > + union { > + /* dso data file */ > + struct { > + struct rb_root cache; > + int fd; > + int status; > + u32 status_seen; > + size_t file_size; > + struct list_head open_entry; > + u64 debug_frame_offset; > + u64 eh_frame_hdr_offset; > + } data; > + /* bpf prog information */ > + struct { > + u32 id; > + u32 sub_id; > + struct perf_env *env; > + } bpf_prog; > + }; > > union { /* Tool specific area */ > void *priv; > diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c > index 758bf5f74e6e..4e2e304d4037 100644 > --- a/tools/perf/util/symbol.c > +++ b/tools/perf/util/symbol.c > @@ -1451,6 +1451,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, > case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO: > return true; > > + case DSO_BINARY_TYPE__BPF_PROG_INFO: > case DSO_BINARY_TYPE__NOT_FOUND: > default: > return false; > -- > 2.17.1
Em Mon, Mar 18, 2019 at 01:38:48PM -0300, Arnaldo Carvalho de Melo escreveu: > Em Mon, Mar 11, 2019 at 10:30:48PM -0700, Song Liu escreveu: > > This patch enables the annotation of bpf program. > > > > A new dso type DSO_BINARY_TYPE__BPF_PROG_INFO is introduced to for BPF > > programs. In symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso > > calls into a new function symbol__disassemble_bpf(), where annotation > > line information is filled based bpf_prog_info and btf saved in given > > perf_env. > > > > symbol__disassemble_bpf() uses libbfd to disassemble bpf programs. > > > > Signed-off-by: Song Liu <songliubraving@fb.com> > > --- > > tools/build/Makefile.feature | 6 +- > > tools/perf/Makefile.config | 4 + > > I see the changes to these two files, but I can't see the feature test > that it triggers, forgot to do a git-add? Or is it in an upcoming patch > in this series? > > After applying this test it "works": > > make: Entering directory '/home/acme/git/perf/tools/perf' > BUILD: Doing 'make -j8' parallel build > > Auto-detecting system features: > ... dwarf: [ on ] > ... dwarf_getlocations: [ on ] > <SNIP> > ... bpf: [ on ] > ... libaio: [ on ] > ... disassembler-four-args: [ on ] > > Because you added it to FEATURE_TESTS_BASIC, and this means that if > tools/build/feature/test-all.c builds, then what is in > FEATURE_TESTS_BASIC is set to 'on', but you didn't add anything to > tools/build/feature/test-all.c, so it works because all the other > features are present. > > Take a look at: > > 2a07d814747b ("tools build feature: Check if libaio is available") > > To see what needs to be done. > > Either way, its interesting to break this patch in two, one adding the > feature test and another to use it, i.e. the second patch out of this > should have the commit log message in this patch. > > I've applied the patches up to before this one and will continue > processing other patches while you address this. Ok, to continue processing the other patches I chunked out the part below into a 3rd patch from the above one and have it applied already. commit f326de312abc3657b0397817c66cd7e1540655f7 Author: Song Liu <songliubraving@fb.com> Date: Mon Mar 11 22:30:48 2019 -0700 perf symbols: Introduce DSO_BINARY_TYPE__BPF_PROG_INFO Introduce a new dso type DSO_BINARY_TYPE__BPF_PROG_INFO for BPF programs. In symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso will call into a new function symbol__disassemble_bpf() in an upcoming patch, where annotation line information is filled based bpf_prog_info and btf saved in given perf_env. Signed-off-by: Song Liu <songliubraving@fb.com> Reviewed-by: Jiri Olsa <jolsa@kernel.org> Cc: Alexei Starovoitov <ast@kernel.org> Cc: Daniel Borkmann <daniel@iogearbox.net> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stanislav Fomichev <sdf@google.com> Cc: kernel-team@fb.com Link: http://lkml.kernel.org/r/20190312053051.2690567-13-songliubraving@fb.com [ split from a larger patch ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index ba58ba603b69..58547c468c65 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -184,6 +184,7 @@ int dso__read_binary_type_filename(const struct dso *dso, case DSO_BINARY_TYPE__KALLSYMS: case DSO_BINARY_TYPE__GUEST_KALLSYMS: case DSO_BINARY_TYPE__JAVA_JIT: + case DSO_BINARY_TYPE__BPF_PROG_INFO: case DSO_BINARY_TYPE__NOT_FOUND: ret = -1; break; diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index bb417c54c25a..c274b5aa839d 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -14,6 +14,7 @@ struct machine; struct map; +struct perf_env; enum dso_binary_type { DSO_BINARY_TYPE__KALLSYMS = 0, @@ -35,6 +36,7 @@ enum dso_binary_type { DSO_BINARY_TYPE__KCORE, DSO_BINARY_TYPE__GUEST_KCORE, DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, + DSO_BINARY_TYPE__BPF_PROG_INFO, DSO_BINARY_TYPE__NOT_FOUND, }; @@ -178,17 +180,25 @@ struct dso { struct auxtrace_cache *auxtrace_cache; int comp; - /* dso data file */ - struct { - struct rb_root cache; - int fd; - int status; - u32 status_seen; - size_t file_size; - struct list_head open_entry; - u64 debug_frame_offset; - u64 eh_frame_hdr_offset; - } data; + union { + /* dso data file */ + struct { + struct rb_root cache; + int fd; + int status; + u32 status_seen; + size_t file_size; + struct list_head open_entry; + u64 debug_frame_offset; + u64 eh_frame_hdr_offset; + } data; + /* bpf prog information */ + struct { + u32 id; + u32 sub_id; + struct perf_env *env; + } bpf_prog; + }; union { /* Tool specific area */ void *priv; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 58442ca5e3c4..5cbad55cd99d 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1455,6 +1455,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO: return true; + case DSO_BINARY_TYPE__BPF_PROG_INFO: case DSO_BINARY_TYPE__NOT_FOUND: default: return false;
Sorry for the late response. > On Mar 18, 2019, at 9:38 AM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote: > > Em Mon, Mar 11, 2019 at 10:30:48PM -0700, Song Liu escreveu: >> This patch enables the annotation of bpf program. >> >> A new dso type DSO_BINARY_TYPE__BPF_PROG_INFO is introduced to for BPF >> programs. In symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso >> calls into a new function symbol__disassemble_bpf(), where annotation >> line information is filled based bpf_prog_info and btf saved in given >> perf_env. >> >> symbol__disassemble_bpf() uses libbfd to disassemble bpf programs. >> >> Signed-off-by: Song Liu <songliubraving@fb.com> >> --- >> tools/build/Makefile.feature | 6 +- >> tools/perf/Makefile.config | 4 + > > I see the changes to these two files, but I can't see the feature test > that it triggers, forgot to do a git-add? Or is it in an upcoming patch > in this series? test-disassembler-four-args.c is an existing test used by bpftool. It was added in fb982666e380c1632a74495b68b3c33a66e76430 . > > After applying this test it "works": > > make: Entering directory '/home/acme/git/perf/tools/perf' > BUILD: Doing 'make -j8' parallel build > > Auto-detecting system features: > ... dwarf: [ on ] > ... dwarf_getlocations: [ on ] > <SNIP> > ... bpf: [ on ] > ... libaio: [ on ] > ... disassembler-four-args: [ on ] > > Because you added it to FEATURE_TESTS_BASIC, and this means that if > tools/build/feature/test-all.c builds, then what is in > FEATURE_TESTS_BASIC is set to 'on', but you didn't add anything to > tools/build/feature/test-all.c, so it works because all the other > features are present. > > Take a look at: > > 2a07d814747b ("tools build feature: Check if libaio is available") > > To see what needs to be done. I used different versions of gcc to verify that current version of the patch works for both test-succeed and test-fail cases. I guess something like the following is needed? But the test does work without it. Thanks, Song diff --git i/tools/build/feature/test-all.c w/tools/build/feature/test-all.c index e903b86b742f..7853e6d91090 100644 --- i/tools/build/feature/test-all.c +++ w/tools/build/feature/test-all.c @@ -178,6 +178,10 @@ # include "test-reallocarray.c" #undef main +#define main main_test_disassembler_four_args +# include "test-disassembler-four-args.c" +#undef main + int main(int argc, char *argv[]) { main_test_libpython(); @@ -219,6 +223,7 @@ int main(int argc, char *argv[]) main_test_setns(); main_test_libaio(); main_test_reallocarray(); + main_test_disassembler_four_args(); return 0; } > > Either way, its interesting to break this patch in two, one adding the > feature test and another to use it, i.e. the second patch out of this > should have the commit log message in this patch. > > I've applied the patches up to before this one and will continue > processing other patches while you address this. > > Thanks, > > - Arnaldo > >> tools/perf/util/annotate.c | 150 ++++++++++++++++++++++++++++++++++- >> tools/perf/util/dso.c | 1 + >> tools/perf/util/dso.h | 32 +++++--- >> tools/perf/util/symbol.c | 1 + >> 6 files changed, 180 insertions(+), 14 deletions(-) >> >> diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature >> index 61e46d54a67c..8d3864b061f3 100644 >> --- a/tools/build/Makefile.feature >> +++ b/tools/build/Makefile.feature >> @@ -66,7 +66,8 @@ FEATURE_TESTS_BASIC := \ >> sched_getcpu \ >> sdt \ >> setns \ >> - libaio >> + libaio \ >> + disassembler-four-args >> >> # FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list >> # of all feature tests >> @@ -118,7 +119,8 @@ FEATURE_DISPLAY ?= \ >> lzma \ >> get_cpuid \ >> bpf \ >> - libaio >> + libaio \ >> + disassembler-four-args >> >> # Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features. >> # If in the future we need per-feature checks/flags for features not >> diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config >> index df4ad45599ca..c51b59e43dcc 100644 >> --- a/tools/perf/Makefile.config >> +++ b/tools/perf/Makefile.config >> @@ -808,6 +808,10 @@ ifdef HAVE_KVM_STAT_SUPPORT >> CFLAGS += -DHAVE_KVM_STAT_SUPPORT >> endif >> >> +ifeq ($(feature-disassembler-four-args), 1) >> + CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE >> +endif >> + >> ifeq (${IS_64_BIT}, 1) >> ifndef NO_PERF_READ_VDSO32 >> $(call feature_check,compile-32) >> diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c >> index 5f6dbbf5d749..e492b19a157c 100644 >> --- a/tools/perf/util/annotate.c >> +++ b/tools/perf/util/annotate.c >> @@ -10,6 +10,10 @@ >> #include <errno.h> >> #include <inttypes.h> >> #include <libgen.h> >> +#include <bpf/bpf.h> >> +#include <bpf/btf.h> >> +#include <bpf/libbpf.h> >> +#include <linux/btf.h> >> #include "util.h" >> #include "ui/ui.h" >> #include "sort.h" >> @@ -24,6 +28,7 @@ >> #include "annotate.h" >> #include "evsel.h" >> #include "evlist.h" >> +#include "bpf-event.h" >> #include "block-range.h" >> #include "string2.h" >> #include "arch/common.h" >> @@ -31,6 +36,9 @@ >> #include <pthread.h> >> #include <linux/bitops.h> >> #include <linux/kernel.h> >> +#include <bfd.h> >> +#include <dis-asm.h> >> +#include <bpf/libbpf.h> >> >> /* FIXME: For the HE_COLORSET */ >> #include "ui/browser.h" >> @@ -1674,6 +1682,144 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil >> return 0; >> } >> >> +static int symbol__disassemble_bpf(struct symbol *sym, >> + struct annotate_args *args) >> +{ >> + struct annotation *notes = symbol__annotation(sym); >> + struct annotation_options *opts = args->options; >> + struct bpf_prog_info_linear *info_linear; >> + struct bpf_prog_linfo *prog_linfo = NULL; >> + struct bpf_prog_info_node *info_node; >> + int len = sym->end - sym->start; >> + disassembler_ftype disassemble; >> + struct map *map = args->ms.map; >> + struct disassemble_info info; >> + struct dso *dso = map->dso; >> + int pc = 0, count, sub_id; >> + struct btf *btf = NULL; >> + char tpath[PATH_MAX]; >> + size_t buf_size; >> + int nr_skip = 0; >> + int ret = -1; >> + char *buf; >> + bfd *bfdf; >> + FILE *s; >> + >> + if (dso->binary_type != DSO_BINARY_TYPE__BPF_PROG_INFO) >> + return -1; >> + >> + pr_debug("%s: handling sym %s addr %lx len %lx\n", __func__, >> + sym->name, sym->start, sym->end - sym->start); >> + >> + memset(tpath, 0, sizeof(tpath)); >> + perf_exe(tpath, sizeof(tpath)); >> + >> + bfdf = bfd_openr(tpath, NULL); >> + assert(bfdf); >> + assert(bfd_check_format(bfdf, bfd_object)); >> + >> + s = open_memstream(&buf, &buf_size); >> + if (!s) >> + goto out; >> + init_disassemble_info(&info, s, >> + (fprintf_ftype) fprintf); >> + >> + info.arch = bfd_get_arch(bfdf); >> + info.mach = bfd_get_mach(bfdf); >> + >> + info_node = perf_env__find_bpf_prog_info(dso->bpf_prog.env, >> + dso->bpf_prog.id); >> + if (!info_node) >> + goto out; >> + info_linear = info_node->info_linear; >> + sub_id = dso->bpf_prog.sub_id; >> + >> + info.buffer = (void *)(info_linear->info.jited_prog_insns); >> + info.buffer_length = info_linear->info.jited_prog_len; >> + >> + if (info_linear->info.nr_line_info) >> + prog_linfo = bpf_prog_linfo__new(&info_linear->info); >> + >> + if (info_linear->info.btf_id) { >> + struct btf_node *node; >> + >> + node = perf_env__find_btf(dso->bpf_prog.env, >> + info_linear->info.btf_id); >> + if (node) >> + btf = btf__new((__u8 *)(node->data), >> + node->data_size); >> + } >> + >> + disassemble_init_for_target(&info); >> + >> +#ifdef DISASM_FOUR_ARGS_SIGNATURE >> + disassemble = disassembler(info.arch, >> + bfd_big_endian(bfdf), >> + info.mach, >> + bfdf); >> +#else >> + disassemble = disassembler(bfdf); >> +#endif >> + assert(disassemble); >> + >> + fflush(s); >> + do { >> + const struct bpf_line_info *linfo = NULL; >> + struct disasm_line *dl; >> + size_t prev_buf_size; >> + const char *srcline; >> + u64 addr; >> + >> + addr = pc + ((u64 *)(info_linear->info.jited_ksyms))[sub_id]; >> + count = disassemble(pc, &info); >> + >> + if (prog_linfo) >> + linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo, >> + addr, sub_id, >> + nr_skip); >> + >> + if (linfo && btf) { >> + srcline = btf__name_by_offset(btf, linfo->line_off); >> + nr_skip++; >> + } else >> + srcline = NULL; >> + >> + fprintf(s, "\n"); >> + prev_buf_size = buf_size; >> + fflush(s); >> + >> + if (!opts->hide_src_code && srcline) { >> + args->offset = -1; >> + args->line = strdup(srcline); >> + args->line_nr = 0; >> + args->ms.sym = sym; >> + dl = disasm_line__new(args); >> + if (dl) { >> + annotation_line__add(&dl->al, >> + ¬es->src->source); >> + } >> + } >> + >> + args->offset = pc; >> + args->line = buf + prev_buf_size; >> + args->line_nr = 0; >> + args->ms.sym = sym; >> + dl = disasm_line__new(args); >> + if (dl) >> + annotation_line__add(&dl->al, ¬es->src->source); >> + >> + pc += count; >> + } while (count > 0 && pc < len); >> + >> + ret = 0; >> +out: >> + free(prog_linfo); >> + free(btf); >> + fclose(s); >> + bfd_close(bfdf); >> + return ret; >> +} >> + >> static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) >> { >> struct annotation_options *opts = args->options; >> @@ -1701,7 +1847,9 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) >> pr_debug("annotating [%p] %30s : [%p] %30s\n", >> dso, dso->long_name, sym, sym->name); >> >> - if (dso__is_kcore(dso)) { >> + if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) { >> + return symbol__disassemble_bpf(sym, args); >> + } else if (dso__is_kcore(dso)) { >> kce.kcore_filename = symfs_filename; >> kce.addr = map__rip_2objdump(map, sym->start); >> kce.offs = sym->start; >> diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c >> index ba58ba603b69..58547c468c65 100644 >> --- a/tools/perf/util/dso.c >> +++ b/tools/perf/util/dso.c >> @@ -184,6 +184,7 @@ int dso__read_binary_type_filename(const struct dso *dso, >> case DSO_BINARY_TYPE__KALLSYMS: >> case DSO_BINARY_TYPE__GUEST_KALLSYMS: >> case DSO_BINARY_TYPE__JAVA_JIT: >> + case DSO_BINARY_TYPE__BPF_PROG_INFO: >> case DSO_BINARY_TYPE__NOT_FOUND: >> ret = -1; >> break; >> diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h >> index bb417c54c25a..c274b5aa839d 100644 >> --- a/tools/perf/util/dso.h >> +++ b/tools/perf/util/dso.h >> @@ -14,6 +14,7 @@ >> >> struct machine; >> struct map; >> +struct perf_env; >> >> enum dso_binary_type { >> DSO_BINARY_TYPE__KALLSYMS = 0, >> @@ -35,6 +36,7 @@ enum dso_binary_type { >> DSO_BINARY_TYPE__KCORE, >> DSO_BINARY_TYPE__GUEST_KCORE, >> DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, >> + DSO_BINARY_TYPE__BPF_PROG_INFO, >> DSO_BINARY_TYPE__NOT_FOUND, >> }; >> >> @@ -178,17 +180,25 @@ struct dso { >> struct auxtrace_cache *auxtrace_cache; >> int comp; >> >> - /* dso data file */ >> - struct { >> - struct rb_root cache; >> - int fd; >> - int status; >> - u32 status_seen; >> - size_t file_size; >> - struct list_head open_entry; >> - u64 debug_frame_offset; >> - u64 eh_frame_hdr_offset; >> - } data; >> + union { >> + /* dso data file */ >> + struct { >> + struct rb_root cache; >> + int fd; >> + int status; >> + u32 status_seen; >> + size_t file_size; >> + struct list_head open_entry; >> + u64 debug_frame_offset; >> + u64 eh_frame_hdr_offset; >> + } data; >> + /* bpf prog information */ >> + struct { >> + u32 id; >> + u32 sub_id; >> + struct perf_env *env; >> + } bpf_prog; >> + }; >> >> union { /* Tool specific area */ >> void *priv; >> diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c >> index 758bf5f74e6e..4e2e304d4037 100644 >> --- a/tools/perf/util/symbol.c >> +++ b/tools/perf/util/symbol.c >> @@ -1451,6 +1451,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, >> case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO: >> return true; >> >> + case DSO_BINARY_TYPE__BPF_PROG_INFO: >> case DSO_BINARY_TYPE__NOT_FOUND: >> default: >> return false; >> -- >> 2.17.1 > > -- > > - Arnaldo
> On Mar 18, 2019, at 9:43 AM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote: > > Em Mon, Mar 18, 2019 at 01:38:48PM -0300, Arnaldo Carvalho de Melo escreveu: >> Em Mon, Mar 11, 2019 at 10:30:48PM -0700, Song Liu escreveu: >>> This patch enables the annotation of bpf program. >>> >>> A new dso type DSO_BINARY_TYPE__BPF_PROG_INFO is introduced to for BPF >>> programs. In symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso >>> calls into a new function symbol__disassemble_bpf(), where annotation >>> line information is filled based bpf_prog_info and btf saved in given >>> perf_env. >>> >>> symbol__disassemble_bpf() uses libbfd to disassemble bpf programs. >>> >>> Signed-off-by: Song Liu <songliubraving@fb.com> >>> --- >>> tools/build/Makefile.feature | 6 +- >>> tools/perf/Makefile.config | 4 + >> >> I see the changes to these two files, but I can't see the feature test >> that it triggers, forgot to do a git-add? Or is it in an upcoming patch >> in this series? >> >> After applying this test it "works": >> >> make: Entering directory '/home/acme/git/perf/tools/perf' >> BUILD: Doing 'make -j8' parallel build >> >> Auto-detecting system features: >> ... dwarf: [ on ] >> ... dwarf_getlocations: [ on ] >> <SNIP> >> ... bpf: [ on ] >> ... libaio: [ on ] >> ... disassembler-four-args: [ on ] >> >> Because you added it to FEATURE_TESTS_BASIC, and this means that if >> tools/build/feature/test-all.c builds, then what is in >> FEATURE_TESTS_BASIC is set to 'on', but you didn't add anything to >> tools/build/feature/test-all.c, so it works because all the other >> features are present. >> >> Take a look at: >> >> 2a07d814747b ("tools build feature: Check if libaio is available") >> >> To see what needs to be done. >> >> Either way, its interesting to break this patch in two, one adding the >> feature test and another to use it, i.e. the second patch out of this >> should have the commit log message in this patch. >> >> I've applied the patches up to before this one and will continue >> processing other patches while you address this. > > Ok, to continue processing the other patches I chunked out the part > below into a 3rd patch from the above one and have it applied already. Could you please push applied patches to the tmp.perf/bpf-annotation branch? Thanks, Song > > commit f326de312abc3657b0397817c66cd7e1540655f7 > Author: Song Liu <songliubraving@fb.com> > Date: Mon Mar 11 22:30:48 2019 -0700 > > perf symbols: Introduce DSO_BINARY_TYPE__BPF_PROG_INFO > > Introduce a new dso type DSO_BINARY_TYPE__BPF_PROG_INFO for BPF programs. In > symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso will call into a new > function symbol__disassemble_bpf() in an upcoming patch, where annotation line > information is filled based bpf_prog_info and btf saved in given perf_env. > > Signed-off-by: Song Liu <songliubraving@fb.com> > Reviewed-by: Jiri Olsa <jolsa@kernel.org> > Cc: Alexei Starovoitov <ast@kernel.org> > Cc: Daniel Borkmann <daniel@iogearbox.net> > Cc: Namhyung Kim <namhyung@kernel.org> > Cc: Peter Zijlstra <peterz@infradead.org> > Cc: Stanislav Fomichev <sdf@google.com> > Cc: kernel-team@fb.com > Link: http://lkml.kernel.org/r/20190312053051.2690567-13-songliubraving@fb.com > [ split from a larger patch ] > Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> > > diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c > index ba58ba603b69..58547c468c65 100644 > --- a/tools/perf/util/dso.c > +++ b/tools/perf/util/dso.c > @@ -184,6 +184,7 @@ int dso__read_binary_type_filename(const struct dso *dso, > case DSO_BINARY_TYPE__KALLSYMS: > case DSO_BINARY_TYPE__GUEST_KALLSYMS: > case DSO_BINARY_TYPE__JAVA_JIT: > + case DSO_BINARY_TYPE__BPF_PROG_INFO: > case DSO_BINARY_TYPE__NOT_FOUND: > ret = -1; > break; > diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h > index bb417c54c25a..c274b5aa839d 100644 > --- a/tools/perf/util/dso.h > +++ b/tools/perf/util/dso.h > @@ -14,6 +14,7 @@ > > struct machine; > struct map; > +struct perf_env; > > enum dso_binary_type { > DSO_BINARY_TYPE__KALLSYMS = 0, > @@ -35,6 +36,7 @@ enum dso_binary_type { > DSO_BINARY_TYPE__KCORE, > DSO_BINARY_TYPE__GUEST_KCORE, > DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, > + DSO_BINARY_TYPE__BPF_PROG_INFO, > DSO_BINARY_TYPE__NOT_FOUND, > }; > > @@ -178,17 +180,25 @@ struct dso { > struct auxtrace_cache *auxtrace_cache; > int comp; > > - /* dso data file */ > - struct { > - struct rb_root cache; > - int fd; > - int status; > - u32 status_seen; > - size_t file_size; > - struct list_head open_entry; > - u64 debug_frame_offset; > - u64 eh_frame_hdr_offset; > - } data; > + union { > + /* dso data file */ > + struct { > + struct rb_root cache; > + int fd; > + int status; > + u32 status_seen; > + size_t file_size; > + struct list_head open_entry; > + u64 debug_frame_offset; > + u64 eh_frame_hdr_offset; > + } data; > + /* bpf prog information */ > + struct { > + u32 id; > + u32 sub_id; > + struct perf_env *env; > + } bpf_prog; > + }; > > union { /* Tool specific area */ > void *priv; > diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c > index 58442ca5e3c4..5cbad55cd99d 100644 > --- a/tools/perf/util/symbol.c > +++ b/tools/perf/util/symbol.c > @@ -1455,6 +1455,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, > case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO: > return true; > > + case DSO_BINARY_TYPE__BPF_PROG_INFO: > case DSO_BINARY_TYPE__NOT_FOUND: > default: > return false;
Em Tue, Mar 19, 2019 at 06:05:30AM +0000, Song Liu escreveu: > Sorry for the late response. > > > On Mar 18, 2019, at 9:38 AM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote: > > > > Em Mon, Mar 11, 2019 at 10:30:48PM -0700, Song Liu escreveu: > >> This patch enables the annotation of bpf program. > >> > >> A new dso type DSO_BINARY_TYPE__BPF_PROG_INFO is introduced to for BPF > >> programs. In symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso > >> calls into a new function symbol__disassemble_bpf(), where annotation > >> line information is filled based bpf_prog_info and btf saved in given > >> perf_env. > >> > >> symbol__disassemble_bpf() uses libbfd to disassemble bpf programs. > >> > >> Signed-off-by: Song Liu <songliubraving@fb.com> > >> --- > >> tools/build/Makefile.feature | 6 +- > >> tools/perf/Makefile.config | 4 + > > > > I see the changes to these two files, but I can't see the feature test > > that it triggers, forgot to do a git-add? Or is it in an upcoming patch > > in this series? > > test-disassembler-four-args.c is an existing test used by bpftool. > It was added in fb982666e380c1632a74495b68b3c33a66e76430 . Ok, I'll add that to the commit log message, but see below > > > > After applying this test it "works": > > > > make: Entering directory '/home/acme/git/perf/tools/perf' > > BUILD: Doing 'make -j8' parallel build > > > > Auto-detecting system features: > > ... dwarf: [ on ] > > ... dwarf_getlocations: [ on ] > > <SNIP> > > ... bpf: [ on ] > > ... libaio: [ on ] > > ... disassembler-four-args: [ on ] > > > > Because you added it to FEATURE_TESTS_BASIC, and this means that if > > tools/build/feature/test-all.c builds, then what is in > > FEATURE_TESTS_BASIC is set to 'on', but you didn't add anything to > > tools/build/feature/test-all.c, so it works because all the other > > features are present. > > > > Take a look at: > > > > 2a07d814747b ("tools build feature: Check if libaio is available") > > > > To see what needs to be done. > > I used different versions of gcc to verify that current version of the > patch works for both test-succeed and test-fail cases. I guess something > like the following is needed? But the test does work without it. The following is definetely needed, otherwise if all the other tests in test-all.c works, this disassembler-four-args feature test will never be performed. - Arnaldo > diff --git i/tools/build/feature/test-all.c w/tools/build/feature/test-all.c > index e903b86b742f..7853e6d91090 100644 > --- i/tools/build/feature/test-all.c > +++ w/tools/build/feature/test-all.c > @@ -178,6 +178,10 @@ > # include "test-reallocarray.c" > #undef main > > +#define main main_test_disassembler_four_args > +# include "test-disassembler-four-args.c" > +#undef main > + > int main(int argc, char *argv[]) > { > main_test_libpython(); > @@ -219,6 +223,7 @@ int main(int argc, char *argv[]) > main_test_setns(); > main_test_libaio(); > main_test_reallocarray(); > + main_test_disassembler_four_args(); > > return 0; > } > > > > > > Either way, its interesting to break this patch in two, one adding the > > feature test and another to use it, i.e. the second patch out of this > > should have the commit log message in this patch. > > > > I've applied the patches up to before this one and will continue > > processing other patches while you address this. > > > > Thanks, > > > > - Arnaldo > > > >> tools/perf/util/annotate.c | 150 ++++++++++++++++++++++++++++++++++- > >> tools/perf/util/dso.c | 1 + > >> tools/perf/util/dso.h | 32 +++++--- > >> tools/perf/util/symbol.c | 1 + > >> 6 files changed, 180 insertions(+), 14 deletions(-) > >> > >> diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature > >> index 61e46d54a67c..8d3864b061f3 100644 > >> --- a/tools/build/Makefile.feature > >> +++ b/tools/build/Makefile.feature > >> @@ -66,7 +66,8 @@ FEATURE_TESTS_BASIC := \ > >> sched_getcpu \ > >> sdt \ > >> setns \ > >> - libaio > >> + libaio \ > >> + disassembler-four-args > >> > >> # FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list > >> # of all feature tests > >> @@ -118,7 +119,8 @@ FEATURE_DISPLAY ?= \ > >> lzma \ > >> get_cpuid \ > >> bpf \ > >> - libaio > >> + libaio \ > >> + disassembler-four-args > >> > >> # Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features. > >> # If in the future we need per-feature checks/flags for features not > >> diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config > >> index df4ad45599ca..c51b59e43dcc 100644 > >> --- a/tools/perf/Makefile.config > >> +++ b/tools/perf/Makefile.config > >> @@ -808,6 +808,10 @@ ifdef HAVE_KVM_STAT_SUPPORT > >> CFLAGS += -DHAVE_KVM_STAT_SUPPORT > >> endif > >> > >> +ifeq ($(feature-disassembler-four-args), 1) > >> + CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE > >> +endif > >> + > >> ifeq (${IS_64_BIT}, 1) > >> ifndef NO_PERF_READ_VDSO32 > >> $(call feature_check,compile-32) > >> diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c > >> index 5f6dbbf5d749..e492b19a157c 100644 > >> --- a/tools/perf/util/annotate.c > >> +++ b/tools/perf/util/annotate.c > >> @@ -10,6 +10,10 @@ > >> #include <errno.h> > >> #include <inttypes.h> > >> #include <libgen.h> > >> +#include <bpf/bpf.h> > >> +#include <bpf/btf.h> > >> +#include <bpf/libbpf.h> > >> +#include <linux/btf.h> > >> #include "util.h" > >> #include "ui/ui.h" > >> #include "sort.h" > >> @@ -24,6 +28,7 @@ > >> #include "annotate.h" > >> #include "evsel.h" > >> #include "evlist.h" > >> +#include "bpf-event.h" > >> #include "block-range.h" > >> #include "string2.h" > >> #include "arch/common.h" > >> @@ -31,6 +36,9 @@ > >> #include <pthread.h> > >> #include <linux/bitops.h> > >> #include <linux/kernel.h> > >> +#include <bfd.h> > >> +#include <dis-asm.h> > >> +#include <bpf/libbpf.h> > >> > >> /* FIXME: For the HE_COLORSET */ > >> #include "ui/browser.h" > >> @@ -1674,6 +1682,144 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil > >> return 0; > >> } > >> > >> +static int symbol__disassemble_bpf(struct symbol *sym, > >> + struct annotate_args *args) > >> +{ > >> + struct annotation *notes = symbol__annotation(sym); > >> + struct annotation_options *opts = args->options; > >> + struct bpf_prog_info_linear *info_linear; > >> + struct bpf_prog_linfo *prog_linfo = NULL; > >> + struct bpf_prog_info_node *info_node; > >> + int len = sym->end - sym->start; > >> + disassembler_ftype disassemble; > >> + struct map *map = args->ms.map; > >> + struct disassemble_info info; > >> + struct dso *dso = map->dso; > >> + int pc = 0, count, sub_id; > >> + struct btf *btf = NULL; > >> + char tpath[PATH_MAX]; > >> + size_t buf_size; > >> + int nr_skip = 0; > >> + int ret = -1; > >> + char *buf; > >> + bfd *bfdf; > >> + FILE *s; > >> + > >> + if (dso->binary_type != DSO_BINARY_TYPE__BPF_PROG_INFO) > >> + return -1; > >> + > >> + pr_debug("%s: handling sym %s addr %lx len %lx\n", __func__, > >> + sym->name, sym->start, sym->end - sym->start); > >> + > >> + memset(tpath, 0, sizeof(tpath)); > >> + perf_exe(tpath, sizeof(tpath)); > >> + > >> + bfdf = bfd_openr(tpath, NULL); > >> + assert(bfdf); > >> + assert(bfd_check_format(bfdf, bfd_object)); > >> + > >> + s = open_memstream(&buf, &buf_size); > >> + if (!s) > >> + goto out; > >> + init_disassemble_info(&info, s, > >> + (fprintf_ftype) fprintf); > >> + > >> + info.arch = bfd_get_arch(bfdf); > >> + info.mach = bfd_get_mach(bfdf); > >> + > >> + info_node = perf_env__find_bpf_prog_info(dso->bpf_prog.env, > >> + dso->bpf_prog.id); > >> + if (!info_node) > >> + goto out; > >> + info_linear = info_node->info_linear; > >> + sub_id = dso->bpf_prog.sub_id; > >> + > >> + info.buffer = (void *)(info_linear->info.jited_prog_insns); > >> + info.buffer_length = info_linear->info.jited_prog_len; > >> + > >> + if (info_linear->info.nr_line_info) > >> + prog_linfo = bpf_prog_linfo__new(&info_linear->info); > >> + > >> + if (info_linear->info.btf_id) { > >> + struct btf_node *node; > >> + > >> + node = perf_env__find_btf(dso->bpf_prog.env, > >> + info_linear->info.btf_id); > >> + if (node) > >> + btf = btf__new((__u8 *)(node->data), > >> + node->data_size); > >> + } > >> + > >> + disassemble_init_for_target(&info); > >> + > >> +#ifdef DISASM_FOUR_ARGS_SIGNATURE > >> + disassemble = disassembler(info.arch, > >> + bfd_big_endian(bfdf), > >> + info.mach, > >> + bfdf); > >> +#else > >> + disassemble = disassembler(bfdf); > >> +#endif > >> + assert(disassemble); > >> + > >> + fflush(s); > >> + do { > >> + const struct bpf_line_info *linfo = NULL; > >> + struct disasm_line *dl; > >> + size_t prev_buf_size; > >> + const char *srcline; > >> + u64 addr; > >> + > >> + addr = pc + ((u64 *)(info_linear->info.jited_ksyms))[sub_id]; > >> + count = disassemble(pc, &info); > >> + > >> + if (prog_linfo) > >> + linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo, > >> + addr, sub_id, > >> + nr_skip); > >> + > >> + if (linfo && btf) { > >> + srcline = btf__name_by_offset(btf, linfo->line_off); > >> + nr_skip++; > >> + } else > >> + srcline = NULL; > >> + > >> + fprintf(s, "\n"); > >> + prev_buf_size = buf_size; > >> + fflush(s); > >> + > >> + if (!opts->hide_src_code && srcline) { > >> + args->offset = -1; > >> + args->line = strdup(srcline); > >> + args->line_nr = 0; > >> + args->ms.sym = sym; > >> + dl = disasm_line__new(args); > >> + if (dl) { > >> + annotation_line__add(&dl->al, > >> + ¬es->src->source); > >> + } > >> + } > >> + > >> + args->offset = pc; > >> + args->line = buf + prev_buf_size; > >> + args->line_nr = 0; > >> + args->ms.sym = sym; > >> + dl = disasm_line__new(args); > >> + if (dl) > >> + annotation_line__add(&dl->al, ¬es->src->source); > >> + > >> + pc += count; > >> + } while (count > 0 && pc < len); > >> + > >> + ret = 0; > >> +out: > >> + free(prog_linfo); > >> + free(btf); > >> + fclose(s); > >> + bfd_close(bfdf); > >> + return ret; > >> +} > >> + > >> static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) > >> { > >> struct annotation_options *opts = args->options; > >> @@ -1701,7 +1847,9 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) > >> pr_debug("annotating [%p] %30s : [%p] %30s\n", > >> dso, dso->long_name, sym, sym->name); > >> > >> - if (dso__is_kcore(dso)) { > >> + if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) { > >> + return symbol__disassemble_bpf(sym, args); > >> + } else if (dso__is_kcore(dso)) { > >> kce.kcore_filename = symfs_filename; > >> kce.addr = map__rip_2objdump(map, sym->start); > >> kce.offs = sym->start; > >> diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c > >> index ba58ba603b69..58547c468c65 100644 > >> --- a/tools/perf/util/dso.c > >> +++ b/tools/perf/util/dso.c > >> @@ -184,6 +184,7 @@ int dso__read_binary_type_filename(const struct dso *dso, > >> case DSO_BINARY_TYPE__KALLSYMS: > >> case DSO_BINARY_TYPE__GUEST_KALLSYMS: > >> case DSO_BINARY_TYPE__JAVA_JIT: > >> + case DSO_BINARY_TYPE__BPF_PROG_INFO: > >> case DSO_BINARY_TYPE__NOT_FOUND: > >> ret = -1; > >> break; > >> diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h > >> index bb417c54c25a..c274b5aa839d 100644 > >> --- a/tools/perf/util/dso.h > >> +++ b/tools/perf/util/dso.h > >> @@ -14,6 +14,7 @@ > >> > >> struct machine; > >> struct map; > >> +struct perf_env; > >> > >> enum dso_binary_type { > >> DSO_BINARY_TYPE__KALLSYMS = 0, > >> @@ -35,6 +36,7 @@ enum dso_binary_type { > >> DSO_BINARY_TYPE__KCORE, > >> DSO_BINARY_TYPE__GUEST_KCORE, > >> DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, > >> + DSO_BINARY_TYPE__BPF_PROG_INFO, > >> DSO_BINARY_TYPE__NOT_FOUND, > >> }; > >> > >> @@ -178,17 +180,25 @@ struct dso { > >> struct auxtrace_cache *auxtrace_cache; > >> int comp; > >> > >> - /* dso data file */ > >> - struct { > >> - struct rb_root cache; > >> - int fd; > >> - int status; > >> - u32 status_seen; > >> - size_t file_size; > >> - struct list_head open_entry; > >> - u64 debug_frame_offset; > >> - u64 eh_frame_hdr_offset; > >> - } data; > >> + union { > >> + /* dso data file */ > >> + struct { > >> + struct rb_root cache; > >> + int fd; > >> + int status; > >> + u32 status_seen; > >> + size_t file_size; > >> + struct list_head open_entry; > >> + u64 debug_frame_offset; > >> + u64 eh_frame_hdr_offset; > >> + } data; > >> + /* bpf prog information */ > >> + struct { > >> + u32 id; > >> + u32 sub_id; > >> + struct perf_env *env; > >> + } bpf_prog; > >> + }; > >> > >> union { /* Tool specific area */ > >> void *priv; > >> diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c > >> index 758bf5f74e6e..4e2e304d4037 100644 > >> --- a/tools/perf/util/symbol.c > >> +++ b/tools/perf/util/symbol.c > >> @@ -1451,6 +1451,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, > >> case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO: > >> return true; > >> > >> + case DSO_BINARY_TYPE__BPF_PROG_INFO: > >> case DSO_BINARY_TYPE__NOT_FOUND: > >> default: > >> return false; > >> -- > >> 2.17.1 > > > > -- > > > > - Arnaldo
Em Tue, Mar 19, 2019 at 06:10:42AM +0000, Song Liu escreveu: > > > > On Mar 18, 2019, at 9:43 AM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote: > > > > Em Mon, Mar 18, 2019 at 01:38:48PM -0300, Arnaldo Carvalho de Melo escreveu: > >> Em Mon, Mar 11, 2019 at 10:30:48PM -0700, Song Liu escreveu: > >>> This patch enables the annotation of bpf program. > >>> > >>> A new dso type DSO_BINARY_TYPE__BPF_PROG_INFO is introduced to for BPF > >>> programs. In symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso > >>> calls into a new function symbol__disassemble_bpf(), where annotation > >>> line information is filled based bpf_prog_info and btf saved in given > >>> perf_env. > >>> > >>> symbol__disassemble_bpf() uses libbfd to disassemble bpf programs. > >>> > >>> Signed-off-by: Song Liu <songliubraving@fb.com> > >>> --- > >>> tools/build/Makefile.feature | 6 +- > >>> tools/perf/Makefile.config | 4 + > >> > >> I see the changes to these two files, but I can't see the feature test > >> that it triggers, forgot to do a git-add? Or is it in an upcoming patch > >> in this series? > >> > >> After applying this test it "works": > >> > >> make: Entering directory '/home/acme/git/perf/tools/perf' > >> BUILD: Doing 'make -j8' parallel build > >> > >> Auto-detecting system features: > >> ... dwarf: [ on ] > >> ... dwarf_getlocations: [ on ] > >> <SNIP> > >> ... bpf: [ on ] > >> ... libaio: [ on ] > >> ... disassembler-four-args: [ on ] > >> > >> Because you added it to FEATURE_TESTS_BASIC, and this means that if > >> tools/build/feature/test-all.c builds, then what is in > >> FEATURE_TESTS_BASIC is set to 'on', but you didn't add anything to > >> tools/build/feature/test-all.c, so it works because all the other > >> features are present. > >> > >> Take a look at: > >> > >> 2a07d814747b ("tools build feature: Check if libaio is available") > >> > >> To see what needs to be done. > >> > >> Either way, its interesting to break this patch in two, one adding the > >> feature test and another to use it, i.e. the second patch out of this > >> should have the commit log message in this patch. > >> > >> I've applied the patches up to before this one and will continue > >> processing other patches while you address this. > > > > Ok, to continue processing the other patches I chunked out the part > > below into a 3rd patch from the above one and have it applied already. > > Could you please push applied patches to the tmp.perf/bpf-annotation > branch? It is in my perf/core branch already. > Thanks, > Song > > > > > commit f326de312abc3657b0397817c66cd7e1540655f7 > > Author: Song Liu <songliubraving@fb.com> > > Date: Mon Mar 11 22:30:48 2019 -0700 > > > > perf symbols: Introduce DSO_BINARY_TYPE__BPF_PROG_INFO > > > > Introduce a new dso type DSO_BINARY_TYPE__BPF_PROG_INFO for BPF programs. In > > symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso will call into a new > > function symbol__disassemble_bpf() in an upcoming patch, where annotation line > > information is filled based bpf_prog_info and btf saved in given perf_env. > > > > Signed-off-by: Song Liu <songliubraving@fb.com> > > Reviewed-by: Jiri Olsa <jolsa@kernel.org> > > Cc: Alexei Starovoitov <ast@kernel.org> > > Cc: Daniel Borkmann <daniel@iogearbox.net> > > Cc: Namhyung Kim <namhyung@kernel.org> > > Cc: Peter Zijlstra <peterz@infradead.org> > > Cc: Stanislav Fomichev <sdf@google.com> > > Cc: kernel-team@fb.com > > Link: http://lkml.kernel.org/r/20190312053051.2690567-13-songliubraving@fb.com > > [ split from a larger patch ] > > Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> > > > > diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c > > index ba58ba603b69..58547c468c65 100644 > > --- a/tools/perf/util/dso.c > > +++ b/tools/perf/util/dso.c > > @@ -184,6 +184,7 @@ int dso__read_binary_type_filename(const struct dso *dso, > > case DSO_BINARY_TYPE__KALLSYMS: > > case DSO_BINARY_TYPE__GUEST_KALLSYMS: > > case DSO_BINARY_TYPE__JAVA_JIT: > > + case DSO_BINARY_TYPE__BPF_PROG_INFO: > > case DSO_BINARY_TYPE__NOT_FOUND: > > ret = -1; > > break; > > diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h > > index bb417c54c25a..c274b5aa839d 100644 > > --- a/tools/perf/util/dso.h > > +++ b/tools/perf/util/dso.h > > @@ -14,6 +14,7 @@ > > > > struct machine; > > struct map; > > +struct perf_env; > > > > enum dso_binary_type { > > DSO_BINARY_TYPE__KALLSYMS = 0, > > @@ -35,6 +36,7 @@ enum dso_binary_type { > > DSO_BINARY_TYPE__KCORE, > > DSO_BINARY_TYPE__GUEST_KCORE, > > DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, > > + DSO_BINARY_TYPE__BPF_PROG_INFO, > > DSO_BINARY_TYPE__NOT_FOUND, > > }; > > > > @@ -178,17 +180,25 @@ struct dso { > > struct auxtrace_cache *auxtrace_cache; > > int comp; > > > > - /* dso data file */ > > - struct { > > - struct rb_root cache; > > - int fd; > > - int status; > > - u32 status_seen; > > - size_t file_size; > > - struct list_head open_entry; > > - u64 debug_frame_offset; > > - u64 eh_frame_hdr_offset; > > - } data; > > + union { > > + /* dso data file */ > > + struct { > > + struct rb_root cache; > > + int fd; > > + int status; > > + u32 status_seen; > > + size_t file_size; > > + struct list_head open_entry; > > + u64 debug_frame_offset; > > + u64 eh_frame_hdr_offset; > > + } data; > > + /* bpf prog information */ > > + struct { > > + u32 id; > > + u32 sub_id; > > + struct perf_env *env; > > + } bpf_prog; > > + }; > > > > union { /* Tool specific area */ > > void *priv; > > diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c > > index 58442ca5e3c4..5cbad55cd99d 100644 > > --- a/tools/perf/util/symbol.c > > +++ b/tools/perf/util/symbol.c > > @@ -1455,6 +1455,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, > > case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO: > > return true; > > > > + case DSO_BINARY_TYPE__BPF_PROG_INFO: > > case DSO_BINARY_TYPE__NOT_FOUND: > > default: > > return false;
Em Tue, Mar 19, 2019 at 06:05:30AM +0000, Song Liu escreveu: > Sorry for the late response. > > > On Mar 18, 2019, at 9:38 AM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote: > > > > Em Mon, Mar 11, 2019 at 10:30:48PM -0700, Song Liu escreveu: > >> This patch enables the annotation of bpf program. > >> > >> A new dso type DSO_BINARY_TYPE__BPF_PROG_INFO is introduced to for BPF > >> programs. In symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso > >> calls into a new function symbol__disassemble_bpf(), where annotation > >> line information is filled based bpf_prog_info and btf saved in given > >> perf_env. > >> > >> symbol__disassemble_bpf() uses libbfd to disassemble bpf programs. > >> > >> Signed-off-by: Song Liu <songliubraving@fb.com> > >> --- > >> tools/build/Makefile.feature | 6 +- > >> tools/perf/Makefile.config | 4 + > > > > I see the changes to these two files, but I can't see the feature test > > that it triggers, forgot to do a git-add? Or is it in an upcoming patch > > in this series? > > test-disassembler-four-args.c is an existing test used by bpftool. > It was added in fb982666e380c1632a74495b68b3c33a66e76430 . > > > > > After applying this test it "works": > > > > make: Entering directory '/home/acme/git/perf/tools/perf' > > BUILD: Doing 'make -j8' parallel build > > > > Auto-detecting system features: > > ... dwarf: [ on ] > > ... dwarf_getlocations: [ on ] > > <SNIP> > > ... bpf: [ on ] > > ... libaio: [ on ] > > ... disassembler-four-args: [ on ] > > > > Because you added it to FEATURE_TESTS_BASIC, and this means that if > > tools/build/feature/test-all.c builds, then what is in > > FEATURE_TESTS_BASIC is set to 'on', but you didn't add anything to > > tools/build/feature/test-all.c, so it works because all the other > > features are present. > > > > Take a look at: > > > > 2a07d814747b ("tools build feature: Check if libaio is available") > > > > To see what needs to be done. > > I used different versions of gcc to verify that current version of the > patch works for both test-succeed and test-fail cases. I guess something > like the following is needed? But the test does work without it. Even with the file below, it fails, as: [acme@quaco perf]$ cat /tmp/build/perf/feature/test-all.make.output /usr/bin/ld: /tmp/ccTj7iV6.o: in function `main_test_disassembler_four_args': /home/acme/git/perf/tools/build/feature/test-disassembler-four-args.c:9: undefined reference to `disassembler' collect2: error: ld returned 1 exit status [acme@quaco perf]$ Then we do the test for each of the features and _then_ this works: [acme@quaco perf]$ ls -la /tmp/build/perf/feature/test-disassembler-four-args.* -rwxrwxr-x. 1 acme acme 2098312 Mar 19 10:51 /tmp/build/perf/feature/test-disassembler-four-args.bin -rw-rw-r--. 1 acme acme 1079 Mar 19 10:51 /tmp/build/perf/feature/test-disassembler-four-args.d -rw-rw-r--. 1 acme acme 0 Mar 19 10:51 /tmp/build/perf/feature/test-disassembler-four-args.make.output [acme@quaco perf]$ So there is still something missing, i.e. which objects to add to the test-all case, I'll fix it. > Thanks, > Song > > > diff --git i/tools/build/feature/test-all.c w/tools/build/feature/test-all.c > index e903b86b742f..7853e6d91090 100644 > --- i/tools/build/feature/test-all.c > +++ w/tools/build/feature/test-all.c > @@ -178,6 +178,10 @@ > # include "test-reallocarray.c" > #undef main > > +#define main main_test_disassembler_four_args > +# include "test-disassembler-four-args.c" > +#undef main > + > int main(int argc, char *argv[]) > { > main_test_libpython(); > @@ -219,6 +223,7 @@ int main(int argc, char *argv[]) > main_test_setns(); > main_test_libaio(); > main_test_reallocarray(); > + main_test_disassembler_four_args(); > > return 0; > } > > > > > > Either way, its interesting to break this patch in two, one adding the > > feature test and another to use it, i.e. the second patch out of this > > should have the commit log message in this patch. > > > > I've applied the patches up to before this one and will continue > > processing other patches while you address this. > > > > Thanks, > > > > - Arnaldo > > > >> tools/perf/util/annotate.c | 150 ++++++++++++++++++++++++++++++++++- > >> tools/perf/util/dso.c | 1 + > >> tools/perf/util/dso.h | 32 +++++--- > >> tools/perf/util/symbol.c | 1 + > >> 6 files changed, 180 insertions(+), 14 deletions(-) > >> > >> diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature > >> index 61e46d54a67c..8d3864b061f3 100644 > >> --- a/tools/build/Makefile.feature > >> +++ b/tools/build/Makefile.feature > >> @@ -66,7 +66,8 @@ FEATURE_TESTS_BASIC := \ > >> sched_getcpu \ > >> sdt \ > >> setns \ > >> - libaio > >> + libaio \ > >> + disassembler-four-args > >> > >> # FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list > >> # of all feature tests > >> @@ -118,7 +119,8 @@ FEATURE_DISPLAY ?= \ > >> lzma \ > >> get_cpuid \ > >> bpf \ > >> - libaio > >> + libaio \ > >> + disassembler-four-args > >> > >> # Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features. > >> # If in the future we need per-feature checks/flags for features not > >> diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config > >> index df4ad45599ca..c51b59e43dcc 100644 > >> --- a/tools/perf/Makefile.config > >> +++ b/tools/perf/Makefile.config > >> @@ -808,6 +808,10 @@ ifdef HAVE_KVM_STAT_SUPPORT > >> CFLAGS += -DHAVE_KVM_STAT_SUPPORT > >> endif > >> > >> +ifeq ($(feature-disassembler-four-args), 1) > >> + CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE > >> +endif > >> + > >> ifeq (${IS_64_BIT}, 1) > >> ifndef NO_PERF_READ_VDSO32 > >> $(call feature_check,compile-32) > >> diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c > >> index 5f6dbbf5d749..e492b19a157c 100644 > >> --- a/tools/perf/util/annotate.c > >> +++ b/tools/perf/util/annotate.c > >> @@ -10,6 +10,10 @@ > >> #include <errno.h> > >> #include <inttypes.h> > >> #include <libgen.h> > >> +#include <bpf/bpf.h> > >> +#include <bpf/btf.h> > >> +#include <bpf/libbpf.h> > >> +#include <linux/btf.h> > >> #include "util.h" > >> #include "ui/ui.h" > >> #include "sort.h" > >> @@ -24,6 +28,7 @@ > >> #include "annotate.h" > >> #include "evsel.h" > >> #include "evlist.h" > >> +#include "bpf-event.h" > >> #include "block-range.h" > >> #include "string2.h" > >> #include "arch/common.h" > >> @@ -31,6 +36,9 @@ > >> #include <pthread.h> > >> #include <linux/bitops.h> > >> #include <linux/kernel.h> > >> +#include <bfd.h> > >> +#include <dis-asm.h> > >> +#include <bpf/libbpf.h> > >> > >> /* FIXME: For the HE_COLORSET */ > >> #include "ui/browser.h" > >> @@ -1674,6 +1682,144 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil > >> return 0; > >> } > >> > >> +static int symbol__disassemble_bpf(struct symbol *sym, > >> + struct annotate_args *args) > >> +{ > >> + struct annotation *notes = symbol__annotation(sym); > >> + struct annotation_options *opts = args->options; > >> + struct bpf_prog_info_linear *info_linear; > >> + struct bpf_prog_linfo *prog_linfo = NULL; > >> + struct bpf_prog_info_node *info_node; > >> + int len = sym->end - sym->start; > >> + disassembler_ftype disassemble; > >> + struct map *map = args->ms.map; > >> + struct disassemble_info info; > >> + struct dso *dso = map->dso; > >> + int pc = 0, count, sub_id; > >> + struct btf *btf = NULL; > >> + char tpath[PATH_MAX]; > >> + size_t buf_size; > >> + int nr_skip = 0; > >> + int ret = -1; > >> + char *buf; > >> + bfd *bfdf; > >> + FILE *s; > >> + > >> + if (dso->binary_type != DSO_BINARY_TYPE__BPF_PROG_INFO) > >> + return -1; > >> + > >> + pr_debug("%s: handling sym %s addr %lx len %lx\n", __func__, > >> + sym->name, sym->start, sym->end - sym->start); > >> + > >> + memset(tpath, 0, sizeof(tpath)); > >> + perf_exe(tpath, sizeof(tpath)); > >> + > >> + bfdf = bfd_openr(tpath, NULL); > >> + assert(bfdf); > >> + assert(bfd_check_format(bfdf, bfd_object)); > >> + > >> + s = open_memstream(&buf, &buf_size); > >> + if (!s) > >> + goto out; > >> + init_disassemble_info(&info, s, > >> + (fprintf_ftype) fprintf); > >> + > >> + info.arch = bfd_get_arch(bfdf); > >> + info.mach = bfd_get_mach(bfdf); > >> + > >> + info_node = perf_env__find_bpf_prog_info(dso->bpf_prog.env, > >> + dso->bpf_prog.id); > >> + if (!info_node) > >> + goto out; > >> + info_linear = info_node->info_linear; > >> + sub_id = dso->bpf_prog.sub_id; > >> + > >> + info.buffer = (void *)(info_linear->info.jited_prog_insns); > >> + info.buffer_length = info_linear->info.jited_prog_len; > >> + > >> + if (info_linear->info.nr_line_info) > >> + prog_linfo = bpf_prog_linfo__new(&info_linear->info); > >> + > >> + if (info_linear->info.btf_id) { > >> + struct btf_node *node; > >> + > >> + node = perf_env__find_btf(dso->bpf_prog.env, > >> + info_linear->info.btf_id); > >> + if (node) > >> + btf = btf__new((__u8 *)(node->data), > >> + node->data_size); > >> + } > >> + > >> + disassemble_init_for_target(&info); > >> + > >> +#ifdef DISASM_FOUR_ARGS_SIGNATURE > >> + disassemble = disassembler(info.arch, > >> + bfd_big_endian(bfdf), > >> + info.mach, > >> + bfdf); > >> +#else > >> + disassemble = disassembler(bfdf); > >> +#endif > >> + assert(disassemble); > >> + > >> + fflush(s); > >> + do { > >> + const struct bpf_line_info *linfo = NULL; > >> + struct disasm_line *dl; > >> + size_t prev_buf_size; > >> + const char *srcline; > >> + u64 addr; > >> + > >> + addr = pc + ((u64 *)(info_linear->info.jited_ksyms))[sub_id]; > >> + count = disassemble(pc, &info); > >> + > >> + if (prog_linfo) > >> + linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo, > >> + addr, sub_id, > >> + nr_skip); > >> + > >> + if (linfo && btf) { > >> + srcline = btf__name_by_offset(btf, linfo->line_off); > >> + nr_skip++; > >> + } else > >> + srcline = NULL; > >> + > >> + fprintf(s, "\n"); > >> + prev_buf_size = buf_size; > >> + fflush(s); > >> + > >> + if (!opts->hide_src_code && srcline) { > >> + args->offset = -1; > >> + args->line = strdup(srcline); > >> + args->line_nr = 0; > >> + args->ms.sym = sym; > >> + dl = disasm_line__new(args); > >> + if (dl) { > >> + annotation_line__add(&dl->al, > >> + ¬es->src->source); > >> + } > >> + } > >> + > >> + args->offset = pc; > >> + args->line = buf + prev_buf_size; > >> + args->line_nr = 0; > >> + args->ms.sym = sym; > >> + dl = disasm_line__new(args); > >> + if (dl) > >> + annotation_line__add(&dl->al, ¬es->src->source); > >> + > >> + pc += count; > >> + } while (count > 0 && pc < len); > >> + > >> + ret = 0; > >> +out: > >> + free(prog_linfo); > >> + free(btf); > >> + fclose(s); > >> + bfd_close(bfdf); > >> + return ret; > >> +} > >> + > >> static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) > >> { > >> struct annotation_options *opts = args->options; > >> @@ -1701,7 +1847,9 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) > >> pr_debug("annotating [%p] %30s : [%p] %30s\n", > >> dso, dso->long_name, sym, sym->name); > >> > >> - if (dso__is_kcore(dso)) { > >> + if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) { > >> + return symbol__disassemble_bpf(sym, args); > >> + } else if (dso__is_kcore(dso)) { > >> kce.kcore_filename = symfs_filename; > >> kce.addr = map__rip_2objdump(map, sym->start); > >> kce.offs = sym->start; > >> diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c > >> index ba58ba603b69..58547c468c65 100644 > >> --- a/tools/perf/util/dso.c > >> +++ b/tools/perf/util/dso.c > >> @@ -184,6 +184,7 @@ int dso__read_binary_type_filename(const struct dso *dso, > >> case DSO_BINARY_TYPE__KALLSYMS: > >> case DSO_BINARY_TYPE__GUEST_KALLSYMS: > >> case DSO_BINARY_TYPE__JAVA_JIT: > >> + case DSO_BINARY_TYPE__BPF_PROG_INFO: > >> case DSO_BINARY_TYPE__NOT_FOUND: > >> ret = -1; > >> break; > >> diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h > >> index bb417c54c25a..c274b5aa839d 100644 > >> --- a/tools/perf/util/dso.h > >> +++ b/tools/perf/util/dso.h > >> @@ -14,6 +14,7 @@ > >> > >> struct machine; > >> struct map; > >> +struct perf_env; > >> > >> enum dso_binary_type { > >> DSO_BINARY_TYPE__KALLSYMS = 0, > >> @@ -35,6 +36,7 @@ enum dso_binary_type { > >> DSO_BINARY_TYPE__KCORE, > >> DSO_BINARY_TYPE__GUEST_KCORE, > >> DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, > >> + DSO_BINARY_TYPE__BPF_PROG_INFO, > >> DSO_BINARY_TYPE__NOT_FOUND, > >> }; > >> > >> @@ -178,17 +180,25 @@ struct dso { > >> struct auxtrace_cache *auxtrace_cache; > >> int comp; > >> > >> - /* dso data file */ > >> - struct { > >> - struct rb_root cache; > >> - int fd; > >> - int status; > >> - u32 status_seen; > >> - size_t file_size; > >> - struct list_head open_entry; > >> - u64 debug_frame_offset; > >> - u64 eh_frame_hdr_offset; > >> - } data; > >> + union { > >> + /* dso data file */ > >> + struct { > >> + struct rb_root cache; > >> + int fd; > >> + int status; > >> + u32 status_seen; > >> + size_t file_size; > >> + struct list_head open_entry; > >> + u64 debug_frame_offset; > >> + u64 eh_frame_hdr_offset; > >> + } data; > >> + /* bpf prog information */ > >> + struct { > >> + u32 id; > >> + u32 sub_id; > >> + struct perf_env *env; > >> + } bpf_prog; > >> + }; > >> > >> union { /* Tool specific area */ > >> void *priv; > >> diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c > >> index 758bf5f74e6e..4e2e304d4037 100644 > >> --- a/tools/perf/util/symbol.c > >> +++ b/tools/perf/util/symbol.c > >> @@ -1451,6 +1451,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, > >> case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO: > >> return true; > >> > >> + case DSO_BINARY_TYPE__BPF_PROG_INFO: > >> case DSO_BINARY_TYPE__NOT_FOUND: > >> default: > >> return false; > >> -- > >> 2.17.1 > > > > -- > > > > - Arnaldo
Em Tue, Mar 19, 2019 at 10:58:13AM -0300, Arnaldo Carvalho de Melo escreveu: > Em Tue, Mar 19, 2019 at 06:05:30AM +0000, Song Liu escreveu: > > test-disassembler-four-args.c is an existing test used by bpftool. > > It was added in fb982666e380c1632a74495b68b3c33a66e76430 . > > > After applying this test it "works": > > > make: Entering directory '/home/acme/git/perf/tools/perf' > > > BUILD: Doing 'make -j8' parallel build > > > Auto-detecting system features: > > > ... dwarf: [ on ] > > > ... dwarf_getlocations: [ on ] > > > <SNIP> > > > ... bpf: [ on ] > > > ... libaio: [ on ] > > > ... disassembler-four-args: [ on ] > > > > > > Because you added it to FEATURE_TESTS_BASIC, and this means that if > > > tools/build/feature/test-all.c builds, then what is in > > > FEATURE_TESTS_BASIC is set to 'on', but you didn't add anything to > > > tools/build/feature/test-all.c, so it works because all the other > > > features are present. > > > Take a look at: > > > 2a07d814747b ("tools build feature: Check if libaio is available") > > > To see what needs to be done. > > I used different versions of gcc to verify that current version of the > > patch works for both test-succeed and test-fail cases. I guess something > > like the following is needed? But the test does work without it. > Even with the file below, it fails, as: > [acme@quaco perf]$ cat /tmp/build/perf/feature/test-all.make.output > /usr/bin/ld: /tmp/ccTj7iV6.o: in function `main_test_disassembler_four_args': > /home/acme/git/perf/tools/build/feature/test-disassembler-four-args.c:9: undefined reference to `disassembler' > collect2: error: ld returned 1 exit status > [acme@quaco perf]$ > Then we do the test for each of the features and _then_ this works: > [acme@quaco perf]$ ls -la /tmp/build/perf/feature/test-disassembler-four-args.* > -rwxrwxr-x. 1 acme acme 2098312 Mar 19 10:51 /tmp/build/perf/feature/test-disassembler-four-args.bin > -rw-rw-r--. 1 acme acme 1079 Mar 19 10:51 /tmp/build/perf/feature/test-disassembler-four-args.d > -rw-rw-r--. 1 acme acme 0 Mar 19 10:51 /tmp/build/perf/feature/test-disassembler-four-args.make.output > [acme@quaco perf]$ > > So there is still something missing, i.e. which objects to add to the > test-all case, I'll fix it. This was missing: diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index c51b59e43dcc..4f491ad4f492 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -227,6 +227,8 @@ FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS) FEATURE_CHECK_LDFLAGS-libaio = -lrt +FEATURE_CHECK_LDFLAGS-disassembler-four-args = -lopcodes + CFLAGS += -fno-omit-frame-pointer CFLAGS += -ggdb3 CFLAGS += -funwind-tables ---------------------- After that, and with a clean /tmp/build/perf, re-running: make -C tools/perf O=/tmp/build/perf we get: [acme@quaco perf]$ ls -la /tmp/build/perf/feature/ total 2888 drwxrwxr-x. 2 acme acme 400 Mar 19 11:08 . drwxrwxr-x. 16 acme acme 4280 Mar 19 11:08 .. -rwxrwxr-x. 1 acme acme 2680352 Mar 19 11:07 test-all.bin -rw-rw-r--. 1 acme acme 38753 Mar 19 11:07 test-all.d -rw-rw-r--. 1 acme acme 0 Mar 19 11:07 test-all.make.output -rw-rw-r--. 1 acme acme 168 Mar 19 11:07 test-bionic.make.output -rwxrwxr-x. 1 acme acme 140960 Mar 19 11:08 test-cplus-demangle.bin -rw-rw-r--. 1 acme acme 101 Mar 19 11:08 test-cplus-demangle.d -rw-rw-r--. 1 acme acme 0 Mar 19 11:08 test-cplus-demangle.make.output -rwxrwxr-x. 1 acme acme 17976 Mar 19 11:08 test-jvmti.bin -rwxrwxr-x. 1 acme acme 17984 Mar 19 11:08 test-jvmti-cmlr.bin -rw-rw-r--. 1 acme acme 1107 Mar 19 11:08 test-jvmti-cmlr.d -rw-rw-r--. 1 acme acme 0 Mar 19 11:08 test-jvmti-cmlr.make.output -rw-rw-r--. 1 acme acme 1014 Mar 19 11:08 test-jvmti.d -rw-rw-r--. 1 acme acme 0 Mar 19 11:08 test-jvmti.make.output -rwxrwxr-x. 1 acme acme 18368 Mar 19 11:07 test-libbabeltrace.bin -rw-rw-r--. 1 acme acme 1470 Mar 19 11:07 test-libbabeltrace.d -rw-rw-r--. 1 acme acme 0 Mar 19 11:07 test-libbabeltrace.make.output -rw-rw-r--. 1 acme acme 179 Mar 19 11:07 test-libunwind-aarch64.make.output -rw-rw-r--. 1 acme acme 163 Mar 19 11:07 test-libunwind-x86.make.output [acme@quaco perf]$ I.e. test-all.bin got built, and if we look at it: [acme@quaco perf]$ nm /tmp/build/perf/feature/test-all.bin | grep disassembler 0000000000061f90 T disassembler 0000000000062110 T disassembler_options_cmp 0000000000061fb0 T disassembler_usage 0000000000061f40 T main_test_disassembler_four_args 000000000006b7c0 T print_i386_disassembler_options [acme@quaco perf]$ I.e. the -lopcodes was added to the test-all.bin, and as we include that itest-disassembler-four-args.c in the test-all.c file, it gets linked and that test-all.c build doesn't fail, so all that is in FEATURE_TESTS_BASIC is marked as present, CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE gets set, etc. Now the test is really being performed, the test-all.bin feature detection fast path is working, proceeding. - Arnaldo
Em Tue, Mar 19, 2019 at 11:14:35AM -0300, Arnaldo Carvalho de Melo escreveu: > > Now the test is really being performed, the test-all.bin feature > detection fast path is working, proceeding. Now it all works, really nice! I added a 'Committer testing' section with all the steps to test this and pushed to: https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/commit/?h=perf/core&id=6530d44e7dc1d41c73fe70b9e6ea1b9cabebb57f Which I repeat here, please go thru it and check if everything is ok, if the disassembled + original BPF source code looks ok, etc: Committer testing: 1) Have a BPF program running, one that has BTF info, etc, I used the tools/perf/examples/bpf/augmented_raw_syscalls.c put in place by 'perf trace'. # grep -B1 augmented_raw ~/.perfconfig [trace] add_events = /home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.c # # perf trace -e *mmsg dnf/6245 sendmmsg(20, 0x7f5485a88030, 2, MSG_NOSIGNAL) = 2 NetworkManager/10055 sendmmsg(22<socket:[1056822]>, 0x7f8126ad1bb0, 2, MSG_NOSIGNAL) = 2 2) Then do a 'perf record' system wide for a while: # perf record -a ^C[ perf record: Woken up 68 times to write data ] [ perf record: Captured and wrote 19.427 MB perf.data (366891 samples) ] # 3) Check that we captured BPF and BTF info in the perf.data file: # perf report --header-only | grep 'b[pt]f' # event : name = cycles:ppp, , id = { 294789, 294790, 294791, 294792, 294793, 294794, 294795, 294796 }, size = 112, { sample_period, sample_freq } = 4000, sample_type = IP|TID|TIME|CPU|PERIOD, read_format = ID, disabled = 1, inherit = 1, mmap = 1, comm = 1, freq = 1, task = 1, precise_ip = 3, sample_id_all = 1, exclude_guest = 1, mmap2 = 1, comm_exec = 1, ksymbol = 1, bpf_event = 1 # bpf_prog_info of id 13 # bpf_prog_info of id 14 # bpf_prog_info of id 15 # bpf_prog_info of id 16 # bpf_prog_info of id 17 # bpf_prog_info of id 18 # bpf_prog_info of id 21 # bpf_prog_info of id 22 # bpf_prog_info of id 41 # bpf_prog_info of id 42 # btf info of id 2 # 4) Check which programs got recorded: # perf report | grep bpf_prog | head 0.16% exe bpf_prog_819967866022f1e1_sys_enter [k] bpf_prog_819967866022f1e1_sys_enter 0.14% exe bpf_prog_c1bd85c092d6e4aa_sys_exit [k] bpf_prog_c1bd85c092d6e4aa_sys_exit 0.08% fuse-overlayfs bpf_prog_819967866022f1e1_sys_enter [k] bpf_prog_819967866022f1e1_sys_enter 0.07% fuse-overlayfs bpf_prog_c1bd85c092d6e4aa_sys_exit [k] bpf_prog_c1bd85c092d6e4aa_sys_exit 0.01% clang-4.0 bpf_prog_c1bd85c092d6e4aa_sys_exit [k] bpf_prog_c1bd85c092d6e4aa_sys_exit 0.01% clang-4.0 bpf_prog_819967866022f1e1_sys_enter [k] bpf_prog_819967866022f1e1_sys_enter 0.00% clang bpf_prog_c1bd85c092d6e4aa_sys_exit [k] bpf_prog_c1bd85c092d6e4aa_sys_exit 0.00% runc bpf_prog_819967866022f1e1_sys_enter [k] bpf_prog_819967866022f1e1_sys_enter 0.00% clang bpf_prog_819967866022f1e1_sys_enter [k] bpf_prog_819967866022f1e1_sys_enter 0.00% sh bpf_prog_c1bd85c092d6e4aa_sys_exit [k] bpf_prog_c1bd85c092d6e4aa_sys_exit # This was with the default --sort order for 'perf report', which is: --sort comm,dso,symbol If we just look for the symbol, for instance: # perf report --sort symbol | grep bpf_prog | head 0.26% [k] bpf_prog_819967866022f1e1_sys_enter - - 0.24% [k] bpf_prog_c1bd85c092d6e4aa_sys_exit - - # or the DSO: # perf report --sort dso | grep bpf_prog | head 0.26% bpf_prog_819967866022f1e1_sys_enter 0.24% bpf_prog_c1bd85c092d6e4aa_sys_exit # We'll see the two BPF programs that augmented_raw_syscalls.o puts in place, one attached to the raw_syscalls:sys_enter and another to the raw_syscalls:sys_exit tracepoints, as expected. Now we can finally do, from the command line, annotation for one of those two symbols, with the original BPF program source coude intermixed with the disassembled JITed code: # perf annotate --stdio2 bpf_prog_819967866022f1e1_sys_enter Samples: 950 of event 'cycles:ppp', 4000 Hz, Event count (approx.): 553756947, [percent: local period] bpf_prog_819967866022f1e1_sys_enter() bpf_prog_819967866022f1e1_sys_enter Percent int sys_enter(struct syscall_enter_args *args) 53.41 push %rbp 0.63 mov %rsp,%rbp 0.31 sub $0x170,%rsp 1.93 sub $0x28,%rbp 7.02 mov %rbx,0x0(%rbp) 3.20 mov %r13,0x8(%rbp) 1.07 mov %r14,0x10(%rbp) 0.61 mov %r15,0x18(%rbp) 0.11 xor %eax,%eax 1.29 mov %rax,0x20(%rbp) 0.11 mov %rdi,%rbx return bpf_get_current_pid_tgid(); 2.02 → callq *ffffffffda6776d9 2.76 mov %eax,-0x148(%rbp) mov %rbp,%rsi int sys_enter(struct syscall_enter_args *args) add $0xfffffffffffffeb8,%rsi return bpf_map_lookup_elem(pids, &pid) != NULL; movabs $0xffff975ac2607800,%rdi 1.26 → callq *ffffffffda6789e9 cmp $0x0,%rax 2.43 → je 0 add $0x38,%rax 0.21 xor %r13d,%r13d if (pid_filter__has(&pids_filtered, getpid())) 0.81 cmp $0x0,%rax → jne 0 mov %rbp,%rdi probe_read(&augmented_args.args, sizeof(augmented_args.args), args); 2.22 add $0xfffffffffffffeb8,%rdi 0.11 mov $0x40,%esi 0.32 mov %rbx,%rdx 2.74 → callq *ffffffffda658409 syscall = bpf_map_lookup_elem(&syscalls, &augmented_args.args.syscall_nr); 0.22 mov %rbp,%rsi 1.69 add $0xfffffffffffffec0,%rsi syscall = bpf_map_lookup_elem(&syscalls, &augmented_args.args.syscall_nr); movabs $0xffff975bfcd36000,%rdi add $0xd0,%rdi 0.21 mov 0x0(%rsi),%eax 0.93 cmp $0x200,%rax → jae 0 0.10 shl $0x3,%rax 0.11 add %rdi,%rax 0.11 → jmp 0 xor %eax,%eax if (syscall == NULL || !syscall->enabled) 1.07 cmp $0x0,%rax → je 0 if (syscall == NULL || !syscall->enabled) 6.57 movzbq 0x0(%rax),%rdi if (syscall == NULL || !syscall->enabled) cmp $0x0,%rdi 0.95 → je 0 mov $0x40,%r8d switch (augmented_args.args.syscall_nr) { mov -0x140(%rbp),%rdi switch (augmented_args.args.syscall_nr) { cmp $0x2,%rdi → je 0 cmp $0x101,%rdi → je 0 cmp $0x15,%rdi → jne 0 case SYS_OPEN: filename_arg = (const void *)args->args[0]; mov 0x10(%rbx),%rdx → jmp 0 case SYS_OPENAT: filename_arg = (const void *)args->args[1]; mov 0x18(%rbx),%rdx if (filename_arg != NULL) { cmp $0x0,%rdx → je 0 xor %edi,%edi augmented_args.filename.reserved = 0; mov %edi,-0x104(%rbp) augmented_args.filename.size = probe_read_str(&augmented_args.filename.value, mov %rbp,%rdi add $0xffffffffffffff00,%rdi augmented_args.filename.size = probe_read_str(&augmented_args.filename.value, mov $0x100,%esi → callq *ffffffffda658499 mov $0x148,%r8d augmented_args.filename.size = probe_read_str(&augmented_args.filename.value, mov %eax,-0x108(%rbp) augmented_args.filename.size = probe_read_str(&augmented_args.filename.value, mov %rax,%rdi shl $0x20,%rdi shr $0x20,%rdi if (augmented_args.filename.size < sizeof(augmented_args.filename.value)) { cmp $0xff,%rdi → ja 0 len -= sizeof(augmented_args.filename.value) - augmented_args.filename.size; add $0x48,%rax len &= sizeof(augmented_args.filename.value) - 1; and $0xff,%rax mov %rax,%r8 mov %rbp,%rcx return perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, &augmented_args, len); add $0xfffffffffffffeb8,%rcx mov %rbx,%rdi movabs $0xffff975fbd72d800,%rsi mov $0xffffffff,%edx → callq *ffffffffda658ad9 mov %rax,%r13 } mov %r13,%rax 0.72 mov 0x0(%rbp),%rbx mov 0x8(%rbp),%r13 1.16 mov 0x10(%rbp),%r14 0.10 mov 0x18(%rbp),%r15 0.42 add $0x28,%rbp 0.54 leaveq 0.54 ← retq # Please see 'man perf-config' to see how to control what should be seen, via ~/.perfconfig [annotate] section, for instance, one can suppress the source code and see just the disassembly, etc. Alternatively, use the TUI bu just using 'perf annotate', press '/bpf_prog' to see the bpf symbols, press enter and do the interactive annotation, which allows for dumping to a file after selecting the the various output tunables, for instance, the above without source code intermixed, plus showing all the instruction offsets: # perf annotate bpf_prog_819967866022f1e1_sys_enter Then press: 's' to hide the source code + 'O' twice to show all instruction offsets, then 'P' to print to the bpf_prog_819967866022f1e1_sys_enter.annotation file, which will have: # cat bpf_prog_819967866022f1e1_sys_enter.annotation bpf_prog_819967866022f1e1_sys_enter() bpf_prog_819967866022f1e1_sys_enter Event: cycles:ppp 53.41 0: push %rbp 0.63 1: mov %rsp,%rbp 0.31 4: sub $0x170,%rsp 1.93 b: sub $0x28,%rbp 7.02 f: mov %rbx,0x0(%rbp) 3.20 13: mov %r13,0x8(%rbp) 1.07 17: mov %r14,0x10(%rbp) 0.61 1b: mov %r15,0x18(%rbp) 0.11 1f: xor %eax,%eax 1.29 21: mov %rax,0x20(%rbp) 0.11 25: mov %rdi,%rbx 2.02 28: → callq *ffffffffda6776d9 2.76 2d: mov %eax,-0x148(%rbp) 33: mov %rbp,%rsi 36: add $0xfffffffffffffeb8,%rsi 3d: movabs $0xffff975ac2607800,%rdi 1.26 47: → callq *ffffffffda6789e9 4c: cmp $0x0,%rax 2.43 50: → je 0 52: add $0x38,%rax 0.21 56: xor %r13d,%r13d 0.81 59: cmp $0x0,%rax 5d: → jne 0 63: mov %rbp,%rdi 2.22 66: add $0xfffffffffffffeb8,%rdi 0.11 6d: mov $0x40,%esi 0.32 72: mov %rbx,%rdx 2.74 75: → callq *ffffffffda658409 0.22 7a: mov %rbp,%rsi 1.69 7d: add $0xfffffffffffffec0,%rsi 84: movabs $0xffff975bfcd36000,%rdi 8e: add $0xd0,%rdi 0.21 95: mov 0x0(%rsi),%eax 0.93 98: cmp $0x200,%rax 9f: → jae 0 0.10 a1: shl $0x3,%rax 0.11 a5: add %rdi,%rax 0.11 a8: → jmp 0 aa: xor %eax,%eax 1.07 ac: cmp $0x0,%rax b0: → je 0 6.57 b6: movzbq 0x0(%rax),%rdi bb: cmp $0x0,%rdi 0.95 bf: → je 0 c5: mov $0x40,%r8d cb: mov -0x140(%rbp),%rdi d2: cmp $0x2,%rdi d6: → je 0 d8: cmp $0x101,%rdi df: → je 0 e1: cmp $0x15,%rdi e5: → jne 0 e7: mov 0x10(%rbx),%rdx eb: → jmp 0 ed: mov 0x18(%rbx),%rdx f1: cmp $0x0,%rdx f5: → je 0 f7: xor %edi,%edi f9: mov %edi,-0x104(%rbp) ff: mov %rbp,%rdi 102: add $0xffffffffffffff00,%rdi 109: mov $0x100,%esi 10e: → callq *ffffffffda658499 113: mov $0x148,%r8d 119: mov %eax,-0x108(%rbp) 11f: mov %rax,%rdi 122: shl $0x20,%rdi 126: shr $0x20,%rdi 12a: cmp $0xff,%rdi 131: → ja 0 133: add $0x48,%rax 137: and $0xff,%rax 13d: mov %rax,%r8 140: mov %rbp,%rcx 143: add $0xfffffffffffffeb8,%rcx 14a: mov %rbx,%rdi 14d: movabs $0xffff975fbd72d800,%rsi 157: mov $0xffffffff,%edx 15c: → callq *ffffffffda658ad9 161: mov %rax,%r13 164: mov %r13,%rax 0.72 167: mov 0x0(%rbp),%rbx 16b: mov 0x8(%rbp),%r13 1.16 16f: mov 0x10(%rbp),%r14 0.10 173: mov 0x18(%rbp),%r15 0.42 177: add $0x28,%rbp 0.54 17b: leaveq 0.54 17c: ← retq Another cool way to test all this is to symple use 'perf top' look for those symbols, go there and press enter, annotate it live :-) Signed-off-by: Song Liu <songliubraving@fb.com> Reviewed-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@kernel.org> Cc: Daniel Borkmann <daniel@iogearbox.net> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stanislav Fomichev <sdf@google.com> Link: http://lkml.kernel.org/r/20190312053051.2690567-13-songliubraving@fb.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
> On Mar 19, 2019, at 7:52 AM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote: > > Em Tue, Mar 19, 2019 at 11:14:35AM -0300, Arnaldo Carvalho de Melo escreveu: >> >> Now the test is really being performed, the test-all.bin feature >> detection fast path is working, proceeding. > > Now it all works, really nice! > > I added a 'Committer testing' section with all the steps to test this > and pushed to: > > https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/commit/?h=perf/core&id=6530d44e7dc1d41c73fe70b9e6ea1b9cabebb57f Thanks Arnaldo! This looks great! I will rebase https://lkml.org/lkml/2019/3/14/681 on top of this branch and resend. Song > Which I repeat here, please go thru it and check if everything is ok, if > the disassembled + original BPF source code looks ok, etc: > > Committer testing: > > 1) Have a BPF program running, one that has BTF info, etc, I used > the tools/perf/examples/bpf/augmented_raw_syscalls.c put in place > by 'perf trace'. > > # grep -B1 augmented_raw ~/.perfconfig > [trace] > add_events = /home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.c > # > # perf trace -e *mmsg > dnf/6245 sendmmsg(20, 0x7f5485a88030, 2, MSG_NOSIGNAL) = 2 > NetworkManager/10055 sendmmsg(22<socket:[1056822]>, 0x7f8126ad1bb0, 2, MSG_NOSIGNAL) = 2 > > 2) Then do a 'perf record' system wide for a while: > > # perf record -a > ^C[ perf record: Woken up 68 times to write data ] > [ perf record: Captured and wrote 19.427 MB perf.data (366891 samples) ] > # > > 3) Check that we captured BPF and BTF info in the perf.data file: > > # perf report --header-only | grep 'b[pt]f' > # event : name = cycles:ppp, , id = { 294789, 294790, 294791, 294792, 294793, 294794, 294795, 294796 }, size = 112, { sample_period, sample_freq } = 4000, sample_type = IP|TID|TIME|CPU|PERIOD, read_format = ID, disabled = 1, inherit = 1, mmap = 1, comm = 1, freq = 1, task = 1, precise_ip = 3, sample_id_all = 1, exclude_guest = 1, mmap2 = 1, comm_exec = 1, ksymbol = 1, bpf_event = 1 > # bpf_prog_info of id 13 > # bpf_prog_info of id 14 > # bpf_prog_info of id 15 > # bpf_prog_info of id 16 > # bpf_prog_info of id 17 > # bpf_prog_info of id 18 > # bpf_prog_info of id 21 > # bpf_prog_info of id 22 > # bpf_prog_info of id 41 > # bpf_prog_info of id 42 > # btf info of id 2 > # > > 4) Check which programs got recorded: > > # perf report | grep bpf_prog | head > 0.16% exe bpf_prog_819967866022f1e1_sys_enter [k] bpf_prog_819967866022f1e1_sys_enter > 0.14% exe bpf_prog_c1bd85c092d6e4aa_sys_exit [k] bpf_prog_c1bd85c092d6e4aa_sys_exit > 0.08% fuse-overlayfs bpf_prog_819967866022f1e1_sys_enter [k] bpf_prog_819967866022f1e1_sys_enter > 0.07% fuse-overlayfs bpf_prog_c1bd85c092d6e4aa_sys_exit [k] bpf_prog_c1bd85c092d6e4aa_sys_exit > 0.01% clang-4.0 bpf_prog_c1bd85c092d6e4aa_sys_exit [k] bpf_prog_c1bd85c092d6e4aa_sys_exit > 0.01% clang-4.0 bpf_prog_819967866022f1e1_sys_enter [k] bpf_prog_819967866022f1e1_sys_enter > 0.00% clang bpf_prog_c1bd85c092d6e4aa_sys_exit [k] bpf_prog_c1bd85c092d6e4aa_sys_exit > 0.00% runc bpf_prog_819967866022f1e1_sys_enter [k] bpf_prog_819967866022f1e1_sys_enter > 0.00% clang bpf_prog_819967866022f1e1_sys_enter [k] bpf_prog_819967866022f1e1_sys_enter > 0.00% sh bpf_prog_c1bd85c092d6e4aa_sys_exit [k] bpf_prog_c1bd85c092d6e4aa_sys_exit > # > > This was with the default --sort order for 'perf report', which is: > > --sort comm,dso,symbol > > If we just look for the symbol, for instance: > > # perf report --sort symbol | grep bpf_prog | head > 0.26% [k] bpf_prog_819967866022f1e1_sys_enter - - > 0.24% [k] bpf_prog_c1bd85c092d6e4aa_sys_exit - - > # > > or the DSO: > > # perf report --sort dso | grep bpf_prog | head > 0.26% bpf_prog_819967866022f1e1_sys_enter > 0.24% bpf_prog_c1bd85c092d6e4aa_sys_exit > # > > We'll see the two BPF programs that augmented_raw_syscalls.o puts in > place, one attached to the raw_syscalls:sys_enter and another to the > raw_syscalls:sys_exit tracepoints, as expected. > > Now we can finally do, from the command line, annotation for one of > those two symbols, with the original BPF program source coude intermixed > with the disassembled JITed code: > > # perf annotate --stdio2 bpf_prog_819967866022f1e1_sys_enter > > Samples: 950 of event 'cycles:ppp', 4000 Hz, Event count (approx.): 553756947, [percent: local period] > bpf_prog_819967866022f1e1_sys_enter() bpf_prog_819967866022f1e1_sys_enter > Percent int sys_enter(struct syscall_enter_args *args) > 53.41 push %rbp > > 0.63 mov %rsp,%rbp > 0.31 sub $0x170,%rsp > 1.93 sub $0x28,%rbp > 7.02 mov %rbx,0x0(%rbp) > 3.20 mov %r13,0x8(%rbp) > 1.07 mov %r14,0x10(%rbp) > 0.61 mov %r15,0x18(%rbp) > 0.11 xor %eax,%eax > 1.29 mov %rax,0x20(%rbp) > 0.11 mov %rdi,%rbx > return bpf_get_current_pid_tgid(); > 2.02 → callq *ffffffffda6776d9 > 2.76 mov %eax,-0x148(%rbp) > mov %rbp,%rsi > int sys_enter(struct syscall_enter_args *args) > add $0xfffffffffffffeb8,%rsi > return bpf_map_lookup_elem(pids, &pid) != NULL; > movabs $0xffff975ac2607800,%rdi > > 1.26 → callq *ffffffffda6789e9 > cmp $0x0,%rax > 2.43 → je 0 > add $0x38,%rax > 0.21 xor %r13d,%r13d > if (pid_filter__has(&pids_filtered, getpid())) > 0.81 cmp $0x0,%rax > → jne 0 > mov %rbp,%rdi > probe_read(&augmented_args.args, sizeof(augmented_args.args), args); > 2.22 add $0xfffffffffffffeb8,%rdi > 0.11 mov $0x40,%esi > 0.32 mov %rbx,%rdx > 2.74 → callq *ffffffffda658409 > syscall = bpf_map_lookup_elem(&syscalls, &augmented_args.args.syscall_nr); > 0.22 mov %rbp,%rsi > 1.69 add $0xfffffffffffffec0,%rsi > syscall = bpf_map_lookup_elem(&syscalls, &augmented_args.args.syscall_nr); > movabs $0xffff975bfcd36000,%rdi > > add $0xd0,%rdi > 0.21 mov 0x0(%rsi),%eax > 0.93 cmp $0x200,%rax > → jae 0 > 0.10 shl $0x3,%rax > > 0.11 add %rdi,%rax > 0.11 → jmp 0 > xor %eax,%eax > if (syscall == NULL || !syscall->enabled) > 1.07 cmp $0x0,%rax > → je 0 > if (syscall == NULL || !syscall->enabled) > 6.57 movzbq 0x0(%rax),%rdi > > if (syscall == NULL || !syscall->enabled) > cmp $0x0,%rdi > 0.95 → je 0 > mov $0x40,%r8d > switch (augmented_args.args.syscall_nr) { > mov -0x140(%rbp),%rdi > switch (augmented_args.args.syscall_nr) { > cmp $0x2,%rdi > → je 0 > cmp $0x101,%rdi > → je 0 > cmp $0x15,%rdi > → jne 0 > case SYS_OPEN: filename_arg = (const void *)args->args[0]; > mov 0x10(%rbx),%rdx > → jmp 0 > case SYS_OPENAT: filename_arg = (const void *)args->args[1]; > mov 0x18(%rbx),%rdx > if (filename_arg != NULL) { > cmp $0x0,%rdx > → je 0 > xor %edi,%edi > augmented_args.filename.reserved = 0; > mov %edi,-0x104(%rbp) > augmented_args.filename.size = probe_read_str(&augmented_args.filename.value, > mov %rbp,%rdi > add $0xffffffffffffff00,%rdi > augmented_args.filename.size = probe_read_str(&augmented_args.filename.value, > mov $0x100,%esi > → callq *ffffffffda658499 > mov $0x148,%r8d > augmented_args.filename.size = probe_read_str(&augmented_args.filename.value, > mov %eax,-0x108(%rbp) > augmented_args.filename.size = probe_read_str(&augmented_args.filename.value, > mov %rax,%rdi > shl $0x20,%rdi > > shr $0x20,%rdi > > if (augmented_args.filename.size < sizeof(augmented_args.filename.value)) { > cmp $0xff,%rdi > → ja 0 > len -= sizeof(augmented_args.filename.value) - augmented_args.filename.size; > add $0x48,%rax > len &= sizeof(augmented_args.filename.value) - 1; > and $0xff,%rax > mov %rax,%r8 > mov %rbp,%rcx > return perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, &augmented_args, len); > add $0xfffffffffffffeb8,%rcx > mov %rbx,%rdi > movabs $0xffff975fbd72d800,%rsi > > mov $0xffffffff,%edx > → callq *ffffffffda658ad9 > mov %rax,%r13 > } > mov %r13,%rax > 0.72 mov 0x0(%rbp),%rbx > mov 0x8(%rbp),%r13 > 1.16 mov 0x10(%rbp),%r14 > 0.10 mov 0x18(%rbp),%r15 > 0.42 add $0x28,%rbp > 0.54 leaveq > 0.54 ← retq > # > > Please see 'man perf-config' to see how to control what should be seen, > via ~/.perfconfig [annotate] section, for instance, one can suppress the > source code and see just the disassembly, etc. > > Alternatively, use the TUI bu just using 'perf annotate', press > '/bpf_prog' to see the bpf symbols, press enter and do the interactive > annotation, which allows for dumping to a file after selecting the > the various output tunables, for instance, the above without source code > intermixed, plus showing all the instruction offsets: > > # perf annotate bpf_prog_819967866022f1e1_sys_enter > > Then press: 's' to hide the source code + 'O' twice to show all > instruction offsets, then 'P' to print to the > bpf_prog_819967866022f1e1_sys_enter.annotation file, which will have: > > # cat bpf_prog_819967866022f1e1_sys_enter.annotation > bpf_prog_819967866022f1e1_sys_enter() bpf_prog_819967866022f1e1_sys_enter > Event: cycles:ppp > > 53.41 0: push %rbp > > 0.63 1: mov %rsp,%rbp > 0.31 4: sub $0x170,%rsp > 1.93 b: sub $0x28,%rbp > 7.02 f: mov %rbx,0x0(%rbp) > 3.20 13: mov %r13,0x8(%rbp) > 1.07 17: mov %r14,0x10(%rbp) > 0.61 1b: mov %r15,0x18(%rbp) > 0.11 1f: xor %eax,%eax > 1.29 21: mov %rax,0x20(%rbp) > 0.11 25: mov %rdi,%rbx > 2.02 28: → callq *ffffffffda6776d9 > 2.76 2d: mov %eax,-0x148(%rbp) > 33: mov %rbp,%rsi > 36: add $0xfffffffffffffeb8,%rsi > 3d: movabs $0xffff975ac2607800,%rdi > > 1.26 47: → callq *ffffffffda6789e9 > 4c: cmp $0x0,%rax > 2.43 50: → je 0 > 52: add $0x38,%rax > 0.21 56: xor %r13d,%r13d > 0.81 59: cmp $0x0,%rax > 5d: → jne 0 > 63: mov %rbp,%rdi > 2.22 66: add $0xfffffffffffffeb8,%rdi > 0.11 6d: mov $0x40,%esi > 0.32 72: mov %rbx,%rdx > 2.74 75: → callq *ffffffffda658409 > 0.22 7a: mov %rbp,%rsi > 1.69 7d: add $0xfffffffffffffec0,%rsi > 84: movabs $0xffff975bfcd36000,%rdi > > 8e: add $0xd0,%rdi > 0.21 95: mov 0x0(%rsi),%eax > 0.93 98: cmp $0x200,%rax > 9f: → jae 0 > 0.10 a1: shl $0x3,%rax > > 0.11 a5: add %rdi,%rax > 0.11 a8: → jmp 0 > aa: xor %eax,%eax > 1.07 ac: cmp $0x0,%rax > b0: → je 0 > 6.57 b6: movzbq 0x0(%rax),%rdi > > bb: cmp $0x0,%rdi > 0.95 bf: → je 0 > c5: mov $0x40,%r8d > cb: mov -0x140(%rbp),%rdi > d2: cmp $0x2,%rdi > d6: → je 0 > d8: cmp $0x101,%rdi > df: → je 0 > e1: cmp $0x15,%rdi > e5: → jne 0 > e7: mov 0x10(%rbx),%rdx > eb: → jmp 0 > ed: mov 0x18(%rbx),%rdx > f1: cmp $0x0,%rdx > f5: → je 0 > f7: xor %edi,%edi > f9: mov %edi,-0x104(%rbp) > ff: mov %rbp,%rdi > 102: add $0xffffffffffffff00,%rdi > 109: mov $0x100,%esi > 10e: → callq *ffffffffda658499 > 113: mov $0x148,%r8d > 119: mov %eax,-0x108(%rbp) > 11f: mov %rax,%rdi > 122: shl $0x20,%rdi > > 126: shr $0x20,%rdi > > 12a: cmp $0xff,%rdi > 131: → ja 0 > 133: add $0x48,%rax > 137: and $0xff,%rax > 13d: mov %rax,%r8 > 140: mov %rbp,%rcx > 143: add $0xfffffffffffffeb8,%rcx > 14a: mov %rbx,%rdi > 14d: movabs $0xffff975fbd72d800,%rsi > > 157: mov $0xffffffff,%edx > 15c: → callq *ffffffffda658ad9 > 161: mov %rax,%r13 > 164: mov %r13,%rax > 0.72 167: mov 0x0(%rbp),%rbx > 16b: mov 0x8(%rbp),%r13 > 1.16 16f: mov 0x10(%rbp),%r14 > 0.10 173: mov 0x18(%rbp),%r15 > 0.42 177: add $0x28,%rbp > 0.54 17b: leaveq > 0.54 17c: ← retq > > Another cool way to test all this is to symple use 'perf top' look for > those symbols, go there and press enter, annotate it live :-) > > Signed-off-by: Song Liu <songliubraving@fb.com> > Reviewed-by: Jiri Olsa <jolsa@kernel.org> > Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> > Cc: Alexei Starovoitov <ast@kernel.org> > Cc: Daniel Borkmann <daniel@iogearbox.net> > Cc: Namhyung Kim <namhyung@kernel.org> > Cc: Peter Zijlstra <peterz@infradead.org> > Cc: Stanislav Fomichev <sdf@google.com> > Link: http://lkml.kernel.org/r/20190312053051.2690567-13-songliubraving@fb.com > Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Em Tue, Mar 19, 2019 at 04:51:44PM +0000, Song Liu escreveu: > > > > On Mar 19, 2019, at 7:52 AM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote: > > > > Em Tue, Mar 19, 2019 at 11:14:35AM -0300, Arnaldo Carvalho de Melo escreveu: > >> > >> Now the test is really being performed, the test-all.bin feature > >> detection fast path is working, proceeding. > > > > Now it all works, really nice! > > > > I added a 'Committer testing' section with all the steps to test this > > and pushed to: > > > > https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/commit/?h=perf/core&id=6530d44e7dc1d41c73fe70b9e6ea1b9cabebb57f > > Thanks Arnaldo! This looks great! > > I will rebase https://lkml.org/lkml/2019/3/14/681 on top of this branch > and resend. I just found one new bug, that may appear now since I took a series of fixes found by gcc's ASan feature, i.e. on the exit path we're crashing on: [root@quaco ~]# perf top perf: Segmentation fault -------- backtrace -------- perf[0x5a785a] /lib64/libc.so.6(+0x385bf)[0x7fd68443c5bf] perf(rb_first+0x2b)[0x4d6eeb] perf(dso__delete+0xb7)[0x4dffb7] perf[0x4f9e37] perf(perf_session__delete+0x64)[0x504df4] perf(cmd_top+0x1957)[0x454467] perf[0x4aad18] perf(main+0x61c)[0x42ec7c] /lib64/libc.so.6(__libc_start_main+0xf2)[0x7fd684428412] perf(_start+0x2d)[0x42eead] [root@quaco ~]# [root@quaco ~]# addr2line -fe ~/bin/perf 0x4dffb7 dso_cache__free /home/acme/git/perf/tools/perf/util/dso.c:713 And that is because of that union: + union { + /* dso data file */ + struct { + struct rb_root cache; + int fd; + int status; + u32 status_seen; + size_t file_size; + struct list_head open_entry; + u64 debug_frame_offset; + u64 eh_frame_hdr_offset; + } data; + /* bpf prog information */ + struct { + u32 id; + u32 sub_id; + struct perf_env *env; + } bpf_prog; + }; On the dso exit path, it is trying to traverse the data.cache rbtree, when what is that is that bpf_prog.id, etc, I'll just remove the union for now, later we can do the data.cache access or bpf_prog based on some other test.
Em Tue, Mar 19, 2019 at 01:55:31PM -0300, Arnaldo Carvalho de Melo escreveu: > Em Tue, Mar 19, 2019 at 04:51:44PM +0000, Song Liu escreveu: > > > > > > > On Mar 19, 2019, at 7:52 AM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote: > > > > > > Em Tue, Mar 19, 2019 at 11:14:35AM -0300, Arnaldo Carvalho de Melo escreveu: > > >> > > >> Now the test is really being performed, the test-all.bin feature > > >> detection fast path is working, proceeding. > > > > > > Now it all works, really nice! > > > > > > I added a 'Committer testing' section with all the steps to test this > > > and pushed to: > > > > > > https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/commit/?h=perf/core&id=6530d44e7dc1d41c73fe70b9e6ea1b9cabebb57f > > > > Thanks Arnaldo! This looks great! > > > > I will rebase https://lkml.org/lkml/2019/3/14/681 on top of this branch > > and resend. > > I just found one new bug, that may appear now since I took a series of > fixes found by gcc's ASan feature, i.e. on the exit path we're crashing > on: > > [root@quaco ~]# perf top > perf: Segmentation fault > -------- backtrace -------- > perf[0x5a785a] > /lib64/libc.so.6(+0x385bf)[0x7fd68443c5bf] > perf(rb_first+0x2b)[0x4d6eeb] > perf(dso__delete+0xb7)[0x4dffb7] > perf[0x4f9e37] > perf(perf_session__delete+0x64)[0x504df4] > perf(cmd_top+0x1957)[0x454467] > perf[0x4aad18] > perf(main+0x61c)[0x42ec7c] > /lib64/libc.so.6(__libc_start_main+0xf2)[0x7fd684428412] > perf(_start+0x2d)[0x42eead] > [root@quaco ~]# > [root@quaco ~]# addr2line -fe ~/bin/perf 0x4dffb7 > dso_cache__free > /home/acme/git/perf/tools/perf/util/dso.c:713 > > > And that is because of that union: > > + union { > + /* dso data file */ > + struct { > + struct rb_root cache; > + int fd; > + int status; > + u32 status_seen; > + size_t file_size; > + struct list_head open_entry; > + u64 debug_frame_offset; > + u64 eh_frame_hdr_offset; > + } data; > + /* bpf prog information */ > + struct { > + u32 id; > + u32 sub_id; > + struct perf_env *env; > + } bpf_prog; > + }; > > > On the dso exit path, it is trying to traverse the data.cache rbtree, > when what is that is that bpf_prog.id, etc, I'll just remove the union > for now, later we can do the data.cache access or bpf_prog based on some > other test. One more on 32-bit arches, a uintptr_t case for the jited_ksyms on the BPF annotate patch, will fix. - Arnaldo
diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index 61e46d54a67c..8d3864b061f3 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature @@ -66,7 +66,8 @@ FEATURE_TESTS_BASIC := \ sched_getcpu \ sdt \ setns \ - libaio + libaio \ + disassembler-four-args # FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list # of all feature tests @@ -118,7 +119,8 @@ FEATURE_DISPLAY ?= \ lzma \ get_cpuid \ bpf \ - libaio + libaio \ + disassembler-four-args # Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features. # If in the future we need per-feature checks/flags for features not diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index df4ad45599ca..c51b59e43dcc 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -808,6 +808,10 @@ ifdef HAVE_KVM_STAT_SUPPORT CFLAGS += -DHAVE_KVM_STAT_SUPPORT endif +ifeq ($(feature-disassembler-four-args), 1) + CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE +endif + ifeq (${IS_64_BIT}, 1) ifndef NO_PERF_READ_VDSO32 $(call feature_check,compile-32) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 5f6dbbf5d749..e492b19a157c 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -10,6 +10,10 @@ #include <errno.h> #include <inttypes.h> #include <libgen.h> +#include <bpf/bpf.h> +#include <bpf/btf.h> +#include <bpf/libbpf.h> +#include <linux/btf.h> #include "util.h" #include "ui/ui.h" #include "sort.h" @@ -24,6 +28,7 @@ #include "annotate.h" #include "evsel.h" #include "evlist.h" +#include "bpf-event.h" #include "block-range.h" #include "string2.h" #include "arch/common.h" @@ -31,6 +36,9 @@ #include <pthread.h> #include <linux/bitops.h> #include <linux/kernel.h> +#include <bfd.h> +#include <dis-asm.h> +#include <bpf/libbpf.h> /* FIXME: For the HE_COLORSET */ #include "ui/browser.h" @@ -1674,6 +1682,144 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil return 0; } +static int symbol__disassemble_bpf(struct symbol *sym, + struct annotate_args *args) +{ + struct annotation *notes = symbol__annotation(sym); + struct annotation_options *opts = args->options; + struct bpf_prog_info_linear *info_linear; + struct bpf_prog_linfo *prog_linfo = NULL; + struct bpf_prog_info_node *info_node; + int len = sym->end - sym->start; + disassembler_ftype disassemble; + struct map *map = args->ms.map; + struct disassemble_info info; + struct dso *dso = map->dso; + int pc = 0, count, sub_id; + struct btf *btf = NULL; + char tpath[PATH_MAX]; + size_t buf_size; + int nr_skip = 0; + int ret = -1; + char *buf; + bfd *bfdf; + FILE *s; + + if (dso->binary_type != DSO_BINARY_TYPE__BPF_PROG_INFO) + return -1; + + pr_debug("%s: handling sym %s addr %lx len %lx\n", __func__, + sym->name, sym->start, sym->end - sym->start); + + memset(tpath, 0, sizeof(tpath)); + perf_exe(tpath, sizeof(tpath)); + + bfdf = bfd_openr(tpath, NULL); + assert(bfdf); + assert(bfd_check_format(bfdf, bfd_object)); + + s = open_memstream(&buf, &buf_size); + if (!s) + goto out; + init_disassemble_info(&info, s, + (fprintf_ftype) fprintf); + + info.arch = bfd_get_arch(bfdf); + info.mach = bfd_get_mach(bfdf); + + info_node = perf_env__find_bpf_prog_info(dso->bpf_prog.env, + dso->bpf_prog.id); + if (!info_node) + goto out; + info_linear = info_node->info_linear; + sub_id = dso->bpf_prog.sub_id; + + info.buffer = (void *)(info_linear->info.jited_prog_insns); + info.buffer_length = info_linear->info.jited_prog_len; + + if (info_linear->info.nr_line_info) + prog_linfo = bpf_prog_linfo__new(&info_linear->info); + + if (info_linear->info.btf_id) { + struct btf_node *node; + + node = perf_env__find_btf(dso->bpf_prog.env, + info_linear->info.btf_id); + if (node) + btf = btf__new((__u8 *)(node->data), + node->data_size); + } + + disassemble_init_for_target(&info); + +#ifdef DISASM_FOUR_ARGS_SIGNATURE + disassemble = disassembler(info.arch, + bfd_big_endian(bfdf), + info.mach, + bfdf); +#else + disassemble = disassembler(bfdf); +#endif + assert(disassemble); + + fflush(s); + do { + const struct bpf_line_info *linfo = NULL; + struct disasm_line *dl; + size_t prev_buf_size; + const char *srcline; + u64 addr; + + addr = pc + ((u64 *)(info_linear->info.jited_ksyms))[sub_id]; + count = disassemble(pc, &info); + + if (prog_linfo) + linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo, + addr, sub_id, + nr_skip); + + if (linfo && btf) { + srcline = btf__name_by_offset(btf, linfo->line_off); + nr_skip++; + } else + srcline = NULL; + + fprintf(s, "\n"); + prev_buf_size = buf_size; + fflush(s); + + if (!opts->hide_src_code && srcline) { + args->offset = -1; + args->line = strdup(srcline); + args->line_nr = 0; + args->ms.sym = sym; + dl = disasm_line__new(args); + if (dl) { + annotation_line__add(&dl->al, + ¬es->src->source); + } + } + + args->offset = pc; + args->line = buf + prev_buf_size; + args->line_nr = 0; + args->ms.sym = sym; + dl = disasm_line__new(args); + if (dl) + annotation_line__add(&dl->al, ¬es->src->source); + + pc += count; + } while (count > 0 && pc < len); + + ret = 0; +out: + free(prog_linfo); + free(btf); + fclose(s); + bfd_close(bfdf); + return ret; +} + static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) { struct annotation_options *opts = args->options; @@ -1701,7 +1847,9 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) pr_debug("annotating [%p] %30s : [%p] %30s\n", dso, dso->long_name, sym, sym->name); - if (dso__is_kcore(dso)) { + if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) { + return symbol__disassemble_bpf(sym, args); + } else if (dso__is_kcore(dso)) { kce.kcore_filename = symfs_filename; kce.addr = map__rip_2objdump(map, sym->start); kce.offs = sym->start; diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index ba58ba603b69..58547c468c65 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -184,6 +184,7 @@ int dso__read_binary_type_filename(const struct dso *dso, case DSO_BINARY_TYPE__KALLSYMS: case DSO_BINARY_TYPE__GUEST_KALLSYMS: case DSO_BINARY_TYPE__JAVA_JIT: + case DSO_BINARY_TYPE__BPF_PROG_INFO: case DSO_BINARY_TYPE__NOT_FOUND: ret = -1; break; diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index bb417c54c25a..c274b5aa839d 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -14,6 +14,7 @@ struct machine; struct map; +struct perf_env; enum dso_binary_type { DSO_BINARY_TYPE__KALLSYMS = 0, @@ -35,6 +36,7 @@ enum dso_binary_type { DSO_BINARY_TYPE__KCORE, DSO_BINARY_TYPE__GUEST_KCORE, DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, + DSO_BINARY_TYPE__BPF_PROG_INFO, DSO_BINARY_TYPE__NOT_FOUND, }; @@ -178,17 +180,25 @@ struct dso { struct auxtrace_cache *auxtrace_cache; int comp; - /* dso data file */ - struct { - struct rb_root cache; - int fd; - int status; - u32 status_seen; - size_t file_size; - struct list_head open_entry; - u64 debug_frame_offset; - u64 eh_frame_hdr_offset; - } data; + union { + /* dso data file */ + struct { + struct rb_root cache; + int fd; + int status; + u32 status_seen; + size_t file_size; + struct list_head open_entry; + u64 debug_frame_offset; + u64 eh_frame_hdr_offset; + } data; + /* bpf prog information */ + struct { + u32 id; + u32 sub_id; + struct perf_env *env; + } bpf_prog; + }; union { /* Tool specific area */ void *priv; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 758bf5f74e6e..4e2e304d4037 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1451,6 +1451,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO: return true; + case DSO_BINARY_TYPE__BPF_PROG_INFO: case DSO_BINARY_TYPE__NOT_FOUND: default: return false;
This patch enables the annotation of bpf program. A new dso type DSO_BINARY_TYPE__BPF_PROG_INFO is introduced to for BPF programs. In symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso calls into a new function symbol__disassemble_bpf(), where annotation line information is filled based bpf_prog_info and btf saved in given perf_env. symbol__disassemble_bpf() uses libbfd to disassemble bpf programs. Signed-off-by: Song Liu <songliubraving@fb.com> --- tools/build/Makefile.feature | 6 +- tools/perf/Makefile.config | 4 + tools/perf/util/annotate.c | 150 ++++++++++++++++++++++++++++++++++- tools/perf/util/dso.c | 1 + tools/perf/util/dso.h | 32 +++++--- tools/perf/util/symbol.c | 1 + 6 files changed, 180 insertions(+), 14 deletions(-)