diff options
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/probe-event.c | 137 | ||||
-rw-r--r-- | tools/perf/util/probe-event.h | 2 |
2 files changed, 136 insertions, 3 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 88a3b6d75c7c..1e60a659578b 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -40,6 +40,8 @@ #include "debug.h" #include "cache.h" #include "color.h" +#include "symbol.h" +#include "thread.h" #include "parse-events.h" /* For debugfs_path */ #include "probe-event.h" @@ -65,6 +67,38 @@ static int e_snprintf(char *str, size_t size, const char *format, ...) return ret; } + +static struct map_groups kmap_groups; +static struct map *kmaps[MAP__NR_TYPES]; + +/* Initialize symbol maps for vmlinux */ +static void init_vmlinux(void) +{ + symbol_conf.sort_by_name = true; + if (symbol_conf.vmlinux_name == NULL) + symbol_conf.try_vmlinux_path = true; + else + pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name); + if (symbol__init() < 0) + die("Failed to init symbol map."); + + map_groups__init(&kmap_groups); + if (map_groups__create_kernel_maps(&kmap_groups, kmaps) < 0) + die("Failed to create kernel maps."); +} + +#ifndef NO_DWARF_SUPPORT +static int open_vmlinux(void) +{ + if (map__load(kmaps[MAP__FUNCTION], NULL) < 0) { + pr_debug("Failed to load kernel map.\n"); + return -EINVAL; + } + pr_debug("Try to open %s\n", kmaps[MAP__FUNCTION]->dso->long_name); + return open(kmaps[MAP__FUNCTION]->dso->long_name, O_RDONLY); +} +#endif + void parse_line_range_desc(const char *arg, struct line_range *lr) { const char *ptr; @@ -586,8 +620,8 @@ static void get_new_event_name(char *buf, size_t len, const char *base, die("Too many events are on the same function."); } -void add_trace_kprobe_events(struct probe_point *probes, int nr_probes, - bool force_add) +static void __add_trace_kprobe_events(struct probe_point *probes, + int nr_probes, bool force_add) { int i, j, fd; struct probe_point *pp; @@ -640,6 +674,92 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes, close(fd); } +/* Currently just checking function name from symbol map */ +static void evaluate_probe_point(struct probe_point *pp) +{ + struct symbol *sym; + sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION], + pp->function, NULL); + if (!sym) + die("Kernel symbol \'%s\' not found - probe not added.", + pp->function); +} + +void add_trace_kprobe_events(struct probe_point *probes, int nr_probes, + bool force_add, bool need_dwarf) +{ + int i, ret; + struct probe_point *pp; +#ifndef NO_DWARF_SUPPORT + int fd; +#endif + /* Add probes */ + init_vmlinux(); + + if (need_dwarf) +#ifdef NO_DWARF_SUPPORT + die("Debuginfo-analysis is not supported"); +#else /* !NO_DWARF_SUPPORT */ + pr_debug("Some probes require debuginfo.\n"); + + fd = open_vmlinux(); + if (fd < 0) { + if (need_dwarf) + die("Could not open debuginfo file."); + + pr_debug("Could not open vmlinux/module file." + " Try to use symbols.\n"); + goto end_dwarf; + } + + /* Searching probe points */ + for (i = 0; i < nr_probes; i++) { + pp = &probes[i]; + if (pp->found) + continue; + + lseek(fd, SEEK_SET, 0); + ret = find_probe_point(fd, pp); + if (ret > 0) + continue; + if (ret == 0) { /* No error but failed to find probe point. */ + synthesize_perf_probe_point(pp); + die("Probe point '%s' not found. - probe not added.", + pp->probes[0]); + } + /* Error path */ + if (need_dwarf) { + if (ret == -ENOENT) + pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO=y.\n"); + die("Could not analyze debuginfo."); + } + pr_debug("An error occurred in debuginfo analysis." + " Try to use symbols.\n"); + break; + } + close(fd); + +end_dwarf: +#endif /* !NO_DWARF_SUPPORT */ + + /* Synthesize probes without dwarf */ + for (i = 0; i < nr_probes; i++) { + pp = &probes[i]; + if (pp->found) /* This probe is already found. */ + continue; + + evaluate_probe_point(pp); + ret = synthesize_trace_kprobe_event(pp); + if (ret == -E2BIG) + die("probe point definition becomes too long."); + else if (ret < 0) + die("Failed to synthesize a probe point."); + } + + /* Settng up probe points */ + __add_trace_kprobe_events(probes, nr_probes, force_add); +} + static void __del_trace_kprobe_event(int fd, struct str_node *ent) { char *p; @@ -759,6 +879,17 @@ void show_line_range(struct line_range *lr) unsigned int l = 1; struct line_node *ln; FILE *fp; + int fd, ret; + + /* Search a line range */ + init_vmlinux(); + fd = open_vmlinux(); + if (fd < 0) + die("Could not open debuginfo file."); + ret = find_line_range(fd, lr); + if (ret <= 0) + die("Source line is not found.\n"); + close(fd); setup_pager(); @@ -788,3 +919,5 @@ void show_line_range(struct line_range *lr) fclose(fp); } + + diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 711287d4baea..3865e163bb59 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -13,7 +13,7 @@ extern int synthesize_perf_probe_event(struct probe_point *pp); extern void parse_trace_kprobe_event(const char *str, struct probe_point *pp); extern int synthesize_trace_kprobe_event(struct probe_point *pp); extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes, - bool force_add); + bool force_add, bool need_dwarf); extern void del_trace_kprobe_events(struct strlist *dellist); extern void show_perf_probe_events(void); extern void show_line_range(struct line_range *lr); |