diff options
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/bpf_lock_contention.c | 57 | ||||
-rw-r--r-- | tools/perf/util/bpf_skel/lock_contention.bpf.c | 38 | ||||
-rw-r--r-- | tools/perf/util/debug.c | 4 | ||||
-rw-r--r-- | tools/perf/util/dlfilter.c | 2 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 10 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 1 | ||||
-rw-r--r-- | tools/perf/util/lock-contention.h | 10 | ||||
-rw-r--r-- | tools/perf/util/scripting-engines/Build | 2 | ||||
-rw-r--r-- | tools/perf/util/setup.py | 13 | ||||
-rw-r--r-- | tools/perf/util/sort.c | 129 | ||||
-rw-r--r-- | tools/perf/util/sort.h | 1 | ||||
-rw-r--r-- | tools/perf/util/srcline.c | 20 | ||||
-rw-r--r-- | tools/perf/util/symbol-elf.c | 28 | ||||
-rw-r--r-- | tools/perf/util/symbol-minimal.c | 5 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 1 |
15 files changed, 293 insertions, 28 deletions
diff --git a/tools/perf/util/bpf_lock_contention.c b/tools/perf/util/bpf_lock_contention.c index 8e1b791dc58f..0236334fd69b 100644 --- a/tools/perf/util/bpf_lock_contention.c +++ b/tools/perf/util/bpf_lock_contention.c @@ -20,7 +20,7 @@ static struct lock_contention_bpf *skel; int lock_contention_prepare(struct lock_contention *con) { int i, fd; - int ncpus = 1, ntasks = 1; + int ncpus = 1, ntasks = 1, ntypes = 1, naddrs = 1; struct evlist *evlist = con->evlist; struct target *target = con->target; @@ -46,9 +46,42 @@ int lock_contention_prepare(struct lock_contention *con) ncpus = perf_cpu_map__nr(evlist->core.user_requested_cpus); if (target__has_task(target)) ntasks = perf_thread_map__nr(evlist->core.threads); + if (con->filters->nr_types) + ntypes = con->filters->nr_types; + + /* resolve lock name filters to addr */ + if (con->filters->nr_syms) { + struct symbol *sym; + struct map *kmap; + unsigned long *addrs; + + for (i = 0; i < con->filters->nr_syms; i++) { + sym = machine__find_kernel_symbol_by_name(con->machine, + con->filters->syms[i], + &kmap); + if (sym == NULL) { + pr_warning("ignore unknown symbol: %s\n", + con->filters->syms[i]); + continue; + } + + addrs = realloc(con->filters->addrs, + (con->filters->nr_addrs + 1) * sizeof(*addrs)); + if (addrs == NULL) { + pr_warning("memory allocation failure\n"); + continue; + } + + addrs[con->filters->nr_addrs++] = kmap->unmap_ip(kmap, sym->start); + con->filters->addrs = addrs; + } + naddrs = con->filters->nr_addrs; + } bpf_map__set_max_entries(skel->maps.cpu_filter, ncpus); bpf_map__set_max_entries(skel->maps.task_filter, ntasks); + bpf_map__set_max_entries(skel->maps.type_filter, ntypes); + bpf_map__set_max_entries(skel->maps.addr_filter, naddrs); if (lock_contention_bpf__load(skel) < 0) { pr_err("Failed to load lock-contention BPF skeleton\n"); @@ -90,6 +123,26 @@ int lock_contention_prepare(struct lock_contention *con) bpf_map_update_elem(fd, &pid, &val, BPF_ANY); } + if (con->filters->nr_types) { + u8 val = 1; + + skel->bss->has_type = 1; + fd = bpf_map__fd(skel->maps.type_filter); + + for (i = 0; i < con->filters->nr_types; i++) + bpf_map_update_elem(fd, &con->filters->types[i], &val, BPF_ANY); + } + + if (con->filters->nr_addrs) { + u8 val = 1; + + skel->bss->has_addr = 1; + fd = bpf_map__fd(skel->maps.addr_filter); + + for (i = 0; i < con->filters->nr_addrs; i++) + bpf_map_update_elem(fd, &con->filters->addrs[i], &val, BPF_ANY); + } + /* these don't work well if in the rodata section */ skel->bss->stack_skip = con->stack_skip; skel->bss->aggr_mode = con->aggr_mode; @@ -215,7 +268,7 @@ int lock_contention_read(struct lock_contention *con) break; } - if (verbose) { + if (verbose > 0) { st->callstack = memdup(stack_trace, stack_size); if (st->callstack == NULL) break; diff --git a/tools/perf/util/bpf_skel/lock_contention.bpf.c b/tools/perf/util/bpf_skel/lock_contention.bpf.c index 11b0fc7ee53b..ad0ca5d50557 100644 --- a/tools/perf/util/bpf_skel/lock_contention.bpf.c +++ b/tools/perf/util/bpf_skel/lock_contention.bpf.c @@ -62,10 +62,26 @@ struct { __uint(max_entries, 1); } task_filter SEC(".maps"); +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(__u32)); + __uint(value_size, sizeof(__u8)); + __uint(max_entries, 1); +} type_filter SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(__u64)); + __uint(value_size, sizeof(__u8)); + __uint(max_entries, 1); +} addr_filter SEC(".maps"); + /* control flags */ int enabled; int has_cpu; int has_task; +int has_type; +int has_addr; int stack_skip; /* determine the key of lock stat */ @@ -74,7 +90,7 @@ int aggr_mode; /* error stat */ int lost; -static inline int can_record(void) +static inline int can_record(u64 *ctx) { if (has_cpu) { __u32 cpu = bpf_get_smp_processor_id(); @@ -94,6 +110,24 @@ static inline int can_record(void) return 0; } + if (has_type) { + __u8 *ok; + __u32 flags = (__u32)ctx[1]; + + ok = bpf_map_lookup_elem(&type_filter, &flags); + if (!ok) + return 0; + } + + if (has_addr) { + __u8 *ok; + __u64 addr = ctx[0]; + + ok = bpf_map_lookup_elem(&addr_filter, &addr); + if (!ok) + return 0; + } + return 1; } @@ -116,7 +150,7 @@ int contention_begin(u64 *ctx) __u32 pid; struct tstamp_data *pelem; - if (!enabled || !can_record()) + if (!enabled || !can_record(ctx)) return 0; pid = bpf_get_current_pid_tgid(); diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 65e6c22f38e4..190e818a0717 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -241,6 +241,10 @@ int perf_quiet_option(void) opt++; } + /* For debug variables that are used as bool types, set to 0. */ + redirect_to_stderr = 0; + debug_peo_args = 0; + return 0; } diff --git a/tools/perf/util/dlfilter.c b/tools/perf/util/dlfilter.c index 54e4d4495e00..37beb7530288 100644 --- a/tools/perf/util/dlfilter.c +++ b/tools/perf/util/dlfilter.c @@ -579,7 +579,7 @@ static void list_filters(const char *dirname) if (!get_filter_desc(dirname, entry->d_name, &desc, &long_desc)) continue; printf(" %-36s %s\n", entry->d_name, desc ? desc : ""); - if (verbose) { + if (verbose > 0) { char *p = long_desc; char *line; diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 17a05e943b44..b6e4b4edde43 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -1781,8 +1781,8 @@ static void hierarchy_insert_output_entry(struct rb_root_cached *root, /* update column width of dynamic entry */ perf_hpp_list__for_each_sort_list(he->hpp_list, fmt) { - if (perf_hpp__is_dynamic_entry(fmt)) - fmt->sort(fmt, he, NULL); + if (fmt->init) + fmt->init(fmt, he); } } @@ -1879,10 +1879,10 @@ static void __hists__insert_output_entry(struct rb_root_cached *entries, rb_link_node(&he->rb_node, parent, p); rb_insert_color_cached(&he->rb_node, entries, leftmost); + /* update column width of dynamic entries */ perf_hpp_list__for_each_sort_list(&perf_hpp_list, fmt) { - if (perf_hpp__is_dynamic_entry(fmt) && - perf_hpp__defined_dynamic_entry(fmt, he->hists)) - fmt->sort(fmt, he, NULL); /* update column width */ + if (fmt->init) + fmt->init(fmt, he); } } diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index ebd8a8f783ee..d93a4e510dc7 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -272,6 +272,7 @@ struct perf_hpp_fmt { struct hists *hists, int line, int *span); int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hists *hists); + void (*init)(struct perf_hpp_fmt *fmt, struct hist_entry *he); int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he); int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, diff --git a/tools/perf/util/lock-contention.h b/tools/perf/util/lock-contention.h index 47fd47fb56c1..b99e83fccf5c 100644 --- a/tools/perf/util/lock-contention.h +++ b/tools/perf/util/lock-contention.h @@ -5,6 +5,15 @@ #include <linux/list.h> #include <linux/rbtree.h> +struct lock_filter { + int nr_types; + int nr_addrs; + int nr_syms; + unsigned int *types; + unsigned long *addrs; + char **syms; +}; + struct lock_stat { struct hlist_node hash_entry; struct rb_node rb; /* used for sorting */ @@ -113,6 +122,7 @@ struct lock_contention { struct target *target; struct machine *machine; struct hlist_head *result; + struct lock_filter *filters; unsigned long map_nr_entries; int lost; int max_stack; diff --git a/tools/perf/util/scripting-engines/Build b/tools/perf/util/scripting-engines/Build index d47820c0b4d4..2c96aa3cc1ec 100644 --- a/tools/perf/util/scripting-engines/Build +++ b/tools/perf/util/scripting-engines/Build @@ -5,4 +5,4 @@ endif CFLAGS_trace-event-perl.o += $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-nested-externs -Wno-undef -Wno-switch-default -Wno-bad-function-cast -Wno-declaration-after-statement -Wno-switch-enum -CFLAGS_trace-event-python.o += $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-deprecated-declarations +CFLAGS_trace-event-python.o += $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-deprecated-declarations -Wno-switch-enum diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index 4f265d0222c4..c294db713677 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py @@ -3,11 +3,20 @@ from subprocess import Popen, PIPE from re import sub cc = getenv("CC") -cc_is_clang = b"clang version" in Popen([cc.split()[0], "-v"], stderr=PIPE).stderr.readline() + +# Check if CC has options, as is the case in yocto, where it uses CC="cc --sysroot..." +cc_tokens = cc.split() +if len(cc_tokens) > 1: + cc = cc_tokens[0] + cc_options = " ".join([str(e) for e in cc_tokens[1:]]) + " " +else: + cc_options = "" + +cc_is_clang = b"clang version" in Popen([cc, "-v"], stderr=PIPE).stderr.readline() src_feature_tests = getenv('srctree') + '/tools/build/feature' def clang_has_option(option): - cc_output = Popen([cc.split()[0], str(cc.split()[1:]) + option, path.join(src_feature_tests, "test-hello.c") ], stderr=PIPE).stderr.readlines() + cc_output = Popen([cc, cc_options + option, path.join(src_feature_tests, "test-hello.c") ], stderr=PIPE).stderr.readlines() return [o for o in cc_output if ((b"unknown argument" in o) or (b"is not supported" in o))] == [ ] if cc_is_clang: diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 0ecc2cb13792..e188f74698dd 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -374,6 +374,18 @@ char *hist_entry__srcline(struct hist_entry *he) static int64_t sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) { + int64_t ret; + + ret = _sort__addr_cmp(left->ip, right->ip); + if (ret) + return ret; + + return sort__dso_cmp(left, right); +} + +static int64_t +sort__srcline_collapse(struct hist_entry *left, struct hist_entry *right) +{ if (!left->srcline) left->srcline = hist_entry__srcline(left); if (!right->srcline) @@ -382,18 +394,31 @@ sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) return strcmp(right->srcline, left->srcline); } -static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf, - size_t size, unsigned int width) +static int64_t +sort__srcline_sort(struct hist_entry *left, struct hist_entry *right) +{ + return sort__srcline_collapse(left, right); +} + +static void +sort__srcline_init(struct hist_entry *he) { if (!he->srcline) he->srcline = hist_entry__srcline(he); +} +static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf, + size_t size, unsigned int width) +{ return repsep_snprintf(bf, size, "%-.*s", width, he->srcline); } struct sort_entry sort_srcline = { .se_header = "Source:Line", .se_cmp = sort__srcline_cmp, + .se_collapse = sort__srcline_collapse, + .se_sort = sort__srcline_sort, + .se_init = sort__srcline_init, .se_snprintf = hist_entry__srcline_snprintf, .se_width_idx = HISTC_SRCLINE, }; @@ -408,6 +433,12 @@ static char *addr_map_symbol__srcline(struct addr_map_symbol *ams) static int64_t sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right) { + return left->branch_info->from.addr - right->branch_info->from.addr; +} + +static int64_t +sort__srcline_from_collapse(struct hist_entry *left, struct hist_entry *right) +{ if (!left->branch_info->srcline_from) left->branch_info->srcline_from = addr_map_symbol__srcline(&left->branch_info->from); @@ -417,6 +448,18 @@ sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right) return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from); } +static int64_t +sort__srcline_from_sort(struct hist_entry *left, struct hist_entry *right) +{ + return sort__srcline_from_collapse(left, right); +} + +static void sort__srcline_from_init(struct hist_entry *he) +{ + if (!he->branch_info->srcline_from) + he->branch_info->srcline_from = addr_map_symbol__srcline(&he->branch_info->from); +} + static int hist_entry__srcline_from_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) { @@ -426,6 +469,9 @@ static int hist_entry__srcline_from_snprintf(struct hist_entry *he, char *bf, struct sort_entry sort_srcline_from = { .se_header = "From Source:Line", .se_cmp = sort__srcline_from_cmp, + .se_collapse = sort__srcline_from_collapse, + .se_sort = sort__srcline_from_sort, + .se_init = sort__srcline_from_init, .se_snprintf = hist_entry__srcline_from_snprintf, .se_width_idx = HISTC_SRCLINE_FROM, }; @@ -435,6 +481,12 @@ struct sort_entry sort_srcline_from = { static int64_t sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right) { + return left->branch_info->to.addr - right->branch_info->to.addr; +} + +static int64_t +sort__srcline_to_collapse(struct hist_entry *left, struct hist_entry *right) +{ if (!left->branch_info->srcline_to) left->branch_info->srcline_to = addr_map_symbol__srcline(&left->branch_info->to); @@ -444,6 +496,18 @@ sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right) return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to); } +static int64_t +sort__srcline_to_sort(struct hist_entry *left, struct hist_entry *right) +{ + return sort__srcline_to_collapse(left, right); +} + +static void sort__srcline_to_init(struct hist_entry *he) +{ + if (!he->branch_info->srcline_to) + he->branch_info->srcline_to = addr_map_symbol__srcline(&he->branch_info->to); +} + static int hist_entry__srcline_to_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) { @@ -453,6 +517,9 @@ static int hist_entry__srcline_to_snprintf(struct hist_entry *he, char *bf, struct sort_entry sort_srcline_to = { .se_header = "To Source:Line", .se_cmp = sort__srcline_to_cmp, + .se_collapse = sort__srcline_to_collapse, + .se_sort = sort__srcline_to_sort, + .se_init = sort__srcline_to_init, .se_snprintf = hist_entry__srcline_to_snprintf, .se_width_idx = HISTC_SRCLINE_TO, }; @@ -544,18 +611,41 @@ sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right) return strcmp(right->srcfile, left->srcfile); } -static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf, - size_t size, unsigned int width) +static int64_t +sort__srcfile_collapse(struct hist_entry *left, struct hist_entry *right) +{ + if (!left->srcfile) + left->srcfile = hist_entry__get_srcfile(left); + if (!right->srcfile) + right->srcfile = hist_entry__get_srcfile(right); + + return strcmp(right->srcfile, left->srcfile); +} + +static int64_t +sort__srcfile_sort(struct hist_entry *left, struct hist_entry *right) +{ + return sort__srcfile_collapse(left, right); +} + +static void sort__srcfile_init(struct hist_entry *he) { if (!he->srcfile) he->srcfile = hist_entry__get_srcfile(he); +} +static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf, + size_t size, unsigned int width) +{ return repsep_snprintf(bf, size, "%-.*s", width, he->srcfile); } struct sort_entry sort_srcfile = { .se_header = "Source File", .se_cmp = sort__srcfile_cmp, + .se_collapse = sort__srcfile_collapse, + .se_sort = sort__srcfile_sort, + .se_init = sort__srcfile_init, .se_snprintf = hist_entry__srcfile_snprintf, .se_width_idx = HISTC_SRCFILE, }; @@ -2251,6 +2341,19 @@ static void hse_free(struct perf_hpp_fmt *fmt) free(hse); } +static void hse_init(struct perf_hpp_fmt *fmt, struct hist_entry *he) +{ + struct hpp_sort_entry *hse; + + if (!perf_hpp__is_sort_entry(fmt)) + return; + + hse = container_of(fmt, struct hpp_sort_entry, hpp); + + if (hse->se->se_init) + hse->se->se_init(he); +} + static struct hpp_sort_entry * __sort_dimension__alloc_hpp(struct sort_dimension *sd, int level) { @@ -2274,6 +2377,7 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd, int level) hse->hpp.sort = __sort__hpp_sort; hse->hpp.equal = __sort__hpp_equal; hse->hpp.free = hse_free; + hse->hpp.init = hse_init; INIT_LIST_HEAD(&hse->hpp.list); INIT_LIST_HEAD(&hse->hpp.sort_list); @@ -2556,11 +2660,6 @@ static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt, hde = container_of(fmt, struct hpp_dynamic_entry, hpp); - if (b == NULL) { - update_dynamic_len(hde, a); - return 0; - } - field = hde->field; if (field->flags & TEP_FIELD_IS_DYNAMIC) { unsigned long long dyn; @@ -2610,6 +2709,17 @@ static void hde_free(struct perf_hpp_fmt *fmt) free(hde); } +static void __sort__hde_init(struct perf_hpp_fmt *fmt, struct hist_entry *he) +{ + struct hpp_dynamic_entry *hde; + + if (!perf_hpp__is_dynamic_entry(fmt)) + return; + + hde = container_of(fmt, struct hpp_dynamic_entry, hpp); + update_dynamic_len(hde, he); +} + static struct hpp_dynamic_entry * __alloc_dynamic_entry(struct evsel *evsel, struct tep_format_field *field, int level) @@ -2632,6 +2742,7 @@ __alloc_dynamic_entry(struct evsel *evsel, struct tep_format_field *field, hde->hpp.entry = __sort__hde_entry; hde->hpp.color = NULL; + hde->hpp.init = __sort__hde_init; hde->hpp.cmp = __sort__hde_cmp; hde->hpp.collapse = __sort__hde_cmp; hde->hpp.sort = __sort__hde_cmp; diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 04ff8b61a2a7..921715e6aec4 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -282,6 +282,7 @@ struct sort_entry { int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size, unsigned int width); int (*se_filter)(struct hist_entry *he, int type, const void *arg); + void (*se_init)(struct hist_entry *he); u8 se_width_idx; }; diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c index af468e3bb6fa..33321867416b 100644 --- a/tools/perf/util/srcline.c +++ b/tools/perf/util/srcline.c @@ -550,6 +550,9 @@ static int addr2line(const char *dso_name, u64 addr, size_t inline_count = 0; if (!a2l) { + if (!filename__has_section(dso_name, ".debug_line")) + goto out; + dso->a2l = addr2line_subprocess_init(dso_name); a2l = dso->a2l; } @@ -570,13 +573,15 @@ static int addr2line(const char *dso_name, u64 addr, * "??"/"??:0" lines. */ if (fprintf(a2l->to_child, "%016"PRIx64"\n,\n", addr) < 0 || fflush(a2l->to_child) != 0) { - pr_warning("%s %s: could not send request\n", __func__, dso_name); + if (!symbol_conf.disable_add2line_warn) + pr_warning("%s %s: could not send request\n", __func__, dso_name); goto out; } switch (read_addr2line_record(a2l, &record_function, &record_filename, &record_line_nr)) { case -1: - pr_warning("%s %s: could not read first record\n", __func__, dso_name); + if (!symbol_conf.disable_add2line_warn) + pr_warning("%s %s: could not read first record\n", __func__, dso_name); goto out; case 0: /* @@ -585,14 +590,17 @@ static int addr2line(const char *dso_name, u64 addr, */ switch (read_addr2line_record(a2l, NULL, NULL, NULL)) { case -1: - pr_warning("%s %s: could not read delimiter record\n", __func__, dso_name); + if (!symbol_conf.disable_add2line_warn) + pr_warning("%s %s: could not read delimiter record\n", + __func__, dso_name); break; case 0: /* As expected. */ break; default: - pr_warning("%s %s: unexpected record instead of sentinel", - __func__, dso_name); + if (!symbol_conf.disable_add2line_warn) + pr_warning("%s %s: unexpected record instead of sentinel", + __func__, dso_name); break; } goto out; @@ -716,7 +724,7 @@ out: if (!show_addr) return (show_sym && sym) ? - strndup(sym->name, sym->namelen) : NULL; + strndup(sym->name, sym->namelen) : SRCLINE_UNKNOWN; if (sym) { if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "", diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 80345695b136..96767d1b3f1c 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -233,6 +233,34 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, return NULL; } +bool filename__has_section(const char *filename, const char *sec) +{ + int fd; + Elf *elf; + GElf_Ehdr ehdr; + GElf_Shdr shdr; + bool found = false; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return false; + + elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); + if (elf == NULL) + goto out; + + if (gelf_getehdr(elf, &ehdr) == NULL) + goto elf_out; + + found = !!elf_section_by_name(elf, &ehdr, &shdr, sec, NULL); + +elf_out: + elf_end(elf); +out: + close(fd); + return found; +} + static int elf_read_program_header(Elf *elf, u64 vaddr, GElf_Phdr *phdr) { size_t i, phdrnum; diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index f9eb0bee7f15..a81a14769bd1 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c @@ -385,3 +385,8 @@ char *dso__demangle_sym(struct dso *dso __maybe_unused, { return NULL; } + +bool filename__has_section(const char *filename __maybe_unused, const char *sec __maybe_unused) +{ + return false; +} diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index e297de14184c..f735108c4d4e 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -165,6 +165,7 @@ int modules__parse(const char *filename, void *arg, u64 start, u64 size)); int filename__read_debuglink(const char *filename, char *debuglink, size_t size); +bool filename__has_section(const char *filename, const char *sec); struct perf_env; int symbol__init(struct perf_env *env); |