aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>2010-10-21 06:13:41 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2010-10-21 14:11:44 -0400
commit469b9b88488e89114bb3e9ac5ee7906b7b96123f (patch)
tree9f002195a8b1167eddbe560ac834e6ba2dedb19f /tools
parentfb8c5a56c7ddbc2b0d2ee7a8da60fe1355f75141 (diff)
perf probe: Add basic module support
Add basic module probe support on perf probe. This introduces "--module <MODNAME>" option to perf probe for putting probes and showing lines and variables in the given module. Currently, this supports only probing on running modules. Supporting off-line module probing is the next step. e.g.) [show lines] # ./perf probe --module drm -L drm_vblank_info <drm_vblank_info:0> 0 int drm_vblank_info(struct seq_file *m, void *data) 1 { struct drm_info_node *node = (struct drm_info_node *) m->private 3 struct drm_device *dev = node->minor->dev; ... [show vars] # ./perf probe --module drm -V drm_vblank_info:3 Available variables at drm_vblank_info:3 @<drm_vblank_info+20> (unknown_type) data struct drm_info_node* node struct seq_file* m [put a probe] # ./perf probe --module drm drm_vblank_info:3 node m Add new event: probe:drm_vblank_info (on drm_vblank_info:3 with node m) You can now use it on all perf tools, such as: perf record -e probe:drm_vblank_info -aR sleep 1 [list probes] # ./perf probe -l probe:drm_vblank_info (on drm_vblank_info:3@drivers/gpu/drm/drm_info.c with ... Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> Cc: Ingo Molnar <mingo@elte.hu> Cc: Frederic Weisbecker <fweisbec@gmail.com> LKML-Reference: <20101021101341.3542.71638.stgit@ltc236.sdl.hitachi.co.jp> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Documentation/perf-probe.txt9
-rw-r--r--tools/perf/builtin-probe.c11
-rw-r--r--tools/perf/util/map.h10
-rw-r--r--tools/perf/util/probe-event.c123
-rw-r--r--tools/perf/util/probe-event.h10
-rw-r--r--tools/perf/util/probe-finder.c142
-rw-r--r--tools/perf/util/probe-finder.h3
7 files changed, 239 insertions, 69 deletions
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 148c178a35a..62de1b7f4e7 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -16,9 +16,9 @@ or
16or 16or
17'perf probe' --list 17'perf probe' --list
18or 18or
19'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]' 19'perf probe' [options] --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
20or 20or
21'perf probe' [--externs] --vars='PROBEPOINT' 21'perf probe' [options] --vars='PROBEPOINT'
22 22
23DESCRIPTION 23DESCRIPTION
24----------- 24-----------
@@ -33,6 +33,11 @@ OPTIONS
33--vmlinux=PATH:: 33--vmlinux=PATH::
34 Specify vmlinux path which has debuginfo (Dwarf binary). 34 Specify vmlinux path which has debuginfo (Dwarf binary).
35 35
36-m::
37--module=MODNAME::
38 Specify module name in which perf-probe searches probe points
39 or lines.
40
36-s:: 41-s::
37--source=PATH:: 42--source=PATH::
38 Specify path to kernel source. 43 Specify path to kernel source.
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index bdf60cfdf70..2e000c068cc 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -57,6 +57,7 @@ static struct {
57 struct perf_probe_event events[MAX_PROBES]; 57 struct perf_probe_event events[MAX_PROBES];
58 struct strlist *dellist; 58 struct strlist *dellist;
59 struct line_range line_range; 59 struct line_range line_range;
60 const char *target_module;
60 int max_probe_points; 61 int max_probe_points;
61} params; 62} params;
62 63
@@ -162,8 +163,8 @@ static const char * const probe_usage[] = {
162 "perf probe [<options>] --del '[GROUP:]EVENT' ...", 163 "perf probe [<options>] --del '[GROUP:]EVENT' ...",
163 "perf probe --list", 164 "perf probe --list",
164#ifdef DWARF_SUPPORT 165#ifdef DWARF_SUPPORT
165 "perf probe --line 'LINEDESC'", 166 "perf probe [<options>] --line 'LINEDESC'",
166 "perf probe [--externs] --vars 'PROBEPOINT'", 167 "perf probe [<options>] --vars 'PROBEPOINT'",
167#endif 168#endif
168 NULL 169 NULL
169}; 170};
@@ -214,6 +215,8 @@ static const struct option options[] = {
214 "file", "vmlinux pathname"), 215 "file", "vmlinux pathname"),
215 OPT_STRING('s', "source", &symbol_conf.source_prefix, 216 OPT_STRING('s', "source", &symbol_conf.source_prefix,
216 "directory", "path to kernel source"), 217 "directory", "path to kernel source"),
218 OPT_STRING('m', "module", &params.target_module,
219 "modname", "target module name"),
217#endif 220#endif
218 OPT__DRY_RUN(&probe_event_dry_run), 221 OPT__DRY_RUN(&probe_event_dry_run),
219 OPT_INTEGER('\0', "max-probes", &params.max_probe_points, 222 OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
@@ -278,7 +281,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
278 usage_with_options(probe_usage, options); 281 usage_with_options(probe_usage, options);
279 } 282 }
280 283
281 ret = show_line_range(&params.line_range); 284 ret = show_line_range(&params.line_range, params.target_module);
282 if (ret < 0) 285 if (ret < 0)
283 pr_err(" Error: Failed to show lines. (%d)\n", ret); 286 pr_err(" Error: Failed to show lines. (%d)\n", ret);
284 return ret; 287 return ret;
@@ -291,6 +294,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
291 } 294 }
292 ret = show_available_vars(params.events, params.nevents, 295 ret = show_available_vars(params.events, params.nevents,
293 params.max_probe_points, 296 params.max_probe_points,
297 params.target_module,
294 params.show_ext_vars); 298 params.show_ext_vars);
295 if (ret < 0) 299 if (ret < 0)
296 pr_err(" Error: Failed to show vars. (%d)\n", ret); 300 pr_err(" Error: Failed to show vars. (%d)\n", ret);
@@ -310,6 +314,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
310 if (params.nevents) { 314 if (params.nevents) {
311 ret = add_perf_probe_events(params.events, params.nevents, 315 ret = add_perf_probe_events(params.events, params.nevents,
312 params.max_probe_points, 316 params.max_probe_points,
317 params.target_module,
313 params.force_add); 318 params.force_add);
314 if (ret < 0) { 319 if (ret < 0) {
315 pr_err(" Error: Failed to add events. (%d)\n", ret); 320 pr_err(" Error: Failed to add events. (%d)\n", ret);
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 78575796d5f..b397c038372 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -215,6 +215,16 @@ struct symbol *map_groups__find_function_by_name(struct map_groups *self,
215 return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter); 215 return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter);
216} 216}
217 217
218static inline
219struct symbol *machine__find_kernel_function_by_name(struct machine *self,
220 const char *name,
221 struct map **mapp,
222 symbol_filter_t filter)
223{
224 return map_groups__find_function_by_name(&self->kmaps, name, mapp,
225 filter);
226}
227
218int map_groups__fixup_overlappings(struct map_groups *self, struct map *map, 228int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
219 int verbose, FILE *fp); 229 int verbose, FILE *fp);
220 230
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 82b0976e205..3b6a5297bf1 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -74,10 +74,9 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
74static char *synthesize_perf_probe_point(struct perf_probe_point *pp); 74static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
75static struct machine machine; 75static struct machine machine;
76 76
77/* Initialize symbol maps and path of vmlinux */ 77/* Initialize symbol maps and path of vmlinux/modules */
78static int init_vmlinux(void) 78static int init_vmlinux(void)
79{ 79{
80 struct dso *kernel;
81 int ret; 80 int ret;
82 81
83 symbol_conf.sort_by_name = true; 82 symbol_conf.sort_by_name = true;
@@ -91,33 +90,61 @@ static int init_vmlinux(void)
91 goto out; 90 goto out;
92 } 91 }
93 92
94 ret = machine__init(&machine, "/", 0); 93 ret = machine__init(&machine, "", HOST_KERNEL_ID);
95 if (ret < 0) 94 if (ret < 0)
96 goto out; 95 goto out;
97 96
98 kernel = dso__new_kernel(symbol_conf.vmlinux_name); 97 if (machine__create_kernel_maps(&machine) < 0) {
99 if (kernel == NULL) 98 pr_debug("machine__create_kernel_maps ");
100 die("Failed to create kernel dso."); 99 goto out;
101 100 }
102 ret = __machine__create_kernel_maps(&machine, kernel);
103 if (ret < 0)
104 pr_debug("Failed to create kernel maps.\n");
105
106out: 101out:
107 if (ret < 0) 102 if (ret < 0)
108 pr_warning("Failed to init vmlinux path.\n"); 103 pr_warning("Failed to init vmlinux path.\n");
109 return ret; 104 return ret;
110} 105}
111 106
107static struct symbol *__find_kernel_function_by_name(const char *name,
108 struct map **mapp)
109{
110 return machine__find_kernel_function_by_name(&machine, name, mapp,
111 NULL);
112}
113
114const char *kernel_get_module_path(const char *module)
115{
116 struct dso *dso;
117
118 if (module) {
119 list_for_each_entry(dso, &machine.kernel_dsos, node) {
120 if (strncmp(dso->short_name + 1, module,
121 dso->short_name_len - 2) == 0)
122 goto found;
123 }
124 pr_debug("Failed to find module %s.\n", module);
125 return NULL;
126 } else {
127 dso = machine.vmlinux_maps[MAP__FUNCTION]->dso;
128 if (dso__load_vmlinux_path(dso,
129 machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) {
130 pr_debug("Failed to load kernel map.\n");
131 return NULL;
132 }
133 }
134found:
135 return dso->long_name;
136}
137
112#ifdef DWARF_SUPPORT 138#ifdef DWARF_SUPPORT
113static int open_vmlinux(void) 139static int open_vmlinux(const char *module)
114{ 140{
115 if (map__load(machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) { 141 const char *path = kernel_get_module_path(module);
116 pr_debug("Failed to load kernel map.\n"); 142 if (!path) {
117 return -EINVAL; 143 pr_err("Failed to find path of %s module", module ?: "kernel");
144 return -ENOENT;
118 } 145 }
119 pr_debug("Try to open %s\n", machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name); 146 pr_debug("Try to open %s\n", path);
120 return open(machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name, O_RDONLY); 147 return open(path, O_RDONLY);
121} 148}
122 149
123/* 150/*
@@ -125,20 +152,19 @@ static int open_vmlinux(void)
125 * Currently only handles kprobes. 152 * Currently only handles kprobes.
126 */ 153 */
127static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, 154static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
128 struct perf_probe_point *pp) 155 struct perf_probe_point *pp)
129{ 156{
130 struct symbol *sym; 157 struct symbol *sym;
131 int fd, ret = -ENOENT; 158 struct map *map;
159 u64 addr;
160 int ret = -ENOENT;
132 161
133 sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION], 162 sym = __find_kernel_function_by_name(tp->symbol, &map);
134 tp->symbol, NULL);
135 if (sym) { 163 if (sym) {
136 fd = open_vmlinux(); 164 addr = map->unmap_ip(map, sym->start + tp->offset);
137 if (fd >= 0) { 165 pr_debug("try to find %s+%ld@%llx\n", tp->symbol,
138 ret = find_perf_probe_point(fd, 166 tp->offset, addr);
139 sym->start + tp->offset, pp); 167 ret = find_perf_probe_point((unsigned long)addr, pp);
140 close(fd);
141 }
142 } 168 }
143 if (ret <= 0) { 169 if (ret <= 0) {
144 pr_debug("Failed to find corresponding probes from " 170 pr_debug("Failed to find corresponding probes from "
@@ -156,12 +182,12 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
156/* Try to find perf_probe_event with debuginfo */ 182/* Try to find perf_probe_event with debuginfo */
157static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 183static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
158 struct probe_trace_event **tevs, 184 struct probe_trace_event **tevs,
159 int max_tevs) 185 int max_tevs, const char *module)
160{ 186{
161 bool need_dwarf = perf_probe_event_need_dwarf(pev); 187 bool need_dwarf = perf_probe_event_need_dwarf(pev);
162 int fd, ntevs; 188 int fd, ntevs;
163 189
164 fd = open_vmlinux(); 190 fd = open_vmlinux(module);
165 if (fd < 0) { 191 if (fd < 0) {
166 if (need_dwarf) { 192 if (need_dwarf) {
167 pr_warning("Failed to open debuginfo file.\n"); 193 pr_warning("Failed to open debuginfo file.\n");
@@ -300,7 +326,7 @@ error:
300 * Show line-range always requires debuginfo to find source file and 326 * Show line-range always requires debuginfo to find source file and
301 * line number. 327 * line number.
302 */ 328 */
303int show_line_range(struct line_range *lr) 329int show_line_range(struct line_range *lr, const char *module)
304{ 330{
305 int l = 1; 331 int l = 1;
306 struct line_node *ln; 332 struct line_node *ln;
@@ -313,7 +339,7 @@ int show_line_range(struct line_range *lr)
313 if (ret < 0) 339 if (ret < 0)
314 return ret; 340 return ret;
315 341
316 fd = open_vmlinux(); 342 fd = open_vmlinux(module);
317 if (fd < 0) { 343 if (fd < 0) {
318 pr_warning("Failed to open debuginfo file.\n"); 344 pr_warning("Failed to open debuginfo file.\n");
319 return fd; 345 return fd;
@@ -421,7 +447,7 @@ static int show_available_vars_at(int fd, struct perf_probe_event *pev,
421 447
422/* Show available variables on given probe point */ 448/* Show available variables on given probe point */
423int show_available_vars(struct perf_probe_event *pevs, int npevs, 449int show_available_vars(struct perf_probe_event *pevs, int npevs,
424 int max_vls, bool externs) 450 int max_vls, const char *module, bool externs)
425{ 451{
426 int i, fd, ret = 0; 452 int i, fd, ret = 0;
427 453
@@ -429,7 +455,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
429 if (ret < 0) 455 if (ret < 0)
430 return ret; 456 return ret;
431 457
432 fd = open_vmlinux(); 458 fd = open_vmlinux(module);
433 if (fd < 0) { 459 if (fd < 0) {
434 pr_warning("Failed to open debuginfo file.\n"); 460 pr_warning("Failed to open debuginfo file.\n");
435 return fd; 461 return fd;
@@ -447,8 +473,15 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
447#else /* !DWARF_SUPPORT */ 473#else /* !DWARF_SUPPORT */
448 474
449static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, 475static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
450 struct perf_probe_point *pp) 476 struct perf_probe_point *pp)
451{ 477{
478 struct symbol *sym;
479
480 sym = __find_kernel_function_by_name(tp->symbol, NULL);
481 if (!sym) {
482 pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
483 return -ENOENT;
484 }
452 pp->function = strdup(tp->symbol); 485 pp->function = strdup(tp->symbol);
453 if (pp->function == NULL) 486 if (pp->function == NULL)
454 return -ENOMEM; 487 return -ENOMEM;
@@ -460,7 +493,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
460 493
461static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 494static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
462 struct probe_trace_event **tevs __unused, 495 struct probe_trace_event **tevs __unused,
463 int max_tevs __unused) 496 int max_tevs __unused, const char *mod __unused)
464{ 497{
465 if (perf_probe_event_need_dwarf(pev)) { 498 if (perf_probe_event_need_dwarf(pev)) {
466 pr_warning("Debuginfo-analysis is not supported.\n"); 499 pr_warning("Debuginfo-analysis is not supported.\n");
@@ -469,14 +502,15 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
469 return 0; 502 return 0;
470} 503}
471 504
472int show_line_range(struct line_range *lr __unused) 505int show_line_range(struct line_range *lr __unused, const char *module __unused)
473{ 506{
474 pr_warning("Debuginfo-analysis is not supported.\n"); 507 pr_warning("Debuginfo-analysis is not supported.\n");
475 return -ENOSYS; 508 return -ENOSYS;
476} 509}
477 510
478int show_available_vars(struct perf_probe_event *pevs __unused, 511int show_available_vars(struct perf_probe_event *pevs __unused,
479 int npevs __unused, int max_probe_points __unused) 512 int npevs __unused, int max_vls __unused,
513 const char *module __unused, bool externs __unused)
480{ 514{
481 pr_warning("Debuginfo-analysis is not supported.\n"); 515 pr_warning("Debuginfo-analysis is not supported.\n");
482 return -ENOSYS; 516 return -ENOSYS;
@@ -1159,7 +1193,7 @@ error:
1159} 1193}
1160 1194
1161static int convert_to_perf_probe_event(struct probe_trace_event *tev, 1195static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1162 struct perf_probe_event *pev) 1196 struct perf_probe_event *pev)
1163{ 1197{
1164 char buf[64] = ""; 1198 char buf[64] = "";
1165 int i, ret; 1199 int i, ret;
@@ -1588,14 +1622,14 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
1588 1622
1589static int convert_to_probe_trace_events(struct perf_probe_event *pev, 1623static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1590 struct probe_trace_event **tevs, 1624 struct probe_trace_event **tevs,
1591 int max_tevs) 1625 int max_tevs, const char *module)
1592{ 1626{
1593 struct symbol *sym; 1627 struct symbol *sym;
1594 int ret = 0, i; 1628 int ret = 0, i;
1595 struct probe_trace_event *tev; 1629 struct probe_trace_event *tev;
1596 1630
1597 /* Convert perf_probe_event with debuginfo */ 1631 /* Convert perf_probe_event with debuginfo */
1598 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs); 1632 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module);
1599 if (ret != 0) 1633 if (ret != 0)
1600 return ret; 1634 return ret;
1601 1635
@@ -1644,8 +1678,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1644 } 1678 }
1645 1679
1646 /* Currently just checking function name from symbol map */ 1680 /* Currently just checking function name from symbol map */
1647 sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION], 1681 sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
1648 tev->point.symbol, NULL);
1649 if (!sym) { 1682 if (!sym) {
1650 pr_warning("Kernel symbol \'%s\' not found.\n", 1683 pr_warning("Kernel symbol \'%s\' not found.\n",
1651 tev->point.symbol); 1684 tev->point.symbol);
@@ -1668,7 +1701,7 @@ struct __event_package {
1668}; 1701};
1669 1702
1670int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, 1703int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1671 int max_tevs, bool force_add) 1704 int max_tevs, const char *module, bool force_add)
1672{ 1705{
1673 int i, j, ret; 1706 int i, j, ret;
1674 struct __event_package *pkgs; 1707 struct __event_package *pkgs;
@@ -1689,7 +1722,9 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1689 pkgs[i].pev = &pevs[i]; 1722 pkgs[i].pev = &pevs[i];
1690 /* Convert with or without debuginfo */ 1723 /* Convert with or without debuginfo */
1691 ret = convert_to_probe_trace_events(pkgs[i].pev, 1724 ret = convert_to_probe_trace_events(pkgs[i].pev,
1692 &pkgs[i].tevs, max_tevs); 1725 &pkgs[i].tevs,
1726 max_tevs,
1727 module);
1693 if (ret < 0) 1728 if (ret < 0)
1694 goto end; 1729 goto end;
1695 pkgs[i].ntevs = ret; 1730 pkgs[i].ntevs = ret;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index c74b1fd2c1f..5accbedfea3 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -115,14 +115,18 @@ extern void clear_perf_probe_event(struct perf_probe_event *pev);
115/* Command string to line-range */ 115/* Command string to line-range */
116extern int parse_line_range_desc(const char *cmd, struct line_range *lr); 116extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
117 117
118/* Internal use: Return kernel/module path */
119extern const char *kernel_get_module_path(const char *module);
118 120
119extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, 121extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
120 int max_probe_points, bool force_add); 122 int max_probe_points, const char *module,
123 bool force_add);
121extern int del_perf_probe_events(struct strlist *dellist); 124extern int del_perf_probe_events(struct strlist *dellist);
122extern int show_perf_probe_events(void); 125extern int show_perf_probe_events(void);
123extern int show_line_range(struct line_range *lr); 126extern int show_line_range(struct line_range *lr, const char *module);
124extern int show_available_vars(struct perf_probe_event *pevs, int npevs, 127extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
125 int max_probe_points, bool externs); 128 int max_probe_points, const char *module,
129 bool externs);
126 130
127 131
128/* Maximum index number of event-name postfix */ 132/* Maximum index number of event-name postfix */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index a274fd0c143..c20bd52833a 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -116,6 +116,101 @@ static void line_list__free(struct list_head *head)
116 } 116 }
117} 117}
118 118
119/* Dwarf FL wrappers */
120
121static int __linux_kernel_find_elf(Dwfl_Module *mod,
122 void **userdata,
123 const char *module_name,
124 Dwarf_Addr base,
125 char **file_name, Elf **elfp)
126{
127 int fd;
128 const char *path = kernel_get_module_path(module_name);
129
130 if (path) {
131 fd = open(path, O_RDONLY);
132 if (fd >= 0) {
133 *file_name = strdup(path);
134 return fd;
135 }
136 }
137 /* If failed, try to call standard method */
138 return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base,
139 file_name, elfp);
140}
141
142static char *debuginfo_path; /* Currently dummy */
143
144static const Dwfl_Callbacks offline_callbacks = {
145 .find_debuginfo = dwfl_standard_find_debuginfo,
146 .debuginfo_path = &debuginfo_path,
147
148 .section_address = dwfl_offline_section_address,
149
150 /* We use this table for core files too. */
151 .find_elf = dwfl_build_id_find_elf,
152};
153
154static const Dwfl_Callbacks kernel_callbacks = {
155 .find_debuginfo = dwfl_standard_find_debuginfo,
156 .debuginfo_path = &debuginfo_path,
157
158 .find_elf = __linux_kernel_find_elf,
159 .section_address = dwfl_linux_kernel_module_section_address,
160};
161
162/* Get a Dwarf from offline image */
163static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias)
164{
165 Dwfl_Module *mod;
166 Dwarf *dbg = NULL;
167
168 if (!dwflp)
169 return NULL;
170
171 *dwflp = dwfl_begin(&offline_callbacks);
172 if (!*dwflp)
173 return NULL;
174
175 mod = dwfl_report_offline(*dwflp, "", "", fd);
176 if (!mod)
177 goto error;
178
179 dbg = dwfl_module_getdwarf(mod, bias);
180 if (!dbg) {
181error:
182 dwfl_end(*dwflp);
183 *dwflp = NULL;
184 }
185 return dbg;
186}
187
188/* Get a Dwarf from live kernel image */
189static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp,
190 Dwarf_Addr *bias)
191{
192 Dwarf *dbg;
193
194 if (!dwflp)
195 return NULL;
196
197 *dwflp = dwfl_begin(&kernel_callbacks);
198 if (!*dwflp)
199 return NULL;
200
201 /* Load the kernel dwarves: Don't care the result here */
202 dwfl_linux_kernel_report_kernel(*dwflp);
203 dwfl_linux_kernel_report_modules(*dwflp);
204
205 dbg = dwfl_addrdwarf(*dwflp, addr, bias);
206 /* Here, check whether we could get a real dwarf */
207 if (!dbg) {
208 dwfl_end(*dwflp);
209 *dwflp = NULL;
210 }
211 return dbg;
212}
213
119/* Dwarf wrappers */ 214/* Dwarf wrappers */
120 215
121/* Find the realpath of the target file. */ 216/* Find the realpath of the target file. */
@@ -1177,10 +1272,12 @@ static int find_probes(int fd, struct probe_finder *pf)
1177 Dwarf_Off off, noff; 1272 Dwarf_Off off, noff;
1178 size_t cuhl; 1273 size_t cuhl;
1179 Dwarf_Die *diep; 1274 Dwarf_Die *diep;
1180 Dwarf *dbg; 1275 Dwarf *dbg = NULL;
1276 Dwfl *dwfl;
1277 Dwarf_Addr bias; /* Currently ignored */
1181 int ret = 0; 1278 int ret = 0;
1182 1279
1183 dbg = dwarf_begin(fd, DWARF_C_READ); 1280 dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
1184 if (!dbg) { 1281 if (!dbg) {
1185 pr_warning("No dwarf info found in the vmlinux - " 1282 pr_warning("No dwarf info found in the vmlinux - "
1186 "please rebuild with CONFIG_DEBUG_INFO=y.\n"); 1283 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
@@ -1221,7 +1318,8 @@ static int find_probes(int fd, struct probe_finder *pf)
1221 off = noff; 1318 off = noff;
1222 } 1319 }
1223 line_list__free(&pf->lcache); 1320 line_list__free(&pf->lcache);
1224 dwarf_end(dbg); 1321 if (dwfl)
1322 dwfl_end(dwfl);
1225 1323
1226 return ret; 1324 return ret;
1227} 1325}
@@ -1412,23 +1510,31 @@ int find_available_vars_at(int fd, struct perf_probe_event *pev,
1412} 1510}
1413 1511
1414/* Reverse search */ 1512/* Reverse search */
1415int find_perf_probe_point(int fd, unsigned long addr, 1513int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
1416 struct perf_probe_point *ppt)
1417{ 1514{
1418 Dwarf_Die cudie, spdie, indie; 1515 Dwarf_Die cudie, spdie, indie;
1419 Dwarf *dbg; 1516 Dwarf *dbg = NULL;
1517 Dwfl *dwfl = NULL;
1420 Dwarf_Line *line; 1518 Dwarf_Line *line;
1421 Dwarf_Addr laddr, eaddr; 1519 Dwarf_Addr laddr, eaddr, bias = 0;
1422 const char *tmp; 1520 const char *tmp;
1423 int lineno, ret = 0; 1521 int lineno, ret = 0;
1424 bool found = false; 1522 bool found = false;
1425 1523
1426 dbg = dwarf_begin(fd, DWARF_C_READ); 1524 /* Open the live linux kernel */
1427 if (!dbg) 1525 dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias);
1428 return -EBADF; 1526 if (!dbg) {
1527 pr_warning("No dwarf info found in the vmlinux - "
1528 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
1529 ret = -EINVAL;
1530 goto end;
1531 }
1429 1532
1533 /* Adjust address with bias */
1534 addr += bias;
1430 /* Find cu die */ 1535 /* Find cu die */
1431 if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) { 1536 if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) {
1537 pr_warning("No CU DIE is found at %lx\n", addr);
1432 ret = -EINVAL; 1538 ret = -EINVAL;
1433 goto end; 1539 goto end;
1434 } 1540 }
@@ -1491,7 +1597,8 @@ found:
1491 } 1597 }
1492 1598
1493end: 1599end:
1494 dwarf_end(dbg); 1600 if (dwfl)
1601 dwfl_end(dwfl);
1495 if (ret >= 0) 1602 if (ret >= 0)
1496 ret = found ? 1 : 0; 1603 ret = found ? 1 : 0;
1497 return ret; 1604 return ret;
@@ -1624,6 +1731,8 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1624 struct line_finder *lf = param->data; 1731 struct line_finder *lf = param->data;
1625 struct line_range *lr = lf->lr; 1732 struct line_range *lr = lf->lr;
1626 1733
1734 pr_debug("find (%lx) %s\n", dwarf_dieoffset(sp_die),
1735 dwarf_diename(sp_die));
1627 if (dwarf_tag(sp_die) == DW_TAG_subprogram && 1736 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
1628 die_compare_name(sp_die, lr->function)) { 1737 die_compare_name(sp_die, lr->function)) {
1629 lf->fname = dwarf_decl_file(sp_die); 1738 lf->fname = dwarf_decl_file(sp_die);
@@ -1667,10 +1776,12 @@ int find_line_range(int fd, struct line_range *lr)
1667 Dwarf_Off off = 0, noff; 1776 Dwarf_Off off = 0, noff;
1668 size_t cuhl; 1777 size_t cuhl;
1669 Dwarf_Die *diep; 1778 Dwarf_Die *diep;
1670 Dwarf *dbg; 1779 Dwarf *dbg = NULL;
1780 Dwfl *dwfl;
1781 Dwarf_Addr bias; /* Currently ignored */
1671 const char *comp_dir; 1782 const char *comp_dir;
1672 1783
1673 dbg = dwarf_begin(fd, DWARF_C_READ); 1784 dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
1674 if (!dbg) { 1785 if (!dbg) {
1675 pr_warning("No dwarf info found in the vmlinux - " 1786 pr_warning("No dwarf info found in the vmlinux - "
1676 "please rebuild with CONFIG_DEBUG_INFO=y.\n"); 1787 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
@@ -1716,8 +1827,7 @@ int find_line_range(int fd, struct line_range *lr)
1716 } 1827 }
1717 1828
1718 pr_debug("path: %s\n", lr->path); 1829 pr_debug("path: %s\n", lr->path);
1719 dwarf_end(dbg); 1830 dwfl_end(dwfl);
1720
1721 return (ret < 0) ? ret : lf.found; 1831 return (ret < 0) ? ret : lf.found;
1722} 1832}
1723 1833
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 516912a0401..bba69d45569 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -22,7 +22,7 @@ extern int find_probe_trace_events(int fd, struct perf_probe_event *pev,
22 int max_tevs); 22 int max_tevs);
23 23
24/* Find a perf_probe_point from debuginfo */ 24/* Find a perf_probe_point from debuginfo */
25extern int find_perf_probe_point(int fd, unsigned long addr, 25extern int find_perf_probe_point(unsigned long addr,
26 struct perf_probe_point *ppt); 26 struct perf_probe_point *ppt);
27 27
28/* Find a line range */ 28/* Find a line range */
@@ -35,6 +35,7 @@ extern int find_available_vars_at(int fd, struct perf_probe_event *pev,
35 35
36#include <dwarf.h> 36#include <dwarf.h>
37#include <libdw.h> 37#include <libdw.h>
38#include <libdwfl.h>
38#include <version.h> 39#include <version.h>
39 40
40struct probe_finder { 41struct probe_finder {