diff options
author | Masami Hiramatsu <mhiramat@redhat.com> | 2010-03-16 18:05:37 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-03-17 11:32:30 +0100 |
commit | e0faa8d35845bb1893cf9e608a5a5d92e9390bf0 (patch) | |
tree | 4bc641f43f9b572b4ae8f19e8201932a9d611987 /tools/perf/util/probe-event.c | |
parent | 31facc5f1ac674fbcc29f212377e589396bb934c (diff) |
perf probe: Move add-probe routine to util/
Move add-probe routine to util/probe_event.c. This simplifies
main routine for reducing maintenance cost.
Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: systemtap <systemtap@sources.redhat.com>
Cc: DLE <dle-develop@lists.sourceforge.net>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20100316220537.32050.72214.stgit@localhost6.localdomain6>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util/probe-event.c')
-rw-r--r-- | tools/perf/util/probe-event.c | 137 |
1 files changed, 135 insertions, 2 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 88a3b6d75c7..1e60a659578 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); } + + |